]> git.proxmox.com Git - mirror_qemu.git/commitdiff
Merge remote-tracking branch 'remotes/ericb/tags/pull-nbd-2021-07-09-v2' into staging
authorPeter Maydell <peter.maydell@linaro.org>
Tue, 13 Jul 2021 13:32:20 +0000 (14:32 +0100)
committerPeter Maydell <peter.maydell@linaro.org>
Tue, 13 Jul 2021 13:32:20 +0000 (14:32 +0100)
nbd patches for 2021-07-09

- enhance 'qemu-img map --output=json' to make it easier to duplicate
backing chain allocation patterns
- fix a race in the 'yank' QMP command in relation to NBD requests

# gpg: Signature made Mon 12 Jul 2021 18:43:37 BST
# gpg:                using RSA key 71C2CC22B1C4602927D2F3AAA7A16B4A2527436A
# gpg: Good signature from "Eric Blake <eblake@redhat.com>" [full]
# gpg:                 aka "Eric Blake (Free Software Programmer) <ebb9@byu.net>" [full]
# gpg:                 aka "[jpeg image of size 6874]" [full]
# Primary key fingerprint: 71C2 CC22 B1C4 6029 27D2  F3AA A7A1 6B4A 2527 436A

* remotes/ericb/tags/pull-nbd-2021-07-09-v2:
  nbd: register yank function earlier
  qemu-img: Reword 'qemu-img map --output=json' docs
  qemu-img: Make unallocated part of backing chain obvious in map
  iotests: Improve and rename test 309 to nbd-qemu-allocation

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
102 files changed:
MAINTAINERS
configure
hw/intc/s390_flic_kvm.c
hw/net/dp8393x.c
hw/pci-host/Kconfig
hw/pci-host/meson.build
hw/pci-host/prep.c [deleted file]
hw/pci-host/raven.c [new file with mode: 0644]
hw/ppc/Kconfig
hw/s390x/meson.build
hw/s390x/s390-stattrib-kvm.c
hw/s390x/tod-kvm.c
hw/s390x/tod-qemu.c [deleted file]
hw/s390x/tod-tcg.c [new file with mode: 0644]
hw/s390x/tod.c
hw/sd/sd.c
hw/vfio/ap.c
include/hw/s390x/tod.h
meson.build
monitor/misc.c
scripts/qemu-trace-stap
target/mips/tcg/sysemu/mips-semi.c
target/mips/tcg/translate.c
target/mips/tcg/tx79.decode
target/mips/tcg/tx79_translate.c
target/s390x/arch_dump.c
target/s390x/cc_helper.c [deleted file]
target/s390x/cpu-dump.c [new file with mode: 0644]
target/s390x/cpu-sysemu.c [new file with mode: 0644]
target/s390x/cpu.c
target/s390x/cpu_features_def.h.inc
target/s390x/cpu_models.c
target/s390x/cpu_models_sysemu.c [new file with mode: 0644]
target/s390x/cpu_models_user.c [new file with mode: 0644]
target/s390x/crypto_helper.c [deleted file]
target/s390x/diag.c
target/s390x/excp_helper.c [deleted file]
target/s390x/fpu_helper.c [deleted file]
target/s390x/gdbstub.c
target/s390x/gen-features.c
target/s390x/helper.c
target/s390x/helper.h
target/s390x/insn-data.def [deleted file]
target/s390x/insn-format.def [deleted file]
target/s390x/int_helper.c [deleted file]
target/s390x/internal.h [deleted file]
target/s390x/interrupt.c
target/s390x/ioinst.c
target/s390x/kvm-stub.c [deleted file]
target/s390x/kvm.c [deleted file]
target/s390x/kvm/kvm.c [new file with mode: 0644]
target/s390x/kvm/kvm_s390x.h [new file with mode: 0644]
target/s390x/kvm/meson.build [new file with mode: 0644]
target/s390x/kvm/trace-events [new file with mode: 0644]
target/s390x/kvm/trace.h [new file with mode: 0644]
target/s390x/kvm_s390x.h [deleted file]
target/s390x/machine.c
target/s390x/mem_helper.c [deleted file]
target/s390x/meson.build
target/s390x/misc_helper.c [deleted file]
target/s390x/mmu_helper.c
target/s390x/s390-tod.h [deleted file]
target/s390x/s390x-internal.h [new file with mode: 0644]
target/s390x/sigp.c
target/s390x/tcg-stub.c [deleted file]
target/s390x/tcg/cc_helper.c [new file with mode: 0644]
target/s390x/tcg/crypto_helper.c [new file with mode: 0644]
target/s390x/tcg/excp_helper.c [new file with mode: 0644]
target/s390x/tcg/fpu_helper.c [new file with mode: 0644]
target/s390x/tcg/insn-data.def [new file with mode: 0644]
target/s390x/tcg/insn-format.def [new file with mode: 0644]
target/s390x/tcg/int_helper.c [new file with mode: 0644]
target/s390x/tcg/mem_helper.c [new file with mode: 0644]
target/s390x/tcg/meson.build [new file with mode: 0644]
target/s390x/tcg/misc_helper.c [new file with mode: 0644]
target/s390x/tcg/s390-tod.h [new file with mode: 0644]
target/s390x/tcg/tcg_s390x.h [new file with mode: 0644]
target/s390x/tcg/translate.c [new file with mode: 0644]
target/s390x/tcg/translate_vx.c.inc [new file with mode: 0644]
target/s390x/tcg/vec.h [new file with mode: 0644]
target/s390x/tcg/vec_fpu_helper.c [new file with mode: 0644]
target/s390x/tcg/vec_helper.c [new file with mode: 0644]
target/s390x/tcg/vec_int_helper.c [new file with mode: 0644]
target/s390x/tcg/vec_string_helper.c [new file with mode: 0644]
target/s390x/tcg_s390x.h [deleted file]
target/s390x/trace-events
target/s390x/translate.c [deleted file]
target/s390x/translate_vx.c.inc [deleted file]
target/s390x/vec.h [deleted file]
target/s390x/vec_fpu_helper.c [deleted file]
target/s390x/vec_helper.c [deleted file]
target/s390x/vec_int_helper.c [deleted file]
target/s390x/vec_string_helper.c [deleted file]
tests/qtest/fuzz-sdcard-test.c [new file with mode: 0644]
tests/qtest/meson.build
trace/control-target.c
trace/control.c
trace/control.h
trace/meson.build
trace/qmp.c
trace/simple.c
trace/simple.h

index 3026b979b7f0e47f11cb13c4d2994577d688da32..c340bb02b0fa351f5ab49d30e9bc42a336aed0e1 100644 (file)
@@ -297,6 +297,8 @@ M: Richard Henderson <richard.henderson@linaro.org>
 M: David Hildenbrand <david@redhat.com>
 S: Maintained
 F: target/s390x/
+F: target/s390x/tcg
+F: target/s390x/cpu_models_*.[ch]
 F: hw/s390x/
 F: disas/s390.c
 F: tests/tcg/s390x/
@@ -393,9 +395,7 @@ M: Halil Pasic <pasic@linux.ibm.com>
 M: Cornelia Huck <cohuck@redhat.com>
 M: Christian Borntraeger <borntraeger@de.ibm.com>
 S: Supported
-F: target/s390x/kvm.c
-F: target/s390x/kvm_s390x.h
-F: target/s390x/kvm-stub.c
+F: target/s390x/kvm/
 F: target/s390x/ioinst.[ch]
 F: target/s390x/machine.c
 F: target/s390x/sigp.c
@@ -1304,7 +1304,7 @@ S: Maintained
 F: hw/ppc/prep.c
 F: hw/ppc/prep_systemio.c
 F: hw/ppc/rs6000_mc.c
-F: hw/pci-host/prep.[hc]
+F: hw/pci-host/raven.c
 F: hw/isa/i82378.c
 F: hw/isa/pc87312.c
 F: hw/dma/i82374.c
@@ -1823,7 +1823,8 @@ F: include/hw/sd/sd*
 F: hw/sd/core.c
 F: hw/sd/sd*
 F: hw/sd/ssi-sd.c
-F: tests/qtest/sd*
+F: tests/qtest/fuzz-sdcard-test.c
+F: tests/qtest/sdhci-test.c
 
 USB
 M: Gerd Hoffmann <kraxel@redhat.com>
index 85db248ac1075c0a25e400759b3f292460643a05..4d0a2bfdd87301b9ae18834606bc9edc75e36f01 100755 (executable)
--- a/configure
+++ b/configure
@@ -3606,21 +3606,8 @@ fi
 ##########################################
 # For 'ust' backend, test if ust headers are present
 if have_backend "ust"; then
-  cat > $TMPC << EOF
-#include <lttng/tracepoint.h>
-int main(void) { return 0; }
-EOF
-  if compile_prog "" "-Wl,--no-as-needed -ldl" ; then
-    if $pkg_config lttng-ust --exists; then
-      lttng_ust_libs=$($pkg_config --libs lttng-ust)
-    else
-      lttng_ust_libs="-llttng-ust -ldl"
-    fi
-    if $pkg_config liburcu-bp --exists; then
-      urcu_bp_libs=$($pkg_config --libs liburcu-bp)
-    else
-      urcu_bp_libs="-lurcu-bp"
-    fi
+  if $pkg_config lttng-ust --exists; then
+    lttng_ust_libs=$($pkg_config --libs lttng-ust)
   else
     error_exit "Trace backend 'ust' missing lttng-ust header files"
   fi
@@ -4773,7 +4760,6 @@ fi
 if have_backend "ust"; then
   echo "CONFIG_TRACE_UST=y" >> $config_host_mak
   echo "LTTNG_UST_LIBS=$lttng_ust_libs" >> $config_host_mak
-  echo "URCU_BP_LIBS=$urcu_bp_libs" >> $config_host_mak
 fi
 if have_backend "dtrace"; then
   echo "CONFIG_TRACE_DTRACE=y" >> $config_host_mak
index 929cfa3a686c3ff0354ae50e11583a173b7395dc..efe5054182c372d31e0aafa4b0b3a18f13025441 100644 (file)
@@ -11,7 +11,7 @@
  */
 
 #include "qemu/osdep.h"
-#include "kvm_s390x.h"
+#include "kvm/kvm_s390x.h"
 #include <sys/ioctl.h>
 #include "qemu/error-report.h"
 #include "qemu/module.h"
index 252c0a26641369644470dc31010cdcf3d510764e..45b954e46c25987ee3604e00ab277ba05b938d5e 100644 (file)
@@ -85,6 +85,7 @@ static const char *reg_names[] = {
 #define SONIC_MPT    0x2e
 #define SONIC_MDT    0x2f
 #define SONIC_DCR2   0x3f
+#define SONIC_REG_COUNT  0x40
 
 #define SONIC_CR_HTX     0x0001
 #define SONIC_CR_TXP     0x0002
@@ -157,12 +158,11 @@ struct dp8393xState {
     MemoryRegion mmio;
 
     /* Registers */
-    uint8_t cam[16][6];
-    uint16_t regs[0x40];
+    uint16_t cam[16][3];
+    uint16_t regs[SONIC_REG_COUNT];
 
     /* Temporaries */
     uint8_t tx_buffer[0x10000];
-    uint16_t data[12];
     int loopback_packet;
 
     /* Memory access */
@@ -219,34 +219,48 @@ static uint32_t dp8393x_wt(dp8393xState *s)
     return s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
 }
 
-static uint16_t dp8393x_get(dp8393xState *s, int width, int offset)
+static uint16_t dp8393x_get(dp8393xState *s, hwaddr addr, int offset)
 {
+    const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
     uint16_t val;
 
-    if (s->big_endian) {
-        val = be16_to_cpu(s->data[offset * width + width - 1]);
+    if (s->regs[SONIC_DCR] & SONIC_DCR_DW) {
+        addr += offset << 2;
+        if (s->big_endian) {
+            val = address_space_ldl_be(&s->as, addr, attrs, NULL);
+        } else {
+            val = address_space_ldl_le(&s->as, addr, attrs, NULL);
+        }
     } else {
-        val = le16_to_cpu(s->data[offset * width]);
+        addr += offset << 1;
+        if (s->big_endian) {
+            val = address_space_lduw_be(&s->as, addr, attrs, NULL);
+        } else {
+            val = address_space_lduw_le(&s->as, addr, attrs, NULL);
+        }
     }
+
     return val;
 }
 
-static void dp8393x_put(dp8393xState *s, int width, int offset,
-                        uint16_t val)
+static void dp8393x_put(dp8393xState *s,
+                        hwaddr addr, int offset, uint16_t val)
 {
-    if (s->big_endian) {
-        if (width == 2) {
-            s->data[offset * 2] = 0;
-            s->data[offset * 2 + 1] = cpu_to_be16(val);
+    const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
+
+    if (s->regs[SONIC_DCR] & SONIC_DCR_DW) {
+        addr += offset << 2;
+        if (s->big_endian) {
+            address_space_stl_be(&s->as, addr, val, attrs, NULL);
         } else {
-            s->data[offset] = cpu_to_be16(val);
+            address_space_stl_le(&s->as, addr, val, attrs, NULL);
         }
     } else {
-        if (width == 2) {
-            s->data[offset * 2] = cpu_to_le16(val);
-            s->data[offset * 2 + 1] = 0;
+        addr += offset << 1;
+        if (s->big_endian) {
+            address_space_stw_be(&s->as, addr, val, attrs, NULL);
         } else {
-            s->data[offset] = cpu_to_le16(val);
+            address_space_stw_le(&s->as, addr, val, attrs, NULL);
         }
     }
 }
@@ -270,34 +284,28 @@ static void dp8393x_update_irq(dp8393xState *s)
 static void dp8393x_do_load_cam(dp8393xState *s)
 {
     int width, size;
-    uint16_t index = 0;
+    uint16_t index;
 
     width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
     size = sizeof(uint16_t) * 4 * width;
 
     while (s->regs[SONIC_CDC] & 0x1f) {
         /* Fill current entry */
-        address_space_read(&s->as, dp8393x_cdp(s),
-                           MEMTXATTRS_UNSPECIFIED, s->data, size);
-        s->cam[index][0] = dp8393x_get(s, width, 1) & 0xff;
-        s->cam[index][1] = dp8393x_get(s, width, 1) >> 8;
-        s->cam[index][2] = dp8393x_get(s, width, 2) & 0xff;
-        s->cam[index][3] = dp8393x_get(s, width, 2) >> 8;
-        s->cam[index][4] = dp8393x_get(s, width, 3) & 0xff;
-        s->cam[index][5] = dp8393x_get(s, width, 3) >> 8;
-        trace_dp8393x_load_cam(index, s->cam[index][0], s->cam[index][1],
-                               s->cam[index][2], s->cam[index][3],
-                               s->cam[index][4], s->cam[index][5]);
+        index = dp8393x_get(s, dp8393x_cdp(s), 0) & 0xf;
+        s->cam[index][0] = dp8393x_get(s, dp8393x_cdp(s), 1);
+        s->cam[index][1] = dp8393x_get(s, dp8393x_cdp(s), 2);
+        s->cam[index][2] = dp8393x_get(s, dp8393x_cdp(s), 3);
+        trace_dp8393x_load_cam(index,
+                               s->cam[index][0] >> 8, s->cam[index][0] & 0xff,
+                               s->cam[index][1] >> 8, s->cam[index][1] & 0xff,
+                               s->cam[index][2] >> 8, s->cam[index][2] & 0xff);
         /* Move to next entry */
         s->regs[SONIC_CDC]--;
         s->regs[SONIC_CDP] += size;
-        index++;
     }
 
     /* Read CAM enable */
-    address_space_read(&s->as, dp8393x_cdp(s),
-                       MEMTXATTRS_UNSPECIFIED, s->data, size);
-    s->regs[SONIC_CE] = dp8393x_get(s, width, 0);
+    s->regs[SONIC_CE] = dp8393x_get(s, dp8393x_cdp(s), 0);
     trace_dp8393x_load_cam_done(s->regs[SONIC_CE]);
 
     /* Done */
@@ -313,14 +321,12 @@ static void dp8393x_do_read_rra(dp8393xState *s)
     /* Read memory */
     width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
     size = sizeof(uint16_t) * 4 * width;
-    address_space_read(&s->as, dp8393x_rrp(s),
-                       MEMTXATTRS_UNSPECIFIED, s->data, size);
 
     /* Update SONIC registers */
-    s->regs[SONIC_CRBA0] = dp8393x_get(s, width, 0);
-    s->regs[SONIC_CRBA1] = dp8393x_get(s, width, 1);
-    s->regs[SONIC_RBWC0] = dp8393x_get(s, width, 2);
-    s->regs[SONIC_RBWC1] = dp8393x_get(s, width, 3);
+    s->regs[SONIC_CRBA0] = dp8393x_get(s, dp8393x_rrp(s), 0);
+    s->regs[SONIC_CRBA1] = dp8393x_get(s, dp8393x_rrp(s), 1);
+    s->regs[SONIC_RBWC0] = dp8393x_get(s, dp8393x_rrp(s), 2);
+    s->regs[SONIC_RBWC1] = dp8393x_get(s, dp8393x_rrp(s), 3);
     trace_dp8393x_read_rra_regs(s->regs[SONIC_CRBA0], s->regs[SONIC_CRBA1],
                                 s->regs[SONIC_RBWC0], s->regs[SONIC_RBWC1]);
 
@@ -416,28 +422,22 @@ static void dp8393x_do_receiver_disable(dp8393xState *s)
 static void dp8393x_do_transmit_packets(dp8393xState *s)
 {
     NetClientState *nc = qemu_get_queue(s->nic);
-    int width, size;
     int tx_len, len;
     uint16_t i;
 
-    width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
-
     while (1) {
         /* Read memory */
-        size = sizeof(uint16_t) * 6 * width;
         s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA];
         trace_dp8393x_transmit_packet(dp8393x_ttda(s));
-        address_space_read(&s->as, dp8393x_ttda(s) + sizeof(uint16_t) * width,
-                           MEMTXATTRS_UNSPECIFIED, s->data, size);
         tx_len = 0;
 
         /* Update registers */
-        s->regs[SONIC_TCR] = dp8393x_get(s, width, 0) & 0xf000;
-        s->regs[SONIC_TPS] = dp8393x_get(s, width, 1);
-        s->regs[SONIC_TFC] = dp8393x_get(s, width, 2);
-        s->regs[SONIC_TSA0] = dp8393x_get(s, width, 3);
-        s->regs[SONIC_TSA1] = dp8393x_get(s, width, 4);
-        s->regs[SONIC_TFS] = dp8393x_get(s, width, 5);
+        s->regs[SONIC_TCR] = dp8393x_get(s, dp8393x_ttda(s), 1) & 0xf000;
+        s->regs[SONIC_TPS] = dp8393x_get(s, dp8393x_ttda(s), 2);
+        s->regs[SONIC_TFC] = dp8393x_get(s, dp8393x_ttda(s), 3);
+        s->regs[SONIC_TSA0] = dp8393x_get(s, dp8393x_ttda(s), 4);
+        s->regs[SONIC_TSA1] = dp8393x_get(s, dp8393x_ttda(s), 5);
+        s->regs[SONIC_TFS] = dp8393x_get(s, dp8393x_ttda(s), 6);
 
         /* Handle programmable interrupt */
         if (s->regs[SONIC_TCR] & SONIC_TCR_PINT) {
@@ -459,15 +459,12 @@ static void dp8393x_do_transmit_packets(dp8393xState *s)
             i++;
             if (i != s->regs[SONIC_TFC]) {
                 /* Read next fragment details */
-                size = sizeof(uint16_t) * 3 * width;
-                address_space_read(&s->as,
-                                   dp8393x_ttda(s)
-                                   + sizeof(uint16_t) * width * (4 + 3 * i),
-                                   MEMTXATTRS_UNSPECIFIED, s->data,
-                                   size);
-                s->regs[SONIC_TSA0] = dp8393x_get(s, width, 0);
-                s->regs[SONIC_TSA1] = dp8393x_get(s, width, 1);
-                s->regs[SONIC_TFS] = dp8393x_get(s, width, 2);
+                s->regs[SONIC_TSA0] = dp8393x_get(s, dp8393x_ttda(s),
+                                                  4 + 3 * i);
+                s->regs[SONIC_TSA1] = dp8393x_get(s, dp8393x_ttda(s),
+                                                  5 + 3 * i);
+                s->regs[SONIC_TFS] = dp8393x_get(s, dp8393x_ttda(s),
+                                                 6 + 3 * i);
             }
         }
 
@@ -500,22 +497,12 @@ static void dp8393x_do_transmit_packets(dp8393xState *s)
         s->regs[SONIC_TCR] |= SONIC_TCR_PTX;
 
         /* Write status */
-        dp8393x_put(s, width, 0,
-                    s->regs[SONIC_TCR] & 0x0fff); /* status */
-        size = sizeof(uint16_t) * width;
-        address_space_write(&s->as, dp8393x_ttda(s),
-                            MEMTXATTRS_UNSPECIFIED, s->data, size);
+        dp8393x_put(s, dp8393x_ttda(s), 0, s->regs[SONIC_TCR] & 0x0fff);
 
         if (!(s->regs[SONIC_CR] & SONIC_CR_HTX)) {
             /* Read footer of packet */
-            size = sizeof(uint16_t) * width;
-            address_space_read(&s->as,
-                               dp8393x_ttda(s)
-                               + sizeof(uint16_t) * width
-                                 * (4 + 3 * s->regs[SONIC_TFC]),
-                               MEMTXATTRS_UNSPECIFIED, s->data,
-                               size);
-            s->regs[SONIC_CTDA] = dp8393x_get(s, width, 0);
+            s->regs[SONIC_CTDA] = dp8393x_get(s, dp8393x_ttda(s),
+                                              4 + 3 * s->regs[SONIC_TFC]);
             if (s->regs[SONIC_CTDA] & SONIC_DESC_EOL) {
                 /* EOL detected */
                 break;
@@ -591,8 +578,7 @@ static uint64_t dp8393x_read(void *opaque, hwaddr addr, unsigned int size)
     case SONIC_CAP1:
     case SONIC_CAP0:
         if (s->regs[SONIC_CR] & SONIC_CR_RST) {
-            val = s->cam[s->regs[SONIC_CEP] & 0xf][2 * (SONIC_CAP0 - reg) + 1] << 8;
-            val |= s->cam[s->regs[SONIC_CEP] & 0xf][2 * (SONIC_CAP0 - reg)];
+            val = s->cam[s->regs[SONIC_CEP] & 0xf][SONIC_CAP0 - reg];
         }
         break;
     /* All other registers have no special contraints */
@@ -602,15 +588,14 @@ static uint64_t dp8393x_read(void *opaque, hwaddr addr, unsigned int size)
 
     trace_dp8393x_read(reg, reg_names[reg], val, size);
 
-    return s->big_endian ? val << 16 : val;
+    return val;
 }
 
-static void dp8393x_write(void *opaque, hwaddr addr, uint64_t data,
+static void dp8393x_write(void *opaque, hwaddr addr, uint64_t val,
                           unsigned int size)
 {
     dp8393xState *s = opaque;
     int reg = addr >> s->it_shift;
-    uint32_t val = s->big_endian ? data >> 16 : data;
 
     trace_dp8393x_write(reg, reg_names[reg], val, size);
 
@@ -691,11 +676,16 @@ static void dp8393x_write(void *opaque, hwaddr addr, uint64_t data,
     }
 }
 
+/*
+ * Since .impl.max_access_size is effectively controlled by the it_shift
+ * property, leave it unspecified for now to allow the memory API to
+ * correctly zero extend the 16-bit register values to the access size up to and
+ * including it_shift.
+ */
 static const MemoryRegionOps dp8393x_ops = {
     .read = dp8393x_read,
     .write = dp8393x_write,
-    .impl.min_access_size = 4,
-    .impl.max_access_size = 4,
+    .impl.min_access_size = 2,
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
@@ -764,7 +754,7 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
     dp8393xState *s = qemu_get_nic_opaque(nc);
     int packet_type;
     uint32_t available, address;
-    int width, rx_len, padded_len;
+    int rx_len, padded_len;
     uint32_t checksum;
     int size;
 
@@ -777,10 +767,8 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
 
     rx_len = pkt_size + sizeof(checksum);
     if (s->regs[SONIC_DCR] & SONIC_DCR_DW) {
-        width = 2;
         padded_len = ((rx_len - 1) | 3) + 1;
     } else {
-        width = 1;
         padded_len = ((rx_len - 1) | 1) + 1;
     }
 
@@ -801,11 +789,7 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
     /* Check for EOL */
     if (s->regs[SONIC_LLFA] & SONIC_DESC_EOL) {
         /* Are we still in resource exhaustion? */
-        size = sizeof(uint16_t) * 1 * width;
-        address = dp8393x_crda(s) + sizeof(uint16_t) * 5 * width;
-        address_space_read(&s->as, address, MEMTXATTRS_UNSPECIFIED,
-                           s->data, size);
-        s->regs[SONIC_LLFA] = dp8393x_get(s, width, 0);
+        s->regs[SONIC_LLFA] = dp8393x_get(s, dp8393x_crda(s), 5);
         if (s->regs[SONIC_LLFA] & SONIC_DESC_EOL) {
             /* Still EOL ; stop reception */
             return -1;
@@ -813,11 +797,7 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
         /* Link has been updated by host */
 
         /* Clear in_use */
-        size = sizeof(uint16_t) * width;
-        address = dp8393x_crda(s) + sizeof(uint16_t) * 6 * width;
-        dp8393x_put(s, width, 0, 0);
-        address_space_rw(&s->as, address, MEMTXATTRS_UNSPECIFIED,
-                         (uint8_t *)s->data, size, 1);
+        dp8393x_put(s, dp8393x_crda(s), 6, 0x0000);
 
         /* Move to next descriptor */
         s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
@@ -846,8 +826,8 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
     /* Pad short packets to keep pointers aligned */
     if (rx_len < padded_len) {
         size = padded_len - rx_len;
-        address_space_rw(&s->as, address, MEMTXATTRS_UNSPECIFIED,
-            (uint8_t *)"\xFF\xFF\xFF", size, 1);
+        address_space_write(&s->as, address, MEMTXATTRS_UNSPECIFIED,
+                            "\xFF\xFF\xFF", size);
         address += size;
     }
 
@@ -871,32 +851,20 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
 
     /* Write status to memory */
     trace_dp8393x_receive_write_status(dp8393x_crda(s));
-    dp8393x_put(s, width, 0, s->regs[SONIC_RCR]); /* status */
-    dp8393x_put(s, width, 1, rx_len); /* byte count */
-    dp8393x_put(s, width, 2, s->regs[SONIC_TRBA0]); /* pkt_ptr0 */
-    dp8393x_put(s, width, 3, s->regs[SONIC_TRBA1]); /* pkt_ptr1 */
-    dp8393x_put(s, width, 4, s->regs[SONIC_RSC]); /* seq_no */
-    size = sizeof(uint16_t) * 5 * width;
-    address_space_write(&s->as, dp8393x_crda(s),
-                        MEMTXATTRS_UNSPECIFIED,
-                        s->data, size);
+    dp8393x_put(s, dp8393x_crda(s), 0, s->regs[SONIC_RCR]); /* status */
+    dp8393x_put(s, dp8393x_crda(s), 1, rx_len); /* byte count */
+    dp8393x_put(s, dp8393x_crda(s), 2, s->regs[SONIC_TRBA0]); /* pkt_ptr0 */
+    dp8393x_put(s, dp8393x_crda(s), 3, s->regs[SONIC_TRBA1]); /* pkt_ptr1 */
+    dp8393x_put(s, dp8393x_crda(s), 4, s->regs[SONIC_RSC]); /* seq_no */
 
     /* Check link field */
-    size = sizeof(uint16_t) * width;
-    address_space_read(&s->as,
-                       dp8393x_crda(s) + sizeof(uint16_t) * 5 * width,
-                       MEMTXATTRS_UNSPECIFIED, s->data, size);
-    s->regs[SONIC_LLFA] = dp8393x_get(s, width, 0);
+    s->regs[SONIC_LLFA] = dp8393x_get(s, dp8393x_crda(s), 5);
     if (s->regs[SONIC_LLFA] & SONIC_DESC_EOL) {
         /* EOL detected */
         s->regs[SONIC_ISR] |= SONIC_ISR_RDE;
     } else {
         /* Clear in_use */
-        size = sizeof(uint16_t) * width;
-        address = dp8393x_crda(s) + sizeof(uint16_t) * 6 * width;
-        dp8393x_put(s, width, 0, 0);
-        address_space_write(&s->as, address, MEMTXATTRS_UNSPECIFIED,
-                            s->data, size);
+        dp8393x_put(s, dp8393x_crda(s), 6, 0x0000);
 
         /* Move to next descriptor */
         s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
@@ -972,7 +940,7 @@ static void dp8393x_realize(DeviceState *dev, Error **errp)
 
     address_space_init(&s->as, s->dma_mr, "dp8393x");
     memory_region_init_io(&s->mmio, OBJECT(dev), &dp8393x_ops, s,
-                          "dp8393x-regs", 0x40 << s->it_shift);
+                          "dp8393x-regs", SONIC_REG_COUNT << s->it_shift);
 
     s->nic = qemu_new_nic(&net_dp83932_info, &s->conf,
                           object_get_typename(OBJECT(dev)), dev->id, s);
@@ -983,11 +951,11 @@ static void dp8393x_realize(DeviceState *dev, Error **errp)
 
 static const VMStateDescription vmstate_dp8393x = {
     .name = "dp8393x",
-    .version_id = 0,
-    .minimum_version_id = 0,
+    .version_id = 1,
+    .minimum_version_id = 1,
     .fields = (VMStateField []) {
-        VMSTATE_BUFFER_UNSAFE(cam, dp8393xState, 0, 16 * 6),
-        VMSTATE_UINT16_ARRAY(regs, dp8393xState, 0x40),
+        VMSTATE_UINT16_2DARRAY(cam, dp8393xState, 16, 3),
+        VMSTATE_UINT16_ARRAY(regs, dp8393xState, SONIC_REG_COUNT),
         VMSTATE_END_OF_LIST()
     }
 };
index 79c20bf28bb55ca119b48b7ba2e86f3884cc64e3..84494400b86e95be0f9a626b7af240c7cd09b2f2 100644 (file)
@@ -6,7 +6,7 @@ config XEN_IGD_PASSTHROUGH
     default y
     depends on XEN && PCI_I440FX
 
-config PREP_PCI
+config RAVEN_PCI
     bool
     select PCI
     select OR_IRQ
index 1698d3a1920a8cab51f7dcb628c15e2a2e69f0a7..4c4f39c15c69b5e3124538522d1d3f1ed6821f50 100644 (file)
@@ -13,7 +13,7 @@ pci_ss.add(when: 'CONFIG_REMOTE_PCIHOST', if_true: files('remote.c'))
 pci_ss.add(when: 'CONFIG_SH_PCI', if_true: files('sh_pci.c'))
 
 # PPC devices
-pci_ss.add(when: 'CONFIG_PREP_PCI', if_true: files('prep.c'))
+pci_ss.add(when: 'CONFIG_RAVEN_PCI', if_true: files('raven.c'))
 pci_ss.add(when: 'CONFIG_GRACKLE_PCI', if_true: files('grackle.c'))
 # NewWorld PowerMac
 pci_ss.add(when: 'CONFIG_UNIN_PCI', if_true: files('uninorth.c'))
diff --git a/hw/pci-host/prep.c b/hw/pci-host/prep.c
deleted file mode 100644 (file)
index 9fef74f..0000000
+++ /dev/null
@@ -1,442 +0,0 @@
-/*
- * QEMU PREP PCI host
- *
- * Copyright (c) 2006 Fabrice Bellard
- * Copyright (c) 2011-2013 Andreas Färber
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qemu/datadir.h"
-#include "qemu/units.h"
-#include "qemu/log.h"
-#include "qapi/error.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_bus.h"
-#include "hw/pci/pci_host.h"
-#include "hw/qdev-properties.h"
-#include "migration/vmstate.h"
-#include "hw/intc/i8259.h"
-#include "hw/irq.h"
-#include "hw/loader.h"
-#include "hw/or-irq.h"
-#include "elf.h"
-#include "qom/object.h"
-
-#define TYPE_RAVEN_PCI_DEVICE "raven"
-#define TYPE_RAVEN_PCI_HOST_BRIDGE "raven-pcihost"
-
-OBJECT_DECLARE_SIMPLE_TYPE(RavenPCIState, RAVEN_PCI_DEVICE)
-
-struct RavenPCIState {
-    PCIDevice dev;
-
-    uint32_t elf_machine;
-    char *bios_name;
-    MemoryRegion bios;
-};
-
-typedef struct PRePPCIState PREPPCIState;
-DECLARE_INSTANCE_CHECKER(PREPPCIState, RAVEN_PCI_HOST_BRIDGE,
-                         TYPE_RAVEN_PCI_HOST_BRIDGE)
-
-struct PRePPCIState {
-    PCIHostState parent_obj;
-
-    qemu_or_irq *or_irq;
-    qemu_irq pci_irqs[PCI_NUM_PINS];
-    PCIBus pci_bus;
-    AddressSpace pci_io_as;
-    MemoryRegion pci_io;
-    MemoryRegion pci_io_non_contiguous;
-    MemoryRegion pci_memory;
-    MemoryRegion pci_intack;
-    MemoryRegion bm;
-    MemoryRegion bm_ram_alias;
-    MemoryRegion bm_pci_memory_alias;
-    AddressSpace bm_as;
-    RavenPCIState pci_dev;
-
-    int contiguous_map;
-    bool is_legacy_prep;
-};
-
-#define BIOS_SIZE (1 * MiB)
-
-static inline uint32_t raven_pci_io_config(hwaddr addr)
-{
-    int i;
-
-    for (i = 0; i < 11; i++) {
-        if ((addr & (1 << (11 + i))) != 0) {
-            break;
-        }
-    }
-    return (addr & 0x7ff) |  (i << 11);
-}
-
-static void raven_pci_io_write(void *opaque, hwaddr addr,
-                               uint64_t val, unsigned int size)
-{
-    PREPPCIState *s = opaque;
-    PCIHostState *phb = PCI_HOST_BRIDGE(s);
-    pci_data_write(phb->bus, raven_pci_io_config(addr), val, size);
-}
-
-static uint64_t raven_pci_io_read(void *opaque, hwaddr addr,
-                                  unsigned int size)
-{
-    PREPPCIState *s = opaque;
-    PCIHostState *phb = PCI_HOST_BRIDGE(s);
-    return pci_data_read(phb->bus, raven_pci_io_config(addr), size);
-}
-
-static const MemoryRegionOps raven_pci_io_ops = {
-    .read = raven_pci_io_read,
-    .write = raven_pci_io_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static uint64_t raven_intack_read(void *opaque, hwaddr addr,
-                                  unsigned int size)
-{
-    return pic_read_irq(isa_pic);
-}
-
-static void raven_intack_write(void *opaque, hwaddr addr,
-                                        uint64_t data, unsigned size)
-{
-    qemu_log_mask(LOG_UNIMP, "%s not implemented\n", __func__);
-}
-
-static const MemoryRegionOps raven_intack_ops = {
-    .read = raven_intack_read,
-    .write = raven_intack_write,
-    .valid = {
-        .max_access_size = 1,
-    },
-};
-
-static inline hwaddr raven_io_address(PREPPCIState *s,
-                                      hwaddr addr)
-{
-    if (s->contiguous_map == 0) {
-        /* 64 KB contiguous space for IOs */
-        addr &= 0xFFFF;
-    } else {
-        /* 8 MB non-contiguous space for IOs */
-        addr = (addr & 0x1F) | ((addr & 0x007FFF000) >> 7);
-    }
-
-    /* FIXME: handle endianness switch */
-
-    return addr;
-}
-
-static uint64_t raven_io_read(void *opaque, hwaddr addr,
-                              unsigned int size)
-{
-    PREPPCIState *s = opaque;
-    uint8_t buf[4];
-
-    addr = raven_io_address(s, addr);
-    address_space_read(&s->pci_io_as, addr + 0x80000000,
-                       MEMTXATTRS_UNSPECIFIED, buf, size);
-
-    if (size == 1) {
-        return buf[0];
-    } else if (size == 2) {
-        return lduw_le_p(buf);
-    } else if (size == 4) {
-        return ldl_le_p(buf);
-    } else {
-        g_assert_not_reached();
-    }
-}
-
-static void raven_io_write(void *opaque, hwaddr addr,
-                           uint64_t val, unsigned int size)
-{
-    PREPPCIState *s = opaque;
-    uint8_t buf[4];
-
-    addr = raven_io_address(s, addr);
-
-    if (size == 1) {
-        buf[0] = val;
-    } else if (size == 2) {
-        stw_le_p(buf, val);
-    } else if (size == 4) {
-        stl_le_p(buf, val);
-    } else {
-        g_assert_not_reached();
-    }
-
-    address_space_write(&s->pci_io_as, addr + 0x80000000,
-                        MEMTXATTRS_UNSPECIFIED, buf, size);
-}
-
-static const MemoryRegionOps raven_io_ops = {
-    .read = raven_io_read,
-    .write = raven_io_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl.max_access_size = 4,
-    .valid.unaligned = true,
-};
-
-static int raven_map_irq(PCIDevice *pci_dev, int irq_num)
-{
-    return (irq_num + (pci_dev->devfn >> 3)) & 1;
-}
-
-static void raven_set_irq(void *opaque, int irq_num, int level)
-{
-    PREPPCIState *s = opaque;
-
-    qemu_set_irq(s->pci_irqs[irq_num], level);
-}
-
-static AddressSpace *raven_pcihost_set_iommu(PCIBus *bus, void *opaque,
-                                             int devfn)
-{
-    PREPPCIState *s = opaque;
-
-    return &s->bm_as;
-}
-
-static void raven_change_gpio(void *opaque, int n, int level)
-{
-    PREPPCIState *s = opaque;
-
-    s->contiguous_map = level;
-}
-
-static void raven_pcihost_realizefn(DeviceState *d, Error **errp)
-{
-    SysBusDevice *dev = SYS_BUS_DEVICE(d);
-    PCIHostState *h = PCI_HOST_BRIDGE(dev);
-    PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(dev);
-    MemoryRegion *address_space_mem = get_system_memory();
-    int i;
-
-    if (s->is_legacy_prep) {
-        for (i = 0; i < PCI_NUM_PINS; i++) {
-            sysbus_init_irq(dev, &s->pci_irqs[i]);
-        }
-    } else {
-        /* According to PReP specification section 6.1.6 "System Interrupt
-         * Assignments", all PCI interrupts are routed via IRQ 15 */
-        s->or_irq = OR_IRQ(object_new(TYPE_OR_IRQ));
-        object_property_set_int(OBJECT(s->or_irq), "num-lines", PCI_NUM_PINS,
-                                &error_fatal);
-        qdev_realize(DEVICE(s->or_irq), NULL, &error_fatal);
-        sysbus_init_irq(dev, &s->or_irq->out_irq);
-
-        for (i = 0; i < PCI_NUM_PINS; i++) {
-            s->pci_irqs[i] = qdev_get_gpio_in(DEVICE(s->or_irq), i);
-        }
-    }
-
-    qdev_init_gpio_in(d, raven_change_gpio, 1);
-
-    pci_bus_irqs(&s->pci_bus, raven_set_irq, raven_map_irq, s, PCI_NUM_PINS);
-
-    memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_le_ops, s,
-                          "pci-conf-idx", 4);
-    memory_region_add_subregion(&s->pci_io, 0xcf8, &h->conf_mem);
-
-    memory_region_init_io(&h->data_mem, OBJECT(h), &pci_host_data_le_ops, s,
-                          "pci-conf-data", 4);
-    memory_region_add_subregion(&s->pci_io, 0xcfc, &h->data_mem);
-
-    memory_region_init_io(&h->mmcfg, OBJECT(s), &raven_pci_io_ops, s,
-                          "pciio", 0x00400000);
-    memory_region_add_subregion(address_space_mem, 0x80800000, &h->mmcfg);
-
-    memory_region_init_io(&s->pci_intack, OBJECT(s), &raven_intack_ops, s,
-                          "pci-intack", 1);
-    memory_region_add_subregion(address_space_mem, 0xbffffff0, &s->pci_intack);
-
-    /* TODO Remove once realize propagates to child devices. */
-    qdev_realize(DEVICE(&s->pci_dev), BUS(&s->pci_bus), errp);
-}
-
-static void raven_pcihost_initfn(Object *obj)
-{
-    PCIHostState *h = PCI_HOST_BRIDGE(obj);
-    PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(obj);
-    MemoryRegion *address_space_mem = get_system_memory();
-    DeviceState *pci_dev;
-
-    memory_region_init(&s->pci_io, obj, "pci-io", 0x3f800000);
-    memory_region_init_io(&s->pci_io_non_contiguous, obj, &raven_io_ops, s,
-                          "pci-io-non-contiguous", 0x00800000);
-    memory_region_init(&s->pci_memory, obj, "pci-memory", 0x3f000000);
-    address_space_init(&s->pci_io_as, &s->pci_io, "raven-io");
-
-    /* CPU address space */
-    memory_region_add_subregion(address_space_mem, 0x80000000, &s->pci_io);
-    memory_region_add_subregion_overlap(address_space_mem, 0x80000000,
-                                        &s->pci_io_non_contiguous, 1);
-    memory_region_add_subregion(address_space_mem, 0xc0000000, &s->pci_memory);
-    pci_root_bus_new_inplace(&s->pci_bus, sizeof(s->pci_bus), DEVICE(obj), NULL,
-                             &s->pci_memory, &s->pci_io, 0, TYPE_PCI_BUS);
-
-    /* Bus master address space */
-    memory_region_init(&s->bm, obj, "bm-raven", 4 * GiB);
-    memory_region_init_alias(&s->bm_pci_memory_alias, obj, "bm-pci-memory",
-                             &s->pci_memory, 0,
-                             memory_region_size(&s->pci_memory));
-    memory_region_init_alias(&s->bm_ram_alias, obj, "bm-system",
-                             get_system_memory(), 0, 0x80000000);
-    memory_region_add_subregion(&s->bm, 0         , &s->bm_pci_memory_alias);
-    memory_region_add_subregion(&s->bm, 0x80000000, &s->bm_ram_alias);
-    address_space_init(&s->bm_as, &s->bm, "raven-bm");
-    pci_setup_iommu(&s->pci_bus, raven_pcihost_set_iommu, s);
-
-    h->bus = &s->pci_bus;
-
-    object_initialize(&s->pci_dev, sizeof(s->pci_dev), TYPE_RAVEN_PCI_DEVICE);
-    pci_dev = DEVICE(&s->pci_dev);
-    object_property_set_int(OBJECT(&s->pci_dev), "addr", PCI_DEVFN(0, 0),
-                            NULL);
-    qdev_prop_set_bit(pci_dev, "multifunction", false);
-}
-
-static void raven_realize(PCIDevice *d, Error **errp)
-{
-    RavenPCIState *s = RAVEN_PCI_DEVICE(d);
-    char *filename;
-    int bios_size = -1;
-
-    d->config[0x0C] = 0x08; // cache_line_size
-    d->config[0x0D] = 0x10; // latency_timer
-    d->config[0x34] = 0x00; // capabilities_pointer
-
-    memory_region_init_rom_nomigrate(&s->bios, OBJECT(s), "bios", BIOS_SIZE,
-                                     &error_fatal);
-    memory_region_add_subregion(get_system_memory(), (uint32_t)(-BIOS_SIZE),
-                                &s->bios);
-    if (s->bios_name) {
-        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, s->bios_name);
-        if (filename) {
-            if (s->elf_machine != EM_NONE) {
-                bios_size = load_elf(filename, NULL, NULL, NULL, NULL,
-                                     NULL, NULL, NULL, 1, s->elf_machine,
-                                     0, 0);
-            }
-            if (bios_size < 0) {
-                bios_size = get_image_size(filename);
-                if (bios_size > 0 && bios_size <= BIOS_SIZE) {
-                    hwaddr bios_addr;
-                    bios_size = (bios_size + 0xfff) & ~0xfff;
-                    bios_addr = (uint32_t)(-BIOS_SIZE);
-                    bios_size = load_image_targphys(filename, bios_addr,
-                                                    bios_size);
-                }
-            }
-        }
-        g_free(filename);
-        if (bios_size < 0 || bios_size > BIOS_SIZE) {
-            memory_region_del_subregion(get_system_memory(), &s->bios);
-            error_setg(errp, "Could not load bios image '%s'", s->bios_name);
-            return;
-        }
-    }
-
-    vmstate_register_ram_global(&s->bios);
-}
-
-static const VMStateDescription vmstate_raven = {
-    .name = "raven",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .fields = (VMStateField[]) {
-        VMSTATE_PCI_DEVICE(dev, RavenPCIState),
-        VMSTATE_END_OF_LIST()
-    },
-};
-
-static void raven_class_init(ObjectClass *klass, void *data)
-{
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    k->realize = raven_realize;
-    k->vendor_id = PCI_VENDOR_ID_MOTOROLA;
-    k->device_id = PCI_DEVICE_ID_MOTOROLA_RAVEN;
-    k->revision = 0x00;
-    k->class_id = PCI_CLASS_BRIDGE_HOST;
-    dc->desc = "PReP Host Bridge - Motorola Raven";
-    dc->vmsd = &vmstate_raven;
-    /*
-     * Reason: PCI-facing part of the host bridge, not usable without
-     * the host-facing part, which can't be device_add'ed, yet.
-     */
-    dc->user_creatable = false;
-}
-
-static const TypeInfo raven_info = {
-    .name = TYPE_RAVEN_PCI_DEVICE,
-    .parent = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(RavenPCIState),
-    .class_init = raven_class_init,
-    .interfaces = (InterfaceInfo[]) {
-        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
-        { },
-    },
-};
-
-static Property raven_pcihost_properties[] = {
-    DEFINE_PROP_UINT32("elf-machine", PREPPCIState, pci_dev.elf_machine,
-                       EM_NONE),
-    DEFINE_PROP_STRING("bios-name", PREPPCIState, pci_dev.bios_name),
-    /* Temporary workaround until legacy prep machine is removed */
-    DEFINE_PROP_BOOL("is-legacy-prep", PREPPCIState, is_legacy_prep,
-                     false),
-    DEFINE_PROP_END_OF_LIST()
-};
-
-static void raven_pcihost_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
-    dc->realize = raven_pcihost_realizefn;
-    device_class_set_props(dc, raven_pcihost_properties);
-    dc->fw_name = "pci";
-}
-
-static const TypeInfo raven_pcihost_info = {
-    .name = TYPE_RAVEN_PCI_HOST_BRIDGE,
-    .parent = TYPE_PCI_HOST_BRIDGE,
-    .instance_size = sizeof(PREPPCIState),
-    .instance_init = raven_pcihost_initfn,
-    .class_init = raven_pcihost_class_init,
-};
-
-static void raven_register_types(void)
-{
-    type_register_static(&raven_pcihost_info);
-    type_register_static(&raven_info);
-}
-
-type_init(raven_register_types)
diff --git a/hw/pci-host/raven.c b/hw/pci-host/raven.c
new file mode 100644 (file)
index 0000000..3be27f0
--- /dev/null
@@ -0,0 +1,445 @@
+/*
+ * QEMU PREP PCI host
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ * Copyright (c) 2011-2013 Andreas Färber
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qemu/datadir.h"
+#include "qemu/units.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
+#include "hw/pci/pci_host.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+#include "hw/intc/i8259.h"
+#include "hw/irq.h"
+#include "hw/loader.h"
+#include "hw/or-irq.h"
+#include "elf.h"
+#include "qom/object.h"
+
+#define TYPE_RAVEN_PCI_DEVICE "raven"
+#define TYPE_RAVEN_PCI_HOST_BRIDGE "raven-pcihost"
+
+OBJECT_DECLARE_SIMPLE_TYPE(RavenPCIState, RAVEN_PCI_DEVICE)
+
+struct RavenPCIState {
+    PCIDevice dev;
+
+    uint32_t elf_machine;
+    char *bios_name;
+    MemoryRegion bios;
+};
+
+typedef struct PRePPCIState PREPPCIState;
+DECLARE_INSTANCE_CHECKER(PREPPCIState, RAVEN_PCI_HOST_BRIDGE,
+                         TYPE_RAVEN_PCI_HOST_BRIDGE)
+
+struct PRePPCIState {
+    PCIHostState parent_obj;
+
+    qemu_or_irq *or_irq;
+    qemu_irq pci_irqs[PCI_NUM_PINS];
+    PCIBus pci_bus;
+    AddressSpace pci_io_as;
+    MemoryRegion pci_io;
+    MemoryRegion pci_io_non_contiguous;
+    MemoryRegion pci_memory;
+    MemoryRegion pci_intack;
+    MemoryRegion bm;
+    MemoryRegion bm_ram_alias;
+    MemoryRegion bm_pci_memory_alias;
+    AddressSpace bm_as;
+    RavenPCIState pci_dev;
+
+    int contiguous_map;
+    bool is_legacy_prep;
+};
+
+#define BIOS_SIZE (1 * MiB)
+
+#define PCI_IO_BASE_ADDR    0x80000000  /* Physical address on main bus */
+
+static inline uint32_t raven_pci_io_config(hwaddr addr)
+{
+    int i;
+
+    for (i = 0; i < 11; i++) {
+        if ((addr & (1 << (11 + i))) != 0) {
+            break;
+        }
+    }
+    return (addr & 0x7ff) |  (i << 11);
+}
+
+static void raven_pci_io_write(void *opaque, hwaddr addr,
+                               uint64_t val, unsigned int size)
+{
+    PREPPCIState *s = opaque;
+    PCIHostState *phb = PCI_HOST_BRIDGE(s);
+    pci_data_write(phb->bus, raven_pci_io_config(addr), val, size);
+}
+
+static uint64_t raven_pci_io_read(void *opaque, hwaddr addr,
+                                  unsigned int size)
+{
+    PREPPCIState *s = opaque;
+    PCIHostState *phb = PCI_HOST_BRIDGE(s);
+    return pci_data_read(phb->bus, raven_pci_io_config(addr), size);
+}
+
+static const MemoryRegionOps raven_pci_io_ops = {
+    .read = raven_pci_io_read,
+    .write = raven_pci_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static uint64_t raven_intack_read(void *opaque, hwaddr addr,
+                                  unsigned int size)
+{
+    return pic_read_irq(isa_pic);
+}
+
+static void raven_intack_write(void *opaque, hwaddr addr,
+                                        uint64_t data, unsigned size)
+{
+    qemu_log_mask(LOG_UNIMP, "%s not implemented\n", __func__);
+}
+
+static const MemoryRegionOps raven_intack_ops = {
+    .read = raven_intack_read,
+    .write = raven_intack_write,
+    .valid = {
+        .max_access_size = 1,
+    },
+};
+
+static inline hwaddr raven_io_address(PREPPCIState *s,
+                                      hwaddr addr)
+{
+    if (s->contiguous_map == 0) {
+        /* 64 KB contiguous space for IOs */
+        addr &= 0xFFFF;
+    } else {
+        /* 8 MB non-contiguous space for IOs */
+        addr = (addr & 0x1F) | ((addr & 0x007FFF000) >> 7);
+    }
+
+    /* FIXME: handle endianness switch */
+
+    return addr;
+}
+
+static uint64_t raven_io_read(void *opaque, hwaddr addr,
+                              unsigned int size)
+{
+    PREPPCIState *s = opaque;
+    uint8_t buf[4];
+
+    addr = raven_io_address(s, addr);
+    address_space_read(&s->pci_io_as, addr + PCI_IO_BASE_ADDR,
+                       MEMTXATTRS_UNSPECIFIED, buf, size);
+
+    if (size == 1) {
+        return buf[0];
+    } else if (size == 2) {
+        return lduw_le_p(buf);
+    } else if (size == 4) {
+        return ldl_le_p(buf);
+    } else {
+        g_assert_not_reached();
+    }
+}
+
+static void raven_io_write(void *opaque, hwaddr addr,
+                           uint64_t val, unsigned int size)
+{
+    PREPPCIState *s = opaque;
+    uint8_t buf[4];
+
+    addr = raven_io_address(s, addr);
+
+    if (size == 1) {
+        buf[0] = val;
+    } else if (size == 2) {
+        stw_le_p(buf, val);
+    } else if (size == 4) {
+        stl_le_p(buf, val);
+    } else {
+        g_assert_not_reached();
+    }
+
+    address_space_write(&s->pci_io_as, addr + PCI_IO_BASE_ADDR,
+                        MEMTXATTRS_UNSPECIFIED, buf, size);
+}
+
+static const MemoryRegionOps raven_io_ops = {
+    .read = raven_io_read,
+    .write = raven_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl.max_access_size = 4,
+    .valid.unaligned = true,
+};
+
+static int raven_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    return (irq_num + (pci_dev->devfn >> 3)) & 1;
+}
+
+static void raven_set_irq(void *opaque, int irq_num, int level)
+{
+    PREPPCIState *s = opaque;
+
+    qemu_set_irq(s->pci_irqs[irq_num], level);
+}
+
+static AddressSpace *raven_pcihost_set_iommu(PCIBus *bus, void *opaque,
+                                             int devfn)
+{
+    PREPPCIState *s = opaque;
+
+    return &s->bm_as;
+}
+
+static void raven_change_gpio(void *opaque, int n, int level)
+{
+    PREPPCIState *s = opaque;
+
+    s->contiguous_map = level;
+}
+
+static void raven_pcihost_realizefn(DeviceState *d, Error **errp)
+{
+    SysBusDevice *dev = SYS_BUS_DEVICE(d);
+    PCIHostState *h = PCI_HOST_BRIDGE(dev);
+    PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(dev);
+    MemoryRegion *address_space_mem = get_system_memory();
+    int i;
+
+    if (s->is_legacy_prep) {
+        for (i = 0; i < PCI_NUM_PINS; i++) {
+            sysbus_init_irq(dev, &s->pci_irqs[i]);
+        }
+    } else {
+        /* According to PReP specification section 6.1.6 "System Interrupt
+         * Assignments", all PCI interrupts are routed via IRQ 15 */
+        s->or_irq = OR_IRQ(object_new(TYPE_OR_IRQ));
+        object_property_set_int(OBJECT(s->or_irq), "num-lines", PCI_NUM_PINS,
+                                &error_fatal);
+        qdev_realize(DEVICE(s->or_irq), NULL, &error_fatal);
+        sysbus_init_irq(dev, &s->or_irq->out_irq);
+
+        for (i = 0; i < PCI_NUM_PINS; i++) {
+            s->pci_irqs[i] = qdev_get_gpio_in(DEVICE(s->or_irq), i);
+        }
+    }
+
+    qdev_init_gpio_in(d, raven_change_gpio, 1);
+
+    pci_bus_irqs(&s->pci_bus, raven_set_irq, raven_map_irq, s, PCI_NUM_PINS);
+
+    memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_le_ops, s,
+                          "pci-conf-idx", 4);
+    memory_region_add_subregion(&s->pci_io, 0xcf8, &h->conf_mem);
+
+    memory_region_init_io(&h->data_mem, OBJECT(h), &pci_host_data_le_ops, s,
+                          "pci-conf-data", 4);
+    memory_region_add_subregion(&s->pci_io, 0xcfc, &h->data_mem);
+
+    memory_region_init_io(&h->mmcfg, OBJECT(s), &raven_pci_io_ops, s,
+                          "pciio", 0x00400000);
+    memory_region_add_subregion(address_space_mem, 0x80800000, &h->mmcfg);
+
+    memory_region_init_io(&s->pci_intack, OBJECT(s), &raven_intack_ops, s,
+                          "pci-intack", 1);
+    memory_region_add_subregion(address_space_mem, 0xbffffff0, &s->pci_intack);
+
+    /* TODO Remove once realize propagates to child devices. */
+    qdev_realize(DEVICE(&s->pci_dev), BUS(&s->pci_bus), errp);
+}
+
+static void raven_pcihost_initfn(Object *obj)
+{
+    PCIHostState *h = PCI_HOST_BRIDGE(obj);
+    PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(obj);
+    MemoryRegion *address_space_mem = get_system_memory();
+    DeviceState *pci_dev;
+
+    memory_region_init(&s->pci_io, obj, "pci-io", 0x3f800000);
+    memory_region_init_io(&s->pci_io_non_contiguous, obj, &raven_io_ops, s,
+                          "pci-io-non-contiguous", 0x00800000);
+    memory_region_init(&s->pci_memory, obj, "pci-memory", 0x3f000000);
+    address_space_init(&s->pci_io_as, &s->pci_io, "raven-io");
+
+    /* CPU address space */
+    memory_region_add_subregion(address_space_mem, PCI_IO_BASE_ADDR,
+                                &s->pci_io);
+    memory_region_add_subregion_overlap(address_space_mem, PCI_IO_BASE_ADDR,
+                                        &s->pci_io_non_contiguous, 1);
+    memory_region_add_subregion(address_space_mem, 0xc0000000, &s->pci_memory);
+    pci_root_bus_new_inplace(&s->pci_bus, sizeof(s->pci_bus), DEVICE(obj), NULL,
+                             &s->pci_memory, &s->pci_io, 0, TYPE_PCI_BUS);
+
+    /* Bus master address space */
+    memory_region_init(&s->bm, obj, "bm-raven", 4 * GiB);
+    memory_region_init_alias(&s->bm_pci_memory_alias, obj, "bm-pci-memory",
+                             &s->pci_memory, 0,
+                             memory_region_size(&s->pci_memory));
+    memory_region_init_alias(&s->bm_ram_alias, obj, "bm-system",
+                             get_system_memory(), 0, 0x80000000);
+    memory_region_add_subregion(&s->bm, 0         , &s->bm_pci_memory_alias);
+    memory_region_add_subregion(&s->bm, 0x80000000, &s->bm_ram_alias);
+    address_space_init(&s->bm_as, &s->bm, "raven-bm");
+    pci_setup_iommu(&s->pci_bus, raven_pcihost_set_iommu, s);
+
+    h->bus = &s->pci_bus;
+
+    object_initialize(&s->pci_dev, sizeof(s->pci_dev), TYPE_RAVEN_PCI_DEVICE);
+    pci_dev = DEVICE(&s->pci_dev);
+    object_property_set_int(OBJECT(&s->pci_dev), "addr", PCI_DEVFN(0, 0),
+                            NULL);
+    qdev_prop_set_bit(pci_dev, "multifunction", false);
+}
+
+static void raven_realize(PCIDevice *d, Error **errp)
+{
+    RavenPCIState *s = RAVEN_PCI_DEVICE(d);
+    char *filename;
+    int bios_size = -1;
+
+    d->config[0x0C] = 0x08; // cache_line_size
+    d->config[0x0D] = 0x10; // latency_timer
+    d->config[0x34] = 0x00; // capabilities_pointer
+
+    memory_region_init_rom_nomigrate(&s->bios, OBJECT(s), "bios", BIOS_SIZE,
+                                     &error_fatal);
+    memory_region_add_subregion(get_system_memory(), (uint32_t)(-BIOS_SIZE),
+                                &s->bios);
+    if (s->bios_name) {
+        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, s->bios_name);
+        if (filename) {
+            if (s->elf_machine != EM_NONE) {
+                bios_size = load_elf(filename, NULL, NULL, NULL, NULL,
+                                     NULL, NULL, NULL, 1, s->elf_machine,
+                                     0, 0);
+            }
+            if (bios_size < 0) {
+                bios_size = get_image_size(filename);
+                if (bios_size > 0 && bios_size <= BIOS_SIZE) {
+                    hwaddr bios_addr;
+                    bios_size = (bios_size + 0xfff) & ~0xfff;
+                    bios_addr = (uint32_t)(-BIOS_SIZE);
+                    bios_size = load_image_targphys(filename, bios_addr,
+                                                    bios_size);
+                }
+            }
+        }
+        g_free(filename);
+        if (bios_size < 0 || bios_size > BIOS_SIZE) {
+            memory_region_del_subregion(get_system_memory(), &s->bios);
+            error_setg(errp, "Could not load bios image '%s'", s->bios_name);
+            return;
+        }
+    }
+
+    vmstate_register_ram_global(&s->bios);
+}
+
+static const VMStateDescription vmstate_raven = {
+    .name = "raven",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(dev, RavenPCIState),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static void raven_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    k->realize = raven_realize;
+    k->vendor_id = PCI_VENDOR_ID_MOTOROLA;
+    k->device_id = PCI_DEVICE_ID_MOTOROLA_RAVEN;
+    k->revision = 0x00;
+    k->class_id = PCI_CLASS_BRIDGE_HOST;
+    dc->desc = "PReP Host Bridge - Motorola Raven";
+    dc->vmsd = &vmstate_raven;
+    /*
+     * Reason: PCI-facing part of the host bridge, not usable without
+     * the host-facing part, which can't be device_add'ed, yet.
+     */
+    dc->user_creatable = false;
+}
+
+static const TypeInfo raven_info = {
+    .name = TYPE_RAVEN_PCI_DEVICE,
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(RavenPCIState),
+    .class_init = raven_class_init,
+    .interfaces = (InterfaceInfo[]) {
+        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+        { },
+    },
+};
+
+static Property raven_pcihost_properties[] = {
+    DEFINE_PROP_UINT32("elf-machine", PREPPCIState, pci_dev.elf_machine,
+                       EM_NONE),
+    DEFINE_PROP_STRING("bios-name", PREPPCIState, pci_dev.bios_name),
+    /* Temporary workaround until legacy prep machine is removed */
+    DEFINE_PROP_BOOL("is-legacy-prep", PREPPCIState, is_legacy_prep,
+                     false),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static void raven_pcihost_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+    dc->realize = raven_pcihost_realizefn;
+    device_class_set_props(dc, raven_pcihost_properties);
+    dc->fw_name = "pci";
+}
+
+static const TypeInfo raven_pcihost_info = {
+    .name = TYPE_RAVEN_PCI_HOST_BRIDGE,
+    .parent = TYPE_PCI_HOST_BRIDGE,
+    .instance_size = sizeof(PREPPCIState),
+    .instance_init = raven_pcihost_initfn,
+    .class_init = raven_pcihost_class_init,
+};
+
+static void raven_register_types(void)
+{
+    type_register_static(&raven_pcihost_info);
+    type_register_static(&raven_info);
+}
+
+type_init(raven_register_types)
index 7fcafec60a4cff3d967dbd8708e98281b7a46fcc..322a7eb031e5cdcbd3de851cb5e4436def8dd9fc 100644 (file)
@@ -85,7 +85,7 @@ config PREP
     imply PCI_DEVICES
     imply TEST_DEVICES
     select CS4231A
-    select PREP_PCI
+    select RAVEN_PCI
     select I82378
     select LSI_SCSI_PCI
     select M48T59
index 327e9c93afa9dd0defda23edcd0dd4db43ed942d..28484256ec0b3ce9fd238177fa8115fb91c39ae7 100644 (file)
@@ -16,7 +16,6 @@ s390x_ss.add(files(
   'sclp.c',
   'sclpcpu.c',
   'sclpquiesce.c',
-  'tod-qemu.c',
   'tod.c',
 ))
 s390x_ss.add(when: 'CONFIG_KVM', if_true: files(
@@ -25,6 +24,9 @@ s390x_ss.add(when: 'CONFIG_KVM', if_true: files(
   's390-stattrib-kvm.c',
   'pv.c',
 ))
+s390x_ss.add(when: 'CONFIG_TCG', if_true: files(
+  'tod-tcg.c',
+))
 s390x_ss.add(when: 'CONFIG_S390_CCW_VIRTIO', if_true: files('s390-virtio-ccw.c'))
 s390x_ss.add(when: 'CONFIG_TERMINAL3270', if_true: files('3270-ccw.c'))
 s390x_ss.add(when: 'CONFIG_VFIO', if_true: files('s390-pci-vfio.c'))
index f0b11a74e49976f0d90163fa5c187959962a5be8..24cd01382e2d74d62c2d7e980eb6aca1077d893d 100644 (file)
@@ -16,7 +16,7 @@
 #include "qemu/error-report.h"
 #include "sysemu/kvm.h"
 #include "exec/ram_addr.h"
-#include "kvm_s390x.h"
+#include "kvm/kvm_s390x.h"
 
 Object *kvm_s390_stattrib_create(void)
 {
index 0b9447748619d735431d001b6dc860d401ba8bb6..ec855811aeb5cc855c2b9bc09d096d2ed48f2b38 100644 (file)
@@ -13,7 +13,7 @@
 #include "qemu/module.h"
 #include "sysemu/runstate.h"
 #include "hw/s390x/tod.h"
-#include "kvm_s390x.h"
+#include "kvm/kvm_s390x.h"
 
 static void kvm_s390_get_tod_raw(S390TOD *tod, Error **errp)
 {
diff --git a/hw/s390x/tod-qemu.c b/hw/s390x/tod-qemu.c
deleted file mode 100644 (file)
index e91b959..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * TOD (Time Of Day) clock - QEMU implementation
- *
- * Copyright 2018 Red Hat, Inc.
- * Author(s): David Hildenbrand <david@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qapi/error.h"
-#include "hw/s390x/tod.h"
-#include "qemu/timer.h"
-#include "qemu/cutils.h"
-#include "qemu/module.h"
-#include "cpu.h"
-#include "tcg_s390x.h"
-
-static void qemu_s390_tod_get(const S390TODState *td, S390TOD *tod,
-                              Error **errp)
-{
-    *tod = td->base;
-
-    tod->low += time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
-    if (tod->low < td->base.low) {
-        tod->high++;
-    }
-}
-
-static void qemu_s390_tod_set(S390TODState *td, const S390TOD *tod,
-                              Error **errp)
-{
-    CPUState *cpu;
-
-    td->base = *tod;
-
-    td->base.low -= time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
-    if (td->base.low > tod->low) {
-        td->base.high--;
-    }
-
-    /*
-     * The TOD has been changed and we have to recalculate the CKC values
-     * for all CPUs. We do this asynchronously, as "SET CLOCK should be
-     * issued only while all other activity on all CPUs .. has been
-     * suspended".
-     */
-    CPU_FOREACH(cpu) {
-        async_run_on_cpu(cpu, tcg_s390_tod_updated, RUN_ON_CPU_NULL);
-    }
-}
-
-static void qemu_s390_tod_class_init(ObjectClass *oc, void *data)
-{
-    S390TODClass *tdc = S390_TOD_CLASS(oc);
-
-    tdc->get = qemu_s390_tod_get;
-    tdc->set = qemu_s390_tod_set;
-}
-
-static void qemu_s390_tod_init(Object *obj)
-{
-    S390TODState *td = S390_TOD(obj);
-    struct tm tm;
-
-    qemu_get_timedate(&tm, 0);
-    td->base.high = 0;
-    td->base.low = TOD_UNIX_EPOCH + (time2tod(mktimegm(&tm)) * 1000000000ULL);
-    if (td->base.low < TOD_UNIX_EPOCH) {
-        td->base.high += 1;
-    }
-}
-
-static TypeInfo qemu_s390_tod_info = {
-    .name = TYPE_QEMU_S390_TOD,
-    .parent = TYPE_S390_TOD,
-    .instance_size = sizeof(S390TODState),
-    .instance_init = qemu_s390_tod_init,
-    .class_init = qemu_s390_tod_class_init,
-    .class_size = sizeof(S390TODClass),
-};
-
-static void register_types(void)
-{
-    type_register_static(&qemu_s390_tod_info);
-}
-type_init(register_types);
diff --git a/hw/s390x/tod-tcg.c b/hw/s390x/tod-tcg.c
new file mode 100644 (file)
index 0000000..9bb94ff
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * TOD (Time Of Day) clock - TCG implementation
+ *
+ * Copyright 2018 Red Hat, Inc.
+ * Author(s): David Hildenbrand <david@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qapi/error.h"
+#include "hw/s390x/tod.h"
+#include "qemu/timer.h"
+#include "qemu/cutils.h"
+#include "qemu/module.h"
+#include "cpu.h"
+#include "tcg/tcg_s390x.h"
+
+static void qemu_s390_tod_get(const S390TODState *td, S390TOD *tod,
+                              Error **errp)
+{
+    *tod = td->base;
+
+    tod->low += time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
+    if (tod->low < td->base.low) {
+        tod->high++;
+    }
+}
+
+static void qemu_s390_tod_set(S390TODState *td, const S390TOD *tod,
+                              Error **errp)
+{
+    CPUState *cpu;
+
+    td->base = *tod;
+
+    td->base.low -= time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
+    if (td->base.low > tod->low) {
+        td->base.high--;
+    }
+
+    /*
+     * The TOD has been changed and we have to recalculate the CKC values
+     * for all CPUs. We do this asynchronously, as "SET CLOCK should be
+     * issued only while all other activity on all CPUs .. has been
+     * suspended".
+     */
+    CPU_FOREACH(cpu) {
+        async_run_on_cpu(cpu, tcg_s390_tod_updated, RUN_ON_CPU_NULL);
+    }
+}
+
+static void qemu_s390_tod_class_init(ObjectClass *oc, void *data)
+{
+    S390TODClass *tdc = S390_TOD_CLASS(oc);
+
+    tdc->get = qemu_s390_tod_get;
+    tdc->set = qemu_s390_tod_set;
+}
+
+static void qemu_s390_tod_init(Object *obj)
+{
+    S390TODState *td = S390_TOD(obj);
+    struct tm tm;
+
+    qemu_get_timedate(&tm, 0);
+    td->base.high = 0;
+    td->base.low = TOD_UNIX_EPOCH + (time2tod(mktimegm(&tm)) * 1000000000ULL);
+    if (td->base.low < TOD_UNIX_EPOCH) {
+        td->base.high += 1;
+    }
+}
+
+static TypeInfo qemu_s390_tod_info = {
+    .name = TYPE_QEMU_S390_TOD,
+    .parent = TYPE_S390_TOD,
+    .instance_size = sizeof(S390TODState),
+    .instance_init = qemu_s390_tod_init,
+    .class_init = qemu_s390_tod_class_init,
+    .class_size = sizeof(S390TODClass),
+};
+
+static void register_types(void)
+{
+    type_register_static(&qemu_s390_tod_info);
+}
+type_init(register_types);
index 3c2979175ef7d83da027d038cda4a79f270b9254..fd5a36bf24ebfbcc73d6d56b86318f5fbb9b1414 100644 (file)
@@ -14,6 +14,8 @@
 #include "qemu/error-report.h"
 #include "qemu/module.h"
 #include "sysemu/kvm.h"
+#include "sysemu/tcg.h"
+#include "sysemu/qtest.h"
 #include "migration/qemu-file-types.h"
 #include "migration/register.h"
 
@@ -23,8 +25,13 @@ void s390_init_tod(void)
 
     if (kvm_enabled()) {
         obj = object_new(TYPE_KVM_S390_TOD);
-    } else {
+    } else if (tcg_enabled()) {
         obj = object_new(TYPE_QEMU_S390_TOD);
+    } else if (qtest_enabled()) {
+        return;
+    } else {
+        error_report("current accelerator not handled in s390_init_tod!");
+        abort();
     }
     object_property_add_child(qdev_get_machine(), TYPE_S390_TOD, obj);
     object_unref(obj);
index 282d39a704274ac2838c9c0810f0833ff762e0c8..1f964e022b15f42bea8b49799a047a0f8dcf8b94 100644 (file)
@@ -937,6 +937,19 @@ static void sd_lock_command(SDState *sd)
         sd->card_status &= ~CARD_IS_LOCKED;
 }
 
+static bool address_in_range(SDState *sd, const char *desc,
+                             uint64_t addr, uint32_t length)
+{
+    if (addr + length > sd->size) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s offset %"PRIu64" > card %"PRIu64" [%%%u]\n",
+                      desc, addr, sd->size, length);
+        sd->card_status |= ADDRESS_ERROR;
+        return false;
+    }
+    return true;
+}
+
 static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
 {
     uint32_t rca = 0x0000;
@@ -1218,8 +1231,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
         switch (sd->state) {
         case sd_transfer_state:
 
-            if (addr + sd->blk_len > sd->size) {
-                sd->card_status |= ADDRESS_ERROR;
+            if (!address_in_range(sd, "READ_BLOCK", addr, sd->blk_len)) {
                 return sd_r1;
             }
 
@@ -1264,8 +1276,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
         switch (sd->state) {
         case sd_transfer_state:
 
-            if (addr + sd->blk_len > sd->size) {
-                sd->card_status |= ADDRESS_ERROR;
+            if (!address_in_range(sd, "WRITE_BLOCK", addr, sd->blk_len)) {
                 return sd_r1;
             }
 
@@ -1325,8 +1336,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
 
         switch (sd->state) {
         case sd_transfer_state:
-            if (addr >= sd->size) {
-                sd->card_status |= ADDRESS_ERROR;
+            if (!address_in_range(sd, "SET_WRITE_PROT", addr, 1)) {
                 return sd_r1b;
             }
 
@@ -1348,8 +1358,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
 
         switch (sd->state) {
         case sd_transfer_state:
-            if (addr >= sd->size) {
-                sd->card_status |= ADDRESS_ERROR;
+            if (!address_in_range(sd, "CLR_WRITE_PROT", addr, 1)) {
                 return sd_r1b;
             }
 
@@ -1371,6 +1380,11 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
 
         switch (sd->state) {
         case sd_transfer_state:
+            if (!address_in_range(sd, "SEND_WRITE_PROT",
+                                  req.arg, sd->blk_len)) {
+                return sd_r1;
+            }
+
             sd->state = sd_sendingdata_state;
             *(uint32_t *) sd->data = sd_wpbits(sd, req.arg);
             sd->data_start = addr;
@@ -1504,7 +1518,8 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
         return sd_illegal;
     }
 
-    qemu_log_mask(LOG_GUEST_ERROR, "SD: CMD%i in a wrong state\n", req.cmd);
+    qemu_log_mask(LOG_GUEST_ERROR, "SD: CMD%i in a wrong state: %s\n",
+                  req.cmd, sd_state_name(sd->state));
     return sd_illegal;
 }
 
@@ -1825,8 +1840,8 @@ void sd_write_byte(SDState *sd, uint8_t value)
     case 25:   /* CMD25:  WRITE_MULTIPLE_BLOCK */
         if (sd->data_offset == 0) {
             /* Start of the block - let's check the address is valid */
-            if (sd->data_start + sd->blk_len > sd->size) {
-                sd->card_status |= ADDRESS_ERROR;
+            if (!address_in_range(sd, "WRITE_MULTIPLE_BLOCK",
+                                  sd->data_start, sd->blk_len)) {
                 break;
             }
             if (sd->size <= SDSC_MAX_CAPACITY) {
@@ -1998,8 +2013,8 @@ uint8_t sd_read_byte(SDState *sd)
 
     case 18:   /* CMD18:  READ_MULTIPLE_BLOCK */
         if (sd->data_offset == 0) {
-            if (sd->data_start + io_len > sd->size) {
-                sd->card_status |= ADDRESS_ERROR;
+            if (!address_in_range(sd, "READ_MULTIPLE_BLOCK",
+                                  sd->data_start, io_len)) {
                 return 0x00;
             }
             BLK_READ_BLOCK(sd->data_start, io_len);
index 4b32aca1a05e8fbac40ca966bed21436cbe38d28..e0dd561e85a32cdbe20444508d70fab67f09570a 100644 (file)
@@ -21,7 +21,7 @@
 #include "qemu/module.h"
 #include "qemu/option.h"
 #include "qemu/config-file.h"
-#include "kvm_s390x.h"
+#include "kvm/kvm_s390x.h"
 #include "migration/vmstate.h"
 #include "hw/qdev-properties.h"
 #include "hw/s390x/ap-bridge.h"
index ff3195a4bf8a584f2c25a0758570d437ddd02708..0935e850891014fa247c6788ea23908428ce31ac 100644 (file)
@@ -12,7 +12,7 @@
 #define HW_S390_TOD_H
 
 #include "hw/qdev-core.h"
-#include "target/s390x/s390-tod.h"
+#include "tcg/s390-tod.h"
 #include "qom/object.h"
 
 typedef struct S390TOD {
index dd7f9ed6a876c455ff1b88336cd73e0376708f96..b0e2b9a8a085456ae878ddb21a17b6d14283f4eb 100644 (file)
@@ -319,10 +319,6 @@ lttng = not_found
 if 'CONFIG_TRACE_UST' in config_host
   lttng = declare_dependency(link_args: config_host['LTTNG_UST_LIBS'].split())
 endif
-urcubp = not_found
-if 'CONFIG_TRACE_UST' in config_host
-  urcubp = declare_dependency(link_args: config_host['URCU_BP_LIBS'].split())
-endif
 pixman = not_found
 if have_system or have_tools
   pixman = dependency('pixman-1', required: have_system, version:'>=0.21.8',
@@ -2123,6 +2119,7 @@ if have_system or have_user
     'target/ppc',
     'target/riscv',
     'target/s390x',
+    'target/s390x/kvm',
     'target/sparc',
   ]
 endif
index b28874d6dc590a9edf4938dc9350edee99a73c53..ffe79668706204c4dbd27d93f32900d5da51a541 100644 (file)
@@ -1804,7 +1804,7 @@ void info_trace_events_completion(ReadLineState *rs, int nb_args, const char *st
         TraceEventIter iter;
         TraceEvent *ev;
         char *pattern = g_strdup_printf("%s*", str);
-        trace_event_iter_init(&iter, pattern);
+        trace_event_iter_init_pattern(&iter, pattern);
         while ((ev = trace_event_iter_next(&iter)) != NULL) {
             readline_add_completion(rs, trace_event_get_name(ev));
         }
@@ -1822,7 +1822,7 @@ void trace_event_completion(ReadLineState *rs, int nb_args, const char *str)
         TraceEventIter iter;
         TraceEvent *ev;
         char *pattern = g_strdup_printf("%s*", str);
-        trace_event_iter_init(&iter, pattern);
+        trace_event_iter_init_pattern(&iter, pattern);
         while ((ev = trace_event_iter_next(&iter)) != NULL) {
             readline_add_completion(rs, trace_event_get_name(ev));
         }
index 90527eb974f4c4707e1422b8bafac55cb36615d8..eb6e951ff235940bdb6ba3e1b6c11f0afcc7074e 100755 (executable)
@@ -55,11 +55,6 @@ def tapset_dir(binary):
     return os.path.realpath(tapset)
 
 
-def tapset_env(tapset_dir):
-    tenv = copy.copy(os.environ)
-    tenv["SYSTEMTAP_TAPSET"] = tapset_dir
-    return tenv
-
 def cmd_run(args):
     prefix = probe_prefix(args.binary)
     tapsets = tapset_dir(args.binary)
@@ -81,11 +76,11 @@ def cmd_run(args):
 
     # We request an 8MB buffer, since the stap default 1MB buffer
     # can be easily overflowed by frequently firing QEMU traces
-    stapargs = ["stap", "-s", "8"]
+    stapargs = ["stap", "-s", "8", "-I", tapsets ]
     if args.pid is not None:
         stapargs.extend(["-x", args.pid])
     stapargs.extend(["-e", script])
-    subprocess.call(stapargs, env=tapset_env(tapsets))
+    subprocess.call(stapargs)
 
 
 def cmd_list(args):
@@ -101,10 +96,9 @@ def cmd_list(args):
 
         if verbose:
             print("Listing probes with name '%s'" % script)
-        proc = subprocess.Popen(["stap", "-l", script],
+        proc = subprocess.Popen(["stap", "-I", tapsets, "-l", script],
                                 stdout=subprocess.PIPE,
-                                universal_newlines=True,
-                                env=tapset_env(tapsets))
+                                universal_newlines=True)
         out, err = proc.communicate()
         if proc.returncode != 0:
             print("No probes found, are the tapsets installed in %s" % tapset_dir(args.binary))
index 77108b0b1a9c3e07ae33506e12e26735a4facaec..b4a383ae90c32aba2c420bc7f3b5600e45a90538 100644 (file)
@@ -74,25 +74,19 @@ enum UHIOpenFlags {
     UHIOpen_EXCL   = 0x800
 };
 
-/* Errno values taken from asm-mips/errno.h */
-static const uint16_t host_to_mips_errno[] = {
-    [ENAMETOOLONG] = 78,
+static int errno_mips(int host_errno)
+{
+    /* Errno values taken from asm-mips/errno.h */
+    switch (host_errno) {
+    case 0:             return 0;
+    case ENAMETOOLONG:  return 78;
 #ifdef EOVERFLOW
-    [EOVERFLOW]    = 79,
+    case EOVERFLOW:     return 79;
 #endif
 #ifdef ELOOP
-    [ELOOP]        = 90,
+    case ELOOP:         return 90;
 #endif
-};
-
-static int errno_mips(int err)
-{
-    if (err < 0 || err >= ARRAY_SIZE(host_to_mips_errno)) {
-        return EINVAL;
-    } else if (host_to_mips_errno[err]) {
-        return host_to_mips_errno[err];
-    } else {
-        return err;
+    default:            return EINVAL;
     }
 }
 
index 47c967acbfd689a08b4ec82a9ebbb9e3f378944e..fd980ea9663d6a671016707823a34d5a4c3d7a8f 100644 (file)
@@ -1179,7 +1179,6 @@ enum {
 
 enum {
     MMI_OPC_CLASS_MMI = 0x1C << 26,    /* Same as OPC_SPECIAL2 */
-    MMI_OPC_LQ        = 0x1E << 26,    /* Same as OPC_MSA */
     MMI_OPC_SQ        = 0x1F << 26,    /* Same as OPC_SPECIAL3 */
 };
 
@@ -15166,11 +15165,6 @@ static void decode_mmi(CPUMIPSState *env, DisasContext *ctx)
     }
 }
 
-static void gen_mmi_lq(CPUMIPSState *env, DisasContext *ctx)
-{
-    gen_reserved_instruction(ctx);    /* TODO: MMI_OPC_LQ */
-}
-
 static void gen_mmi_sq(DisasContext *ctx, int base, int rt, int offset)
 {
     gen_reserved_instruction(ctx);    /* TODO: MMI_OPC_SQ */
@@ -16069,14 +16063,8 @@ static bool decode_opc_legacy(CPUMIPSState *env, DisasContext *ctx)
             gen_compute_branch(ctx, op, 4, rs, rt, offset, 4);
         }
         break;
-    case OPC_MDMX: /* MMI_OPC_LQ */
-        if (ctx->insn_flags & INSN_R5900) {
-#if defined(TARGET_MIPS64)
-            gen_mmi_lq(env, ctx);
-#endif
-        } else {
-            /* MDMX: Not implemented. */
-        }
+    case OPC_MDMX:
+        /* MDMX: Not implemented. */
         break;
     case OPC_PCREL:
         check_insn(ctx, ISA_MIPS_R6);
index 0f748b53a64a458a389bf192a8f18dcb1e5947f6..03a25a5096d1cbfc318a704133f0fc8035b202c0 100644 (file)
@@ -13,6 +13,8 @@
 
 &rtype           rs rt rd sa
 
+&itype           base rt offset
+
 ###########################################################################
 # Named instruction formats.  These are generally used to
 # reduce the amount of duplication between instruction patterns.
@@ -22,6 +24,8 @@
 @rs             ...... rs:5  ..... ..........  ......   &rtype rt=0 rd=0 sa=0
 @rd             ...... ..........  rd:5  ..... ......   &rtype rs=0 rt=0 sa=0
 
+@ldst            ...... base:5 rt:5 offset:16            &itype
+
 ###########################################################################
 
 MFHI1           011100 0000000000  ..... 00000 010000   @rd
@@ -29,11 +33,41 @@ MTHI1           011100 .....  0000000000 00000 010001   @rs
 MFLO1           011100 0000000000  ..... 00000 010010   @rd
 MTLO1           011100 .....  0000000000 00000 010011   @rs
 
+# MMI0
+
+PSUBW           011100 ..... ..... ..... 00001 001000   @rs_rt_rd
+PCGTW           011100 ..... ..... ..... 00010 001000   @rs_rt_rd
+PSUBH           011100 ..... ..... ..... 00101 001000   @rs_rt_rd
+PCGTH           011100 ..... ..... ..... 00110 001000   @rs_rt_rd
+PSUBB           011100 ..... ..... ..... 01001 001000   @rs_rt_rd
+PCGTB           011100 ..... ..... ..... 01010 001000   @rs_rt_rd
+PEXTLW          011100 ..... ..... ..... 10010 001000   @rs_rt_rd
+PPACW           011100 ..... ..... ..... 10011 001000   @rs_rt_rd
+PEXTLH          011100 ..... ..... ..... 10110 001000   @rs_rt_rd
+PEXTLB          011100 ..... ..... ..... 11010 001000   @rs_rt_rd
+
+# MMI1
+
+PCEQW           011100 ..... ..... ..... 00010 101000   @rs_rt_rd
+PCEQH           011100 ..... ..... ..... 00110 101000   @rs_rt_rd
+PCEQB           011100 ..... ..... ..... 01010 101000   @rs_rt_rd
+PEXTUW          011100 ..... ..... ..... 10010 101000   @rs_rt_rd
+
 # MMI2
 
 PCPYLD          011100 ..... ..... ..... 01110 001001   @rs_rt_rd
+PAND            011100 ..... ..... ..... 10010 001001   @rs_rt_rd
+PXOR            011100 ..... ..... ..... 10011 001001   @rs_rt_rd
+PROT3W          011100 00000 ..... ..... 11111 001001   @rt_rd
 
 # MMI3
 
 PCPYUD          011100 ..... ..... ..... 01110 101001   @rs_rt_rd
+POR             011100 ..... ..... ..... 10010 101001   @rs_rt_rd
+PNOR            011100 ..... ..... ..... 10011 101001   @rs_rt_rd
 PCPYH           011100 00000 ..... ..... 11011 101001   @rt_rd
+
+# SPECIAL
+
+LQ              011110 ..... ..... ................     @ldst
+SQ              011111 ..... ..... ................     @ldst
index ad83774b977cb8ae128f1431cb952efda8a6d79f..395d6afa1f105c2ecb61095e18972e17c696a9a3 100644 (file)
@@ -2,12 +2,14 @@
  * Toshiba TX79-specific instructions translation routines
  *
  *  Copyright (c) 2018 Fredrik Noring
+ *  Copyright (c) 2021 Philippe Mathieu-Daudé
  *
  * SPDX-License-Identifier: GPL-2.0-or-later
  */
 
 #include "qemu/osdep.h"
 #include "tcg/tcg-op.h"
+#include "tcg/tcg-op-gvec.h"
 #include "exec/helper-gen.h"
 #include "translate.h"
 
@@ -114,6 +116,53 @@ static bool trans_MTLO1(DisasContext *ctx, arg_rtype *a)
  * PSUBUW  rd, rs, rt        Parallel Subtract with Unsigned saturation Word
  */
 
+static bool trans_parallel_arith(DisasContext *ctx, arg_rtype *a,
+                                 void (*gen_logic_i64)(TCGv_i64, TCGv_i64, TCGv_i64))
+{
+    TCGv_i64 ax, bx;
+
+    if (a->rd == 0) {
+        /* nop */
+        return true;
+    }
+
+    ax = tcg_temp_new_i64();
+    bx = tcg_temp_new_i64();
+
+    /* Lower half */
+    gen_load_gpr(ax, a->rs);
+    gen_load_gpr(bx, a->rt);
+    gen_logic_i64(cpu_gpr[a->rd], ax, bx);
+
+    /* Upper half */
+    gen_load_gpr_hi(ax, a->rs);
+    gen_load_gpr_hi(bx, a->rt);
+    gen_logic_i64(cpu_gpr_hi[a->rd], ax, bx);
+
+    tcg_temp_free(bx);
+    tcg_temp_free(ax);
+
+    return true;
+}
+
+/* Parallel Subtract Byte */
+static bool trans_PSUBB(DisasContext *ctx, arg_rtype *a)
+{
+    return trans_parallel_arith(ctx, a, tcg_gen_vec_sub8_i64);
+}
+
+/* Parallel Subtract Halfword */
+static bool trans_PSUBH(DisasContext *ctx, arg_rtype *a)
+{
+    return trans_parallel_arith(ctx, a, tcg_gen_vec_sub16_i64);
+}
+
+/* Parallel Subtract Word */
+static bool trans_PSUBW(DisasContext *ctx, arg_rtype *a)
+{
+    return trans_parallel_arith(ctx, a, tcg_gen_vec_sub32_i64);
+}
+
 /*
  *     Min/Max (4 instructions)
  *     ------------------------
@@ -139,6 +188,30 @@ static bool trans_MTLO1(DisasContext *ctx, arg_rtype *a)
  * PNOR    rd, rs, rt        Parallel NOR
  */
 
+/* Parallel And */
+static bool trans_PAND(DisasContext *ctx, arg_rtype *a)
+{
+    return trans_parallel_arith(ctx, a, tcg_gen_and_i64);
+}
+
+/* Parallel Or */
+static bool trans_POR(DisasContext *ctx, arg_rtype *a)
+{
+    return trans_parallel_arith(ctx, a, tcg_gen_or_i64);
+}
+
+/* Parallel Exclusive Or */
+static bool trans_PXOR(DisasContext *ctx, arg_rtype *a)
+{
+    return trans_parallel_arith(ctx, a, tcg_gen_xor_i64);
+}
+
+/* Parallel Not Or */
+static bool trans_PNOR(DisasContext *ctx, arg_rtype *a)
+{
+    return trans_parallel_arith(ctx, a, tcg_gen_nor_i64);
+}
+
 /*
  *     Shift (9 instructions)
  *     ----------------------
@@ -164,6 +237,90 @@ static bool trans_MTLO1(DisasContext *ctx, arg_rtype *a)
  * PCEQW   rd, rs, rt        Parallel Compare for Equal Word
  */
 
+static bool trans_parallel_compare(DisasContext *ctx, arg_rtype *a,
+                                   TCGCond cond, unsigned wlen)
+{
+    TCGv_i64 c0, c1, ax, bx, t0, t1, t2;
+
+    if (a->rd == 0) {
+        /* nop */
+        return true;
+    }
+
+    c0 = tcg_const_tl(0);
+    c1 = tcg_const_tl(0xffffffff);
+    ax = tcg_temp_new_i64();
+    bx = tcg_temp_new_i64();
+    t0 = tcg_temp_new_i64();
+    t1 = tcg_temp_new_i64();
+    t2 = tcg_temp_new_i64();
+
+    /* Lower half */
+    gen_load_gpr(ax, a->rs);
+    gen_load_gpr(bx, a->rt);
+    for (int i = 0; i < (64 / wlen); i++) {
+        tcg_gen_sextract_i64(t0, ax, wlen * i, wlen);
+        tcg_gen_sextract_i64(t1, bx, wlen * i, wlen);
+        tcg_gen_movcond_i64(cond, t2, t1, t0, c1, c0);
+        tcg_gen_deposit_i64(cpu_gpr[a->rd], cpu_gpr[a->rd], t2, wlen * i, wlen);
+    }
+    /* Upper half */
+    gen_load_gpr_hi(ax, a->rs);
+    gen_load_gpr_hi(bx, a->rt);
+    for (int i = 0; i < (64 / wlen); i++) {
+        tcg_gen_sextract_i64(t0, ax, wlen * i, wlen);
+        tcg_gen_sextract_i64(t1, bx, wlen * i, wlen);
+        tcg_gen_movcond_i64(cond, t2, t1, t0, c1, c0);
+        tcg_gen_deposit_i64(cpu_gpr_hi[a->rd], cpu_gpr_hi[a->rd], t2, wlen * i, wlen);
+    }
+
+    tcg_temp_free(t2);
+    tcg_temp_free(t1);
+    tcg_temp_free(t0);
+    tcg_temp_free(bx);
+    tcg_temp_free(ax);
+    tcg_temp_free(c1);
+    tcg_temp_free(c0);
+
+    return true;
+}
+
+/* Parallel Compare for Greater Than Byte */
+static bool trans_PCGTB(DisasContext *ctx, arg_rtype *a)
+{
+    return trans_parallel_compare(ctx, a, TCG_COND_GE, 8);
+}
+
+/* Parallel Compare for Equal Byte */
+static bool trans_PCEQB(DisasContext *ctx, arg_rtype *a)
+{
+    return trans_parallel_compare(ctx, a, TCG_COND_EQ, 8);
+}
+
+/* Parallel Compare for Greater Than Halfword */
+static bool trans_PCGTH(DisasContext *ctx, arg_rtype *a)
+{
+    return trans_parallel_compare(ctx, a, TCG_COND_GE, 16);
+}
+
+/* Parallel Compare for Equal Halfword */
+static bool trans_PCEQH(DisasContext *ctx, arg_rtype *a)
+{
+    return trans_parallel_compare(ctx, a, TCG_COND_EQ, 16);
+}
+
+/* Parallel Compare for Greater Than Word */
+static bool trans_PCGTW(DisasContext *ctx, arg_rtype *a)
+{
+    return trans_parallel_compare(ctx, a, TCG_COND_GE, 32);
+}
+
+/* Parallel Compare for Equal Word */
+static bool trans_PCEQW(DisasContext *ctx, arg_rtype *a)
+{
+    return trans_parallel_compare(ctx, a, TCG_COND_EQ, 32);
+}
+
 /*
  *     LZC (1 instruction)
  *     -------------------
@@ -177,6 +334,68 @@ static bool trans_MTLO1(DisasContext *ctx, arg_rtype *a)
  * SQ      rt, offset(base)  Store Quadword
  */
 
+static bool trans_LQ(DisasContext *ctx, arg_itype *a)
+{
+    TCGv_i64 t0;
+    TCGv addr;
+
+    if (a->rt == 0) {
+        /* nop */
+        return true;
+    }
+
+    t0 = tcg_temp_new_i64();
+    addr = tcg_temp_new();
+
+    gen_base_offset_addr(ctx, addr, a->base, a->offset);
+    /*
+     * Clear least-significant four bits of the effective
+     * address, effectively creating an aligned address.
+     */
+    tcg_gen_andi_tl(addr, addr, ~0xf);
+
+    /* Lower half */
+    tcg_gen_qemu_ld_i64(t0, addr, ctx->mem_idx, MO_TEQ);
+    gen_store_gpr(t0, a->rt);
+
+    /* Upper half */
+    tcg_gen_addi_i64(addr, addr, 8);
+    tcg_gen_qemu_ld_i64(t0, addr, ctx->mem_idx, MO_TEQ);
+    gen_store_gpr_hi(t0, a->rt);
+
+    tcg_temp_free(t0);
+    tcg_temp_free(addr);
+
+    return true;
+}
+
+static bool trans_SQ(DisasContext *ctx, arg_itype *a)
+{
+    TCGv_i64 t0 = tcg_temp_new_i64();
+    TCGv addr = tcg_temp_new();
+
+    gen_base_offset_addr(ctx, addr, a->base, a->offset);
+    /*
+     * Clear least-significant four bits of the effective
+     * address, effectively creating an aligned address.
+     */
+    tcg_gen_andi_tl(addr, addr, ~0xf);
+
+    /* Lower half */
+    gen_load_gpr(t0, a->rt);
+    tcg_gen_qemu_st_i64(t0, addr, ctx->mem_idx, MO_TEQ);
+
+    /* Upper half */
+    tcg_gen_addi_i64(addr, addr, 8);
+    gen_load_gpr_hi(t0, a->rt);
+    tcg_gen_qemu_st_i64(t0, addr, ctx->mem_idx, MO_TEQ);
+
+    tcg_temp_free(addr);
+    tcg_temp_free(t0);
+
+    return true;
+}
+
 /*
  *     Multiply and Divide (19 instructions)
  *     -------------------------------------
@@ -217,6 +436,141 @@ static bool trans_MTLO1(DisasContext *ctx, arg_rtype *a)
  * PEXTLW  rd, rs, rt        Parallel Extend Lower from Word
  */
 
+/* Parallel Pack to Word */
+static bool trans_PPACW(DisasContext *ctx, arg_rtype *a)
+{
+    TCGv_i64 a0, b0, t0;
+
+    if (a->rd == 0) {
+        /* nop */
+        return true;
+    }
+
+    a0 = tcg_temp_new_i64();
+    b0 = tcg_temp_new_i64();
+    t0 = tcg_temp_new_i64();
+
+    gen_load_gpr(a0, a->rs);
+    gen_load_gpr(b0, a->rt);
+
+    gen_load_gpr_hi(t0, a->rt); /* b1 */
+    tcg_gen_deposit_i64(cpu_gpr[a->rd], b0, t0, 32, 32);
+
+    gen_load_gpr_hi(t0, a->rs); /* a1 */
+    tcg_gen_deposit_i64(cpu_gpr_hi[a->rd], a0, t0, 32, 32);
+
+    tcg_temp_free(t0);
+    tcg_temp_free(b0);
+    tcg_temp_free(a0);
+
+    return true;
+}
+
+static void gen_pextw(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 a, TCGv_i64 b)
+{
+    tcg_gen_deposit_i64(dl, b, a, 32, 32);
+    tcg_gen_shri_i64(b, b, 32);
+    tcg_gen_deposit_i64(dh, a, b, 0, 32);
+}
+
+static bool trans_PEXTLx(DisasContext *ctx, arg_rtype *a, unsigned wlen)
+{
+    TCGv_i64 ax, bx;
+
+    if (a->rd == 0) {
+        /* nop */
+        return true;
+    }
+
+    ax = tcg_temp_new_i64();
+    bx = tcg_temp_new_i64();
+
+    gen_load_gpr(ax, a->rs);
+    gen_load_gpr(bx, a->rt);
+
+    /* Lower half */
+    for (int i = 0; i < 64 / (2 * wlen); i++) {
+        tcg_gen_deposit_i64(cpu_gpr[a->rd],
+                            cpu_gpr[a->rd], bx, 2 * wlen * i, wlen);
+        tcg_gen_deposit_i64(cpu_gpr[a->rd],
+                            cpu_gpr[a->rd], ax, 2 * wlen * i + wlen, wlen);
+        tcg_gen_shri_i64(bx, bx, wlen);
+        tcg_gen_shri_i64(ax, ax, wlen);
+    }
+    /* Upper half */
+    for (int i = 0; i < 64 / (2 * wlen); i++) {
+        tcg_gen_deposit_i64(cpu_gpr_hi[a->rd],
+                            cpu_gpr_hi[a->rd], bx, 2 * wlen * i, wlen);
+        tcg_gen_deposit_i64(cpu_gpr_hi[a->rd],
+                            cpu_gpr_hi[a->rd], ax, 2 * wlen * i + wlen, wlen);
+        tcg_gen_shri_i64(bx, bx, wlen);
+        tcg_gen_shri_i64(ax, ax, wlen);
+    }
+
+    tcg_temp_free(bx);
+    tcg_temp_free(ax);
+
+    return true;
+}
+
+/* Parallel Extend Lower from Byte */
+static bool trans_PEXTLB(DisasContext *ctx, arg_rtype *a)
+{
+    return trans_PEXTLx(ctx, a, 8);
+}
+
+/* Parallel Extend Lower from Halfword */
+static bool trans_PEXTLH(DisasContext *ctx, arg_rtype *a)
+{
+    return trans_PEXTLx(ctx, a, 16);
+}
+
+/* Parallel Extend Lower from Word */
+static bool trans_PEXTLW(DisasContext *ctx, arg_rtype *a)
+{
+    TCGv_i64 ax, bx;
+
+    if (a->rd == 0) {
+        /* nop */
+        return true;
+    }
+
+    ax = tcg_temp_new_i64();
+    bx = tcg_temp_new_i64();
+
+    gen_load_gpr(ax, a->rs);
+    gen_load_gpr(bx, a->rt);
+    gen_pextw(cpu_gpr[a->rd], cpu_gpr_hi[a->rd], ax, bx);
+
+    tcg_temp_free(bx);
+    tcg_temp_free(ax);
+
+    return true;
+}
+
+/* Parallel Extend Upper from Word */
+static bool trans_PEXTUW(DisasContext *ctx, arg_rtype *a)
+{
+    TCGv_i64 ax, bx;
+
+    if (a->rd == 0) {
+        /* nop */
+        return true;
+    }
+
+    ax = tcg_temp_new_i64();
+    bx = tcg_temp_new_i64();
+
+    gen_load_gpr_hi(ax, a->rs);
+    gen_load_gpr_hi(bx, a->rt);
+    gen_pextw(cpu_gpr[a->rd], cpu_gpr_hi[a->rd], ax, bx);
+
+    tcg_temp_free(bx);
+    tcg_temp_free(ax);
+
+    return true;
+}
+
 /*
  *     Others (16 instructions)
  *     ------------------------
@@ -301,3 +655,31 @@ static bool trans_PCPYUD(DisasContext *s, arg_rtype *a)
 
     return true;
 }
+
+/* Parallel Rotate 3 Words Left */
+static bool trans_PROT3W(DisasContext *ctx, arg_rtype *a)
+{
+    TCGv_i64 ax;
+
+    if (a->rd == 0) {
+        /* nop */
+        return true;
+    }
+    if (a->rt == 0) {
+        tcg_gen_movi_i64(cpu_gpr[a->rd], 0);
+        tcg_gen_movi_i64(cpu_gpr_hi[a->rd], 0);
+        return true;
+    }
+
+    ax = tcg_temp_new_i64();
+
+    tcg_gen_mov_i64(ax, cpu_gpr_hi[a->rt]);
+    tcg_gen_deposit_i64(cpu_gpr_hi[a->rd], ax, cpu_gpr[a->rt], 0, 32);
+
+    tcg_gen_deposit_i64(cpu_gpr[a->rd], cpu_gpr[a->rt], ax, 0, 32);
+    tcg_gen_rotri_i64(cpu_gpr[a->rd], cpu_gpr[a->rd], 32);
+
+    tcg_temp_free(ax);
+
+    return true;
+}
index cc1330876befe1f5a8d0f6a14d1ae64ffa1c2f74..08daf93ae1f09fffb08a6d94b4deb0852df07b2f 100644 (file)
@@ -13,7 +13,7 @@
 
 #include "qemu/osdep.h"
 #include "cpu.h"
-#include "internal.h"
+#include "s390x-internal.h"
 #include "elf.h"
 #include "sysemu/dump.h"
 
diff --git a/target/s390x/cc_helper.c b/target/s390x/cc_helper.c
deleted file mode 100644 (file)
index e7a74d6..0000000
+++ /dev/null
@@ -1,538 +0,0 @@
-/*
- *  S/390 condition code helper routines
- *
- *  Copyright (c) 2009 Ulrich Hecht
- *  Copyright (c) 2009 Alexander Graf
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "internal.h"
-#include "tcg_s390x.h"
-#include "exec/exec-all.h"
-#include "exec/helper-proto.h"
-#include "qemu/host-utils.h"
-
-/* #define DEBUG_HELPER */
-#ifdef DEBUG_HELPER
-#define HELPER_LOG(x...) qemu_log(x)
-#else
-#define HELPER_LOG(x...)
-#endif
-
-static uint32_t cc_calc_ltgt_32(int32_t src, int32_t dst)
-{
-    if (src == dst) {
-        return 0;
-    } else if (src < dst) {
-        return 1;
-    } else {
-        return 2;
-    }
-}
-
-static uint32_t cc_calc_ltgt0_32(int32_t dst)
-{
-    return cc_calc_ltgt_32(dst, 0);
-}
-
-static uint32_t cc_calc_ltgt_64(int64_t src, int64_t dst)
-{
-    if (src == dst) {
-        return 0;
-    } else if (src < dst) {
-        return 1;
-    } else {
-        return 2;
-    }
-}
-
-static uint32_t cc_calc_ltgt0_64(int64_t dst)
-{
-    return cc_calc_ltgt_64(dst, 0);
-}
-
-static uint32_t cc_calc_ltugtu_32(uint32_t src, uint32_t dst)
-{
-    if (src == dst) {
-        return 0;
-    } else if (src < dst) {
-        return 1;
-    } else {
-        return 2;
-    }
-}
-
-static uint32_t cc_calc_ltugtu_64(uint64_t src, uint64_t dst)
-{
-    if (src == dst) {
-        return 0;
-    } else if (src < dst) {
-        return 1;
-    } else {
-        return 2;
-    }
-}
-
-static uint32_t cc_calc_tm_32(uint32_t val, uint32_t mask)
-{
-    uint32_t r = val & mask;
-
-    if (r == 0) {
-        return 0;
-    } else if (r == mask) {
-        return 3;
-    } else {
-        return 1;
-    }
-}
-
-static uint32_t cc_calc_tm_64(uint64_t val, uint64_t mask)
-{
-    uint64_t r = val & mask;
-
-    if (r == 0) {
-        return 0;
-    } else if (r == mask) {
-        return 3;
-    } else {
-        int top = clz64(mask);
-        if ((int64_t)(val << top) < 0) {
-            return 2;
-        } else {
-            return 1;
-        }
-    }
-}
-
-static uint32_t cc_calc_nz(uint64_t dst)
-{
-    return !!dst;
-}
-
-static uint32_t cc_calc_addu(uint64_t carry_out, uint64_t result)
-{
-    g_assert(carry_out <= 1);
-    return (result != 0) + 2 * carry_out;
-}
-
-static uint32_t cc_calc_subu(uint64_t borrow_out, uint64_t result)
-{
-    return cc_calc_addu(borrow_out + 1, result);
-}
-
-static uint32_t cc_calc_add_64(int64_t a1, int64_t a2, int64_t ar)
-{
-    if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
-        return 3; /* overflow */
-    } else {
-        if (ar < 0) {
-            return 1;
-        } else if (ar > 0) {
-            return 2;
-        } else {
-            return 0;
-        }
-    }
-}
-
-static uint32_t cc_calc_sub_64(int64_t a1, int64_t a2, int64_t ar)
-{
-    if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
-        return 3; /* overflow */
-    } else {
-        if (ar < 0) {
-            return 1;
-        } else if (ar > 0) {
-            return 2;
-        } else {
-            return 0;
-        }
-    }
-}
-
-static uint32_t cc_calc_abs_64(int64_t dst)
-{
-    if ((uint64_t)dst == 0x8000000000000000ULL) {
-        return 3;
-    } else if (dst) {
-        return 2;
-    } else {
-        return 0;
-    }
-}
-
-static uint32_t cc_calc_nabs_64(int64_t dst)
-{
-    return !!dst;
-}
-
-static uint32_t cc_calc_comp_64(int64_t dst)
-{
-    if ((uint64_t)dst == 0x8000000000000000ULL) {
-        return 3;
-    } else if (dst < 0) {
-        return 1;
-    } else if (dst > 0) {
-        return 2;
-    } else {
-        return 0;
-    }
-}
-
-
-static uint32_t cc_calc_add_32(int32_t a1, int32_t a2, int32_t ar)
-{
-    if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
-        return 3; /* overflow */
-    } else {
-        if (ar < 0) {
-            return 1;
-        } else if (ar > 0) {
-            return 2;
-        } else {
-            return 0;
-        }
-    }
-}
-
-static uint32_t cc_calc_sub_32(int32_t a1, int32_t a2, int32_t ar)
-{
-    if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
-        return 3; /* overflow */
-    } else {
-        if (ar < 0) {
-            return 1;
-        } else if (ar > 0) {
-            return 2;
-        } else {
-            return 0;
-        }
-    }
-}
-
-static uint32_t cc_calc_abs_32(int32_t dst)
-{
-    if ((uint32_t)dst == 0x80000000UL) {
-        return 3;
-    } else if (dst) {
-        return 2;
-    } else {
-        return 0;
-    }
-}
-
-static uint32_t cc_calc_nabs_32(int32_t dst)
-{
-    return !!dst;
-}
-
-static uint32_t cc_calc_comp_32(int32_t dst)
-{
-    if ((uint32_t)dst == 0x80000000UL) {
-        return 3;
-    } else if (dst < 0) {
-        return 1;
-    } else if (dst > 0) {
-        return 2;
-    } else {
-        return 0;
-    }
-}
-
-/* calculate condition code for insert character under mask insn */
-static uint32_t cc_calc_icm(uint64_t mask, uint64_t val)
-{
-    if ((val & mask) == 0) {
-        return 0;
-    } else {
-        int top = clz64(mask);
-        if ((int64_t)(val << top) < 0) {
-            return 1;
-        } else {
-            return 2;
-        }
-    }
-}
-
-static uint32_t cc_calc_sla_32(uint32_t src, int shift)
-{
-    uint32_t mask = ((1U << shift) - 1U) << (32 - shift);
-    uint32_t sign = 1U << 31;
-    uint32_t match;
-    int32_t r;
-
-    /* Check if the sign bit stays the same.  */
-    if (src & sign) {
-        match = mask;
-    } else {
-        match = 0;
-    }
-    if ((src & mask) != match) {
-        /* Overflow.  */
-        return 3;
-    }
-
-    r = ((src << shift) & ~sign) | (src & sign);
-    if (r == 0) {
-        return 0;
-    } else if (r < 0) {
-        return 1;
-    }
-    return 2;
-}
-
-static uint32_t cc_calc_sla_64(uint64_t src, int shift)
-{
-    uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift);
-    uint64_t sign = 1ULL << 63;
-    uint64_t match;
-    int64_t r;
-
-    /* Check if the sign bit stays the same.  */
-    if (src & sign) {
-        match = mask;
-    } else {
-        match = 0;
-    }
-    if ((src & mask) != match) {
-        /* Overflow.  */
-        return 3;
-    }
-
-    r = ((src << shift) & ~sign) | (src & sign);
-    if (r == 0) {
-        return 0;
-    } else if (r < 0) {
-        return 1;
-    }
-    return 2;
-}
-
-static uint32_t cc_calc_flogr(uint64_t dst)
-{
-    return dst ? 2 : 0;
-}
-
-static uint32_t cc_calc_lcbb(uint64_t dst)
-{
-    return dst == 16 ? 0 : 3;
-}
-
-static uint32_t cc_calc_vc(uint64_t low, uint64_t high)
-{
-    if (high == -1ull && low == -1ull) {
-        /* all elements match */
-        return 0;
-    } else if (high == 0 && low == 0) {
-        /* no elements match */
-        return 3;
-    } else {
-        /* some elements but not all match */
-        return 1;
-    }
-}
-
-static uint32_t cc_calc_muls_32(int64_t res)
-{
-    const int64_t tmp = res >> 31;
-
-    if (!res) {
-        return 0;
-    } else if (tmp && tmp != -1) {
-        return 3;
-    } else if (res < 0) {
-        return 1;
-    }
-    return 2;
-}
-
-static uint64_t cc_calc_muls_64(int64_t res_high, uint64_t res_low)
-{
-    if (!res_high && !res_low) {
-        return 0;
-    } else if (res_high + (res_low >> 63) != 0) {
-        return 3;
-    } else if (res_high < 0) {
-        return 1;
-    }
-    return 2;
-}
-
-static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op,
-                                  uint64_t src, uint64_t dst, uint64_t vr)
-{
-    uint32_t r = 0;
-
-    switch (cc_op) {
-    case CC_OP_CONST0:
-    case CC_OP_CONST1:
-    case CC_OP_CONST2:
-    case CC_OP_CONST3:
-        /* cc_op value _is_ cc */
-        r = cc_op;
-        break;
-    case CC_OP_LTGT0_32:
-        r = cc_calc_ltgt0_32(dst);
-        break;
-    case CC_OP_LTGT0_64:
-        r =  cc_calc_ltgt0_64(dst);
-        break;
-    case CC_OP_LTGT_32:
-        r =  cc_calc_ltgt_32(src, dst);
-        break;
-    case CC_OP_LTGT_64:
-        r =  cc_calc_ltgt_64(src, dst);
-        break;
-    case CC_OP_LTUGTU_32:
-        r =  cc_calc_ltugtu_32(src, dst);
-        break;
-    case CC_OP_LTUGTU_64:
-        r =  cc_calc_ltugtu_64(src, dst);
-        break;
-    case CC_OP_TM_32:
-        r =  cc_calc_tm_32(src, dst);
-        break;
-    case CC_OP_TM_64:
-        r =  cc_calc_tm_64(src, dst);
-        break;
-    case CC_OP_NZ:
-        r =  cc_calc_nz(dst);
-        break;
-    case CC_OP_ADDU:
-        r = cc_calc_addu(src, dst);
-        break;
-    case CC_OP_SUBU:
-        r = cc_calc_subu(src, dst);
-        break;
-    case CC_OP_ADD_64:
-        r =  cc_calc_add_64(src, dst, vr);
-        break;
-    case CC_OP_SUB_64:
-        r =  cc_calc_sub_64(src, dst, vr);
-        break;
-    case CC_OP_ABS_64:
-        r =  cc_calc_abs_64(dst);
-        break;
-    case CC_OP_NABS_64:
-        r =  cc_calc_nabs_64(dst);
-        break;
-    case CC_OP_COMP_64:
-        r =  cc_calc_comp_64(dst);
-        break;
-    case CC_OP_MULS_64:
-        r = cc_calc_muls_64(src, dst);
-        break;
-
-    case CC_OP_ADD_32:
-        r =  cc_calc_add_32(src, dst, vr);
-        break;
-    case CC_OP_SUB_32:
-        r =  cc_calc_sub_32(src, dst, vr);
-        break;
-    case CC_OP_ABS_32:
-        r =  cc_calc_abs_32(dst);
-        break;
-    case CC_OP_NABS_32:
-        r =  cc_calc_nabs_32(dst);
-        break;
-    case CC_OP_COMP_32:
-        r =  cc_calc_comp_32(dst);
-        break;
-    case CC_OP_MULS_32:
-        r = cc_calc_muls_32(dst);
-        break;
-
-    case CC_OP_ICM:
-        r =  cc_calc_icm(src, dst);
-        break;
-    case CC_OP_SLA_32:
-        r =  cc_calc_sla_32(src, dst);
-        break;
-    case CC_OP_SLA_64:
-        r =  cc_calc_sla_64(src, dst);
-        break;
-    case CC_OP_FLOGR:
-        r = cc_calc_flogr(dst);
-        break;
-    case CC_OP_LCBB:
-        r = cc_calc_lcbb(dst);
-        break;
-    case CC_OP_VC:
-        r = cc_calc_vc(src, dst);
-        break;
-
-    case CC_OP_NZ_F32:
-        r = set_cc_nz_f32(dst);
-        break;
-    case CC_OP_NZ_F64:
-        r = set_cc_nz_f64(dst);
-        break;
-    case CC_OP_NZ_F128:
-        r = set_cc_nz_f128(make_float128(src, dst));
-        break;
-
-    default:
-        cpu_abort(env_cpu(env), "Unknown CC operation: %s\n", cc_name(cc_op));
-    }
-
-    HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __func__,
-               cc_name(cc_op), src, dst, vr, r);
-    return r;
-}
-
-uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
-                 uint64_t vr)
-{
-    return do_calc_cc(env, cc_op, src, dst, vr);
-}
-
-uint32_t HELPER(calc_cc)(CPUS390XState *env, uint32_t cc_op, uint64_t src,
-                         uint64_t dst, uint64_t vr)
-{
-    return do_calc_cc(env, cc_op, src, dst, vr);
-}
-
-#ifndef CONFIG_USER_ONLY
-void HELPER(load_psw)(CPUS390XState *env, uint64_t mask, uint64_t addr)
-{
-    s390_cpu_set_psw(env, mask, addr);
-    cpu_loop_exit(env_cpu(env));
-}
-
-void HELPER(sacf)(CPUS390XState *env, uint64_t a1)
-{
-    HELPER_LOG("%s: %16" PRIx64 "\n", __func__, a1);
-
-    switch (a1 & 0xf00) {
-    case 0x000:
-        env->psw.mask &= ~PSW_MASK_ASC;
-        env->psw.mask |= PSW_ASC_PRIMARY;
-        break;
-    case 0x100:
-        env->psw.mask &= ~PSW_MASK_ASC;
-        env->psw.mask |= PSW_ASC_SECONDARY;
-        break;
-    case 0x300:
-        env->psw.mask &= ~PSW_MASK_ASC;
-        env->psw.mask |= PSW_ASC_HOME;
-        break;
-    default:
-        HELPER_LOG("unknown sacf mode: %" PRIx64 "\n", a1);
-        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
-    }
-}
-#endif
diff --git a/target/s390x/cpu-dump.c b/target/s390x/cpu-dump.c
new file mode 100644 (file)
index 0000000..0f5c062
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * S/390 CPU dump to FILE
+ *
+ *  Copyright (c) 2009 Ulrich Hecht
+ *  Copyright (c) 2011 Alexander Graf
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "s390x-internal.h"
+#include "qemu/qemu-print.h"
+#include "sysemu/tcg.h"
+
+void s390_cpu_dump_state(CPUState *cs, FILE *f, int flags)
+{
+    S390CPU *cpu = S390_CPU(cs);
+    CPUS390XState *env = &cpu->env;
+    int i;
+
+    qemu_fprintf(f, "PSW=mask %016" PRIx64 " addr %016" PRIx64,
+                 s390_cpu_get_psw_mask(env), env->psw.addr);
+    if (!tcg_enabled()) {
+        qemu_fprintf(f, "\n");
+    } else if (env->cc_op > 3) {
+        qemu_fprintf(f, " cc %15s\n", cc_name(env->cc_op));
+    } else {
+        qemu_fprintf(f, " cc %02x\n", env->cc_op);
+    }
+
+    for (i = 0; i < 16; i++) {
+        qemu_fprintf(f, "R%02d=%016" PRIx64, i, env->regs[i]);
+        if ((i % 4) == 3) {
+            qemu_fprintf(f, "\n");
+        } else {
+            qemu_fprintf(f, " ");
+        }
+    }
+
+    if (flags & CPU_DUMP_FPU) {
+        if (s390_has_feat(S390_FEAT_VECTOR)) {
+            for (i = 0; i < 32; i++) {
+                qemu_fprintf(f, "V%02d=%016" PRIx64 "%016" PRIx64 "%c",
+                             i, env->vregs[i][0], env->vregs[i][1],
+                             i % 2 ? '\n' : ' ');
+            }
+        } else {
+            for (i = 0; i < 16; i++) {
+                qemu_fprintf(f, "F%02d=%016" PRIx64 "%c",
+                             i, *get_freg(env, i),
+                             (i % 4) == 3 ? '\n' : ' ');
+            }
+        }
+    }
+
+#ifndef CONFIG_USER_ONLY
+    for (i = 0; i < 16; i++) {
+        qemu_fprintf(f, "C%02d=%016" PRIx64, i, env->cregs[i]);
+        if ((i % 4) == 3) {
+            qemu_fprintf(f, "\n");
+        } else {
+            qemu_fprintf(f, " ");
+        }
+    }
+#endif
+
+#ifdef DEBUG_INLINE_BRANCHES
+    for (i = 0; i < CC_OP_MAX; i++) {
+        qemu_fprintf(f, "  %15s = %10ld\t%10ld\n", cc_name(i),
+                     inline_branch_miss[i], inline_branch_hit[i]);
+    }
+#endif
+
+    qemu_fprintf(f, "\n");
+}
+
+const char *cc_name(enum cc_op cc_op)
+{
+    static const char * const cc_names[] = {
+        [CC_OP_CONST0]    = "CC_OP_CONST0",
+        [CC_OP_CONST1]    = "CC_OP_CONST1",
+        [CC_OP_CONST2]    = "CC_OP_CONST2",
+        [CC_OP_CONST3]    = "CC_OP_CONST3",
+        [CC_OP_DYNAMIC]   = "CC_OP_DYNAMIC",
+        [CC_OP_STATIC]    = "CC_OP_STATIC",
+        [CC_OP_NZ]        = "CC_OP_NZ",
+        [CC_OP_ADDU]      = "CC_OP_ADDU",
+        [CC_OP_SUBU]      = "CC_OP_SUBU",
+        [CC_OP_LTGT_32]   = "CC_OP_LTGT_32",
+        [CC_OP_LTGT_64]   = "CC_OP_LTGT_64",
+        [CC_OP_LTUGTU_32] = "CC_OP_LTUGTU_32",
+        [CC_OP_LTUGTU_64] = "CC_OP_LTUGTU_64",
+        [CC_OP_LTGT0_32]  = "CC_OP_LTGT0_32",
+        [CC_OP_LTGT0_64]  = "CC_OP_LTGT0_64",
+        [CC_OP_ADD_64]    = "CC_OP_ADD_64",
+        [CC_OP_SUB_64]    = "CC_OP_SUB_64",
+        [CC_OP_ABS_64]    = "CC_OP_ABS_64",
+        [CC_OP_NABS_64]   = "CC_OP_NABS_64",
+        [CC_OP_ADD_32]    = "CC_OP_ADD_32",
+        [CC_OP_SUB_32]    = "CC_OP_SUB_32",
+        [CC_OP_ABS_32]    = "CC_OP_ABS_32",
+        [CC_OP_NABS_32]   = "CC_OP_NABS_32",
+        [CC_OP_COMP_32]   = "CC_OP_COMP_32",
+        [CC_OP_COMP_64]   = "CC_OP_COMP_64",
+        [CC_OP_TM_32]     = "CC_OP_TM_32",
+        [CC_OP_TM_64]     = "CC_OP_TM_64",
+        [CC_OP_NZ_F32]    = "CC_OP_NZ_F32",
+        [CC_OP_NZ_F64]    = "CC_OP_NZ_F64",
+        [CC_OP_NZ_F128]   = "CC_OP_NZ_F128",
+        [CC_OP_ICM]       = "CC_OP_ICM",
+        [CC_OP_SLA_32]    = "CC_OP_SLA_32",
+        [CC_OP_SLA_64]    = "CC_OP_SLA_64",
+        [CC_OP_FLOGR]     = "CC_OP_FLOGR",
+        [CC_OP_LCBB]      = "CC_OP_LCBB",
+        [CC_OP_VC]        = "CC_OP_VC",
+        [CC_OP_MULS_32]   = "CC_OP_MULS_32",
+        [CC_OP_MULS_64]   = "CC_OP_MULS_64",
+    };
+
+    return cc_names[cc_op];
+}
diff --git a/target/s390x/cpu-sysemu.c b/target/s390x/cpu-sysemu.c
new file mode 100644 (file)
index 0000000..df2c6bf
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * QEMU S/390 CPU - System Emulation-only code
+ *
+ * Copyright (c) 2009 Ulrich Hecht
+ * Copyright (c) 2011 Alexander Graf
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ * Copyright (c) 2012 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "cpu.h"
+#include "s390x-internal.h"
+#include "kvm/kvm_s390x.h"
+#include "sysemu/kvm.h"
+#include "sysemu/reset.h"
+#include "qemu/timer.h"
+#include "trace.h"
+#include "qapi/qapi-visit-run-state.h"
+#include "sysemu/hw_accel.h"
+
+#include "hw/s390x/pv.h"
+#include "hw/boards.h"
+#include "sysemu/arch_init.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/tcg.h"
+#include "hw/core/sysemu-cpu-ops.h"
+
+/* S390CPUClass::load_normal() */
+static void s390_cpu_load_normal(CPUState *s)
+{
+    S390CPU *cpu = S390_CPU(s);
+    uint64_t spsw;
+
+    if (!s390_is_pv()) {
+        spsw = ldq_phys(s->as, 0);
+        cpu->env.psw.mask = spsw & PSW_MASK_SHORT_CTRL;
+        /*
+         * Invert short psw indication, so SIE will report a specification
+         * exception if it was not set.
+         */
+        cpu->env.psw.mask ^= PSW_MASK_SHORTPSW;
+        cpu->env.psw.addr = spsw & PSW_MASK_SHORT_ADDR;
+    } else {
+        /*
+         * Firmware requires us to set the load state before we set
+         * the cpu to operating on protected guests.
+         */
+        s390_cpu_set_state(S390_CPU_STATE_LOAD, cpu);
+    }
+    s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
+}
+
+void s390_cpu_machine_reset_cb(void *opaque)
+{
+    S390CPU *cpu = opaque;
+
+    run_on_cpu(CPU(cpu), s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
+}
+
+static GuestPanicInformation *s390_cpu_get_crash_info(CPUState *cs)
+{
+    GuestPanicInformation *panic_info;
+    S390CPU *cpu = S390_CPU(cs);
+
+    cpu_synchronize_state(cs);
+    panic_info = g_malloc0(sizeof(GuestPanicInformation));
+
+    panic_info->type = GUEST_PANIC_INFORMATION_TYPE_S390;
+    panic_info->u.s390.core = cpu->env.core_id;
+    panic_info->u.s390.psw_mask = cpu->env.psw.mask;
+    panic_info->u.s390.psw_addr = cpu->env.psw.addr;
+    panic_info->u.s390.reason = cpu->env.crash_reason;
+
+    return panic_info;
+}
+
+static void s390_cpu_get_crash_info_qom(Object *obj, Visitor *v,
+                                        const char *name, void *opaque,
+                                        Error **errp)
+{
+    CPUState *cs = CPU(obj);
+    GuestPanicInformation *panic_info;
+
+    if (!cs->crash_occurred) {
+        error_setg(errp, "No crash occurred");
+        return;
+    }
+
+    panic_info = s390_cpu_get_crash_info(cs);
+
+    visit_type_GuestPanicInformation(v, "crash-information", &panic_info,
+                                     errp);
+    qapi_free_GuestPanicInformation(panic_info);
+}
+
+void s390_cpu_init_sysemu(Object *obj)
+{
+    CPUState *cs = CPU(obj);
+    S390CPU *cpu = S390_CPU(obj);
+
+    cs->start_powered_off = true;
+    object_property_add(obj, "crash-information", "GuestPanicInformation",
+                        s390_cpu_get_crash_info_qom, NULL, NULL, NULL);
+    cpu->env.tod_timer =
+        timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_tod_timer, cpu);
+    cpu->env.cpu_timer =
+        timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_cpu_timer, cpu);
+    s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
+}
+
+bool s390_cpu_realize_sysemu(DeviceState *dev, Error **errp)
+{
+    S390CPU *cpu = S390_CPU(dev);
+    MachineState *ms = MACHINE(qdev_get_machine());
+    unsigned int max_cpus = ms->smp.max_cpus;
+
+    if (cpu->env.core_id >= max_cpus) {
+        error_setg(errp, "Unable to add CPU with core-id: %" PRIu32
+                   ", maximum core-id: %d", cpu->env.core_id,
+                   max_cpus - 1);
+        return false;
+    }
+
+    if (cpu_exists(cpu->env.core_id)) {
+        error_setg(errp, "Unable to add CPU with core-id: %" PRIu32
+                   ", it already exists", cpu->env.core_id);
+        return false;
+    }
+
+    /* sync cs->cpu_index and env->core_id. The latter is needed for TCG. */
+    CPU(cpu)->cpu_index = cpu->env.core_id;
+    return true;
+}
+
+void s390_cpu_finalize(Object *obj)
+{
+    S390CPU *cpu = S390_CPU(obj);
+
+    timer_free(cpu->env.tod_timer);
+    timer_free(cpu->env.cpu_timer);
+
+    qemu_unregister_reset(s390_cpu_machine_reset_cb, cpu);
+    g_free(cpu->irqstate);
+}
+
+static const struct SysemuCPUOps s390_sysemu_ops = {
+    .get_phys_page_debug = s390_cpu_get_phys_page_debug,
+    .get_crash_info = s390_cpu_get_crash_info,
+    .write_elf64_note = s390_cpu_write_elf64_note,
+    .legacy_vmsd = &vmstate_s390_cpu,
+};
+
+void s390_cpu_class_init_sysemu(CPUClass *cc)
+{
+    S390CPUClass *scc = S390_CPU_CLASS(cc);
+
+    scc->load_normal = s390_cpu_load_normal;
+    cc->sysemu_ops = &s390_sysemu_ops;
+}
+
+static bool disabled_wait(CPUState *cpu)
+{
+    return cpu->halted && !(S390_CPU(cpu)->env.psw.mask &
+                            (PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK));
+}
+
+static unsigned s390_count_running_cpus(void)
+{
+    CPUState *cpu;
+    int nr_running = 0;
+
+    CPU_FOREACH(cpu) {
+        uint8_t state = S390_CPU(cpu)->env.cpu_state;
+        if (state == S390_CPU_STATE_OPERATING ||
+            state == S390_CPU_STATE_LOAD) {
+            if (!disabled_wait(cpu)) {
+                nr_running++;
+            }
+        }
+    }
+
+    return nr_running;
+}
+
+unsigned int s390_cpu_halt(S390CPU *cpu)
+{
+    CPUState *cs = CPU(cpu);
+    trace_cpu_halt(cs->cpu_index);
+
+    if (!cs->halted) {
+        cs->halted = 1;
+        cs->exception_index = EXCP_HLT;
+    }
+
+    return s390_count_running_cpus();
+}
+
+void s390_cpu_unhalt(S390CPU *cpu)
+{
+    CPUState *cs = CPU(cpu);
+    trace_cpu_unhalt(cs->cpu_index);
+
+    if (cs->halted) {
+        cs->halted = 0;
+        cs->exception_index = -1;
+    }
+}
+
+unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu)
+ {
+    trace_cpu_set_state(CPU(cpu)->cpu_index, cpu_state);
+
+    switch (cpu_state) {
+    case S390_CPU_STATE_STOPPED:
+    case S390_CPU_STATE_CHECK_STOP:
+        /* halt the cpu for common infrastructure */
+        s390_cpu_halt(cpu);
+        break;
+    case S390_CPU_STATE_OPERATING:
+    case S390_CPU_STATE_LOAD:
+        /*
+         * Starting a CPU with a PSW WAIT bit set:
+         * KVM: handles this internally and triggers another WAIT exit.
+         * TCG: will actually try to continue to run. Don't unhalt, will
+         *      be done when the CPU actually has work (an interrupt).
+         */
+        if (!tcg_enabled() || !(cpu->env.psw.mask & PSW_MASK_WAIT)) {
+            s390_cpu_unhalt(cpu);
+        }
+        break;
+    default:
+        error_report("Requested CPU state is not a valid S390 CPU state: %u",
+                     cpu_state);
+        exit(1);
+    }
+    if (kvm_enabled() && cpu->env.cpu_state != cpu_state) {
+        kvm_s390_set_cpu_state(cpu, cpu_state);
+    }
+    cpu->env.cpu_state = cpu_state;
+
+    return s390_count_running_cpus();
+}
+
+int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit)
+{
+    if (kvm_enabled()) {
+        return kvm_s390_set_mem_limit(new_limit, hw_limit);
+    }
+    return 0;
+}
+
+void s390_set_max_pagesize(uint64_t pagesize, Error **errp)
+{
+    if (kvm_enabled()) {
+        kvm_s390_set_max_pagesize(pagesize, errp);
+    }
+}
+
+void s390_cmma_reset(void)
+{
+    if (kvm_enabled()) {
+        kvm_s390_cmma_reset();
+    }
+}
+
+int s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch_id,
+                                int vq, bool assign)
+{
+    if (kvm_enabled()) {
+        return kvm_s390_assign_subch_ioeventfd(notifier, sch_id, vq, assign);
+    } else {
+        return 0;
+    }
+}
+
+void s390_crypto_reset(void)
+{
+    if (kvm_enabled()) {
+        kvm_s390_crypto_reset();
+    }
+}
+
+void s390_enable_css_support(S390CPU *cpu)
+{
+    if (kvm_enabled()) {
+        kvm_s390_enable_css_support(cpu);
+    }
+}
+
+void s390_do_cpu_set_diag318(CPUState *cs, run_on_cpu_data arg)
+{
+    if (kvm_enabled()) {
+        kvm_s390_set_diag318(cs, arg.host_ulong);
+    }
+}
index 890f382a36c6abc2edb0aea95408e9580fd79c3d..7b7b05f1d3a0084cd7ab349a2d67e87272fd8d53 100644 (file)
 #include "qemu/osdep.h"
 #include "qapi/error.h"
 #include "cpu.h"
-#include "internal.h"
-#include "kvm_s390x.h"
+#include "s390x-internal.h"
+#include "kvm/kvm_s390x.h"
 #include "sysemu/kvm.h"
 #include "sysemu/reset.h"
-#include "qemu/timer.h"
-#include "qemu/error-report.h"
 #include "qemu/module.h"
 #include "trace.h"
-#include "qapi/visitor.h"
 #include "qapi/qapi-types-machine.h"
-#include "qapi/qapi-visit-run-state.h"
 #include "sysemu/hw_accel.h"
 #include "hw/qdev-properties.h"
-#ifndef CONFIG_USER_ONLY
-#include "hw/s390x/pv.h"
-#include "hw/boards.h"
-#include "sysemu/arch_init.h"
-#include "sysemu/tcg.h"
-#endif
 #include "fpu/softfloat-helpers.h"
 #include "disas/capstone.h"
+#include "sysemu/tcg.h"
 
 #define CR0_RESET       0xE0UL
 #define CR14_RESET      0xC2000000UL;
 
+void s390_cpu_set_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
+{
+#ifndef CONFIG_USER_ONLY
+    uint64_t old_mask = env->psw.mask;
+#endif
+
+    env->psw.addr = addr;
+    env->psw.mask = mask;
+
+    /* KVM will handle all WAITs and trigger a WAIT exit on disabled_wait */
+    if (!tcg_enabled()) {
+        return;
+    }
+    env->cc_op = (mask >> 44) & 3;
+
+#ifndef CONFIG_USER_ONLY
+    if ((old_mask ^ mask) & PSW_MASK_PER) {
+        s390_cpu_recompute_watchpoints(env_cpu(env));
+    }
+
+    if (mask & PSW_MASK_WAIT) {
+        s390_handle_wait(env_archcpu(env));
+    }
+#endif
+}
+
+uint64_t s390_cpu_get_psw_mask(CPUS390XState *env)
+{
+    uint64_t r = env->psw.mask;
+
+    if (tcg_enabled()) {
+        uint64_t cc = calc_cc(env, env->cc_op, env->cc_src,
+                              env->cc_dst, env->cc_vr);
+
+        assert(cc <= 3);
+        r &= ~PSW_MASK_CC;
+        r |= cc << 44;
+    }
+
+    return r;
+}
+
 static void s390_cpu_set_pc(CPUState *cs, vaddr value)
 {
     S390CPU *cpu = S390_CPU(cs);
@@ -72,33 +105,6 @@ static bool s390_cpu_has_work(CPUState *cs)
     return s390_cpu_has_int(cpu);
 }
 
-#if !defined(CONFIG_USER_ONLY)
-/* S390CPUClass::load_normal() */
-static void s390_cpu_load_normal(CPUState *s)
-{
-    S390CPU *cpu = S390_CPU(s);
-    uint64_t spsw;
-
-    if (!s390_is_pv()) {
-        spsw = ldq_phys(s->as, 0);
-        cpu->env.psw.mask = spsw & PSW_MASK_SHORT_CTRL;
-        /*
-         * Invert short psw indication, so SIE will report a specification
-         * exception if it was not set.
-         */
-        cpu->env.psw.mask ^= PSW_MASK_SHORTPSW;
-        cpu->env.psw.addr = spsw & PSW_MASK_SHORT_ADDR;
-    } else {
-        /*
-         * Firmware requires us to set the load state before we set
-         * the cpu to operating on protected guests.
-         */
-        s390_cpu_set_state(S390_CPU_STATE_LOAD, cpu);
-    }
-    s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
-}
-#endif
-
 /* S390CPUClass::reset() */
 static void s390_cpu_reset(CPUState *s, cpu_reset_type type)
 {
@@ -169,15 +175,6 @@ static void s390_cpu_reset(CPUState *s, cpu_reset_type type)
     }
 }
 
-#if !defined(CONFIG_USER_ONLY)
-static void s390_cpu_machine_reset_cb(void *opaque)
-{
-    S390CPU *cpu = opaque;
-
-    run_on_cpu(CPU(cpu), s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
-}
-#endif
-
 static void s390_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
 {
     info->mach = bfd_mach_s390_64;
@@ -191,9 +188,6 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
 {
     CPUState *cs = CPU(dev);
     S390CPUClass *scc = S390_CPU_GET_CLASS(dev);
-#if !defined(CONFIG_USER_ONLY)
-    S390CPU *cpu = S390_CPU(dev);
-#endif
     Error *err = NULL;
 
     /* the model has to be realized before qemu_init_vcpu() due to kvm */
@@ -203,23 +197,9 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
     }
 
 #if !defined(CONFIG_USER_ONLY)
-    MachineState *ms = MACHINE(qdev_get_machine());
-    unsigned int max_cpus = ms->smp.max_cpus;
-    if (cpu->env.core_id >= max_cpus) {
-        error_setg(&err, "Unable to add CPU with core-id: %" PRIu32
-                   ", maximum core-id: %d", cpu->env.core_id,
-                   max_cpus - 1);
-        goto out;
-    }
-
-    if (cpu_exists(cpu->env.core_id)) {
-        error_setg(&err, "Unable to add CPU with core-id: %" PRIu32
-                   ", it already exists", cpu->env.core_id);
+    if (!s390_cpu_realize_sysemu(dev, &err)) {
         goto out;
     }
-
-    /* sync cs->cpu_index and env->core_id. The latter is needed for TCG. */
-    cs->cpu_index = cpu->env.core_id;
 #endif
 
     cpu_exec_realizefn(cs, &err);
@@ -228,7 +208,7 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
     }
 
 #if !defined(CONFIG_USER_ONLY)
-    qemu_register_reset(s390_cpu_machine_reset_cb, cpu);
+    qemu_register_reset(s390_cpu_machine_reset_cb, S390_CPU(dev));
 #endif
     s390_cpu_gdb_init(cs);
     qemu_init_vcpu(cs);
@@ -250,44 +230,6 @@ out:
     error_propagate(errp, err);
 }
 
-#if !defined(CONFIG_USER_ONLY)
-static GuestPanicInformation *s390_cpu_get_crash_info(CPUState *cs)
-{
-    GuestPanicInformation *panic_info;
-    S390CPU *cpu = S390_CPU(cs);
-
-    cpu_synchronize_state(cs);
-    panic_info = g_malloc0(sizeof(GuestPanicInformation));
-
-    panic_info->type = GUEST_PANIC_INFORMATION_TYPE_S390;
-    panic_info->u.s390.core = cpu->env.core_id;
-    panic_info->u.s390.psw_mask = cpu->env.psw.mask;
-    panic_info->u.s390.psw_addr = cpu->env.psw.addr;
-    panic_info->u.s390.reason = cpu->env.crash_reason;
-
-    return panic_info;
-}
-
-static void s390_cpu_get_crash_info_qom(Object *obj, Visitor *v,
-                                        const char *name, void *opaque,
-                                        Error **errp)
-{
-    CPUState *cs = CPU(obj);
-    GuestPanicInformation *panic_info;
-
-    if (!cs->crash_occurred) {
-        error_setg(errp, "No crash occurred");
-        return;
-    }
-
-    panic_info = s390_cpu_get_crash_info(cs);
-
-    visit_type_GuestPanicInformation(v, "crash-information", &panic_info,
-                                     errp);
-    qapi_free_GuestPanicInformation(panic_info);
-}
-#endif
-
 static void s390_cpu_initfn(Object *obj)
 {
     CPUState *cs = CPU(obj);
@@ -295,169 +237,12 @@ static void s390_cpu_initfn(Object *obj)
 
     cpu_set_cpustate_pointers(cpu);
     cs->exception_index = EXCP_HLT;
-#if !defined(CONFIG_USER_ONLY)
-    cs->start_powered_off = true;
-    object_property_add(obj, "crash-information", "GuestPanicInformation",
-                        s390_cpu_get_crash_info_qom, NULL, NULL, NULL);
-    cpu->env.tod_timer =
-        timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_tod_timer, cpu);
-    cpu->env.cpu_timer =
-        timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_cpu_timer, cpu);
-    s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
-#endif
-}
 
-static void s390_cpu_finalize(Object *obj)
-{
 #if !defined(CONFIG_USER_ONLY)
-    S390CPU *cpu = S390_CPU(obj);
-
-    timer_free(cpu->env.tod_timer);
-    timer_free(cpu->env.cpu_timer);
-
-    qemu_unregister_reset(s390_cpu_machine_reset_cb, cpu);
-    g_free(cpu->irqstate);
+    s390_cpu_init_sysemu(obj);
 #endif
 }
 
-#if !defined(CONFIG_USER_ONLY)
-static bool disabled_wait(CPUState *cpu)
-{
-    return cpu->halted && !(S390_CPU(cpu)->env.psw.mask &
-                            (PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK));
-}
-
-static unsigned s390_count_running_cpus(void)
-{
-    CPUState *cpu;
-    int nr_running = 0;
-
-    CPU_FOREACH(cpu) {
-        uint8_t state = S390_CPU(cpu)->env.cpu_state;
-        if (state == S390_CPU_STATE_OPERATING ||
-            state == S390_CPU_STATE_LOAD) {
-            if (!disabled_wait(cpu)) {
-                nr_running++;
-            }
-        }
-    }
-
-    return nr_running;
-}
-
-unsigned int s390_cpu_halt(S390CPU *cpu)
-{
-    CPUState *cs = CPU(cpu);
-    trace_cpu_halt(cs->cpu_index);
-
-    if (!cs->halted) {
-        cs->halted = 1;
-        cs->exception_index = EXCP_HLT;
-    }
-
-    return s390_count_running_cpus();
-}
-
-void s390_cpu_unhalt(S390CPU *cpu)
-{
-    CPUState *cs = CPU(cpu);
-    trace_cpu_unhalt(cs->cpu_index);
-
-    if (cs->halted) {
-        cs->halted = 0;
-        cs->exception_index = -1;
-    }
-}
-
-unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu)
- {
-    trace_cpu_set_state(CPU(cpu)->cpu_index, cpu_state);
-
-    switch (cpu_state) {
-    case S390_CPU_STATE_STOPPED:
-    case S390_CPU_STATE_CHECK_STOP:
-        /* halt the cpu for common infrastructure */
-        s390_cpu_halt(cpu);
-        break;
-    case S390_CPU_STATE_OPERATING:
-    case S390_CPU_STATE_LOAD:
-        /*
-         * Starting a CPU with a PSW WAIT bit set:
-         * KVM: handles this internally and triggers another WAIT exit.
-         * TCG: will actually try to continue to run. Don't unhalt, will
-         *      be done when the CPU actually has work (an interrupt).
-         */
-        if (!tcg_enabled() || !(cpu->env.psw.mask & PSW_MASK_WAIT)) {
-            s390_cpu_unhalt(cpu);
-        }
-        break;
-    default:
-        error_report("Requested CPU state is not a valid S390 CPU state: %u",
-                     cpu_state);
-        exit(1);
-    }
-    if (kvm_enabled() && cpu->env.cpu_state != cpu_state) {
-        kvm_s390_set_cpu_state(cpu, cpu_state);
-    }
-    cpu->env.cpu_state = cpu_state;
-
-    return s390_count_running_cpus();
-}
-
-int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit)
-{
-    if (kvm_enabled()) {
-        return kvm_s390_set_mem_limit(new_limit, hw_limit);
-    }
-    return 0;
-}
-
-void s390_set_max_pagesize(uint64_t pagesize, Error **errp)
-{
-    if (kvm_enabled()) {
-        kvm_s390_set_max_pagesize(pagesize, errp);
-    }
-}
-
-void s390_cmma_reset(void)
-{
-    if (kvm_enabled()) {
-        kvm_s390_cmma_reset();
-    }
-}
-
-int s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch_id,
-                                int vq, bool assign)
-{
-    if (kvm_enabled()) {
-        return kvm_s390_assign_subch_ioeventfd(notifier, sch_id, vq, assign);
-    } else {
-        return 0;
-    }
-}
-
-void s390_crypto_reset(void)
-{
-    if (kvm_enabled()) {
-        kvm_s390_crypto_reset();
-    }
-}
-
-void s390_enable_css_support(S390CPU *cpu)
-{
-    if (kvm_enabled()) {
-        kvm_s390_enable_css_support(cpu);
-    }
-}
-
-void s390_do_cpu_set_diag318(CPUState *cs, run_on_cpu_data arg)
-{
-    if (kvm_enabled()) {
-        kvm_s390_set_diag318(cs, arg.host_ulong);
-    }
-}
-#endif
-
 static gchar *s390_gdb_arch_name(CPUState *cs)
 {
     return g_strdup("s390:64-bit");
@@ -476,17 +261,6 @@ static void s390_cpu_reset_full(DeviceState *dev)
     return s390_cpu_reset(s, S390_CPU_RESET_CLEAR);
 }
 
-#ifndef CONFIG_USER_ONLY
-#include "hw/core/sysemu-cpu-ops.h"
-
-static const struct SysemuCPUOps s390_sysemu_ops = {
-    .get_phys_page_debug = s390_cpu_get_phys_page_debug,
-    .get_crash_info = s390_cpu_get_crash_info,
-    .write_elf64_note = s390_cpu_write_elf64_note,
-    .legacy_vmsd = &vmstate_s390_cpu,
-};
-#endif
-
 #ifdef CONFIG_TCG
 #include "hw/core/tcg-cpu-ops.h"
 
@@ -515,9 +289,7 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data)
     dc->user_creatable = true;
 
     device_class_set_parent_reset(dc, s390_cpu_reset_full, &scc->parent_reset);
-#if !defined(CONFIG_USER_ONLY)
-    scc->load_normal = s390_cpu_load_normal;
-#endif
+
     scc->reset = s390_cpu_reset;
     cc->class_by_name = s390_cpu_class_by_name,
     cc->has_work = s390_cpu_has_work;
@@ -526,7 +298,7 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data)
     cc->gdb_read_register = s390_cpu_gdb_read_register;
     cc->gdb_write_register = s390_cpu_gdb_write_register;
 #ifndef CONFIG_USER_ONLY
-    cc->sysemu_ops = &s390_sysemu_ops;
+    s390_cpu_class_init_sysemu(cc);
 #endif
     cc->disas_set_info = s390_cpu_disas_set_info;
     cc->gdb_num_core_regs = S390_NUM_CORE_REGS;
@@ -546,7 +318,11 @@ static const TypeInfo s390_cpu_type_info = {
     .instance_size = sizeof(S390CPU),
     .instance_align = __alignof__(S390CPU),
     .instance_init = s390_cpu_initfn,
+
+#ifndef CONFIG_USER_ONLY
     .instance_finalize = s390_cpu_finalize,
+#endif /* !CONFIG_USER_ONLY */
+
     .abstract = true,
     .class_size = sizeof(S390CPUClass),
     .class_init = s390_cpu_class_init,
index 7db3449e04346fad4dbf904a13d677bdc2ccc8dd..e86662bb3b8a3da3fc1a6d8cc91bf6dc0948747a 100644 (file)
@@ -109,6 +109,11 @@ DEF_FEAT(VECTOR_PACKED_DECIMAL_ENH, "vxpdeh", STFL, 152, "Vector-Packed-Decimal-
 DEF_FEAT(MSA_EXT_9, "msa9-base", STFL, 155, "Message-security-assist-extension-9 facility (excluding subfunctions)")
 DEF_FEAT(ETOKEN, "etoken", STFL, 156, "Etoken facility")
 DEF_FEAT(UNPACK, "unpack", STFL, 161, "Unpack facility")
+DEF_FEAT(NNPA, "nnpa", STFL, 165, "NNPA facility")
+DEF_FEAT(VECTOR_PACKED_DECIMAL_ENH2, "vxpdeh2", STFL, 192, "Vector-Packed-Decimal-Enhancement facility 2")
+DEF_FEAT(BEAR_ENH, "beareh", STFL, 193, "BEAR-enhancement facility")
+DEF_FEAT(RDP, "rdp", STFL, 194, "Reset-DAT-protection facility")
+DEF_FEAT(PAI, "pai", STFL, 196, "Processor-Activity-Instrumentation facility")
 
 /* Features exposed via SCLP SCCB Byte 80 - 98  (bit numbers relative to byte-80) */
 DEF_FEAT(SIE_GSLS, "gsls", SCLP_CONF_CHAR, 40, "SIE: Guest-storage-limit-suppression facility")
index 94090a6e223d957e87ba99f4bf5798cba18cff55..4e4598cc774cdea85422a29db7f6c753c77eeca4 100644 (file)
 
 #include "qemu/osdep.h"
 #include "cpu.h"
-#include "internal.h"
-#include "kvm_s390x.h"
+#include "s390x-internal.h"
+#include "kvm/kvm_s390x.h"
 #include "sysemu/kvm.h"
 #include "sysemu/tcg.h"
 #include "qapi/error.h"
 #include "qapi/visitor.h"
-#include "qemu/error-report.h"
 #include "qemu/module.h"
 #include "qemu/qemu-print.h"
-#include "qapi/qmp/qerror.h"
-#include "qapi/qobject-input-visitor.h"
-#include "qapi/qmp/qdict.h"
 #ifndef CONFIG_USER_ONLY
-#include "sysemu/arch_init.h"
 #include "sysemu/sysemu.h"
-#include "hw/pci/pci.h"
 #endif
-#include "qapi/qapi-commands-machine-target.h"
 #include "hw/s390x/pv.h"
 
 #define CPUDEF_INIT(_type, _gen, _ec_ga, _mha_pow, _hmfai, _name, _desc) \
@@ -88,6 +81,8 @@ static S390CPUDef s390_cpu_defs[] = {
     CPUDEF_INIT(0x3907, 14, 1, 47, 0x08000000U, "z14ZR1", "IBM z14 Model ZR1 GA1"),
     CPUDEF_INIT(0x8561, 15, 1, 47, 0x08000000U, "gen15a", "IBM z15 T01 GA1"),
     CPUDEF_INIT(0x8562, 15, 1, 47, 0x08000000U, "gen15b", "IBM z15 T02 GA1"),
+    CPUDEF_INIT(0x3931, 16, 1, 47, 0x08000000U, "gen16a", "IBM 3931 GA1"),
+    CPUDEF_INIT(0x3932, 16, 1, 47, 0x08000000U, "gen16b", "IBM 3932 GA1"),
 };
 
 #define QEMU_MAX_CPU_TYPE 0x3906
@@ -414,381 +409,6 @@ void s390_cpu_list(void)
     }
 }
 
-static S390CPUModel *get_max_cpu_model(Error **errp);
-
-#ifndef CONFIG_USER_ONLY
-static void list_add_feat(const char *name, void *opaque);
-
-static void check_unavailable_features(const S390CPUModel *max_model,
-                                       const S390CPUModel *model,
-                                       strList **unavailable)
-{
-    S390FeatBitmap missing;
-
-    /* check general model compatibility */
-    if (max_model->def->gen < model->def->gen ||
-        (max_model->def->gen == model->def->gen &&
-         max_model->def->ec_ga < model->def->ec_ga)) {
-        list_add_feat("type", unavailable);
-    }
-
-    /* detect missing features if any to properly report them */
-    bitmap_andnot(missing, model->features, max_model->features,
-                  S390_FEAT_MAX);
-    if (!bitmap_empty(missing, S390_FEAT_MAX)) {
-        s390_feat_bitmap_to_ascii(missing, unavailable, list_add_feat);
-    }
-}
-
-struct CpuDefinitionInfoListData {
-    CpuDefinitionInfoList *list;
-    S390CPUModel *model;
-};
-
-static void create_cpu_model_list(ObjectClass *klass, void *opaque)
-{
-    struct CpuDefinitionInfoListData *cpu_list_data = opaque;
-    CpuDefinitionInfoList **cpu_list = &cpu_list_data->list;
-    CpuDefinitionInfo *info;
-    char *name = g_strdup(object_class_get_name(klass));
-    S390CPUClass *scc = S390_CPU_CLASS(klass);
-
-    /* strip off the -s390x-cpu */
-    g_strrstr(name, "-" TYPE_S390_CPU)[0] = 0;
-    info = g_new0(CpuDefinitionInfo, 1);
-    info->name = name;
-    info->has_migration_safe = true;
-    info->migration_safe = scc->is_migration_safe;
-    info->q_static = scc->is_static;
-    info->q_typename = g_strdup(object_class_get_name(klass));
-    /* check for unavailable features */
-    if (cpu_list_data->model) {
-        Object *obj;
-        S390CPU *sc;
-        obj = object_new_with_class(klass);
-        sc = S390_CPU(obj);
-        if (sc->model) {
-            info->has_unavailable_features = true;
-            check_unavailable_features(cpu_list_data->model, sc->model,
-                                       &info->unavailable_features);
-        }
-        object_unref(obj);
-    }
-
-    QAPI_LIST_PREPEND(*cpu_list, info);
-}
-
-CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
-{
-    struct CpuDefinitionInfoListData list_data = {
-        .list = NULL,
-    };
-
-    list_data.model = get_max_cpu_model(NULL);
-
-    object_class_foreach(create_cpu_model_list, TYPE_S390_CPU, false,
-                         &list_data);
-
-    return list_data.list;
-}
-
-static void cpu_model_from_info(S390CPUModel *model, const CpuModelInfo *info,
-                                Error **errp)
-{
-    Error *err = NULL;
-    const QDict *qdict = NULL;
-    const QDictEntry *e;
-    Visitor *visitor;
-    ObjectClass *oc;
-    S390CPU *cpu;
-    Object *obj;
-
-    if (info->props) {
-        qdict = qobject_to(QDict, info->props);
-        if (!qdict) {
-            error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict");
-            return;
-        }
-    }
-
-    oc = cpu_class_by_name(TYPE_S390_CPU, info->name);
-    if (!oc) {
-        error_setg(errp, "The CPU definition \'%s\' is unknown.", info->name);
-        return;
-    }
-    if (S390_CPU_CLASS(oc)->kvm_required && !kvm_enabled()) {
-        error_setg(errp, "The CPU definition '%s' requires KVM", info->name);
-        return;
-    }
-    obj = object_new_with_class(oc);
-    cpu = S390_CPU(obj);
-
-    if (!cpu->model) {
-        error_setg(errp, "Details about the host CPU model are not available, "
-                         "it cannot be used.");
-        object_unref(obj);
-        return;
-    }
-
-    if (qdict) {
-        visitor = qobject_input_visitor_new(info->props);
-        if (!visit_start_struct(visitor, NULL, NULL, 0, errp)) {
-            visit_free(visitor);
-            object_unref(obj);
-            return;
-        }
-        for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
-            if (!object_property_set(obj, e->key, visitor, &err)) {
-                break;
-            }
-        }
-        if (!err) {
-            visit_check_struct(visitor, &err);
-        }
-        visit_end_struct(visitor, NULL);
-        visit_free(visitor);
-        if (err) {
-            error_propagate(errp, err);
-            object_unref(obj);
-            return;
-        }
-    }
-
-    /* copy the model and throw the cpu away */
-    memcpy(model, cpu->model, sizeof(*model));
-    object_unref(obj);
-}
-
-static void qdict_add_disabled_feat(const char *name, void *opaque)
-{
-    qdict_put_bool(opaque, name, false);
-}
-
-static void qdict_add_enabled_feat(const char *name, void *opaque)
-{
-    qdict_put_bool(opaque, name, true);
-}
-
-/* convert S390CPUDef into a static CpuModelInfo */
-static void cpu_info_from_model(CpuModelInfo *info, const S390CPUModel *model,
-                                bool delta_changes)
-{
-    QDict *qdict = qdict_new();
-    S390FeatBitmap bitmap;
-
-    /* always fallback to the static base model */
-    info->name = g_strdup_printf("%s-base", model->def->name);
-
-    if (delta_changes) {
-        /* features deleted from the base feature set */
-        bitmap_andnot(bitmap, model->def->base_feat, model->features,
-                      S390_FEAT_MAX);
-        if (!bitmap_empty(bitmap, S390_FEAT_MAX)) {
-            s390_feat_bitmap_to_ascii(bitmap, qdict, qdict_add_disabled_feat);
-        }
-
-        /* features added to the base feature set */
-        bitmap_andnot(bitmap, model->features, model->def->base_feat,
-                      S390_FEAT_MAX);
-        if (!bitmap_empty(bitmap, S390_FEAT_MAX)) {
-            s390_feat_bitmap_to_ascii(bitmap, qdict, qdict_add_enabled_feat);
-        }
-    } else {
-        /* expand all features */
-        s390_feat_bitmap_to_ascii(model->features, qdict,
-                                  qdict_add_enabled_feat);
-        bitmap_complement(bitmap, model->features, S390_FEAT_MAX);
-        s390_feat_bitmap_to_ascii(bitmap, qdict, qdict_add_disabled_feat);
-    }
-
-    if (!qdict_size(qdict)) {
-        qobject_unref(qdict);
-    } else {
-        info->props = QOBJECT(qdict);
-        info->has_props = true;
-    }
-}
-
-CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
-                                                      CpuModelInfo *model,
-                                                      Error **errp)
-{
-    Error *err = NULL;
-    CpuModelExpansionInfo *expansion_info = NULL;
-    S390CPUModel s390_model;
-    bool delta_changes = false;
-
-    /* convert it to our internal representation */
-    cpu_model_from_info(&s390_model, model, &err);
-    if (err) {
-        error_propagate(errp, err);
-        return NULL;
-    }
-
-    if (type == CPU_MODEL_EXPANSION_TYPE_STATIC) {
-        delta_changes = true;
-    } else if (type != CPU_MODEL_EXPANSION_TYPE_FULL) {
-        error_setg(errp, "The requested expansion type is not supported.");
-        return NULL;
-    }
-
-    /* convert it back to a static representation */
-    expansion_info = g_new0(CpuModelExpansionInfo, 1);
-    expansion_info->model = g_malloc0(sizeof(*expansion_info->model));
-    cpu_info_from_model(expansion_info->model, &s390_model, delta_changes);
-    return expansion_info;
-}
-
-static void list_add_feat(const char *name, void *opaque)
-{
-    strList **last = (strList **) opaque;
-
-    QAPI_LIST_PREPEND(*last, g_strdup(name));
-}
-
-CpuModelCompareInfo *qmp_query_cpu_model_comparison(CpuModelInfo *infoa,
-                                                     CpuModelInfo *infob,
-                                                     Error **errp)
-{
-    Error *err = NULL;
-    CpuModelCompareResult feat_result, gen_result;
-    CpuModelCompareInfo *compare_info;
-    S390FeatBitmap missing, added;
-    S390CPUModel modela, modelb;
-
-    /* convert both models to our internal representation */
-    cpu_model_from_info(&modela, infoa, &err);
-    if (err) {
-        error_propagate(errp, err);
-        return NULL;
-    }
-    cpu_model_from_info(&modelb, infob, &err);
-    if (err) {
-        error_propagate(errp, err);
-        return NULL;
-    }
-    compare_info = g_new0(CpuModelCompareInfo, 1);
-
-    /* check the cpu generation and ga level */
-    if (modela.def->gen == modelb.def->gen) {
-        if (modela.def->ec_ga == modelb.def->ec_ga) {
-            /* ec and corresponding bc are identical */
-            gen_result = CPU_MODEL_COMPARE_RESULT_IDENTICAL;
-        } else if (modela.def->ec_ga < modelb.def->ec_ga) {
-            gen_result = CPU_MODEL_COMPARE_RESULT_SUBSET;
-        } else {
-            gen_result = CPU_MODEL_COMPARE_RESULT_SUPERSET;
-        }
-    } else if (modela.def->gen < modelb.def->gen) {
-        gen_result = CPU_MODEL_COMPARE_RESULT_SUBSET;
-    } else {
-        gen_result = CPU_MODEL_COMPARE_RESULT_SUPERSET;
-    }
-    if (gen_result != CPU_MODEL_COMPARE_RESULT_IDENTICAL) {
-        /* both models cannot be made identical */
-        list_add_feat("type", &compare_info->responsible_properties);
-    }
-
-    /* check the feature set */
-    if (bitmap_equal(modela.features, modelb.features, S390_FEAT_MAX)) {
-        feat_result = CPU_MODEL_COMPARE_RESULT_IDENTICAL;
-    } else {
-        bitmap_andnot(missing, modela.features, modelb.features, S390_FEAT_MAX);
-        s390_feat_bitmap_to_ascii(missing,
-                                  &compare_info->responsible_properties,
-                                  list_add_feat);
-        bitmap_andnot(added, modelb.features, modela.features, S390_FEAT_MAX);
-        s390_feat_bitmap_to_ascii(added, &compare_info->responsible_properties,
-                                  list_add_feat);
-        if (bitmap_empty(missing, S390_FEAT_MAX)) {
-            feat_result = CPU_MODEL_COMPARE_RESULT_SUBSET;
-        } else if (bitmap_empty(added, S390_FEAT_MAX)) {
-            feat_result = CPU_MODEL_COMPARE_RESULT_SUPERSET;
-        } else {
-            feat_result = CPU_MODEL_COMPARE_RESULT_INCOMPATIBLE;
-        }
-    }
-
-    /* combine the results */
-    if (gen_result == feat_result) {
-        compare_info->result = gen_result;
-    } else if (feat_result == CPU_MODEL_COMPARE_RESULT_IDENTICAL) {
-        compare_info->result = gen_result;
-    } else if (gen_result == CPU_MODEL_COMPARE_RESULT_IDENTICAL) {
-        compare_info->result = feat_result;
-    } else {
-        compare_info->result = CPU_MODEL_COMPARE_RESULT_INCOMPATIBLE;
-    }
-    return compare_info;
-}
-
-CpuModelBaselineInfo *qmp_query_cpu_model_baseline(CpuModelInfo *infoa,
-                                                    CpuModelInfo *infob,
-                                                    Error **errp)
-{
-    Error *err = NULL;
-    CpuModelBaselineInfo *baseline_info;
-    S390CPUModel modela, modelb, model;
-    uint16_t cpu_type;
-    uint8_t max_gen_ga;
-    uint8_t max_gen;
-
-    /* convert both models to our internal representation */
-    cpu_model_from_info(&modela, infoa, &err);
-    if (err) {
-        error_propagate(errp, err);
-        return NULL;
-    }
-
-    cpu_model_from_info(&modelb, infob, &err);
-    if (err) {
-        error_propagate(errp, err);
-        return NULL;
-    }
-
-    /* features both models support */
-    bitmap_and(model.features, modela.features, modelb.features, S390_FEAT_MAX);
-
-    /* detect the maximum model not regarding features */
-    if (modela.def->gen == modelb.def->gen) {
-        if (modela.def->type == modelb.def->type) {
-            cpu_type = modela.def->type;
-        } else {
-            cpu_type = 0;
-        }
-        max_gen = modela.def->gen;
-        max_gen_ga = MIN(modela.def->ec_ga, modelb.def->ec_ga);
-    } else if (modela.def->gen > modelb.def->gen) {
-        cpu_type = modelb.def->type;
-        max_gen = modelb.def->gen;
-        max_gen_ga = modelb.def->ec_ga;
-    } else {
-        cpu_type = modela.def->type;
-        max_gen = modela.def->gen;
-        max_gen_ga = modela.def->ec_ga;
-    }
-
-    model.def = s390_find_cpu_def(cpu_type, max_gen, max_gen_ga,
-                                  model.features);
-
-    /* models without early base features (esan3) are bad */
-    if (!model.def) {
-        error_setg(errp, "No compatible CPU model could be created as"
-                   " important base features are disabled");
-        return NULL;
-    }
-
-    /* strip off features not part of the max model */
-    bitmap_and(model.features, model.features, model.def->full_feat,
-               S390_FEAT_MAX);
-
-    baseline_info = g_new0(CpuModelBaselineInfo, 1);
-    baseline_info->model = g_malloc0(sizeof(*baseline_info->model));
-    cpu_info_from_model(baseline_info->model, &model, true);
-    return baseline_info;
-}
-#endif
-
 static void check_consistency(const S390CPUModel *model)
 {
     static int dep[][2] = {
@@ -812,6 +432,8 @@ static void check_consistency(const S390CPUModel *model)
         { S390_FEAT_MSA_EXT_9, S390_FEAT_MSA_EXT_4 },
         { S390_FEAT_MULTIPLE_EPOCH, S390_FEAT_TOD_CLOCK_STEERING },
         { S390_FEAT_VECTOR_PACKED_DECIMAL, S390_FEAT_VECTOR },
+        { S390_FEAT_VECTOR_PACKED_DECIMAL_ENH, S390_FEAT_VECTOR_PACKED_DECIMAL },
+        { S390_FEAT_VECTOR_PACKED_DECIMAL_ENH2, S390_FEAT_VECTOR_PACKED_DECIMAL_ENH },
         { S390_FEAT_VECTOR_ENH, S390_FEAT_VECTOR },
         { S390_FEAT_INSTRUCTION_EXEC_PROT, S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2 },
         { S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2, S390_FEAT_ESOP },
@@ -843,6 +465,8 @@ static void check_consistency(const S390CPUModel *model)
         { S390_FEAT_PTFF_STOUE, S390_FEAT_MULTIPLE_EPOCH },
         { S390_FEAT_AP_QUEUE_INTERRUPT_CONTROL, S390_FEAT_AP },
         { S390_FEAT_DIAG_318, S390_FEAT_EXTENDED_LENGTH_SCCB },
+        { S390_FEAT_NNPA, S390_FEAT_VECTOR },
+        { S390_FEAT_RDP, S390_FEAT_LOCAL_TLB_CLEARING },
     };
     int i;
 
@@ -900,7 +524,7 @@ static void check_compatibility(const S390CPUModel *max_model,
                   "available in the configuration: ");
 }
 
-static S390CPUModel *get_max_cpu_model(Error **errp)
+S390CPUModel *get_max_cpu_model(Error **errp)
 {
     Error *err = NULL;
     static S390CPUModel max_model;
@@ -925,39 +549,6 @@ static S390CPUModel *get_max_cpu_model(Error **errp)
     return &max_model;
 }
 
-static inline void apply_cpu_model(const S390CPUModel *model, Error **errp)
-{
-#ifndef CONFIG_USER_ONLY
-    Error *err = NULL;
-    static S390CPUModel applied_model;
-    static bool applied;
-
-    /*
-     * We have the same model for all VCPUs. KVM can only be configured before
-     * any VCPUs are defined in KVM.
-     */
-    if (applied) {
-        if (model && memcmp(&applied_model, model, sizeof(S390CPUModel))) {
-            error_setg(errp, "Mixed CPU models are not supported on s390x.");
-        }
-        return;
-    }
-
-    if (kvm_enabled()) {
-        kvm_s390_apply_cpu_model(model, &err);
-        if (err) {
-            error_propagate(errp, err);
-            return;
-        }
-    }
-
-    applied = true;
-    if (model) {
-        applied_model = *model;
-    }
-#endif
-}
-
 void s390_realize_cpu_model(CPUState *cs, Error **errp)
 {
     Error *err = NULL;
diff --git a/target/s390x/cpu_models_sysemu.c b/target/s390x/cpu_models_sysemu.c
new file mode 100644 (file)
index 0000000..05c3cca
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+ * CPU models for s390x - System Emulation-only
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * Author(s): David Hildenbrand <dahi@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "s390x-internal.h"
+#include "kvm/kvm_s390x.h"
+#include "sysemu/kvm.h"
+#include "sysemu/tcg.h"
+#include "qapi/error.h"
+#include "qapi/visitor.h"
+#include "qapi/qmp/qerror.h"
+#include "qapi/qobject-input-visitor.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qapi-commands-machine-target.h"
+
+static void list_add_feat(const char *name, void *opaque);
+
+static void check_unavailable_features(const S390CPUModel *max_model,
+                                       const S390CPUModel *model,
+                                       strList **unavailable)
+{
+    S390FeatBitmap missing;
+
+    /* check general model compatibility */
+    if (max_model->def->gen < model->def->gen ||
+        (max_model->def->gen == model->def->gen &&
+         max_model->def->ec_ga < model->def->ec_ga)) {
+        list_add_feat("type", unavailable);
+    }
+
+    /* detect missing features if any to properly report them */
+    bitmap_andnot(missing, model->features, max_model->features,
+                  S390_FEAT_MAX);
+    if (!bitmap_empty(missing, S390_FEAT_MAX)) {
+        s390_feat_bitmap_to_ascii(missing, unavailable, list_add_feat);
+    }
+}
+
+struct CpuDefinitionInfoListData {
+    CpuDefinitionInfoList *list;
+    S390CPUModel *model;
+};
+
+static void create_cpu_model_list(ObjectClass *klass, void *opaque)
+{
+    struct CpuDefinitionInfoListData *cpu_list_data = opaque;
+    CpuDefinitionInfoList **cpu_list = &cpu_list_data->list;
+    CpuDefinitionInfo *info;
+    char *name = g_strdup(object_class_get_name(klass));
+    S390CPUClass *scc = S390_CPU_CLASS(klass);
+
+    /* strip off the -s390x-cpu */
+    g_strrstr(name, "-" TYPE_S390_CPU)[0] = 0;
+    info = g_new0(CpuDefinitionInfo, 1);
+    info->name = name;
+    info->has_migration_safe = true;
+    info->migration_safe = scc->is_migration_safe;
+    info->q_static = scc->is_static;
+    info->q_typename = g_strdup(object_class_get_name(klass));
+    /* check for unavailable features */
+    if (cpu_list_data->model) {
+        Object *obj;
+        S390CPU *sc;
+        obj = object_new_with_class(klass);
+        sc = S390_CPU(obj);
+        if (sc->model) {
+            info->has_unavailable_features = true;
+            check_unavailable_features(cpu_list_data->model, sc->model,
+                                       &info->unavailable_features);
+        }
+        object_unref(obj);
+    }
+
+    QAPI_LIST_PREPEND(*cpu_list, info);
+}
+
+CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
+{
+    struct CpuDefinitionInfoListData list_data = {
+        .list = NULL,
+    };
+
+    list_data.model = get_max_cpu_model(NULL);
+
+    object_class_foreach(create_cpu_model_list, TYPE_S390_CPU, false,
+                         &list_data);
+
+    return list_data.list;
+}
+
+static void cpu_model_from_info(S390CPUModel *model, const CpuModelInfo *info,
+                                Error **errp)
+{
+    Error *err = NULL;
+    const QDict *qdict = NULL;
+    const QDictEntry *e;
+    Visitor *visitor;
+    ObjectClass *oc;
+    S390CPU *cpu;
+    Object *obj;
+
+    if (info->props) {
+        qdict = qobject_to(QDict, info->props);
+        if (!qdict) {
+            error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict");
+            return;
+        }
+    }
+
+    oc = cpu_class_by_name(TYPE_S390_CPU, info->name);
+    if (!oc) {
+        error_setg(errp, "The CPU definition \'%s\' is unknown.", info->name);
+        return;
+    }
+    if (S390_CPU_CLASS(oc)->kvm_required && !kvm_enabled()) {
+        error_setg(errp, "The CPU definition '%s' requires KVM", info->name);
+        return;
+    }
+    obj = object_new_with_class(oc);
+    cpu = S390_CPU(obj);
+
+    if (!cpu->model) {
+        error_setg(errp, "Details about the host CPU model are not available, "
+                         "it cannot be used.");
+        object_unref(obj);
+        return;
+    }
+
+    if (qdict) {
+        visitor = qobject_input_visitor_new(info->props);
+        if (!visit_start_struct(visitor, NULL, NULL, 0, errp)) {
+            visit_free(visitor);
+            object_unref(obj);
+            return;
+        }
+        for (e = qdict_first(qdict); e; e = qdict_next(qdict, e)) {
+            if (!object_property_set(obj, e->key, visitor, &err)) {
+                break;
+            }
+        }
+        if (!err) {
+            visit_check_struct(visitor, &err);
+        }
+        visit_end_struct(visitor, NULL);
+        visit_free(visitor);
+        if (err) {
+            error_propagate(errp, err);
+            object_unref(obj);
+            return;
+        }
+    }
+
+    /* copy the model and throw the cpu away */
+    memcpy(model, cpu->model, sizeof(*model));
+    object_unref(obj);
+}
+
+static void qdict_add_disabled_feat(const char *name, void *opaque)
+{
+    qdict_put_bool(opaque, name, false);
+}
+
+static void qdict_add_enabled_feat(const char *name, void *opaque)
+{
+    qdict_put_bool(opaque, name, true);
+}
+
+/* convert S390CPUDef into a static CpuModelInfo */
+static void cpu_info_from_model(CpuModelInfo *info, const S390CPUModel *model,
+                                bool delta_changes)
+{
+    QDict *qdict = qdict_new();
+    S390FeatBitmap bitmap;
+
+    /* always fallback to the static base model */
+    info->name = g_strdup_printf("%s-base", model->def->name);
+
+    if (delta_changes) {
+        /* features deleted from the base feature set */
+        bitmap_andnot(bitmap, model->def->base_feat, model->features,
+                      S390_FEAT_MAX);
+        if (!bitmap_empty(bitmap, S390_FEAT_MAX)) {
+            s390_feat_bitmap_to_ascii(bitmap, qdict, qdict_add_disabled_feat);
+        }
+
+        /* features added to the base feature set */
+        bitmap_andnot(bitmap, model->features, model->def->base_feat,
+                      S390_FEAT_MAX);
+        if (!bitmap_empty(bitmap, S390_FEAT_MAX)) {
+            s390_feat_bitmap_to_ascii(bitmap, qdict, qdict_add_enabled_feat);
+        }
+    } else {
+        /* expand all features */
+        s390_feat_bitmap_to_ascii(model->features, qdict,
+                                  qdict_add_enabled_feat);
+        bitmap_complement(bitmap, model->features, S390_FEAT_MAX);
+        s390_feat_bitmap_to_ascii(bitmap, qdict, qdict_add_disabled_feat);
+    }
+
+    if (!qdict_size(qdict)) {
+        qobject_unref(qdict);
+    } else {
+        info->props = QOBJECT(qdict);
+        info->has_props = true;
+    }
+}
+
+CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
+                                                      CpuModelInfo *model,
+                                                      Error **errp)
+{
+    Error *err = NULL;
+    CpuModelExpansionInfo *expansion_info = NULL;
+    S390CPUModel s390_model;
+    bool delta_changes = false;
+
+    /* convert it to our internal representation */
+    cpu_model_from_info(&s390_model, model, &err);
+    if (err) {
+        error_propagate(errp, err);
+        return NULL;
+    }
+
+    if (type == CPU_MODEL_EXPANSION_TYPE_STATIC) {
+        delta_changes = true;
+    } else if (type != CPU_MODEL_EXPANSION_TYPE_FULL) {
+        error_setg(errp, "The requested expansion type is not supported.");
+        return NULL;
+    }
+
+    /* convert it back to a static representation */
+    expansion_info = g_new0(CpuModelExpansionInfo, 1);
+    expansion_info->model = g_malloc0(sizeof(*expansion_info->model));
+    cpu_info_from_model(expansion_info->model, &s390_model, delta_changes);
+    return expansion_info;
+}
+
+static void list_add_feat(const char *name, void *opaque)
+{
+    strList **last = (strList **) opaque;
+
+    QAPI_LIST_PREPEND(*last, g_strdup(name));
+}
+
+CpuModelCompareInfo *qmp_query_cpu_model_comparison(CpuModelInfo *infoa,
+                                                     CpuModelInfo *infob,
+                                                     Error **errp)
+{
+    Error *err = NULL;
+    CpuModelCompareResult feat_result, gen_result;
+    CpuModelCompareInfo *compare_info;
+    S390FeatBitmap missing, added;
+    S390CPUModel modela, modelb;
+
+    /* convert both models to our internal representation */
+    cpu_model_from_info(&modela, infoa, &err);
+    if (err) {
+        error_propagate(errp, err);
+        return NULL;
+    }
+    cpu_model_from_info(&modelb, infob, &err);
+    if (err) {
+        error_propagate(errp, err);
+        return NULL;
+    }
+    compare_info = g_new0(CpuModelCompareInfo, 1);
+
+    /* check the cpu generation and ga level */
+    if (modela.def->gen == modelb.def->gen) {
+        if (modela.def->ec_ga == modelb.def->ec_ga) {
+            /* ec and corresponding bc are identical */
+            gen_result = CPU_MODEL_COMPARE_RESULT_IDENTICAL;
+        } else if (modela.def->ec_ga < modelb.def->ec_ga) {
+            gen_result = CPU_MODEL_COMPARE_RESULT_SUBSET;
+        } else {
+            gen_result = CPU_MODEL_COMPARE_RESULT_SUPERSET;
+        }
+    } else if (modela.def->gen < modelb.def->gen) {
+        gen_result = CPU_MODEL_COMPARE_RESULT_SUBSET;
+    } else {
+        gen_result = CPU_MODEL_COMPARE_RESULT_SUPERSET;
+    }
+    if (gen_result != CPU_MODEL_COMPARE_RESULT_IDENTICAL) {
+        /* both models cannot be made identical */
+        list_add_feat("type", &compare_info->responsible_properties);
+    }
+
+    /* check the feature set */
+    if (bitmap_equal(modela.features, modelb.features, S390_FEAT_MAX)) {
+        feat_result = CPU_MODEL_COMPARE_RESULT_IDENTICAL;
+    } else {
+        bitmap_andnot(missing, modela.features, modelb.features, S390_FEAT_MAX);
+        s390_feat_bitmap_to_ascii(missing,
+                                  &compare_info->responsible_properties,
+                                  list_add_feat);
+        bitmap_andnot(added, modelb.features, modela.features, S390_FEAT_MAX);
+        s390_feat_bitmap_to_ascii(added, &compare_info->responsible_properties,
+                                  list_add_feat);
+        if (bitmap_empty(missing, S390_FEAT_MAX)) {
+            feat_result = CPU_MODEL_COMPARE_RESULT_SUBSET;
+        } else if (bitmap_empty(added, S390_FEAT_MAX)) {
+            feat_result = CPU_MODEL_COMPARE_RESULT_SUPERSET;
+        } else {
+            feat_result = CPU_MODEL_COMPARE_RESULT_INCOMPATIBLE;
+        }
+    }
+
+    /* combine the results */
+    if (gen_result == feat_result) {
+        compare_info->result = gen_result;
+    } else if (feat_result == CPU_MODEL_COMPARE_RESULT_IDENTICAL) {
+        compare_info->result = gen_result;
+    } else if (gen_result == CPU_MODEL_COMPARE_RESULT_IDENTICAL) {
+        compare_info->result = feat_result;
+    } else {
+        compare_info->result = CPU_MODEL_COMPARE_RESULT_INCOMPATIBLE;
+    }
+    return compare_info;
+}
+
+CpuModelBaselineInfo *qmp_query_cpu_model_baseline(CpuModelInfo *infoa,
+                                                    CpuModelInfo *infob,
+                                                    Error **errp)
+{
+    Error *err = NULL;
+    CpuModelBaselineInfo *baseline_info;
+    S390CPUModel modela, modelb, model;
+    uint16_t cpu_type;
+    uint8_t max_gen_ga;
+    uint8_t max_gen;
+
+    /* convert both models to our internal representation */
+    cpu_model_from_info(&modela, infoa, &err);
+    if (err) {
+        error_propagate(errp, err);
+        return NULL;
+    }
+
+    cpu_model_from_info(&modelb, infob, &err);
+    if (err) {
+        error_propagate(errp, err);
+        return NULL;
+    }
+
+    /* features both models support */
+    bitmap_and(model.features, modela.features, modelb.features, S390_FEAT_MAX);
+
+    /* detect the maximum model not regarding features */
+    if (modela.def->gen == modelb.def->gen) {
+        if (modela.def->type == modelb.def->type) {
+            cpu_type = modela.def->type;
+        } else {
+            cpu_type = 0;
+        }
+        max_gen = modela.def->gen;
+        max_gen_ga = MIN(modela.def->ec_ga, modelb.def->ec_ga);
+    } else if (modela.def->gen > modelb.def->gen) {
+        cpu_type = modelb.def->type;
+        max_gen = modelb.def->gen;
+        max_gen_ga = modelb.def->ec_ga;
+    } else {
+        cpu_type = modela.def->type;
+        max_gen = modela.def->gen;
+        max_gen_ga = modela.def->ec_ga;
+    }
+
+    model.def = s390_find_cpu_def(cpu_type, max_gen, max_gen_ga,
+                                  model.features);
+
+    /* models without early base features (esan3) are bad */
+    if (!model.def) {
+        error_setg(errp, "No compatible CPU model could be created as"
+                   " important base features are disabled");
+        return NULL;
+    }
+
+    /* strip off features not part of the max model */
+    bitmap_and(model.features, model.features, model.def->full_feat,
+               S390_FEAT_MAX);
+
+    baseline_info = g_new0(CpuModelBaselineInfo, 1);
+    baseline_info->model = g_malloc0(sizeof(*baseline_info->model));
+    cpu_info_from_model(baseline_info->model, &model, true);
+    return baseline_info;
+}
+
+void apply_cpu_model(const S390CPUModel *model, Error **errp)
+{
+    Error *err = NULL;
+    static S390CPUModel applied_model;
+    static bool applied;
+
+    /*
+     * We have the same model for all VCPUs. KVM can only be configured before
+     * any VCPUs are defined in KVM.
+     */
+    if (applied) {
+        if (model && memcmp(&applied_model, model, sizeof(S390CPUModel))) {
+            error_setg(errp, "Mixed CPU models are not supported on s390x.");
+        }
+        return;
+    }
+
+    if (kvm_enabled()) {
+        kvm_s390_apply_cpu_model(model, &err);
+        if (err) {
+            error_propagate(errp, err);
+            return;
+        }
+    }
+
+    applied = true;
+    if (model) {
+        applied_model = *model;
+    }
+}
diff --git a/target/s390x/cpu_models_user.c b/target/s390x/cpu_models_user.c
new file mode 100644 (file)
index 0000000..df24d12
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * CPU models for s390x - User-mode
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * Author(s): David Hildenbrand <dahi@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "s390x-internal.h"
+#include "qapi/error.h"
+
+void apply_cpu_model(const S390CPUModel *model, Error **errp)
+{
+}
diff --git a/target/s390x/crypto_helper.c b/target/s390x/crypto_helper.c
deleted file mode 100644 (file)
index ff3fbc3..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- *  s390x crypto helpers
- *
- *  Copyright (c) 2017 Red Hat Inc
- *
- *  Authors:
- *   David Hildenbrand <david@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/main-loop.h"
-#include "internal.h"
-#include "tcg_s390x.h"
-#include "exec/helper-proto.h"
-#include "exec/exec-all.h"
-#include "exec/cpu_ldst.h"
-
-uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3,
-                     uint32_t type)
-{
-    const uintptr_t ra = GETPC();
-    const uint8_t mod = env->regs[0] & 0x80ULL;
-    const uint8_t fc = env->regs[0] & 0x7fULL;
-    uint8_t subfunc[16] = { 0 };
-    uint64_t param_addr;
-    int i;
-
-    switch (type) {
-    case S390_FEAT_TYPE_KMAC:
-    case S390_FEAT_TYPE_KIMD:
-    case S390_FEAT_TYPE_KLMD:
-    case S390_FEAT_TYPE_PCKMO:
-    case S390_FEAT_TYPE_PCC:
-        if (mod) {
-            tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
-        }
-        break;
-    }
-
-    s390_get_feat_block(type, subfunc);
-    if (!test_be_bit(fc, subfunc)) {
-        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
-    }
-
-    switch (fc) {
-    case 0: /* query subfunction */
-        for (i = 0; i < 16; i++) {
-            param_addr = wrap_address(env, env->regs[1] + i);
-            cpu_stb_data_ra(env, param_addr, subfunc[i], ra);
-        }
-        break;
-    default:
-        /* we don't implement any other subfunction yet */
-        g_assert_not_reached();
-    }
-
-    return 0;
-}
index d620cd4bd438daa6be01e5a1e4512cd4498471b1..76b01dcd68bbba7c6011069ac1eec4fa833a3a7e 100644 (file)
 
 #include "qemu/osdep.h"
 #include "cpu.h"
-#include "internal.h"
+#include "s390x-internal.h"
 #include "hw/watchdog/wdt_diag288.h"
 #include "sysemu/cpus.h"
 #include "hw/s390x/ipl.h"
 #include "hw/s390x/s390-virtio-ccw.h"
 #include "hw/s390x/pv.h"
-#include "kvm_s390x.h"
+#include "sysemu/kvm.h"
+#include "kvm/kvm_s390x.h"
 
 int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
 {
@@ -168,7 +169,7 @@ out:
             return;
         }
 
-        if (kvm_s390_get_hpage_1m()) {
+        if (kvm_enabled() && kvm_s390_get_hpage_1m()) {
             error_report("Protected VMs can currently not be backed with "
                          "huge pages");
             env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV;
diff --git a/target/s390x/excp_helper.c b/target/s390x/excp_helper.c
deleted file mode 100644 (file)
index 9c36142..0000000
+++ /dev/null
@@ -1,641 +0,0 @@
-/*
- * s390x exception / interrupt helpers
- *
- *  Copyright (c) 2009 Ulrich Hecht
- *  Copyright (c) 2011 Alexander Graf
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "internal.h"
-#include "exec/helper-proto.h"
-#include "qemu/timer.h"
-#include "exec/exec-all.h"
-#include "exec/cpu_ldst.h"
-#include "hw/s390x/ioinst.h"
-#include "exec/address-spaces.h"
-#include "tcg_s390x.h"
-#ifndef CONFIG_USER_ONLY
-#include "hw/s390x/s390_flic.h"
-#include "hw/boards.h"
-#endif
-
-void QEMU_NORETURN tcg_s390_program_interrupt(CPUS390XState *env,
-                                              uint32_t code, uintptr_t ra)
-{
-    CPUState *cs = env_cpu(env);
-
-    cpu_restore_state(cs, ra, true);
-    qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
-                  env->psw.addr);
-    trigger_pgm_exception(env, code);
-    cpu_loop_exit(cs);
-}
-
-void QEMU_NORETURN tcg_s390_data_exception(CPUS390XState *env, uint32_t dxc,
-                                           uintptr_t ra)
-{
-    g_assert(dxc <= 0xff);
-#if !defined(CONFIG_USER_ONLY)
-    /* Store the DXC into the lowcore */
-    stl_phys(env_cpu(env)->as,
-             env->psa + offsetof(LowCore, data_exc_code), dxc);
-#endif
-
-    /* Store the DXC into the FPC if AFP is enabled */
-    if (env->cregs[0] & CR0_AFP) {
-        env->fpc = deposit32(env->fpc, 8, 8, dxc);
-    }
-    tcg_s390_program_interrupt(env, PGM_DATA, ra);
-}
-
-void QEMU_NORETURN tcg_s390_vector_exception(CPUS390XState *env, uint32_t vxc,
-                                             uintptr_t ra)
-{
-    g_assert(vxc <= 0xff);
-#if !defined(CONFIG_USER_ONLY)
-    /* Always store the VXC into the lowcore, without AFP it is undefined */
-    stl_phys(env_cpu(env)->as,
-             env->psa + offsetof(LowCore, data_exc_code), vxc);
-#endif
-
-    /* Always store the VXC into the FPC, without AFP it is undefined */
-    env->fpc = deposit32(env->fpc, 8, 8, vxc);
-    tcg_s390_program_interrupt(env, PGM_VECTOR_PROCESSING, ra);
-}
-
-void HELPER(data_exception)(CPUS390XState *env, uint32_t dxc)
-{
-    tcg_s390_data_exception(env, dxc, GETPC());
-}
-
-#if defined(CONFIG_USER_ONLY)
-
-void s390_cpu_do_interrupt(CPUState *cs)
-{
-    cs->exception_index = -1;
-}
-
-bool s390_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
-                       MMUAccessType access_type, int mmu_idx,
-                       bool probe, uintptr_t retaddr)
-{
-    S390CPU *cpu = S390_CPU(cs);
-
-    trigger_pgm_exception(&cpu->env, PGM_ADDRESSING);
-    /* On real machines this value is dropped into LowMem.  Since this
-       is userland, simply put this someplace that cpu_loop can find it.  */
-    cpu->env.__excp_addr = address;
-    cpu_loop_exit_restore(cs, retaddr);
-}
-
-#else /* !CONFIG_USER_ONLY */
-
-static inline uint64_t cpu_mmu_idx_to_asc(int mmu_idx)
-{
-    switch (mmu_idx) {
-    case MMU_PRIMARY_IDX:
-        return PSW_ASC_PRIMARY;
-    case MMU_SECONDARY_IDX:
-        return PSW_ASC_SECONDARY;
-    case MMU_HOME_IDX:
-        return PSW_ASC_HOME;
-    default:
-        abort();
-    }
-}
-
-bool s390_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
-                       MMUAccessType access_type, int mmu_idx,
-                       bool probe, uintptr_t retaddr)
-{
-    S390CPU *cpu = S390_CPU(cs);
-    CPUS390XState *env = &cpu->env;
-    target_ulong vaddr, raddr;
-    uint64_t asc, tec;
-    int prot, excp;
-
-    qemu_log_mask(CPU_LOG_MMU, "%s: addr 0x%" VADDR_PRIx " rw %d mmu_idx %d\n",
-                  __func__, address, access_type, mmu_idx);
-
-    vaddr = address;
-
-    if (mmu_idx < MMU_REAL_IDX) {
-        asc = cpu_mmu_idx_to_asc(mmu_idx);
-        /* 31-Bit mode */
-        if (!(env->psw.mask & PSW_MASK_64)) {
-            vaddr &= 0x7fffffff;
-        }
-        excp = mmu_translate(env, vaddr, access_type, asc, &raddr, &prot, &tec);
-    } else if (mmu_idx == MMU_REAL_IDX) {
-        /* 31-Bit mode */
-        if (!(env->psw.mask & PSW_MASK_64)) {
-            vaddr &= 0x7fffffff;
-        }
-        excp = mmu_translate_real(env, vaddr, access_type, &raddr, &prot, &tec);
-    } else {
-        g_assert_not_reached();
-    }
-
-    /* check out of RAM access */
-    if (!excp &&
-        !address_space_access_valid(&address_space_memory, raddr,
-                                    TARGET_PAGE_SIZE, access_type,
-                                    MEMTXATTRS_UNSPECIFIED)) {
-        MachineState *ms = MACHINE(qdev_get_machine());
-        qemu_log_mask(CPU_LOG_MMU,
-                      "%s: raddr %" PRIx64 " > ram_size %" PRIx64 "\n",
-                      __func__, (uint64_t)raddr, (uint64_t)ms->ram_size);
-        excp = PGM_ADDRESSING;
-        tec = 0; /* unused */
-    }
-
-    env->tlb_fill_exc = excp;
-    env->tlb_fill_tec = tec;
-
-    if (!excp) {
-        qemu_log_mask(CPU_LOG_MMU,
-                      "%s: set tlb %" PRIx64 " -> %" PRIx64 " (%x)\n",
-                      __func__, (uint64_t)vaddr, (uint64_t)raddr, prot);
-        tlb_set_page(cs, address & TARGET_PAGE_MASK, raddr, prot,
-                     mmu_idx, TARGET_PAGE_SIZE);
-        return true;
-    }
-    if (probe) {
-        return false;
-    }
-
-    if (excp != PGM_ADDRESSING) {
-        stq_phys(env_cpu(env)->as,
-                 env->psa + offsetof(LowCore, trans_exc_code), tec);
-    }
-
-    /*
-     * For data accesses, ILEN will be filled in from the unwind info,
-     * within cpu_loop_exit_restore.  For code accesses, retaddr == 0,
-     * and so unwinding will not occur.  However, ILEN is also undefined
-     * for that case -- we choose to set ILEN = 2.
-     */
-    env->int_pgm_ilen = 2;
-    trigger_pgm_exception(env, excp);
-    cpu_loop_exit_restore(cs, retaddr);
-}
-
-static void do_program_interrupt(CPUS390XState *env)
-{
-    uint64_t mask, addr;
-    LowCore *lowcore;
-    int ilen = env->int_pgm_ilen;
-
-    assert(ilen == 2 || ilen == 4 || ilen == 6);
-
-    switch (env->int_pgm_code) {
-    case PGM_PER:
-        if (env->per_perc_atmid & PER_CODE_EVENT_NULLIFICATION) {
-            break;
-        }
-        /* FALL THROUGH */
-    case PGM_OPERATION:
-    case PGM_PRIVILEGED:
-    case PGM_EXECUTE:
-    case PGM_PROTECTION:
-    case PGM_ADDRESSING:
-    case PGM_SPECIFICATION:
-    case PGM_DATA:
-    case PGM_FIXPT_OVERFLOW:
-    case PGM_FIXPT_DIVIDE:
-    case PGM_DEC_OVERFLOW:
-    case PGM_DEC_DIVIDE:
-    case PGM_HFP_EXP_OVERFLOW:
-    case PGM_HFP_EXP_UNDERFLOW:
-    case PGM_HFP_SIGNIFICANCE:
-    case PGM_HFP_DIVIDE:
-    case PGM_TRANS_SPEC:
-    case PGM_SPECIAL_OP:
-    case PGM_OPERAND:
-    case PGM_HFP_SQRT:
-    case PGM_PC_TRANS_SPEC:
-    case PGM_ALET_SPEC:
-    case PGM_MONITOR:
-        /* advance the PSW if our exception is not nullifying */
-        env->psw.addr += ilen;
-        break;
-    }
-
-    qemu_log_mask(CPU_LOG_INT,
-                  "%s: code=0x%x ilen=%d psw: %" PRIx64 " %" PRIx64 "\n",
-                  __func__, env->int_pgm_code, ilen, env->psw.mask,
-                  env->psw.addr);
-
-    lowcore = cpu_map_lowcore(env);
-
-    /* Signal PER events with the exception.  */
-    if (env->per_perc_atmid) {
-        env->int_pgm_code |= PGM_PER;
-        lowcore->per_address = cpu_to_be64(env->per_address);
-        lowcore->per_perc_atmid = cpu_to_be16(env->per_perc_atmid);
-        env->per_perc_atmid = 0;
-    }
-
-    lowcore->pgm_ilen = cpu_to_be16(ilen);
-    lowcore->pgm_code = cpu_to_be16(env->int_pgm_code);
-    lowcore->program_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
-    lowcore->program_old_psw.addr = cpu_to_be64(env->psw.addr);
-    mask = be64_to_cpu(lowcore->program_new_psw.mask);
-    addr = be64_to_cpu(lowcore->program_new_psw.addr);
-    lowcore->per_breaking_event_addr = cpu_to_be64(env->gbea);
-
-    cpu_unmap_lowcore(lowcore);
-
-    s390_cpu_set_psw(env, mask, addr);
-}
-
-static void do_svc_interrupt(CPUS390XState *env)
-{
-    uint64_t mask, addr;
-    LowCore *lowcore;
-
-    lowcore = cpu_map_lowcore(env);
-
-    lowcore->svc_code = cpu_to_be16(env->int_svc_code);
-    lowcore->svc_ilen = cpu_to_be16(env->int_svc_ilen);
-    lowcore->svc_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
-    lowcore->svc_old_psw.addr = cpu_to_be64(env->psw.addr + env->int_svc_ilen);
-    mask = be64_to_cpu(lowcore->svc_new_psw.mask);
-    addr = be64_to_cpu(lowcore->svc_new_psw.addr);
-
-    cpu_unmap_lowcore(lowcore);
-
-    s390_cpu_set_psw(env, mask, addr);
-
-    /* When a PER event is pending, the PER exception has to happen
-       immediately after the SERVICE CALL one.  */
-    if (env->per_perc_atmid) {
-        env->int_pgm_code = PGM_PER;
-        env->int_pgm_ilen = env->int_svc_ilen;
-        do_program_interrupt(env);
-    }
-}
-
-#define VIRTIO_SUBCODE_64 0x0D00
-
-static void do_ext_interrupt(CPUS390XState *env)
-{
-    QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic());
-    S390CPU *cpu = env_archcpu(env);
-    uint64_t mask, addr;
-    uint16_t cpu_addr;
-    LowCore *lowcore;
-
-    if (!(env->psw.mask & PSW_MASK_EXT)) {
-        cpu_abort(CPU(cpu), "Ext int w/o ext mask\n");
-    }
-
-    lowcore = cpu_map_lowcore(env);
-
-    if ((env->pending_int & INTERRUPT_EMERGENCY_SIGNAL) &&
-        (env->cregs[0] & CR0_EMERGENCY_SIGNAL_SC)) {
-        MachineState *ms = MACHINE(qdev_get_machine());
-        unsigned int max_cpus = ms->smp.max_cpus;
-
-        lowcore->ext_int_code = cpu_to_be16(EXT_EMERGENCY);
-        cpu_addr = find_first_bit(env->emergency_signals, S390_MAX_CPUS);
-        g_assert(cpu_addr < S390_MAX_CPUS);
-        lowcore->cpu_addr = cpu_to_be16(cpu_addr);
-        clear_bit(cpu_addr, env->emergency_signals);
-        if (bitmap_empty(env->emergency_signals, max_cpus)) {
-            env->pending_int &= ~INTERRUPT_EMERGENCY_SIGNAL;
-        }
-    } else if ((env->pending_int & INTERRUPT_EXTERNAL_CALL) &&
-               (env->cregs[0] & CR0_EXTERNAL_CALL_SC)) {
-        lowcore->ext_int_code = cpu_to_be16(EXT_EXTERNAL_CALL);
-        lowcore->cpu_addr = cpu_to_be16(env->external_call_addr);
-        env->pending_int &= ~INTERRUPT_EXTERNAL_CALL;
-    } else if ((env->pending_int & INTERRUPT_EXT_CLOCK_COMPARATOR) &&
-               (env->cregs[0] & CR0_CKC_SC)) {
-        lowcore->ext_int_code = cpu_to_be16(EXT_CLOCK_COMP);
-        lowcore->cpu_addr = 0;
-        env->pending_int &= ~INTERRUPT_EXT_CLOCK_COMPARATOR;
-    } else if ((env->pending_int & INTERRUPT_EXT_CPU_TIMER) &&
-               (env->cregs[0] & CR0_CPU_TIMER_SC)) {
-        lowcore->ext_int_code = cpu_to_be16(EXT_CPU_TIMER);
-        lowcore->cpu_addr = 0;
-        env->pending_int &= ~INTERRUPT_EXT_CPU_TIMER;
-    } else if (qemu_s390_flic_has_service(flic) &&
-               (env->cregs[0] & CR0_SERVICE_SC)) {
-        uint32_t param;
-
-        param = qemu_s390_flic_dequeue_service(flic);
-        lowcore->ext_int_code = cpu_to_be16(EXT_SERVICE);
-        lowcore->ext_params = cpu_to_be32(param);
-        lowcore->cpu_addr = 0;
-    } else {
-        g_assert_not_reached();
-    }
-
-    mask = be64_to_cpu(lowcore->external_new_psw.mask);
-    addr = be64_to_cpu(lowcore->external_new_psw.addr);
-    lowcore->external_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
-    lowcore->external_old_psw.addr = cpu_to_be64(env->psw.addr);
-
-    cpu_unmap_lowcore(lowcore);
-
-    s390_cpu_set_psw(env, mask, addr);
-}
-
-static void do_io_interrupt(CPUS390XState *env)
-{
-    QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic());
-    uint64_t mask, addr;
-    QEMUS390FlicIO *io;
-    LowCore *lowcore;
-
-    g_assert(env->psw.mask & PSW_MASK_IO);
-    io = qemu_s390_flic_dequeue_io(flic, env->cregs[6]);
-    g_assert(io);
-
-    lowcore = cpu_map_lowcore(env);
-
-    lowcore->subchannel_id = cpu_to_be16(io->id);
-    lowcore->subchannel_nr = cpu_to_be16(io->nr);
-    lowcore->io_int_parm = cpu_to_be32(io->parm);
-    lowcore->io_int_word = cpu_to_be32(io->word);
-    lowcore->io_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
-    lowcore->io_old_psw.addr = cpu_to_be64(env->psw.addr);
-    mask = be64_to_cpu(lowcore->io_new_psw.mask);
-    addr = be64_to_cpu(lowcore->io_new_psw.addr);
-
-    cpu_unmap_lowcore(lowcore);
-    g_free(io);
-
-    s390_cpu_set_psw(env, mask, addr);
-}
-
-typedef struct MchkExtSaveArea {
-    uint64_t    vregs[32][2];                     /* 0x0000 */
-    uint8_t     pad_0x0200[0x0400 - 0x0200];      /* 0x0200 */
-} MchkExtSaveArea;
-QEMU_BUILD_BUG_ON(sizeof(MchkExtSaveArea) != 1024);
-
-static int mchk_store_vregs(CPUS390XState *env, uint64_t mcesao)
-{
-    hwaddr len = sizeof(MchkExtSaveArea);
-    MchkExtSaveArea *sa;
-    int i;
-
-    sa = cpu_physical_memory_map(mcesao, &len, true);
-    if (!sa) {
-        return -EFAULT;
-    }
-    if (len != sizeof(MchkExtSaveArea)) {
-        cpu_physical_memory_unmap(sa, len, 1, 0);
-        return -EFAULT;
-    }
-
-    for (i = 0; i < 32; i++) {
-        sa->vregs[i][0] = cpu_to_be64(env->vregs[i][0]);
-        sa->vregs[i][1] = cpu_to_be64(env->vregs[i][1]);
-    }
-
-    cpu_physical_memory_unmap(sa, len, 1, len);
-    return 0;
-}
-
-static void do_mchk_interrupt(CPUS390XState *env)
-{
-    QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic());
-    uint64_t mcic = s390_build_validity_mcic() | MCIC_SC_CP;
-    uint64_t mask, addr, mcesao = 0;
-    LowCore *lowcore;
-    int i;
-
-    /* for now we only support channel report machine checks (floating) */
-    g_assert(env->psw.mask & PSW_MASK_MCHECK);
-    g_assert(env->cregs[14] & CR14_CHANNEL_REPORT_SC);
-
-    qemu_s390_flic_dequeue_crw_mchk(flic);
-
-    lowcore = cpu_map_lowcore(env);
-
-    /* extended save area */
-    if (mcic & MCIC_VB_VR) {
-        /* length and alignment is 1024 bytes */
-        mcesao = be64_to_cpu(lowcore->mcesad) & ~0x3ffull;
-    }
-
-    /* try to store vector registers */
-    if (!mcesao || mchk_store_vregs(env, mcesao)) {
-        mcic &= ~MCIC_VB_VR;
-    }
-
-    /* we are always in z/Architecture mode */
-    lowcore->ar_access_id = 1;
-
-    for (i = 0; i < 16; i++) {
-        lowcore->floating_pt_save_area[i] = cpu_to_be64(*get_freg(env, i));
-        lowcore->gpregs_save_area[i] = cpu_to_be64(env->regs[i]);
-        lowcore->access_regs_save_area[i] = cpu_to_be32(env->aregs[i]);
-        lowcore->cregs_save_area[i] = cpu_to_be64(env->cregs[i]);
-    }
-    lowcore->prefixreg_save_area = cpu_to_be32(env->psa);
-    lowcore->fpt_creg_save_area = cpu_to_be32(env->fpc);
-    lowcore->tod_progreg_save_area = cpu_to_be32(env->todpr);
-    lowcore->cpu_timer_save_area = cpu_to_be64(env->cputm);
-    lowcore->clock_comp_save_area = cpu_to_be64(env->ckc >> 8);
-
-    lowcore->mcic = cpu_to_be64(mcic);
-    lowcore->mcck_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
-    lowcore->mcck_old_psw.addr = cpu_to_be64(env->psw.addr);
-    mask = be64_to_cpu(lowcore->mcck_new_psw.mask);
-    addr = be64_to_cpu(lowcore->mcck_new_psw.addr);
-
-    cpu_unmap_lowcore(lowcore);
-
-    s390_cpu_set_psw(env, mask, addr);
-}
-
-void s390_cpu_do_interrupt(CPUState *cs)
-{
-    QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic());
-    S390CPU *cpu = S390_CPU(cs);
-    CPUS390XState *env = &cpu->env;
-    bool stopped = false;
-
-    qemu_log_mask(CPU_LOG_INT, "%s: %d at psw=%" PRIx64 ":%" PRIx64 "\n",
-                  __func__, cs->exception_index, env->psw.mask, env->psw.addr);
-
-try_deliver:
-    /* handle machine checks */
-    if (cs->exception_index == -1 && s390_cpu_has_mcck_int(cpu)) {
-        cs->exception_index = EXCP_MCHK;
-    }
-    /* handle external interrupts */
-    if (cs->exception_index == -1 && s390_cpu_has_ext_int(cpu)) {
-        cs->exception_index = EXCP_EXT;
-    }
-    /* handle I/O interrupts */
-    if (cs->exception_index == -1 && s390_cpu_has_io_int(cpu)) {
-        cs->exception_index = EXCP_IO;
-    }
-    /* RESTART interrupt */
-    if (cs->exception_index == -1 && s390_cpu_has_restart_int(cpu)) {
-        cs->exception_index = EXCP_RESTART;
-    }
-    /* STOP interrupt has least priority */
-    if (cs->exception_index == -1 && s390_cpu_has_stop_int(cpu)) {
-        cs->exception_index = EXCP_STOP;
-    }
-
-    switch (cs->exception_index) {
-    case EXCP_PGM:
-        do_program_interrupt(env);
-        break;
-    case EXCP_SVC:
-        do_svc_interrupt(env);
-        break;
-    case EXCP_EXT:
-        do_ext_interrupt(env);
-        break;
-    case EXCP_IO:
-        do_io_interrupt(env);
-        break;
-    case EXCP_MCHK:
-        do_mchk_interrupt(env);
-        break;
-    case EXCP_RESTART:
-        do_restart_interrupt(env);
-        break;
-    case EXCP_STOP:
-        do_stop_interrupt(env);
-        stopped = true;
-        break;
-    }
-
-    if (cs->exception_index != -1 && !stopped) {
-        /* check if there are more pending interrupts to deliver */
-        cs->exception_index = -1;
-        goto try_deliver;
-    }
-    cs->exception_index = -1;
-
-    /* we might still have pending interrupts, but not deliverable */
-    if (!env->pending_int && !qemu_s390_flic_has_any(flic)) {
-        cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
-    }
-
-    /* WAIT PSW during interrupt injection or STOP interrupt */
-    if ((env->psw.mask & PSW_MASK_WAIT) || stopped) {
-        /* don't trigger a cpu_loop_exit(), use an interrupt instead */
-        cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HALT);
-    } else if (cs->halted) {
-        /* unhalt if we had a WAIT PSW somehwere in our injection chain */
-        s390_cpu_unhalt(cpu);
-    }
-}
-
-bool s390_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
-{
-    if (interrupt_request & CPU_INTERRUPT_HARD) {
-        S390CPU *cpu = S390_CPU(cs);
-        CPUS390XState *env = &cpu->env;
-
-        if (env->ex_value) {
-            /* Execution of the target insn is indivisible from
-               the parent EXECUTE insn.  */
-            return false;
-        }
-        if (s390_cpu_has_int(cpu)) {
-            s390_cpu_do_interrupt(cs);
-            return true;
-        }
-        if (env->psw.mask & PSW_MASK_WAIT) {
-            /* Woken up because of a floating interrupt but it has already
-             * been delivered. Go back to sleep. */
-            cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HALT);
-        }
-    }
-    return false;
-}
-
-void s390x_cpu_debug_excp_handler(CPUState *cs)
-{
-    S390CPU *cpu = S390_CPU(cs);
-    CPUS390XState *env = &cpu->env;
-    CPUWatchpoint *wp_hit = cs->watchpoint_hit;
-
-    if (wp_hit && wp_hit->flags & BP_CPU) {
-        /* FIXME: When the storage-alteration-space control bit is set,
-           the exception should only be triggered if the memory access
-           is done using an address space with the storage-alteration-event
-           bit set.  We have no way to detect that with the current
-           watchpoint code.  */
-        cs->watchpoint_hit = NULL;
-
-        env->per_address = env->psw.addr;
-        env->per_perc_atmid |= PER_CODE_EVENT_STORE | get_per_atmid(env);
-        /* FIXME: We currently no way to detect the address space used
-           to trigger the watchpoint.  For now just consider it is the
-           current default ASC. This turn to be true except when MVCP
-           and MVCS instrutions are not used.  */
-        env->per_perc_atmid |= env->psw.mask & (PSW_MASK_ASC) >> 46;
-
-        /*
-         * Remove all watchpoints to re-execute the code.  A PER exception
-         * will be triggered, it will call s390_cpu_set_psw which will
-         * recompute the watchpoints.
-         */
-        cpu_watchpoint_remove_all(cs, BP_CPU);
-        cpu_loop_exit_noexc(cs);
-    }
-}
-
-/* Unaligned accesses are only diagnosed with MO_ALIGN.  At the moment,
-   this is only for the atomic operations, for which we want to raise a
-   specification exception.  */
-void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
-                                   MMUAccessType access_type,
-                                   int mmu_idx, uintptr_t retaddr)
-{
-    S390CPU *cpu = S390_CPU(cs);
-    CPUS390XState *env = &cpu->env;
-
-    tcg_s390_program_interrupt(env, PGM_SPECIFICATION, retaddr);
-}
-
-static void QEMU_NORETURN monitor_event(CPUS390XState *env,
-                                        uint64_t monitor_code,
-                                        uint8_t monitor_class, uintptr_t ra)
-{
-    /* Store the Monitor Code and the Monitor Class Number into the lowcore */
-    stq_phys(env_cpu(env)->as,
-             env->psa + offsetof(LowCore, monitor_code), monitor_code);
-    stw_phys(env_cpu(env)->as,
-             env->psa + offsetof(LowCore, mon_class_num), monitor_class);
-
-    tcg_s390_program_interrupt(env, PGM_MONITOR, ra);
-}
-
-void HELPER(monitor_call)(CPUS390XState *env, uint64_t monitor_code,
-                          uint32_t monitor_class)
-{
-    g_assert(monitor_class <= 0xff);
-
-    if (env->cregs[8] & (0x8000 >> monitor_class)) {
-        monitor_event(env, monitor_code, monitor_class, GETPC());
-    }
-}
-
-#endif /* !CONFIG_USER_ONLY */
diff --git a/target/s390x/fpu_helper.c b/target/s390x/fpu_helper.c
deleted file mode 100644 (file)
index 13af158..0000000
+++ /dev/null
@@ -1,921 +0,0 @@
-/*
- *  S/390 FPU helper routines
- *
- *  Copyright (c) 2009 Ulrich Hecht
- *  Copyright (c) 2009 Alexander Graf
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "internal.h"
-#include "tcg_s390x.h"
-#include "exec/exec-all.h"
-#include "exec/cpu_ldst.h"
-#include "exec/helper-proto.h"
-#include "fpu/softfloat.h"
-
-/* #define DEBUG_HELPER */
-#ifdef DEBUG_HELPER
-#define HELPER_LOG(x...) qemu_log(x)
-#else
-#define HELPER_LOG(x...)
-#endif
-
-#define RET128(F) (env->retxl = F.low, F.high)
-
-uint8_t s390_softfloat_exc_to_ieee(unsigned int exc)
-{
-    uint8_t s390_exc = 0;
-
-    s390_exc |= (exc & float_flag_invalid) ? S390_IEEE_MASK_INVALID : 0;
-    s390_exc |= (exc & float_flag_divbyzero) ? S390_IEEE_MASK_DIVBYZERO : 0;
-    s390_exc |= (exc & float_flag_overflow) ? S390_IEEE_MASK_OVERFLOW : 0;
-    s390_exc |= (exc & float_flag_underflow) ? S390_IEEE_MASK_UNDERFLOW : 0;
-    s390_exc |= (exc & float_flag_inexact) ? S390_IEEE_MASK_INEXACT : 0;
-
-    return s390_exc;
-}
-
-/* Should be called after any operation that may raise IEEE exceptions.  */
-static void handle_exceptions(CPUS390XState *env, bool XxC, uintptr_t retaddr)
-{
-    unsigned s390_exc, qemu_exc;
-
-    /* Get the exceptions raised by the current operation.  Reset the
-       fpu_status contents so that the next operation has a clean slate.  */
-    qemu_exc = env->fpu_status.float_exception_flags;
-    if (qemu_exc == 0) {
-        return;
-    }
-    env->fpu_status.float_exception_flags = 0;
-    s390_exc = s390_softfloat_exc_to_ieee(qemu_exc);
-
-    /*
-     * IEEE-Underflow exception recognition exists if a tininess condition
-     * (underflow) exists and
-     * - The mask bit in the FPC is zero and the result is inexact
-     * - The mask bit in the FPC is one
-     * So tininess conditions that are not inexact don't trigger any
-     * underflow action in case the mask bit is not one.
-     */
-    if (!(s390_exc & S390_IEEE_MASK_INEXACT) &&
-        !((env->fpc >> 24) & S390_IEEE_MASK_UNDERFLOW)) {
-        s390_exc &= ~S390_IEEE_MASK_UNDERFLOW;
-    }
-
-    /*
-     * FIXME:
-     * 1. Right now, all inexact conditions are inidicated as
-     *    "truncated" (0) and never as "incremented" (1) in the DXC.
-     * 2. Only traps due to invalid/divbyzero are suppressing. Other traps
-     *    are completing, meaning the target register has to be written!
-     *    This, however will mean that we have to write the register before
-     *    triggering the trap - impossible right now.
-     */
-
-    /*
-     * invalid/divbyzero cannot coexist with other conditions.
-     * overflow/underflow however can coexist with inexact, we have to
-     * handle it separatly.
-     */
-    if (s390_exc & ~S390_IEEE_MASK_INEXACT) {
-        if (s390_exc & ~S390_IEEE_MASK_INEXACT & env->fpc >> 24) {
-            /* trap condition - inexact reported along */
-            tcg_s390_data_exception(env, s390_exc, retaddr);
-        }
-        /* nontrap condition - inexact handled differently */
-        env->fpc |= (s390_exc & ~S390_IEEE_MASK_INEXACT) << 16;
-    }
-
-    /* inexact handling */
-    if (s390_exc & S390_IEEE_MASK_INEXACT && !XxC) {
-        /* trap condition - overflow/underflow _not_ reported along */
-        if (s390_exc & S390_IEEE_MASK_INEXACT & env->fpc >> 24) {
-            tcg_s390_data_exception(env, s390_exc & S390_IEEE_MASK_INEXACT,
-                                    retaddr);
-        }
-        /* nontrap condition */
-        env->fpc |= (s390_exc & S390_IEEE_MASK_INEXACT) << 16;
-    }
-}
-
-int float_comp_to_cc(CPUS390XState *env, FloatRelation float_compare)
-{
-    switch (float_compare) {
-    case float_relation_equal:
-        return 0;
-    case float_relation_less:
-        return 1;
-    case float_relation_greater:
-        return 2;
-    case float_relation_unordered:
-        return 3;
-    default:
-        cpu_abort(env_cpu(env), "unknown return value for float compare\n");
-    }
-}
-
-/* condition codes for unary FP ops */
-uint32_t set_cc_nz_f32(float32 v)
-{
-    if (float32_is_any_nan(v)) {
-        return 3;
-    } else if (float32_is_zero(v)) {
-        return 0;
-    } else if (float32_is_neg(v)) {
-        return 1;
-    } else {
-        return 2;
-    }
-}
-
-uint32_t set_cc_nz_f64(float64 v)
-{
-    if (float64_is_any_nan(v)) {
-        return 3;
-    } else if (float64_is_zero(v)) {
-        return 0;
-    } else if (float64_is_neg(v)) {
-        return 1;
-    } else {
-        return 2;
-    }
-}
-
-uint32_t set_cc_nz_f128(float128 v)
-{
-    if (float128_is_any_nan(v)) {
-        return 3;
-    } else if (float128_is_zero(v)) {
-        return 0;
-    } else if (float128_is_neg(v)) {
-        return 1;
-    } else {
-        return 2;
-    }
-}
-
-static inline uint8_t round_from_m34(uint32_t m34)
-{
-    return extract32(m34, 0, 4);
-}
-
-static inline bool xxc_from_m34(uint32_t m34)
-{
-    /* XxC is bit 1 of m4 */
-    return extract32(m34, 4 + 3 - 1, 1);
-}
-
-/* 32-bit FP addition */
-uint64_t HELPER(aeb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
-{
-    float32 ret = float32_add(f1, f2, &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return ret;
-}
-
-/* 64-bit FP addition */
-uint64_t HELPER(adb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
-{
-    float64 ret = float64_add(f1, f2, &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return ret;
-}
-
-/* 128-bit FP addition */
-uint64_t HELPER(axb)(CPUS390XState *env, uint64_t ah, uint64_t al,
-                     uint64_t bh, uint64_t bl)
-{
-    float128 ret = float128_add(make_float128(ah, al),
-                                make_float128(bh, bl),
-                                &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return RET128(ret);
-}
-
-/* 32-bit FP subtraction */
-uint64_t HELPER(seb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
-{
-    float32 ret = float32_sub(f1, f2, &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return ret;
-}
-
-/* 64-bit FP subtraction */
-uint64_t HELPER(sdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
-{
-    float64 ret = float64_sub(f1, f2, &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return ret;
-}
-
-/* 128-bit FP subtraction */
-uint64_t HELPER(sxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
-                     uint64_t bh, uint64_t bl)
-{
-    float128 ret = float128_sub(make_float128(ah, al),
-                                make_float128(bh, bl),
-                                &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return RET128(ret);
-}
-
-/* 32-bit FP division */
-uint64_t HELPER(deb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
-{
-    float32 ret = float32_div(f1, f2, &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return ret;
-}
-
-/* 64-bit FP division */
-uint64_t HELPER(ddb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
-{
-    float64 ret = float64_div(f1, f2, &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return ret;
-}
-
-/* 128-bit FP division */
-uint64_t HELPER(dxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
-                     uint64_t bh, uint64_t bl)
-{
-    float128 ret = float128_div(make_float128(ah, al),
-                                make_float128(bh, bl),
-                                &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return RET128(ret);
-}
-
-/* 32-bit FP multiplication */
-uint64_t HELPER(meeb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
-{
-    float32 ret = float32_mul(f1, f2, &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return ret;
-}
-
-/* 64-bit FP multiplication */
-uint64_t HELPER(mdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
-{
-    float64 ret = float64_mul(f1, f2, &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return ret;
-}
-
-/* 64/32-bit FP multiplication */
-uint64_t HELPER(mdeb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
-{
-    float64 ret = float32_to_float64(f2, &env->fpu_status);
-    ret = float64_mul(f1, ret, &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return ret;
-}
-
-/* 128-bit FP multiplication */
-uint64_t HELPER(mxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
-                     uint64_t bh, uint64_t bl)
-{
-    float128 ret = float128_mul(make_float128(ah, al),
-                                make_float128(bh, bl),
-                                &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return RET128(ret);
-}
-
-/* 128/64-bit FP multiplication */
-uint64_t HELPER(mxdb)(CPUS390XState *env, uint64_t ah, uint64_t al,
-                      uint64_t f2)
-{
-    float128 ret = float64_to_float128(f2, &env->fpu_status);
-    ret = float128_mul(make_float128(ah, al), ret, &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return RET128(ret);
-}
-
-/* convert 32-bit float to 64-bit float */
-uint64_t HELPER(ldeb)(CPUS390XState *env, uint64_t f2)
-{
-    float64 ret = float32_to_float64(f2, &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return ret;
-}
-
-/* convert 128-bit float to 64-bit float */
-uint64_t HELPER(ldxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
-                      uint32_t m34)
-{
-    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
-    float64 ret = float128_to_float64(make_float128(ah, al), &env->fpu_status);
-
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_exceptions(env, xxc_from_m34(m34), GETPC());
-    return ret;
-}
-
-/* convert 64-bit float to 128-bit float */
-uint64_t HELPER(lxdb)(CPUS390XState *env, uint64_t f2)
-{
-    float128 ret = float64_to_float128(f2, &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return RET128(ret);
-}
-
-/* convert 32-bit float to 128-bit float */
-uint64_t HELPER(lxeb)(CPUS390XState *env, uint64_t f2)
-{
-    float128 ret = float32_to_float128(f2, &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return RET128(ret);
-}
-
-/* convert 64-bit float to 32-bit float */
-uint64_t HELPER(ledb)(CPUS390XState *env, uint64_t f2, uint32_t m34)
-{
-    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
-    float32 ret = float64_to_float32(f2, &env->fpu_status);
-
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_exceptions(env, xxc_from_m34(m34), GETPC());
-    return ret;
-}
-
-/* convert 128-bit float to 32-bit float */
-uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al,
-                      uint32_t m34)
-{
-    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
-    float32 ret = float128_to_float32(make_float128(ah, al), &env->fpu_status);
-
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_exceptions(env, xxc_from_m34(m34), GETPC());
-    return ret;
-}
-
-/* 32-bit FP compare */
-uint32_t HELPER(ceb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
-{
-    FloatRelation cmp = float32_compare_quiet(f1, f2, &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return float_comp_to_cc(env, cmp);
-}
-
-/* 64-bit FP compare */
-uint32_t HELPER(cdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
-{
-    FloatRelation cmp = float64_compare_quiet(f1, f2, &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return float_comp_to_cc(env, cmp);
-}
-
-/* 128-bit FP compare */
-uint32_t HELPER(cxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
-                     uint64_t bh, uint64_t bl)
-{
-    FloatRelation cmp = float128_compare_quiet(make_float128(ah, al),
-                                               make_float128(bh, bl),
-                                               &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return float_comp_to_cc(env, cmp);
-}
-
-int s390_swap_bfp_rounding_mode(CPUS390XState *env, int m3)
-{
-    int ret = env->fpu_status.float_rounding_mode;
-
-    switch (m3) {
-    case 0:
-        /* current mode */
-        break;
-    case 1:
-        /* round to nearest with ties away from 0 */
-        set_float_rounding_mode(float_round_ties_away, &env->fpu_status);
-        break;
-    case 3:
-        /* round to prepare for shorter precision */
-        set_float_rounding_mode(float_round_to_odd, &env->fpu_status);
-        break;
-    case 4:
-        /* round to nearest with ties to even */
-        set_float_rounding_mode(float_round_nearest_even, &env->fpu_status);
-        break;
-    case 5:
-        /* round to zero */
-        set_float_rounding_mode(float_round_to_zero, &env->fpu_status);
-        break;
-    case 6:
-        /* round to +inf */
-        set_float_rounding_mode(float_round_up, &env->fpu_status);
-        break;
-    case 7:
-        /* round to -inf */
-        set_float_rounding_mode(float_round_down, &env->fpu_status);
-        break;
-    default:
-        g_assert_not_reached();
-    }
-    return ret;
-}
-
-void s390_restore_bfp_rounding_mode(CPUS390XState *env, int old_mode)
-{
-    set_float_rounding_mode(old_mode, &env->fpu_status);
-}
-
-/* convert 64-bit int to 32-bit float */
-uint64_t HELPER(cegb)(CPUS390XState *env, int64_t v2, uint32_t m34)
-{
-    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
-    float32 ret = int64_to_float32(v2, &env->fpu_status);
-
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_exceptions(env, xxc_from_m34(m34), GETPC());
-    return ret;
-}
-
-/* convert 64-bit int to 64-bit float */
-uint64_t HELPER(cdgb)(CPUS390XState *env, int64_t v2, uint32_t m34)
-{
-    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
-    float64 ret = int64_to_float64(v2, &env->fpu_status);
-
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_exceptions(env, xxc_from_m34(m34), GETPC());
-    return ret;
-}
-
-/* convert 64-bit int to 128-bit float */
-uint64_t HELPER(cxgb)(CPUS390XState *env, int64_t v2, uint32_t m34)
-{
-    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
-    float128 ret = int64_to_float128(v2, &env->fpu_status);
-
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_exceptions(env, xxc_from_m34(m34), GETPC());
-    return RET128(ret);
-}
-
-/* convert 64-bit uint to 32-bit float */
-uint64_t HELPER(celgb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
-{
-    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
-    float32 ret = uint64_to_float32(v2, &env->fpu_status);
-
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_exceptions(env, xxc_from_m34(m34), GETPC());
-    return ret;
-}
-
-/* convert 64-bit uint to 64-bit float */
-uint64_t HELPER(cdlgb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
-{
-    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
-    float64 ret = uint64_to_float64(v2, &env->fpu_status);
-
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_exceptions(env, xxc_from_m34(m34), GETPC());
-    return ret;
-}
-
-/* convert 64-bit uint to 128-bit float */
-uint64_t HELPER(cxlgb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
-{
-    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
-    float128 ret = uint64_to_float128(v2, &env->fpu_status);
-
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_exceptions(env, xxc_from_m34(m34), GETPC());
-    return RET128(ret);
-}
-
-/* convert 32-bit float to 64-bit int */
-uint64_t HELPER(cgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
-{
-    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
-    int64_t ret = float32_to_int64(v2, &env->fpu_status);
-
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_exceptions(env, xxc_from_m34(m34), GETPC());
-    if (float32_is_any_nan(v2)) {
-        return INT64_MIN;
-    }
-    return ret;
-}
-
-/* convert 64-bit float to 64-bit int */
-uint64_t HELPER(cgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
-{
-    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
-    int64_t ret = float64_to_int64(v2, &env->fpu_status);
-
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_exceptions(env, xxc_from_m34(m34), GETPC());
-    if (float64_is_any_nan(v2)) {
-        return INT64_MIN;
-    }
-    return ret;
-}
-
-/* convert 128-bit float to 64-bit int */
-uint64_t HELPER(cgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
-{
-    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
-    float128 v2 = make_float128(h, l);
-    int64_t ret = float128_to_int64(v2, &env->fpu_status);
-
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_exceptions(env, xxc_from_m34(m34), GETPC());
-    if (float128_is_any_nan(v2)) {
-        return INT64_MIN;
-    }
-    return ret;
-}
-
-/* convert 32-bit float to 32-bit int */
-uint64_t HELPER(cfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
-{
-    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
-    int32_t ret = float32_to_int32(v2, &env->fpu_status);
-
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_exceptions(env, xxc_from_m34(m34), GETPC());
-    if (float32_is_any_nan(v2)) {
-        return INT32_MIN;
-    }
-    return ret;
-}
-
-/* convert 64-bit float to 32-bit int */
-uint64_t HELPER(cfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
-{
-    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
-    int32_t ret = float64_to_int32(v2, &env->fpu_status);
-
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_exceptions(env, xxc_from_m34(m34), GETPC());
-    if (float64_is_any_nan(v2)) {
-        return INT32_MIN;
-    }
-    return ret;
-}
-
-/* convert 128-bit float to 32-bit int */
-uint64_t HELPER(cfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
-{
-    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
-    float128 v2 = make_float128(h, l);
-    int32_t ret = float128_to_int32(v2, &env->fpu_status);
-
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_exceptions(env, xxc_from_m34(m34), GETPC());
-    if (float128_is_any_nan(v2)) {
-        return INT32_MIN;
-    }
-    return ret;
-}
-
-/* convert 32-bit float to 64-bit uint */
-uint64_t HELPER(clgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
-{
-    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
-    uint64_t ret = float32_to_uint64(v2, &env->fpu_status);
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_exceptions(env, xxc_from_m34(m34), GETPC());
-    if (float32_is_any_nan(v2)) {
-        return 0;
-    }
-    return ret;
-}
-
-/* convert 64-bit float to 64-bit uint */
-uint64_t HELPER(clgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
-{
-    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
-    uint64_t ret = float64_to_uint64(v2, &env->fpu_status);
-
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_exceptions(env, xxc_from_m34(m34), GETPC());
-    if (float64_is_any_nan(v2)) {
-        return 0;
-    }
-    return ret;
-}
-
-/* convert 128-bit float to 64-bit uint */
-uint64_t HELPER(clgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
-{
-    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
-    uint64_t ret = float128_to_uint64(make_float128(h, l), &env->fpu_status);
-
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_exceptions(env, xxc_from_m34(m34), GETPC());
-    if (float128_is_any_nan(make_float128(h, l))) {
-        return 0;
-    }
-    return ret;
-}
-
-/* convert 32-bit float to 32-bit uint */
-uint64_t HELPER(clfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
-{
-    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
-    uint32_t ret = float32_to_uint32(v2, &env->fpu_status);
-
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_exceptions(env, xxc_from_m34(m34), GETPC());
-    if (float32_is_any_nan(v2)) {
-        return 0;
-    }
-    return ret;
-}
-
-/* convert 64-bit float to 32-bit uint */
-uint64_t HELPER(clfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
-{
-    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
-    uint32_t ret = float64_to_uint32(v2, &env->fpu_status);
-
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_exceptions(env, xxc_from_m34(m34), GETPC());
-    if (float64_is_any_nan(v2)) {
-        return 0;
-    }
-    return ret;
-}
-
-/* convert 128-bit float to 32-bit uint */
-uint64_t HELPER(clfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
-{
-    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
-    uint32_t ret = float128_to_uint32(make_float128(h, l), &env->fpu_status);
-
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_exceptions(env, xxc_from_m34(m34), GETPC());
-    if (float128_is_any_nan(make_float128(h, l))) {
-        return 0;
-    }
-    return ret;
-}
-
-/* round to integer 32-bit */
-uint64_t HELPER(fieb)(CPUS390XState *env, uint64_t f2, uint32_t m34)
-{
-    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
-    float32 ret = float32_round_to_int(f2, &env->fpu_status);
-
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_exceptions(env, xxc_from_m34(m34), GETPC());
-    return ret;
-}
-
-/* round to integer 64-bit */
-uint64_t HELPER(fidb)(CPUS390XState *env, uint64_t f2, uint32_t m34)
-{
-    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
-    float64 ret = float64_round_to_int(f2, &env->fpu_status);
-
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_exceptions(env, xxc_from_m34(m34), GETPC());
-    return ret;
-}
-
-/* round to integer 128-bit */
-uint64_t HELPER(fixb)(CPUS390XState *env, uint64_t ah, uint64_t al,
-                      uint32_t m34)
-{
-    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
-    float128 ret = float128_round_to_int(make_float128(ah, al),
-                                         &env->fpu_status);
-
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_exceptions(env, xxc_from_m34(m34), GETPC());
-    return RET128(ret);
-}
-
-/* 32-bit FP compare and signal */
-uint32_t HELPER(keb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
-{
-    FloatRelation cmp = float32_compare(f1, f2, &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return float_comp_to_cc(env, cmp);
-}
-
-/* 64-bit FP compare and signal */
-uint32_t HELPER(kdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
-{
-    FloatRelation cmp = float64_compare(f1, f2, &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return float_comp_to_cc(env, cmp);
-}
-
-/* 128-bit FP compare and signal */
-uint32_t HELPER(kxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
-                     uint64_t bh, uint64_t bl)
-{
-    FloatRelation cmp = float128_compare(make_float128(ah, al),
-                                         make_float128(bh, bl),
-                                         &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return float_comp_to_cc(env, cmp);
-}
-
-/* 32-bit FP multiply and add */
-uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1,
-                      uint64_t f2, uint64_t f3)
-{
-    float32 ret = float32_muladd(f2, f3, f1, 0, &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return ret;
-}
-
-/* 64-bit FP multiply and add */
-uint64_t HELPER(madb)(CPUS390XState *env, uint64_t f1,
-                      uint64_t f2, uint64_t f3)
-{
-    float64 ret = float64_muladd(f2, f3, f1, 0, &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return ret;
-}
-
-/* 32-bit FP multiply and subtract */
-uint64_t HELPER(mseb)(CPUS390XState *env, uint64_t f1,
-                      uint64_t f2, uint64_t f3)
-{
-    float32 ret = float32_muladd(f2, f3, f1, float_muladd_negate_c,
-                                 &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return ret;
-}
-
-/* 64-bit FP multiply and subtract */
-uint64_t HELPER(msdb)(CPUS390XState *env, uint64_t f1,
-                      uint64_t f2, uint64_t f3)
-{
-    float64 ret = float64_muladd(f2, f3, f1, float_muladd_negate_c,
-                                 &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return ret;
-}
-
-/* The rightmost bit has the number 11. */
-static inline uint16_t dcmask(int bit, bool neg)
-{
-    return 1 << (11 - bit - neg);
-}
-
-#define DEF_FLOAT_DCMASK(_TYPE) \
-uint16_t _TYPE##_dcmask(CPUS390XState *env, _TYPE f1)              \
-{                                                                  \
-    const bool neg = _TYPE##_is_neg(f1);                           \
-                                                                   \
-    /* Sorted by most common cases - only one class is possible */ \
-    if (_TYPE##_is_normal(f1)) {                                   \
-        return dcmask(2, neg);                                     \
-    } else if (_TYPE##_is_zero(f1)) {                              \
-        return dcmask(0, neg);                                     \
-    } else if (_TYPE##_is_denormal(f1)) {                          \
-        return dcmask(4, neg);                                     \
-    } else if (_TYPE##_is_infinity(f1)) {                          \
-        return dcmask(6, neg);                                     \
-    } else if (_TYPE##_is_quiet_nan(f1, &env->fpu_status)) {       \
-        return dcmask(8, neg);                                     \
-    }                                                              \
-    /* signaling nan, as last remaining case */                    \
-    return dcmask(10, neg);                                        \
-}
-DEF_FLOAT_DCMASK(float32)
-DEF_FLOAT_DCMASK(float64)
-DEF_FLOAT_DCMASK(float128)
-
-/* test data class 32-bit */
-uint32_t HELPER(tceb)(CPUS390XState *env, uint64_t f1, uint64_t m2)
-{
-    return (m2 & float32_dcmask(env, f1)) != 0;
-}
-
-/* test data class 64-bit */
-uint32_t HELPER(tcdb)(CPUS390XState *env, uint64_t v1, uint64_t m2)
-{
-    return (m2 & float64_dcmask(env, v1)) != 0;
-}
-
-/* test data class 128-bit */
-uint32_t HELPER(tcxb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t m2)
-{
-    return (m2 & float128_dcmask(env, make_float128(ah, al))) != 0;
-}
-
-/* square root 32-bit */
-uint64_t HELPER(sqeb)(CPUS390XState *env, uint64_t f2)
-{
-    float32 ret = float32_sqrt(f2, &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return ret;
-}
-
-/* square root 64-bit */
-uint64_t HELPER(sqdb)(CPUS390XState *env, uint64_t f2)
-{
-    float64 ret = float64_sqrt(f2, &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return ret;
-}
-
-/* square root 128-bit */
-uint64_t HELPER(sqxb)(CPUS390XState *env, uint64_t ah, uint64_t al)
-{
-    float128 ret = float128_sqrt(make_float128(ah, al), &env->fpu_status);
-    handle_exceptions(env, false, GETPC());
-    return RET128(ret);
-}
-
-static const int fpc_to_rnd[8] = {
-    float_round_nearest_even,
-    float_round_to_zero,
-    float_round_up,
-    float_round_down,
-    -1,
-    -1,
-    -1,
-    float_round_to_odd,
-};
-
-/* set fpc */
-void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc)
-{
-    if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u ||
-        (!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) {
-        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
-    }
-
-    /* Install everything in the main FPC.  */
-    env->fpc = fpc;
-
-    /* Install the rounding mode in the shadow fpu_status.  */
-    set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status);
-}
-
-/* set fpc and signal */
-void HELPER(sfas)(CPUS390XState *env, uint64_t fpc)
-{
-    uint32_t signalling = env->fpc;
-    uint32_t s390_exc;
-
-    if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u ||
-        (!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) {
-        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
-    }
-
-    /*
-     * FPC is set to the FPC operand with a bitwise OR of the signalling
-     * flags.
-     */
-    env->fpc = fpc | (signalling & 0x00ff0000);
-    set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status);
-
-    /*
-     * If any signaling flag is enabled in the new FPC mask, a
-     * simulated-iee-exception exception occurs.
-     */
-    s390_exc = (signalling >> 16) & (fpc >> 24);
-    if (s390_exc) {
-        if (s390_exc & S390_IEEE_MASK_INVALID) {
-            s390_exc = S390_IEEE_MASK_INVALID;
-        } else if (s390_exc & S390_IEEE_MASK_DIVBYZERO) {
-            s390_exc = S390_IEEE_MASK_DIVBYZERO;
-        } else if (s390_exc & S390_IEEE_MASK_OVERFLOW) {
-            s390_exc &= (S390_IEEE_MASK_OVERFLOW | S390_IEEE_MASK_INEXACT);
-        } else if (s390_exc & S390_IEEE_MASK_UNDERFLOW) {
-            s390_exc &= (S390_IEEE_MASK_UNDERFLOW | S390_IEEE_MASK_INEXACT);
-        } else if (s390_exc & S390_IEEE_MASK_INEXACT) {
-            s390_exc = S390_IEEE_MASK_INEXACT;
-        } else if (s390_exc & S390_IEEE_MASK_QUANTUM) {
-            s390_exc = S390_IEEE_MASK_QUANTUM;
-        }
-        tcg_s390_data_exception(env, s390_exc | 3, GETPC());
-    }
-}
-
-/* set bfp rounding mode */
-void HELPER(srnm)(CPUS390XState *env, uint64_t rnd)
-{
-    if (rnd > 0x7 || fpc_to_rnd[rnd & 0x7] == -1) {
-        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
-    }
-
-    env->fpc = deposit32(env->fpc, 0, 3, rnd);
-    set_float_rounding_mode(fpc_to_rnd[rnd & 0x7], &env->fpu_status);
-}
index 5b4e38a13b2a126472814fad3ac23080c0cc2284..a5d69d0e0bc5d281821dafff4d245dcd557199b1 100644 (file)
@@ -20,7 +20,7 @@
 
 #include "qemu/osdep.h"
 #include "cpu.h"
-#include "internal.h"
+#include "s390x-internal.h"
 #include "exec/exec-all.h"
 #include "exec/gdbstub.h"
 #include "qemu/bitops.h"
index 242c95ede48aa2ab4fcd775aee12bff1c2b12df2..7d85322d6814411951d6610b19fe9217cdd076a7 100644 (file)
@@ -424,6 +424,8 @@ static uint16_t base_GEN15_GA1[] = {
     S390_FEAT_MISC_INSTRUCTION_EXT3,
 };
 
+#define base_GEN16_GA1 EmptyFeat
+
 /* Full features (in order of release)
  * Automatically includes corresponding base features.
  * Full features are all features this hardware supports even if kvm/QEMU do not
@@ -567,6 +569,15 @@ static uint16_t full_GEN15_GA1[] = {
     S390_FEAT_UNPACK,
 };
 
+static uint16_t full_GEN16_GA1[] = {
+    S390_FEAT_NNPA,
+    S390_FEAT_VECTOR_PACKED_DECIMAL_ENH2,
+    S390_FEAT_BEAR_ENH,
+    S390_FEAT_RDP,
+    S390_FEAT_PAI,
+};
+
+
 /* Default features (in order of release)
  * Automatically includes corresponding base features.
  * Default features are all features this version of QEMU supports for this
@@ -652,6 +663,8 @@ static uint16_t default_GEN15_GA1[] = {
     S390_FEAT_ETOKEN,
 };
 
+#define default_GEN16_GA1 EmptyFeat
+
 /* QEMU (CPU model) features */
 
 static uint16_t qemu_V2_11[] = {
@@ -785,6 +798,7 @@ static CpuFeatDefSpec CpuFeatDef[] = {
     CPU_FEAT_INITIALIZER(GEN14_GA1),
     CPU_FEAT_INITIALIZER(GEN14_GA2),
     CPU_FEAT_INITIALIZER(GEN15_GA1),
+    CPU_FEAT_INITIALIZER(GEN16_GA1),
 };
 
 #define FEAT_GROUP_INITIALIZER(_name)                  \
index 1445b74451f42d08f65828d4fc214e6a9fb38f38..6e35473c7f8a66dc16dcb997c529a59b88de4bac 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  S/390 helpers
+ *  S/390 helpers - sysemu only
  *
  *  Copyright (c) 2009 Ulrich Hecht
  *  Copyright (c) 2011 Alexander Graf
 
 #include "qemu/osdep.h"
 #include "cpu.h"
-#include "internal.h"
+#include "s390x-internal.h"
 #include "exec/gdbstub.h"
 #include "qemu/timer.h"
-#include "qemu/qemu-print.h"
 #include "hw/s390x/ioinst.h"
 #include "hw/s390x/pv.h"
 #include "sysemu/hw_accel.h"
 #include "sysemu/runstate.h"
-#ifndef CONFIG_USER_ONLY
 #include "sysemu/tcg.h"
-#endif
 
-#ifndef CONFIG_USER_ONLY
 void s390x_tod_timer(void *opaque)
 {
     cpu_inject_clock_comparator((S390CPU *) opaque);
@@ -285,157 +281,3 @@ int s390_store_adtl_status(S390CPU *cpu, hwaddr addr, hwaddr len)
     cpu_physical_memory_unmap(sa, len, 1, len);
     return 0;
 }
-#else
-/* For user-only, tcg is always enabled. */
-#define tcg_enabled() true
-#endif /* CONFIG_USER_ONLY */
-
-void s390_cpu_set_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
-{
-#ifndef CONFIG_USER_ONLY
-    uint64_t old_mask = env->psw.mask;
-#endif
-
-    env->psw.addr = addr;
-    env->psw.mask = mask;
-
-    /* KVM will handle all WAITs and trigger a WAIT exit on disabled_wait */
-    if (!tcg_enabled()) {
-        return;
-    }
-    env->cc_op = (mask >> 44) & 3;
-
-#ifndef CONFIG_USER_ONLY
-    if ((old_mask ^ mask) & PSW_MASK_PER) {
-        s390_cpu_recompute_watchpoints(env_cpu(env));
-    }
-
-    if (mask & PSW_MASK_WAIT) {
-        s390_handle_wait(env_archcpu(env));
-    }
-#endif
-}
-
-uint64_t s390_cpu_get_psw_mask(CPUS390XState *env)
-{
-    uint64_t r = env->psw.mask;
-
-    if (tcg_enabled()) {
-        uint64_t cc = calc_cc(env, env->cc_op, env->cc_src,
-                              env->cc_dst, env->cc_vr);
-
-        assert(cc <= 3);
-        r &= ~PSW_MASK_CC;
-        r |= cc << 44;
-    }
-
-    return r;
-}
-
-void s390_cpu_dump_state(CPUState *cs, FILE *f, int flags)
-{
-    S390CPU *cpu = S390_CPU(cs);
-    CPUS390XState *env = &cpu->env;
-    int i;
-
-    qemu_fprintf(f, "PSW=mask %016" PRIx64 " addr %016" PRIx64,
-                 s390_cpu_get_psw_mask(env), env->psw.addr);
-    if (!tcg_enabled()) {
-        qemu_fprintf(f, "\n");
-    } else if (env->cc_op > 3) {
-        qemu_fprintf(f, " cc %15s\n", cc_name(env->cc_op));
-    } else {
-        qemu_fprintf(f, " cc %02x\n", env->cc_op);
-    }
-
-    for (i = 0; i < 16; i++) {
-        qemu_fprintf(f, "R%02d=%016" PRIx64, i, env->regs[i]);
-        if ((i % 4) == 3) {
-            qemu_fprintf(f, "\n");
-        } else {
-            qemu_fprintf(f, " ");
-        }
-    }
-
-    if (flags & CPU_DUMP_FPU) {
-        if (s390_has_feat(S390_FEAT_VECTOR)) {
-            for (i = 0; i < 32; i++) {
-                qemu_fprintf(f, "V%02d=%016" PRIx64 "%016" PRIx64 "%c",
-                             i, env->vregs[i][0], env->vregs[i][1],
-                             i % 2 ? '\n' : ' ');
-            }
-        } else {
-            for (i = 0; i < 16; i++) {
-                qemu_fprintf(f, "F%02d=%016" PRIx64 "%c",
-                             i, *get_freg(env, i),
-                             (i % 4) == 3 ? '\n' : ' ');
-            }
-        }
-    }
-
-#ifndef CONFIG_USER_ONLY
-    for (i = 0; i < 16; i++) {
-        qemu_fprintf(f, "C%02d=%016" PRIx64, i, env->cregs[i]);
-        if ((i % 4) == 3) {
-            qemu_fprintf(f, "\n");
-        } else {
-            qemu_fprintf(f, " ");
-        }
-    }
-#endif
-
-#ifdef DEBUG_INLINE_BRANCHES
-    for (i = 0; i < CC_OP_MAX; i++) {
-        qemu_fprintf(f, "  %15s = %10ld\t%10ld\n", cc_name(i),
-                     inline_branch_miss[i], inline_branch_hit[i]);
-    }
-#endif
-
-    qemu_fprintf(f, "\n");
-}
-
-const char *cc_name(enum cc_op cc_op)
-{
-    static const char * const cc_names[] = {
-        [CC_OP_CONST0]    = "CC_OP_CONST0",
-        [CC_OP_CONST1]    = "CC_OP_CONST1",
-        [CC_OP_CONST2]    = "CC_OP_CONST2",
-        [CC_OP_CONST3]    = "CC_OP_CONST3",
-        [CC_OP_DYNAMIC]   = "CC_OP_DYNAMIC",
-        [CC_OP_STATIC]    = "CC_OP_STATIC",
-        [CC_OP_NZ]        = "CC_OP_NZ",
-        [CC_OP_ADDU]      = "CC_OP_ADDU",
-        [CC_OP_SUBU]      = "CC_OP_SUBU",
-        [CC_OP_LTGT_32]   = "CC_OP_LTGT_32",
-        [CC_OP_LTGT_64]   = "CC_OP_LTGT_64",
-        [CC_OP_LTUGTU_32] = "CC_OP_LTUGTU_32",
-        [CC_OP_LTUGTU_64] = "CC_OP_LTUGTU_64",
-        [CC_OP_LTGT0_32]  = "CC_OP_LTGT0_32",
-        [CC_OP_LTGT0_64]  = "CC_OP_LTGT0_64",
-        [CC_OP_ADD_64]    = "CC_OP_ADD_64",
-        [CC_OP_SUB_64]    = "CC_OP_SUB_64",
-        [CC_OP_ABS_64]    = "CC_OP_ABS_64",
-        [CC_OP_NABS_64]   = "CC_OP_NABS_64",
-        [CC_OP_ADD_32]    = "CC_OP_ADD_32",
-        [CC_OP_SUB_32]    = "CC_OP_SUB_32",
-        [CC_OP_ABS_32]    = "CC_OP_ABS_32",
-        [CC_OP_NABS_32]   = "CC_OP_NABS_32",
-        [CC_OP_COMP_32]   = "CC_OP_COMP_32",
-        [CC_OP_COMP_64]   = "CC_OP_COMP_64",
-        [CC_OP_TM_32]     = "CC_OP_TM_32",
-        [CC_OP_TM_64]     = "CC_OP_TM_64",
-        [CC_OP_NZ_F32]    = "CC_OP_NZ_F32",
-        [CC_OP_NZ_F64]    = "CC_OP_NZ_F64",
-        [CC_OP_NZ_F128]   = "CC_OP_NZ_F128",
-        [CC_OP_ICM]       = "CC_OP_ICM",
-        [CC_OP_SLA_32]    = "CC_OP_SLA_32",
-        [CC_OP_SLA_64]    = "CC_OP_SLA_64",
-        [CC_OP_FLOGR]     = "CC_OP_FLOGR",
-        [CC_OP_LCBB]      = "CC_OP_LCBB",
-        [CC_OP_VC]        = "CC_OP_VC",
-        [CC_OP_MULS_32]   = "CC_OP_MULS_32",
-        [CC_OP_MULS_64]   = "CC_OP_MULS_64",
-    };
-
-    return cc_names[cc_op];
-}
index ba045f559d4afb71354e6bbd933eba4c95b300eb..6215ca00bcbd3c91c81222a1f0dc10efa2b38350 100644 (file)
@@ -64,18 +64,18 @@ DEF_HELPER_FLAGS_5(cxb, TCG_CALL_NO_WG_SE, i32, env, i64, i64, i64, i64)
 DEF_HELPER_FLAGS_3(keb, TCG_CALL_NO_WG, i32, env, i64, i64)
 DEF_HELPER_FLAGS_3(kdb, TCG_CALL_NO_WG, i32, env, i64, i64)
 DEF_HELPER_FLAGS_5(kxb, TCG_CALL_NO_WG, i32, env, i64, i64, i64, i64)
-DEF_HELPER_FLAGS_3(cgeb, TCG_CALL_NO_WG, i64, env, i64, i32)
-DEF_HELPER_FLAGS_3(cgdb, TCG_CALL_NO_WG, i64, env, i64, i32)
-DEF_HELPER_FLAGS_4(cgxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32)
-DEF_HELPER_FLAGS_3(cfeb, TCG_CALL_NO_WG, i64, env, i64, i32)
-DEF_HELPER_FLAGS_3(cfdb, TCG_CALL_NO_WG, i64, env, i64, i32)
-DEF_HELPER_FLAGS_4(cfxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32)
-DEF_HELPER_FLAGS_3(clgeb, TCG_CALL_NO_WG, i64, env, i64, i32)
-DEF_HELPER_FLAGS_3(clgdb, TCG_CALL_NO_WG, i64, env, i64, i32)
-DEF_HELPER_FLAGS_4(clgxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32)
-DEF_HELPER_FLAGS_3(clfeb, TCG_CALL_NO_WG, i64, env, i64, i32)
-DEF_HELPER_FLAGS_3(clfdb, TCG_CALL_NO_WG, i64, env, i64, i32)
-DEF_HELPER_FLAGS_4(clfxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32)
+DEF_HELPER_3(cgeb, i64, env, i64, i32)
+DEF_HELPER_3(cgdb, i64, env, i64, i32)
+DEF_HELPER_4(cgxb, i64, env, i64, i64, i32)
+DEF_HELPER_3(cfeb, i64, env, i64, i32)
+DEF_HELPER_3(cfdb, i64, env, i64, i32)
+DEF_HELPER_4(cfxb, i64, env, i64, i64, i32)
+DEF_HELPER_3(clgeb, i64, env, i64, i32)
+DEF_HELPER_3(clgdb, i64, env, i64, i32)
+DEF_HELPER_4(clgxb, i64, env, i64, i64, i32)
+DEF_HELPER_3(clfeb, i64, env, i64, i32)
+DEF_HELPER_3(clfdb, i64, env, i64, i32)
+DEF_HELPER_4(clfxb, i64, env, i64, i64, i32)
 DEF_HELPER_FLAGS_3(fieb, TCG_CALL_NO_WG, i64, env, i64, i32)
 DEF_HELPER_FLAGS_3(fidb, TCG_CALL_NO_WG, i64, env, i64, i32)
 DEF_HELPER_FLAGS_4(fixb, TCG_CALL_NO_WG, i64, env, i64, i64, i32)
diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def
deleted file mode 100644 (file)
index 3e55942..0000000
+++ /dev/null
@@ -1,1398 +0,0 @@
-/*
- *  Arguments to the opcode prototypes
- *
- *  C(OPC,    NAME,    FMT,   FAC, I1, I2, P, W, OP, CC)
- *  D(OPC,    NAME,    FMT,   FAC, I1, I2, P, W, OP, CC, DATA)
- *  E(OPC,    NAME,    FMT,   FAC, I1, I2, P, W, OP, CC, DATA, FLAGS)
- *  F(OPC,    NAME,    FMT,   FAC, I1, I2, P, W, OP, CC, FLAGS)
- *
- *  OPC  = (op << 8) | op2 where op is the major, op2 the minor opcode
- *  NAME = name of the opcode, used internally
- *  FMT  = format of the opcode (defined in insn-format.def)
- *  FAC  = facility the opcode is available in (defined in DisasFacility)
- *  I1   = func in1_xx fills o->in1
- *  I2   = func in2_xx fills o->in2
- *  P    = func prep_xx initializes o->*out*
- *  W    = func wout_xx writes o->*out* somewhere
- *  OP   = func op_xx does the bulk of the operation
- *  CC   = func cout_xx defines how cc should get set
- *  DATA = immediate argument to op_xx function
- *  FLAGS = categorize the type of instruction (e.g. for advanced checks)
- *
- *  The helpers get called in order: I1, I2, P, OP, W, CC
- */
-
-/* ADD */
-    C(0x1a00, AR,      RR_a,  Z,   r1, r2, new, r1_32, add, adds32)
-    C(0xb9f8, ARK,     RRF_a, DO,  r2, r3, new, r1_32, add, adds32)
-    C(0x5a00, A,       RX_a,  Z,   r1, m2_32s, new, r1_32, add, adds32)
-    C(0xe35a, AY,      RXY_a, LD,  r1, m2_32s, new, r1_32, add, adds32)
-    C(0xb908, AGR,     RRE,   Z,   r1, r2, r1, 0, add, adds64)
-    C(0xb918, AGFR,    RRE,   Z,   r1, r2_32s, r1, 0, add, adds64)
-    C(0xb9e8, AGRK,    RRF_a, DO,  r2, r3, r1, 0, add, adds64)
-    C(0xe308, AG,      RXY_a, Z,   r1, m2_64, r1, 0, add, adds64)
-    C(0xe318, AGF,     RXY_a, Z,   r1, m2_32s, r1, 0, add, adds64)
-    F(0xb30a, AEBR,    RRE,   Z,   e1, e2, new, e1, aeb, f32, IF_BFP)
-    F(0xb31a, ADBR,    RRE,   Z,   f1, f2, new, f1, adb, f64, IF_BFP)
-    F(0xb34a, AXBR,    RRE,   Z,   x2h, x2l, x1, x1, axb, f128, IF_BFP)
-    F(0xed0a, AEB,     RXE,   Z,   e1, m2_32u, new, e1, aeb, f32, IF_BFP)
-    F(0xed1a, ADB,     RXE,   Z,   f1, m2_64, new, f1, adb, f64, IF_BFP)
-/* ADD HIGH */
-    C(0xb9c8, AHHHR,   RRF_a, HW,  r2_sr32, r3_sr32, new, r1_32h, add, adds32)
-    C(0xb9d8, AHHLR,   RRF_a, HW,  r2_sr32, r3, new, r1_32h, add, adds32)
-/* ADD IMMEDIATE */
-    C(0xc209, AFI,     RIL_a, EI,  r1, i2, new, r1_32, add, adds32)
-    D(0xeb6a, ASI,     SIY,   GIE, la1, i2, new, 0, asi, adds32, MO_TESL)
-    C(0xecd8, AHIK,    RIE_d, DO,  r3, i2, new, r1_32, add, adds32)
-    C(0xc208, AGFI,    RIL_a, EI,  r1, i2, r1, 0, add, adds64)
-    D(0xeb7a, AGSI,    SIY,   GIE, la1, i2, new, 0, asi, adds64, MO_TEQ)
-    C(0xecd9, AGHIK,   RIE_d, DO,  r3, i2, r1, 0, add, adds64)
-/* ADD IMMEDIATE HIGH */
-    C(0xcc08, AIH,     RIL_a, HW,  r1_sr32, i2, new, r1_32h, add, adds32)
-/* ADD HALFWORD */
-    C(0x4a00, AH,      RX_a,  Z,   r1, m2_16s, new, r1_32, add, adds32)
-    C(0xe37a, AHY,     RXY_a, LD,  r1, m2_16s, new, r1_32, add, adds32)
-    C(0xe338, AGH,     RXY_a, MIE2,r1, m2_16s, r1, 0, add, adds64)
-/* ADD HALFWORD IMMEDIATE */
-    C(0xa70a, AHI,     RI_a,  Z,   r1, i2, new, r1_32, add, adds32)
-    C(0xa70b, AGHI,    RI_a,  Z,   r1, i2, r1, 0, add, adds64)
-
-/* ADD LOGICAL */
-    C(0x1e00, ALR,     RR_a,  Z,   r1_32u, r2_32u, new, r1_32, add, addu32)
-    C(0xb9fa, ALRK,    RRF_a, DO,  r2_32u, r3_32u, new, r1_32, add, addu32)
-    C(0x5e00, AL,      RX_a,  Z,   r1_32u, m2_32u, new, r1_32, add, addu32)
-    C(0xe35e, ALY,     RXY_a, LD,  r1_32u, m2_32u, new, r1_32, add, addu32)
-    C(0xb90a, ALGR,    RRE,   Z,   r1, r2, r1, 0, addu64, addu64)
-    C(0xb91a, ALGFR,   RRE,   Z,   r1, r2_32u, r1, 0, addu64, addu64)
-    C(0xb9ea, ALGRK,   RRF_a, DO,  r2, r3, r1, 0, addu64, addu64)
-    C(0xe30a, ALG,     RXY_a, Z,   r1, m2_64, r1, 0, addu64, addu64)
-    C(0xe31a, ALGF,    RXY_a, Z,   r1, m2_32u, r1, 0, addu64, addu64)
-/* ADD LOGICAL HIGH */
-    C(0xb9ca, ALHHHR,  RRF_a, HW,  r2_sr32, r3_sr32, new, r1_32h, add, addu32)
-    C(0xb9da, ALHHLR,  RRF_a, HW,  r2_sr32, r3_32u, new, r1_32h, add, addu32)
-/* ADD LOGICAL IMMEDIATE */
-    C(0xc20b, ALFI,    RIL_a, EI,  r1_32u, i2_32u, new, r1_32, add, addu32)
-    C(0xc20a, ALGFI,   RIL_a, EI,  r1, i2_32u, r1, 0, addu64, addu64)
-/* ADD LOGICAL WITH SIGNED IMMEDIATE */
-    D(0xeb6e, ALSI,    SIY,   GIE, la1, i2_32u, new, 0, asi, addu32, MO_TEUL)
-    C(0xecda, ALHSIK,  RIE_d, DO,  r3_32u, i2_32u, new, r1_32, add, addu32)
-    D(0xeb7e, ALGSI,   SIY,   GIE, la1, i2, new, 0, asiu64, addu64, MO_TEQ)
-    C(0xecdb, ALGHSIK, RIE_d, DO,  r3, i2, r1, 0, addu64, addu64)
-/* ADD LOGICAL WITH SIGNED IMMEDIATE HIGH */
-    C(0xcc0a, ALSIH,   RIL_a, HW,  r1_sr32, i2_32u, new, r1_32h, add, addu32)
-    C(0xcc0b, ALSIHN,  RIL_a, HW,  r1_sr32, i2_32u, new, r1_32h, add, 0)
-/* ADD LOGICAL WITH CARRY */
-    C(0xb998, ALCR,    RRE,   Z,   r1_32u, r2_32u, new, r1_32, addc32, addu32)
-    C(0xb988, ALCGR,   RRE,   Z,   r1, r2, r1, 0, addc64, addu64)
-    C(0xe398, ALC,     RXY_a, Z,   r1_32u, m2_32u, new, r1_32, addc32, addu32)
-    C(0xe388, ALCG,    RXY_a, Z,   r1, m2_64, r1, 0, addc64, addu64)
-
-/* AND */
-    C(0x1400, NR,      RR_a,  Z,   r1, r2, new, r1_32, and, nz32)
-    C(0xb9f4, NRK,     RRF_a, DO,  r2, r3, new, r1_32, and, nz32)
-    C(0x5400, N,       RX_a,  Z,   r1, m2_32s, new, r1_32, and, nz32)
-    C(0xe354, NY,      RXY_a, LD,  r1, m2_32s, new, r1_32, and, nz32)
-    C(0xb980, NGR,     RRE,   Z,   r1, r2, r1, 0, and, nz64)
-    C(0xb9e4, NGRK,    RRF_a, DO,  r2, r3, r1, 0, and, nz64)
-    C(0xe380, NG,      RXY_a, Z,   r1, m2_64, r1, 0, and, nz64)
-    C(0xd400, NC,      SS_a,  Z,   la1, a2, 0, 0, nc, 0)
-/* AND IMMEDIATE */
-    D(0xc00a, NIHF,    RIL_a, EI,  r1_o, i2_32u, r1, 0, andi, 0, 0x2020)
-    D(0xc00b, NILF,    RIL_a, EI,  r1_o, i2_32u, r1, 0, andi, 0, 0x2000)
-    D(0xa504, NIHH,    RI_a,  Z,   r1_o, i2_16u, r1, 0, andi, 0, 0x1030)
-    D(0xa505, NIHL,    RI_a,  Z,   r1_o, i2_16u, r1, 0, andi, 0, 0x1020)
-    D(0xa506, NILH,    RI_a,  Z,   r1_o, i2_16u, r1, 0, andi, 0, 0x1010)
-    D(0xa507, NILL,    RI_a,  Z,   r1_o, i2_16u, r1, 0, andi, 0, 0x1000)
-    D(0x9400, NI,      SI,    Z,   la1, i2_8u, new, 0, ni, nz64, MO_UB)
-    D(0xeb54, NIY,     SIY,   LD,  la1, i2_8u, new, 0, ni, nz64, MO_UB)
-
-/* BRANCH AND LINK */
-    C(0x0500, BALR,    RR_a,  Z,   0, r2_nz, r1, 0, bal, 0)
-    C(0x4500, BAL,     RX_a,  Z,   0, a2, r1, 0, bal, 0)
-/* BRANCH AND SAVE */
-    C(0x0d00, BASR,    RR_a,  Z,   0, r2_nz, r1, 0, bas, 0)
-    C(0x4d00, BAS,     RX_a,  Z,   0, a2, r1, 0, bas, 0)
-/* BRANCH RELATIVE AND SAVE */
-    C(0xa705, BRAS,    RI_b,  Z,   0, 0, r1, 0, basi, 0)
-    C(0xc005, BRASL,   RIL_b, Z,   0, 0, r1, 0, basi, 0)
-/* BRANCH INDIRECT ON CONDITION */
-    C(0xe347, BIC,     RXY_b, MIE2,0, m2_64w, 0, 0, bc, 0)
-/* BRANCH ON CONDITION */
-    C(0x0700, BCR,     RR_b,  Z,   0, r2_nz, 0, 0, bc, 0)
-    C(0x4700, BC,      RX_b,  Z,   0, a2, 0, 0, bc, 0)
-/* BRANCH RELATIVE ON CONDITION */
-    C(0xa704, BRC,     RI_c,  Z,   0, 0, 0, 0, bc, 0)
-    C(0xc004, BRCL,    RIL_c, Z,   0, 0, 0, 0, bc, 0)
-/* BRANCH ON COUNT */
-    C(0x0600, BCTR,    RR_a,  Z,   0, r2_nz, 0, 0, bct32, 0)
-    C(0xb946, BCTGR,   RRE,   Z,   0, r2_nz, 0, 0, bct64, 0)
-    C(0x4600, BCT,     RX_a,  Z,   0, a2, 0, 0, bct32, 0)
-    C(0xe346, BCTG,    RXY_a, Z,   0, a2, 0, 0, bct64, 0)
-/* BRANCH RELATIVE ON COUNT */
-    C(0xa706, BRCT,    RI_b,  Z,   0, 0, 0, 0, bct32, 0)
-    C(0xa707, BRCTG,   RI_b,  Z,   0, 0, 0, 0, bct64, 0)
-/* BRANCH RELATIVE ON COUNT HIGH */
-    C(0xcc06, BRCTH,   RIL_b, HW,  0, 0, 0, 0, bcth, 0)
-/* BRANCH ON INDEX */
-    D(0x8600, BXH,     RS_a,  Z,   0, a2, 0, 0, bx32, 0, 0)
-    D(0x8700, BXLE,    RS_a,  Z,   0, a2, 0, 0, bx32, 0, 1)
-    D(0xeb44, BXHG,    RSY_a, Z,   0, a2, 0, 0, bx64, 0, 0)
-    D(0xeb45, BXLEG,   RSY_a, Z,   0, a2, 0, 0, bx64, 0, 1)
-/* BRANCH RELATIVE ON INDEX */
-    D(0x8400, BRXH,    RSI,   Z,   0, 0, 0, 0, bx32, 0, 0)
-    D(0x8500, BRXLE,   RSI,   Z,   0, 0, 0, 0, bx32, 0, 1)
-    D(0xec44, BRXHG,   RIE_e, Z,   0, 0, 0, 0, bx64, 0, 0)
-    D(0xec45, BRXHLE,  RIE_e, Z,   0, 0, 0, 0, bx64, 0, 1)
-/* BRANCH PREDICTION PRELOAD */
-    /* ??? Format is SMI, but implemented as NOP, so we need no fields.  */
-    C(0xc700, BPP,     E,     EH,  0, 0, 0, 0, 0, 0)
-/* BRANCH PREDICTION RELATIVE PRELOAD */
-    /* ??? Format is MII, but implemented as NOP, so we need no fields.  */
-    C(0xc500, BPRP,    E,     EH,  0, 0, 0, 0, 0, 0)
-/* NEXT INSTRUCTION ACCESS INTENT */
-    /* ??? Format is IE, but implemented as NOP, so we need no fields.  */
-    C(0xb2fa, NIAI,    E,     EH,  0, 0, 0, 0, 0, 0)
-
-/* CHECKSUM */
-    C(0xb241, CKSM,    RRE,   Z,   r1_o, ra2, new, r1_32, cksm, 0)
-
-/* COPY SIGN */
-    F(0xb372, CPSDR,   RRF_b, FPSSH, f3, f2, new, f1, cps, 0, IF_AFP1 | IF_AFP2 | IF_AFP3)
-
-/* COMPARE */
-    C(0x1900, CR,      RR_a,  Z,   r1_o, r2_o, 0, 0, 0, cmps32)
-    C(0x5900, C,       RX_a,  Z,   r1_o, m2_32s, 0, 0, 0, cmps32)
-    C(0xe359, CY,      RXY_a, LD,  r1_o, m2_32s, 0, 0, 0, cmps32)
-    C(0xb920, CGR,     RRE,   Z,   r1_o, r2_o, 0, 0, 0, cmps64)
-    C(0xb930, CGFR,    RRE,   Z,   r1_o, r2_32s, 0, 0, 0, cmps64)
-    C(0xe320, CG,      RXY_a, Z,   r1_o, m2_64, 0, 0, 0, cmps64)
-    C(0xe330, CGF,     RXY_a, Z,   r1_o, m2_32s, 0, 0, 0, cmps64)
-    F(0xb309, CEBR,    RRE,   Z,   e1, e2, 0, 0, ceb, 0, IF_BFP)
-    F(0xb319, CDBR,    RRE,   Z,   f1, f2, 0, 0, cdb, 0, IF_BFP)
-    F(0xb349, CXBR,    RRE,   Z,   x2h, x2l, x1, 0, cxb, 0, IF_BFP)
-    F(0xed09, CEB,     RXE,   Z,   e1, m2_32u, 0, 0, ceb, 0, IF_BFP)
-    F(0xed19, CDB,     RXE,   Z,   f1, m2_64, 0, 0, cdb, 0, IF_BFP)
-/* COMPARE AND SIGNAL */
-    F(0xb308, KEBR,    RRE,   Z,   e1, e2, 0, 0, keb, 0, IF_BFP)
-    F(0xb318, KDBR,    RRE,   Z,   f1, f2, 0, 0, kdb, 0, IF_BFP)
-    F(0xb348, KXBR,    RRE,   Z,   x2h, x2l, x1, 0, kxb, 0, IF_BFP)
-    F(0xed08, KEB,     RXE,   Z,   e1, m2_32u, 0, 0, keb, 0, IF_BFP)
-    F(0xed18, KDB,     RXE,   Z,   f1, m2_64, 0, 0, kdb, 0, IF_BFP)
-/* COMPARE IMMEDIATE */
-    C(0xc20d, CFI,     RIL_a, EI,  r1, i2, 0, 0, 0, cmps32)
-    C(0xc20c, CGFI,    RIL_a, EI,  r1, i2, 0, 0, 0, cmps64)
-/* COMPARE RELATIVE LONG */
-    C(0xc60d, CRL,     RIL_b, GIE, r1, mri2_32s, 0, 0, 0, cmps32)
-    C(0xc608, CGRL,    RIL_b, GIE, r1, mri2_64, 0, 0, 0, cmps64)
-    C(0xc60c, CGFRL,   RIL_b, GIE, r1, mri2_32s, 0, 0, 0, cmps64)
-/* COMPARE HALFWORD */
-    C(0x4900, CH,      RX_a,  Z,   r1_o, m2_16s, 0, 0, 0, cmps32)
-    C(0xe379, CHY,     RXY_a, LD,  r1_o, m2_16s, 0, 0, 0, cmps32)
-    C(0xe334, CGH,     RXY_a, GIE, r1_o, m2_16s, 0, 0, 0, cmps64)
-/* COMPARE HALFWORD IMMEDIATE */
-    C(0xa70e, CHI,     RI_a,  Z,   r1_o, i2, 0, 0, 0, cmps32)
-    C(0xa70f, CGHI,    RI_a,  Z,   r1_o, i2, 0, 0, 0, cmps64)
-    C(0xe554, CHHSI,   SIL,   GIE, m1_16s, i2, 0, 0, 0, cmps64)
-    C(0xe55c, CHSI,    SIL,   GIE, m1_32s, i2, 0, 0, 0, cmps64)
-    C(0xe558, CGHSI,   SIL,   GIE, m1_64, i2, 0, 0, 0, cmps64)
-/* COMPARE HALFWORD RELATIVE LONG */
-    C(0xc605, CHRL,    RIL_b, GIE, r1_o, mri2_32s, 0, 0, 0, cmps32)
-    C(0xc604, CGHRL,   RIL_b, GIE, r1_o, mri2_64, 0, 0, 0, cmps64)
-/* COMPARE HIGH */
-    C(0xb9cd, CHHR,    RRE,   HW,  r1_sr32, r2_sr32, 0, 0, 0, cmps32)
-    C(0xb9dd, CHLR,    RRE,   HW,  r1_sr32, r2_o, 0, 0, 0, cmps32)
-    C(0xe3cd, CHF,     RXY_a, HW,  r1_sr32, m2_32s, 0, 0, 0, cmps32)
-/* COMPARE IMMEDIATE HIGH */
-    C(0xcc0d, CIH,     RIL_a, HW,  r1_sr32, i2, 0, 0, 0, cmps32)
-
-/* COMPARE LOGICAL */
-    C(0x1500, CLR,     RR_a,  Z,   r1, r2, 0, 0, 0, cmpu32)
-    C(0x5500, CL,      RX_a,  Z,   r1, m2_32s, 0, 0, 0, cmpu32)
-    C(0xe355, CLY,     RXY_a, LD,  r1, m2_32s, 0, 0, 0, cmpu32)
-    C(0xb921, CLGR,    RRE,   Z,   r1, r2, 0, 0, 0, cmpu64)
-    C(0xb931, CLGFR,   RRE,   Z,   r1, r2_32u, 0, 0, 0, cmpu64)
-    C(0xe321, CLG,     RXY_a, Z,   r1, m2_64, 0, 0, 0, cmpu64)
-    C(0xe331, CLGF,    RXY_a, Z,   r1, m2_32u, 0, 0, 0, cmpu64)
-    C(0xd500, CLC,     SS_a,  Z,   la1, a2, 0, 0, clc, 0)
-/* COMPARE LOGICAL HIGH */
-    C(0xb9cf, CLHHR,   RRE,   HW,  r1_sr32, r2_sr32, 0, 0, 0, cmpu32)
-    C(0xb9df, CLHLR,   RRE,   HW,  r1_sr32, r2_o, 0, 0, 0, cmpu32)
-    C(0xe3cf, CLHF,    RXY_a, HW,  r1_sr32, m2_32s, 0, 0, 0, cmpu32)
-/* COMPARE LOGICAL IMMEDIATE */
-    C(0xc20f, CLFI,    RIL_a, EI,  r1, i2, 0, 0, 0, cmpu32)
-    C(0xc20e, CLGFI,   RIL_a, EI,  r1, i2_32u, 0, 0, 0, cmpu64)
-    C(0x9500, CLI,     SI,    Z,   m1_8u, i2_8u, 0, 0, 0, cmpu64)
-    C(0xeb55, CLIY,    SIY,   LD,  m1_8u, i2_8u, 0, 0, 0, cmpu64)
-    C(0xe555, CLHHSI,  SIL,   GIE, m1_16u, i2_16u, 0, 0, 0, cmpu64)
-    C(0xe55d, CLFHSI,  SIL,   GIE, m1_32u, i2_16u, 0, 0, 0, cmpu64)
-    C(0xe559, CLGHSI,  SIL,   GIE, m1_64, i2_16u, 0, 0, 0, cmpu64)
-/* COMPARE LOGICAL IMMEDIATE HIGH */
-    C(0xcc0f, CLIH,    RIL_a, HW,  r1_sr32, i2, 0, 0, 0, cmpu32)
-/* COMPARE LOGICAL RELATIVE LONG */
-    C(0xc60f, CLRL,    RIL_b, GIE, r1_o, mri2_32u, 0, 0, 0, cmpu32)
-    C(0xc60a, CLGRL,   RIL_b, GIE, r1_o, mri2_64, 0, 0, 0, cmpu64)
-    C(0xc60e, CLGFRL,  RIL_b, GIE, r1_o, mri2_32u, 0, 0, 0, cmpu64)
-    C(0xc607, CLHRL,   RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu32)
-    C(0xc606, CLGHRL,  RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu64)
-/* COMPARE LOGICAL LONG */
-    C(0x0f00, CLCL,    RR_a,  Z,   0, 0, 0, 0, clcl, 0)
-/* COMPARE LOGICAL LONG EXTENDED */
-    C(0xa900, CLCLE,   RS_a,  Z,   0, a2, 0, 0, clcle, 0)
-/* COMPARE LOGICAL LONG UNICODE */
-    C(0xeb8f, CLCLU,   RSY_a, E2,  0, a2, 0, 0, clclu, 0)
-/* COMPARE LOGICAL CHARACTERS UNDER MASK */
-    C(0xbd00, CLM,     RS_b,  Z,   r1_o, a2, 0, 0, clm, 0)
-    C(0xeb21, CLMY,    RSY_b, LD,  r1_o, a2, 0, 0, clm, 0)
-    C(0xeb20, CLMH,    RSY_b, Z,   r1_sr32, a2, 0, 0, clm, 0)
-/* COMPARE LOGICAL STRING */
-    C(0xb25d, CLST,    RRE,   Z,   r1_o, r2_o, 0, 0, clst, 0)
-
-/* COMPARE AND BRANCH */
-    D(0xecf6, CRB,     RRS,   GIE, r1_32s, r2_32s, 0, 0, cj, 0, 0)
-    D(0xece4, CGRB,    RRS,   GIE, r1_o, r2_o, 0, 0, cj, 0, 0)
-    D(0xec76, CRJ,     RIE_b, GIE, r1_32s, r2_32s, 0, 0, cj, 0, 0)
-    D(0xec64, CGRJ,    RIE_b, GIE, r1_o, r2_o, 0, 0, cj, 0, 0)
-    D(0xecfe, CIB,     RIS,   GIE, r1_32s, i2, 0, 0, cj, 0, 0)
-    D(0xecfc, CGIB,    RIS,   GIE, r1_o, i2, 0, 0, cj, 0, 0)
-    D(0xec7e, CIJ,     RIE_c, GIE, r1_32s, i2, 0, 0, cj, 0, 0)
-    D(0xec7c, CGIJ,    RIE_c, GIE, r1_o, i2, 0, 0, cj, 0, 0)
-/* COMPARE LOGICAL AND BRANCH */
-    D(0xecf7, CLRB,    RRS,   GIE, r1_32u, r2_32u, 0, 0, cj, 0, 1)
-    D(0xece5, CLGRB,   RRS,   GIE, r1_o, r2_o, 0, 0, cj, 0, 1)
-    D(0xec77, CLRJ,    RIE_b, GIE, r1_32u, r2_32u, 0, 0, cj, 0, 1)
-    D(0xec65, CLGRJ,   RIE_b, GIE, r1_o, r2_o, 0, 0, cj, 0, 1)
-    D(0xecff, CLIB,    RIS,   GIE, r1_32u, i2_8u, 0, 0, cj, 0, 1)
-    D(0xecfd, CLGIB,   RIS,   GIE, r1_o, i2_8u, 0, 0, cj, 0, 1)
-    D(0xec7f, CLIJ,    RIE_c, GIE, r1_32u, i2_8u, 0, 0, cj, 0, 1)
-    D(0xec7d, CLGIJ,   RIE_c, GIE, r1_o, i2_8u, 0, 0, cj, 0, 1)
-
-/* COMPARE AND SWAP */
-    D(0xba00, CS,      RS_a,  Z,   r3_32u, r1_32u, new, r1_32, cs, 0, MO_TEUL)
-    D(0xeb14, CSY,     RSY_a, LD,  r3_32u, r1_32u, new, r1_32, cs, 0, MO_TEUL)
-    D(0xeb30, CSG,     RSY_a, Z,   r3_o, r1_o, new, r1, cs, 0, MO_TEQ)
-/* COMPARE DOUBLE AND SWAP */
-    D(0xbb00, CDS,     RS_a,  Z,   r3_D32, r1_D32, new, r1_D32, cs, 0, MO_TEQ)
-    D(0xeb31, CDSY,    RSY_a, LD,  r3_D32, r1_D32, new, r1_D32, cs, 0, MO_TEQ)
-    C(0xeb3e, CDSG,    RSY_a, Z,   0, 0, 0, 0, cdsg, 0)
-/* COMPARE AND SWAP AND STORE */
-    C(0xc802, CSST,    SSF,   CASS, la1, a2, 0, 0, csst, 0)
-
-/* COMPARE AND TRAP */
-    D(0xb972, CRT,     RRF_c, GIE, r1_32s, r2_32s, 0, 0, ct, 0, 0)
-    D(0xb960, CGRT,    RRF_c, GIE, r1_o, r2_o, 0, 0, ct, 0, 0)
-    D(0xec72, CIT,     RIE_a, GIE, r1_32s, i2, 0, 0, ct, 0, 0)
-    D(0xec70, CGIT,    RIE_a, GIE, r1_o, i2, 0, 0, ct, 0, 0)
-/* COMPARE LOGICAL AND TRAP */
-    D(0xb973, CLRT,    RRF_c, GIE, r1_32u, r2_32u, 0, 0, ct, 0, 1)
-    D(0xb961, CLGRT,   RRF_c, GIE, r1_o, r2_o, 0, 0, ct, 0, 1)
-    D(0xeb23, CLT,     RSY_b, MIE, r1_32u, m2_32u, 0, 0, ct, 0, 1)
-    D(0xeb2b, CLGT,    RSY_b, MIE, r1_o, m2_64, 0, 0, ct, 0, 1)
-    D(0xec73, CLFIT,   RIE_a, GIE, r1_32u, i2_32u, 0, 0, ct, 0, 1)
-    D(0xec71, CLGIT,   RIE_a, GIE, r1_o, i2_32u, 0, 0, ct, 0, 1)
-
-/* CONVERT TO DECIMAL */
-    C(0x4e00, CVD,     RX_a,  Z,   r1_o, a2, 0, 0, cvd, 0)
-    C(0xe326, CVDY,    RXY_a, LD,  r1_o, a2, 0, 0, cvd, 0)
-/* CONVERT TO FIXED */
-    F(0xb398, CFEBR,   RRF_e, Z,   0, e2, new, r1_32, cfeb, 0, IF_BFP)
-    F(0xb399, CFDBR,   RRF_e, Z,   0, f2, new, r1_32, cfdb, 0, IF_BFP)
-    F(0xb39a, CFXBR,   RRF_e, Z,   x2h, x2l, new, r1_32, cfxb, 0, IF_BFP)
-    F(0xb3a8, CGEBR,   RRF_e, Z,   0, e2, r1, 0, cgeb, 0, IF_BFP)
-    F(0xb3a9, CGDBR,   RRF_e, Z,   0, f2, r1, 0, cgdb, 0, IF_BFP)
-    F(0xb3aa, CGXBR,   RRF_e, Z,   x2h, x2l, r1, 0, cgxb, 0, IF_BFP)
-/* CONVERT FROM FIXED */
-    F(0xb394, CEFBR,   RRF_e, Z,   0, r2_32s, new, e1, cegb, 0, IF_BFP)
-    F(0xb395, CDFBR,   RRF_e, Z,   0, r2_32s, new, f1, cdgb, 0, IF_BFP)
-    F(0xb396, CXFBR,   RRF_e, Z,   0, r2_32s, new_P, x1, cxgb, 0, IF_BFP)
-    F(0xb3a4, CEGBR,   RRF_e, Z,   0, r2_o, new, e1, cegb, 0, IF_BFP)
-    F(0xb3a5, CDGBR,   RRF_e, Z,   0, r2_o, new, f1, cdgb, 0, IF_BFP)
-    F(0xb3a6, CXGBR,   RRF_e, Z,   0, r2_o, new_P, x1, cxgb, 0, IF_BFP)
-/* CONVERT TO LOGICAL */
-    F(0xb39c, CLFEBR,  RRF_e, FPE, 0, e2, new, r1_32, clfeb, 0, IF_BFP)
-    F(0xb39d, CLFDBR,  RRF_e, FPE, 0, f2, new, r1_32, clfdb, 0, IF_BFP)
-    F(0xb39e, CLFXBR,  RRF_e, FPE, x2h, x2l, new, r1_32, clfxb, 0, IF_BFP)
-    F(0xb3ac, CLGEBR,  RRF_e, FPE, 0, e2, r1, 0, clgeb, 0, IF_BFP)
-    F(0xb3ad, CLGDBR,  RRF_e, FPE, 0, f2, r1, 0, clgdb, 0, IF_BFP)
-    F(0xb3ae, CLGXBR,  RRF_e, FPE, x2h, x2l, r1, 0, clgxb, 0, IF_BFP)
-/* CONVERT FROM LOGICAL */
-    F(0xb390, CELFBR,  RRF_e, FPE, 0, r2_32u, new, e1, celgb, 0, IF_BFP)
-    F(0xb391, CDLFBR,  RRF_e, FPE, 0, r2_32u, new, f1, cdlgb, 0, IF_BFP)
-    F(0xb392, CXLFBR,  RRF_e, FPE, 0, r2_32u, new_P, x1, cxlgb, 0, IF_BFP)
-    F(0xb3a0, CELGBR,  RRF_e, FPE, 0, r2_o, new, e1, celgb, 0, IF_BFP)
-    F(0xb3a1, CDLGBR,  RRF_e, FPE, 0, r2_o, new, f1, cdlgb, 0, IF_BFP)
-    F(0xb3a2, CXLGBR,  RRF_e, FPE, 0, r2_o, new_P, x1, cxlgb, 0, IF_BFP)
-
-/* CONVERT UTF-8 TO UTF-16 */
-    D(0xb2a7, CU12,    RRF_c, Z,   0, 0, 0, 0, cuXX, 0, 12)
-/* CONVERT UTF-8 TO UTF-32 */
-    D(0xb9b0, CU14,    RRF_c, ETF3, 0, 0, 0, 0, cuXX, 0, 14)
-/* CONVERT UTF-16 to UTF-8 */
-    D(0xb2a6, CU21,    RRF_c, Z,   0, 0, 0, 0, cuXX, 0, 21)
-/* CONVERT UTF-16 to UTF-32 */
-    D(0xb9b1, CU24,    RRF_c, ETF3, 0, 0, 0, 0, cuXX, 0, 24)
-/* CONVERT UTF-32 to UTF-8 */
-    D(0xb9b2, CU41,    RRF_c, ETF3, 0, 0, 0, 0, cuXX, 0, 41)
-/* CONVERT UTF-32 to UTF-16 */
-    D(0xb9b3, CU42,    RRF_c, ETF3, 0, 0, 0, 0, cuXX, 0, 42)
-
-/* DIVIDE */
-    C(0x1d00, DR,      RR_a,  Z,   r1_D32, r2_32s, new_P, r1_P32, divs32, 0)
-    C(0x5d00, D,       RX_a,  Z,   r1_D32, m2_32s, new_P, r1_P32, divs32, 0)
-    F(0xb30d, DEBR,    RRE,   Z,   e1, e2, new, e1, deb, 0, IF_BFP)
-    F(0xb31d, DDBR,    RRE,   Z,   f1, f2, new, f1, ddb, 0, IF_BFP)
-    F(0xb34d, DXBR,    RRE,   Z,   x2h, x2l, x1, x1, dxb, 0, IF_BFP)
-    F(0xed0d, DEB,     RXE,   Z,   e1, m2_32u, new, e1, deb, 0, IF_BFP)
-    F(0xed1d, DDB,     RXE,   Z,   f1, m2_64, new, f1, ddb, 0, IF_BFP)
-/* DIVIDE LOGICAL */
-    C(0xb997, DLR,     RRE,   Z,   r1_D32, r2_32u, new_P, r1_P32, divu32, 0)
-    C(0xe397, DL,      RXY_a, Z,   r1_D32, m2_32u, new_P, r1_P32, divu32, 0)
-    C(0xb987, DLGR,    RRE,   Z,   0, r2_o, r1_P, 0, divu64, 0)
-    C(0xe387, DLG,     RXY_a, Z,   0, m2_64, r1_P, 0, divu64, 0)
-/* DIVIDE SINGLE */
-    C(0xb90d, DSGR,    RRE,   Z,   r1p1, r2, r1_P, 0, divs64, 0)
-    C(0xb91d, DSGFR,   RRE,   Z,   r1p1, r2_32s, r1_P, 0, divs64, 0)
-    C(0xe30d, DSG,     RXY_a, Z,   r1p1, m2_64, r1_P, 0, divs64, 0)
-    C(0xe31d, DSGF,    RXY_a, Z,   r1p1, m2_32s, r1_P, 0, divs64, 0)
-
-/* EXCLUSIVE OR */
-    C(0x1700, XR,      RR_a,  Z,   r1, r2, new, r1_32, xor, nz32)
-    C(0xb9f7, XRK,     RRF_a, DO,  r2, r3, new, r1_32, xor, nz32)
-    C(0x5700, X,       RX_a,  Z,   r1, m2_32s, new, r1_32, xor, nz32)
-    C(0xe357, XY,      RXY_a, LD,  r1, m2_32s, new, r1_32, xor, nz32)
-    C(0xb982, XGR,     RRE,   Z,   r1, r2, r1, 0, xor, nz64)
-    C(0xb9e7, XGRK,    RRF_a, DO,  r2, r3, r1, 0, xor, nz64)
-    C(0xe382, XG,      RXY_a, Z,   r1, m2_64, r1, 0, xor, nz64)
-    C(0xd700, XC,      SS_a,  Z,   0, 0, 0, 0, xc, 0)
-/* EXCLUSIVE OR IMMEDIATE */
-    D(0xc006, XIHF,    RIL_a, EI,  r1_o, i2_32u, r1, 0, xori, 0, 0x2020)
-    D(0xc007, XILF,    RIL_a, EI,  r1_o, i2_32u, r1, 0, xori, 0, 0x2000)
-    D(0x9700, XI,      SI,    Z,   la1, i2_8u, new, 0, xi, nz64, MO_UB)
-    D(0xeb57, XIY,     SIY,   LD,  la1, i2_8u, new, 0, xi, nz64, MO_UB)
-
-/* EXECUTE */
-    C(0x4400, EX,      RX_a,  Z,   0, a2, 0, 0, ex, 0)
-/* EXECUTE RELATIVE LONG */
-    C(0xc600, EXRL,    RIL_b, EE,  0, ri2, 0, 0, ex, 0)
-
-/* EXTRACT ACCESS */
-    C(0xb24f, EAR,     RRE,   Z,   0, 0, new, r1_32, ear, 0)
-/* EXTRACT CPU ATTRIBUTE */
-    C(0xeb4c, ECAG,    RSY_a, GIE, 0, a2, r1, 0, ecag, 0)
-/* EXTRACT CPU TIME */
-    F(0xc801, ECTG,    SSF,   ECT, 0, 0, 0, 0, ectg, 0, IF_IO)
-/* EXTRACT FPC */
-    F(0xb38c, EFPC,    RRE,   Z,   0, 0, new, r1_32, efpc, 0, IF_BFP)
-/* EXTRACT PSW */
-    C(0xb98d, EPSW,    RRE,   Z,   0, 0, 0, 0, epsw, 0)
-
-/* FIND LEFTMOST ONE */
-    C(0xb983, FLOGR,   RRE,   EI,  0, r2_o, r1_P, 0, flogr, 0)
-
-/* INSERT CHARACTER */
-    C(0x4300, IC,      RX_a,  Z,   0, m2_8u, 0, r1_8, mov2, 0)
-    C(0xe373, ICY,     RXY_a, LD,  0, m2_8u, 0, r1_8, mov2, 0)
-/* INSERT CHARACTERS UNDER MASK */
-    D(0xbf00, ICM,     RS_b,  Z,   0, a2, r1, 0, icm, 0, 0)
-    D(0xeb81, ICMY,    RSY_b, LD,  0, a2, r1, 0, icm, 0, 0)
-    D(0xeb80, ICMH,    RSY_b, Z,   0, a2, r1, 0, icm, 0, 32)
-/* INSERT IMMEDIATE */
-    D(0xc008, IIHF,    RIL_a, EI,  r1_o, i2_32u, r1, 0, insi, 0, 0x2020)
-    D(0xc009, IILF,    RIL_a, EI,  r1_o, i2_32u, r1, 0, insi, 0, 0x2000)
-    D(0xa500, IIHH,    RI_a,  Z,   r1_o, i2_16u, r1, 0, insi, 0, 0x1030)
-    D(0xa501, IIHL,    RI_a,  Z,   r1_o, i2_16u, r1, 0, insi, 0, 0x1020)
-    D(0xa502, IILH,    RI_a,  Z,   r1_o, i2_16u, r1, 0, insi, 0, 0x1010)
-    D(0xa503, IILL,    RI_a,  Z,   r1_o, i2_16u, r1, 0, insi, 0, 0x1000)
-/* INSERT PROGRAM MASK */
-    C(0xb222, IPM,     RRE,   Z,   0, 0, r1, 0, ipm, 0)
-
-/* LOAD */
-    C(0x1800, LR,      RR_a,  Z,   0, r2_o, 0, cond_r1r2_32, mov2, 0)
-    C(0x5800, L,       RX_a,  Z,   0, a2, new, r1_32, ld32s, 0)
-    C(0xe358, LY,      RXY_a, LD,  0, a2, new, r1_32, ld32s, 0)
-    C(0xb904, LGR,     RRE,   Z,   0, r2_o, 0, r1, mov2, 0)
-    C(0xb914, LGFR,    RRE,   Z,   0, r2_32s, 0, r1, mov2, 0)
-    C(0xe304, LG,      RXY_a, Z,   0, a2, r1, 0, ld64, 0)
-    C(0xe314, LGF,     RXY_a, Z,   0, a2, r1, 0, ld32s, 0)
-    F(0x2800, LDR,     RR_a,  Z,   0, f2, 0, f1, mov2, 0, IF_AFP1 | IF_AFP2)
-    F(0x6800, LD,      RX_a,  Z,   0, m2_64, 0, f1, mov2, 0, IF_AFP1)
-    F(0xed65, LDY,     RXY_a, LD,  0, m2_64, 0, f1, mov2, 0, IF_AFP1)
-    F(0x3800, LER,     RR_a,  Z,   0, e2, 0, cond_e1e2, mov2, 0, IF_AFP1 | IF_AFP2)
-    F(0x7800, LE,      RX_a,  Z,   0, m2_32u, 0, e1, mov2, 0, IF_AFP1)
-    F(0xed64, LEY,     RXY_a, LD,  0, m2_32u, 0, e1, mov2, 0, IF_AFP1)
-    F(0xb365, LXR,     RRE,   Z,   x2h, x2l, 0, x1, movx, 0, IF_AFP1)
-/* LOAD IMMEDIATE */
-    C(0xc001, LGFI,    RIL_a, EI,  0, i2, 0, r1, mov2, 0)
-/* LOAD RELATIVE LONG */
-    C(0xc40d, LRL,     RIL_b, GIE, 0, ri2, new, r1_32, ld32s, 0)
-    C(0xc408, LGRL,    RIL_b, GIE, 0, ri2, r1, 0, ld64, 0)
-    C(0xc40c, LGFRL,   RIL_b, GIE, 0, ri2, r1, 0, ld32s, 0)
-/* LOAD ADDRESS */
-    C(0x4100, LA,      RX_a,  Z,   0, a2, 0, r1, mov2, 0)
-    C(0xe371, LAY,     RXY_a, LD,  0, a2, 0, r1, mov2, 0)
-/* LOAD ADDRESS EXTENDED */
-    C(0x5100, LAE,     RX_a,  Z,   0, a2, 0, r1, mov2e, 0)
-    C(0xe375, LAEY,    RXY_a, GIE, 0, a2, 0, r1, mov2e, 0)
-/* LOAD ADDRESS RELATIVE LONG */
-    C(0xc000, LARL,    RIL_b, Z,   0, ri2, 0, r1, mov2, 0)
-/* LOAD AND ADD */
-    D(0xebf8, LAA,     RSY_a, ILA, r3_32s, a2, new, in2_r1_32, laa, adds32, MO_TESL)
-    D(0xebe8, LAAG,    RSY_a, ILA, r3, a2, new, in2_r1, laa, adds64, MO_TEQ)
-/* LOAD AND ADD LOGICAL */
-    D(0xebfa, LAAL,    RSY_a, ILA, r3_32u, a2, new, in2_r1_32, laa, addu32, MO_TEUL)
-    D(0xebea, LAALG,   RSY_a, ILA, r3, a2, new, in2_r1, laa, addu64, MO_TEQ)
-/* LOAD AND AND */
-    D(0xebf4, LAN,     RSY_a, ILA, r3_32s, a2, new, in2_r1_32, lan, nz32, MO_TESL)
-    D(0xebe4, LANG,    RSY_a, ILA, r3, a2, new, in2_r1, lan, nz64, MO_TEQ)
-/* LOAD AND EXCLUSIVE OR */
-    D(0xebf7, LAX,     RSY_a, ILA, r3_32s, a2, new, in2_r1_32, lax, nz32, MO_TESL)
-    D(0xebe7, LAXG,    RSY_a, ILA, r3, a2, new, in2_r1, lax, nz64, MO_TEQ)
-/* LOAD AND OR */
-    D(0xebf6, LAO,     RSY_a, ILA, r3_32s, a2, new, in2_r1_32, lao, nz32, MO_TESL)
-    D(0xebe6, LAOG,    RSY_a, ILA, r3, a2, new, in2_r1, lao, nz64, MO_TEQ)
-/* LOAD AND TEST */
-    C(0x1200, LTR,     RR_a,  Z,   0, r2_o, 0, cond_r1r2_32, mov2, s32)
-    C(0xb902, LTGR,    RRE,   Z,   0, r2_o, 0, r1, mov2, s64)
-    C(0xb912, LTGFR,   RRE,   Z,   0, r2_32s, 0, r1, mov2, s64)
-    C(0xe312, LT,      RXY_a, EI,  0, a2, new, r1_32, ld32s, s64)
-    C(0xe302, LTG,     RXY_a, EI,  0, a2, r1, 0, ld64, s64)
-    C(0xe332, LTGF,    RXY_a, GIE, 0, a2, r1, 0, ld32s, s64)
-    F(0xb302, LTEBR,   RRE,   Z,   0, e2, 0, cond_e1e2, mov2, f32, IF_BFP)
-    F(0xb312, LTDBR,   RRE,   Z,   0, f2, 0, f1, mov2, f64, IF_BFP)
-    F(0xb342, LTXBR,   RRE,   Z,   x2h, x2l, 0, x1, movx, f128, IF_BFP)
-/* LOAD AND TRAP */
-    C(0xe39f, LAT,     RXY_a, LAT, 0, m2_32u, r1, 0, lat, 0)
-    C(0xe385, LGAT,    RXY_a, LAT, 0, a2, r1, 0, lgat, 0)
-/* LOAD AND ZERO RIGHTMOST BYTE */
-    C(0xe3eb, LZRF,    RXY_a, LZRB, 0, m2_32u, new, r1_32, lzrb, 0)
-    C(0xe32a, LZRG,    RXY_a, LZRB, 0, m2_64, r1, 0, lzrb, 0)
-/* LOAD LOGICAL AND ZERO RIGHTMOST BYTE */
-    C(0xe33a, LLZRGF,  RXY_a, LZRB, 0, m2_32u, r1, 0, lzrb, 0)
-/* LOAD BYTE */
-    C(0xb926, LBR,     RRE,   EI,  0, r2_8s, 0, r1_32, mov2, 0)
-    C(0xb906, LGBR,    RRE,   EI,  0, r2_8s, 0, r1, mov2, 0)
-    C(0xe376, LB,      RXY_a, LD,  0, a2, new, r1_32, ld8s, 0)
-    C(0xe377, LGB,     RXY_a, LD,  0, a2, r1, 0, ld8s, 0)
-/* LOAD BYTE HIGH */
-    C(0xe3c0, LBH,     RXY_a, HW,  0, a2, new, r1_32h, ld8s, 0)
-/* LOAD COMPLEMENT */
-    C(0x1300, LCR,     RR_a,  Z,   0, r2, new, r1_32, neg, neg32)
-    C(0xb903, LCGR,    RRE,   Z,   0, r2, r1, 0, neg, neg64)
-    C(0xb913, LCGFR,   RRE,   Z,   0, r2_32s, r1, 0, neg, neg64)
-    F(0xb303, LCEBR,   RRE,   Z,   0, e2, new, e1, negf32, f32, IF_BFP)
-    F(0xb313, LCDBR,   RRE,   Z,   0, f2, new, f1, negf64, f64, IF_BFP)
-    F(0xb343, LCXBR,   RRE,   Z,   x2h, x2l, new_P, x1, negf128, f128, IF_BFP)
-    F(0xb373, LCDFR,   RRE,   FPSSH, 0, f2, new, f1, negf64, 0, IF_AFP1 | IF_AFP2)
-/* LOAD COUNT TO BLOCK BOUNDARY */
-    C(0xe727, LCBB,    RXE,   V,   la2, 0, r1, 0, lcbb, 0)
-/* LOAD HALFWORD */
-    C(0xb927, LHR,     RRE,   EI,  0, r2_16s, 0, r1_32, mov2, 0)
-    C(0xb907, LGHR,    RRE,   EI,  0, r2_16s, 0, r1, mov2, 0)
-    C(0x4800, LH,      RX_a,  Z,   0, a2, new, r1_32, ld16s, 0)
-    C(0xe378, LHY,     RXY_a, LD,  0, a2, new, r1_32, ld16s, 0)
-    C(0xe315, LGH,     RXY_a, Z,   0, a2, r1, 0, ld16s, 0)
-/* LOAD HALFWORD HIGH */
-    C(0xe3c4, LHH,     RXY_a, HW,  0, a2, new, r1_32h, ld16s, 0)
-/* LOAD HALFWORD IMMEDIATE */
-    C(0xa708, LHI,     RI_a,  Z,   0, i2, 0, r1_32, mov2, 0)
-    C(0xa709, LGHI,    RI_a,  Z,   0, i2, 0, r1, mov2, 0)
-/* LOAD HALFWORD RELATIVE LONG */
-    C(0xc405, LHRL,    RIL_b, GIE, 0, ri2, new, r1_32, ld16s, 0)
-    C(0xc404, LGHRL,   RIL_b, GIE, 0, ri2, r1, 0, ld16s, 0)
-/* LOAD HIGH */
-    C(0xe3ca, LFH,     RXY_a, HW,  0, a2, new, r1_32h, ld32u, 0)
-/* LOAG HIGH AND TRAP */
-    C(0xe3c8, LFHAT,   RXY_a, LAT, 0, m2_32u, r1, 0, lfhat, 0)
-/* LOAD LOGICAL */
-    C(0xb916, LLGFR,   RRE,   Z,   0, r2_32u, 0, r1, mov2, 0)
-    C(0xe316, LLGF,    RXY_a, Z,   0, a2, r1, 0, ld32u, 0)
-/* LOAD LOGICAL AND TRAP */
-    C(0xe39d, LLGFAT,  RXY_a, LAT, 0, a2, r1, 0, llgfat, 0)
-/* LOAD LOGICAL RELATIVE LONG */
-    C(0xc40e, LLGFRL,  RIL_b, GIE, 0, ri2, r1, 0, ld32u, 0)
-/* LOAD LOGICAL CHARACTER */
-    C(0xb994, LLCR,    RRE,   EI,  0, r2_8u, 0, r1_32, mov2, 0)
-    C(0xb984, LLGCR,   RRE,   EI,  0, r2_8u, 0, r1, mov2, 0)
-    C(0xe394, LLC,     RXY_a, EI,  0, a2, new, r1_32, ld8u, 0)
-    C(0xe390, LLGC,    RXY_a, Z,   0, a2, r1, 0, ld8u, 0)
-/* LOAD LOGICAL CHARACTER HIGH */
-    C(0xe3c2, LLCH,    RXY_a, HW,  0, a2, new, r1_32h, ld8u, 0)
-/* LOAD LOGICAL HALFWORD */
-    C(0xb995, LLHR,    RRE,   EI,  0, r2_16u, 0, r1_32, mov2, 0)
-    C(0xb985, LLGHR,   RRE,   EI,  0, r2_16u, 0, r1, mov2, 0)
-    C(0xe395, LLH,     RXY_a, EI,  0, a2, new, r1_32, ld16u, 0)
-    C(0xe391, LLGH,    RXY_a, Z,   0, a2, r1, 0, ld16u, 0)
-/* LOAD LOGICAL HALFWORD HIGH */
-    C(0xe3c6, LLHH,    RXY_a, HW,  0, a2, new, r1_32h, ld16u, 0)
-/* LOAD LOGICAL HALFWORD RELATIVE LONG */
-    C(0xc402, LLHRL,   RIL_b, GIE, 0, ri2, new, r1_32, ld16u, 0)
-    C(0xc406, LLGHRL,  RIL_b, GIE, 0, ri2, r1, 0, ld16u, 0)
-/* LOAD LOGICAL IMMEDATE */
-    D(0xc00e, LLIHF,   RIL_a, EI, 0, i2_32u_shl, 0, r1, mov2, 0, 32)
-    D(0xc00f, LLILF,   RIL_a, EI, 0, i2_32u_shl, 0, r1, mov2, 0, 0)
-    D(0xa50c, LLIHH,   RI_a,  Z,  0, i2_16u_shl, 0, r1, mov2, 0, 48)
-    D(0xa50d, LLIHL,   RI_a,  Z,  0, i2_16u_shl, 0, r1, mov2, 0, 32)
-    D(0xa50e, LLILH,   RI_a,  Z,  0, i2_16u_shl, 0, r1, mov2, 0, 16)
-    D(0xa50f, LLILL,   RI_a,  Z,  0, i2_16u_shl, 0, r1, mov2, 0, 0)
-/* LOAD LOGICAL THIRTY ONE BITS */
-    C(0xb917, LLGTR,   RRE,   Z,  0, r2_o, r1, 0, llgt, 0)
-    C(0xe317, LLGT,    RXY_a, Z,  0, m2_32u, r1, 0, llgt, 0)
-/* LOAD LOGICAL THIRTY ONE BITS AND TRAP */
-    C(0xe39c, LLGTAT,  RXY_a, LAT, 0, m2_32u, r1, 0, llgtat, 0)
-
-/* LOAD FPR FROM GR */
-    F(0xb3c1, LDGR,    RRE,   FPRGR, 0, r2_o, 0, f1, mov2, 0, IF_AFP1)
-/* LOAD GR FROM FPR */
-    F(0xb3cd, LGDR,    RRE,   FPRGR, 0, f2, 0, r1, mov2, 0, IF_AFP2)
-/* LOAD NEGATIVE */
-    C(0x1100, LNR,     RR_a,  Z,   0, r2_32s, new, r1_32, nabs, nabs32)
-    C(0xb901, LNGR,    RRE,   Z,   0, r2, r1, 0, nabs, nabs64)
-    C(0xb911, LNGFR,   RRE,   Z,   0, r2_32s, r1, 0, nabs, nabs64)
-    F(0xb301, LNEBR,   RRE,   Z,   0, e2, new, e1, nabsf32, f32, IF_BFP)
-    F(0xb311, LNDBR,   RRE,   Z,   0, f2, new, f1, nabsf64, f64, IF_BFP)
-    F(0xb341, LNXBR,   RRE,   Z,   x2h, x2l, new_P, x1, nabsf128, f128, IF_BFP)
-    F(0xb371, LNDFR,   RRE,   FPSSH, 0, f2, new, f1, nabsf64, 0, IF_AFP1 | IF_AFP2)
-/* LOAD ON CONDITION */
-    C(0xb9f2, LOCR,    RRF_c, LOC, r1, r2, new, r1_32, loc, 0)
-    C(0xb9e2, LOCGR,   RRF_c, LOC, r1, r2, r1, 0, loc, 0)
-    C(0xebf2, LOC,     RSY_b, LOC, r1, m2_32u, new, r1_32, loc, 0)
-    C(0xebe2, LOCG,    RSY_b, LOC, r1, m2_64, r1, 0, loc, 0)
-/* LOAD HALFWORD IMMEDIATE ON CONDITION */
-    C(0xec42, LOCHI,   RIE_g, LOC2, r1, i2, new, r1_32, loc, 0)
-    C(0xec46, LOCGHI,  RIE_g, LOC2, r1, i2, r1, 0, loc, 0)
-    C(0xec4e, LOCHHI,  RIE_g, LOC2, r1_sr32, i2, new, r1_32h, loc, 0)
-/* LOAD HIGH ON CONDITION */
-    C(0xb9e0, LOCFHR,  RRF_c, LOC2, r1_sr32, r2, new, r1_32h, loc, 0)
-    C(0xebe0, LOCFH,   RSY_b, LOC2, r1_sr32, m2_32u, new, r1_32h, loc, 0)
-/* LOAD PAIR DISJOINT */
-    D(0xc804, LPD,     SSF,   ILA, 0, 0, new_P, r3_P32, lpd, 0, MO_TEUL)
-    D(0xc805, LPDG,    SSF,   ILA, 0, 0, new_P, r3_P64, lpd, 0, MO_TEQ)
-/* LOAD PAIR FROM QUADWORD */
-    C(0xe38f, LPQ,     RXY_a, Z,   0, a2, r1_P, 0, lpq, 0)
-/* LOAD POSITIVE */
-    C(0x1000, LPR,     RR_a,  Z,   0, r2_32s, new, r1_32, abs, abs32)
-    C(0xb900, LPGR,    RRE,   Z,   0, r2, r1, 0, abs, abs64)
-    C(0xb910, LPGFR,   RRE,   Z,   0, r2_32s, r1, 0, abs, abs64)
-    F(0xb300, LPEBR,   RRE,   Z,   0, e2, new, e1, absf32, f32, IF_BFP)
-    F(0xb310, LPDBR,   RRE,   Z,   0, f2, new, f1, absf64, f64, IF_BFP)
-    F(0xb340, LPXBR,   RRE,   Z,   x2h, x2l, new_P, x1, absf128, f128, IF_BFP)
-    F(0xb370, LPDFR,   RRE,   FPSSH, 0, f2, new, f1, absf64, 0, IF_AFP1 | IF_AFP2)
-/* LOAD REVERSED */
-    C(0xb91f, LRVR,    RRE,   Z,   0, r2_32u, new, r1_32, rev32, 0)
-    C(0xb90f, LRVGR,   RRE,   Z,   0, r2_o, r1, 0, rev64, 0)
-    C(0xe31f, LRVH,    RXY_a, Z,   0, m2_16u, new, r1_16, rev16, 0)
-    C(0xe31e, LRV,     RXY_a, Z,   0, m2_32u, new, r1_32, rev32, 0)
-    C(0xe30f, LRVG,    RXY_a, Z,   0, m2_64, r1, 0, rev64, 0)
-/* LOAD ZERO */
-    F(0xb374, LZER,    RRE,   Z,   0, 0, 0, e1, zero, 0, IF_AFP1)
-    F(0xb375, LZDR,    RRE,   Z,   0, 0, 0, f1, zero, 0, IF_AFP1)
-    F(0xb376, LZXR,    RRE,   Z,   0, 0, 0, x1, zero2, 0, IF_AFP1)
-
-/* LOAD FPC */
-    F(0xb29d, LFPC,    S,     Z,   0, m2_32u, 0, 0, sfpc, 0, IF_BFP)
-/* LOAD FPC AND SIGNAL */
-    F(0xb2bd, LFAS,    S,     IEEEE_SIM, 0, m2_32u, 0, 0, sfas, 0, IF_DFP)
-/* LOAD FP INTEGER */
-    F(0xb357, FIEBR,   RRF_e, Z,   0, e2, new, e1, fieb, 0, IF_BFP)
-    F(0xb35f, FIDBR,   RRF_e, Z,   0, f2, new, f1, fidb, 0, IF_BFP)
-    F(0xb347, FIXBR,   RRF_e, Z,   x2h, x2l, new_P, x1, fixb, 0, IF_BFP)
-
-/* LOAD LENGTHENED */
-    F(0xb304, LDEBR,   RRE,   Z,   0, e2, new, f1, ldeb, 0, IF_BFP)
-    F(0xb305, LXDBR,   RRE,   Z,   0, f2, new_P, x1, lxdb, 0, IF_BFP)
-    F(0xb306, LXEBR,   RRE,   Z,   0, e2, new_P, x1, lxeb, 0, IF_BFP)
-    F(0xed04, LDEB,    RXE,   Z,   0, m2_32u, new, f1, ldeb, 0, IF_BFP)
-    F(0xed05, LXDB,    RXE,   Z,   0, m2_64, new_P, x1, lxdb, 0, IF_BFP)
-    F(0xed06, LXEB,    RXE,   Z,   0, m2_32u, new_P, x1, lxeb, 0, IF_BFP)
-    F(0xb324, LDER,    RXE,   Z,   0, e2, new, f1, lde, 0, IF_AFP1)
-    F(0xed24, LDE,     RXE,   Z,   0, m2_32u, new, f1, lde, 0, IF_AFP1)
-/* LOAD ROUNDED */
-    F(0xb344, LEDBR,   RRF_e, Z,   0, f2, new, e1, ledb, 0, IF_BFP)
-    F(0xb345, LDXBR,   RRF_e, Z,   x2h, x2l, new, f1, ldxb, 0, IF_BFP)
-    F(0xb346, LEXBR,   RRF_e, Z,   x2h, x2l, new, e1, lexb, 0, IF_BFP)
-
-/* LOAD MULTIPLE */
-    C(0x9800, LM,      RS_a,  Z,   0, a2, 0, 0, lm32, 0)
-    C(0xeb98, LMY,     RSY_a, LD,  0, a2, 0, 0, lm32, 0)
-    C(0xeb04, LMG,     RSY_a, Z,   0, a2, 0, 0, lm64, 0)
-/* LOAD MULTIPLE HIGH */
-    C(0xeb96, LMH,     RSY_a, Z,   0, a2, 0, 0, lmh, 0)
-/* LOAD ACCESS MULTIPLE */
-    C(0x9a00, LAM,     RS_a,  Z,   0, a2, 0, 0, lam, 0)
-    C(0xeb9a, LAMY,    RSY_a, LD,  0, a2, 0, 0, lam, 0)
-
-/* MONITOR CALL */
-    C(0xaf00, MC,      SI,    Z,   la1, 0, 0, 0, mc, 0)
-
-/* MOVE */
-    C(0xd200, MVC,     SS_a,  Z,   la1, a2, 0, 0, mvc, 0)
-    C(0xe544, MVHHI,   SIL,   GIE, la1, i2, 0, m1_16, mov2, 0)
-    C(0xe54c, MVHI,    SIL,   GIE, la1, i2, 0, m1_32, mov2, 0)
-    C(0xe548, MVGHI,   SIL,   GIE, la1, i2, 0, m1_64, mov2, 0)
-    C(0x9200, MVI,     SI,    Z,   la1, i2, 0, m1_8, mov2, 0)
-    C(0xeb52, MVIY,    SIY,   LD,  la1, i2, 0, m1_8, mov2, 0)
-/* MOVE INVERSE */
-    C(0xe800, MVCIN,   SS_a,  Z,   la1, a2, 0, 0, mvcin, 0)
-/* MOVE LONG */
-    C(0x0e00, MVCL,    RR_a,  Z,   0, 0, 0, 0, mvcl, 0)
-/* MOVE LONG EXTENDED */
-    C(0xa800, MVCLE,   RS_a,  Z,   0, a2, 0, 0, mvcle, 0)
-/* MOVE LONG UNICODE */
-    C(0xeb8e, MVCLU,   RSY_a, E2,  0, a2, 0, 0, mvclu, 0)
-/* MOVE NUMERICS */
-    C(0xd100, MVN,     SS_a,  Z,   la1, a2, 0, 0, mvn, 0)
-/* MOVE PAGE */
-    C(0xb254, MVPG,    RRE,   Z,   0, 0, 0, 0, mvpg, 0)
-/* MOVE STRING */
-    C(0xb255, MVST,    RRE,   Z,   0, 0, 0, 0, mvst, 0)
-/* MOVE WITH OPTIONAL SPECIFICATION */
-    C(0xc800, MVCOS,   SSF,   MVCOS, la1, a2, 0, 0, mvcos, 0)
-/* MOVE WITH OFFSET */
-    /* Really format SS_b, but we pack both lengths into one argument
-       for the helper call, so we might as well leave one 8-bit field.  */
-    C(0xf100, MVO,     SS_a,  Z,   la1, a2, 0, 0, mvo, 0)
-/* MOVE ZONES */
-    C(0xd300, MVZ,     SS_a,  Z,   la1, a2, 0, 0, mvz, 0)
-
-/* MULTIPLY */
-    C(0x1c00, MR,      RR_a,  Z,   r1p1_32s, r2_32s, new, r1_D32, mul, 0)
-    C(0xb9ec, MGRK,    RRF_a, MIE2,r3_o, r2_o, r1_P, 0, muls128, 0)
-    C(0x5c00, M,       RX_a,  Z,   r1p1_32s, m2_32s, new, r1_D32, mul, 0)
-    C(0xe35c, MFY,     RXY_a, GIE, r1p1_32s, m2_32s, new, r1_D32, mul, 0)
-    C(0xe384, MG,      RXY_a, MIE2,r1p1_o, m2_64, r1_P, 0, muls128, 0)
-    F(0xb317, MEEBR,   RRE,   Z,   e1, e2, new, e1, meeb, 0, IF_BFP)
-    F(0xb31c, MDBR,    RRE,   Z,   f1, f2, new, f1, mdb, 0, IF_BFP)
-    F(0xb34c, MXBR,    RRE,   Z,   x2h, x2l, x1, x1, mxb, 0, IF_BFP)
-    F(0xb30c, MDEBR,   RRE,   Z,   f1, e2, new, f1, mdeb, 0, IF_BFP)
-    F(0xb307, MXDBR,   RRE,   Z,   0, f2, x1, x1, mxdb, 0, IF_BFP)
-    F(0xed17, MEEB,    RXE,   Z,   e1, m2_32u, new, e1, meeb, 0, IF_BFP)
-    F(0xed1c, MDB,     RXE,   Z,   f1, m2_64, new, f1, mdb, 0, IF_BFP)
-    F(0xed0c, MDEB,    RXE,   Z,   f1, m2_32u, new, f1, mdeb, 0, IF_BFP)
-    F(0xed07, MXDB,    RXE,   Z,   0, m2_64, x1, x1, mxdb, 0, IF_BFP)
-/* MULTIPLY HALFWORD */
-    C(0x4c00, MH,      RX_a,  Z,   r1_o, m2_16s, new, r1_32, mul, 0)
-    C(0xe37c, MHY,     RXY_a, GIE, r1_o, m2_16s, new, r1_32, mul, 0)
-    C(0xe33c, MGH,     RXY_a, MIE2,r1_o, m2_16s, r1, 0, mul, 0)
-/* MULTIPLY HALFWORD IMMEDIATE */
-    C(0xa70c, MHI,     RI_a,  Z,   r1_o, i2, new, r1_32, mul, 0)
-    C(0xa70d, MGHI,    RI_a,  Z,   r1_o, i2, r1, 0, mul, 0)
-/* MULTIPLY LOGICAL */
-    C(0xb996, MLR,     RRE,   Z,   r1p1_32u, r2_32u, new, r1_D32, mul, 0)
-    C(0xe396, ML,      RXY_a, Z,   r1p1_32u, m2_32u, new, r1_D32, mul, 0)
-    C(0xb986, MLGR,    RRE,   Z,   r1p1, r2_o, r1_P, 0, mul128, 0)
-    C(0xe386, MLG,     RXY_a, Z,   r1p1, m2_64, r1_P, 0, mul128, 0)
-/* MULTIPLY SINGLE */
-    C(0xb252, MSR,     RRE,   Z,   r1_o, r2_o, new, r1_32, mul, 0)
-    C(0xb9fd, MSRKC,   RRF_a, MIE2,r3_32s, r2_32s, new, r1_32, mul, muls32)
-    C(0x7100, MS,      RX_a,  Z,   r1_o, m2_32s, new, r1_32, mul, 0)
-    C(0xe351, MSY,     RXY_a, LD,  r1_o, m2_32s, new, r1_32, mul, 0)
-    C(0xe353, MSC,     RXY_a, MIE2,r1_32s, m2_32s, new, r1_32, mul, muls32)
-    C(0xb90c, MSGR,    RRE,   Z,   r1_o, r2_o, r1, 0, mul, 0)
-    C(0xb9ed, MSGRKC,  RRF_a, MIE2,r3_o, r2_o, new_P, out2_r1, muls128, muls64)
-    C(0xb91c, MSGFR,   RRE,   Z,   r1_o, r2_32s, r1, 0, mul, 0)
-    C(0xe30c, MSG,     RXY_a, Z,   r1_o, m2_64, r1, 0, mul, 0)
-    C(0xe383, MSGC,    RXY_a, MIE2,r1_o, m2_64, new_P, out2_r1, muls128, muls64)
-    C(0xe31c, MSGF,    RXY_a, Z,   r1_o, m2_32s, r1, 0, mul, 0)
-/* MULTIPLY SINGLE IMMEDIATE */
-    C(0xc201, MSFI,    RIL_a, GIE, r1_o, i2, new, r1_32, mul, 0)
-    C(0xc200, MSGFI,   RIL_a, GIE, r1_o, i2, r1, 0, mul, 0)
-
-/* MULTIPLY AND ADD */
-    F(0xb30e, MAEBR,   RRD,   Z,   e1, e2, new, e1, maeb, 0, IF_BFP)
-    F(0xb31e, MADBR,   RRD,   Z,   f1, f2, new, f1, madb, 0, IF_BFP)
-    F(0xed0e, MAEB,    RXF,   Z,   e1, m2_32u, new, e1, maeb, 0, IF_BFP)
-    F(0xed1e, MADB,    RXF,   Z,   f1, m2_64, new, f1, madb, 0, IF_BFP)
-/* MULTIPLY AND SUBTRACT */
-    F(0xb30f, MSEBR,   RRD,   Z,   e1, e2, new, e1, mseb, 0, IF_BFP)
-    F(0xb31f, MSDBR,   RRD,   Z,   f1, f2, new, f1, msdb, 0, IF_BFP)
-    F(0xed0f, MSEB,    RXF,   Z,   e1, m2_32u, new, e1, mseb, 0, IF_BFP)
-    F(0xed1f, MSDB,    RXF,   Z,   f1, m2_64, new, f1, msdb, 0, IF_BFP)
-
-/* OR */
-    C(0x1600, OR,      RR_a,  Z,   r1, r2, new, r1_32, or, nz32)
-    C(0xb9f6, ORK,     RRF_a, DO,  r2, r3, new, r1_32, or, nz32)
-    C(0x5600, O,       RX_a,  Z,   r1, m2_32s, new, r1_32, or, nz32)
-    C(0xe356, OY,      RXY_a, LD,  r1, m2_32s, new, r1_32, or, nz32)
-    C(0xb981, OGR,     RRE,   Z,   r1, r2, r1, 0, or, nz64)
-    C(0xb9e6, OGRK,    RRF_a, DO,  r2, r3, r1, 0, or, nz64)
-    C(0xe381, OG,      RXY_a, Z,   r1, m2_64, r1, 0, or, nz64)
-    C(0xd600, OC,      SS_a,  Z,   la1, a2, 0, 0, oc, 0)
-/* OR IMMEDIATE */
-    D(0xc00c, OIHF,    RIL_a, EI,  r1_o, i2_32u, r1, 0, ori, 0, 0x2020)
-    D(0xc00d, OILF,    RIL_a, EI,  r1_o, i2_32u, r1, 0, ori, 0, 0x2000)
-    D(0xa508, OIHH,    RI_a,  Z,   r1_o, i2_16u, r1, 0, ori, 0, 0x1030)
-    D(0xa509, OIHL,    RI_a,  Z,   r1_o, i2_16u, r1, 0, ori, 0, 0x1020)
-    D(0xa50a, OILH,    RI_a,  Z,   r1_o, i2_16u, r1, 0, ori, 0, 0x1010)
-    D(0xa50b, OILL,    RI_a,  Z,   r1_o, i2_16u, r1, 0, ori, 0, 0x1000)
-    D(0x9600, OI,      SI,    Z,   la1, i2_8u, new, 0, oi, nz64, MO_UB)
-    D(0xeb56, OIY,     SIY,   LD,  la1, i2_8u, new, 0, oi, nz64, MO_UB)
-
-/* PACK */
-    /* Really format SS_b, but we pack both lengths into one argument
-       for the helper call, so we might as well leave one 8-bit field.  */
-    C(0xf200, PACK,    SS_a,  Z,   la1, a2, 0, 0, pack, 0)
-/* PACK ASCII */
-    C(0xe900, PKA,     SS_f,  E2,  la1, a2, 0, 0, pka, 0)
-/* PACK UNICODE */
-    C(0xe100, PKU,     SS_f,  E2,  la1, a2, 0, 0, pku, 0)
-
-/* PREFETCH */
-    /* Implemented as nops of course.  */
-    C(0xe336, PFD,     RXY_b, GIE, 0, 0, 0, 0, 0, 0)
-    C(0xc602, PFDRL,   RIL_c, GIE, 0, 0, 0, 0, 0, 0)
-/* PERFORM PROCESSOR ASSIST */
-    /* Implemented as nop of course.  */
-    C(0xb2e8, PPA,     RRF_c, PPA, 0, 0, 0, 0, 0, 0)
-
-/* POPULATION COUNT */
-    C(0xb9e1, POPCNT,  RRE,   PC,  0, r2_o, r1, 0, popcnt, nz64)
-
-/* ROTATE LEFT SINGLE LOGICAL */
-    C(0xeb1d, RLL,     RSY_a, Z,   r3_o, sh32, new, r1_32, rll32, 0)
-    C(0xeb1c, RLLG,    RSY_a, Z,   r3_o, sh64, r1, 0, rll64, 0)
-
-/* ROTATE THEN INSERT SELECTED BITS */
-    C(0xec55, RISBG,   RIE_f, GIE, 0, r2, r1, 0, risbg, s64)
-    C(0xec59, RISBGN,  RIE_f, MIE, 0, r2, r1, 0, risbg, 0)
-    C(0xec5d, RISBHG,  RIE_f, HW,  0, r2, r1, 0, risbg, 0)
-    C(0xec51, RISBLG,  RIE_f, HW,  0, r2, r1, 0, risbg, 0)
-/* ROTATE_THEN <OP> SELECTED BITS */
-    C(0xec54, RNSBG,   RIE_f, GIE, 0, r2, r1, 0, rosbg, 0)
-    C(0xec56, ROSBG,   RIE_f, GIE, 0, r2, r1, 0, rosbg, 0)
-    C(0xec57, RXSBG,   RIE_f, GIE, 0, r2, r1, 0, rosbg, 0)
-
-/* SEARCH STRING */
-    C(0xb25e, SRST,    RRE,   Z,   0, 0, 0, 0, srst, 0)
-/* SEARCH STRING UNICODE */
-    C(0xb9be, SRSTU,   RRE,   ETF3, 0, 0, 0, 0, srstu, 0)
-
-/* SET ACCESS */
-    C(0xb24e, SAR,     RRE,   Z,   0, r2_o, 0, 0, sar, 0)
-/* SET ADDRESSING MODE */
-    D(0x010c, SAM24,   E,     Z,   0, 0, 0, 0, sam, 0, 0)
-    D(0x010d, SAM31,   E,     Z,   0, 0, 0, 0, sam, 0, 1)
-    D(0x010e, SAM64,   E,     Z,   0, 0, 0, 0, sam, 0, 3)
-/* SET FPC */
-    F(0xb384, SFPC,    RRE,   Z,   0, r1_o, 0, 0, sfpc, 0, IF_BFP)
-/* SET FPC AND SIGNAL */
-    F(0xb385, SFASR,   RRE,   IEEEE_SIM, 0, r1_o, 0, 0, sfas, 0, IF_DFP)
-/* SET BFP ROUNDING MODE */
-    F(0xb299, SRNM,    S,     Z,   la2, 0, 0, 0, srnm, 0, IF_BFP)
-    F(0xb2b8, SRNMB,   S,     FPE, la2, 0, 0, 0, srnmb, 0, IF_BFP)
-/* SET DFP ROUNDING MODE */
-    F(0xb2b9, SRNMT,   S,     DFPR, la2, 0, 0, 0, srnmt, 0, IF_DFP)
-/* SET PROGRAM MASK */
-    C(0x0400, SPM,     RR_a,  Z,   r1, 0, 0, 0, spm, 0)
-
-/* SHIFT LEFT SINGLE */
-    D(0x8b00, SLA,     RS_a,  Z,   r1, sh32, new, r1_32, sla, 0, 31)
-    D(0xebdd, SLAK,    RSY_a, DO,  r3, sh32, new, r1_32, sla, 0, 31)
-    D(0xeb0b, SLAG,    RSY_a, Z,   r3, sh64, r1, 0, sla, 0, 63)
-/* SHIFT LEFT SINGLE LOGICAL */
-    C(0x8900, SLL,     RS_a,  Z,   r1_o, sh32, new, r1_32, sll, 0)
-    C(0xebdf, SLLK,    RSY_a, DO,  r3_o, sh32, new, r1_32, sll, 0)
-    C(0xeb0d, SLLG,    RSY_a, Z,   r3_o, sh64, r1, 0, sll, 0)
-/* SHIFT RIGHT SINGLE */
-    C(0x8a00, SRA,     RS_a,  Z,   r1_32s, sh32, new, r1_32, sra, s32)
-    C(0xebdc, SRAK,    RSY_a, DO,  r3_32s, sh32, new, r1_32, sra, s32)
-    C(0xeb0a, SRAG,    RSY_a, Z,   r3_o, sh64, r1, 0, sra, s64)
-/* SHIFT RIGHT SINGLE LOGICAL */
-    C(0x8800, SRL,     RS_a,  Z,   r1_32u, sh32, new, r1_32, srl, 0)
-    C(0xebde, SRLK,    RSY_a, DO,  r3_32u, sh32, new, r1_32, srl, 0)
-    C(0xeb0c, SRLG,    RSY_a, Z,   r3_o, sh64, r1, 0, srl, 0)
-/* SHIFT LEFT DOUBLE */
-    D(0x8f00, SLDA,    RS_a,  Z,   r1_D32, sh64, new, r1_D32, sla, 0, 31)
-/* SHIFT LEFT DOUBLE LOGICAL */
-    C(0x8d00, SLDL,    RS_a,  Z,   r1_D32, sh64, new, r1_D32, sll, 0)
-/* SHIFT RIGHT DOUBLE */
-    C(0x8e00, SRDA,    RS_a,  Z,   r1_D32, sh64, new, r1_D32, sra, s64)
-/* SHIFT RIGHT DOUBLE LOGICAL */
-    C(0x8c00, SRDL,    RS_a,  Z,   r1_D32, sh64, new, r1_D32, srl, 0)
-
-/* SQUARE ROOT */
-    F(0xb314, SQEBR,   RRE,   Z,   0, e2, new, e1, sqeb, 0, IF_BFP)
-    F(0xb315, SQDBR,   RRE,   Z,   0, f2, new, f1, sqdb, 0, IF_BFP)
-    F(0xb316, SQXBR,   RRE,   Z,   x2h, x2l, new_P, x1, sqxb, 0, IF_BFP)
-    F(0xed14, SQEB,    RXE,   Z,   0, m2_32u, new, e1, sqeb, 0, IF_BFP)
-    F(0xed15, SQDB,    RXE,   Z,   0, m2_64, new, f1, sqdb, 0, IF_BFP)
-
-/* STORE */
-    C(0x5000, ST,      RX_a,  Z,   r1_o, a2, 0, 0, st32, 0)
-    C(0xe350, STY,     RXY_a, LD,  r1_o, a2, 0, 0, st32, 0)
-    C(0xe324, STG,     RXY_a, Z,   r1_o, a2, 0, 0, st64, 0)
-    F(0x6000, STD,     RX_a,  Z,   f1, a2, 0, 0, st64, 0, IF_AFP1)
-    F(0xed67, STDY,    RXY_a, LD,  f1, a2, 0, 0, st64, 0, IF_AFP1)
-    F(0x7000, STE,     RX_a,  Z,   e1, a2, 0, 0, st32, 0, IF_AFP1)
-    F(0xed66, STEY,    RXY_a, LD,  e1, a2, 0, 0, st32, 0, IF_AFP1)
-/* STORE RELATIVE LONG */
-    C(0xc40f, STRL,    RIL_b, GIE, r1_o, ri2, 0, 0, st32, 0)
-    C(0xc40b, STGRL,   RIL_b, GIE, r1_o, ri2, 0, 0, st64, 0)
-/* STORE CHARACTER */
-    C(0x4200, STC,     RX_a,  Z,   r1_o, a2, 0, 0, st8, 0)
-    C(0xe372, STCY,    RXY_a, LD,  r1_o, a2, 0, 0, st8, 0)
-/* STORE CHARACTER HIGH */
-    C(0xe3c3, STCH,    RXY_a, HW,  r1_sr32, a2, 0, 0, st8, 0)
-/* STORE CHARACTERS UNDER MASK */
-    D(0xbe00, STCM,    RS_b,  Z,   r1_o, a2, 0, 0, stcm, 0, 0)
-    D(0xeb2d, STCMY,   RSY_b, LD,  r1_o, a2, 0, 0, stcm, 0, 0)
-    D(0xeb2c, STCMH,   RSY_b, Z,   r1_o, a2, 0, 0, stcm, 0, 32)
-/* STORE HALFWORD */
-    C(0x4000, STH,     RX_a,  Z,   r1_o, a2, 0, 0, st16, 0)
-    C(0xe370, STHY,    RXY_a, LD,  r1_o, a2, 0, 0, st16, 0)
-/* STORE HALFWORD HIGH */
-    C(0xe3c7, STHH,    RXY_a, HW,  r1_sr32, a2, 0, 0, st16, 0)
-/* STORE HALFWORD RELATIVE LONG */
-    C(0xc407, STHRL,   RIL_b, GIE, r1_o, ri2, 0, 0, st16, 0)
-/* STORE HIGH */
-    C(0xe3cb, STFH,    RXY_a, HW,  r1_sr32, a2, 0, 0, st32, 0)
-/* STORE ON CONDITION */
-    D(0xebf3, STOC,    RSY_b, LOC, 0, 0, 0, 0, soc, 0, 0)
-    D(0xebe3, STOCG,   RSY_b, LOC, 0, 0, 0, 0, soc, 0, 1)
-/* STORE HIGH ON CONDITION */
-    D(0xebe1, STOCFH,  RSY_b, LOC2, 0, 0, 0, 0, soc, 0, 2)
-/* STORE REVERSED */
-    C(0xe33f, STRVH,   RXY_a, Z,   la2, r1_16u, new, m1_16, rev16, 0)
-    C(0xe33e, STRV,    RXY_a, Z,   la2, r1_32u, new, m1_32, rev32, 0)
-    C(0xe32f, STRVG,   RXY_a, Z,   la2, r1_o, new, m1_64, rev64, 0)
-
-/* STORE CLOCK */
-    F(0xb205, STCK,    S,     Z,   la2, 0, new, m1_64, stck, 0, IF_IO)
-    F(0xb27c, STCKF,   S,     SCF, la2, 0, new, m1_64, stck, 0, IF_IO)
-/* STORE CLOCK EXTENDED */
-    F(0xb278, STCKE,   S,     Z,   0, a2, 0, 0, stcke, 0, IF_IO)
-
-/* STORE FACILITY LIST EXTENDED */
-    C(0xb2b0, STFLE,   S,  SFLE,   0, a2, 0, 0, stfle, 0)
-/* STORE FPC */
-    F(0xb29c, STFPC,   S,     Z,   0, a2, new, m2_32, efpc, 0, IF_BFP)
-
-/* STORE MULTIPLE */
-    D(0x9000, STM,     RS_a,  Z,   0, a2, 0, 0, stm, 0, 4)
-    D(0xeb90, STMY,    RSY_a, LD,  0, a2, 0, 0, stm, 0, 4)
-    D(0xeb24, STMG,    RSY_a, Z,   0, a2, 0, 0, stm, 0, 8)
-/* STORE MULTIPLE HIGH */
-    C(0xeb26, STMH,    RSY_a, Z,   0, a2, 0, 0, stmh, 0)
-/* STORE ACCESS MULTIPLE */
-    C(0x9b00, STAM,    RS_a,  Z,   0, a2, 0, 0, stam, 0)
-    C(0xeb9b, STAMY,   RSY_a, LD,  0, a2, 0, 0, stam, 0)
-/* STORE PAIR TO QUADWORD */
-    C(0xe38e, STPQ,    RXY_a, Z,   0, a2, r1_P, 0, stpq, 0)
-
-/* SUBTRACT */
-    C(0x1b00, SR,      RR_a,  Z,   r1, r2, new, r1_32, sub, subs32)
-    C(0xb9f9, SRK,     RRF_a, DO,  r2, r3, new, r1_32, sub, subs32)
-    C(0x5b00, S,       RX_a,  Z,   r1, m2_32s, new, r1_32, sub, subs32)
-    C(0xe35b, SY,      RXY_a, LD,  r1, m2_32s, new, r1_32, sub, subs32)
-    C(0xb909, SGR,     RRE,   Z,   r1, r2, r1, 0, sub, subs64)
-    C(0xb919, SGFR,    RRE,   Z,   r1, r2_32s, r1, 0, sub, subs64)
-    C(0xb9e9, SGRK,    RRF_a, DO,  r2, r3, r1, 0, sub, subs64)
-    C(0xe309, SG,      RXY_a, Z,   r1, m2_64, r1, 0, sub, subs64)
-    C(0xe319, SGF,     RXY_a, Z,   r1, m2_32s, r1, 0, sub, subs64)
-    F(0xb30b, SEBR,    RRE,   Z,   e1, e2, new, e1, seb, f32, IF_BFP)
-    F(0xb31b, SDBR,    RRE,   Z,   f1, f2, new, f1, sdb, f64, IF_BFP)
-    F(0xb34b, SXBR,    RRE,   Z,   x2h, x2l, x1, x1, sxb, f128, IF_BFP)
-    F(0xed0b, SEB,     RXE,   Z,   e1, m2_32u, new, e1, seb, f32, IF_BFP)
-    F(0xed1b, SDB,     RXE,   Z,   f1, m2_64, new, f1, sdb, f64, IF_BFP)
-/* SUBTRACT HALFWORD */
-    C(0x4b00, SH,      RX_a,  Z,   r1, m2_16s, new, r1_32, sub, subs32)
-    C(0xe37b, SHY,     RXY_a, LD,  r1, m2_16s, new, r1_32, sub, subs32)
-    C(0xe339, SGH,     RXY_a, MIE2,r1, m2_16s, r1, 0, sub, subs64)
-/* SUBTRACT HIGH */
-    C(0xb9c9, SHHHR,   RRF_a, HW,  r2_sr32, r3_sr32, new, r1_32h, sub, subs32)
-    C(0xb9d9, SHHLR,   RRF_a, HW,  r2_sr32, r3, new, r1_32h, sub, subs32)
-/* SUBTRACT LOGICAL */
-    C(0x1f00, SLR,     RR_a,  Z,   r1_32u, r2_32u, new, r1_32, sub, subu32)
-    C(0xb9fb, SLRK,    RRF_a, DO,  r2_32u, r3_32u, new, r1_32, sub, subu32)
-    C(0x5f00, SL,      RX_a,  Z,   r1_32u, m2_32u, new, r1_32, sub, subu32)
-    C(0xe35f, SLY,     RXY_a, LD,  r1_32u, m2_32u, new, r1_32, sub, subu32)
-    C(0xb90b, SLGR,    RRE,   Z,   r1, r2, r1, 0, subu64, subu64)
-    C(0xb91b, SLGFR,   RRE,   Z,   r1, r2_32u, r1, 0, subu64, subu64)
-    C(0xb9eb, SLGRK,   RRF_a, DO,  r2, r3, r1, 0, subu64, subu64)
-    C(0xe30b, SLG,     RXY_a, Z,   r1, m2_64, r1, 0, subu64, subu64)
-    C(0xe31b, SLGF,    RXY_a, Z,   r1, m2_32u, r1, 0, subu64, subu64)
-/* SUBTRACT LOCICAL HIGH */
-    C(0xb9cb, SLHHHR,  RRF_a, HW,  r2_sr32, r3_sr32, new, r1_32h, sub, subu32)
-    C(0xb9db, SLHHLR,  RRF_a, HW,  r2_sr32, r3_32u, new, r1_32h, sub, subu32)
-/* SUBTRACT LOGICAL IMMEDIATE */
-    C(0xc205, SLFI,    RIL_a, EI,  r1_32u, i2_32u, new, r1_32, sub, subu32)
-    C(0xc204, SLGFI,   RIL_a, EI,  r1, i2_32u, r1, 0, subu64, subu64)
-/* SUBTRACT LOGICAL WITH BORROW */
-    C(0xb999, SLBR,    RRE,   Z,   r1_32u, r2_32u, new, r1_32, subb32, subu32)
-    C(0xb989, SLBGR,   RRE,   Z,   r1, r2, r1, 0, subb64, subu64)
-    C(0xe399, SLB,     RXY_a, Z,   r1_32u, m2_32u, new, r1_32, subb32, subu32)
-    C(0xe389, SLBG,    RXY_a, Z,   r1, m2_64, r1, 0, subb64, subu64)
-
-/* SUPERVISOR CALL */
-    C(0x0a00, SVC,     I,     Z,   0, 0, 0, 0, svc, 0)
-
-/* TEST ADDRESSING MODE */
-    C(0x010b, TAM,     E,     Z,   0, 0, 0, 0, tam, 0)
-
-/* TEST AND SET */
-    C(0x9300, TS,      S,     Z,   0, a2, 0, 0, ts, 0)
-
-/* TEST DATA CLASS */
-    F(0xed10, TCEB,    RXE,   Z,   e1, a2, 0, 0, tceb, 0, IF_BFP)
-    F(0xed11, TCDB,    RXE,   Z,   f1, a2, 0, 0, tcdb, 0, IF_BFP)
-    F(0xed12, TCXB,    RXE,   Z,   0, a2, x1, 0, tcxb, 0, IF_BFP)
-
-/* TEST DECIMAL */
-    C(0xebc0, TP,      RSL,   E2,  la1, 0, 0, 0, tp, 0)
-
-/* TEST UNDER MASK */
-    C(0x9100, TM,      SI,    Z,   m1_8u, i2_8u, 0, 0, 0, tm32)
-    C(0xeb51, TMY,     SIY,   LD,  m1_8u, i2_8u, 0, 0, 0, tm32)
-    D(0xa702, TMHH,    RI_a,  Z,   r1_o, i2_16u_shl, 0, 0, 0, tm64, 48)
-    D(0xa703, TMHL,    RI_a,  Z,   r1_o, i2_16u_shl, 0, 0, 0, tm64, 32)
-    D(0xa700, TMLH,    RI_a,  Z,   r1_o, i2_16u_shl, 0, 0, 0, tm64, 16)
-    D(0xa701, TMLL,    RI_a,  Z,   r1_o, i2_16u_shl, 0, 0, 0, tm64, 0)
-
-/* TRANSLATE */
-    C(0xdc00, TR,      SS_a,  Z,   la1, a2, 0, 0, tr, 0)
-/* TRANSLATE AND TEST */
-    C(0xdd00, TRT,     SS_a,  Z,   la1, a2, 0, 0, trt, 0)
-/* TRANSLATE AND TEST REVERSE */
-    C(0xd000, TRTR,    SS_a,  ETF3, la1, a2, 0, 0, trtr, 0)
-/* TRANSLATE EXTENDED */
-    C(0xb2a5, TRE,     RRE,   Z,   0, r2, r1_P, 0, tre, 0)
-
-/* TRANSLATE ONE TO ONE */
-    C(0xb993, TROO,    RRF_c, E2,  0, 0, 0, 0, trXX, 0)
-/* TRANSLATE ONE TO TWO */
-    C(0xb992, TROT,    RRF_c, E2,  0, 0, 0, 0, trXX, 0)
-/* TRANSLATE TWO TO ONE */
-    C(0xb991, TRTO,    RRF_c, E2,  0, 0, 0, 0, trXX, 0)
-/* TRANSLATE TWO TO TWO */
-    C(0xb990, TRTT,    RRF_c, E2,  0, 0, 0, 0, trXX, 0)
-
-/* UNPACK */
-    /* Really format SS_b, but we pack both lengths into one argument
-       for the helper call, so we might as well leave one 8-bit field.  */
-    C(0xf300, UNPK,    SS_a,  Z,   la1, a2, 0, 0, unpk, 0)
-/* UNPACK ASCII */
-    C(0xea00, UNPKA,   SS_a,  E2,  la1, a2, 0, 0, unpka, 0)
-/* UNPACK UNICODE */
-    C(0xe200, UNPKU,   SS_a,  E2,  la1, a2, 0, 0, unpku, 0)
-
-/* MSA Instructions */
-    D(0xb91e, KMAC,    RRE,   MSA,  0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMAC)
-    D(0xb928, PCKMO,   RRE,   MSA3, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_PCKMO)
-    D(0xb92a, KMF,     RRE,   MSA4, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMF)
-    D(0xb92b, KMO,     RRE,   MSA4, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMO)
-    D(0xb92c, PCC,     RRE,   MSA4, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_PCC)
-    D(0xb92d, KMCTR,   RRF_b, MSA4, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMCTR)
-    D(0xb92e, KM,      RRE,   MSA,  0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KM)
-    D(0xb92f, KMC,     RRE,   MSA,  0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMC)
-    D(0xb929, KMA,     RRF_b, MSA8, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMA)
-    D(0xb93c, PPNO,    RRE,   MSA5, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_PPNO)
-    D(0xb93e, KIMD,    RRE,   MSA,  0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KIMD)
-    D(0xb93f, KLMD,    RRE,   MSA,  0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KLMD)
-
-/* === Vector Support Instructions === */
-
-/* VECTOR BIT PERMUTE */
-    E(0xe785, VBPERM,  VRR_c, VE,  0, 0, 0, 0, vbperm, 0, 0, IF_VEC)
-/* VECTOR GATHER ELEMENT */
-    E(0xe713, VGEF,    VRV,   V,   la2, 0, 0, 0, vge, 0, ES_32, IF_VEC)
-    E(0xe712, VGEG,    VRV,   V,   la2, 0, 0, 0, vge, 0, ES_64, IF_VEC)
-/* VECTOR GENERATE BYTE MASK */
-    F(0xe744, VGBM,    VRI_a, V,   0, 0, 0, 0, vgbm, 0, IF_VEC)
-/* VECTOR GENERATE MASK */
-    F(0xe746, VGM,     VRI_b, V,   0, 0, 0, 0, vgm, 0, IF_VEC)
-/* VECTOR LOAD */
-    F(0xe706, VL,      VRX,   V,   la2, 0, 0, 0, vl, 0, IF_VEC)
-    F(0xe756, VLR,     VRR_a, V,   0, 0, 0, 0, vlr, 0, IF_VEC)
-/* VECTOR LOAD AND REPLICATE */
-    F(0xe705, VLREP,   VRX,   V,   la2, 0, 0, 0, vlrep, 0, IF_VEC)
-/* VECTOR LOAD ELEMENT */
-    E(0xe700, VLEB,    VRX,   V,   la2, 0, 0, 0, vle, 0, ES_8, IF_VEC)
-    E(0xe701, VLEH,    VRX,   V,   la2, 0, 0, 0, vle, 0, ES_16, IF_VEC)
-    E(0xe703, VLEF,    VRX,   V,   la2, 0, 0, 0, vle, 0, ES_32, IF_VEC)
-    E(0xe702, VLEG,    VRX,   V,   la2, 0, 0, 0, vle, 0, ES_64, IF_VEC)
-/* VECTOR LOAD ELEMENT IMMEDIATE */
-    E(0xe740, VLEIB,   VRI_a, V,   0, 0, 0, 0, vlei, 0, ES_8, IF_VEC)
-    E(0xe741, VLEIH,   VRI_a, V,   0, 0, 0, 0, vlei, 0, ES_16, IF_VEC)
-    E(0xe743, VLEIF,   VRI_a, V,   0, 0, 0, 0, vlei, 0, ES_32, IF_VEC)
-    E(0xe742, VLEIG,   VRI_a, V,   0, 0, 0, 0, vlei, 0, ES_64, IF_VEC)
-/* VECTOR LOAD GR FROM VR ELEMENT */
-    F(0xe721, VLGV,    VRS_c, V,   la2, 0, r1, 0, vlgv, 0, IF_VEC)
-/* VECTOR LOAD LOGICAL ELEMENT AND ZERO */
-    F(0xe704, VLLEZ,   VRX,   V,   la2, 0, 0, 0, vllez, 0, IF_VEC)
-/* VECTOR LOAD MULTIPLE */
-    F(0xe736, VLM,     VRS_a, V,   la2, 0, 0, 0, vlm, 0, IF_VEC)
-/* VECTOR LOAD TO BLOCK BOUNDARY */
-    F(0xe707, VLBB,    VRX,   V,   la2, 0, 0, 0, vlbb, 0, IF_VEC)
-/* VECTOR LOAD VR ELEMENT FROM GR */
-    F(0xe722, VLVG,    VRS_b, V,   la2, r3, 0, 0, vlvg, 0, IF_VEC)
-/* VECTOR LOAD VR FROM GRS DISJOINT */
-    F(0xe762, VLVGP,   VRR_f, V,   r2, r3, 0, 0, vlvgp, 0, IF_VEC)
-/* VECTOR LOAD WITH LENGTH */
-    F(0xe737, VLL,     VRS_b, V,   la2, r3_32u, 0, 0, vll, 0, IF_VEC)
-/* VECTOR MERGE HIGH */
-    F(0xe761, VMRH,    VRR_c, V,   0, 0, 0, 0, vmr, 0, IF_VEC)
-/* VECTOR MERGE LOW */
-    F(0xe760, VMRL,    VRR_c, V,   0, 0, 0, 0, vmr, 0, IF_VEC)
-/* VECTOR PACK */
-    F(0xe794, VPK,     VRR_c, V,   0, 0, 0, 0, vpk, 0, IF_VEC)
-/* VECTOR PACK SATURATE */
-    F(0xe797, VPKS,    VRR_b, V,   0, 0, 0, 0, vpk, 0, IF_VEC)
-/* VECTOR PACK LOGICAL SATURATE */
-    F(0xe795, VPKLS,   VRR_b, V,   0, 0, 0, 0, vpk, 0, IF_VEC)
-    F(0xe78c, VPERM,   VRR_e, V,   0, 0, 0, 0, vperm, 0, IF_VEC)
-/* VECTOR PERMUTE DOUBLEWORD IMMEDIATE */
-    F(0xe784, VPDI,    VRR_c, V,   0, 0, 0, 0, vpdi, 0, IF_VEC)
-/* VECTOR REPLICATE */
-    F(0xe74d, VREP,    VRI_c, V,   0, 0, 0, 0, vrep, 0, IF_VEC)
-/* VECTOR REPLICATE IMMEDIATE */
-    F(0xe745, VREPI,   VRI_a, V,   0, 0, 0, 0, vrepi, 0, IF_VEC)
-/* VECTOR SCATTER ELEMENT */
-    E(0xe71b, VSCEF,   VRV,   V,   la2, 0, 0, 0, vsce, 0, ES_32, IF_VEC)
-    E(0xe71a, VSCEG,   VRV,   V,   la2, 0, 0, 0, vsce, 0, ES_64, IF_VEC)
-/* VECTOR SELECT */
-    F(0xe78d, VSEL,    VRR_e, V,   0, 0, 0, 0, vsel, 0, IF_VEC)
-/* VECTOR SIGN EXTEND TO DOUBLEWORD */
-    F(0xe75f, VSEG,    VRR_a, V,   0, 0, 0, 0, vseg, 0, IF_VEC)
-/* VECTOR STORE */
-    F(0xe70e, VST,     VRX,   V,   la2, 0, 0, 0, vst, 0, IF_VEC)
-/* VECTOR STORE ELEMENT */
-    E(0xe708, VSTEB,   VRX,   V,   la2, 0, 0, 0, vste, 0, ES_8, IF_VEC)
-    E(0xe709, VSTEH,   VRX,   V,   la2, 0, 0, 0, vste, 0, ES_16, IF_VEC)
-    E(0xe70b, VSTEF,   VRX,   V,   la2, 0, 0, 0, vste, 0, ES_32, IF_VEC)
-    E(0xe70a, VSTEG,   VRX,   V,   la2, 0, 0, 0, vste, 0, ES_64, IF_VEC)
-/* VECTOR STORE MULTIPLE */
-    F(0xe73e, VSTM,    VRS_a, V,   la2, 0, 0, 0, vstm, 0, IF_VEC)
-/* VECTOR STORE WITH LENGTH */
-    F(0xe73f, VSTL,    VRS_b, V,   la2, r3_32u, 0, 0, vstl, 0, IF_VEC)
-/* VECTOR UNPACK HIGH */
-    F(0xe7d7, VUPH,    VRR_a, V,   0, 0, 0, 0, vup, 0, IF_VEC)
-/* VECTOR UNPACK LOGICAL HIGH */
-    F(0xe7d5, VUPLH,   VRR_a, V,   0, 0, 0, 0, vup, 0, IF_VEC)
-/* VECTOR UNPACK LOW */
-    F(0xe7d6, VUPL,    VRR_a, V,   0, 0, 0, 0, vup, 0, IF_VEC)
-/* VECTOR UNPACK LOGICAL LOW */
-    F(0xe7d4, VUPLL,   VRR_a, V,   0, 0, 0, 0, vup, 0, IF_VEC)
-
-/* === Vector Integer Instructions === */
-
-/* VECTOR ADD */
-    F(0xe7f3, VA,      VRR_c, V,   0, 0, 0, 0, va, 0, IF_VEC)
-/* VECTOR ADD COMPUTE CARRY */
-    F(0xe7f1, VACC,    VRR_c, V,   0, 0, 0, 0, vacc, 0, IF_VEC)
-/* VECTOR ADD WITH CARRY */
-    F(0xe7bb, VAC,     VRR_d, V,   0, 0, 0, 0, vac, 0, IF_VEC)
-/* VECTOR ADD WITH CARRY COMPUTE CARRY */
-    F(0xe7b9, VACCC,   VRR_d, V,   0, 0, 0, 0, vaccc, 0, IF_VEC)
-/* VECTOR AND */
-    F(0xe768, VN,      VRR_c, V,   0, 0, 0, 0, vn, 0, IF_VEC)
-/* VECTOR AND WITH COMPLEMENT */
-    F(0xe769, VNC,     VRR_c, V,   0, 0, 0, 0, vnc, 0, IF_VEC)
-/* VECTOR AVERAGE */
-    F(0xe7f2, VAVG,    VRR_c, V,   0, 0, 0, 0, vavg, 0, IF_VEC)
-/* VECTOR AVERAGE LOGICAL */
-    F(0xe7f0, VAVGL,   VRR_c, V,   0, 0, 0, 0, vavgl, 0, IF_VEC)
-/* VECTOR CHECKSUM */
-    F(0xe766, VCKSM,   VRR_c, V,   0, 0, 0, 0, vcksm, 0, IF_VEC)
-/* VECTOR ELEMENT COMPARE */
-    F(0xe7db, VEC,     VRR_a, V,   0, 0, 0, 0, vec, cmps64, IF_VEC)
-/* VECTOR ELEMENT COMPARE LOGICAL */
-    F(0xe7d9, VECL,    VRR_a, V,   0, 0, 0, 0, vec, cmpu64, IF_VEC)
-/* VECTOR COMPARE EQUAL */
-    E(0xe7f8, VCEQ,    VRR_b, V,   0, 0, 0, 0, vc, 0, TCG_COND_EQ, IF_VEC)
-/* VECTOR COMPARE HIGH */
-    E(0xe7fb, VCH,     VRR_b, V,   0, 0, 0, 0, vc, 0, TCG_COND_GT, IF_VEC)
-/* VECTOR COMPARE HIGH LOGICAL */
-    E(0xe7f9, VCHL,    VRR_b, V,   0, 0, 0, 0, vc, 0, TCG_COND_GTU, IF_VEC)
-/* VECTOR COUNT LEADING ZEROS */
-    F(0xe753, VCLZ,    VRR_a, V,   0, 0, 0, 0, vclz, 0, IF_VEC)
-/* VECTOR COUNT TRAILING ZEROS */
-    F(0xe752, VCTZ,    VRR_a, V,   0, 0, 0, 0, vctz, 0, IF_VEC)
-/* VECTOR EXCLUSIVE OR */
-    F(0xe76d, VX,      VRR_c, V,   0, 0, 0, 0, vx, 0, IF_VEC)
-/* VECTOR GALOIS FIELD MULTIPLY SUM */
-    F(0xe7b4, VGFM,    VRR_c, V,   0, 0, 0, 0, vgfm, 0, IF_VEC)
-/* VECTOR GALOIS FIELD MULTIPLY SUM AND ACCUMULATE */
-    F(0xe7bc, VGFMA,   VRR_d, V,   0, 0, 0, 0, vgfma, 0, IF_VEC)
-/* VECTOR LOAD COMPLEMENT */
-    F(0xe7de, VLC,     VRR_a, V,   0, 0, 0, 0, vlc, 0, IF_VEC)
-/* VECTOR LOAD POSITIVE */
-    F(0xe7df, VLP,     VRR_a, V,   0, 0, 0, 0, vlp, 0, IF_VEC)
-/* VECTOR MAXIMUM */
-    F(0xe7ff, VMX,     VRR_c, V,   0, 0, 0, 0, vmx, 0, IF_VEC)
-/* VECTOR MAXIMUM LOGICAL */
-    F(0xe7fd, VMXL,    VRR_c, V,   0, 0, 0, 0, vmx, 0, IF_VEC)
-/* VECTOR MINIMUM */
-    F(0xe7fe, VMN,     VRR_c, V,   0, 0, 0, 0, vmx, 0, IF_VEC)
-/* VECTOR MINIMUM LOGICAL */
-    F(0xe7fc, VMNL,    VRR_c, V,   0, 0, 0, 0, vmx, 0, IF_VEC)
-/* VECTOR MULTIPLY AND ADD LOW */
-    F(0xe7aa, VMAL,    VRR_d, V,   0, 0, 0, 0, vma, 0, IF_VEC)
-/* VECTOR MULTIPLY AND ADD HIGH */
-    F(0xe7ab, VMAH,    VRR_d, V,   0, 0, 0, 0, vma, 0, IF_VEC)
-/* VECTOR MULTIPLY AND ADD LOGICAL HIGH */
-    F(0xe7a9, VMALH,   VRR_d, V,   0, 0, 0, 0, vma, 0, IF_VEC)
-/* VECTOR MULTIPLY AND ADD EVEN */
-    F(0xe7ae, VMAE,    VRR_d, V,   0, 0, 0, 0, vma, 0, IF_VEC)
-/* VECTOR MULTIPLY AND ADD LOGICAL EVEN */
-    F(0xe7ac, VMALE,   VRR_d, V,   0, 0, 0, 0, vma, 0, IF_VEC)
-/* VECTOR MULTIPLY AND ADD ODD */
-    F(0xe7af, VMAO,    VRR_d, V,   0, 0, 0, 0, vma, 0, IF_VEC)
-/* VECTOR MULTIPLY AND ADD LOGICAL ODD */
-    F(0xe7ad, VMALO,   VRR_d, V,   0, 0, 0, 0, vma, 0, IF_VEC)
-/* VECTOR MULTIPLY HIGH */
-    F(0xe7a3, VMH,     VRR_c, V,   0, 0, 0, 0, vm, 0, IF_VEC)
-/* VECTOR MULTIPLY LOGICAL HIGH */
-    F(0xe7a1, VMLH,    VRR_c, V,   0, 0, 0, 0, vm, 0, IF_VEC)
-/* VECTOR MULTIPLY LOW */
-    F(0xe7a2, VML,     VRR_c, V,   0, 0, 0, 0, vm, 0, IF_VEC)
-/* VECTOR MULTIPLY EVEN */
-    F(0xe7a6, VME,     VRR_c, V,   0, 0, 0, 0, vm, 0, IF_VEC)
-/* VECTOR MULTIPLY LOGICAL EVEN */
-    F(0xe7a4, VMLE,    VRR_c, V,   0, 0, 0, 0, vm, 0, IF_VEC)
-/* VECTOR MULTIPLY ODD */
-    F(0xe7a7, VMO,     VRR_c, V,   0, 0, 0, 0, vm, 0, IF_VEC)
-/* VECTOR MULTIPLY LOGICAL ODD */
-    F(0xe7a5, VMLO,    VRR_c, V,   0, 0, 0, 0, vm, 0, IF_VEC)
-/* VECTOR MULTIPLY SUM LOGICAL */
-    F(0xe7b8, VMSL,    VRR_d, VE,  0, 0, 0, 0, vmsl, 0, IF_VEC)
-/* VECTOR NAND */
-    F(0xe76e, VNN,     VRR_c, VE,  0, 0, 0, 0, vnn, 0, IF_VEC)
-/* VECTOR NOR */
-    F(0xe76b, VNO,     VRR_c, V,   0, 0, 0, 0, vno, 0, IF_VEC)
-/* VECTOR NOT EXCLUSIVE OR */
-    F(0xe76c, VNX,     VRR_c, VE,  0, 0, 0, 0, vnx, 0, IF_VEC)
-/* VECTOR OR */
-    F(0xe76a, VO,      VRR_c, V,   0, 0, 0, 0, vo, 0, IF_VEC)
-/* VECTOR OR WITH COMPLEMENT */
-    F(0xe76f, VOC,     VRR_c, VE,  0, 0, 0, 0, voc, 0, IF_VEC)
-/* VECTOR POPULATION COUNT */
-    F(0xe750, VPOPCT,  VRR_a, V,   0, 0, 0, 0, vpopct, 0, IF_VEC)
-/* VECTOR ELEMENT ROTATE LEFT LOGICAL */
-    F(0xe773, VERLLV,  VRR_c, V,   0, 0, 0, 0, vesv, 0, IF_VEC)
-    F(0xe733, VERLL,   VRS_a, V,   la2, 0, 0, 0, ves, 0, IF_VEC)
-/* VECTOR ELEMENT ROTATE AND INSERT UNDER MASK */
-    F(0xe772, VERIM,   VRI_d, V,   0, 0, 0, 0, verim, 0, IF_VEC)
-/* VECTOR ELEMENT SHIFT LEFT */
-    F(0xe770, VESLV,   VRR_c, V,   0, 0, 0, 0, vesv, 0, IF_VEC)
-    F(0xe730, VESL,    VRS_a, V,   la2, 0, 0, 0, ves, 0, IF_VEC)
-/* VECTOR ELEMENT SHIFT RIGHT ARITHMETIC */
-    F(0xe77a, VESRAV,  VRR_c, V,   0, 0, 0, 0, vesv, 0, IF_VEC)
-    F(0xe73a, VESRA,   VRS_a, V,   la2, 0, 0, 0, ves, 0, IF_VEC)
-/* VECTOR ELEMENT SHIFT RIGHT LOGICAL */
-    F(0xe778, VESRLV,  VRR_c, V,   0, 0, 0, 0, vesv, 0, IF_VEC)
-    F(0xe738, VESRL,   VRS_a, V,   la2, 0, 0, 0, ves, 0, IF_VEC)
-/* VECTOR SHIFT LEFT */
-    F(0xe774, VSL,     VRR_c, V,   0, 0, 0, 0, vsl, 0, IF_VEC)
-/* VECTOR SHIFT LEFT BY BYTE */
-    F(0xe775, VSLB,    VRR_c, V,   0, 0, 0, 0, vsl, 0, IF_VEC)
-/* VECTOR SHIFT LEFT DOUBLE BY BYTE */
-    F(0xe777, VSLDB,   VRI_d, V,   0, 0, 0, 0, vsldb, 0, IF_VEC)
-/* VECTOR SHIFT RIGHT ARITHMETIC */
-    F(0xe77e, VSRA,    VRR_c, V,   0, 0, 0, 0, vsra, 0, IF_VEC)
-/* VECTOR SHIFT RIGHT ARITHMETIC BY BYTE */
-    F(0xe77f, VSRAB,   VRR_c, V,   0, 0, 0, 0, vsra, 0, IF_VEC)
-/* VECTOR SHIFT RIGHT LOGICAL */
-    F(0xe77c, VSRL,    VRR_c, V,   0, 0, 0, 0, vsrl, 0, IF_VEC)
-/* VECTOR SHIFT RIGHT LOGICAL BY BYTE */
-    F(0xe77d, VSRLB,   VRR_c, V,   0, 0, 0, 0, vsrl, 0, IF_VEC)
-/* VECTOR SUBTRACT */
-    F(0xe7f7, VS,      VRR_c, V,   0, 0, 0, 0, vs, 0, IF_VEC)
-/* VECTOR SUBTRACT COMPUTE BORROW INDICATION */
-    F(0xe7f5, VSCBI,   VRR_c, V,   0, 0, 0, 0, vscbi, 0, IF_VEC)
-/* VECTOR SUBTRACT WITH BORROW INDICATION */
-    F(0xe7bf, VSBI,    VRR_d, V,   0, 0, 0, 0, vsbi, 0, IF_VEC)
-/* VECTOR SUBTRACT WITH BORROW COMPUTE BORROW INDICATION */
-    F(0xe7bd, VSBCBI,  VRR_d, V,   0, 0, 0, 0, vsbcbi, 0, IF_VEC)
-/* VECTOR SUM ACROSS DOUBLEWORD */
-    F(0xe765, VSUMG,   VRR_c, V,   0, 0, 0, 0, vsumg, 0, IF_VEC)
-/* VECTOR SUM ACROSS QUADWORD */
-    F(0xe767, VSUMQ,   VRR_c, V,   0, 0, 0, 0, vsumq, 0, IF_VEC)
-/* VECTOR SUM ACROSS WORD */
-    F(0xe764, VSUM,    VRR_c, V,   0, 0, 0, 0, vsum, 0, IF_VEC)
-/* VECTOR TEST UNDER MASK */
-    F(0xe7d8, VTM,     VRR_a, V,   0, 0, 0, 0, vtm, 0, IF_VEC)
-
-/* === Vector String Instructions === */
-
-/* VECTOR FIND ANY ELEMENT EQUAL */
-    F(0xe782, VFAE,    VRR_b, V,   0, 0, 0, 0, vfae, 0, IF_VEC)
-/* VECTOR FIND ELEMENT EQUAL */
-    F(0xe780, VFEE,    VRR_b, V,   0, 0, 0, 0, vfee, 0, IF_VEC)
-/* VECTOR FIND ELEMENT NOT EQUAL */
-    F(0xe781, VFENE,   VRR_b, V,   0, 0, 0, 0, vfene, 0, IF_VEC)
-/* VECTOR ISOLATE STRING */
-    F(0xe75c, VISTR,   VRR_a, V,   0, 0, 0, 0, vistr, 0, IF_VEC)
-/* VECTOR STRING RANGE COMPARE */
-    F(0xe78a, VSTRC,   VRR_d, V,   0, 0, 0, 0, vstrc, 0, IF_VEC)
-
-/* === Vector Floating-Point Instructions */
-
-/* VECTOR FP ADD */
-    F(0xe7e3, VFA,     VRR_c, V,   0, 0, 0, 0, vfa, 0, IF_VEC)
-/* VECTOR FP COMPARE SCALAR */
-    F(0xe7cb, WFC,     VRR_a, V,   0, 0, 0, 0, wfc, 0, IF_VEC)
-/* VECTOR FP COMPARE AND SIGNAL SCALAR */
-    F(0xe7ca, WFK,     VRR_a, V,   0, 0, 0, 0, wfc, 0, IF_VEC)
-/* VECTOR FP COMPARE EQUAL */
-    F(0xe7e8, VFCE,    VRR_c, V,   0, 0, 0, 0, vfc, 0, IF_VEC)
-/* VECTOR FP COMPARE HIGH */
-    F(0xe7eb, VFCH,    VRR_c, V,   0, 0, 0, 0, vfc, 0, IF_VEC)
-/* VECTOR FP COMPARE HIGH OR EQUAL */
-    F(0xe7ea, VFCHE,   VRR_c, V,   0, 0, 0, 0, vfc, 0, IF_VEC)
-/* VECTOR FP CONVERT FROM FIXED 64-BIT */
-    F(0xe7c3, VCDG,    VRR_a, V,   0, 0, 0, 0, vcdg, 0, IF_VEC)
-/* VECTOR FP CONVERT FROM LOGICAL 64-BIT */
-    F(0xe7c1, VCDLG,   VRR_a, V,   0, 0, 0, 0, vcdg, 0, IF_VEC)
-/* VECTOR FP CONVERT TO FIXED 64-BIT */
-    F(0xe7c2, VCGD,    VRR_a, V,   0, 0, 0, 0, vcdg, 0, IF_VEC)
-/* VECTOR FP CONVERT TO LOGICAL 64-BIT */
-    F(0xe7c0, VCLGD,   VRR_a, V,   0, 0, 0, 0, vcdg, 0, IF_VEC)
-/* VECTOR FP DIVIDE */
-    F(0xe7e5, VFD,     VRR_c, V,   0, 0, 0, 0, vfa, 0, IF_VEC)
-/* VECTOR LOAD FP INTEGER */
-    F(0xe7c7, VFI,     VRR_a, V,   0, 0, 0, 0, vcdg, 0, IF_VEC)
-/* VECTOR FP LOAD LENGTHENED */
-    F(0xe7c4, VFLL,    VRR_a, V,   0, 0, 0, 0, vfll, 0, IF_VEC)
-/* VECTOR FP LOAD ROUNDED */
-    F(0xe7c5, VFLR,    VRR_a, V,   0, 0, 0, 0, vcdg, 0, IF_VEC)
-/* VECTOR FP MAXIMUM */
-    F(0xe7ef, VFMAX,   VRR_c, VE,  0, 0, 0, 0, vfmax, 0, IF_VEC)
-/* VECTOR FP MINIMUM */
-    F(0xe7ee, VFMIN,   VRR_c, VE,  0, 0, 0, 0, vfmax, 0, IF_VEC)
-/* VECTOR FP MULTIPLY */
-    F(0xe7e7, VFM,     VRR_c, V,   0, 0, 0, 0, vfa, 0, IF_VEC)
-/* VECTOR FP MULTIPLY AND ADD */
-    F(0xe78f, VFMA,    VRR_e, V,   0, 0, 0, 0, vfma, 0, IF_VEC)
-/* VECTOR FP MULTIPLY AND SUBTRACT */
-    F(0xe78e, VFMS,    VRR_e, V,   0, 0, 0, 0, vfma, 0, IF_VEC)
-/* VECTOR FP NEGATIVE MULTIPLY AND ADD */
-    F(0xe79f, VFNMA,   VRR_e, VE,  0, 0, 0, 0, vfma, 0, IF_VEC)
-/* VECTOR FP NEGATIVE MULTIPLY AND SUBTRACT */
-    F(0xe79e, VFNMS,   VRR_e, VE,   0, 0, 0, 0, vfma, 0, IF_VEC)
-/* VECTOR FP PERFORM SIGN OPERATION */
-    F(0xe7cc, VFPSO,   VRR_a, V,   0, 0, 0, 0, vfpso, 0, IF_VEC)
-/* VECTOR FP SQUARE ROOT */
-    F(0xe7ce, VFSQ,    VRR_a, V,   0, 0, 0, 0, vfsq, 0, IF_VEC)
-/* VECTOR FP SUBTRACT */
-    F(0xe7e2, VFS,     VRR_c, V,   0, 0, 0, 0, vfa, 0, IF_VEC)
-/* VECTOR FP TEST DATA CLASS IMMEDIATE */
-    F(0xe74a, VFTCI,   VRI_e, V,   0, 0, 0, 0, vftci, 0, IF_VEC)
-
-#ifndef CONFIG_USER_ONLY
-/* COMPARE AND SWAP AND PURGE */
-    E(0xb250, CSP,     RRE,   Z,   r1_32u, ra2, r1_P, 0, csp, 0, MO_TEUL, IF_PRIV)
-    E(0xb98a, CSPG,    RRE, DAT_ENH, r1_o, ra2, r1_P, 0, csp, 0, MO_TEQ, IF_PRIV)
-/* DIAGNOSE (KVM hypercall) */
-    F(0x8300, DIAG,    RSI,   Z,   0, 0, 0, 0, diag, 0, IF_PRIV | IF_IO)
-/* INSERT STORAGE KEY EXTENDED */
-    F(0xb229, ISKE,    RRE,   Z,   0, r2_o, new, r1_8, iske, 0, IF_PRIV)
-/* INVALIDATE DAT TABLE ENTRY */
-    F(0xb98e, IPDE,    RRF_b, Z,   r1_o, r2_o, 0, 0, idte, 0, IF_PRIV)
-/* INVALIDATE PAGE TABLE ENTRY */
-    F(0xb221, IPTE,    RRF_a, Z,   r1_o, r2_o, 0, 0, ipte, 0, IF_PRIV)
-/* LOAD CONTROL */
-    F(0xb700, LCTL,    RS_a,  Z,   0, a2, 0, 0, lctl, 0, IF_PRIV)
-    F(0xeb2f, LCTLG,   RSY_a, Z,   0, a2, 0, 0, lctlg, 0, IF_PRIV)
-/* LOAD PROGRAM PARAMETER */
-    F(0xb280, LPP,     S,   LPP,   0, m2_64, 0, 0, lpp, 0, IF_PRIV)
-/* LOAD PSW */
-    F(0x8200, LPSW,    S,     Z,   0, a2, 0, 0, lpsw, 0, IF_PRIV)
-/* LOAD PSW EXTENDED */
-    F(0xb2b2, LPSWE,   S,     Z,   0, a2, 0, 0, lpswe, 0, IF_PRIV)
-/* LOAD REAL ADDRESS */
-    F(0xb100, LRA,     RX_a,  Z,   0, a2, r1, 0, lra, 0, IF_PRIV)
-    F(0xe313, LRAY,    RXY_a, LD,  0, a2, r1, 0, lra, 0, IF_PRIV)
-    F(0xe303, LRAG,    RXY_a, Z,   0, a2, r1, 0, lra, 0, IF_PRIV)
-/* LOAD USING REAL ADDRESS */
-    E(0xb24b, LURA,    RRE,   Z,   0, ra2, new, r1_32, lura, 0, MO_TEUL, IF_PRIV)
-    E(0xb905, LURAG,   RRE,   Z,   0, ra2, r1, 0, lura, 0, MO_TEQ, IF_PRIV)
-/* MOVE TO PRIMARY */
-    F(0xda00, MVCP,    SS_d,  Z,   la1, a2, 0, 0, mvcp, 0, IF_PRIV)
-/* MOVE TO SECONDARY */
-    F(0xdb00, MVCS,    SS_d,  Z,   la1, a2, 0, 0, mvcs, 0, IF_PRIV)
-/* PURGE TLB */
-    F(0xb20d, PTLB,    S,     Z,   0, 0, 0, 0, ptlb, 0, IF_PRIV)
-/* RESET REFERENCE BIT EXTENDED */
-    F(0xb22a, RRBE,    RRE,   Z,   0, r2_o, 0, 0, rrbe, 0, IF_PRIV)
-/* SERVICE CALL LOGICAL PROCESSOR (PV hypercall) */
-    F(0xb220, SERVC,   RRE,   Z,   r1_o, r2_o, 0, 0, servc, 0, IF_PRIV | IF_IO)
-/* SET ADDRESS SPACE CONTROL FAST */
-    F(0xb279, SACF,    S,     Z,   0, a2, 0, 0, sacf, 0, IF_PRIV)
-/* SET CLOCK */
-    F(0xb204, SCK,     S,     Z,   la2, 0, 0, 0, sck, 0, IF_PRIV | IF_IO)
-/* SET CLOCK COMPARATOR */
-    F(0xb206, SCKC,    S,     Z,   0, m2_64a, 0, 0, sckc, 0, IF_PRIV | IF_IO)
-/* SET CLOCK PROGRAMMABLE FIELD */
-    F(0x0107, SCKPF,   E,     Z,   0, 0, 0, 0, sckpf, 0, IF_PRIV)
-/* SET CPU TIMER */
-    F(0xb208, SPT,     S,     Z,   0, m2_64a, 0, 0, spt, 0, IF_PRIV | IF_IO)
-/* SET PREFIX */
-    F(0xb210, SPX,     S,     Z,   0, m2_32ua, 0, 0, spx, 0, IF_PRIV)
-/* SET PSW KEY FROM ADDRESS */
-    F(0xb20a, SPKA,    S,     Z,   0, a2, 0, 0, spka, 0, IF_PRIV)
-/* SET STORAGE KEY EXTENDED */
-    F(0xb22b, SSKE,    RRF_c, Z,   r1_o, r2_o, 0, 0, sske, 0, IF_PRIV)
-/* SET SYSTEM MASK */
-    F(0x8000, SSM,     S,     Z,   0, m2_8u, 0, 0, ssm, 0, IF_PRIV)
-/* SIGNAL PROCESSOR */
-    F(0xae00, SIGP,    RS_a,  Z,   0, a2, 0, 0, sigp, 0, IF_PRIV | IF_IO)
-/* STORE CLOCK COMPARATOR */
-    F(0xb207, STCKC,   S,     Z,   la2, 0, new, m1_64a, stckc, 0, IF_PRIV)
-/* STORE CONTROL */
-    F(0xb600, STCTL,   RS_a,  Z,   0, a2, 0, 0, stctl, 0, IF_PRIV)
-    F(0xeb25, STCTG,   RSY_a, Z,   0, a2, 0, 0, stctg, 0, IF_PRIV)
-/* STORE CPU ADDRESS */
-    F(0xb212, STAP,    S,     Z,   la2, 0, new, m1_16a, stap, 0, IF_PRIV)
-/* STORE CPU ID */
-    F(0xb202, STIDP,   S,     Z,   la2, 0, new, m1_64a, stidp, 0, IF_PRIV)
-/* STORE CPU TIMER */
-    F(0xb209, STPT,    S,     Z,   la2, 0, new, m1_64a, stpt, 0, IF_PRIV | IF_IO)
-/* STORE FACILITY LIST */
-    F(0xb2b1, STFL,    S,     Z,   0, 0, 0, 0, stfl, 0, IF_PRIV)
-/* STORE PREFIX */
-    F(0xb211, STPX,    S,     Z,   la2, 0, new, m1_32a, stpx, 0, IF_PRIV)
-/* STORE SYSTEM INFORMATION */
-    F(0xb27d, STSI,    S,     Z,   0, a2, 0, 0, stsi, 0, IF_PRIV)
-/* STORE THEN AND SYSTEM MASK */
-    F(0xac00, STNSM,   SI,    Z,   la1, 0, 0, 0, stnosm, 0, IF_PRIV)
-/* STORE THEN OR SYSTEM MASK */
-    F(0xad00, STOSM,   SI,    Z,   la1, 0, 0, 0, stnosm, 0, IF_PRIV)
-/* STORE USING REAL ADDRESS */
-    E(0xb246, STURA,   RRE,   Z,   r1_o, ra2, 0, 0, stura, 0, MO_TEUL, IF_PRIV)
-    E(0xb925, STURG,   RRE,   Z,   r1_o, ra2, 0, 0, stura, 0, MO_TEQ, IF_PRIV)
-/* TEST BLOCK */
-    F(0xb22c, TB,      RRE,   Z,   0, r2_o, 0, 0, testblock, 0, IF_PRIV)
-/* TEST PROTECTION */
-    C(0xe501, TPROT,   SSE,   Z,   la1, a2, 0, 0, tprot, 0)
-
-/* CCW I/O Instructions */
-    F(0xb276, XSCH,    S,     Z,   0, 0, 0, 0, xsch, 0, IF_PRIV | IF_IO)
-    F(0xb230, CSCH,    S,     Z,   0, 0, 0, 0, csch, 0, IF_PRIV | IF_IO)
-    F(0xb231, HSCH,    S,     Z,   0, 0, 0, 0, hsch, 0, IF_PRIV | IF_IO)
-    F(0xb232, MSCH,    S,     Z,   0, insn, 0, 0, msch, 0, IF_PRIV | IF_IO)
-    F(0xb23b, RCHP,    S,     Z,   0, 0, 0, 0, rchp, 0, IF_PRIV | IF_IO)
-    F(0xb238, RSCH,    S,     Z,   0, 0, 0, 0, rsch, 0, IF_PRIV | IF_IO)
-    F(0xb237, SAL,     S,     Z,   0, 0, 0, 0, sal, 0, IF_PRIV | IF_IO)
-    F(0xb23c, SCHM,    S,     Z,   0, insn, 0, 0, schm, 0, IF_PRIV | IF_IO)
-    F(0xb274, SIGA,    S,     Z,   0, 0, 0, 0, siga, 0, IF_PRIV | IF_IO)
-    F(0xb23a, STCPS,   S,     Z,   0, 0, 0, 0, stcps, 0, IF_PRIV | IF_IO)
-    F(0xb233, SSCH,    S,     Z,   0, insn, 0, 0, ssch, 0, IF_PRIV | IF_IO)
-    F(0xb239, STCRW,   S,     Z,   0, insn, 0, 0, stcrw, 0, IF_PRIV | IF_IO)
-    F(0xb234, STSCH,   S,     Z,   0, insn, 0, 0, stsch, 0, IF_PRIV | IF_IO)
-    F(0xb236, TPI ,    S,     Z,   la2, 0, 0, 0, tpi, 0, IF_PRIV | IF_IO)
-    F(0xb235, TSCH,    S,     Z,   0, insn, 0, 0, tsch, 0, IF_PRIV | IF_IO)
-    /* ??? Not listed in PoO ninth edition, but there's a linux driver that
-       uses it: "A CHSC subchannel is usually present on LPAR only."  */
-    F(0xb25f, CHSC,  RRE,     Z,   0, insn, 0, 0, chsc, 0, IF_PRIV | IF_IO)
-
-/* zPCI Instructions */
-    /* None of these instructions are documented in the PoP, so this is all
-       based upon target/s390x/kvm.c and Linux code and likely incomplete */
-    F(0xebd0, PCISTB, RSY_a, PCI, la2, 0, 0, 0, pcistb, 0, IF_PRIV | IF_IO)
-    F(0xebd1, SIC, RSY_a, AIS, r1, r3, 0, 0, sic, 0, IF_PRIV | IF_IO)
-    F(0xb9a0, CLP, RRF_c, PCI, 0, 0, 0, 0, clp, 0, IF_PRIV | IF_IO)
-    F(0xb9d0, PCISTG, RRE, PCI, 0, 0, 0, 0, pcistg, 0, IF_PRIV | IF_IO)
-    F(0xb9d2, PCILG, RRE, PCI, 0, 0, 0, 0, pcilg, 0, IF_PRIV | IF_IO)
-    F(0xb9d3, RPCIT, RRE, PCI, 0, 0, 0, 0, rpcit, 0, IF_PRIV | IF_IO)
-    F(0xe3d0, MPCIFC, RXY_a, PCI, la2, 0, 0, 0, mpcifc, 0, IF_PRIV | IF_IO)
-    F(0xe3d4, STPCIFC, RXY_a, PCI, la2, 0, 0, 0, stpcifc, 0, IF_PRIV | IF_IO)
-
-#endif /* CONFIG_USER_ONLY */
diff --git a/target/s390x/insn-format.def b/target/s390x/insn-format.def
deleted file mode 100644 (file)
index 6253edb..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/* Description of s390 insn formats.  */
-/* NAME   F1,          F2... */
-F0(E)
-F1(I,     I(1, 8, 8))
-F2(RI_a,  R(1, 8),     I(2,16,16))
-F2(RI_b,  R(1, 8),     I(2,16,16))
-F2(RI_c,  M(1, 8),     I(2,16,16))
-F3(RIE_a, R(1, 8),     I(2,16,16),  M(3,32))
-F4(RIE_b, R(1, 8),     R(2,12),     M(3,32),   I(4,16,16))
-F4(RIE_c, R(1, 8),     I(2,32, 8),  M(3,12),   I(4,16,16))
-F3(RIE_d, R(1, 8),     I(2,16,16),  R(3,12))
-F3(RIE_e, R(1, 8),     I(2,16,16),  R(3,12))
-F5(RIE_f, R(1, 8),     R(2,12),     I(3,16,8), I(4,24,8),  I(5,32,8))
-F3(RIE_g, R(1, 8),     I(2,16,16),  M(3,12))
-F2(RIL_a, R(1, 8),     I(2,16,32))
-F2(RIL_b, R(1, 8),     I(2,16,32))
-F2(RIL_c, M(1, 8),     I(2,16,32))
-F4(RIS,   R(1, 8),     I(2,32, 8),  M(3,12),   BD(4,16,20))
-/* ??? The PoO does not call out subtypes _a and _b for RR, as it does
-   for e.g. RX.  Our checking requires this for e.g. BCR.  */
-F2(RR_a,  R(1, 8),     R(2,12))
-F2(RR_b,  M(1, 8),     R(2,12))
-F2(RRE,   R(1,24),     R(2,28))
-F3(RRD,   R(1,16),     R(2,28),     R(3,24))
-F4(RRF_a, R(1,24),     R(2,28),     R(3,16),   M(4,20))
-F4(RRF_b, R(1,24),     R(2,28),     R(3,16),   M(4,20))
-F4(RRF_c, R(1,24),     R(2,28),     M(3,16),   M(4,20))
-F4(RRF_d, R(1,24),     R(2,28),     M(3,16),   M(4,20))
-F4(RRF_e, R(1,24),     R(2,28),     M(3,16),   M(4,20))
-F4(RRS,   R(1, 8),     R(2,12),     M(3,32),   BD(4,16,20))
-F3(RS_a,  R(1, 8),     BD(2,16,20), R(3,12))
-F3(RS_b,  R(1, 8),     BD(2,16,20), M(3,12))
-F3(RSI,   R(1, 8),     I(2,16,16),  R(3,12))
-F2(RSL,   L(1, 8, 4),  BD(1,16,20))
-F3(RSY_a, R(1, 8),     BDL(2),      R(3,12))
-F3(RSY_b, R(1, 8),     BDL(2),      M(3,12))
-F2(RX_a,  R(1, 8),     BXD(2))
-F2(RX_b,  M(1, 8),     BXD(2))
-F3(RXE,   R(1, 8),     BXD(2),      M(3,32))
-F3(RXF,   R(1,32),     BXD(2),      R(3, 8))
-F2(RXY_a, R(1, 8),     BXDL(2))
-F2(RXY_b, M(1, 8),     BXDL(2))
-F1(S,     BD(2,16,20))
-F2(SI,    BD(1,16,20), I(2,8,8))
-F2(SIL,   BD(1,16,20), I(2,32,16))
-F2(SIY,   BDL(1),      I(2, 8, 8))
-F3(SS_a,  L(1, 8, 8),  BD(1,16,20), BD(2,32,36))
-F4(SS_b,  L(1, 8, 4),  BD(1,16,20), L(2,12,4),   BD(2,32,36))
-F4(SS_c,  L(1, 8, 4),  BD(1,16,20), BD(2,32,36), I(3,12, 4))
-/* ??? Odd man out.  The L1 field here is really a register, but the
-   easy way to compress the fields has R1 and B1 overlap.  */
-F4(SS_d,  L(1, 8, 4),  BD(1,16,20), BD(2,32,36), R(3,12))
-F4(SS_e,  R(1, 8),     BD(2,16,20), R(3,12),     BD(4,32,36))
-F3(SS_f,  BD(1,16,20), L(2,8,8),    BD(2,32,36))
-F2(SSE,   BD(1,16,20), BD(2,32,36))
-F3(SSF,   BD(1,16,20), BD(2,32,36), R(3,8))
-F3(VRI_a, V(1,8),      I(2,16,16),  M(3,32))
-F4(VRI_b, V(1,8),      I(2,16,8),   I(3,24,8),   M(4,32))
-F4(VRI_c, V(1,8),      V(3,12),     I(2,16,16),  M(4,32))
-F5(VRI_d, V(1,8),      V(2,12),     V(3,16),     I(4,24,8),   M(5,32))
-F5(VRI_e, V(1,8),      V(2,12),     I(3,16,12),  M(5,28),     M(4,32))
-F5(VRI_f, V(1,8),      V(2,12),     V(3,16),     M(5,24),     I(4,28,8))
-F5(VRI_g, V(1,8),      V(2,12),     I(4,16,8),   M(5,24),     I(3,28,8))
-F3(VRI_h, V(1,8),      I(2,16,16),  I(3,32,4))
-F4(VRI_i, V(1,8),      R(2,12),     M(4,24),     I(3,28,8))
-F5(VRR_a, V(1,8),      V(2,12),     M(5,24),     M(4,28),     M(3,32))
-F5(VRR_b, V(1,8),      V(2,12),     V(3,16),     M(5,24),     M(4,32))
-F6(VRR_c, V(1,8),      V(2,12),     V(3,16),     M(6,24),     M(5,28),  M(4,32))
-F6(VRR_d, V(1,8),      V(2,12),     V(3,16),     M(5,20),     M(6,24),  V(4,32))
-F6(VRR_e, V(1,8),      V(2,12),     V(3,16),     M(6,20),     M(5,28),  V(4,32))
-F3(VRR_f, V(1,8),      R(2,12),     R(3,16))
-F1(VRR_g, V(1,12))
-F3(VRR_h, V(1,12),     V(2,16),     M(3,24))
-F3(VRR_i, R(1,8),      V(2,12),     M(3,24))
-F4(VRS_a, V(1,8),      V(3,12),     BD(2,16,20), M(4,32))
-F4(VRS_b, V(1,8),      R(3,12),     BD(2,16,20), M(4,32))
-F4(VRS_c, R(1,8),      V(3,12),     BD(2,16,20), M(4,32))
-F3(VRS_d, R(3,12),     BD(2,16,20), V(1,32))
-F4(VRV,   V(1,8),      V(2,12),     BD(2,16,20), M(3,32))
-F3(VRX,   V(1,8),      BXD(2),      M(3,32))
-F3(VSI,   I(3,8,8),    BD(2,16,20), V(1,32))
diff --git a/target/s390x/int_helper.c b/target/s390x/int_helper.c
deleted file mode 100644 (file)
index 658507d..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- *  S/390 integer helper routines
- *
- *  Copyright (c) 2009 Ulrich Hecht
- *  Copyright (c) 2009 Alexander Graf
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "internal.h"
-#include "tcg_s390x.h"
-#include "exec/exec-all.h"
-#include "qemu/host-utils.h"
-#include "exec/helper-proto.h"
-
-/* #define DEBUG_HELPER */
-#ifdef DEBUG_HELPER
-#define HELPER_LOG(x...) qemu_log(x)
-#else
-#define HELPER_LOG(x...)
-#endif
-
-/* 64/32 -> 32 signed division */
-int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64)
-{
-    int32_t ret, b = b64;
-    int64_t q;
-
-    if (b == 0) {
-        tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
-    }
-
-    ret = q = a / b;
-    env->retxl = a % b;
-
-    /* Catch non-representable quotient.  */
-    if (ret != q) {
-        tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
-    }
-
-    return ret;
-}
-
-/* 64/32 -> 32 unsigned division */
-uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b64)
-{
-    uint32_t ret, b = b64;
-    uint64_t q;
-
-    if (b == 0) {
-        tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
-    }
-
-    ret = q = a / b;
-    env->retxl = a % b;
-
-    /* Catch non-representable quotient.  */
-    if (ret != q) {
-        tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
-    }
-
-    return ret;
-}
-
-/* 64/64 -> 64 signed division */
-int64_t HELPER(divs64)(CPUS390XState *env, int64_t a, int64_t b)
-{
-    /* Catch divide by zero, and non-representable quotient (MIN / -1).  */
-    if (b == 0 || (b == -1 && a == (1ll << 63))) {
-        tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
-    }
-    env->retxl = a % b;
-    return a / b;
-}
-
-/* 128 -> 64/64 unsigned division */
-uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al,
-                        uint64_t b)
-{
-    uint64_t ret;
-    /* Signal divide by zero.  */
-    if (b == 0) {
-        tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
-    }
-    if (ah == 0) {
-        /* 64 -> 64/64 case */
-        env->retxl = al % b;
-        ret = al / b;
-    } else {
-        /* ??? Move i386 idivq helper to host-utils.  */
-#ifdef CONFIG_INT128
-        __uint128_t a = ((__uint128_t)ah << 64) | al;
-        __uint128_t q = a / b;
-        env->retxl = a % b;
-        ret = q;
-        if (ret != q) {
-            tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
-        }
-#else
-        /* 32-bit hosts would need special wrapper functionality - just abort if
-           we encounter such a case; it's very unlikely anyways. */
-        cpu_abort(env_cpu(env), "128 -> 64/64 division not implemented\n");
-#endif
-    }
-    return ret;
-}
-
-uint64_t HELPER(cvd)(int32_t reg)
-{
-    /* positive 0 */
-    uint64_t dec = 0x0c;
-    int64_t bin = reg;
-    int shift;
-
-    if (bin < 0) {
-        bin = -bin;
-        dec = 0x0d;
-    }
-
-    for (shift = 4; (shift < 64) && bin; shift += 4) {
-        dec |= (bin % 10) << shift;
-        bin /= 10;
-    }
-
-    return dec;
-}
-
-uint64_t HELPER(popcnt)(uint64_t val)
-{
-    /* Note that we don't fold past bytes. */
-    val = (val & 0x5555555555555555ULL) + ((val >> 1) & 0x5555555555555555ULL);
-    val = (val & 0x3333333333333333ULL) + ((val >> 2) & 0x3333333333333333ULL);
-    val = (val + (val >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
-    return val;
-}
diff --git a/target/s390x/internal.h b/target/s390x/internal.h
deleted file mode 100644 (file)
index 9256275..0000000
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * s390x internal definitions and helpers
- *
- * Copyright (c) 2009 Ulrich Hecht
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#ifndef S390X_INTERNAL_H
-#define S390X_INTERNAL_H
-
-#include "cpu.h"
-
-#ifndef CONFIG_USER_ONLY
-typedef struct LowCore {
-    /* prefix area: defined by architecture */
-    uint32_t        ccw1[2];                  /* 0x000 */
-    uint32_t        ccw2[4];                  /* 0x008 */
-    uint8_t         pad1[0x80 - 0x18];        /* 0x018 */
-    uint32_t        ext_params;               /* 0x080 */
-    uint16_t        cpu_addr;                 /* 0x084 */
-    uint16_t        ext_int_code;             /* 0x086 */
-    uint16_t        svc_ilen;                 /* 0x088 */
-    uint16_t        svc_code;                 /* 0x08a */
-    uint16_t        pgm_ilen;                 /* 0x08c */
-    uint16_t        pgm_code;                 /* 0x08e */
-    uint32_t        data_exc_code;            /* 0x090 */
-    uint16_t        mon_class_num;            /* 0x094 */
-    uint16_t        per_perc_atmid;           /* 0x096 */
-    uint64_t        per_address;              /* 0x098 */
-    uint8_t         exc_access_id;            /* 0x0a0 */
-    uint8_t         per_access_id;            /* 0x0a1 */
-    uint8_t         op_access_id;             /* 0x0a2 */
-    uint8_t         ar_access_id;             /* 0x0a3 */
-    uint8_t         pad2[0xA8 - 0xA4];        /* 0x0a4 */
-    uint64_t        trans_exc_code;           /* 0x0a8 */
-    uint64_t        monitor_code;             /* 0x0b0 */
-    uint16_t        subchannel_id;            /* 0x0b8 */
-    uint16_t        subchannel_nr;            /* 0x0ba */
-    uint32_t        io_int_parm;              /* 0x0bc */
-    uint32_t        io_int_word;              /* 0x0c0 */
-    uint8_t         pad3[0xc8 - 0xc4];        /* 0x0c4 */
-    uint32_t        stfl_fac_list;            /* 0x0c8 */
-    uint8_t         pad4[0xe8 - 0xcc];        /* 0x0cc */
-    uint64_t        mcic;                     /* 0x0e8 */
-    uint8_t         pad5[0xf4 - 0xf0];        /* 0x0f0 */
-    uint32_t        external_damage_code;     /* 0x0f4 */
-    uint64_t        failing_storage_address;  /* 0x0f8 */
-    uint8_t         pad6[0x110 - 0x100];      /* 0x100 */
-    uint64_t        per_breaking_event_addr;  /* 0x110 */
-    uint8_t         pad7[0x120 - 0x118];      /* 0x118 */
-    PSW             restart_old_psw;          /* 0x120 */
-    PSW             external_old_psw;         /* 0x130 */
-    PSW             svc_old_psw;              /* 0x140 */
-    PSW             program_old_psw;          /* 0x150 */
-    PSW             mcck_old_psw;             /* 0x160 */
-    PSW             io_old_psw;               /* 0x170 */
-    uint8_t         pad8[0x1a0 - 0x180];      /* 0x180 */
-    PSW             restart_new_psw;          /* 0x1a0 */
-    PSW             external_new_psw;         /* 0x1b0 */
-    PSW             svc_new_psw;              /* 0x1c0 */
-    PSW             program_new_psw;          /* 0x1d0 */
-    PSW             mcck_new_psw;             /* 0x1e0 */
-    PSW             io_new_psw;               /* 0x1f0 */
-    uint8_t         pad13[0x11b0 - 0x200];    /* 0x200 */
-
-    uint64_t        mcesad;                    /* 0x11B0 */
-
-    /* 64 bit extparam used for pfault, diag 250 etc  */
-    uint64_t        ext_params2;               /* 0x11B8 */
-
-    uint8_t         pad14[0x1200 - 0x11C0];    /* 0x11C0 */
-
-    /* System info area */
-
-    uint64_t        floating_pt_save_area[16]; /* 0x1200 */
-    uint64_t        gpregs_save_area[16];      /* 0x1280 */
-    uint32_t        st_status_fixed_logout[4]; /* 0x1300 */
-    uint8_t         pad15[0x1318 - 0x1310];    /* 0x1310 */
-    uint32_t        prefixreg_save_area;       /* 0x1318 */
-    uint32_t        fpt_creg_save_area;        /* 0x131c */
-    uint8_t         pad16[0x1324 - 0x1320];    /* 0x1320 */
-    uint32_t        tod_progreg_save_area;     /* 0x1324 */
-    uint64_t        cpu_timer_save_area;       /* 0x1328 */
-    uint64_t        clock_comp_save_area;      /* 0x1330 */
-    uint8_t         pad17[0x1340 - 0x1338];    /* 0x1338 */
-    uint32_t        access_regs_save_area[16]; /* 0x1340 */
-    uint64_t        cregs_save_area[16];       /* 0x1380 */
-
-    /* align to the top of the prefix area */
-
-    uint8_t         pad18[0x2000 - 0x1400];    /* 0x1400 */
-} QEMU_PACKED LowCore;
-QEMU_BUILD_BUG_ON(sizeof(LowCore) != 8192);
-#endif /* CONFIG_USER_ONLY */
-
-#define MAX_ILEN 6
-
-/* While the PoO talks about ILC (a number between 1-3) what is actually
-   stored in LowCore is shifted left one bit (an even between 2-6).  As
-   this is the actual length of the insn and therefore more useful, that
-   is what we want to pass around and manipulate.  To make sure that we
-   have applied this distinction universally, rename the "ILC" to "ILEN".  */
-static inline int get_ilen(uint8_t opc)
-{
-    switch (opc >> 6) {
-    case 0:
-        return 2;
-    case 1:
-    case 2:
-        return 4;
-    default:
-        return 6;
-    }
-}
-
-/* Compute the ATMID field that is stored in the per_perc_atmid lowcore
-   entry when a PER exception is triggered.  */
-static inline uint8_t get_per_atmid(CPUS390XState *env)
-{
-    return ((env->psw.mask & PSW_MASK_64) ?       (1 << 7) : 0) |
-                                                  (1 << 6)      |
-           ((env->psw.mask & PSW_MASK_32) ?       (1 << 5) : 0) |
-           ((env->psw.mask & PSW_MASK_DAT) ?      (1 << 4) : 0) |
-           ((env->psw.mask & PSW_ASC_SECONDARY) ? (1 << 3) : 0) |
-           ((env->psw.mask & PSW_ASC_ACCREG) ?    (1 << 2) : 0);
-}
-
-static inline uint64_t wrap_address(CPUS390XState *env, uint64_t a)
-{
-    if (!(env->psw.mask & PSW_MASK_64)) {
-        if (!(env->psw.mask & PSW_MASK_32)) {
-            /* 24-Bit mode */
-            a &= 0x00ffffff;
-        } else {
-            /* 31-Bit mode */
-            a &= 0x7fffffff;
-        }
-    }
-    return a;
-}
-
-/* CC optimization */
-
-/* Instead of computing the condition codes after each x86 instruction,
- * QEMU just stores the result (called CC_DST), the type of operation
- * (called CC_OP) and whatever operands are needed (CC_SRC and possibly
- * CC_VR). When the condition codes are needed, the condition codes can
- * be calculated using this information. Condition codes are not generated
- * if they are only needed for conditional branches.
- */
-enum cc_op {
-    CC_OP_CONST0 = 0,           /* CC is 0 */
-    CC_OP_CONST1,               /* CC is 1 */
-    CC_OP_CONST2,               /* CC is 2 */
-    CC_OP_CONST3,               /* CC is 3 */
-
-    CC_OP_DYNAMIC,              /* CC calculation defined by env->cc_op */
-    CC_OP_STATIC,               /* CC value is env->cc_op */
-
-    CC_OP_NZ,                   /* env->cc_dst != 0 */
-    CC_OP_ADDU,                 /* dst != 0, src = carry out (0,1) */
-    CC_OP_SUBU,                 /* dst != 0, src = borrow out (0,-1) */
-
-    CC_OP_LTGT_32,              /* signed less/greater than (32bit) */
-    CC_OP_LTGT_64,              /* signed less/greater than (64bit) */
-    CC_OP_LTUGTU_32,            /* unsigned less/greater than (32bit) */
-    CC_OP_LTUGTU_64,            /* unsigned less/greater than (64bit) */
-    CC_OP_LTGT0_32,             /* signed less/greater than 0 (32bit) */
-    CC_OP_LTGT0_64,             /* signed less/greater than 0 (64bit) */
-
-    CC_OP_ADD_64,               /* overflow on add (64bit) */
-    CC_OP_SUB_64,               /* overflow on subtraction (64bit) */
-    CC_OP_ABS_64,               /* sign eval on abs (64bit) */
-    CC_OP_NABS_64,              /* sign eval on nabs (64bit) */
-    CC_OP_MULS_64,              /* overflow on signed multiply (64bit) */
-
-    CC_OP_ADD_32,               /* overflow on add (32bit) */
-    CC_OP_SUB_32,               /* overflow on subtraction (32bit) */
-    CC_OP_ABS_32,               /* sign eval on abs (64bit) */
-    CC_OP_NABS_32,              /* sign eval on nabs (64bit) */
-    CC_OP_MULS_32,              /* overflow on signed multiply (32bit) */
-
-    CC_OP_COMP_32,              /* complement */
-    CC_OP_COMP_64,              /* complement */
-
-    CC_OP_TM_32,                /* test under mask (32bit) */
-    CC_OP_TM_64,                /* test under mask (64bit) */
-
-    CC_OP_NZ_F32,               /* FP dst != 0 (32bit) */
-    CC_OP_NZ_F64,               /* FP dst != 0 (64bit) */
-    CC_OP_NZ_F128,              /* FP dst != 0 (128bit) */
-
-    CC_OP_ICM,                  /* insert characters under mask */
-    CC_OP_SLA_32,               /* Calculate shift left signed (32bit) */
-    CC_OP_SLA_64,               /* Calculate shift left signed (64bit) */
-    CC_OP_FLOGR,                /* find leftmost one */
-    CC_OP_LCBB,                 /* load count to block boundary */
-    CC_OP_VC,                   /* vector compare result */
-    CC_OP_MAX
-};
-
-#ifndef CONFIG_USER_ONLY
-
-static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb,
-                                       uint8_t *ar)
-{
-    hwaddr addr = 0;
-    uint8_t reg;
-
-    reg = ipb >> 28;
-    if (reg > 0) {
-        addr = env->regs[reg];
-    }
-    addr += (ipb >> 16) & 0xfff;
-    if (ar) {
-        *ar = reg;
-    }
-
-    return addr;
-}
-
-/* Base/displacement are at the same locations. */
-#define decode_basedisp_rs decode_basedisp_s
-
-#endif /* CONFIG_USER_ONLY */
-
-/* arch_dump.c */
-int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
-                              int cpuid, void *opaque);
-
-
-/* cc_helper.c */
-const char *cc_name(enum cc_op cc_op);
-uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
-                 uint64_t vr);
-
-/* cpu.c */
-#ifndef CONFIG_USER_ONLY
-unsigned int s390_cpu_halt(S390CPU *cpu);
-void s390_cpu_unhalt(S390CPU *cpu);
-#else
-static inline unsigned int s390_cpu_halt(S390CPU *cpu)
-{
-    return 0;
-}
-
-static inline void s390_cpu_unhalt(S390CPU *cpu)
-{
-}
-#endif /* CONFIG_USER_ONLY */
-
-
-/* cpu_models.c */
-void s390_cpu_model_class_register_props(ObjectClass *oc);
-void s390_realize_cpu_model(CPUState *cs, Error **errp);
-ObjectClass *s390_cpu_class_by_name(const char *name);
-
-
-/* excp_helper.c */
-void s390x_cpu_debug_excp_handler(CPUState *cs);
-void s390_cpu_do_interrupt(CPUState *cpu);
-bool s390_cpu_exec_interrupt(CPUState *cpu, int int_req);
-bool s390_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
-                       MMUAccessType access_type, int mmu_idx,
-                       bool probe, uintptr_t retaddr);
-void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
-                                   MMUAccessType access_type,
-                                   int mmu_idx, uintptr_t retaddr);
-
-
-/* fpu_helper.c */
-uint32_t set_cc_nz_f32(float32 v);
-uint32_t set_cc_nz_f64(float64 v);
-uint32_t set_cc_nz_f128(float128 v);
-#define S390_IEEE_MASK_INVALID   0x80
-#define S390_IEEE_MASK_DIVBYZERO 0x40
-#define S390_IEEE_MASK_OVERFLOW  0x20
-#define S390_IEEE_MASK_UNDERFLOW 0x10
-#define S390_IEEE_MASK_INEXACT   0x08
-#define S390_IEEE_MASK_QUANTUM   0x04
-uint8_t s390_softfloat_exc_to_ieee(unsigned int exc);
-int s390_swap_bfp_rounding_mode(CPUS390XState *env, int m3);
-void s390_restore_bfp_rounding_mode(CPUS390XState *env, int old_mode);
-int float_comp_to_cc(CPUS390XState *env, int float_compare);
-
-#define DCMASK_ZERO             0x0c00
-#define DCMASK_NORMAL           0x0300
-#define DCMASK_SUBNORMAL        0x00c0
-#define DCMASK_INFINITY         0x0030
-#define DCMASK_QUIET_NAN        0x000c
-#define DCMASK_SIGNALING_NAN    0x0003
-#define DCMASK_NAN              0x000f
-#define DCMASK_NEGATIVE         0x0555
-uint16_t float32_dcmask(CPUS390XState *env, float32 f1);
-uint16_t float64_dcmask(CPUS390XState *env, float64 f1);
-uint16_t float128_dcmask(CPUS390XState *env, float128 f1);
-
-
-/* gdbstub.c */
-int s390_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
-int s390_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
-void s390_cpu_gdb_init(CPUState *cs);
-
-
-/* helper.c */
-void s390_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
-void do_restart_interrupt(CPUS390XState *env);
-#ifndef CONFIG_USER_ONLY
-void s390_cpu_recompute_watchpoints(CPUState *cs);
-void s390x_tod_timer(void *opaque);
-void s390x_cpu_timer(void *opaque);
-void s390_handle_wait(S390CPU *cpu);
-hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-hwaddr s390_cpu_get_phys_addr_debug(CPUState *cpu, vaddr addr);
-#define S390_STORE_STATUS_DEF_ADDR offsetof(LowCore, floating_pt_save_area)
-int s390_store_status(S390CPU *cpu, hwaddr addr, bool store_arch);
-int s390_store_adtl_status(S390CPU *cpu, hwaddr addr, hwaddr len);
-LowCore *cpu_map_lowcore(CPUS390XState *env);
-void cpu_unmap_lowcore(LowCore *lowcore);
-#endif /* CONFIG_USER_ONLY */
-
-
-/* interrupt.c */
-void trigger_pgm_exception(CPUS390XState *env, uint32_t code);
-void cpu_inject_clock_comparator(S390CPU *cpu);
-void cpu_inject_cpu_timer(S390CPU *cpu);
-void cpu_inject_emergency_signal(S390CPU *cpu, uint16_t src_cpu_addr);
-int cpu_inject_external_call(S390CPU *cpu, uint16_t src_cpu_addr);
-bool s390_cpu_has_io_int(S390CPU *cpu);
-bool s390_cpu_has_ext_int(S390CPU *cpu);
-bool s390_cpu_has_mcck_int(S390CPU *cpu);
-bool s390_cpu_has_int(S390CPU *cpu);
-bool s390_cpu_has_restart_int(S390CPU *cpu);
-bool s390_cpu_has_stop_int(S390CPU *cpu);
-void cpu_inject_restart(S390CPU *cpu);
-void cpu_inject_stop(S390CPU *cpu);
-
-
-/* ioinst.c */
-void ioinst_handle_xsch(S390CPU *cpu, uint64_t reg1, uintptr_t ra);
-void ioinst_handle_csch(S390CPU *cpu, uint64_t reg1, uintptr_t ra);
-void ioinst_handle_hsch(S390CPU *cpu, uint64_t reg1, uintptr_t ra);
-void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb,
-                        uintptr_t ra);
-void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb,
-                        uintptr_t ra);
-void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb, uintptr_t ra);
-void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb,
-                         uintptr_t ra);
-int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra);
-void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra);
-void ioinst_handle_schm(S390CPU *cpu, uint64_t reg1, uint64_t reg2,
-                        uint32_t ipb, uintptr_t ra);
-void ioinst_handle_rsch(S390CPU *cpu, uint64_t reg1, uintptr_t ra);
-void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1, uintptr_t ra);
-void ioinst_handle_sal(S390CPU *cpu, uint64_t reg1, uintptr_t ra);
-
-
-/* mem_helper.c */
-target_ulong mmu_real2abs(CPUS390XState *env, target_ulong raddr);
-void probe_write_access(CPUS390XState *env, uint64_t addr, uint64_t len,
-                        uintptr_t ra);
-
-
-/* mmu_helper.c */
-int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
-                  target_ulong *raddr, int *flags, uint64_t *tec);
-int mmu_translate_real(CPUS390XState *env, target_ulong raddr, int rw,
-                       target_ulong *addr, int *flags, uint64_t *tec);
-
-
-/* misc_helper.c */
-int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3);
-void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3,
-                     uintptr_t ra);
-
-
-/* translate.c */
-void s390x_translate_init(void);
-
-
-/* sigp.c */
-int handle_sigp(CPUS390XState *env, uint8_t order, uint64_t r1, uint64_t r3);
-void do_stop_interrupt(CPUS390XState *env);
-
-#endif /* S390X_INTERNAL_H */
index 9b4d08f2be3787c540b04247fe30590217d90edb..5195f060ecbf1db7f9486048df4632243b4fec3d 100644 (file)
@@ -9,13 +9,13 @@
 
 #include "qemu/osdep.h"
 #include "cpu.h"
-#include "kvm_s390x.h"
-#include "internal.h"
+#include "kvm/kvm_s390x.h"
+#include "s390x-internal.h"
 #include "exec/exec-all.h"
 #include "sysemu/kvm.h"
 #include "sysemu/tcg.h"
 #include "hw/s390x/ioinst.h"
-#include "tcg_s390x.h"
+#include "tcg/tcg_s390x.h"
 #if !defined(CONFIG_USER_ONLY)
 #include "hw/s390x/s390_flic.h"
 #endif
index 1ee11522e15039a2121e0325790efbcfd8b054bc..4eb0a7a9f8141cfe1d85f9efa071632bf6690567 100644 (file)
@@ -12,7 +12,7 @@
 #include "qemu/osdep.h"
 
 #include "cpu.h"
-#include "internal.h"
+#include "s390x-internal.h"
 #include "hw/s390x/ioinst.h"
 #include "trace.h"
 #include "hw/s390x/s390-pci-bus.h"
diff --git a/target/s390x/kvm-stub.c b/target/s390x/kvm-stub.c
deleted file mode 100644 (file)
index 8a308cf..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * QEMU KVM support -- s390x specific function stubs.
- *
- * Copyright (c) 2009 Ulrich Hecht
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "kvm_s390x.h"
-
-void kvm_s390_access_exception(S390CPU *cpu, uint16_t code, uint64_t te_code)
-{
-}
-
-int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf,
-                    int len, bool is_write)
-{
-    return -ENOSYS;
-}
-
-void kvm_s390_program_interrupt(S390CPU *cpu, uint16_t code)
-{
-}
-
-int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state)
-{
-    return -ENOSYS;
-}
-
-void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu)
-{
-}
-
-int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu)
-{
-    return 0;
-}
-
-int kvm_s390_get_hpage_1m(void)
-{
-    return 0;
-}
-
-int kvm_s390_get_ri(void)
-{
-    return 0;
-}
-
-int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_low)
-{
-    return -ENOSYS;
-}
-
-int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_low)
-{
-    return -ENOSYS;
-}
-
-int kvm_s390_set_clock(uint8_t tod_high, uint64_t tod_low)
-{
-    return -ENOSYS;
-}
-
-int kvm_s390_set_clock_ext(uint8_t tod_high, uint64_t tod_low)
-{
-    return -ENOSYS;
-}
-
-void kvm_s390_enable_css_support(S390CPU *cpu)
-{
-}
-
-int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch,
-                                    int vq, bool assign)
-{
-    return -ENOSYS;
-}
-
-void kvm_s390_cmma_reset(void)
-{
-}
-
-void kvm_s390_reset_vcpu_initial(S390CPU *cpu)
-{
-}
-
-void kvm_s390_reset_vcpu_clear(S390CPU *cpu)
-{
-}
-
-void kvm_s390_reset_vcpu_normal(S390CPU *cpu)
-{
-}
-
-int kvm_s390_set_mem_limit(uint64_t new_limit, uint64_t *hw_limit)
-{
-    return 0;
-}
-
-void kvm_s390_set_max_pagesize(uint64_t pagesize, Error **errp)
-{
-}
-
-void kvm_s390_crypto_reset(void)
-{
-}
-
-void kvm_s390_stop_interrupt(S390CPU *cpu)
-{
-}
-
-void kvm_s390_restart_interrupt(S390CPU *cpu)
-{
-}
-
-void kvm_s390_set_diag318(CPUState *cs, uint64_t diag318_info)
-{
-}
diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
deleted file mode 100644 (file)
index 2388924..0000000
+++ /dev/null
@@ -1,2564 +0,0 @@
-/*
- * QEMU S390x KVM implementation
- *
- * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
- * Copyright IBM Corp. 2012
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include <sys/ioctl.h>
-
-#include <linux/kvm.h>
-#include <asm/ptrace.h>
-
-#include "qemu-common.h"
-#include "cpu.h"
-#include "internal.h"
-#include "kvm_s390x.h"
-#include "sysemu/kvm_int.h"
-#include "qemu/cutils.h"
-#include "qapi/error.h"
-#include "qemu/error-report.h"
-#include "qemu/timer.h"
-#include "qemu/units.h"
-#include "qemu/main-loop.h"
-#include "qemu/mmap-alloc.h"
-#include "qemu/log.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/hw_accel.h"
-#include "sysemu/runstate.h"
-#include "sysemu/device_tree.h"
-#include "exec/gdbstub.h"
-#include "exec/ram_addr.h"
-#include "trace.h"
-#include "hw/s390x/s390-pci-inst.h"
-#include "hw/s390x/s390-pci-bus.h"
-#include "hw/s390x/ipl.h"
-#include "hw/s390x/ebcdic.h"
-#include "exec/memattrs.h"
-#include "hw/s390x/s390-virtio-ccw.h"
-#include "hw/s390x/s390-virtio-hcall.h"
-#include "hw/s390x/pv.h"
-
-#ifndef DEBUG_KVM
-#define DEBUG_KVM  0
-#endif
-
-#define DPRINTF(fmt, ...) do {                \
-    if (DEBUG_KVM) {                          \
-        fprintf(stderr, fmt, ## __VA_ARGS__); \
-    }                                         \
-} while (0)
-
-#define kvm_vm_check_mem_attr(s, attr) \
-    kvm_vm_check_attr(s, KVM_S390_VM_MEM_CTRL, attr)
-
-#define IPA0_DIAG                       0x8300
-#define IPA0_SIGP                       0xae00
-#define IPA0_B2                         0xb200
-#define IPA0_B9                         0xb900
-#define IPA0_EB                         0xeb00
-#define IPA0_E3                         0xe300
-
-#define PRIV_B2_SCLP_CALL               0x20
-#define PRIV_B2_CSCH                    0x30
-#define PRIV_B2_HSCH                    0x31
-#define PRIV_B2_MSCH                    0x32
-#define PRIV_B2_SSCH                    0x33
-#define PRIV_B2_STSCH                   0x34
-#define PRIV_B2_TSCH                    0x35
-#define PRIV_B2_TPI                     0x36
-#define PRIV_B2_SAL                     0x37
-#define PRIV_B2_RSCH                    0x38
-#define PRIV_B2_STCRW                   0x39
-#define PRIV_B2_STCPS                   0x3a
-#define PRIV_B2_RCHP                    0x3b
-#define PRIV_B2_SCHM                    0x3c
-#define PRIV_B2_CHSC                    0x5f
-#define PRIV_B2_SIGA                    0x74
-#define PRIV_B2_XSCH                    0x76
-
-#define PRIV_EB_SQBS                    0x8a
-#define PRIV_EB_PCISTB                  0xd0
-#define PRIV_EB_SIC                     0xd1
-
-#define PRIV_B9_EQBS                    0x9c
-#define PRIV_B9_CLP                     0xa0
-#define PRIV_B9_PCISTG                  0xd0
-#define PRIV_B9_PCILG                   0xd2
-#define PRIV_B9_RPCIT                   0xd3
-
-#define PRIV_E3_MPCIFC                  0xd0
-#define PRIV_E3_STPCIFC                 0xd4
-
-#define DIAG_TIMEREVENT                 0x288
-#define DIAG_IPL                        0x308
-#define DIAG_SET_CONTROL_PROGRAM_CODES  0x318
-#define DIAG_KVM_HYPERCALL              0x500
-#define DIAG_KVM_BREAKPOINT             0x501
-
-#define ICPT_INSTRUCTION                0x04
-#define ICPT_PROGRAM                    0x08
-#define ICPT_EXT_INT                    0x14
-#define ICPT_WAITPSW                    0x1c
-#define ICPT_SOFT_INTERCEPT             0x24
-#define ICPT_CPU_STOP                   0x28
-#define ICPT_OPEREXC                    0x2c
-#define ICPT_IO                         0x40
-#define ICPT_PV_INSTR                   0x68
-#define ICPT_PV_INSTR_NOTIFICATION      0x6c
-
-#define NR_LOCAL_IRQS 32
-/*
- * Needs to be big enough to contain max_cpus emergency signals
- * and in addition NR_LOCAL_IRQS interrupts
- */
-#define VCPU_IRQ_BUF_SIZE(max_cpus) (sizeof(struct kvm_s390_irq) * \
-                                     (max_cpus + NR_LOCAL_IRQS))
-/*
- * KVM does only support memory slots up to KVM_MEM_MAX_NR_PAGES pages
- * as the dirty bitmap must be managed by bitops that take an int as
- * position indicator. This would end at an unaligned  address
- * (0x7fffff00000). As future variants might provide larger pages
- * and to make all addresses properly aligned, let us split at 4TB.
- */
-#define KVM_SLOT_MAX_BYTES (4UL * TiB)
-
-static CPUWatchpoint hw_watchpoint;
-/*
- * We don't use a list because this structure is also used to transmit the
- * hardware breakpoints to the kernel.
- */
-static struct kvm_hw_breakpoint *hw_breakpoints;
-static int nb_hw_breakpoints;
-
-const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
-    KVM_CAP_LAST_INFO
-};
-
-static int cap_sync_regs;
-static int cap_async_pf;
-static int cap_mem_op;
-static int cap_s390_irq;
-static int cap_ri;
-static int cap_hpage_1m;
-static int cap_vcpu_resets;
-static int cap_protected;
-
-static int active_cmma;
-
-static int kvm_s390_query_mem_limit(uint64_t *memory_limit)
-{
-    struct kvm_device_attr attr = {
-        .group = KVM_S390_VM_MEM_CTRL,
-        .attr = KVM_S390_VM_MEM_LIMIT_SIZE,
-        .addr = (uint64_t) memory_limit,
-    };
-
-    return kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
-}
-
-int kvm_s390_set_mem_limit(uint64_t new_limit, uint64_t *hw_limit)
-{
-    int rc;
-
-    struct kvm_device_attr attr = {
-        .group = KVM_S390_VM_MEM_CTRL,
-        .attr = KVM_S390_VM_MEM_LIMIT_SIZE,
-        .addr = (uint64_t) &new_limit,
-    };
-
-    if (!kvm_vm_check_mem_attr(kvm_state, KVM_S390_VM_MEM_LIMIT_SIZE)) {
-        return 0;
-    }
-
-    rc = kvm_s390_query_mem_limit(hw_limit);
-    if (rc) {
-        return rc;
-    } else if (*hw_limit < new_limit) {
-        return -E2BIG;
-    }
-
-    return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
-}
-
-int kvm_s390_cmma_active(void)
-{
-    return active_cmma;
-}
-
-static bool kvm_s390_cmma_available(void)
-{
-    static bool initialized, value;
-
-    if (!initialized) {
-        initialized = true;
-        value = kvm_vm_check_mem_attr(kvm_state, KVM_S390_VM_MEM_ENABLE_CMMA) &&
-                kvm_vm_check_mem_attr(kvm_state, KVM_S390_VM_MEM_CLR_CMMA);
-    }
-    return value;
-}
-
-void kvm_s390_cmma_reset(void)
-{
-    int rc;
-    struct kvm_device_attr attr = {
-        .group = KVM_S390_VM_MEM_CTRL,
-        .attr = KVM_S390_VM_MEM_CLR_CMMA,
-    };
-
-    if (!kvm_s390_cmma_active()) {
-        return;
-    }
-
-    rc = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
-    trace_kvm_clear_cmma(rc);
-}
-
-static void kvm_s390_enable_cmma(void)
-{
-    int rc;
-    struct kvm_device_attr attr = {
-        .group = KVM_S390_VM_MEM_CTRL,
-        .attr = KVM_S390_VM_MEM_ENABLE_CMMA,
-    };
-
-    if (cap_hpage_1m) {
-        warn_report("CMM will not be enabled because it is not "
-                    "compatible with huge memory backings.");
-        return;
-    }
-    rc = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
-    active_cmma = !rc;
-    trace_kvm_enable_cmma(rc);
-}
-
-static void kvm_s390_set_attr(uint64_t attr)
-{
-    struct kvm_device_attr attribute = {
-        .group = KVM_S390_VM_CRYPTO,
-        .attr  = attr,
-    };
-
-    int ret = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attribute);
-
-    if (ret) {
-        error_report("Failed to set crypto device attribute %lu: %s",
-                     attr, strerror(-ret));
-    }
-}
-
-static void kvm_s390_init_aes_kw(void)
-{
-    uint64_t attr = KVM_S390_VM_CRYPTO_DISABLE_AES_KW;
-
-    if (object_property_get_bool(OBJECT(qdev_get_machine()), "aes-key-wrap",
-                                 NULL)) {
-            attr = KVM_S390_VM_CRYPTO_ENABLE_AES_KW;
-    }
-
-    if (kvm_vm_check_attr(kvm_state, KVM_S390_VM_CRYPTO, attr)) {
-            kvm_s390_set_attr(attr);
-    }
-}
-
-static void kvm_s390_init_dea_kw(void)
-{
-    uint64_t attr = KVM_S390_VM_CRYPTO_DISABLE_DEA_KW;
-
-    if (object_property_get_bool(OBJECT(qdev_get_machine()), "dea-key-wrap",
-                                 NULL)) {
-            attr = KVM_S390_VM_CRYPTO_ENABLE_DEA_KW;
-    }
-
-    if (kvm_vm_check_attr(kvm_state, KVM_S390_VM_CRYPTO, attr)) {
-            kvm_s390_set_attr(attr);
-    }
-}
-
-void kvm_s390_crypto_reset(void)
-{
-    if (s390_has_feat(S390_FEAT_MSA_EXT_3)) {
-        kvm_s390_init_aes_kw();
-        kvm_s390_init_dea_kw();
-    }
-}
-
-void kvm_s390_set_max_pagesize(uint64_t pagesize, Error **errp)
-{
-    if (pagesize == 4 * KiB) {
-        return;
-    }
-
-    if (!hpage_1m_allowed()) {
-        error_setg(errp, "This QEMU machine does not support huge page "
-                   "mappings");
-        return;
-    }
-
-    if (pagesize != 1 * MiB) {
-        error_setg(errp, "Memory backing with 2G pages was specified, "
-                   "but KVM does not support this memory backing");
-        return;
-    }
-
-    if (kvm_vm_enable_cap(kvm_state, KVM_CAP_S390_HPAGE_1M, 0)) {
-        error_setg(errp, "Memory backing with 1M pages was specified, "
-                   "but KVM does not support this memory backing");
-        return;
-    }
-
-    cap_hpage_1m = 1;
-}
-
-int kvm_s390_get_hpage_1m(void)
-{
-    return cap_hpage_1m;
-}
-
-static void ccw_machine_class_foreach(ObjectClass *oc, void *opaque)
-{
-    MachineClass *mc = MACHINE_CLASS(oc);
-
-    mc->default_cpu_type = S390_CPU_TYPE_NAME("host");
-}
-
-int kvm_arch_init(MachineState *ms, KVMState *s)
-{
-    object_class_foreach(ccw_machine_class_foreach, TYPE_S390_CCW_MACHINE,
-                         false, NULL);
-
-    if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
-        error_report("KVM is missing capability KVM_CAP_DEVICE_CTRL - "
-                     "please use kernel 3.15 or newer");
-        return -1;
-    }
-    if (!kvm_check_extension(s, KVM_CAP_S390_COW)) {
-        error_report("KVM is missing capability KVM_CAP_S390_COW - "
-                     "unsupported environment");
-        return -1;
-    }
-
-    cap_sync_regs = kvm_check_extension(s, KVM_CAP_SYNC_REGS);
-    cap_async_pf = kvm_check_extension(s, KVM_CAP_ASYNC_PF);
-    cap_mem_op = kvm_check_extension(s, KVM_CAP_S390_MEM_OP);
-    cap_s390_irq = kvm_check_extension(s, KVM_CAP_S390_INJECT_IRQ);
-    cap_vcpu_resets = kvm_check_extension(s, KVM_CAP_S390_VCPU_RESETS);
-    cap_protected = kvm_check_extension(s, KVM_CAP_S390_PROTECTED);
-
-    kvm_vm_enable_cap(s, KVM_CAP_S390_USER_SIGP, 0);
-    kvm_vm_enable_cap(s, KVM_CAP_S390_VECTOR_REGISTERS, 0);
-    kvm_vm_enable_cap(s, KVM_CAP_S390_USER_STSI, 0);
-    if (ri_allowed()) {
-        if (kvm_vm_enable_cap(s, KVM_CAP_S390_RI, 0) == 0) {
-            cap_ri = 1;
-        }
-    }
-    if (cpu_model_allowed()) {
-        kvm_vm_enable_cap(s, KVM_CAP_S390_GS, 0);
-    }
-
-    /*
-     * The migration interface for ais was introduced with kernel 4.13
-     * but the capability itself had been active since 4.12. As migration
-     * support is considered necessary, we only try to enable this for
-     * newer machine types if KVM_CAP_S390_AIS_MIGRATION is available.
-     */
-    if (cpu_model_allowed() && kvm_kernel_irqchip_allowed() &&
-        kvm_check_extension(s, KVM_CAP_S390_AIS_MIGRATION)) {
-        kvm_vm_enable_cap(s, KVM_CAP_S390_AIS, 0);
-    }
-
-    kvm_set_max_memslot_size(KVM_SLOT_MAX_BYTES);
-    return 0;
-}
-
-int kvm_arch_irqchip_create(KVMState *s)
-{
-    return 0;
-}
-
-unsigned long kvm_arch_vcpu_id(CPUState *cpu)
-{
-    return cpu->cpu_index;
-}
-
-int kvm_arch_init_vcpu(CPUState *cs)
-{
-    unsigned int max_cpus = MACHINE(qdev_get_machine())->smp.max_cpus;
-    S390CPU *cpu = S390_CPU(cs);
-    kvm_s390_set_cpu_state(cpu, cpu->env.cpu_state);
-    cpu->irqstate = g_malloc0(VCPU_IRQ_BUF_SIZE(max_cpus));
-    return 0;
-}
-
-int kvm_arch_destroy_vcpu(CPUState *cs)
-{
-    S390CPU *cpu = S390_CPU(cs);
-
-    g_free(cpu->irqstate);
-    cpu->irqstate = NULL;
-
-    return 0;
-}
-
-static void kvm_s390_reset_vcpu(S390CPU *cpu, unsigned long type)
-{
-    CPUState *cs = CPU(cpu);
-
-    /*
-     * The reset call is needed here to reset in-kernel vcpu data that
-     * we can't access directly from QEMU (i.e. with older kernels
-     * which don't support sync_regs/ONE_REG).  Before this ioctl
-     * cpu_synchronize_state() is called in common kvm code
-     * (kvm-all).
-     */
-    if (kvm_vcpu_ioctl(cs, type)) {
-        error_report("CPU reset failed on CPU %i type %lx",
-                     cs->cpu_index, type);
-    }
-}
-
-void kvm_s390_reset_vcpu_initial(S390CPU *cpu)
-{
-    kvm_s390_reset_vcpu(cpu, KVM_S390_INITIAL_RESET);
-}
-
-void kvm_s390_reset_vcpu_clear(S390CPU *cpu)
-{
-    if (cap_vcpu_resets) {
-        kvm_s390_reset_vcpu(cpu, KVM_S390_CLEAR_RESET);
-    } else {
-        kvm_s390_reset_vcpu(cpu, KVM_S390_INITIAL_RESET);
-    }
-}
-
-void kvm_s390_reset_vcpu_normal(S390CPU *cpu)
-{
-    if (cap_vcpu_resets) {
-        kvm_s390_reset_vcpu(cpu, KVM_S390_NORMAL_RESET);
-    }
-}
-
-static int can_sync_regs(CPUState *cs, int regs)
-{
-    return cap_sync_regs && (cs->kvm_run->kvm_valid_regs & regs) == regs;
-}
-
-int kvm_arch_put_registers(CPUState *cs, int level)
-{
-    S390CPU *cpu = S390_CPU(cs);
-    CPUS390XState *env = &cpu->env;
-    struct kvm_sregs sregs;
-    struct kvm_regs regs;
-    struct kvm_fpu fpu = {};
-    int r;
-    int i;
-
-    /* always save the PSW  and the GPRS*/
-    cs->kvm_run->psw_addr = env->psw.addr;
-    cs->kvm_run->psw_mask = env->psw.mask;
-
-    if (can_sync_regs(cs, KVM_SYNC_GPRS)) {
-        for (i = 0; i < 16; i++) {
-            cs->kvm_run->s.regs.gprs[i] = env->regs[i];
-            cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_GPRS;
-        }
-    } else {
-        for (i = 0; i < 16; i++) {
-            regs.gprs[i] = env->regs[i];
-        }
-        r = kvm_vcpu_ioctl(cs, KVM_SET_REGS, &regs);
-        if (r < 0) {
-            return r;
-        }
-    }
-
-    if (can_sync_regs(cs, KVM_SYNC_VRS)) {
-        for (i = 0; i < 32; i++) {
-            cs->kvm_run->s.regs.vrs[i][0] = env->vregs[i][0];
-            cs->kvm_run->s.regs.vrs[i][1] = env->vregs[i][1];
-        }
-        cs->kvm_run->s.regs.fpc = env->fpc;
-        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_VRS;
-    } else if (can_sync_regs(cs, KVM_SYNC_FPRS)) {
-        for (i = 0; i < 16; i++) {
-            cs->kvm_run->s.regs.fprs[i] = *get_freg(env, i);
-        }
-        cs->kvm_run->s.regs.fpc = env->fpc;
-        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_FPRS;
-    } else {
-        /* Floating point */
-        for (i = 0; i < 16; i++) {
-            fpu.fprs[i] = *get_freg(env, i);
-        }
-        fpu.fpc = env->fpc;
-
-        r = kvm_vcpu_ioctl(cs, KVM_SET_FPU, &fpu);
-        if (r < 0) {
-            return r;
-        }
-    }
-
-    /* Do we need to save more than that? */
-    if (level == KVM_PUT_RUNTIME_STATE) {
-        return 0;
-    }
-
-    if (can_sync_regs(cs, KVM_SYNC_ARCH0)) {
-        cs->kvm_run->s.regs.cputm = env->cputm;
-        cs->kvm_run->s.regs.ckc = env->ckc;
-        cs->kvm_run->s.regs.todpr = env->todpr;
-        cs->kvm_run->s.regs.gbea = env->gbea;
-        cs->kvm_run->s.regs.pp = env->pp;
-        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_ARCH0;
-    } else {
-        /*
-         * These ONE_REGS are not protected by a capability. As they are only
-         * necessary for migration we just trace a possible error, but don't
-         * return with an error return code.
-         */
-        kvm_set_one_reg(cs, KVM_REG_S390_CPU_TIMER, &env->cputm);
-        kvm_set_one_reg(cs, KVM_REG_S390_CLOCK_COMP, &env->ckc);
-        kvm_set_one_reg(cs, KVM_REG_S390_TODPR, &env->todpr);
-        kvm_set_one_reg(cs, KVM_REG_S390_GBEA, &env->gbea);
-        kvm_set_one_reg(cs, KVM_REG_S390_PP, &env->pp);
-    }
-
-    if (can_sync_regs(cs, KVM_SYNC_RICCB)) {
-        memcpy(cs->kvm_run->s.regs.riccb, env->riccb, 64);
-        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_RICCB;
-    }
-
-    /* pfault parameters */
-    if (can_sync_regs(cs, KVM_SYNC_PFAULT)) {
-        cs->kvm_run->s.regs.pft = env->pfault_token;
-        cs->kvm_run->s.regs.pfs = env->pfault_select;
-        cs->kvm_run->s.regs.pfc = env->pfault_compare;
-        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_PFAULT;
-    } else if (cap_async_pf) {
-        r = kvm_set_one_reg(cs, KVM_REG_S390_PFTOKEN, &env->pfault_token);
-        if (r < 0) {
-            return r;
-        }
-        r = kvm_set_one_reg(cs, KVM_REG_S390_PFCOMPARE, &env->pfault_compare);
-        if (r < 0) {
-            return r;
-        }
-        r = kvm_set_one_reg(cs, KVM_REG_S390_PFSELECT, &env->pfault_select);
-        if (r < 0) {
-            return r;
-        }
-    }
-
-    /* access registers and control registers*/
-    if (can_sync_regs(cs, KVM_SYNC_ACRS | KVM_SYNC_CRS)) {
-        for (i = 0; i < 16; i++) {
-            cs->kvm_run->s.regs.acrs[i] = env->aregs[i];
-            cs->kvm_run->s.regs.crs[i] = env->cregs[i];
-        }
-        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_ACRS;
-        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_CRS;
-    } else {
-        for (i = 0; i < 16; i++) {
-            sregs.acrs[i] = env->aregs[i];
-            sregs.crs[i] = env->cregs[i];
-        }
-        r = kvm_vcpu_ioctl(cs, KVM_SET_SREGS, &sregs);
-        if (r < 0) {
-            return r;
-        }
-    }
-
-    if (can_sync_regs(cs, KVM_SYNC_GSCB)) {
-        memcpy(cs->kvm_run->s.regs.gscb, env->gscb, 32);
-        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_GSCB;
-    }
-
-    if (can_sync_regs(cs, KVM_SYNC_BPBC)) {
-        cs->kvm_run->s.regs.bpbc = env->bpbc;
-        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_BPBC;
-    }
-
-    if (can_sync_regs(cs, KVM_SYNC_ETOKEN)) {
-        cs->kvm_run->s.regs.etoken = env->etoken;
-        cs->kvm_run->s.regs.etoken_extension  = env->etoken_extension;
-        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_ETOKEN;
-    }
-
-    if (can_sync_regs(cs, KVM_SYNC_DIAG318)) {
-        cs->kvm_run->s.regs.diag318 = env->diag318_info;
-        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_DIAG318;
-    }
-
-    /* Finally the prefix */
-    if (can_sync_regs(cs, KVM_SYNC_PREFIX)) {
-        cs->kvm_run->s.regs.prefix = env->psa;
-        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_PREFIX;
-    } else {
-        /* prefix is only supported via sync regs */
-    }
-    return 0;
-}
-
-int kvm_arch_get_registers(CPUState *cs)
-{
-    S390CPU *cpu = S390_CPU(cs);
-    CPUS390XState *env = &cpu->env;
-    struct kvm_sregs sregs;
-    struct kvm_regs regs;
-    struct kvm_fpu fpu;
-    int i, r;
-
-    /* get the PSW */
-    env->psw.addr = cs->kvm_run->psw_addr;
-    env->psw.mask = cs->kvm_run->psw_mask;
-
-    /* the GPRS */
-    if (can_sync_regs(cs, KVM_SYNC_GPRS)) {
-        for (i = 0; i < 16; i++) {
-            env->regs[i] = cs->kvm_run->s.regs.gprs[i];
-        }
-    } else {
-        r = kvm_vcpu_ioctl(cs, KVM_GET_REGS, &regs);
-        if (r < 0) {
-            return r;
-        }
-         for (i = 0; i < 16; i++) {
-            env->regs[i] = regs.gprs[i];
-        }
-    }
-
-    /* The ACRS and CRS */
-    if (can_sync_regs(cs, KVM_SYNC_ACRS | KVM_SYNC_CRS)) {
-        for (i = 0; i < 16; i++) {
-            env->aregs[i] = cs->kvm_run->s.regs.acrs[i];
-            env->cregs[i] = cs->kvm_run->s.regs.crs[i];
-        }
-    } else {
-        r = kvm_vcpu_ioctl(cs, KVM_GET_SREGS, &sregs);
-        if (r < 0) {
-            return r;
-        }
-         for (i = 0; i < 16; i++) {
-            env->aregs[i] = sregs.acrs[i];
-            env->cregs[i] = sregs.crs[i];
-        }
-    }
-
-    /* Floating point and vector registers */
-    if (can_sync_regs(cs, KVM_SYNC_VRS)) {
-        for (i = 0; i < 32; i++) {
-            env->vregs[i][0] = cs->kvm_run->s.regs.vrs[i][0];
-            env->vregs[i][1] = cs->kvm_run->s.regs.vrs[i][1];
-        }
-        env->fpc = cs->kvm_run->s.regs.fpc;
-    } else if (can_sync_regs(cs, KVM_SYNC_FPRS)) {
-        for (i = 0; i < 16; i++) {
-            *get_freg(env, i) = cs->kvm_run->s.regs.fprs[i];
-        }
-        env->fpc = cs->kvm_run->s.regs.fpc;
-    } else {
-        r = kvm_vcpu_ioctl(cs, KVM_GET_FPU, &fpu);
-        if (r < 0) {
-            return r;
-        }
-        for (i = 0; i < 16; i++) {
-            *get_freg(env, i) = fpu.fprs[i];
-        }
-        env->fpc = fpu.fpc;
-    }
-
-    /* The prefix */
-    if (can_sync_regs(cs, KVM_SYNC_PREFIX)) {
-        env->psa = cs->kvm_run->s.regs.prefix;
-    }
-
-    if (can_sync_regs(cs, KVM_SYNC_ARCH0)) {
-        env->cputm = cs->kvm_run->s.regs.cputm;
-        env->ckc = cs->kvm_run->s.regs.ckc;
-        env->todpr = cs->kvm_run->s.regs.todpr;
-        env->gbea = cs->kvm_run->s.regs.gbea;
-        env->pp = cs->kvm_run->s.regs.pp;
-    } else {
-        /*
-         * These ONE_REGS are not protected by a capability. As they are only
-         * necessary for migration we just trace a possible error, but don't
-         * return with an error return code.
-         */
-        kvm_get_one_reg(cs, KVM_REG_S390_CPU_TIMER, &env->cputm);
-        kvm_get_one_reg(cs, KVM_REG_S390_CLOCK_COMP, &env->ckc);
-        kvm_get_one_reg(cs, KVM_REG_S390_TODPR, &env->todpr);
-        kvm_get_one_reg(cs, KVM_REG_S390_GBEA, &env->gbea);
-        kvm_get_one_reg(cs, KVM_REG_S390_PP, &env->pp);
-    }
-
-    if (can_sync_regs(cs, KVM_SYNC_RICCB)) {
-        memcpy(env->riccb, cs->kvm_run->s.regs.riccb, 64);
-    }
-
-    if (can_sync_regs(cs, KVM_SYNC_GSCB)) {
-        memcpy(env->gscb, cs->kvm_run->s.regs.gscb, 32);
-    }
-
-    if (can_sync_regs(cs, KVM_SYNC_BPBC)) {
-        env->bpbc = cs->kvm_run->s.regs.bpbc;
-    }
-
-    if (can_sync_regs(cs, KVM_SYNC_ETOKEN)) {
-        env->etoken = cs->kvm_run->s.regs.etoken;
-        env->etoken_extension = cs->kvm_run->s.regs.etoken_extension;
-    }
-
-    /* pfault parameters */
-    if (can_sync_regs(cs, KVM_SYNC_PFAULT)) {
-        env->pfault_token = cs->kvm_run->s.regs.pft;
-        env->pfault_select = cs->kvm_run->s.regs.pfs;
-        env->pfault_compare = cs->kvm_run->s.regs.pfc;
-    } else if (cap_async_pf) {
-        r = kvm_get_one_reg(cs, KVM_REG_S390_PFTOKEN, &env->pfault_token);
-        if (r < 0) {
-            return r;
-        }
-        r = kvm_get_one_reg(cs, KVM_REG_S390_PFCOMPARE, &env->pfault_compare);
-        if (r < 0) {
-            return r;
-        }
-        r = kvm_get_one_reg(cs, KVM_REG_S390_PFSELECT, &env->pfault_select);
-        if (r < 0) {
-            return r;
-        }
-    }
-
-    if (can_sync_regs(cs, KVM_SYNC_DIAG318)) {
-        env->diag318_info = cs->kvm_run->s.regs.diag318;
-    }
-
-    return 0;
-}
-
-int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_low)
-{
-    int r;
-    struct kvm_device_attr attr = {
-        .group = KVM_S390_VM_TOD,
-        .attr = KVM_S390_VM_TOD_LOW,
-        .addr = (uint64_t)tod_low,
-    };
-
-    r = kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
-    if (r) {
-        return r;
-    }
-
-    attr.attr = KVM_S390_VM_TOD_HIGH;
-    attr.addr = (uint64_t)tod_high;
-    return kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
-}
-
-int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_low)
-{
-    int r;
-    struct kvm_s390_vm_tod_clock gtod;
-    struct kvm_device_attr attr = {
-        .group = KVM_S390_VM_TOD,
-        .attr = KVM_S390_VM_TOD_EXT,
-        .addr = (uint64_t)&gtod,
-    };
-
-    r = kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
-    *tod_high = gtod.epoch_idx;
-    *tod_low  = gtod.tod;
-
-    return r;
-}
-
-int kvm_s390_set_clock(uint8_t tod_high, uint64_t tod_low)
-{
-    int r;
-    struct kvm_device_attr attr = {
-        .group = KVM_S390_VM_TOD,
-        .attr = KVM_S390_VM_TOD_LOW,
-        .addr = (uint64_t)&tod_low,
-    };
-
-    r = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
-    if (r) {
-        return r;
-    }
-
-    attr.attr = KVM_S390_VM_TOD_HIGH;
-    attr.addr = (uint64_t)&tod_high;
-    return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
-}
-
-int kvm_s390_set_clock_ext(uint8_t tod_high, uint64_t tod_low)
-{
-    struct kvm_s390_vm_tod_clock gtod = {
-        .epoch_idx = tod_high,
-        .tod  = tod_low,
-    };
-    struct kvm_device_attr attr = {
-        .group = KVM_S390_VM_TOD,
-        .attr = KVM_S390_VM_TOD_EXT,
-        .addr = (uint64_t)&gtod,
-    };
-
-    return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
-}
-
-/**
- * kvm_s390_mem_op:
- * @addr:      the logical start address in guest memory
- * @ar:        the access register number
- * @hostbuf:   buffer in host memory. NULL = do only checks w/o copying
- * @len:       length that should be transferred
- * @is_write:  true = write, false = read
- * Returns:    0 on success, non-zero if an exception or error occurred
- *
- * Use KVM ioctl to read/write from/to guest memory. An access exception
- * is injected into the vCPU in case of translation errors.
- */
-int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf,
-                    int len, bool is_write)
-{
-    struct kvm_s390_mem_op mem_op = {
-        .gaddr = addr,
-        .flags = KVM_S390_MEMOP_F_INJECT_EXCEPTION,
-        .size = len,
-        .op = is_write ? KVM_S390_MEMOP_LOGICAL_WRITE
-                       : KVM_S390_MEMOP_LOGICAL_READ,
-        .buf = (uint64_t)hostbuf,
-        .ar = ar,
-    };
-    int ret;
-
-    if (!cap_mem_op) {
-        return -ENOSYS;
-    }
-    if (!hostbuf) {
-        mem_op.flags |= KVM_S390_MEMOP_F_CHECK_ONLY;
-    }
-
-    ret = kvm_vcpu_ioctl(CPU(cpu), KVM_S390_MEM_OP, &mem_op);
-    if (ret < 0) {
-        warn_report("KVM_S390_MEM_OP failed: %s", strerror(-ret));
-    }
-    return ret;
-}
-
-int kvm_s390_mem_op_pv(S390CPU *cpu, uint64_t offset, void *hostbuf,
-                       int len, bool is_write)
-{
-    struct kvm_s390_mem_op mem_op = {
-        .sida_offset = offset,
-        .size = len,
-        .op = is_write ? KVM_S390_MEMOP_SIDA_WRITE
-                       : KVM_S390_MEMOP_SIDA_READ,
-        .buf = (uint64_t)hostbuf,
-    };
-    int ret;
-
-    if (!cap_mem_op || !cap_protected) {
-        return -ENOSYS;
-    }
-
-    ret = kvm_vcpu_ioctl(CPU(cpu), KVM_S390_MEM_OP, &mem_op);
-    if (ret < 0) {
-        error_report("KVM_S390_MEM_OP failed: %s", strerror(-ret));
-        abort();
-    }
-    return ret;
-}
-
-static uint8_t const *sw_bp_inst;
-static uint8_t sw_bp_ilen;
-
-static void determine_sw_breakpoint_instr(void)
-{
-        /* DIAG 501 is used for sw breakpoints with old kernels */
-        static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
-        /* Instruction 0x0000 is used for sw breakpoints with recent kernels */
-        static const uint8_t instr_0x0000[] = {0x00, 0x00};
-
-        if (sw_bp_inst) {
-            return;
-        }
-        if (kvm_vm_enable_cap(kvm_state, KVM_CAP_S390_USER_INSTR0, 0)) {
-            sw_bp_inst = diag_501;
-            sw_bp_ilen = sizeof(diag_501);
-            DPRINTF("KVM: will use 4-byte sw breakpoints.\n");
-        } else {
-            sw_bp_inst = instr_0x0000;
-            sw_bp_ilen = sizeof(instr_0x0000);
-            DPRINTF("KVM: will use 2-byte sw breakpoints.\n");
-        }
-}
-
-int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
-{
-    determine_sw_breakpoint_instr();
-
-    if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn,
-                            sw_bp_ilen, 0) ||
-        cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)sw_bp_inst, sw_bp_ilen, 1)) {
-        return -EINVAL;
-    }
-    return 0;
-}
-
-int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
-{
-    uint8_t t[MAX_ILEN];
-
-    if (cpu_memory_rw_debug(cs, bp->pc, t, sw_bp_ilen, 0)) {
-        return -EINVAL;
-    } else if (memcmp(t, sw_bp_inst, sw_bp_ilen)) {
-        return -EINVAL;
-    } else if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn,
-                                   sw_bp_ilen, 1)) {
-        return -EINVAL;
-    }
-
-    return 0;
-}
-
-static struct kvm_hw_breakpoint *find_hw_breakpoint(target_ulong addr,
-                                                    int len, int type)
-{
-    int n;
-
-    for (n = 0; n < nb_hw_breakpoints; n++) {
-        if (hw_breakpoints[n].addr == addr && hw_breakpoints[n].type == type &&
-            (hw_breakpoints[n].len == len || len == -1)) {
-            return &hw_breakpoints[n];
-        }
-    }
-
-    return NULL;
-}
-
-static int insert_hw_breakpoint(target_ulong addr, int len, int type)
-{
-    int size;
-
-    if (find_hw_breakpoint(addr, len, type)) {
-        return -EEXIST;
-    }
-
-    size = (nb_hw_breakpoints + 1) * sizeof(struct kvm_hw_breakpoint);
-
-    if (!hw_breakpoints) {
-        nb_hw_breakpoints = 0;
-        hw_breakpoints = (struct kvm_hw_breakpoint *)g_try_malloc(size);
-    } else {
-        hw_breakpoints =
-            (struct kvm_hw_breakpoint *)g_try_realloc(hw_breakpoints, size);
-    }
-
-    if (!hw_breakpoints) {
-        nb_hw_breakpoints = 0;
-        return -ENOMEM;
-    }
-
-    hw_breakpoints[nb_hw_breakpoints].addr = addr;
-    hw_breakpoints[nb_hw_breakpoints].len = len;
-    hw_breakpoints[nb_hw_breakpoints].type = type;
-
-    nb_hw_breakpoints++;
-
-    return 0;
-}
-
-int kvm_arch_insert_hw_breakpoint(target_ulong addr,
-                                  target_ulong len, int type)
-{
-    switch (type) {
-    case GDB_BREAKPOINT_HW:
-        type = KVM_HW_BP;
-        break;
-    case GDB_WATCHPOINT_WRITE:
-        if (len < 1) {
-            return -EINVAL;
-        }
-        type = KVM_HW_WP_WRITE;
-        break;
-    default:
-        return -ENOSYS;
-    }
-    return insert_hw_breakpoint(addr, len, type);
-}
-
-int kvm_arch_remove_hw_breakpoint(target_ulong addr,
-                                  target_ulong len, int type)
-{
-    int size;
-    struct kvm_hw_breakpoint *bp = find_hw_breakpoint(addr, len, type);
-
-    if (bp == NULL) {
-        return -ENOENT;
-    }
-
-    nb_hw_breakpoints--;
-    if (nb_hw_breakpoints > 0) {
-        /*
-         * In order to trim the array, move the last element to the position to
-         * be removed - if necessary.
-         */
-        if (bp != &hw_breakpoints[nb_hw_breakpoints]) {
-            *bp = hw_breakpoints[nb_hw_breakpoints];
-        }
-        size = nb_hw_breakpoints * sizeof(struct kvm_hw_breakpoint);
-        hw_breakpoints =
-             (struct kvm_hw_breakpoint *)g_realloc(hw_breakpoints, size);
-    } else {
-        g_free(hw_breakpoints);
-        hw_breakpoints = NULL;
-    }
-
-    return 0;
-}
-
-void kvm_arch_remove_all_hw_breakpoints(void)
-{
-    nb_hw_breakpoints = 0;
-    g_free(hw_breakpoints);
-    hw_breakpoints = NULL;
-}
-
-void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
-{
-    int i;
-
-    if (nb_hw_breakpoints > 0) {
-        dbg->arch.nr_hw_bp = nb_hw_breakpoints;
-        dbg->arch.hw_bp = hw_breakpoints;
-
-        for (i = 0; i < nb_hw_breakpoints; ++i) {
-            hw_breakpoints[i].phys_addr = s390_cpu_get_phys_addr_debug(cpu,
-                                                       hw_breakpoints[i].addr);
-        }
-        dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP;
-    } else {
-        dbg->arch.nr_hw_bp = 0;
-        dbg->arch.hw_bp = NULL;
-    }
-}
-
-void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run)
-{
-}
-
-MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
-{
-    return MEMTXATTRS_UNSPECIFIED;
-}
-
-int kvm_arch_process_async_events(CPUState *cs)
-{
-    return cs->halted;
-}
-
-static int s390_kvm_irq_to_interrupt(struct kvm_s390_irq *irq,
-                                     struct kvm_s390_interrupt *interrupt)
-{
-    int r = 0;
-
-    interrupt->type = irq->type;
-    switch (irq->type) {
-    case KVM_S390_INT_VIRTIO:
-        interrupt->parm = irq->u.ext.ext_params;
-        /* fall through */
-    case KVM_S390_INT_PFAULT_INIT:
-    case KVM_S390_INT_PFAULT_DONE:
-        interrupt->parm64 = irq->u.ext.ext_params2;
-        break;
-    case KVM_S390_PROGRAM_INT:
-        interrupt->parm = irq->u.pgm.code;
-        break;
-    case KVM_S390_SIGP_SET_PREFIX:
-        interrupt->parm = irq->u.prefix.address;
-        break;
-    case KVM_S390_INT_SERVICE:
-        interrupt->parm = irq->u.ext.ext_params;
-        break;
-    case KVM_S390_MCHK:
-        interrupt->parm = irq->u.mchk.cr14;
-        interrupt->parm64 = irq->u.mchk.mcic;
-        break;
-    case KVM_S390_INT_EXTERNAL_CALL:
-        interrupt->parm = irq->u.extcall.code;
-        break;
-    case KVM_S390_INT_EMERGENCY:
-        interrupt->parm = irq->u.emerg.code;
-        break;
-    case KVM_S390_SIGP_STOP:
-    case KVM_S390_RESTART:
-        break; /* These types have no parameters */
-    case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
-        interrupt->parm = irq->u.io.subchannel_id << 16;
-        interrupt->parm |= irq->u.io.subchannel_nr;
-        interrupt->parm64 = (uint64_t)irq->u.io.io_int_parm << 32;
-        interrupt->parm64 |= irq->u.io.io_int_word;
-        break;
-    default:
-        r = -EINVAL;
-        break;
-    }
-    return r;
-}
-
-static void inject_vcpu_irq_legacy(CPUState *cs, struct kvm_s390_irq *irq)
-{
-    struct kvm_s390_interrupt kvmint = {};
-    int r;
-
-    r = s390_kvm_irq_to_interrupt(irq, &kvmint);
-    if (r < 0) {
-        fprintf(stderr, "%s called with bogus interrupt\n", __func__);
-        exit(1);
-    }
-
-    r = kvm_vcpu_ioctl(cs, KVM_S390_INTERRUPT, &kvmint);
-    if (r < 0) {
-        fprintf(stderr, "KVM failed to inject interrupt\n");
-        exit(1);
-    }
-}
-
-void kvm_s390_vcpu_interrupt(S390CPU *cpu, struct kvm_s390_irq *irq)
-{
-    CPUState *cs = CPU(cpu);
-    int r;
-
-    if (cap_s390_irq) {
-        r = kvm_vcpu_ioctl(cs, KVM_S390_IRQ, irq);
-        if (!r) {
-            return;
-        }
-        error_report("KVM failed to inject interrupt %llx", irq->type);
-        exit(1);
-    }
-
-    inject_vcpu_irq_legacy(cs, irq);
-}
-
-void kvm_s390_floating_interrupt_legacy(struct kvm_s390_irq *irq)
-{
-    struct kvm_s390_interrupt kvmint = {};
-    int r;
-
-    r = s390_kvm_irq_to_interrupt(irq, &kvmint);
-    if (r < 0) {
-        fprintf(stderr, "%s called with bogus interrupt\n", __func__);
-        exit(1);
-    }
-
-    r = kvm_vm_ioctl(kvm_state, KVM_S390_INTERRUPT, &kvmint);
-    if (r < 0) {
-        fprintf(stderr, "KVM failed to inject interrupt\n");
-        exit(1);
-    }
-}
-
-void kvm_s390_program_interrupt(S390CPU *cpu, uint16_t code)
-{
-    struct kvm_s390_irq irq = {
-        .type = KVM_S390_PROGRAM_INT,
-        .u.pgm.code = code,
-    };
-    qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
-                  cpu->env.psw.addr);
-    kvm_s390_vcpu_interrupt(cpu, &irq);
-}
-
-void kvm_s390_access_exception(S390CPU *cpu, uint16_t code, uint64_t te_code)
-{
-    struct kvm_s390_irq irq = {
-        .type = KVM_S390_PROGRAM_INT,
-        .u.pgm.code = code,
-        .u.pgm.trans_exc_code = te_code,
-        .u.pgm.exc_access_id = te_code & 3,
-    };
-
-    kvm_s390_vcpu_interrupt(cpu, &irq);
-}
-
-static void kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run,
-                                 uint16_t ipbh0)
-{
-    CPUS390XState *env = &cpu->env;
-    uint64_t sccb;
-    uint32_t code;
-    int r;
-
-    sccb = env->regs[ipbh0 & 0xf];
-    code = env->regs[(ipbh0 & 0xf0) >> 4];
-
-    switch (run->s390_sieic.icptcode) {
-    case ICPT_PV_INSTR_NOTIFICATION:
-        g_assert(s390_is_pv());
-        /* The notification intercepts are currently handled by KVM */
-        error_report("unexpected SCLP PV notification");
-        exit(1);
-        break;
-    case ICPT_PV_INSTR:
-        g_assert(s390_is_pv());
-        sclp_service_call_protected(env, sccb, code);
-        /* Setting the CC is done by the Ultravisor. */
-        break;
-    case ICPT_INSTRUCTION:
-        g_assert(!s390_is_pv());
-        r = sclp_service_call(env, sccb, code);
-        if (r < 0) {
-            kvm_s390_program_interrupt(cpu, -r);
-            return;
-        }
-        setcc(cpu, r);
-    }
-}
-
-static int handle_b2(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
-{
-    CPUS390XState *env = &cpu->env;
-    int rc = 0;
-    uint16_t ipbh0 = (run->s390_sieic.ipb & 0xffff0000) >> 16;
-
-    switch (ipa1) {
-    case PRIV_B2_XSCH:
-        ioinst_handle_xsch(cpu, env->regs[1], RA_IGNORED);
-        break;
-    case PRIV_B2_CSCH:
-        ioinst_handle_csch(cpu, env->regs[1], RA_IGNORED);
-        break;
-    case PRIV_B2_HSCH:
-        ioinst_handle_hsch(cpu, env->regs[1], RA_IGNORED);
-        break;
-    case PRIV_B2_MSCH:
-        ioinst_handle_msch(cpu, env->regs[1], run->s390_sieic.ipb, RA_IGNORED);
-        break;
-    case PRIV_B2_SSCH:
-        ioinst_handle_ssch(cpu, env->regs[1], run->s390_sieic.ipb, RA_IGNORED);
-        break;
-    case PRIV_B2_STCRW:
-        ioinst_handle_stcrw(cpu, run->s390_sieic.ipb, RA_IGNORED);
-        break;
-    case PRIV_B2_STSCH:
-        ioinst_handle_stsch(cpu, env->regs[1], run->s390_sieic.ipb, RA_IGNORED);
-        break;
-    case PRIV_B2_TSCH:
-        /* We should only get tsch via KVM_EXIT_S390_TSCH. */
-        fprintf(stderr, "Spurious tsch intercept\n");
-        break;
-    case PRIV_B2_CHSC:
-        ioinst_handle_chsc(cpu, run->s390_sieic.ipb, RA_IGNORED);
-        break;
-    case PRIV_B2_TPI:
-        /* This should have been handled by kvm already. */
-        fprintf(stderr, "Spurious tpi intercept\n");
-        break;
-    case PRIV_B2_SCHM:
-        ioinst_handle_schm(cpu, env->regs[1], env->regs[2],
-                           run->s390_sieic.ipb, RA_IGNORED);
-        break;
-    case PRIV_B2_RSCH:
-        ioinst_handle_rsch(cpu, env->regs[1], RA_IGNORED);
-        break;
-    case PRIV_B2_RCHP:
-        ioinst_handle_rchp(cpu, env->regs[1], RA_IGNORED);
-        break;
-    case PRIV_B2_STCPS:
-        /* We do not provide this instruction, it is suppressed. */
-        break;
-    case PRIV_B2_SAL:
-        ioinst_handle_sal(cpu, env->regs[1], RA_IGNORED);
-        break;
-    case PRIV_B2_SIGA:
-        /* Not provided, set CC = 3 for subchannel not operational */
-        setcc(cpu, 3);
-        break;
-    case PRIV_B2_SCLP_CALL:
-        kvm_sclp_service_call(cpu, run, ipbh0);
-        break;
-    default:
-        rc = -1;
-        DPRINTF("KVM: unhandled PRIV: 0xb2%x\n", ipa1);
-        break;
-    }
-
-    return rc;
-}
-
-static uint64_t get_base_disp_rxy(S390CPU *cpu, struct kvm_run *run,
-                                  uint8_t *ar)
-{
-    CPUS390XState *env = &cpu->env;
-    uint32_t x2 = (run->s390_sieic.ipa & 0x000f);
-    uint32_t base2 = run->s390_sieic.ipb >> 28;
-    uint32_t disp2 = ((run->s390_sieic.ipb & 0x0fff0000) >> 16) +
-                     ((run->s390_sieic.ipb & 0xff00) << 4);
-
-    if (disp2 & 0x80000) {
-        disp2 += 0xfff00000;
-    }
-    if (ar) {
-        *ar = base2;
-    }
-
-    return (base2 ? env->regs[base2] : 0) +
-           (x2 ? env->regs[x2] : 0) + (long)(int)disp2;
-}
-
-static uint64_t get_base_disp_rsy(S390CPU *cpu, struct kvm_run *run,
-                                  uint8_t *ar)
-{
-    CPUS390XState *env = &cpu->env;
-    uint32_t base2 = run->s390_sieic.ipb >> 28;
-    uint32_t disp2 = ((run->s390_sieic.ipb & 0x0fff0000) >> 16) +
-                     ((run->s390_sieic.ipb & 0xff00) << 4);
-
-    if (disp2 & 0x80000) {
-        disp2 += 0xfff00000;
-    }
-    if (ar) {
-        *ar = base2;
-    }
-
-    return (base2 ? env->regs[base2] : 0) + (long)(int)disp2;
-}
-
-static int kvm_clp_service_call(S390CPU *cpu, struct kvm_run *run)
-{
-    uint8_t r2 = (run->s390_sieic.ipb & 0x000f0000) >> 16;
-
-    if (s390_has_feat(S390_FEAT_ZPCI)) {
-        return clp_service_call(cpu, r2, RA_IGNORED);
-    } else {
-        return -1;
-    }
-}
-
-static int kvm_pcilg_service_call(S390CPU *cpu, struct kvm_run *run)
-{
-    uint8_t r1 = (run->s390_sieic.ipb & 0x00f00000) >> 20;
-    uint8_t r2 = (run->s390_sieic.ipb & 0x000f0000) >> 16;
-
-    if (s390_has_feat(S390_FEAT_ZPCI)) {
-        return pcilg_service_call(cpu, r1, r2, RA_IGNORED);
-    } else {
-        return -1;
-    }
-}
-
-static int kvm_pcistg_service_call(S390CPU *cpu, struct kvm_run *run)
-{
-    uint8_t r1 = (run->s390_sieic.ipb & 0x00f00000) >> 20;
-    uint8_t r2 = (run->s390_sieic.ipb & 0x000f0000) >> 16;
-
-    if (s390_has_feat(S390_FEAT_ZPCI)) {
-        return pcistg_service_call(cpu, r1, r2, RA_IGNORED);
-    } else {
-        return -1;
-    }
-}
-
-static int kvm_stpcifc_service_call(S390CPU *cpu, struct kvm_run *run)
-{
-    uint8_t r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
-    uint64_t fiba;
-    uint8_t ar;
-
-    if (s390_has_feat(S390_FEAT_ZPCI)) {
-        fiba = get_base_disp_rxy(cpu, run, &ar);
-
-        return stpcifc_service_call(cpu, r1, fiba, ar, RA_IGNORED);
-    } else {
-        return -1;
-    }
-}
-
-static int kvm_sic_service_call(S390CPU *cpu, struct kvm_run *run)
-{
-    CPUS390XState *env = &cpu->env;
-    uint8_t r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
-    uint8_t r3 = run->s390_sieic.ipa & 0x000f;
-    uint8_t isc;
-    uint16_t mode;
-    int r;
-
-    mode = env->regs[r1] & 0xffff;
-    isc = (env->regs[r3] >> 27) & 0x7;
-    r = css_do_sic(env, isc, mode);
-    if (r) {
-        kvm_s390_program_interrupt(cpu, -r);
-    }
-
-    return 0;
-}
-
-static int kvm_rpcit_service_call(S390CPU *cpu, struct kvm_run *run)
-{
-    uint8_t r1 = (run->s390_sieic.ipb & 0x00f00000) >> 20;
-    uint8_t r2 = (run->s390_sieic.ipb & 0x000f0000) >> 16;
-
-    if (s390_has_feat(S390_FEAT_ZPCI)) {
-        return rpcit_service_call(cpu, r1, r2, RA_IGNORED);
-    } else {
-        return -1;
-    }
-}
-
-static int kvm_pcistb_service_call(S390CPU *cpu, struct kvm_run *run)
-{
-    uint8_t r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
-    uint8_t r3 = run->s390_sieic.ipa & 0x000f;
-    uint64_t gaddr;
-    uint8_t ar;
-
-    if (s390_has_feat(S390_FEAT_ZPCI)) {
-        gaddr = get_base_disp_rsy(cpu, run, &ar);
-
-        return pcistb_service_call(cpu, r1, r3, gaddr, ar, RA_IGNORED);
-    } else {
-        return -1;
-    }
-}
-
-static int kvm_mpcifc_service_call(S390CPU *cpu, struct kvm_run *run)
-{
-    uint8_t r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
-    uint64_t fiba;
-    uint8_t ar;
-
-    if (s390_has_feat(S390_FEAT_ZPCI)) {
-        fiba = get_base_disp_rxy(cpu, run, &ar);
-
-        return mpcifc_service_call(cpu, r1, fiba, ar, RA_IGNORED);
-    } else {
-        return -1;
-    }
-}
-
-static int handle_b9(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
-{
-    int r = 0;
-
-    switch (ipa1) {
-    case PRIV_B9_CLP:
-        r = kvm_clp_service_call(cpu, run);
-        break;
-    case PRIV_B9_PCISTG:
-        r = kvm_pcistg_service_call(cpu, run);
-        break;
-    case PRIV_B9_PCILG:
-        r = kvm_pcilg_service_call(cpu, run);
-        break;
-    case PRIV_B9_RPCIT:
-        r = kvm_rpcit_service_call(cpu, run);
-        break;
-    case PRIV_B9_EQBS:
-        /* just inject exception */
-        r = -1;
-        break;
-    default:
-        r = -1;
-        DPRINTF("KVM: unhandled PRIV: 0xb9%x\n", ipa1);
-        break;
-    }
-
-    return r;
-}
-
-static int handle_eb(S390CPU *cpu, struct kvm_run *run, uint8_t ipbl)
-{
-    int r = 0;
-
-    switch (ipbl) {
-    case PRIV_EB_PCISTB:
-        r = kvm_pcistb_service_call(cpu, run);
-        break;
-    case PRIV_EB_SIC:
-        r = kvm_sic_service_call(cpu, run);
-        break;
-    case PRIV_EB_SQBS:
-        /* just inject exception */
-        r = -1;
-        break;
-    default:
-        r = -1;
-        DPRINTF("KVM: unhandled PRIV: 0xeb%x\n", ipbl);
-        break;
-    }
-
-    return r;
-}
-
-static int handle_e3(S390CPU *cpu, struct kvm_run *run, uint8_t ipbl)
-{
-    int r = 0;
-
-    switch (ipbl) {
-    case PRIV_E3_MPCIFC:
-        r = kvm_mpcifc_service_call(cpu, run);
-        break;
-    case PRIV_E3_STPCIFC:
-        r = kvm_stpcifc_service_call(cpu, run);
-        break;
-    default:
-        r = -1;
-        DPRINTF("KVM: unhandled PRIV: 0xe3%x\n", ipbl);
-        break;
-    }
-
-    return r;
-}
-
-static int handle_hypercall(S390CPU *cpu, struct kvm_run *run)
-{
-    CPUS390XState *env = &cpu->env;
-    int ret;
-
-    ret = s390_virtio_hypercall(env);
-    if (ret == -EINVAL) {
-        kvm_s390_program_interrupt(cpu, PGM_SPECIFICATION);
-        return 0;
-    }
-
-    return ret;
-}
-
-static void kvm_handle_diag_288(S390CPU *cpu, struct kvm_run *run)
-{
-    uint64_t r1, r3;
-    int rc;
-
-    r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
-    r3 = run->s390_sieic.ipa & 0x000f;
-    rc = handle_diag_288(&cpu->env, r1, r3);
-    if (rc) {
-        kvm_s390_program_interrupt(cpu, PGM_SPECIFICATION);
-    }
-}
-
-static void kvm_handle_diag_308(S390CPU *cpu, struct kvm_run *run)
-{
-    uint64_t r1, r3;
-
-    r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
-    r3 = run->s390_sieic.ipa & 0x000f;
-    handle_diag_308(&cpu->env, r1, r3, RA_IGNORED);
-}
-
-static int handle_sw_breakpoint(S390CPU *cpu, struct kvm_run *run)
-{
-    CPUS390XState *env = &cpu->env;
-    unsigned long pc;
-
-    pc = env->psw.addr - sw_bp_ilen;
-    if (kvm_find_sw_breakpoint(CPU(cpu), pc)) {
-        env->psw.addr = pc;
-        return EXCP_DEBUG;
-    }
-
-    return -ENOENT;
-}
-
-void kvm_s390_set_diag318(CPUState *cs, uint64_t diag318_info)
-{
-    CPUS390XState *env = &S390_CPU(cs)->env;
-
-    /* Feat bit is set only if KVM supports sync for diag318 */
-    if (s390_has_feat(S390_FEAT_DIAG_318)) {
-        env->diag318_info = diag318_info;
-        cs->kvm_run->s.regs.diag318 = diag318_info;
-        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_DIAG318;
-    }
-}
-
-static void handle_diag_318(S390CPU *cpu, struct kvm_run *run)
-{
-    uint64_t reg = (run->s390_sieic.ipa & 0x00f0) >> 4;
-    uint64_t diag318_info = run->s.regs.gprs[reg];
-    CPUState *t;
-
-    /*
-     * DIAG 318 can only be enabled with KVM support. As such, let's
-     * ensure a guest cannot execute this instruction erroneously.
-     */
-    if (!s390_has_feat(S390_FEAT_DIAG_318)) {
-        kvm_s390_program_interrupt(cpu, PGM_SPECIFICATION);
-        return;
-    }
-
-    CPU_FOREACH(t) {
-        run_on_cpu(t, s390_do_cpu_set_diag318,
-                   RUN_ON_CPU_HOST_ULONG(diag318_info));
-    }
-}
-
-#define DIAG_KVM_CODE_MASK 0x000000000000ffff
-
-static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb)
-{
-    int r = 0;
-    uint16_t func_code;
-
-    /*
-     * For any diagnose call we support, bits 48-63 of the resulting
-     * address specify the function code; the remainder is ignored.
-     */
-    func_code = decode_basedisp_rs(&cpu->env, ipb, NULL) & DIAG_KVM_CODE_MASK;
-    switch (func_code) {
-    case DIAG_TIMEREVENT:
-        kvm_handle_diag_288(cpu, run);
-        break;
-    case DIAG_IPL:
-        kvm_handle_diag_308(cpu, run);
-        break;
-    case DIAG_SET_CONTROL_PROGRAM_CODES:
-        handle_diag_318(cpu, run);
-        break;
-    case DIAG_KVM_HYPERCALL:
-        r = handle_hypercall(cpu, run);
-        break;
-    case DIAG_KVM_BREAKPOINT:
-        r = handle_sw_breakpoint(cpu, run);
-        break;
-    default:
-        DPRINTF("KVM: unknown DIAG: 0x%x\n", func_code);
-        kvm_s390_program_interrupt(cpu, PGM_SPECIFICATION);
-        break;
-    }
-
-    return r;
-}
-
-static int kvm_s390_handle_sigp(S390CPU *cpu, uint8_t ipa1, uint32_t ipb)
-{
-    CPUS390XState *env = &cpu->env;
-    const uint8_t r1 = ipa1 >> 4;
-    const uint8_t r3 = ipa1 & 0x0f;
-    int ret;
-    uint8_t order;
-
-    /* get order code */
-    order = decode_basedisp_rs(env, ipb, NULL) & SIGP_ORDER_MASK;
-
-    ret = handle_sigp(env, order, r1, r3);
-    setcc(cpu, ret);
-    return 0;
-}
-
-static int handle_instruction(S390CPU *cpu, struct kvm_run *run)
-{
-    unsigned int ipa0 = (run->s390_sieic.ipa & 0xff00);
-    uint8_t ipa1 = run->s390_sieic.ipa & 0x00ff;
-    int r = -1;
-
-    DPRINTF("handle_instruction 0x%x 0x%x\n",
-            run->s390_sieic.ipa, run->s390_sieic.ipb);
-    switch (ipa0) {
-    case IPA0_B2:
-        r = handle_b2(cpu, run, ipa1);
-        break;
-    case IPA0_B9:
-        r = handle_b9(cpu, run, ipa1);
-        break;
-    case IPA0_EB:
-        r = handle_eb(cpu, run, run->s390_sieic.ipb & 0xff);
-        break;
-    case IPA0_E3:
-        r = handle_e3(cpu, run, run->s390_sieic.ipb & 0xff);
-        break;
-    case IPA0_DIAG:
-        r = handle_diag(cpu, run, run->s390_sieic.ipb);
-        break;
-    case IPA0_SIGP:
-        r = kvm_s390_handle_sigp(cpu, ipa1, run->s390_sieic.ipb);
-        break;
-    }
-
-    if (r < 0) {
-        r = 0;
-        kvm_s390_program_interrupt(cpu, PGM_OPERATION);
-    }
-
-    return r;
-}
-
-static void unmanageable_intercept(S390CPU *cpu, S390CrashReason reason,
-                                   int pswoffset)
-{
-    CPUState *cs = CPU(cpu);
-
-    s390_cpu_halt(cpu);
-    cpu->env.crash_reason = reason;
-    qemu_system_guest_panicked(cpu_get_crash_info(cs));
-}
-
-/* try to detect pgm check loops */
-static int handle_oper_loop(S390CPU *cpu, struct kvm_run *run)
-{
-    CPUState *cs = CPU(cpu);
-    PSW oldpsw, newpsw;
-
-    newpsw.mask = ldq_phys(cs->as, cpu->env.psa +
-                           offsetof(LowCore, program_new_psw));
-    newpsw.addr = ldq_phys(cs->as, cpu->env.psa +
-                           offsetof(LowCore, program_new_psw) + 8);
-    oldpsw.mask  = run->psw_mask;
-    oldpsw.addr  = run->psw_addr;
-    /*
-     * Avoid endless loops of operation exceptions, if the pgm new
-     * PSW will cause a new operation exception.
-     * The heuristic checks if the pgm new psw is within 6 bytes before
-     * the faulting psw address (with same DAT, AS settings) and the
-     * new psw is not a wait psw and the fault was not triggered by
-     * problem state. In that case go into crashed state.
-     */
-
-    if (oldpsw.addr - newpsw.addr <= 6 &&
-        !(newpsw.mask & PSW_MASK_WAIT) &&
-        !(oldpsw.mask & PSW_MASK_PSTATE) &&
-        (newpsw.mask & PSW_MASK_ASC) == (oldpsw.mask & PSW_MASK_ASC) &&
-        (newpsw.mask & PSW_MASK_DAT) == (oldpsw.mask & PSW_MASK_DAT)) {
-        unmanageable_intercept(cpu, S390_CRASH_REASON_OPINT_LOOP,
-                               offsetof(LowCore, program_new_psw));
-        return EXCP_HALTED;
-    }
-    return 0;
-}
-
-static int handle_intercept(S390CPU *cpu)
-{
-    CPUState *cs = CPU(cpu);
-    struct kvm_run *run = cs->kvm_run;
-    int icpt_code = run->s390_sieic.icptcode;
-    int r = 0;
-
-    DPRINTF("intercept: 0x%x (at 0x%lx)\n", icpt_code, (long)run->psw_addr);
-    switch (icpt_code) {
-        case ICPT_INSTRUCTION:
-        case ICPT_PV_INSTR:
-        case ICPT_PV_INSTR_NOTIFICATION:
-            r = handle_instruction(cpu, run);
-            break;
-        case ICPT_PROGRAM:
-            unmanageable_intercept(cpu, S390_CRASH_REASON_PGMINT_LOOP,
-                                   offsetof(LowCore, program_new_psw));
-            r = EXCP_HALTED;
-            break;
-        case ICPT_EXT_INT:
-            unmanageable_intercept(cpu, S390_CRASH_REASON_EXTINT_LOOP,
-                                   offsetof(LowCore, external_new_psw));
-            r = EXCP_HALTED;
-            break;
-        case ICPT_WAITPSW:
-            /* disabled wait, since enabled wait is handled in kernel */
-            s390_handle_wait(cpu);
-            r = EXCP_HALTED;
-            break;
-        case ICPT_CPU_STOP:
-            do_stop_interrupt(&cpu->env);
-            r = EXCP_HALTED;
-            break;
-        case ICPT_OPEREXC:
-            /* check for break points */
-            r = handle_sw_breakpoint(cpu, run);
-            if (r == -ENOENT) {
-                /* Then check for potential pgm check loops */
-                r = handle_oper_loop(cpu, run);
-                if (r == 0) {
-                    kvm_s390_program_interrupt(cpu, PGM_OPERATION);
-                }
-            }
-            break;
-        case ICPT_SOFT_INTERCEPT:
-            fprintf(stderr, "KVM unimplemented icpt SOFT\n");
-            exit(1);
-            break;
-        case ICPT_IO:
-            fprintf(stderr, "KVM unimplemented icpt IO\n");
-            exit(1);
-            break;
-        default:
-            fprintf(stderr, "Unknown intercept code: %d\n", icpt_code);
-            exit(1);
-            break;
-    }
-
-    return r;
-}
-
-static int handle_tsch(S390CPU *cpu)
-{
-    CPUState *cs = CPU(cpu);
-    struct kvm_run *run = cs->kvm_run;
-    int ret;
-
-    ret = ioinst_handle_tsch(cpu, cpu->env.regs[1], run->s390_tsch.ipb,
-                             RA_IGNORED);
-    if (ret < 0) {
-        /*
-         * Failure.
-         * If an I/O interrupt had been dequeued, we have to reinject it.
-         */
-        if (run->s390_tsch.dequeued) {
-            s390_io_interrupt(run->s390_tsch.subchannel_id,
-                              run->s390_tsch.subchannel_nr,
-                              run->s390_tsch.io_int_parm,
-                              run->s390_tsch.io_int_word);
-        }
-        ret = 0;
-    }
-    return ret;
-}
-
-static void insert_stsi_3_2_2(S390CPU *cpu, __u64 addr, uint8_t ar)
-{
-    const MachineState *ms = MACHINE(qdev_get_machine());
-    uint16_t conf_cpus = 0, reserved_cpus = 0;
-    SysIB_322 sysib;
-    int del, i;
-
-    if (s390_is_pv()) {
-        s390_cpu_pv_mem_read(cpu, 0, &sysib, sizeof(sysib));
-    } else if (s390_cpu_virt_mem_read(cpu, addr, ar, &sysib, sizeof(sysib))) {
-        return;
-    }
-    /* Shift the stack of Extended Names to prepare for our own data */
-    memmove(&sysib.ext_names[1], &sysib.ext_names[0],
-            sizeof(sysib.ext_names[0]) * (sysib.count - 1));
-    /* First virt level, that doesn't provide Ext Names delimits stack. It is
-     * assumed it's not capable of managing Extended Names for lower levels.
-     */
-    for (del = 1; del < sysib.count; del++) {
-        if (!sysib.vm[del].ext_name_encoding || !sysib.ext_names[del][0]) {
-            break;
-        }
-    }
-    if (del < sysib.count) {
-        memset(sysib.ext_names[del], 0,
-               sizeof(sysib.ext_names[0]) * (sysib.count - del));
-    }
-
-    /* count the cpus and split them into configured and reserved ones */
-    for (i = 0; i < ms->possible_cpus->len; i++) {
-        if (ms->possible_cpus->cpus[i].cpu) {
-            conf_cpus++;
-        } else {
-            reserved_cpus++;
-        }
-    }
-    sysib.vm[0].total_cpus = conf_cpus + reserved_cpus;
-    sysib.vm[0].conf_cpus = conf_cpus;
-    sysib.vm[0].reserved_cpus = reserved_cpus;
-
-    /* Insert short machine name in EBCDIC, padded with blanks */
-    if (qemu_name) {
-        memset(sysib.vm[0].name, 0x40, sizeof(sysib.vm[0].name));
-        ebcdic_put(sysib.vm[0].name, qemu_name, MIN(sizeof(sysib.vm[0].name),
-                                                    strlen(qemu_name)));
-    }
-    sysib.vm[0].ext_name_encoding = 2; /* 2 = UTF-8 */
-    /* If hypervisor specifies zero Extended Name in STSI322 SYSIB, it's
-     * considered by s390 as not capable of providing any Extended Name.
-     * Therefore if no name was specified on qemu invocation, we go with the
-     * same "KVMguest" default, which KVM has filled into short name field.
-     */
-    strpadcpy((char *)sysib.ext_names[0],
-              sizeof(sysib.ext_names[0]),
-              qemu_name ?: "KVMguest", '\0');
-
-    /* Insert UUID */
-    memcpy(sysib.vm[0].uuid, &qemu_uuid, sizeof(sysib.vm[0].uuid));
-
-    if (s390_is_pv()) {
-        s390_cpu_pv_mem_write(cpu, 0, &sysib, sizeof(sysib));
-    } else {
-        s390_cpu_virt_mem_write(cpu, addr, ar, &sysib, sizeof(sysib));
-    }
-}
-
-static int handle_stsi(S390CPU *cpu)
-{
-    CPUState *cs = CPU(cpu);
-    struct kvm_run *run = cs->kvm_run;
-
-    switch (run->s390_stsi.fc) {
-    case 3:
-        if (run->s390_stsi.sel1 != 2 || run->s390_stsi.sel2 != 2) {
-            return 0;
-        }
-        /* Only sysib 3.2.2 needs post-handling for now. */
-        insert_stsi_3_2_2(cpu, run->s390_stsi.addr, run->s390_stsi.ar);
-        return 0;
-    default:
-        return 0;
-    }
-}
-
-static int kvm_arch_handle_debug_exit(S390CPU *cpu)
-{
-    CPUState *cs = CPU(cpu);
-    struct kvm_run *run = cs->kvm_run;
-
-    int ret = 0;
-    struct kvm_debug_exit_arch *arch_info = &run->debug.arch;
-
-    switch (arch_info->type) {
-    case KVM_HW_WP_WRITE:
-        if (find_hw_breakpoint(arch_info->addr, -1, arch_info->type)) {
-            cs->watchpoint_hit = &hw_watchpoint;
-            hw_watchpoint.vaddr = arch_info->addr;
-            hw_watchpoint.flags = BP_MEM_WRITE;
-            ret = EXCP_DEBUG;
-        }
-        break;
-    case KVM_HW_BP:
-        if (find_hw_breakpoint(arch_info->addr, -1, arch_info->type)) {
-            ret = EXCP_DEBUG;
-        }
-        break;
-    case KVM_SINGLESTEP:
-        if (cs->singlestep_enabled) {
-            ret = EXCP_DEBUG;
-        }
-        break;
-    default:
-        ret = -ENOSYS;
-    }
-
-    return ret;
-}
-
-int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
-{
-    S390CPU *cpu = S390_CPU(cs);
-    int ret = 0;
-
-    qemu_mutex_lock_iothread();
-
-    kvm_cpu_synchronize_state(cs);
-
-    switch (run->exit_reason) {
-        case KVM_EXIT_S390_SIEIC:
-            ret = handle_intercept(cpu);
-            break;
-        case KVM_EXIT_S390_RESET:
-            s390_ipl_reset_request(cs, S390_RESET_REIPL);
-            break;
-        case KVM_EXIT_S390_TSCH:
-            ret = handle_tsch(cpu);
-            break;
-        case KVM_EXIT_S390_STSI:
-            ret = handle_stsi(cpu);
-            break;
-        case KVM_EXIT_DEBUG:
-            ret = kvm_arch_handle_debug_exit(cpu);
-            break;
-        default:
-            fprintf(stderr, "Unknown KVM exit: %d\n", run->exit_reason);
-            break;
-    }
-    qemu_mutex_unlock_iothread();
-
-    if (ret == 0) {
-        ret = EXCP_INTERRUPT;
-    }
-    return ret;
-}
-
-bool kvm_arch_stop_on_emulation_error(CPUState *cpu)
-{
-    return true;
-}
-
-void kvm_s390_enable_css_support(S390CPU *cpu)
-{
-    int r;
-
-    /* Activate host kernel channel subsystem support. */
-    r = kvm_vcpu_enable_cap(CPU(cpu), KVM_CAP_S390_CSS_SUPPORT, 0);
-    assert(r == 0);
-}
-
-void kvm_arch_init_irq_routing(KVMState *s)
-{
-    /*
-     * Note that while irqchip capabilities generally imply that cpustates
-     * are handled in-kernel, it is not true for s390 (yet); therefore, we
-     * have to override the common code kvm_halt_in_kernel_allowed setting.
-     */
-    if (kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) {
-        kvm_gsi_routing_allowed = true;
-        kvm_halt_in_kernel_allowed = false;
-    }
-}
-
-int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch,
-                                    int vq, bool assign)
-{
-    struct kvm_ioeventfd kick = {
-        .flags = KVM_IOEVENTFD_FLAG_VIRTIO_CCW_NOTIFY |
-        KVM_IOEVENTFD_FLAG_DATAMATCH,
-        .fd = event_notifier_get_fd(notifier),
-        .datamatch = vq,
-        .addr = sch,
-        .len = 8,
-    };
-    trace_kvm_assign_subch_ioeventfd(kick.fd, kick.addr, assign,
-                                     kick.datamatch);
-    if (!kvm_check_extension(kvm_state, KVM_CAP_IOEVENTFD)) {
-        return -ENOSYS;
-    }
-    if (!assign) {
-        kick.flags |= KVM_IOEVENTFD_FLAG_DEASSIGN;
-    }
-    return kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &kick);
-}
-
-int kvm_s390_get_ri(void)
-{
-    return cap_ri;
-}
-
-int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state)
-{
-    struct kvm_mp_state mp_state = {};
-    int ret;
-
-    /* the kvm part might not have been initialized yet */
-    if (CPU(cpu)->kvm_state == NULL) {
-        return 0;
-    }
-
-    switch (cpu_state) {
-    case S390_CPU_STATE_STOPPED:
-        mp_state.mp_state = KVM_MP_STATE_STOPPED;
-        break;
-    case S390_CPU_STATE_CHECK_STOP:
-        mp_state.mp_state = KVM_MP_STATE_CHECK_STOP;
-        break;
-    case S390_CPU_STATE_OPERATING:
-        mp_state.mp_state = KVM_MP_STATE_OPERATING;
-        break;
-    case S390_CPU_STATE_LOAD:
-        mp_state.mp_state = KVM_MP_STATE_LOAD;
-        break;
-    default:
-        error_report("Requested CPU state is not a valid S390 CPU state: %u",
-                     cpu_state);
-        exit(1);
-    }
-
-    ret = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MP_STATE, &mp_state);
-    if (ret) {
-        trace_kvm_failed_cpu_state_set(CPU(cpu)->cpu_index, cpu_state,
-                                       strerror(-ret));
-    }
-
-    return ret;
-}
-
-void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu)
-{
-    unsigned int max_cpus = MACHINE(qdev_get_machine())->smp.max_cpus;
-    struct kvm_s390_irq_state irq_state = {
-        .buf = (uint64_t) cpu->irqstate,
-        .len = VCPU_IRQ_BUF_SIZE(max_cpus),
-    };
-    CPUState *cs = CPU(cpu);
-    int32_t bytes;
-
-    if (!kvm_check_extension(kvm_state, KVM_CAP_S390_IRQ_STATE)) {
-        return;
-    }
-
-    bytes = kvm_vcpu_ioctl(cs, KVM_S390_GET_IRQ_STATE, &irq_state);
-    if (bytes < 0) {
-        cpu->irqstate_saved_size = 0;
-        error_report("Migration of interrupt state failed");
-        return;
-    }
-
-    cpu->irqstate_saved_size = bytes;
-}
-
-int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu)
-{
-    CPUState *cs = CPU(cpu);
-    struct kvm_s390_irq_state irq_state = {
-        .buf = (uint64_t) cpu->irqstate,
-        .len = cpu->irqstate_saved_size,
-    };
-    int r;
-
-    if (cpu->irqstate_saved_size == 0) {
-        return 0;
-    }
-
-    if (!kvm_check_extension(kvm_state, KVM_CAP_S390_IRQ_STATE)) {
-        return -ENOSYS;
-    }
-
-    r = kvm_vcpu_ioctl(cs, KVM_S390_SET_IRQ_STATE, &irq_state);
-    if (r) {
-        error_report("Setting interrupt state failed %d", r);
-    }
-    return r;
-}
-
-int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
-                             uint64_t address, uint32_t data, PCIDevice *dev)
-{
-    S390PCIBusDevice *pbdev;
-    uint32_t vec = data & ZPCI_MSI_VEC_MASK;
-
-    if (!dev) {
-        DPRINTF("add_msi_route no pci device\n");
-        return -ENODEV;
-    }
-
-    pbdev = s390_pci_find_dev_by_target(s390_get_phb(), DEVICE(dev)->id);
-    if (!pbdev) {
-        DPRINTF("add_msi_route no zpci device\n");
-        return -ENODEV;
-    }
-
-    route->type = KVM_IRQ_ROUTING_S390_ADAPTER;
-    route->flags = 0;
-    route->u.adapter.summary_addr = pbdev->routes.adapter.summary_addr;
-    route->u.adapter.ind_addr = pbdev->routes.adapter.ind_addr;
-    route->u.adapter.summary_offset = pbdev->routes.adapter.summary_offset;
-    route->u.adapter.ind_offset = pbdev->routes.adapter.ind_offset + vec;
-    route->u.adapter.adapter_id = pbdev->routes.adapter.adapter_id;
-    return 0;
-}
-
-int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route,
-                                int vector, PCIDevice *dev)
-{
-    return 0;
-}
-
-int kvm_arch_release_virq_post(int virq)
-{
-    return 0;
-}
-
-int kvm_arch_msi_data_to_gsi(uint32_t data)
-{
-    abort();
-}
-
-static int query_cpu_subfunc(S390FeatBitmap features)
-{
-    struct kvm_s390_vm_cpu_subfunc prop = {};
-    struct kvm_device_attr attr = {
-        .group = KVM_S390_VM_CPU_MODEL,
-        .attr = KVM_S390_VM_CPU_MACHINE_SUBFUNC,
-        .addr = (uint64_t) &prop,
-    };
-    int rc;
-
-    rc = kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
-    if (rc) {
-        return  rc;
-    }
-
-    /*
-     * We're going to add all subfunctions now, if the corresponding feature
-     * is available that unlocks the query functions.
-     */
-    s390_add_from_feat_block(features, S390_FEAT_TYPE_PLO, prop.plo);
-    if (test_bit(S390_FEAT_TOD_CLOCK_STEERING, features)) {
-        s390_add_from_feat_block(features, S390_FEAT_TYPE_PTFF, prop.ptff);
-    }
-    if (test_bit(S390_FEAT_MSA, features)) {
-        s390_add_from_feat_block(features, S390_FEAT_TYPE_KMAC, prop.kmac);
-        s390_add_from_feat_block(features, S390_FEAT_TYPE_KMC, prop.kmc);
-        s390_add_from_feat_block(features, S390_FEAT_TYPE_KM, prop.km);
-        s390_add_from_feat_block(features, S390_FEAT_TYPE_KIMD, prop.kimd);
-        s390_add_from_feat_block(features, S390_FEAT_TYPE_KLMD, prop.klmd);
-    }
-    if (test_bit(S390_FEAT_MSA_EXT_3, features)) {
-        s390_add_from_feat_block(features, S390_FEAT_TYPE_PCKMO, prop.pckmo);
-    }
-    if (test_bit(S390_FEAT_MSA_EXT_4, features)) {
-        s390_add_from_feat_block(features, S390_FEAT_TYPE_KMCTR, prop.kmctr);
-        s390_add_from_feat_block(features, S390_FEAT_TYPE_KMF, prop.kmf);
-        s390_add_from_feat_block(features, S390_FEAT_TYPE_KMO, prop.kmo);
-        s390_add_from_feat_block(features, S390_FEAT_TYPE_PCC, prop.pcc);
-    }
-    if (test_bit(S390_FEAT_MSA_EXT_5, features)) {
-        s390_add_from_feat_block(features, S390_FEAT_TYPE_PPNO, prop.ppno);
-    }
-    if (test_bit(S390_FEAT_MSA_EXT_8, features)) {
-        s390_add_from_feat_block(features, S390_FEAT_TYPE_KMA, prop.kma);
-    }
-    if (test_bit(S390_FEAT_MSA_EXT_9, features)) {
-        s390_add_from_feat_block(features, S390_FEAT_TYPE_KDSA, prop.kdsa);
-    }
-    if (test_bit(S390_FEAT_ESORT_BASE, features)) {
-        s390_add_from_feat_block(features, S390_FEAT_TYPE_SORTL, prop.sortl);
-    }
-    if (test_bit(S390_FEAT_DEFLATE_BASE, features)) {
-        s390_add_from_feat_block(features, S390_FEAT_TYPE_DFLTCC, prop.dfltcc);
-    }
-    return 0;
-}
-
-static int configure_cpu_subfunc(const S390FeatBitmap features)
-{
-    struct kvm_s390_vm_cpu_subfunc prop = {};
-    struct kvm_device_attr attr = {
-        .group = KVM_S390_VM_CPU_MODEL,
-        .attr = KVM_S390_VM_CPU_PROCESSOR_SUBFUNC,
-        .addr = (uint64_t) &prop,
-    };
-
-    if (!kvm_vm_check_attr(kvm_state, KVM_S390_VM_CPU_MODEL,
-                           KVM_S390_VM_CPU_PROCESSOR_SUBFUNC)) {
-        /* hardware support might be missing, IBC will handle most of this */
-        return 0;
-    }
-
-    s390_fill_feat_block(features, S390_FEAT_TYPE_PLO, prop.plo);
-    if (test_bit(S390_FEAT_TOD_CLOCK_STEERING, features)) {
-        s390_fill_feat_block(features, S390_FEAT_TYPE_PTFF, prop.ptff);
-    }
-    if (test_bit(S390_FEAT_MSA, features)) {
-        s390_fill_feat_block(features, S390_FEAT_TYPE_KMAC, prop.kmac);
-        s390_fill_feat_block(features, S390_FEAT_TYPE_KMC, prop.kmc);
-        s390_fill_feat_block(features, S390_FEAT_TYPE_KM, prop.km);
-        s390_fill_feat_block(features, S390_FEAT_TYPE_KIMD, prop.kimd);
-        s390_fill_feat_block(features, S390_FEAT_TYPE_KLMD, prop.klmd);
-    }
-    if (test_bit(S390_FEAT_MSA_EXT_3, features)) {
-        s390_fill_feat_block(features, S390_FEAT_TYPE_PCKMO, prop.pckmo);
-    }
-    if (test_bit(S390_FEAT_MSA_EXT_4, features)) {
-        s390_fill_feat_block(features, S390_FEAT_TYPE_KMCTR, prop.kmctr);
-        s390_fill_feat_block(features, S390_FEAT_TYPE_KMF, prop.kmf);
-        s390_fill_feat_block(features, S390_FEAT_TYPE_KMO, prop.kmo);
-        s390_fill_feat_block(features, S390_FEAT_TYPE_PCC, prop.pcc);
-    }
-    if (test_bit(S390_FEAT_MSA_EXT_5, features)) {
-        s390_fill_feat_block(features, S390_FEAT_TYPE_PPNO, prop.ppno);
-    }
-    if (test_bit(S390_FEAT_MSA_EXT_8, features)) {
-        s390_fill_feat_block(features, S390_FEAT_TYPE_KMA, prop.kma);
-    }
-    if (test_bit(S390_FEAT_MSA_EXT_9, features)) {
-        s390_fill_feat_block(features, S390_FEAT_TYPE_KDSA, prop.kdsa);
-    }
-    if (test_bit(S390_FEAT_ESORT_BASE, features)) {
-        s390_fill_feat_block(features, S390_FEAT_TYPE_SORTL, prop.sortl);
-    }
-    if (test_bit(S390_FEAT_DEFLATE_BASE, features)) {
-        s390_fill_feat_block(features, S390_FEAT_TYPE_DFLTCC, prop.dfltcc);
-    }
-    return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
-}
-
-static int kvm_to_feat[][2] = {
-    { KVM_S390_VM_CPU_FEAT_ESOP, S390_FEAT_ESOP },
-    { KVM_S390_VM_CPU_FEAT_SIEF2, S390_FEAT_SIE_F2 },
-    { KVM_S390_VM_CPU_FEAT_64BSCAO , S390_FEAT_SIE_64BSCAO },
-    { KVM_S390_VM_CPU_FEAT_SIIF, S390_FEAT_SIE_SIIF },
-    { KVM_S390_VM_CPU_FEAT_GPERE, S390_FEAT_SIE_GPERE },
-    { KVM_S390_VM_CPU_FEAT_GSLS, S390_FEAT_SIE_GSLS },
-    { KVM_S390_VM_CPU_FEAT_IB, S390_FEAT_SIE_IB },
-    { KVM_S390_VM_CPU_FEAT_CEI, S390_FEAT_SIE_CEI },
-    { KVM_S390_VM_CPU_FEAT_IBS, S390_FEAT_SIE_IBS },
-    { KVM_S390_VM_CPU_FEAT_SKEY, S390_FEAT_SIE_SKEY },
-    { KVM_S390_VM_CPU_FEAT_CMMA, S390_FEAT_SIE_CMMA },
-    { KVM_S390_VM_CPU_FEAT_PFMFI, S390_FEAT_SIE_PFMFI},
-    { KVM_S390_VM_CPU_FEAT_SIGPIF, S390_FEAT_SIE_SIGPIF},
-    { KVM_S390_VM_CPU_FEAT_KSS, S390_FEAT_SIE_KSS},
-};
-
-static int query_cpu_feat(S390FeatBitmap features)
-{
-    struct kvm_s390_vm_cpu_feat prop = {};
-    struct kvm_device_attr attr = {
-        .group = KVM_S390_VM_CPU_MODEL,
-        .attr = KVM_S390_VM_CPU_MACHINE_FEAT,
-        .addr = (uint64_t) &prop,
-    };
-    int rc;
-    int i;
-
-    rc = kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
-    if (rc) {
-        return  rc;
-    }
-
-    for (i = 0; i < ARRAY_SIZE(kvm_to_feat); i++) {
-        if (test_be_bit(kvm_to_feat[i][0], (uint8_t *) prop.feat)) {
-            set_bit(kvm_to_feat[i][1], features);
-        }
-    }
-    return 0;
-}
-
-static int configure_cpu_feat(const S390FeatBitmap features)
-{
-    struct kvm_s390_vm_cpu_feat prop = {};
-    struct kvm_device_attr attr = {
-        .group = KVM_S390_VM_CPU_MODEL,
-        .attr = KVM_S390_VM_CPU_PROCESSOR_FEAT,
-        .addr = (uint64_t) &prop,
-    };
-    int i;
-
-    for (i = 0; i < ARRAY_SIZE(kvm_to_feat); i++) {
-        if (test_bit(kvm_to_feat[i][1], features)) {
-            set_be_bit(kvm_to_feat[i][0], (uint8_t *) prop.feat);
-        }
-    }
-    return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
-}
-
-bool kvm_s390_cpu_models_supported(void)
-{
-    if (!cpu_model_allowed()) {
-        /* compatibility machines interfere with the cpu model */
-        return false;
-    }
-    return kvm_vm_check_attr(kvm_state, KVM_S390_VM_CPU_MODEL,
-                             KVM_S390_VM_CPU_MACHINE) &&
-           kvm_vm_check_attr(kvm_state, KVM_S390_VM_CPU_MODEL,
-                             KVM_S390_VM_CPU_PROCESSOR) &&
-           kvm_vm_check_attr(kvm_state, KVM_S390_VM_CPU_MODEL,
-                             KVM_S390_VM_CPU_MACHINE_FEAT) &&
-           kvm_vm_check_attr(kvm_state, KVM_S390_VM_CPU_MODEL,
-                             KVM_S390_VM_CPU_PROCESSOR_FEAT) &&
-           kvm_vm_check_attr(kvm_state, KVM_S390_VM_CPU_MODEL,
-                             KVM_S390_VM_CPU_MACHINE_SUBFUNC);
-}
-
-void kvm_s390_get_host_cpu_model(S390CPUModel *model, Error **errp)
-{
-    struct kvm_s390_vm_cpu_machine prop = {};
-    struct kvm_device_attr attr = {
-        .group = KVM_S390_VM_CPU_MODEL,
-        .attr = KVM_S390_VM_CPU_MACHINE,
-        .addr = (uint64_t) &prop,
-    };
-    uint16_t unblocked_ibc = 0, cpu_type = 0;
-    int rc;
-
-    memset(model, 0, sizeof(*model));
-
-    if (!kvm_s390_cpu_models_supported()) {
-        error_setg(errp, "KVM doesn't support CPU models");
-        return;
-    }
-
-    /* query the basic cpu model properties */
-    rc = kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
-    if (rc) {
-        error_setg(errp, "KVM: Error querying host CPU model: %d", rc);
-        return;
-    }
-
-    cpu_type = cpuid_type(prop.cpuid);
-    if (has_ibc(prop.ibc)) {
-        model->lowest_ibc = lowest_ibc(prop.ibc);
-        unblocked_ibc = unblocked_ibc(prop.ibc);
-    }
-    model->cpu_id = cpuid_id(prop.cpuid);
-    model->cpu_id_format = cpuid_format(prop.cpuid);
-    model->cpu_ver = 0xff;
-
-    /* get supported cpu features indicated via STFL(E) */
-    s390_add_from_feat_block(model->features, S390_FEAT_TYPE_STFL,
-                             (uint8_t *) prop.fac_mask);
-    /* dat-enhancement facility 2 has no bit but was introduced with stfle */
-    if (test_bit(S390_FEAT_STFLE, model->features)) {
-        set_bit(S390_FEAT_DAT_ENH_2, model->features);
-    }
-    /* get supported cpu features indicated e.g. via SCLP */
-    rc = query_cpu_feat(model->features);
-    if (rc) {
-        error_setg(errp, "KVM: Error querying CPU features: %d", rc);
-        return;
-    }
-    /* get supported cpu subfunctions indicated via query / test bit */
-    rc = query_cpu_subfunc(model->features);
-    if (rc) {
-        error_setg(errp, "KVM: Error querying CPU subfunctions: %d", rc);
-        return;
-    }
-
-    /* PTFF subfunctions might be indicated although kernel support missing */
-    if (!test_bit(S390_FEAT_MULTIPLE_EPOCH, model->features)) {
-        clear_bit(S390_FEAT_PTFF_QSIE, model->features);
-        clear_bit(S390_FEAT_PTFF_QTOUE, model->features);
-        clear_bit(S390_FEAT_PTFF_STOE, model->features);
-        clear_bit(S390_FEAT_PTFF_STOUE, model->features);
-    }
-
-    /* with cpu model support, CMM is only indicated if really available */
-    if (kvm_s390_cmma_available()) {
-        set_bit(S390_FEAT_CMM, model->features);
-    } else {
-        /* no cmm -> no cmm nt */
-        clear_bit(S390_FEAT_CMM_NT, model->features);
-    }
-
-    /* bpb needs kernel support for migration, VSIE and reset */
-    if (!kvm_check_extension(kvm_state, KVM_CAP_S390_BPB)) {
-        clear_bit(S390_FEAT_BPB, model->features);
-    }
-
-    /*
-     * If we have support for protected virtualization, indicate
-     * the protected virtualization IPL unpack facility.
-     */
-    if (cap_protected) {
-        set_bit(S390_FEAT_UNPACK, model->features);
-    }
-
-    /* We emulate a zPCI bus and AEN, therefore we don't need HW support */
-    set_bit(S390_FEAT_ZPCI, model->features);
-    set_bit(S390_FEAT_ADAPTER_EVENT_NOTIFICATION, model->features);
-
-    if (s390_known_cpu_type(cpu_type)) {
-        /* we want the exact model, even if some features are missing */
-        model->def = s390_find_cpu_def(cpu_type, ibc_gen(unblocked_ibc),
-                                       ibc_ec_ga(unblocked_ibc), NULL);
-    } else {
-        /* model unknown, e.g. too new - search using features */
-        model->def = s390_find_cpu_def(0, ibc_gen(unblocked_ibc),
-                                       ibc_ec_ga(unblocked_ibc),
-                                       model->features);
-    }
-    if (!model->def) {
-        error_setg(errp, "KVM: host CPU model could not be identified");
-        return;
-    }
-    /* for now, we can only provide the AP feature with HW support */
-    if (kvm_vm_check_attr(kvm_state, KVM_S390_VM_CRYPTO,
-        KVM_S390_VM_CRYPTO_ENABLE_APIE)) {
-        set_bit(S390_FEAT_AP, model->features);
-    }
-
-    /*
-     * Extended-Length SCCB is handled entirely within QEMU.
-     * For PV guests this is completely fenced by the Ultravisor, as Service
-     * Call error checking and STFLE interpretation are handled via SIE.
-     */
-    set_bit(S390_FEAT_EXTENDED_LENGTH_SCCB, model->features);
-
-    if (kvm_check_extension(kvm_state, KVM_CAP_S390_DIAG318)) {
-        set_bit(S390_FEAT_DIAG_318, model->features);
-    }
-
-    /* strip of features that are not part of the maximum model */
-    bitmap_and(model->features, model->features, model->def->full_feat,
-               S390_FEAT_MAX);
-}
-
-static void kvm_s390_configure_apie(bool interpret)
-{
-    uint64_t attr = interpret ? KVM_S390_VM_CRYPTO_ENABLE_APIE :
-                                KVM_S390_VM_CRYPTO_DISABLE_APIE;
-
-    if (kvm_vm_check_attr(kvm_state, KVM_S390_VM_CRYPTO, attr)) {
-        kvm_s390_set_attr(attr);
-    }
-}
-
-void kvm_s390_apply_cpu_model(const S390CPUModel *model, Error **errp)
-{
-    struct kvm_s390_vm_cpu_processor prop  = {
-        .fac_list = { 0 },
-    };
-    struct kvm_device_attr attr = {
-        .group = KVM_S390_VM_CPU_MODEL,
-        .attr = KVM_S390_VM_CPU_PROCESSOR,
-        .addr = (uint64_t) &prop,
-    };
-    int rc;
-
-    if (!model) {
-        /* compatibility handling if cpu models are disabled */
-        if (kvm_s390_cmma_available()) {
-            kvm_s390_enable_cmma();
-        }
-        return;
-    }
-    if (!kvm_s390_cpu_models_supported()) {
-        error_setg(errp, "KVM doesn't support CPU models");
-        return;
-    }
-    prop.cpuid = s390_cpuid_from_cpu_model(model);
-    prop.ibc = s390_ibc_from_cpu_model(model);
-    /* configure cpu features indicated via STFL(e) */
-    s390_fill_feat_block(model->features, S390_FEAT_TYPE_STFL,
-                         (uint8_t *) prop.fac_list);
-    rc = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
-    if (rc) {
-        error_setg(errp, "KVM: Error configuring the CPU model: %d", rc);
-        return;
-    }
-    /* configure cpu features indicated e.g. via SCLP */
-    rc = configure_cpu_feat(model->features);
-    if (rc) {
-        error_setg(errp, "KVM: Error configuring CPU features: %d", rc);
-        return;
-    }
-    /* configure cpu subfunctions indicated via query / test bit */
-    rc = configure_cpu_subfunc(model->features);
-    if (rc) {
-        error_setg(errp, "KVM: Error configuring CPU subfunctions: %d", rc);
-        return;
-    }
-    /* enable CMM via CMMA */
-    if (test_bit(S390_FEAT_CMM, model->features)) {
-        kvm_s390_enable_cmma();
-    }
-
-    if (test_bit(S390_FEAT_AP, model->features)) {
-        kvm_s390_configure_apie(true);
-    }
-}
-
-void kvm_s390_restart_interrupt(S390CPU *cpu)
-{
-    struct kvm_s390_irq irq = {
-        .type = KVM_S390_RESTART,
-    };
-
-    kvm_s390_vcpu_interrupt(cpu, &irq);
-}
-
-void kvm_s390_stop_interrupt(S390CPU *cpu)
-{
-    struct kvm_s390_irq irq = {
-        .type = KVM_S390_SIGP_STOP,
-    };
-
-    kvm_s390_vcpu_interrupt(cpu, &irq);
-}
-
-bool kvm_arch_cpu_check_are_resettable(void)
-{
-    return true;
-}
diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
new file mode 100644 (file)
index 0000000..5b1fdb5
--- /dev/null
@@ -0,0 +1,2564 @@
+/*
+ * QEMU S390x KVM implementation
+ *
+ * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
+ * Copyright IBM Corp. 2012
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include <sys/ioctl.h>
+
+#include <linux/kvm.h>
+#include <asm/ptrace.h>
+
+#include "qemu-common.h"
+#include "cpu.h"
+#include "s390x-internal.h"
+#include "kvm_s390x.h"
+#include "sysemu/kvm_int.h"
+#include "qemu/cutils.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "qemu/timer.h"
+#include "qemu/units.h"
+#include "qemu/main-loop.h"
+#include "qemu/mmap-alloc.h"
+#include "qemu/log.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/hw_accel.h"
+#include "sysemu/runstate.h"
+#include "sysemu/device_tree.h"
+#include "exec/gdbstub.h"
+#include "exec/ram_addr.h"
+#include "trace.h"
+#include "hw/s390x/s390-pci-inst.h"
+#include "hw/s390x/s390-pci-bus.h"
+#include "hw/s390x/ipl.h"
+#include "hw/s390x/ebcdic.h"
+#include "exec/memattrs.h"
+#include "hw/s390x/s390-virtio-ccw.h"
+#include "hw/s390x/s390-virtio-hcall.h"
+#include "hw/s390x/pv.h"
+
+#ifndef DEBUG_KVM
+#define DEBUG_KVM  0
+#endif
+
+#define DPRINTF(fmt, ...) do {                \
+    if (DEBUG_KVM) {                          \
+        fprintf(stderr, fmt, ## __VA_ARGS__); \
+    }                                         \
+} while (0)
+
+#define kvm_vm_check_mem_attr(s, attr) \
+    kvm_vm_check_attr(s, KVM_S390_VM_MEM_CTRL, attr)
+
+#define IPA0_DIAG                       0x8300
+#define IPA0_SIGP                       0xae00
+#define IPA0_B2                         0xb200
+#define IPA0_B9                         0xb900
+#define IPA0_EB                         0xeb00
+#define IPA0_E3                         0xe300
+
+#define PRIV_B2_SCLP_CALL               0x20
+#define PRIV_B2_CSCH                    0x30
+#define PRIV_B2_HSCH                    0x31
+#define PRIV_B2_MSCH                    0x32
+#define PRIV_B2_SSCH                    0x33
+#define PRIV_B2_STSCH                   0x34
+#define PRIV_B2_TSCH                    0x35
+#define PRIV_B2_TPI                     0x36
+#define PRIV_B2_SAL                     0x37
+#define PRIV_B2_RSCH                    0x38
+#define PRIV_B2_STCRW                   0x39
+#define PRIV_B2_STCPS                   0x3a
+#define PRIV_B2_RCHP                    0x3b
+#define PRIV_B2_SCHM                    0x3c
+#define PRIV_B2_CHSC                    0x5f
+#define PRIV_B2_SIGA                    0x74
+#define PRIV_B2_XSCH                    0x76
+
+#define PRIV_EB_SQBS                    0x8a
+#define PRIV_EB_PCISTB                  0xd0
+#define PRIV_EB_SIC                     0xd1
+
+#define PRIV_B9_EQBS                    0x9c
+#define PRIV_B9_CLP                     0xa0
+#define PRIV_B9_PCISTG                  0xd0
+#define PRIV_B9_PCILG                   0xd2
+#define PRIV_B9_RPCIT                   0xd3
+
+#define PRIV_E3_MPCIFC                  0xd0
+#define PRIV_E3_STPCIFC                 0xd4
+
+#define DIAG_TIMEREVENT                 0x288
+#define DIAG_IPL                        0x308
+#define DIAG_SET_CONTROL_PROGRAM_CODES  0x318
+#define DIAG_KVM_HYPERCALL              0x500
+#define DIAG_KVM_BREAKPOINT             0x501
+
+#define ICPT_INSTRUCTION                0x04
+#define ICPT_PROGRAM                    0x08
+#define ICPT_EXT_INT                    0x14
+#define ICPT_WAITPSW                    0x1c
+#define ICPT_SOFT_INTERCEPT             0x24
+#define ICPT_CPU_STOP                   0x28
+#define ICPT_OPEREXC                    0x2c
+#define ICPT_IO                         0x40
+#define ICPT_PV_INSTR                   0x68
+#define ICPT_PV_INSTR_NOTIFICATION      0x6c
+
+#define NR_LOCAL_IRQS 32
+/*
+ * Needs to be big enough to contain max_cpus emergency signals
+ * and in addition NR_LOCAL_IRQS interrupts
+ */
+#define VCPU_IRQ_BUF_SIZE(max_cpus) (sizeof(struct kvm_s390_irq) * \
+                                     (max_cpus + NR_LOCAL_IRQS))
+/*
+ * KVM does only support memory slots up to KVM_MEM_MAX_NR_PAGES pages
+ * as the dirty bitmap must be managed by bitops that take an int as
+ * position indicator. This would end at an unaligned  address
+ * (0x7fffff00000). As future variants might provide larger pages
+ * and to make all addresses properly aligned, let us split at 4TB.
+ */
+#define KVM_SLOT_MAX_BYTES (4UL * TiB)
+
+static CPUWatchpoint hw_watchpoint;
+/*
+ * We don't use a list because this structure is also used to transmit the
+ * hardware breakpoints to the kernel.
+ */
+static struct kvm_hw_breakpoint *hw_breakpoints;
+static int nb_hw_breakpoints;
+
+const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
+    KVM_CAP_LAST_INFO
+};
+
+static int cap_sync_regs;
+static int cap_async_pf;
+static int cap_mem_op;
+static int cap_s390_irq;
+static int cap_ri;
+static int cap_hpage_1m;
+static int cap_vcpu_resets;
+static int cap_protected;
+
+static int active_cmma;
+
+static int kvm_s390_query_mem_limit(uint64_t *memory_limit)
+{
+    struct kvm_device_attr attr = {
+        .group = KVM_S390_VM_MEM_CTRL,
+        .attr = KVM_S390_VM_MEM_LIMIT_SIZE,
+        .addr = (uint64_t) memory_limit,
+    };
+
+    return kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
+}
+
+int kvm_s390_set_mem_limit(uint64_t new_limit, uint64_t *hw_limit)
+{
+    int rc;
+
+    struct kvm_device_attr attr = {
+        .group = KVM_S390_VM_MEM_CTRL,
+        .attr = KVM_S390_VM_MEM_LIMIT_SIZE,
+        .addr = (uint64_t) &new_limit,
+    };
+
+    if (!kvm_vm_check_mem_attr(kvm_state, KVM_S390_VM_MEM_LIMIT_SIZE)) {
+        return 0;
+    }
+
+    rc = kvm_s390_query_mem_limit(hw_limit);
+    if (rc) {
+        return rc;
+    } else if (*hw_limit < new_limit) {
+        return -E2BIG;
+    }
+
+    return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
+}
+
+int kvm_s390_cmma_active(void)
+{
+    return active_cmma;
+}
+
+static bool kvm_s390_cmma_available(void)
+{
+    static bool initialized, value;
+
+    if (!initialized) {
+        initialized = true;
+        value = kvm_vm_check_mem_attr(kvm_state, KVM_S390_VM_MEM_ENABLE_CMMA) &&
+                kvm_vm_check_mem_attr(kvm_state, KVM_S390_VM_MEM_CLR_CMMA);
+    }
+    return value;
+}
+
+void kvm_s390_cmma_reset(void)
+{
+    int rc;
+    struct kvm_device_attr attr = {
+        .group = KVM_S390_VM_MEM_CTRL,
+        .attr = KVM_S390_VM_MEM_CLR_CMMA,
+    };
+
+    if (!kvm_s390_cmma_active()) {
+        return;
+    }
+
+    rc = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
+    trace_kvm_clear_cmma(rc);
+}
+
+static void kvm_s390_enable_cmma(void)
+{
+    int rc;
+    struct kvm_device_attr attr = {
+        .group = KVM_S390_VM_MEM_CTRL,
+        .attr = KVM_S390_VM_MEM_ENABLE_CMMA,
+    };
+
+    if (cap_hpage_1m) {
+        warn_report("CMM will not be enabled because it is not "
+                    "compatible with huge memory backings.");
+        return;
+    }
+    rc = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
+    active_cmma = !rc;
+    trace_kvm_enable_cmma(rc);
+}
+
+static void kvm_s390_set_attr(uint64_t attr)
+{
+    struct kvm_device_attr attribute = {
+        .group = KVM_S390_VM_CRYPTO,
+        .attr  = attr,
+    };
+
+    int ret = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attribute);
+
+    if (ret) {
+        error_report("Failed to set crypto device attribute %lu: %s",
+                     attr, strerror(-ret));
+    }
+}
+
+static void kvm_s390_init_aes_kw(void)
+{
+    uint64_t attr = KVM_S390_VM_CRYPTO_DISABLE_AES_KW;
+
+    if (object_property_get_bool(OBJECT(qdev_get_machine()), "aes-key-wrap",
+                                 NULL)) {
+            attr = KVM_S390_VM_CRYPTO_ENABLE_AES_KW;
+    }
+
+    if (kvm_vm_check_attr(kvm_state, KVM_S390_VM_CRYPTO, attr)) {
+            kvm_s390_set_attr(attr);
+    }
+}
+
+static void kvm_s390_init_dea_kw(void)
+{
+    uint64_t attr = KVM_S390_VM_CRYPTO_DISABLE_DEA_KW;
+
+    if (object_property_get_bool(OBJECT(qdev_get_machine()), "dea-key-wrap",
+                                 NULL)) {
+            attr = KVM_S390_VM_CRYPTO_ENABLE_DEA_KW;
+    }
+
+    if (kvm_vm_check_attr(kvm_state, KVM_S390_VM_CRYPTO, attr)) {
+            kvm_s390_set_attr(attr);
+    }
+}
+
+void kvm_s390_crypto_reset(void)
+{
+    if (s390_has_feat(S390_FEAT_MSA_EXT_3)) {
+        kvm_s390_init_aes_kw();
+        kvm_s390_init_dea_kw();
+    }
+}
+
+void kvm_s390_set_max_pagesize(uint64_t pagesize, Error **errp)
+{
+    if (pagesize == 4 * KiB) {
+        return;
+    }
+
+    if (!hpage_1m_allowed()) {
+        error_setg(errp, "This QEMU machine does not support huge page "
+                   "mappings");
+        return;
+    }
+
+    if (pagesize != 1 * MiB) {
+        error_setg(errp, "Memory backing with 2G pages was specified, "
+                   "but KVM does not support this memory backing");
+        return;
+    }
+
+    if (kvm_vm_enable_cap(kvm_state, KVM_CAP_S390_HPAGE_1M, 0)) {
+        error_setg(errp, "Memory backing with 1M pages was specified, "
+                   "but KVM does not support this memory backing");
+        return;
+    }
+
+    cap_hpage_1m = 1;
+}
+
+int kvm_s390_get_hpage_1m(void)
+{
+    return cap_hpage_1m;
+}
+
+static void ccw_machine_class_foreach(ObjectClass *oc, void *opaque)
+{
+    MachineClass *mc = MACHINE_CLASS(oc);
+
+    mc->default_cpu_type = S390_CPU_TYPE_NAME("host");
+}
+
+int kvm_arch_init(MachineState *ms, KVMState *s)
+{
+    object_class_foreach(ccw_machine_class_foreach, TYPE_S390_CCW_MACHINE,
+                         false, NULL);
+
+    if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
+        error_report("KVM is missing capability KVM_CAP_DEVICE_CTRL - "
+                     "please use kernel 3.15 or newer");
+        return -1;
+    }
+    if (!kvm_check_extension(s, KVM_CAP_S390_COW)) {
+        error_report("KVM is missing capability KVM_CAP_S390_COW - "
+                     "unsupported environment");
+        return -1;
+    }
+
+    cap_sync_regs = kvm_check_extension(s, KVM_CAP_SYNC_REGS);
+    cap_async_pf = kvm_check_extension(s, KVM_CAP_ASYNC_PF);
+    cap_mem_op = kvm_check_extension(s, KVM_CAP_S390_MEM_OP);
+    cap_s390_irq = kvm_check_extension(s, KVM_CAP_S390_INJECT_IRQ);
+    cap_vcpu_resets = kvm_check_extension(s, KVM_CAP_S390_VCPU_RESETS);
+    cap_protected = kvm_check_extension(s, KVM_CAP_S390_PROTECTED);
+
+    kvm_vm_enable_cap(s, KVM_CAP_S390_USER_SIGP, 0);
+    kvm_vm_enable_cap(s, KVM_CAP_S390_VECTOR_REGISTERS, 0);
+    kvm_vm_enable_cap(s, KVM_CAP_S390_USER_STSI, 0);
+    if (ri_allowed()) {
+        if (kvm_vm_enable_cap(s, KVM_CAP_S390_RI, 0) == 0) {
+            cap_ri = 1;
+        }
+    }
+    if (cpu_model_allowed()) {
+        kvm_vm_enable_cap(s, KVM_CAP_S390_GS, 0);
+    }
+
+    /*
+     * The migration interface for ais was introduced with kernel 4.13
+     * but the capability itself had been active since 4.12. As migration
+     * support is considered necessary, we only try to enable this for
+     * newer machine types if KVM_CAP_S390_AIS_MIGRATION is available.
+     */
+    if (cpu_model_allowed() && kvm_kernel_irqchip_allowed() &&
+        kvm_check_extension(s, KVM_CAP_S390_AIS_MIGRATION)) {
+        kvm_vm_enable_cap(s, KVM_CAP_S390_AIS, 0);
+    }
+
+    kvm_set_max_memslot_size(KVM_SLOT_MAX_BYTES);
+    return 0;
+}
+
+int kvm_arch_irqchip_create(KVMState *s)
+{
+    return 0;
+}
+
+unsigned long kvm_arch_vcpu_id(CPUState *cpu)
+{
+    return cpu->cpu_index;
+}
+
+int kvm_arch_init_vcpu(CPUState *cs)
+{
+    unsigned int max_cpus = MACHINE(qdev_get_machine())->smp.max_cpus;
+    S390CPU *cpu = S390_CPU(cs);
+    kvm_s390_set_cpu_state(cpu, cpu->env.cpu_state);
+    cpu->irqstate = g_malloc0(VCPU_IRQ_BUF_SIZE(max_cpus));
+    return 0;
+}
+
+int kvm_arch_destroy_vcpu(CPUState *cs)
+{
+    S390CPU *cpu = S390_CPU(cs);
+
+    g_free(cpu->irqstate);
+    cpu->irqstate = NULL;
+
+    return 0;
+}
+
+static void kvm_s390_reset_vcpu(S390CPU *cpu, unsigned long type)
+{
+    CPUState *cs = CPU(cpu);
+
+    /*
+     * The reset call is needed here to reset in-kernel vcpu data that
+     * we can't access directly from QEMU (i.e. with older kernels
+     * which don't support sync_regs/ONE_REG).  Before this ioctl
+     * cpu_synchronize_state() is called in common kvm code
+     * (kvm-all).
+     */
+    if (kvm_vcpu_ioctl(cs, type)) {
+        error_report("CPU reset failed on CPU %i type %lx",
+                     cs->cpu_index, type);
+    }
+}
+
+void kvm_s390_reset_vcpu_initial(S390CPU *cpu)
+{
+    kvm_s390_reset_vcpu(cpu, KVM_S390_INITIAL_RESET);
+}
+
+void kvm_s390_reset_vcpu_clear(S390CPU *cpu)
+{
+    if (cap_vcpu_resets) {
+        kvm_s390_reset_vcpu(cpu, KVM_S390_CLEAR_RESET);
+    } else {
+        kvm_s390_reset_vcpu(cpu, KVM_S390_INITIAL_RESET);
+    }
+}
+
+void kvm_s390_reset_vcpu_normal(S390CPU *cpu)
+{
+    if (cap_vcpu_resets) {
+        kvm_s390_reset_vcpu(cpu, KVM_S390_NORMAL_RESET);
+    }
+}
+
+static int can_sync_regs(CPUState *cs, int regs)
+{
+    return cap_sync_regs && (cs->kvm_run->kvm_valid_regs & regs) == regs;
+}
+
+int kvm_arch_put_registers(CPUState *cs, int level)
+{
+    S390CPU *cpu = S390_CPU(cs);
+    CPUS390XState *env = &cpu->env;
+    struct kvm_sregs sregs;
+    struct kvm_regs regs;
+    struct kvm_fpu fpu = {};
+    int r;
+    int i;
+
+    /* always save the PSW  and the GPRS*/
+    cs->kvm_run->psw_addr = env->psw.addr;
+    cs->kvm_run->psw_mask = env->psw.mask;
+
+    if (can_sync_regs(cs, KVM_SYNC_GPRS)) {
+        for (i = 0; i < 16; i++) {
+            cs->kvm_run->s.regs.gprs[i] = env->regs[i];
+            cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_GPRS;
+        }
+    } else {
+        for (i = 0; i < 16; i++) {
+            regs.gprs[i] = env->regs[i];
+        }
+        r = kvm_vcpu_ioctl(cs, KVM_SET_REGS, &regs);
+        if (r < 0) {
+            return r;
+        }
+    }
+
+    if (can_sync_regs(cs, KVM_SYNC_VRS)) {
+        for (i = 0; i < 32; i++) {
+            cs->kvm_run->s.regs.vrs[i][0] = env->vregs[i][0];
+            cs->kvm_run->s.regs.vrs[i][1] = env->vregs[i][1];
+        }
+        cs->kvm_run->s.regs.fpc = env->fpc;
+        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_VRS;
+    } else if (can_sync_regs(cs, KVM_SYNC_FPRS)) {
+        for (i = 0; i < 16; i++) {
+            cs->kvm_run->s.regs.fprs[i] = *get_freg(env, i);
+        }
+        cs->kvm_run->s.regs.fpc = env->fpc;
+        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_FPRS;
+    } else {
+        /* Floating point */
+        for (i = 0; i < 16; i++) {
+            fpu.fprs[i] = *get_freg(env, i);
+        }
+        fpu.fpc = env->fpc;
+
+        r = kvm_vcpu_ioctl(cs, KVM_SET_FPU, &fpu);
+        if (r < 0) {
+            return r;
+        }
+    }
+
+    /* Do we need to save more than that? */
+    if (level == KVM_PUT_RUNTIME_STATE) {
+        return 0;
+    }
+
+    if (can_sync_regs(cs, KVM_SYNC_ARCH0)) {
+        cs->kvm_run->s.regs.cputm = env->cputm;
+        cs->kvm_run->s.regs.ckc = env->ckc;
+        cs->kvm_run->s.regs.todpr = env->todpr;
+        cs->kvm_run->s.regs.gbea = env->gbea;
+        cs->kvm_run->s.regs.pp = env->pp;
+        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_ARCH0;
+    } else {
+        /*
+         * These ONE_REGS are not protected by a capability. As they are only
+         * necessary for migration we just trace a possible error, but don't
+         * return with an error return code.
+         */
+        kvm_set_one_reg(cs, KVM_REG_S390_CPU_TIMER, &env->cputm);
+        kvm_set_one_reg(cs, KVM_REG_S390_CLOCK_COMP, &env->ckc);
+        kvm_set_one_reg(cs, KVM_REG_S390_TODPR, &env->todpr);
+        kvm_set_one_reg(cs, KVM_REG_S390_GBEA, &env->gbea);
+        kvm_set_one_reg(cs, KVM_REG_S390_PP, &env->pp);
+    }
+
+    if (can_sync_regs(cs, KVM_SYNC_RICCB)) {
+        memcpy(cs->kvm_run->s.regs.riccb, env->riccb, 64);
+        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_RICCB;
+    }
+
+    /* pfault parameters */
+    if (can_sync_regs(cs, KVM_SYNC_PFAULT)) {
+        cs->kvm_run->s.regs.pft = env->pfault_token;
+        cs->kvm_run->s.regs.pfs = env->pfault_select;
+        cs->kvm_run->s.regs.pfc = env->pfault_compare;
+        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_PFAULT;
+    } else if (cap_async_pf) {
+        r = kvm_set_one_reg(cs, KVM_REG_S390_PFTOKEN, &env->pfault_token);
+        if (r < 0) {
+            return r;
+        }
+        r = kvm_set_one_reg(cs, KVM_REG_S390_PFCOMPARE, &env->pfault_compare);
+        if (r < 0) {
+            return r;
+        }
+        r = kvm_set_one_reg(cs, KVM_REG_S390_PFSELECT, &env->pfault_select);
+        if (r < 0) {
+            return r;
+        }
+    }
+
+    /* access registers and control registers*/
+    if (can_sync_regs(cs, KVM_SYNC_ACRS | KVM_SYNC_CRS)) {
+        for (i = 0; i < 16; i++) {
+            cs->kvm_run->s.regs.acrs[i] = env->aregs[i];
+            cs->kvm_run->s.regs.crs[i] = env->cregs[i];
+        }
+        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_ACRS;
+        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_CRS;
+    } else {
+        for (i = 0; i < 16; i++) {
+            sregs.acrs[i] = env->aregs[i];
+            sregs.crs[i] = env->cregs[i];
+        }
+        r = kvm_vcpu_ioctl(cs, KVM_SET_SREGS, &sregs);
+        if (r < 0) {
+            return r;
+        }
+    }
+
+    if (can_sync_regs(cs, KVM_SYNC_GSCB)) {
+        memcpy(cs->kvm_run->s.regs.gscb, env->gscb, 32);
+        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_GSCB;
+    }
+
+    if (can_sync_regs(cs, KVM_SYNC_BPBC)) {
+        cs->kvm_run->s.regs.bpbc = env->bpbc;
+        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_BPBC;
+    }
+
+    if (can_sync_regs(cs, KVM_SYNC_ETOKEN)) {
+        cs->kvm_run->s.regs.etoken = env->etoken;
+        cs->kvm_run->s.regs.etoken_extension  = env->etoken_extension;
+        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_ETOKEN;
+    }
+
+    if (can_sync_regs(cs, KVM_SYNC_DIAG318)) {
+        cs->kvm_run->s.regs.diag318 = env->diag318_info;
+        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_DIAG318;
+    }
+
+    /* Finally the prefix */
+    if (can_sync_regs(cs, KVM_SYNC_PREFIX)) {
+        cs->kvm_run->s.regs.prefix = env->psa;
+        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_PREFIX;
+    } else {
+        /* prefix is only supported via sync regs */
+    }
+    return 0;
+}
+
+int kvm_arch_get_registers(CPUState *cs)
+{
+    S390CPU *cpu = S390_CPU(cs);
+    CPUS390XState *env = &cpu->env;
+    struct kvm_sregs sregs;
+    struct kvm_regs regs;
+    struct kvm_fpu fpu;
+    int i, r;
+
+    /* get the PSW */
+    env->psw.addr = cs->kvm_run->psw_addr;
+    env->psw.mask = cs->kvm_run->psw_mask;
+
+    /* the GPRS */
+    if (can_sync_regs(cs, KVM_SYNC_GPRS)) {
+        for (i = 0; i < 16; i++) {
+            env->regs[i] = cs->kvm_run->s.regs.gprs[i];
+        }
+    } else {
+        r = kvm_vcpu_ioctl(cs, KVM_GET_REGS, &regs);
+        if (r < 0) {
+            return r;
+        }
+         for (i = 0; i < 16; i++) {
+            env->regs[i] = regs.gprs[i];
+        }
+    }
+
+    /* The ACRS and CRS */
+    if (can_sync_regs(cs, KVM_SYNC_ACRS | KVM_SYNC_CRS)) {
+        for (i = 0; i < 16; i++) {
+            env->aregs[i] = cs->kvm_run->s.regs.acrs[i];
+            env->cregs[i] = cs->kvm_run->s.regs.crs[i];
+        }
+    } else {
+        r = kvm_vcpu_ioctl(cs, KVM_GET_SREGS, &sregs);
+        if (r < 0) {
+            return r;
+        }
+         for (i = 0; i < 16; i++) {
+            env->aregs[i] = sregs.acrs[i];
+            env->cregs[i] = sregs.crs[i];
+        }
+    }
+
+    /* Floating point and vector registers */
+    if (can_sync_regs(cs, KVM_SYNC_VRS)) {
+        for (i = 0; i < 32; i++) {
+            env->vregs[i][0] = cs->kvm_run->s.regs.vrs[i][0];
+            env->vregs[i][1] = cs->kvm_run->s.regs.vrs[i][1];
+        }
+        env->fpc = cs->kvm_run->s.regs.fpc;
+    } else if (can_sync_regs(cs, KVM_SYNC_FPRS)) {
+        for (i = 0; i < 16; i++) {
+            *get_freg(env, i) = cs->kvm_run->s.regs.fprs[i];
+        }
+        env->fpc = cs->kvm_run->s.regs.fpc;
+    } else {
+        r = kvm_vcpu_ioctl(cs, KVM_GET_FPU, &fpu);
+        if (r < 0) {
+            return r;
+        }
+        for (i = 0; i < 16; i++) {
+            *get_freg(env, i) = fpu.fprs[i];
+        }
+        env->fpc = fpu.fpc;
+    }
+
+    /* The prefix */
+    if (can_sync_regs(cs, KVM_SYNC_PREFIX)) {
+        env->psa = cs->kvm_run->s.regs.prefix;
+    }
+
+    if (can_sync_regs(cs, KVM_SYNC_ARCH0)) {
+        env->cputm = cs->kvm_run->s.regs.cputm;
+        env->ckc = cs->kvm_run->s.regs.ckc;
+        env->todpr = cs->kvm_run->s.regs.todpr;
+        env->gbea = cs->kvm_run->s.regs.gbea;
+        env->pp = cs->kvm_run->s.regs.pp;
+    } else {
+        /*
+         * These ONE_REGS are not protected by a capability. As they are only
+         * necessary for migration we just trace a possible error, but don't
+         * return with an error return code.
+         */
+        kvm_get_one_reg(cs, KVM_REG_S390_CPU_TIMER, &env->cputm);
+        kvm_get_one_reg(cs, KVM_REG_S390_CLOCK_COMP, &env->ckc);
+        kvm_get_one_reg(cs, KVM_REG_S390_TODPR, &env->todpr);
+        kvm_get_one_reg(cs, KVM_REG_S390_GBEA, &env->gbea);
+        kvm_get_one_reg(cs, KVM_REG_S390_PP, &env->pp);
+    }
+
+    if (can_sync_regs(cs, KVM_SYNC_RICCB)) {
+        memcpy(env->riccb, cs->kvm_run->s.regs.riccb, 64);
+    }
+
+    if (can_sync_regs(cs, KVM_SYNC_GSCB)) {
+        memcpy(env->gscb, cs->kvm_run->s.regs.gscb, 32);
+    }
+
+    if (can_sync_regs(cs, KVM_SYNC_BPBC)) {
+        env->bpbc = cs->kvm_run->s.regs.bpbc;
+    }
+
+    if (can_sync_regs(cs, KVM_SYNC_ETOKEN)) {
+        env->etoken = cs->kvm_run->s.regs.etoken;
+        env->etoken_extension = cs->kvm_run->s.regs.etoken_extension;
+    }
+
+    /* pfault parameters */
+    if (can_sync_regs(cs, KVM_SYNC_PFAULT)) {
+        env->pfault_token = cs->kvm_run->s.regs.pft;
+        env->pfault_select = cs->kvm_run->s.regs.pfs;
+        env->pfault_compare = cs->kvm_run->s.regs.pfc;
+    } else if (cap_async_pf) {
+        r = kvm_get_one_reg(cs, KVM_REG_S390_PFTOKEN, &env->pfault_token);
+        if (r < 0) {
+            return r;
+        }
+        r = kvm_get_one_reg(cs, KVM_REG_S390_PFCOMPARE, &env->pfault_compare);
+        if (r < 0) {
+            return r;
+        }
+        r = kvm_get_one_reg(cs, KVM_REG_S390_PFSELECT, &env->pfault_select);
+        if (r < 0) {
+            return r;
+        }
+    }
+
+    if (can_sync_regs(cs, KVM_SYNC_DIAG318)) {
+        env->diag318_info = cs->kvm_run->s.regs.diag318;
+    }
+
+    return 0;
+}
+
+int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_low)
+{
+    int r;
+    struct kvm_device_attr attr = {
+        .group = KVM_S390_VM_TOD,
+        .attr = KVM_S390_VM_TOD_LOW,
+        .addr = (uint64_t)tod_low,
+    };
+
+    r = kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
+    if (r) {
+        return r;
+    }
+
+    attr.attr = KVM_S390_VM_TOD_HIGH;
+    attr.addr = (uint64_t)tod_high;
+    return kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
+}
+
+int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_low)
+{
+    int r;
+    struct kvm_s390_vm_tod_clock gtod;
+    struct kvm_device_attr attr = {
+        .group = KVM_S390_VM_TOD,
+        .attr = KVM_S390_VM_TOD_EXT,
+        .addr = (uint64_t)&gtod,
+    };
+
+    r = kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
+    *tod_high = gtod.epoch_idx;
+    *tod_low  = gtod.tod;
+
+    return r;
+}
+
+int kvm_s390_set_clock(uint8_t tod_high, uint64_t tod_low)
+{
+    int r;
+    struct kvm_device_attr attr = {
+        .group = KVM_S390_VM_TOD,
+        .attr = KVM_S390_VM_TOD_LOW,
+        .addr = (uint64_t)&tod_low,
+    };
+
+    r = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
+    if (r) {
+        return r;
+    }
+
+    attr.attr = KVM_S390_VM_TOD_HIGH;
+    attr.addr = (uint64_t)&tod_high;
+    return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
+}
+
+int kvm_s390_set_clock_ext(uint8_t tod_high, uint64_t tod_low)
+{
+    struct kvm_s390_vm_tod_clock gtod = {
+        .epoch_idx = tod_high,
+        .tod  = tod_low,
+    };
+    struct kvm_device_attr attr = {
+        .group = KVM_S390_VM_TOD,
+        .attr = KVM_S390_VM_TOD_EXT,
+        .addr = (uint64_t)&gtod,
+    };
+
+    return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
+}
+
+/**
+ * kvm_s390_mem_op:
+ * @addr:      the logical start address in guest memory
+ * @ar:        the access register number
+ * @hostbuf:   buffer in host memory. NULL = do only checks w/o copying
+ * @len:       length that should be transferred
+ * @is_write:  true = write, false = read
+ * Returns:    0 on success, non-zero if an exception or error occurred
+ *
+ * Use KVM ioctl to read/write from/to guest memory. An access exception
+ * is injected into the vCPU in case of translation errors.
+ */
+int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf,
+                    int len, bool is_write)
+{
+    struct kvm_s390_mem_op mem_op = {
+        .gaddr = addr,
+        .flags = KVM_S390_MEMOP_F_INJECT_EXCEPTION,
+        .size = len,
+        .op = is_write ? KVM_S390_MEMOP_LOGICAL_WRITE
+                       : KVM_S390_MEMOP_LOGICAL_READ,
+        .buf = (uint64_t)hostbuf,
+        .ar = ar,
+    };
+    int ret;
+
+    if (!cap_mem_op) {
+        return -ENOSYS;
+    }
+    if (!hostbuf) {
+        mem_op.flags |= KVM_S390_MEMOP_F_CHECK_ONLY;
+    }
+
+    ret = kvm_vcpu_ioctl(CPU(cpu), KVM_S390_MEM_OP, &mem_op);
+    if (ret < 0) {
+        warn_report("KVM_S390_MEM_OP failed: %s", strerror(-ret));
+    }
+    return ret;
+}
+
+int kvm_s390_mem_op_pv(S390CPU *cpu, uint64_t offset, void *hostbuf,
+                       int len, bool is_write)
+{
+    struct kvm_s390_mem_op mem_op = {
+        .sida_offset = offset,
+        .size = len,
+        .op = is_write ? KVM_S390_MEMOP_SIDA_WRITE
+                       : KVM_S390_MEMOP_SIDA_READ,
+        .buf = (uint64_t)hostbuf,
+    };
+    int ret;
+
+    if (!cap_mem_op || !cap_protected) {
+        return -ENOSYS;
+    }
+
+    ret = kvm_vcpu_ioctl(CPU(cpu), KVM_S390_MEM_OP, &mem_op);
+    if (ret < 0) {
+        error_report("KVM_S390_MEM_OP failed: %s", strerror(-ret));
+        abort();
+    }
+    return ret;
+}
+
+static uint8_t const *sw_bp_inst;
+static uint8_t sw_bp_ilen;
+
+static void determine_sw_breakpoint_instr(void)
+{
+        /* DIAG 501 is used for sw breakpoints with old kernels */
+        static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
+        /* Instruction 0x0000 is used for sw breakpoints with recent kernels */
+        static const uint8_t instr_0x0000[] = {0x00, 0x00};
+
+        if (sw_bp_inst) {
+            return;
+        }
+        if (kvm_vm_enable_cap(kvm_state, KVM_CAP_S390_USER_INSTR0, 0)) {
+            sw_bp_inst = diag_501;
+            sw_bp_ilen = sizeof(diag_501);
+            DPRINTF("KVM: will use 4-byte sw breakpoints.\n");
+        } else {
+            sw_bp_inst = instr_0x0000;
+            sw_bp_ilen = sizeof(instr_0x0000);
+            DPRINTF("KVM: will use 2-byte sw breakpoints.\n");
+        }
+}
+
+int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+{
+    determine_sw_breakpoint_instr();
+
+    if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn,
+                            sw_bp_ilen, 0) ||
+        cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)sw_bp_inst, sw_bp_ilen, 1)) {
+        return -EINVAL;
+    }
+    return 0;
+}
+
+int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+{
+    uint8_t t[MAX_ILEN];
+
+    if (cpu_memory_rw_debug(cs, bp->pc, t, sw_bp_ilen, 0)) {
+        return -EINVAL;
+    } else if (memcmp(t, sw_bp_inst, sw_bp_ilen)) {
+        return -EINVAL;
+    } else if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn,
+                                   sw_bp_ilen, 1)) {
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static struct kvm_hw_breakpoint *find_hw_breakpoint(target_ulong addr,
+                                                    int len, int type)
+{
+    int n;
+
+    for (n = 0; n < nb_hw_breakpoints; n++) {
+        if (hw_breakpoints[n].addr == addr && hw_breakpoints[n].type == type &&
+            (hw_breakpoints[n].len == len || len == -1)) {
+            return &hw_breakpoints[n];
+        }
+    }
+
+    return NULL;
+}
+
+static int insert_hw_breakpoint(target_ulong addr, int len, int type)
+{
+    int size;
+
+    if (find_hw_breakpoint(addr, len, type)) {
+        return -EEXIST;
+    }
+
+    size = (nb_hw_breakpoints + 1) * sizeof(struct kvm_hw_breakpoint);
+
+    if (!hw_breakpoints) {
+        nb_hw_breakpoints = 0;
+        hw_breakpoints = (struct kvm_hw_breakpoint *)g_try_malloc(size);
+    } else {
+        hw_breakpoints =
+            (struct kvm_hw_breakpoint *)g_try_realloc(hw_breakpoints, size);
+    }
+
+    if (!hw_breakpoints) {
+        nb_hw_breakpoints = 0;
+        return -ENOMEM;
+    }
+
+    hw_breakpoints[nb_hw_breakpoints].addr = addr;
+    hw_breakpoints[nb_hw_breakpoints].len = len;
+    hw_breakpoints[nb_hw_breakpoints].type = type;
+
+    nb_hw_breakpoints++;
+
+    return 0;
+}
+
+int kvm_arch_insert_hw_breakpoint(target_ulong addr,
+                                  target_ulong len, int type)
+{
+    switch (type) {
+    case GDB_BREAKPOINT_HW:
+        type = KVM_HW_BP;
+        break;
+    case GDB_WATCHPOINT_WRITE:
+        if (len < 1) {
+            return -EINVAL;
+        }
+        type = KVM_HW_WP_WRITE;
+        break;
+    default:
+        return -ENOSYS;
+    }
+    return insert_hw_breakpoint(addr, len, type);
+}
+
+int kvm_arch_remove_hw_breakpoint(target_ulong addr,
+                                  target_ulong len, int type)
+{
+    int size;
+    struct kvm_hw_breakpoint *bp = find_hw_breakpoint(addr, len, type);
+
+    if (bp == NULL) {
+        return -ENOENT;
+    }
+
+    nb_hw_breakpoints--;
+    if (nb_hw_breakpoints > 0) {
+        /*
+         * In order to trim the array, move the last element to the position to
+         * be removed - if necessary.
+         */
+        if (bp != &hw_breakpoints[nb_hw_breakpoints]) {
+            *bp = hw_breakpoints[nb_hw_breakpoints];
+        }
+        size = nb_hw_breakpoints * sizeof(struct kvm_hw_breakpoint);
+        hw_breakpoints =
+             (struct kvm_hw_breakpoint *)g_realloc(hw_breakpoints, size);
+    } else {
+        g_free(hw_breakpoints);
+        hw_breakpoints = NULL;
+    }
+
+    return 0;
+}
+
+void kvm_arch_remove_all_hw_breakpoints(void)
+{
+    nb_hw_breakpoints = 0;
+    g_free(hw_breakpoints);
+    hw_breakpoints = NULL;
+}
+
+void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
+{
+    int i;
+
+    if (nb_hw_breakpoints > 0) {
+        dbg->arch.nr_hw_bp = nb_hw_breakpoints;
+        dbg->arch.hw_bp = hw_breakpoints;
+
+        for (i = 0; i < nb_hw_breakpoints; ++i) {
+            hw_breakpoints[i].phys_addr = s390_cpu_get_phys_addr_debug(cpu,
+                                                       hw_breakpoints[i].addr);
+        }
+        dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP;
+    } else {
+        dbg->arch.nr_hw_bp = 0;
+        dbg->arch.hw_bp = NULL;
+    }
+}
+
+void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run)
+{
+}
+
+MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
+{
+    return MEMTXATTRS_UNSPECIFIED;
+}
+
+int kvm_arch_process_async_events(CPUState *cs)
+{
+    return cs->halted;
+}
+
+static int s390_kvm_irq_to_interrupt(struct kvm_s390_irq *irq,
+                                     struct kvm_s390_interrupt *interrupt)
+{
+    int r = 0;
+
+    interrupt->type = irq->type;
+    switch (irq->type) {
+    case KVM_S390_INT_VIRTIO:
+        interrupt->parm = irq->u.ext.ext_params;
+        /* fall through */
+    case KVM_S390_INT_PFAULT_INIT:
+    case KVM_S390_INT_PFAULT_DONE:
+        interrupt->parm64 = irq->u.ext.ext_params2;
+        break;
+    case KVM_S390_PROGRAM_INT:
+        interrupt->parm = irq->u.pgm.code;
+        break;
+    case KVM_S390_SIGP_SET_PREFIX:
+        interrupt->parm = irq->u.prefix.address;
+        break;
+    case KVM_S390_INT_SERVICE:
+        interrupt->parm = irq->u.ext.ext_params;
+        break;
+    case KVM_S390_MCHK:
+        interrupt->parm = irq->u.mchk.cr14;
+        interrupt->parm64 = irq->u.mchk.mcic;
+        break;
+    case KVM_S390_INT_EXTERNAL_CALL:
+        interrupt->parm = irq->u.extcall.code;
+        break;
+    case KVM_S390_INT_EMERGENCY:
+        interrupt->parm = irq->u.emerg.code;
+        break;
+    case KVM_S390_SIGP_STOP:
+    case KVM_S390_RESTART:
+        break; /* These types have no parameters */
+    case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
+        interrupt->parm = irq->u.io.subchannel_id << 16;
+        interrupt->parm |= irq->u.io.subchannel_nr;
+        interrupt->parm64 = (uint64_t)irq->u.io.io_int_parm << 32;
+        interrupt->parm64 |= irq->u.io.io_int_word;
+        break;
+    default:
+        r = -EINVAL;
+        break;
+    }
+    return r;
+}
+
+static void inject_vcpu_irq_legacy(CPUState *cs, struct kvm_s390_irq *irq)
+{
+    struct kvm_s390_interrupt kvmint = {};
+    int r;
+
+    r = s390_kvm_irq_to_interrupt(irq, &kvmint);
+    if (r < 0) {
+        fprintf(stderr, "%s called with bogus interrupt\n", __func__);
+        exit(1);
+    }
+
+    r = kvm_vcpu_ioctl(cs, KVM_S390_INTERRUPT, &kvmint);
+    if (r < 0) {
+        fprintf(stderr, "KVM failed to inject interrupt\n");
+        exit(1);
+    }
+}
+
+void kvm_s390_vcpu_interrupt(S390CPU *cpu, struct kvm_s390_irq *irq)
+{
+    CPUState *cs = CPU(cpu);
+    int r;
+
+    if (cap_s390_irq) {
+        r = kvm_vcpu_ioctl(cs, KVM_S390_IRQ, irq);
+        if (!r) {
+            return;
+        }
+        error_report("KVM failed to inject interrupt %llx", irq->type);
+        exit(1);
+    }
+
+    inject_vcpu_irq_legacy(cs, irq);
+}
+
+void kvm_s390_floating_interrupt_legacy(struct kvm_s390_irq *irq)
+{
+    struct kvm_s390_interrupt kvmint = {};
+    int r;
+
+    r = s390_kvm_irq_to_interrupt(irq, &kvmint);
+    if (r < 0) {
+        fprintf(stderr, "%s called with bogus interrupt\n", __func__);
+        exit(1);
+    }
+
+    r = kvm_vm_ioctl(kvm_state, KVM_S390_INTERRUPT, &kvmint);
+    if (r < 0) {
+        fprintf(stderr, "KVM failed to inject interrupt\n");
+        exit(1);
+    }
+}
+
+void kvm_s390_program_interrupt(S390CPU *cpu, uint16_t code)
+{
+    struct kvm_s390_irq irq = {
+        .type = KVM_S390_PROGRAM_INT,
+        .u.pgm.code = code,
+    };
+    qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
+                  cpu->env.psw.addr);
+    kvm_s390_vcpu_interrupt(cpu, &irq);
+}
+
+void kvm_s390_access_exception(S390CPU *cpu, uint16_t code, uint64_t te_code)
+{
+    struct kvm_s390_irq irq = {
+        .type = KVM_S390_PROGRAM_INT,
+        .u.pgm.code = code,
+        .u.pgm.trans_exc_code = te_code,
+        .u.pgm.exc_access_id = te_code & 3,
+    };
+
+    kvm_s390_vcpu_interrupt(cpu, &irq);
+}
+
+static void kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run,
+                                 uint16_t ipbh0)
+{
+    CPUS390XState *env = &cpu->env;
+    uint64_t sccb;
+    uint32_t code;
+    int r;
+
+    sccb = env->regs[ipbh0 & 0xf];
+    code = env->regs[(ipbh0 & 0xf0) >> 4];
+
+    switch (run->s390_sieic.icptcode) {
+    case ICPT_PV_INSTR_NOTIFICATION:
+        g_assert(s390_is_pv());
+        /* The notification intercepts are currently handled by KVM */
+        error_report("unexpected SCLP PV notification");
+        exit(1);
+        break;
+    case ICPT_PV_INSTR:
+        g_assert(s390_is_pv());
+        sclp_service_call_protected(env, sccb, code);
+        /* Setting the CC is done by the Ultravisor. */
+        break;
+    case ICPT_INSTRUCTION:
+        g_assert(!s390_is_pv());
+        r = sclp_service_call(env, sccb, code);
+        if (r < 0) {
+            kvm_s390_program_interrupt(cpu, -r);
+            return;
+        }
+        setcc(cpu, r);
+    }
+}
+
+static int handle_b2(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
+{
+    CPUS390XState *env = &cpu->env;
+    int rc = 0;
+    uint16_t ipbh0 = (run->s390_sieic.ipb & 0xffff0000) >> 16;
+
+    switch (ipa1) {
+    case PRIV_B2_XSCH:
+        ioinst_handle_xsch(cpu, env->regs[1], RA_IGNORED);
+        break;
+    case PRIV_B2_CSCH:
+        ioinst_handle_csch(cpu, env->regs[1], RA_IGNORED);
+        break;
+    case PRIV_B2_HSCH:
+        ioinst_handle_hsch(cpu, env->regs[1], RA_IGNORED);
+        break;
+    case PRIV_B2_MSCH:
+        ioinst_handle_msch(cpu, env->regs[1], run->s390_sieic.ipb, RA_IGNORED);
+        break;
+    case PRIV_B2_SSCH:
+        ioinst_handle_ssch(cpu, env->regs[1], run->s390_sieic.ipb, RA_IGNORED);
+        break;
+    case PRIV_B2_STCRW:
+        ioinst_handle_stcrw(cpu, run->s390_sieic.ipb, RA_IGNORED);
+        break;
+    case PRIV_B2_STSCH:
+        ioinst_handle_stsch(cpu, env->regs[1], run->s390_sieic.ipb, RA_IGNORED);
+        break;
+    case PRIV_B2_TSCH:
+        /* We should only get tsch via KVM_EXIT_S390_TSCH. */
+        fprintf(stderr, "Spurious tsch intercept\n");
+        break;
+    case PRIV_B2_CHSC:
+        ioinst_handle_chsc(cpu, run->s390_sieic.ipb, RA_IGNORED);
+        break;
+    case PRIV_B2_TPI:
+        /* This should have been handled by kvm already. */
+        fprintf(stderr, "Spurious tpi intercept\n");
+        break;
+    case PRIV_B2_SCHM:
+        ioinst_handle_schm(cpu, env->regs[1], env->regs[2],
+                           run->s390_sieic.ipb, RA_IGNORED);
+        break;
+    case PRIV_B2_RSCH:
+        ioinst_handle_rsch(cpu, env->regs[1], RA_IGNORED);
+        break;
+    case PRIV_B2_RCHP:
+        ioinst_handle_rchp(cpu, env->regs[1], RA_IGNORED);
+        break;
+    case PRIV_B2_STCPS:
+        /* We do not provide this instruction, it is suppressed. */
+        break;
+    case PRIV_B2_SAL:
+        ioinst_handle_sal(cpu, env->regs[1], RA_IGNORED);
+        break;
+    case PRIV_B2_SIGA:
+        /* Not provided, set CC = 3 for subchannel not operational */
+        setcc(cpu, 3);
+        break;
+    case PRIV_B2_SCLP_CALL:
+        kvm_sclp_service_call(cpu, run, ipbh0);
+        break;
+    default:
+        rc = -1;
+        DPRINTF("KVM: unhandled PRIV: 0xb2%x\n", ipa1);
+        break;
+    }
+
+    return rc;
+}
+
+static uint64_t get_base_disp_rxy(S390CPU *cpu, struct kvm_run *run,
+                                  uint8_t *ar)
+{
+    CPUS390XState *env = &cpu->env;
+    uint32_t x2 = (run->s390_sieic.ipa & 0x000f);
+    uint32_t base2 = run->s390_sieic.ipb >> 28;
+    uint32_t disp2 = ((run->s390_sieic.ipb & 0x0fff0000) >> 16) +
+                     ((run->s390_sieic.ipb & 0xff00) << 4);
+
+    if (disp2 & 0x80000) {
+        disp2 += 0xfff00000;
+    }
+    if (ar) {
+        *ar = base2;
+    }
+
+    return (base2 ? env->regs[base2] : 0) +
+           (x2 ? env->regs[x2] : 0) + (long)(int)disp2;
+}
+
+static uint64_t get_base_disp_rsy(S390CPU *cpu, struct kvm_run *run,
+                                  uint8_t *ar)
+{
+    CPUS390XState *env = &cpu->env;
+    uint32_t base2 = run->s390_sieic.ipb >> 28;
+    uint32_t disp2 = ((run->s390_sieic.ipb & 0x0fff0000) >> 16) +
+                     ((run->s390_sieic.ipb & 0xff00) << 4);
+
+    if (disp2 & 0x80000) {
+        disp2 += 0xfff00000;
+    }
+    if (ar) {
+        *ar = base2;
+    }
+
+    return (base2 ? env->regs[base2] : 0) + (long)(int)disp2;
+}
+
+static int kvm_clp_service_call(S390CPU *cpu, struct kvm_run *run)
+{
+    uint8_t r2 = (run->s390_sieic.ipb & 0x000f0000) >> 16;
+
+    if (s390_has_feat(S390_FEAT_ZPCI)) {
+        return clp_service_call(cpu, r2, RA_IGNORED);
+    } else {
+        return -1;
+    }
+}
+
+static int kvm_pcilg_service_call(S390CPU *cpu, struct kvm_run *run)
+{
+    uint8_t r1 = (run->s390_sieic.ipb & 0x00f00000) >> 20;
+    uint8_t r2 = (run->s390_sieic.ipb & 0x000f0000) >> 16;
+
+    if (s390_has_feat(S390_FEAT_ZPCI)) {
+        return pcilg_service_call(cpu, r1, r2, RA_IGNORED);
+    } else {
+        return -1;
+    }
+}
+
+static int kvm_pcistg_service_call(S390CPU *cpu, struct kvm_run *run)
+{
+    uint8_t r1 = (run->s390_sieic.ipb & 0x00f00000) >> 20;
+    uint8_t r2 = (run->s390_sieic.ipb & 0x000f0000) >> 16;
+
+    if (s390_has_feat(S390_FEAT_ZPCI)) {
+        return pcistg_service_call(cpu, r1, r2, RA_IGNORED);
+    } else {
+        return -1;
+    }
+}
+
+static int kvm_stpcifc_service_call(S390CPU *cpu, struct kvm_run *run)
+{
+    uint8_t r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
+    uint64_t fiba;
+    uint8_t ar;
+
+    if (s390_has_feat(S390_FEAT_ZPCI)) {
+        fiba = get_base_disp_rxy(cpu, run, &ar);
+
+        return stpcifc_service_call(cpu, r1, fiba, ar, RA_IGNORED);
+    } else {
+        return -1;
+    }
+}
+
+static int kvm_sic_service_call(S390CPU *cpu, struct kvm_run *run)
+{
+    CPUS390XState *env = &cpu->env;
+    uint8_t r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
+    uint8_t r3 = run->s390_sieic.ipa & 0x000f;
+    uint8_t isc;
+    uint16_t mode;
+    int r;
+
+    mode = env->regs[r1] & 0xffff;
+    isc = (env->regs[r3] >> 27) & 0x7;
+    r = css_do_sic(env, isc, mode);
+    if (r) {
+        kvm_s390_program_interrupt(cpu, -r);
+    }
+
+    return 0;
+}
+
+static int kvm_rpcit_service_call(S390CPU *cpu, struct kvm_run *run)
+{
+    uint8_t r1 = (run->s390_sieic.ipb & 0x00f00000) >> 20;
+    uint8_t r2 = (run->s390_sieic.ipb & 0x000f0000) >> 16;
+
+    if (s390_has_feat(S390_FEAT_ZPCI)) {
+        return rpcit_service_call(cpu, r1, r2, RA_IGNORED);
+    } else {
+        return -1;
+    }
+}
+
+static int kvm_pcistb_service_call(S390CPU *cpu, struct kvm_run *run)
+{
+    uint8_t r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
+    uint8_t r3 = run->s390_sieic.ipa & 0x000f;
+    uint64_t gaddr;
+    uint8_t ar;
+
+    if (s390_has_feat(S390_FEAT_ZPCI)) {
+        gaddr = get_base_disp_rsy(cpu, run, &ar);
+
+        return pcistb_service_call(cpu, r1, r3, gaddr, ar, RA_IGNORED);
+    } else {
+        return -1;
+    }
+}
+
+static int kvm_mpcifc_service_call(S390CPU *cpu, struct kvm_run *run)
+{
+    uint8_t r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
+    uint64_t fiba;
+    uint8_t ar;
+
+    if (s390_has_feat(S390_FEAT_ZPCI)) {
+        fiba = get_base_disp_rxy(cpu, run, &ar);
+
+        return mpcifc_service_call(cpu, r1, fiba, ar, RA_IGNORED);
+    } else {
+        return -1;
+    }
+}
+
+static int handle_b9(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
+{
+    int r = 0;
+
+    switch (ipa1) {
+    case PRIV_B9_CLP:
+        r = kvm_clp_service_call(cpu, run);
+        break;
+    case PRIV_B9_PCISTG:
+        r = kvm_pcistg_service_call(cpu, run);
+        break;
+    case PRIV_B9_PCILG:
+        r = kvm_pcilg_service_call(cpu, run);
+        break;
+    case PRIV_B9_RPCIT:
+        r = kvm_rpcit_service_call(cpu, run);
+        break;
+    case PRIV_B9_EQBS:
+        /* just inject exception */
+        r = -1;
+        break;
+    default:
+        r = -1;
+        DPRINTF("KVM: unhandled PRIV: 0xb9%x\n", ipa1);
+        break;
+    }
+
+    return r;
+}
+
+static int handle_eb(S390CPU *cpu, struct kvm_run *run, uint8_t ipbl)
+{
+    int r = 0;
+
+    switch (ipbl) {
+    case PRIV_EB_PCISTB:
+        r = kvm_pcistb_service_call(cpu, run);
+        break;
+    case PRIV_EB_SIC:
+        r = kvm_sic_service_call(cpu, run);
+        break;
+    case PRIV_EB_SQBS:
+        /* just inject exception */
+        r = -1;
+        break;
+    default:
+        r = -1;
+        DPRINTF("KVM: unhandled PRIV: 0xeb%x\n", ipbl);
+        break;
+    }
+
+    return r;
+}
+
+static int handle_e3(S390CPU *cpu, struct kvm_run *run, uint8_t ipbl)
+{
+    int r = 0;
+
+    switch (ipbl) {
+    case PRIV_E3_MPCIFC:
+        r = kvm_mpcifc_service_call(cpu, run);
+        break;
+    case PRIV_E3_STPCIFC:
+        r = kvm_stpcifc_service_call(cpu, run);
+        break;
+    default:
+        r = -1;
+        DPRINTF("KVM: unhandled PRIV: 0xe3%x\n", ipbl);
+        break;
+    }
+
+    return r;
+}
+
+static int handle_hypercall(S390CPU *cpu, struct kvm_run *run)
+{
+    CPUS390XState *env = &cpu->env;
+    int ret;
+
+    ret = s390_virtio_hypercall(env);
+    if (ret == -EINVAL) {
+        kvm_s390_program_interrupt(cpu, PGM_SPECIFICATION);
+        return 0;
+    }
+
+    return ret;
+}
+
+static void kvm_handle_diag_288(S390CPU *cpu, struct kvm_run *run)
+{
+    uint64_t r1, r3;
+    int rc;
+
+    r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
+    r3 = run->s390_sieic.ipa & 0x000f;
+    rc = handle_diag_288(&cpu->env, r1, r3);
+    if (rc) {
+        kvm_s390_program_interrupt(cpu, PGM_SPECIFICATION);
+    }
+}
+
+static void kvm_handle_diag_308(S390CPU *cpu, struct kvm_run *run)
+{
+    uint64_t r1, r3;
+
+    r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
+    r3 = run->s390_sieic.ipa & 0x000f;
+    handle_diag_308(&cpu->env, r1, r3, RA_IGNORED);
+}
+
+static int handle_sw_breakpoint(S390CPU *cpu, struct kvm_run *run)
+{
+    CPUS390XState *env = &cpu->env;
+    unsigned long pc;
+
+    pc = env->psw.addr - sw_bp_ilen;
+    if (kvm_find_sw_breakpoint(CPU(cpu), pc)) {
+        env->psw.addr = pc;
+        return EXCP_DEBUG;
+    }
+
+    return -ENOENT;
+}
+
+void kvm_s390_set_diag318(CPUState *cs, uint64_t diag318_info)
+{
+    CPUS390XState *env = &S390_CPU(cs)->env;
+
+    /* Feat bit is set only if KVM supports sync for diag318 */
+    if (s390_has_feat(S390_FEAT_DIAG_318)) {
+        env->diag318_info = diag318_info;
+        cs->kvm_run->s.regs.diag318 = diag318_info;
+        cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_DIAG318;
+    }
+}
+
+static void handle_diag_318(S390CPU *cpu, struct kvm_run *run)
+{
+    uint64_t reg = (run->s390_sieic.ipa & 0x00f0) >> 4;
+    uint64_t diag318_info = run->s.regs.gprs[reg];
+    CPUState *t;
+
+    /*
+     * DIAG 318 can only be enabled with KVM support. As such, let's
+     * ensure a guest cannot execute this instruction erroneously.
+     */
+    if (!s390_has_feat(S390_FEAT_DIAG_318)) {
+        kvm_s390_program_interrupt(cpu, PGM_SPECIFICATION);
+        return;
+    }
+
+    CPU_FOREACH(t) {
+        run_on_cpu(t, s390_do_cpu_set_diag318,
+                   RUN_ON_CPU_HOST_ULONG(diag318_info));
+    }
+}
+
+#define DIAG_KVM_CODE_MASK 0x000000000000ffff
+
+static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb)
+{
+    int r = 0;
+    uint16_t func_code;
+
+    /*
+     * For any diagnose call we support, bits 48-63 of the resulting
+     * address specify the function code; the remainder is ignored.
+     */
+    func_code = decode_basedisp_rs(&cpu->env, ipb, NULL) & DIAG_KVM_CODE_MASK;
+    switch (func_code) {
+    case DIAG_TIMEREVENT:
+        kvm_handle_diag_288(cpu, run);
+        break;
+    case DIAG_IPL:
+        kvm_handle_diag_308(cpu, run);
+        break;
+    case DIAG_SET_CONTROL_PROGRAM_CODES:
+        handle_diag_318(cpu, run);
+        break;
+    case DIAG_KVM_HYPERCALL:
+        r = handle_hypercall(cpu, run);
+        break;
+    case DIAG_KVM_BREAKPOINT:
+        r = handle_sw_breakpoint(cpu, run);
+        break;
+    default:
+        DPRINTF("KVM: unknown DIAG: 0x%x\n", func_code);
+        kvm_s390_program_interrupt(cpu, PGM_SPECIFICATION);
+        break;
+    }
+
+    return r;
+}
+
+static int kvm_s390_handle_sigp(S390CPU *cpu, uint8_t ipa1, uint32_t ipb)
+{
+    CPUS390XState *env = &cpu->env;
+    const uint8_t r1 = ipa1 >> 4;
+    const uint8_t r3 = ipa1 & 0x0f;
+    int ret;
+    uint8_t order;
+
+    /* get order code */
+    order = decode_basedisp_rs(env, ipb, NULL) & SIGP_ORDER_MASK;
+
+    ret = handle_sigp(env, order, r1, r3);
+    setcc(cpu, ret);
+    return 0;
+}
+
+static int handle_instruction(S390CPU *cpu, struct kvm_run *run)
+{
+    unsigned int ipa0 = (run->s390_sieic.ipa & 0xff00);
+    uint8_t ipa1 = run->s390_sieic.ipa & 0x00ff;
+    int r = -1;
+
+    DPRINTF("handle_instruction 0x%x 0x%x\n",
+            run->s390_sieic.ipa, run->s390_sieic.ipb);
+    switch (ipa0) {
+    case IPA0_B2:
+        r = handle_b2(cpu, run, ipa1);
+        break;
+    case IPA0_B9:
+        r = handle_b9(cpu, run, ipa1);
+        break;
+    case IPA0_EB:
+        r = handle_eb(cpu, run, run->s390_sieic.ipb & 0xff);
+        break;
+    case IPA0_E3:
+        r = handle_e3(cpu, run, run->s390_sieic.ipb & 0xff);
+        break;
+    case IPA0_DIAG:
+        r = handle_diag(cpu, run, run->s390_sieic.ipb);
+        break;
+    case IPA0_SIGP:
+        r = kvm_s390_handle_sigp(cpu, ipa1, run->s390_sieic.ipb);
+        break;
+    }
+
+    if (r < 0) {
+        r = 0;
+        kvm_s390_program_interrupt(cpu, PGM_OPERATION);
+    }
+
+    return r;
+}
+
+static void unmanageable_intercept(S390CPU *cpu, S390CrashReason reason,
+                                   int pswoffset)
+{
+    CPUState *cs = CPU(cpu);
+
+    s390_cpu_halt(cpu);
+    cpu->env.crash_reason = reason;
+    qemu_system_guest_panicked(cpu_get_crash_info(cs));
+}
+
+/* try to detect pgm check loops */
+static int handle_oper_loop(S390CPU *cpu, struct kvm_run *run)
+{
+    CPUState *cs = CPU(cpu);
+    PSW oldpsw, newpsw;
+
+    newpsw.mask = ldq_phys(cs->as, cpu->env.psa +
+                           offsetof(LowCore, program_new_psw));
+    newpsw.addr = ldq_phys(cs->as, cpu->env.psa +
+                           offsetof(LowCore, program_new_psw) + 8);
+    oldpsw.mask  = run->psw_mask;
+    oldpsw.addr  = run->psw_addr;
+    /*
+     * Avoid endless loops of operation exceptions, if the pgm new
+     * PSW will cause a new operation exception.
+     * The heuristic checks if the pgm new psw is within 6 bytes before
+     * the faulting psw address (with same DAT, AS settings) and the
+     * new psw is not a wait psw and the fault was not triggered by
+     * problem state. In that case go into crashed state.
+     */
+
+    if (oldpsw.addr - newpsw.addr <= 6 &&
+        !(newpsw.mask & PSW_MASK_WAIT) &&
+        !(oldpsw.mask & PSW_MASK_PSTATE) &&
+        (newpsw.mask & PSW_MASK_ASC) == (oldpsw.mask & PSW_MASK_ASC) &&
+        (newpsw.mask & PSW_MASK_DAT) == (oldpsw.mask & PSW_MASK_DAT)) {
+        unmanageable_intercept(cpu, S390_CRASH_REASON_OPINT_LOOP,
+                               offsetof(LowCore, program_new_psw));
+        return EXCP_HALTED;
+    }
+    return 0;
+}
+
+static int handle_intercept(S390CPU *cpu)
+{
+    CPUState *cs = CPU(cpu);
+    struct kvm_run *run = cs->kvm_run;
+    int icpt_code = run->s390_sieic.icptcode;
+    int r = 0;
+
+    DPRINTF("intercept: 0x%x (at 0x%lx)\n", icpt_code, (long)run->psw_addr);
+    switch (icpt_code) {
+        case ICPT_INSTRUCTION:
+        case ICPT_PV_INSTR:
+        case ICPT_PV_INSTR_NOTIFICATION:
+            r = handle_instruction(cpu, run);
+            break;
+        case ICPT_PROGRAM:
+            unmanageable_intercept(cpu, S390_CRASH_REASON_PGMINT_LOOP,
+                                   offsetof(LowCore, program_new_psw));
+            r = EXCP_HALTED;
+            break;
+        case ICPT_EXT_INT:
+            unmanageable_intercept(cpu, S390_CRASH_REASON_EXTINT_LOOP,
+                                   offsetof(LowCore, external_new_psw));
+            r = EXCP_HALTED;
+            break;
+        case ICPT_WAITPSW:
+            /* disabled wait, since enabled wait is handled in kernel */
+            s390_handle_wait(cpu);
+            r = EXCP_HALTED;
+            break;
+        case ICPT_CPU_STOP:
+            do_stop_interrupt(&cpu->env);
+            r = EXCP_HALTED;
+            break;
+        case ICPT_OPEREXC:
+            /* check for break points */
+            r = handle_sw_breakpoint(cpu, run);
+            if (r == -ENOENT) {
+                /* Then check for potential pgm check loops */
+                r = handle_oper_loop(cpu, run);
+                if (r == 0) {
+                    kvm_s390_program_interrupt(cpu, PGM_OPERATION);
+                }
+            }
+            break;
+        case ICPT_SOFT_INTERCEPT:
+            fprintf(stderr, "KVM unimplemented icpt SOFT\n");
+            exit(1);
+            break;
+        case ICPT_IO:
+            fprintf(stderr, "KVM unimplemented icpt IO\n");
+            exit(1);
+            break;
+        default:
+            fprintf(stderr, "Unknown intercept code: %d\n", icpt_code);
+            exit(1);
+            break;
+    }
+
+    return r;
+}
+
+static int handle_tsch(S390CPU *cpu)
+{
+    CPUState *cs = CPU(cpu);
+    struct kvm_run *run = cs->kvm_run;
+    int ret;
+
+    ret = ioinst_handle_tsch(cpu, cpu->env.regs[1], run->s390_tsch.ipb,
+                             RA_IGNORED);
+    if (ret < 0) {
+        /*
+         * Failure.
+         * If an I/O interrupt had been dequeued, we have to reinject it.
+         */
+        if (run->s390_tsch.dequeued) {
+            s390_io_interrupt(run->s390_tsch.subchannel_id,
+                              run->s390_tsch.subchannel_nr,
+                              run->s390_tsch.io_int_parm,
+                              run->s390_tsch.io_int_word);
+        }
+        ret = 0;
+    }
+    return ret;
+}
+
+static void insert_stsi_3_2_2(S390CPU *cpu, __u64 addr, uint8_t ar)
+{
+    const MachineState *ms = MACHINE(qdev_get_machine());
+    uint16_t conf_cpus = 0, reserved_cpus = 0;
+    SysIB_322 sysib;
+    int del, i;
+
+    if (s390_is_pv()) {
+        s390_cpu_pv_mem_read(cpu, 0, &sysib, sizeof(sysib));
+    } else if (s390_cpu_virt_mem_read(cpu, addr, ar, &sysib, sizeof(sysib))) {
+        return;
+    }
+    /* Shift the stack of Extended Names to prepare for our own data */
+    memmove(&sysib.ext_names[1], &sysib.ext_names[0],
+            sizeof(sysib.ext_names[0]) * (sysib.count - 1));
+    /* First virt level, that doesn't provide Ext Names delimits stack. It is
+     * assumed it's not capable of managing Extended Names for lower levels.
+     */
+    for (del = 1; del < sysib.count; del++) {
+        if (!sysib.vm[del].ext_name_encoding || !sysib.ext_names[del][0]) {
+            break;
+        }
+    }
+    if (del < sysib.count) {
+        memset(sysib.ext_names[del], 0,
+               sizeof(sysib.ext_names[0]) * (sysib.count - del));
+    }
+
+    /* count the cpus and split them into configured and reserved ones */
+    for (i = 0; i < ms->possible_cpus->len; i++) {
+        if (ms->possible_cpus->cpus[i].cpu) {
+            conf_cpus++;
+        } else {
+            reserved_cpus++;
+        }
+    }
+    sysib.vm[0].total_cpus = conf_cpus + reserved_cpus;
+    sysib.vm[0].conf_cpus = conf_cpus;
+    sysib.vm[0].reserved_cpus = reserved_cpus;
+
+    /* Insert short machine name in EBCDIC, padded with blanks */
+    if (qemu_name) {
+        memset(sysib.vm[0].name, 0x40, sizeof(sysib.vm[0].name));
+        ebcdic_put(sysib.vm[0].name, qemu_name, MIN(sizeof(sysib.vm[0].name),
+                                                    strlen(qemu_name)));
+    }
+    sysib.vm[0].ext_name_encoding = 2; /* 2 = UTF-8 */
+    /* If hypervisor specifies zero Extended Name in STSI322 SYSIB, it's
+     * considered by s390 as not capable of providing any Extended Name.
+     * Therefore if no name was specified on qemu invocation, we go with the
+     * same "KVMguest" default, which KVM has filled into short name field.
+     */
+    strpadcpy((char *)sysib.ext_names[0],
+              sizeof(sysib.ext_names[0]),
+              qemu_name ?: "KVMguest", '\0');
+
+    /* Insert UUID */
+    memcpy(sysib.vm[0].uuid, &qemu_uuid, sizeof(sysib.vm[0].uuid));
+
+    if (s390_is_pv()) {
+        s390_cpu_pv_mem_write(cpu, 0, &sysib, sizeof(sysib));
+    } else {
+        s390_cpu_virt_mem_write(cpu, addr, ar, &sysib, sizeof(sysib));
+    }
+}
+
+static int handle_stsi(S390CPU *cpu)
+{
+    CPUState *cs = CPU(cpu);
+    struct kvm_run *run = cs->kvm_run;
+
+    switch (run->s390_stsi.fc) {
+    case 3:
+        if (run->s390_stsi.sel1 != 2 || run->s390_stsi.sel2 != 2) {
+            return 0;
+        }
+        /* Only sysib 3.2.2 needs post-handling for now. */
+        insert_stsi_3_2_2(cpu, run->s390_stsi.addr, run->s390_stsi.ar);
+        return 0;
+    default:
+        return 0;
+    }
+}
+
+static int kvm_arch_handle_debug_exit(S390CPU *cpu)
+{
+    CPUState *cs = CPU(cpu);
+    struct kvm_run *run = cs->kvm_run;
+
+    int ret = 0;
+    struct kvm_debug_exit_arch *arch_info = &run->debug.arch;
+
+    switch (arch_info->type) {
+    case KVM_HW_WP_WRITE:
+        if (find_hw_breakpoint(arch_info->addr, -1, arch_info->type)) {
+            cs->watchpoint_hit = &hw_watchpoint;
+            hw_watchpoint.vaddr = arch_info->addr;
+            hw_watchpoint.flags = BP_MEM_WRITE;
+            ret = EXCP_DEBUG;
+        }
+        break;
+    case KVM_HW_BP:
+        if (find_hw_breakpoint(arch_info->addr, -1, arch_info->type)) {
+            ret = EXCP_DEBUG;
+        }
+        break;
+    case KVM_SINGLESTEP:
+        if (cs->singlestep_enabled) {
+            ret = EXCP_DEBUG;
+        }
+        break;
+    default:
+        ret = -ENOSYS;
+    }
+
+    return ret;
+}
+
+int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
+{
+    S390CPU *cpu = S390_CPU(cs);
+    int ret = 0;
+
+    qemu_mutex_lock_iothread();
+
+    kvm_cpu_synchronize_state(cs);
+
+    switch (run->exit_reason) {
+        case KVM_EXIT_S390_SIEIC:
+            ret = handle_intercept(cpu);
+            break;
+        case KVM_EXIT_S390_RESET:
+            s390_ipl_reset_request(cs, S390_RESET_REIPL);
+            break;
+        case KVM_EXIT_S390_TSCH:
+            ret = handle_tsch(cpu);
+            break;
+        case KVM_EXIT_S390_STSI:
+            ret = handle_stsi(cpu);
+            break;
+        case KVM_EXIT_DEBUG:
+            ret = kvm_arch_handle_debug_exit(cpu);
+            break;
+        default:
+            fprintf(stderr, "Unknown KVM exit: %d\n", run->exit_reason);
+            break;
+    }
+    qemu_mutex_unlock_iothread();
+
+    if (ret == 0) {
+        ret = EXCP_INTERRUPT;
+    }
+    return ret;
+}
+
+bool kvm_arch_stop_on_emulation_error(CPUState *cpu)
+{
+    return true;
+}
+
+void kvm_s390_enable_css_support(S390CPU *cpu)
+{
+    int r;
+
+    /* Activate host kernel channel subsystem support. */
+    r = kvm_vcpu_enable_cap(CPU(cpu), KVM_CAP_S390_CSS_SUPPORT, 0);
+    assert(r == 0);
+}
+
+void kvm_arch_init_irq_routing(KVMState *s)
+{
+    /*
+     * Note that while irqchip capabilities generally imply that cpustates
+     * are handled in-kernel, it is not true for s390 (yet); therefore, we
+     * have to override the common code kvm_halt_in_kernel_allowed setting.
+     */
+    if (kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) {
+        kvm_gsi_routing_allowed = true;
+        kvm_halt_in_kernel_allowed = false;
+    }
+}
+
+int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch,
+                                    int vq, bool assign)
+{
+    struct kvm_ioeventfd kick = {
+        .flags = KVM_IOEVENTFD_FLAG_VIRTIO_CCW_NOTIFY |
+        KVM_IOEVENTFD_FLAG_DATAMATCH,
+        .fd = event_notifier_get_fd(notifier),
+        .datamatch = vq,
+        .addr = sch,
+        .len = 8,
+    };
+    trace_kvm_assign_subch_ioeventfd(kick.fd, kick.addr, assign,
+                                     kick.datamatch);
+    if (!kvm_check_extension(kvm_state, KVM_CAP_IOEVENTFD)) {
+        return -ENOSYS;
+    }
+    if (!assign) {
+        kick.flags |= KVM_IOEVENTFD_FLAG_DEASSIGN;
+    }
+    return kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &kick);
+}
+
+int kvm_s390_get_ri(void)
+{
+    return cap_ri;
+}
+
+int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state)
+{
+    struct kvm_mp_state mp_state = {};
+    int ret;
+
+    /* the kvm part might not have been initialized yet */
+    if (CPU(cpu)->kvm_state == NULL) {
+        return 0;
+    }
+
+    switch (cpu_state) {
+    case S390_CPU_STATE_STOPPED:
+        mp_state.mp_state = KVM_MP_STATE_STOPPED;
+        break;
+    case S390_CPU_STATE_CHECK_STOP:
+        mp_state.mp_state = KVM_MP_STATE_CHECK_STOP;
+        break;
+    case S390_CPU_STATE_OPERATING:
+        mp_state.mp_state = KVM_MP_STATE_OPERATING;
+        break;
+    case S390_CPU_STATE_LOAD:
+        mp_state.mp_state = KVM_MP_STATE_LOAD;
+        break;
+    default:
+        error_report("Requested CPU state is not a valid S390 CPU state: %u",
+                     cpu_state);
+        exit(1);
+    }
+
+    ret = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_MP_STATE, &mp_state);
+    if (ret) {
+        trace_kvm_failed_cpu_state_set(CPU(cpu)->cpu_index, cpu_state,
+                                       strerror(-ret));
+    }
+
+    return ret;
+}
+
+void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu)
+{
+    unsigned int max_cpus = MACHINE(qdev_get_machine())->smp.max_cpus;
+    struct kvm_s390_irq_state irq_state = {
+        .buf = (uint64_t) cpu->irqstate,
+        .len = VCPU_IRQ_BUF_SIZE(max_cpus),
+    };
+    CPUState *cs = CPU(cpu);
+    int32_t bytes;
+
+    if (!kvm_check_extension(kvm_state, KVM_CAP_S390_IRQ_STATE)) {
+        return;
+    }
+
+    bytes = kvm_vcpu_ioctl(cs, KVM_S390_GET_IRQ_STATE, &irq_state);
+    if (bytes < 0) {
+        cpu->irqstate_saved_size = 0;
+        error_report("Migration of interrupt state failed");
+        return;
+    }
+
+    cpu->irqstate_saved_size = bytes;
+}
+
+int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu)
+{
+    CPUState *cs = CPU(cpu);
+    struct kvm_s390_irq_state irq_state = {
+        .buf = (uint64_t) cpu->irqstate,
+        .len = cpu->irqstate_saved_size,
+    };
+    int r;
+
+    if (cpu->irqstate_saved_size == 0) {
+        return 0;
+    }
+
+    if (!kvm_check_extension(kvm_state, KVM_CAP_S390_IRQ_STATE)) {
+        return -ENOSYS;
+    }
+
+    r = kvm_vcpu_ioctl(cs, KVM_S390_SET_IRQ_STATE, &irq_state);
+    if (r) {
+        error_report("Setting interrupt state failed %d", r);
+    }
+    return r;
+}
+
+int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
+                             uint64_t address, uint32_t data, PCIDevice *dev)
+{
+    S390PCIBusDevice *pbdev;
+    uint32_t vec = data & ZPCI_MSI_VEC_MASK;
+
+    if (!dev) {
+        DPRINTF("add_msi_route no pci device\n");
+        return -ENODEV;
+    }
+
+    pbdev = s390_pci_find_dev_by_target(s390_get_phb(), DEVICE(dev)->id);
+    if (!pbdev) {
+        DPRINTF("add_msi_route no zpci device\n");
+        return -ENODEV;
+    }
+
+    route->type = KVM_IRQ_ROUTING_S390_ADAPTER;
+    route->flags = 0;
+    route->u.adapter.summary_addr = pbdev->routes.adapter.summary_addr;
+    route->u.adapter.ind_addr = pbdev->routes.adapter.ind_addr;
+    route->u.adapter.summary_offset = pbdev->routes.adapter.summary_offset;
+    route->u.adapter.ind_offset = pbdev->routes.adapter.ind_offset + vec;
+    route->u.adapter.adapter_id = pbdev->routes.adapter.adapter_id;
+    return 0;
+}
+
+int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route,
+                                int vector, PCIDevice *dev)
+{
+    return 0;
+}
+
+int kvm_arch_release_virq_post(int virq)
+{
+    return 0;
+}
+
+int kvm_arch_msi_data_to_gsi(uint32_t data)
+{
+    abort();
+}
+
+static int query_cpu_subfunc(S390FeatBitmap features)
+{
+    struct kvm_s390_vm_cpu_subfunc prop = {};
+    struct kvm_device_attr attr = {
+        .group = KVM_S390_VM_CPU_MODEL,
+        .attr = KVM_S390_VM_CPU_MACHINE_SUBFUNC,
+        .addr = (uint64_t) &prop,
+    };
+    int rc;
+
+    rc = kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
+    if (rc) {
+        return  rc;
+    }
+
+    /*
+     * We're going to add all subfunctions now, if the corresponding feature
+     * is available that unlocks the query functions.
+     */
+    s390_add_from_feat_block(features, S390_FEAT_TYPE_PLO, prop.plo);
+    if (test_bit(S390_FEAT_TOD_CLOCK_STEERING, features)) {
+        s390_add_from_feat_block(features, S390_FEAT_TYPE_PTFF, prop.ptff);
+    }
+    if (test_bit(S390_FEAT_MSA, features)) {
+        s390_add_from_feat_block(features, S390_FEAT_TYPE_KMAC, prop.kmac);
+        s390_add_from_feat_block(features, S390_FEAT_TYPE_KMC, prop.kmc);
+        s390_add_from_feat_block(features, S390_FEAT_TYPE_KM, prop.km);
+        s390_add_from_feat_block(features, S390_FEAT_TYPE_KIMD, prop.kimd);
+        s390_add_from_feat_block(features, S390_FEAT_TYPE_KLMD, prop.klmd);
+    }
+    if (test_bit(S390_FEAT_MSA_EXT_3, features)) {
+        s390_add_from_feat_block(features, S390_FEAT_TYPE_PCKMO, prop.pckmo);
+    }
+    if (test_bit(S390_FEAT_MSA_EXT_4, features)) {
+        s390_add_from_feat_block(features, S390_FEAT_TYPE_KMCTR, prop.kmctr);
+        s390_add_from_feat_block(features, S390_FEAT_TYPE_KMF, prop.kmf);
+        s390_add_from_feat_block(features, S390_FEAT_TYPE_KMO, prop.kmo);
+        s390_add_from_feat_block(features, S390_FEAT_TYPE_PCC, prop.pcc);
+    }
+    if (test_bit(S390_FEAT_MSA_EXT_5, features)) {
+        s390_add_from_feat_block(features, S390_FEAT_TYPE_PPNO, prop.ppno);
+    }
+    if (test_bit(S390_FEAT_MSA_EXT_8, features)) {
+        s390_add_from_feat_block(features, S390_FEAT_TYPE_KMA, prop.kma);
+    }
+    if (test_bit(S390_FEAT_MSA_EXT_9, features)) {
+        s390_add_from_feat_block(features, S390_FEAT_TYPE_KDSA, prop.kdsa);
+    }
+    if (test_bit(S390_FEAT_ESORT_BASE, features)) {
+        s390_add_from_feat_block(features, S390_FEAT_TYPE_SORTL, prop.sortl);
+    }
+    if (test_bit(S390_FEAT_DEFLATE_BASE, features)) {
+        s390_add_from_feat_block(features, S390_FEAT_TYPE_DFLTCC, prop.dfltcc);
+    }
+    return 0;
+}
+
+static int configure_cpu_subfunc(const S390FeatBitmap features)
+{
+    struct kvm_s390_vm_cpu_subfunc prop = {};
+    struct kvm_device_attr attr = {
+        .group = KVM_S390_VM_CPU_MODEL,
+        .attr = KVM_S390_VM_CPU_PROCESSOR_SUBFUNC,
+        .addr = (uint64_t) &prop,
+    };
+
+    if (!kvm_vm_check_attr(kvm_state, KVM_S390_VM_CPU_MODEL,
+                           KVM_S390_VM_CPU_PROCESSOR_SUBFUNC)) {
+        /* hardware support might be missing, IBC will handle most of this */
+        return 0;
+    }
+
+    s390_fill_feat_block(features, S390_FEAT_TYPE_PLO, prop.plo);
+    if (test_bit(S390_FEAT_TOD_CLOCK_STEERING, features)) {
+        s390_fill_feat_block(features, S390_FEAT_TYPE_PTFF, prop.ptff);
+    }
+    if (test_bit(S390_FEAT_MSA, features)) {
+        s390_fill_feat_block(features, S390_FEAT_TYPE_KMAC, prop.kmac);
+        s390_fill_feat_block(features, S390_FEAT_TYPE_KMC, prop.kmc);
+        s390_fill_feat_block(features, S390_FEAT_TYPE_KM, prop.km);
+        s390_fill_feat_block(features, S390_FEAT_TYPE_KIMD, prop.kimd);
+        s390_fill_feat_block(features, S390_FEAT_TYPE_KLMD, prop.klmd);
+    }
+    if (test_bit(S390_FEAT_MSA_EXT_3, features)) {
+        s390_fill_feat_block(features, S390_FEAT_TYPE_PCKMO, prop.pckmo);
+    }
+    if (test_bit(S390_FEAT_MSA_EXT_4, features)) {
+        s390_fill_feat_block(features, S390_FEAT_TYPE_KMCTR, prop.kmctr);
+        s390_fill_feat_block(features, S390_FEAT_TYPE_KMF, prop.kmf);
+        s390_fill_feat_block(features, S390_FEAT_TYPE_KMO, prop.kmo);
+        s390_fill_feat_block(features, S390_FEAT_TYPE_PCC, prop.pcc);
+    }
+    if (test_bit(S390_FEAT_MSA_EXT_5, features)) {
+        s390_fill_feat_block(features, S390_FEAT_TYPE_PPNO, prop.ppno);
+    }
+    if (test_bit(S390_FEAT_MSA_EXT_8, features)) {
+        s390_fill_feat_block(features, S390_FEAT_TYPE_KMA, prop.kma);
+    }
+    if (test_bit(S390_FEAT_MSA_EXT_9, features)) {
+        s390_fill_feat_block(features, S390_FEAT_TYPE_KDSA, prop.kdsa);
+    }
+    if (test_bit(S390_FEAT_ESORT_BASE, features)) {
+        s390_fill_feat_block(features, S390_FEAT_TYPE_SORTL, prop.sortl);
+    }
+    if (test_bit(S390_FEAT_DEFLATE_BASE, features)) {
+        s390_fill_feat_block(features, S390_FEAT_TYPE_DFLTCC, prop.dfltcc);
+    }
+    return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
+}
+
+static int kvm_to_feat[][2] = {
+    { KVM_S390_VM_CPU_FEAT_ESOP, S390_FEAT_ESOP },
+    { KVM_S390_VM_CPU_FEAT_SIEF2, S390_FEAT_SIE_F2 },
+    { KVM_S390_VM_CPU_FEAT_64BSCAO , S390_FEAT_SIE_64BSCAO },
+    { KVM_S390_VM_CPU_FEAT_SIIF, S390_FEAT_SIE_SIIF },
+    { KVM_S390_VM_CPU_FEAT_GPERE, S390_FEAT_SIE_GPERE },
+    { KVM_S390_VM_CPU_FEAT_GSLS, S390_FEAT_SIE_GSLS },
+    { KVM_S390_VM_CPU_FEAT_IB, S390_FEAT_SIE_IB },
+    { KVM_S390_VM_CPU_FEAT_CEI, S390_FEAT_SIE_CEI },
+    { KVM_S390_VM_CPU_FEAT_IBS, S390_FEAT_SIE_IBS },
+    { KVM_S390_VM_CPU_FEAT_SKEY, S390_FEAT_SIE_SKEY },
+    { KVM_S390_VM_CPU_FEAT_CMMA, S390_FEAT_SIE_CMMA },
+    { KVM_S390_VM_CPU_FEAT_PFMFI, S390_FEAT_SIE_PFMFI},
+    { KVM_S390_VM_CPU_FEAT_SIGPIF, S390_FEAT_SIE_SIGPIF},
+    { KVM_S390_VM_CPU_FEAT_KSS, S390_FEAT_SIE_KSS},
+};
+
+static int query_cpu_feat(S390FeatBitmap features)
+{
+    struct kvm_s390_vm_cpu_feat prop = {};
+    struct kvm_device_attr attr = {
+        .group = KVM_S390_VM_CPU_MODEL,
+        .attr = KVM_S390_VM_CPU_MACHINE_FEAT,
+        .addr = (uint64_t) &prop,
+    };
+    int rc;
+    int i;
+
+    rc = kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
+    if (rc) {
+        return  rc;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(kvm_to_feat); i++) {
+        if (test_be_bit(kvm_to_feat[i][0], (uint8_t *) prop.feat)) {
+            set_bit(kvm_to_feat[i][1], features);
+        }
+    }
+    return 0;
+}
+
+static int configure_cpu_feat(const S390FeatBitmap features)
+{
+    struct kvm_s390_vm_cpu_feat prop = {};
+    struct kvm_device_attr attr = {
+        .group = KVM_S390_VM_CPU_MODEL,
+        .attr = KVM_S390_VM_CPU_PROCESSOR_FEAT,
+        .addr = (uint64_t) &prop,
+    };
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(kvm_to_feat); i++) {
+        if (test_bit(kvm_to_feat[i][1], features)) {
+            set_be_bit(kvm_to_feat[i][0], (uint8_t *) prop.feat);
+        }
+    }
+    return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
+}
+
+bool kvm_s390_cpu_models_supported(void)
+{
+    if (!cpu_model_allowed()) {
+        /* compatibility machines interfere with the cpu model */
+        return false;
+    }
+    return kvm_vm_check_attr(kvm_state, KVM_S390_VM_CPU_MODEL,
+                             KVM_S390_VM_CPU_MACHINE) &&
+           kvm_vm_check_attr(kvm_state, KVM_S390_VM_CPU_MODEL,
+                             KVM_S390_VM_CPU_PROCESSOR) &&
+           kvm_vm_check_attr(kvm_state, KVM_S390_VM_CPU_MODEL,
+                             KVM_S390_VM_CPU_MACHINE_FEAT) &&
+           kvm_vm_check_attr(kvm_state, KVM_S390_VM_CPU_MODEL,
+                             KVM_S390_VM_CPU_PROCESSOR_FEAT) &&
+           kvm_vm_check_attr(kvm_state, KVM_S390_VM_CPU_MODEL,
+                             KVM_S390_VM_CPU_MACHINE_SUBFUNC);
+}
+
+void kvm_s390_get_host_cpu_model(S390CPUModel *model, Error **errp)
+{
+    struct kvm_s390_vm_cpu_machine prop = {};
+    struct kvm_device_attr attr = {
+        .group = KVM_S390_VM_CPU_MODEL,
+        .attr = KVM_S390_VM_CPU_MACHINE,
+        .addr = (uint64_t) &prop,
+    };
+    uint16_t unblocked_ibc = 0, cpu_type = 0;
+    int rc;
+
+    memset(model, 0, sizeof(*model));
+
+    if (!kvm_s390_cpu_models_supported()) {
+        error_setg(errp, "KVM doesn't support CPU models");
+        return;
+    }
+
+    /* query the basic cpu model properties */
+    rc = kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
+    if (rc) {
+        error_setg(errp, "KVM: Error querying host CPU model: %d", rc);
+        return;
+    }
+
+    cpu_type = cpuid_type(prop.cpuid);
+    if (has_ibc(prop.ibc)) {
+        model->lowest_ibc = lowest_ibc(prop.ibc);
+        unblocked_ibc = unblocked_ibc(prop.ibc);
+    }
+    model->cpu_id = cpuid_id(prop.cpuid);
+    model->cpu_id_format = cpuid_format(prop.cpuid);
+    model->cpu_ver = 0xff;
+
+    /* get supported cpu features indicated via STFL(E) */
+    s390_add_from_feat_block(model->features, S390_FEAT_TYPE_STFL,
+                             (uint8_t *) prop.fac_mask);
+    /* dat-enhancement facility 2 has no bit but was introduced with stfle */
+    if (test_bit(S390_FEAT_STFLE, model->features)) {
+        set_bit(S390_FEAT_DAT_ENH_2, model->features);
+    }
+    /* get supported cpu features indicated e.g. via SCLP */
+    rc = query_cpu_feat(model->features);
+    if (rc) {
+        error_setg(errp, "KVM: Error querying CPU features: %d", rc);
+        return;
+    }
+    /* get supported cpu subfunctions indicated via query / test bit */
+    rc = query_cpu_subfunc(model->features);
+    if (rc) {
+        error_setg(errp, "KVM: Error querying CPU subfunctions: %d", rc);
+        return;
+    }
+
+    /* PTFF subfunctions might be indicated although kernel support missing */
+    if (!test_bit(S390_FEAT_MULTIPLE_EPOCH, model->features)) {
+        clear_bit(S390_FEAT_PTFF_QSIE, model->features);
+        clear_bit(S390_FEAT_PTFF_QTOUE, model->features);
+        clear_bit(S390_FEAT_PTFF_STOE, model->features);
+        clear_bit(S390_FEAT_PTFF_STOUE, model->features);
+    }
+
+    /* with cpu model support, CMM is only indicated if really available */
+    if (kvm_s390_cmma_available()) {
+        set_bit(S390_FEAT_CMM, model->features);
+    } else {
+        /* no cmm -> no cmm nt */
+        clear_bit(S390_FEAT_CMM_NT, model->features);
+    }
+
+    /* bpb needs kernel support for migration, VSIE and reset */
+    if (!kvm_check_extension(kvm_state, KVM_CAP_S390_BPB)) {
+        clear_bit(S390_FEAT_BPB, model->features);
+    }
+
+    /*
+     * If we have support for protected virtualization, indicate
+     * the protected virtualization IPL unpack facility.
+     */
+    if (cap_protected) {
+        set_bit(S390_FEAT_UNPACK, model->features);
+    }
+
+    /* We emulate a zPCI bus and AEN, therefore we don't need HW support */
+    set_bit(S390_FEAT_ZPCI, model->features);
+    set_bit(S390_FEAT_ADAPTER_EVENT_NOTIFICATION, model->features);
+
+    if (s390_known_cpu_type(cpu_type)) {
+        /* we want the exact model, even if some features are missing */
+        model->def = s390_find_cpu_def(cpu_type, ibc_gen(unblocked_ibc),
+                                       ibc_ec_ga(unblocked_ibc), NULL);
+    } else {
+        /* model unknown, e.g. too new - search using features */
+        model->def = s390_find_cpu_def(0, ibc_gen(unblocked_ibc),
+                                       ibc_ec_ga(unblocked_ibc),
+                                       model->features);
+    }
+    if (!model->def) {
+        error_setg(errp, "KVM: host CPU model could not be identified");
+        return;
+    }
+    /* for now, we can only provide the AP feature with HW support */
+    if (kvm_vm_check_attr(kvm_state, KVM_S390_VM_CRYPTO,
+        KVM_S390_VM_CRYPTO_ENABLE_APIE)) {
+        set_bit(S390_FEAT_AP, model->features);
+    }
+
+    /*
+     * Extended-Length SCCB is handled entirely within QEMU.
+     * For PV guests this is completely fenced by the Ultravisor, as Service
+     * Call error checking and STFLE interpretation are handled via SIE.
+     */
+    set_bit(S390_FEAT_EXTENDED_LENGTH_SCCB, model->features);
+
+    if (kvm_check_extension(kvm_state, KVM_CAP_S390_DIAG318)) {
+        set_bit(S390_FEAT_DIAG_318, model->features);
+    }
+
+    /* strip of features that are not part of the maximum model */
+    bitmap_and(model->features, model->features, model->def->full_feat,
+               S390_FEAT_MAX);
+}
+
+static void kvm_s390_configure_apie(bool interpret)
+{
+    uint64_t attr = interpret ? KVM_S390_VM_CRYPTO_ENABLE_APIE :
+                                KVM_S390_VM_CRYPTO_DISABLE_APIE;
+
+    if (kvm_vm_check_attr(kvm_state, KVM_S390_VM_CRYPTO, attr)) {
+        kvm_s390_set_attr(attr);
+    }
+}
+
+void kvm_s390_apply_cpu_model(const S390CPUModel *model, Error **errp)
+{
+    struct kvm_s390_vm_cpu_processor prop  = {
+        .fac_list = { 0 },
+    };
+    struct kvm_device_attr attr = {
+        .group = KVM_S390_VM_CPU_MODEL,
+        .attr = KVM_S390_VM_CPU_PROCESSOR,
+        .addr = (uint64_t) &prop,
+    };
+    int rc;
+
+    if (!model) {
+        /* compatibility handling if cpu models are disabled */
+        if (kvm_s390_cmma_available()) {
+            kvm_s390_enable_cmma();
+        }
+        return;
+    }
+    if (!kvm_s390_cpu_models_supported()) {
+        error_setg(errp, "KVM doesn't support CPU models");
+        return;
+    }
+    prop.cpuid = s390_cpuid_from_cpu_model(model);
+    prop.ibc = s390_ibc_from_cpu_model(model);
+    /* configure cpu features indicated via STFL(e) */
+    s390_fill_feat_block(model->features, S390_FEAT_TYPE_STFL,
+                         (uint8_t *) prop.fac_list);
+    rc = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
+    if (rc) {
+        error_setg(errp, "KVM: Error configuring the CPU model: %d", rc);
+        return;
+    }
+    /* configure cpu features indicated e.g. via SCLP */
+    rc = configure_cpu_feat(model->features);
+    if (rc) {
+        error_setg(errp, "KVM: Error configuring CPU features: %d", rc);
+        return;
+    }
+    /* configure cpu subfunctions indicated via query / test bit */
+    rc = configure_cpu_subfunc(model->features);
+    if (rc) {
+        error_setg(errp, "KVM: Error configuring CPU subfunctions: %d", rc);
+        return;
+    }
+    /* enable CMM via CMMA */
+    if (test_bit(S390_FEAT_CMM, model->features)) {
+        kvm_s390_enable_cmma();
+    }
+
+    if (test_bit(S390_FEAT_AP, model->features)) {
+        kvm_s390_configure_apie(true);
+    }
+}
+
+void kvm_s390_restart_interrupt(S390CPU *cpu)
+{
+    struct kvm_s390_irq irq = {
+        .type = KVM_S390_RESTART,
+    };
+
+    kvm_s390_vcpu_interrupt(cpu, &irq);
+}
+
+void kvm_s390_stop_interrupt(S390CPU *cpu)
+{
+    struct kvm_s390_irq irq = {
+        .type = KVM_S390_SIGP_STOP,
+    };
+
+    kvm_s390_vcpu_interrupt(cpu, &irq);
+}
+
+bool kvm_arch_cpu_check_are_resettable(void)
+{
+    return true;
+}
diff --git a/target/s390x/kvm/kvm_s390x.h b/target/s390x/kvm/kvm_s390x.h
new file mode 100644 (file)
index 0000000..05a5e1e
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * QEMU KVM support -- s390x specific functions.
+ *
+ * Copyright (c) 2009 Ulrich Hecht
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef KVM_S390X_H
+#define KVM_S390X_H
+
+#include "cpu-qom.h"
+
+struct kvm_s390_irq;
+
+void kvm_s390_floating_interrupt_legacy(struct kvm_s390_irq *irq);
+void kvm_s390_vcpu_interrupt(S390CPU *cpu, struct kvm_s390_irq *irq);
+void kvm_s390_access_exception(S390CPU *cpu, uint16_t code, uint64_t te_code);
+int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf,
+                    int len, bool is_write);
+int kvm_s390_mem_op_pv(S390CPU *cpu, vaddr addr, void *hostbuf, int len,
+                       bool is_write);
+void kvm_s390_program_interrupt(S390CPU *cpu, uint16_t code);
+int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state);
+void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu);
+int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu);
+int kvm_s390_get_hpage_1m(void);
+int kvm_s390_get_ri(void);
+int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_clock);
+int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_clock);
+int kvm_s390_set_clock(uint8_t tod_high, uint64_t tod_clock);
+int kvm_s390_set_clock_ext(uint8_t tod_high, uint64_t tod_clock);
+void kvm_s390_enable_css_support(S390CPU *cpu);
+int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch,
+                                    int vq, bool assign);
+int kvm_s390_cmma_active(void);
+void kvm_s390_cmma_reset(void);
+void kvm_s390_reset_vcpu_clear(S390CPU *cpu);
+void kvm_s390_reset_vcpu_normal(S390CPU *cpu);
+void kvm_s390_reset_vcpu_initial(S390CPU *cpu);
+int kvm_s390_set_mem_limit(uint64_t new_limit, uint64_t *hw_limit);
+void kvm_s390_set_max_pagesize(uint64_t pagesize, Error **errp);
+void kvm_s390_crypto_reset(void);
+void kvm_s390_restart_interrupt(S390CPU *cpu);
+void kvm_s390_stop_interrupt(S390CPU *cpu);
+void kvm_s390_set_diag318(CPUState *cs, uint64_t diag318_info);
+
+#endif /* KVM_S390X_H */
diff --git a/target/s390x/kvm/meson.build b/target/s390x/kvm/meson.build
new file mode 100644 (file)
index 0000000..d135635
--- /dev/null
@@ -0,0 +1,17 @@
+
+s390x_ss.add(when: 'CONFIG_KVM', if_true: files(
+  'kvm.c'
+))
+
+# Newer kernels on s390 check for an S390_PGSTE program header and
+# enable the pgste page table extensions in that case. This makes
+# the vm.allocate_pgste sysctl unnecessary. We enable this program
+# header if
+#  - we build on s390x
+#  - we build the system emulation for s390x (qemu-system-s390x)
+#  - KVM is enabled
+#  - the linker supports --s390-pgste
+if host_machine.cpu_family() == 's390x' and cc.has_link_argument('-Wl,--s390-pgste')
+  s390x_softmmu_ss.add(when: 'CONFIG_KVM',
+                       if_true: declare_dependency(link_args: ['-Wl,--s390-pgste']))
+endif
diff --git a/target/s390x/kvm/trace-events b/target/s390x/kvm/trace-events
new file mode 100644 (file)
index 0000000..5289f5f
--- /dev/null
@@ -0,0 +1,7 @@
+# See docs/devel/tracing.txt for syntax documentation.
+
+# kvm.c
+kvm_enable_cmma(int rc) "CMMA: enabling with result code %d"
+kvm_clear_cmma(int rc) "CMMA: clearing with result code %d"
+kvm_failed_cpu_state_set(int cpu_index, uint8_t state, const char *msg) "Warning: Unable to set cpu %d state %" PRIu8 " to KVM: %s"
+kvm_assign_subch_ioeventfd(int fd, uint32_t addr, bool assign, int datamatch) "fd: %d sch: @0x%x assign: %d vq: %d"
diff --git a/target/s390x/kvm/trace.h b/target/s390x/kvm/trace.h
new file mode 100644 (file)
index 0000000..ae195b1
--- /dev/null
@@ -0,0 +1 @@
+#include "trace/trace-target_s390x_kvm.h"
diff --git a/target/s390x/kvm_s390x.h b/target/s390x/kvm_s390x.h
deleted file mode 100644 (file)
index 05a5e1e..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * QEMU KVM support -- s390x specific functions.
- *
- * Copyright (c) 2009 Ulrich Hecht
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#ifndef KVM_S390X_H
-#define KVM_S390X_H
-
-#include "cpu-qom.h"
-
-struct kvm_s390_irq;
-
-void kvm_s390_floating_interrupt_legacy(struct kvm_s390_irq *irq);
-void kvm_s390_vcpu_interrupt(S390CPU *cpu, struct kvm_s390_irq *irq);
-void kvm_s390_access_exception(S390CPU *cpu, uint16_t code, uint64_t te_code);
-int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf,
-                    int len, bool is_write);
-int kvm_s390_mem_op_pv(S390CPU *cpu, vaddr addr, void *hostbuf, int len,
-                       bool is_write);
-void kvm_s390_program_interrupt(S390CPU *cpu, uint16_t code);
-int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state);
-void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu);
-int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu);
-int kvm_s390_get_hpage_1m(void);
-int kvm_s390_get_ri(void);
-int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_clock);
-int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_clock);
-int kvm_s390_set_clock(uint8_t tod_high, uint64_t tod_clock);
-int kvm_s390_set_clock_ext(uint8_t tod_high, uint64_t tod_clock);
-void kvm_s390_enable_css_support(S390CPU *cpu);
-int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch,
-                                    int vq, bool assign);
-int kvm_s390_cmma_active(void);
-void kvm_s390_cmma_reset(void);
-void kvm_s390_reset_vcpu_clear(S390CPU *cpu);
-void kvm_s390_reset_vcpu_normal(S390CPU *cpu);
-void kvm_s390_reset_vcpu_initial(S390CPU *cpu);
-int kvm_s390_set_mem_limit(uint64_t new_limit, uint64_t *hw_limit);
-void kvm_s390_set_max_pagesize(uint64_t pagesize, Error **errp);
-void kvm_s390_crypto_reset(void);
-void kvm_s390_restart_interrupt(S390CPU *cpu);
-void kvm_s390_stop_interrupt(S390CPU *cpu);
-void kvm_s390_set_diag318(CPUState *cs, uint64_t diag318_info);
-
-#endif /* KVM_S390X_H */
index 5b4e82f1ab99b0371bf29bfe9e9524152dfe7029..37a076858c7566ae07684ad014f4a99956107538 100644 (file)
 
 #include "qemu/osdep.h"
 #include "cpu.h"
-#include "internal.h"
-#include "kvm_s390x.h"
+#include "s390x-internal.h"
+#include "kvm/kvm_s390x.h"
 #include "migration/vmstate.h"
-#include "tcg_s390x.h"
+#include "tcg/tcg_s390x.h"
 #include "sysemu/kvm.h"
 #include "sysemu/tcg.h"
 
diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c
deleted file mode 100644 (file)
index f6a7d29..0000000
+++ /dev/null
@@ -1,3008 +0,0 @@
-/*
- *  S/390 memory access helper routines
- *
- *  Copyright (c) 2009 Ulrich Hecht
- *  Copyright (c) 2009 Alexander Graf
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "internal.h"
-#include "tcg_s390x.h"
-#include "exec/helper-proto.h"
-#include "exec/exec-all.h"
-#include "exec/cpu_ldst.h"
-#include "qemu/int128.h"
-#include "qemu/atomic128.h"
-#include "tcg/tcg.h"
-
-#if !defined(CONFIG_USER_ONLY)
-#include "hw/s390x/storage-keys.h"
-#include "hw/boards.h"
-#endif
-
-/*****************************************************************************/
-/* Softmmu support */
-
-/* #define DEBUG_HELPER */
-#ifdef DEBUG_HELPER
-#define HELPER_LOG(x...) qemu_log(x)
-#else
-#define HELPER_LOG(x...)
-#endif
-
-static inline bool psw_key_valid(CPUS390XState *env, uint8_t psw_key)
-{
-    uint16_t pkm = env->cregs[3] >> 16;
-
-    if (env->psw.mask & PSW_MASK_PSTATE) {
-        /* PSW key has range 0..15, it is valid if the bit is 1 in the PKM */
-        return pkm & (0x80 >> psw_key);
-    }
-    return true;
-}
-
-static bool is_destructive_overlap(CPUS390XState *env, uint64_t dest,
-                                   uint64_t src, uint32_t len)
-{
-    if (!len || src == dest) {
-        return false;
-    }
-    /* Take care of wrapping at the end of address space. */
-    if (unlikely(wrap_address(env, src + len - 1) < src)) {
-        return dest > src || dest <= wrap_address(env, src + len - 1);
-    }
-    return dest > src && dest <= src + len - 1;
-}
-
-/* Trigger a SPECIFICATION exception if an address or a length is not
-   naturally aligned.  */
-static inline void check_alignment(CPUS390XState *env, uint64_t v,
-                                   int wordsize, uintptr_t ra)
-{
-    if (v % wordsize) {
-        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
-    }
-}
-
-/* Load a value from memory according to its size.  */
-static inline uint64_t cpu_ldusize_data_ra(CPUS390XState *env, uint64_t addr,
-                                           int wordsize, uintptr_t ra)
-{
-    switch (wordsize) {
-    case 1:
-        return cpu_ldub_data_ra(env, addr, ra);
-    case 2:
-        return cpu_lduw_data_ra(env, addr, ra);
-    default:
-        abort();
-    }
-}
-
-/* Store a to memory according to its size.  */
-static inline void cpu_stsize_data_ra(CPUS390XState *env, uint64_t addr,
-                                      uint64_t value, int wordsize,
-                                      uintptr_t ra)
-{
-    switch (wordsize) {
-    case 1:
-        cpu_stb_data_ra(env, addr, value, ra);
-        break;
-    case 2:
-        cpu_stw_data_ra(env, addr, value, ra);
-        break;
-    default:
-        abort();
-    }
-}
-
-/* An access covers at most 4096 bytes and therefore at most two pages. */
-typedef struct S390Access {
-    target_ulong vaddr1;
-    target_ulong vaddr2;
-    char *haddr1;
-    char *haddr2;
-    uint16_t size1;
-    uint16_t size2;
-    /*
-     * If we can't access the host page directly, we'll have to do I/O access
-     * via ld/st helpers. These are internal details, so we store the
-     * mmu idx to do the access here instead of passing it around in the
-     * helpers. Maybe, one day we can get rid of ld/st access - once we can
-     * handle TLB_NOTDIRTY differently. We don't expect these special accesses
-     * to trigger exceptions - only if we would have TLB_NOTDIRTY on LAP
-     * pages, we might trigger a new MMU translation - very unlikely that
-     * the mapping changes in between and we would trigger a fault.
-     */
-    int mmu_idx;
-} S390Access;
-
-/*
- * With nonfault=1, return the PGM_ exception that would have been injected
- * into the guest; return 0 if no exception was detected.
- *
- * For !CONFIG_USER_ONLY, the TEC is stored stored to env->tlb_fill_tec.
- * For CONFIG_USER_ONLY, the faulting address is stored to env->__excp_addr.
- */
-static int s390_probe_access(CPUArchState *env, target_ulong addr, int size,
-                             MMUAccessType access_type, int mmu_idx,
-                             bool nonfault, void **phost, uintptr_t ra)
-{
-    int flags;
-
-#if defined(CONFIG_USER_ONLY)
-    flags = page_get_flags(addr);
-    if (!(flags & (access_type == MMU_DATA_LOAD ?  PAGE_READ : PAGE_WRITE_ORG))) {
-        env->__excp_addr = addr;
-        flags = (flags & PAGE_VALID) ? PGM_PROTECTION : PGM_ADDRESSING;
-        if (nonfault) {
-            return flags;
-        }
-        tcg_s390_program_interrupt(env, flags, ra);
-    }
-    *phost = g2h(env_cpu(env), addr);
-#else
-    /*
-     * For !CONFIG_USER_ONLY, we cannot rely on TLB_INVALID_MASK or haddr==NULL
-     * to detect if there was an exception during tlb_fill().
-     */
-    env->tlb_fill_exc = 0;
-    flags = probe_access_flags(env, addr, access_type, mmu_idx, nonfault, phost,
-                               ra);
-    if (env->tlb_fill_exc) {
-        return env->tlb_fill_exc;
-    }
-
-    if (unlikely(flags & TLB_WATCHPOINT)) {
-        /* S390 does not presently use transaction attributes. */
-        cpu_check_watchpoint(env_cpu(env), addr, size,
-                             MEMTXATTRS_UNSPECIFIED,
-                             (access_type == MMU_DATA_STORE
-                              ? BP_MEM_WRITE : BP_MEM_READ), ra);
-    }
-#endif
-    return 0;
-}
-
-static int access_prepare_nf(S390Access *access, CPUS390XState *env,
-                             bool nonfault, vaddr vaddr1, int size,
-                             MMUAccessType access_type,
-                             int mmu_idx, uintptr_t ra)
-{
-    void *haddr1, *haddr2 = NULL;
-    int size1, size2, exc;
-    vaddr vaddr2 = 0;
-
-    assert(size > 0 && size <= 4096);
-
-    size1 = MIN(size, -(vaddr1 | TARGET_PAGE_MASK)),
-    size2 = size - size1;
-
-    exc = s390_probe_access(env, vaddr1, size1, access_type, mmu_idx, nonfault,
-                            &haddr1, ra);
-    if (exc) {
-        return exc;
-    }
-    if (unlikely(size2)) {
-        /* The access crosses page boundaries. */
-        vaddr2 = wrap_address(env, vaddr1 + size1);
-        exc = s390_probe_access(env, vaddr2, size2, access_type, mmu_idx,
-                                nonfault, &haddr2, ra);
-        if (exc) {
-            return exc;
-        }
-    }
-
-    *access = (S390Access) {
-        .vaddr1 = vaddr1,
-        .vaddr2 = vaddr2,
-        .haddr1 = haddr1,
-        .haddr2 = haddr2,
-        .size1 = size1,
-        .size2 = size2,
-        .mmu_idx = mmu_idx
-    };
-    return 0;
-}
-
-static S390Access access_prepare(CPUS390XState *env, vaddr vaddr, int size,
-                                 MMUAccessType access_type, int mmu_idx,
-                                 uintptr_t ra)
-{
-    S390Access ret;
-    int exc = access_prepare_nf(&ret, env, false, vaddr, size,
-                                access_type, mmu_idx, ra);
-    assert(!exc);
-    return ret;
-}
-
-/* Helper to handle memset on a single page. */
-static void do_access_memset(CPUS390XState *env, vaddr vaddr, char *haddr,
-                             uint8_t byte, uint16_t size, int mmu_idx,
-                             uintptr_t ra)
-{
-#ifdef CONFIG_USER_ONLY
-    g_assert(haddr);
-    memset(haddr, byte, size);
-#else
-    TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
-    int i;
-
-    if (likely(haddr)) {
-        memset(haddr, byte, size);
-    } else {
-        /*
-         * Do a single access and test if we can then get access to the
-         * page. This is especially relevant to speed up TLB_NOTDIRTY.
-         */
-        g_assert(size > 0);
-        helper_ret_stb_mmu(env, vaddr, byte, oi, ra);
-        haddr = tlb_vaddr_to_host(env, vaddr, MMU_DATA_STORE, mmu_idx);
-        if (likely(haddr)) {
-            memset(haddr + 1, byte, size - 1);
-        } else {
-            for (i = 1; i < size; i++) {
-                helper_ret_stb_mmu(env, vaddr + i, byte, oi, ra);
-            }
-        }
-    }
-#endif
-}
-
-static void access_memset(CPUS390XState *env, S390Access *desta,
-                          uint8_t byte, uintptr_t ra)
-{
-
-    do_access_memset(env, desta->vaddr1, desta->haddr1, byte, desta->size1,
-                     desta->mmu_idx, ra);
-    if (likely(!desta->size2)) {
-        return;
-    }
-    do_access_memset(env, desta->vaddr2, desta->haddr2, byte, desta->size2,
-                     desta->mmu_idx, ra);
-}
-
-static uint8_t do_access_get_byte(CPUS390XState *env, vaddr vaddr, char **haddr,
-                                  int offset, int mmu_idx, uintptr_t ra)
-{
-#ifdef CONFIG_USER_ONLY
-    return ldub_p(*haddr + offset);
-#else
-    TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
-    uint8_t byte;
-
-    if (likely(*haddr)) {
-        return ldub_p(*haddr + offset);
-    }
-    /*
-     * Do a single access and test if we can then get access to the
-     * page. This is especially relevant to speed up TLB_NOTDIRTY.
-     */
-    byte = helper_ret_ldub_mmu(env, vaddr + offset, oi, ra);
-    *haddr = tlb_vaddr_to_host(env, vaddr, MMU_DATA_LOAD, mmu_idx);
-    return byte;
-#endif
-}
-
-static uint8_t access_get_byte(CPUS390XState *env, S390Access *access,
-                               int offset, uintptr_t ra)
-{
-    if (offset < access->size1) {
-        return do_access_get_byte(env, access->vaddr1, &access->haddr1,
-                                  offset, access->mmu_idx, ra);
-    }
-    return do_access_get_byte(env, access->vaddr2, &access->haddr2,
-                              offset - access->size1, access->mmu_idx, ra);
-}
-
-static void do_access_set_byte(CPUS390XState *env, vaddr vaddr, char **haddr,
-                               int offset, uint8_t byte, int mmu_idx,
-                               uintptr_t ra)
-{
-#ifdef CONFIG_USER_ONLY
-    stb_p(*haddr + offset, byte);
-#else
-    TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
-
-    if (likely(*haddr)) {
-        stb_p(*haddr + offset, byte);
-        return;
-    }
-    /*
-     * Do a single access and test if we can then get access to the
-     * page. This is especially relevant to speed up TLB_NOTDIRTY.
-     */
-    helper_ret_stb_mmu(env, vaddr + offset, byte, oi, ra);
-    *haddr = tlb_vaddr_to_host(env, vaddr, MMU_DATA_STORE, mmu_idx);
-#endif
-}
-
-static void access_set_byte(CPUS390XState *env, S390Access *access,
-                            int offset, uint8_t byte, uintptr_t ra)
-{
-    if (offset < access->size1) {
-        do_access_set_byte(env, access->vaddr1, &access->haddr1, offset, byte,
-                           access->mmu_idx, ra);
-    } else {
-        do_access_set_byte(env, access->vaddr2, &access->haddr2,
-                           offset - access->size1, byte, access->mmu_idx, ra);
-    }
-}
-
-/*
- * Move data with the same semantics as memmove() in case ranges don't overlap
- * or src > dest. Undefined behavior on destructive overlaps.
- */
-static void access_memmove(CPUS390XState *env, S390Access *desta,
-                           S390Access *srca, uintptr_t ra)
-{
-    int diff;
-
-    g_assert(desta->size1 + desta->size2 == srca->size1 + srca->size2);
-
-    /* Fallback to slow access in case we don't have access to all host pages */
-    if (unlikely(!desta->haddr1 || (desta->size2 && !desta->haddr2) ||
-                 !srca->haddr1 || (srca->size2 && !srca->haddr2))) {
-        int i;
-
-        for (i = 0; i < desta->size1 + desta->size2; i++) {
-            uint8_t byte = access_get_byte(env, srca, i, ra);
-
-            access_set_byte(env, desta, i, byte, ra);
-        }
-        return;
-    }
-
-    if (srca->size1 == desta->size1) {
-        memmove(desta->haddr1, srca->haddr1, srca->size1);
-        if (unlikely(srca->size2)) {
-            memmove(desta->haddr2, srca->haddr2, srca->size2);
-        }
-    } else if (srca->size1 < desta->size1) {
-        diff = desta->size1 - srca->size1;
-        memmove(desta->haddr1, srca->haddr1, srca->size1);
-        memmove(desta->haddr1 + srca->size1, srca->haddr2, diff);
-        if (likely(desta->size2)) {
-            memmove(desta->haddr2, srca->haddr2 + diff, desta->size2);
-        }
-    } else {
-        diff = srca->size1 - desta->size1;
-        memmove(desta->haddr1, srca->haddr1, desta->size1);
-        memmove(desta->haddr2, srca->haddr1 + desta->size1, diff);
-        if (likely(srca->size2)) {
-            memmove(desta->haddr2 + diff, srca->haddr2, srca->size2);
-        }
-    }
-}
-
-static int mmu_idx_from_as(uint8_t as)
-{
-    switch (as) {
-    case AS_PRIMARY:
-        return MMU_PRIMARY_IDX;
-    case AS_SECONDARY:
-        return MMU_SECONDARY_IDX;
-    case AS_HOME:
-        return MMU_HOME_IDX;
-    default:
-        /* FIXME AS_ACCREG */
-        g_assert_not_reached();
-    }
-}
-
-/* and on array */
-static uint32_t do_helper_nc(CPUS390XState *env, uint32_t l, uint64_t dest,
-                             uint64_t src, uintptr_t ra)
-{
-    const int mmu_idx = cpu_mmu_index(env, false);
-    S390Access srca1, srca2, desta;
-    uint32_t i;
-    uint8_t c = 0;
-
-    HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
-               __func__, l, dest, src);
-
-    /* NC always processes one more byte than specified - maximum is 256 */
-    l++;
-
-    srca1 = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
-    srca2 = access_prepare(env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
-    desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
-    for (i = 0; i < l; i++) {
-        const uint8_t x = access_get_byte(env, &srca1, i, ra) &
-                          access_get_byte(env, &srca2, i, ra);
-
-        c |= x;
-        access_set_byte(env, &desta, i, x, ra);
-    }
-    return c != 0;
-}
-
-uint32_t HELPER(nc)(CPUS390XState *env, uint32_t l, uint64_t dest,
-                    uint64_t src)
-{
-    return do_helper_nc(env, l, dest, src, GETPC());
-}
-
-/* xor on array */
-static uint32_t do_helper_xc(CPUS390XState *env, uint32_t l, uint64_t dest,
-                             uint64_t src, uintptr_t ra)
-{
-    const int mmu_idx = cpu_mmu_index(env, false);
-    S390Access srca1, srca2, desta;
-    uint32_t i;
-    uint8_t c = 0;
-
-    HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
-               __func__, l, dest, src);
-
-    /* XC always processes one more byte than specified - maximum is 256 */
-    l++;
-
-    srca1 = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
-    srca2 = access_prepare(env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
-    desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
-
-    /* xor with itself is the same as memset(0) */
-    if (src == dest) {
-        access_memset(env, &desta, 0, ra);
-        return 0;
-    }
-
-    for (i = 0; i < l; i++) {
-        const uint8_t x = access_get_byte(env, &srca1, i, ra) ^
-                          access_get_byte(env, &srca2, i, ra);
-
-        c |= x;
-        access_set_byte(env, &desta, i, x, ra);
-    }
-    return c != 0;
-}
-
-uint32_t HELPER(xc)(CPUS390XState *env, uint32_t l, uint64_t dest,
-                    uint64_t src)
-{
-    return do_helper_xc(env, l, dest, src, GETPC());
-}
-
-/* or on array */
-static uint32_t do_helper_oc(CPUS390XState *env, uint32_t l, uint64_t dest,
-                             uint64_t src, uintptr_t ra)
-{
-    const int mmu_idx = cpu_mmu_index(env, false);
-    S390Access srca1, srca2, desta;
-    uint32_t i;
-    uint8_t c = 0;
-
-    HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
-               __func__, l, dest, src);
-
-    /* OC always processes one more byte than specified - maximum is 256 */
-    l++;
-
-    srca1 = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
-    srca2 = access_prepare(env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
-    desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
-    for (i = 0; i < l; i++) {
-        const uint8_t x = access_get_byte(env, &srca1, i, ra) |
-                          access_get_byte(env, &srca2, i, ra);
-
-        c |= x;
-        access_set_byte(env, &desta, i, x, ra);
-    }
-    return c != 0;
-}
-
-uint32_t HELPER(oc)(CPUS390XState *env, uint32_t l, uint64_t dest,
-                    uint64_t src)
-{
-    return do_helper_oc(env, l, dest, src, GETPC());
-}
-
-/* memmove */
-static uint32_t do_helper_mvc(CPUS390XState *env, uint32_t l, uint64_t dest,
-                              uint64_t src, uintptr_t ra)
-{
-    const int mmu_idx = cpu_mmu_index(env, false);
-    S390Access srca, desta;
-    uint32_t i;
-
-    HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
-               __func__, l, dest, src);
-
-    /* MVC always copies one more byte than specified - maximum is 256 */
-    l++;
-
-    srca = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
-    desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
-
-    /*
-     * "When the operands overlap, the result is obtained as if the operands
-     * were processed one byte at a time". Only non-destructive overlaps
-     * behave like memmove().
-     */
-    if (dest == src + 1) {
-        access_memset(env, &desta, access_get_byte(env, &srca, 0, ra), ra);
-    } else if (!is_destructive_overlap(env, dest, src, l)) {
-        access_memmove(env, &desta, &srca, ra);
-    } else {
-        for (i = 0; i < l; i++) {
-            uint8_t byte = access_get_byte(env, &srca, i, ra);
-
-            access_set_byte(env, &desta, i, byte, ra);
-        }
-    }
-
-    return env->cc_op;
-}
-
-void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
-{
-    do_helper_mvc(env, l, dest, src, GETPC());
-}
-
-/* move inverse  */
-void HELPER(mvcin)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
-{
-    const int mmu_idx = cpu_mmu_index(env, false);
-    S390Access srca, desta;
-    uintptr_t ra = GETPC();
-    int i;
-
-    /* MVCIN always copies one more byte than specified - maximum is 256 */
-    l++;
-
-    src = wrap_address(env, src - l + 1);
-    srca = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
-    desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
-    for (i = 0; i < l; i++) {
-        const uint8_t x = access_get_byte(env, &srca, l - i - 1, ra);
-
-        access_set_byte(env, &desta, i, x, ra);
-    }
-}
-
-/* move numerics  */
-void HELPER(mvn)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
-{
-    const int mmu_idx = cpu_mmu_index(env, false);
-    S390Access srca1, srca2, desta;
-    uintptr_t ra = GETPC();
-    int i;
-
-    /* MVN always copies one more byte than specified - maximum is 256 */
-    l++;
-
-    srca1 = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
-    srca2 = access_prepare(env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
-    desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
-    for (i = 0; i < l; i++) {
-        const uint8_t x = (access_get_byte(env, &srca1, i, ra) & 0x0f) |
-                          (access_get_byte(env, &srca2, i, ra) & 0xf0);
-
-        access_set_byte(env, &desta, i, x, ra);
-    }
-}
-
-/* move with offset  */
-void HELPER(mvo)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
-{
-    const int mmu_idx = cpu_mmu_index(env, false);
-    /* MVO always processes one more byte than specified - maximum is 16 */
-    const int len_dest = (l >> 4) + 1;
-    const int len_src = (l & 0xf) + 1;
-    uintptr_t ra = GETPC();
-    uint8_t byte_dest, byte_src;
-    S390Access srca, desta;
-    int i, j;
-
-    srca = access_prepare(env, src, len_src, MMU_DATA_LOAD, mmu_idx, ra);
-    desta = access_prepare(env, dest, len_dest, MMU_DATA_STORE, mmu_idx, ra);
-
-    /* Handle rightmost byte */
-    byte_dest = cpu_ldub_data_ra(env, dest + len_dest - 1, ra);
-    byte_src = access_get_byte(env, &srca, len_src - 1, ra);
-    byte_dest = (byte_dest & 0x0f) | (byte_src << 4);
-    access_set_byte(env, &desta, len_dest - 1, byte_dest, ra);
-
-    /* Process remaining bytes from right to left */
-    for (i = len_dest - 2, j = len_src - 2; i >= 0; i--, j--) {
-        byte_dest = byte_src >> 4;
-        if (j >= 0) {
-            byte_src = access_get_byte(env, &srca, j, ra);
-        } else {
-            byte_src = 0;
-        }
-        byte_dest |= byte_src << 4;
-        access_set_byte(env, &desta, i, byte_dest, ra);
-    }
-}
-
-/* move zones  */
-void HELPER(mvz)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
-{
-    const int mmu_idx = cpu_mmu_index(env, false);
-    S390Access srca1, srca2, desta;
-    uintptr_t ra = GETPC();
-    int i;
-
-    /* MVZ always copies one more byte than specified - maximum is 256 */
-    l++;
-
-    srca1 = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
-    srca2 = access_prepare(env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
-    desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
-    for (i = 0; i < l; i++) {
-        const uint8_t x = (access_get_byte(env, &srca1, i, ra) & 0xf0) |
-                          (access_get_byte(env, &srca2, i, ra) & 0x0f);
-
-        access_set_byte(env, &desta, i, x, ra);
-    }
-}
-
-/* compare unsigned byte arrays */
-static uint32_t do_helper_clc(CPUS390XState *env, uint32_t l, uint64_t s1,
-                              uint64_t s2, uintptr_t ra)
-{
-    uint32_t i;
-    uint32_t cc = 0;
-
-    HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n",
-               __func__, l, s1, s2);
-
-    for (i = 0; i <= l; i++) {
-        uint8_t x = cpu_ldub_data_ra(env, s1 + i, ra);
-        uint8_t y = cpu_ldub_data_ra(env, s2 + i, ra);
-        HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y);
-        if (x < y) {
-            cc = 1;
-            break;
-        } else if (x > y) {
-            cc = 2;
-            break;
-        }
-    }
-
-    HELPER_LOG("\n");
-    return cc;
-}
-
-uint32_t HELPER(clc)(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2)
-{
-    return do_helper_clc(env, l, s1, s2, GETPC());
-}
-
-/* compare logical under mask */
-uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask,
-                     uint64_t addr)
-{
-    uintptr_t ra = GETPC();
-    uint32_t cc = 0;
-
-    HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1,
-               mask, addr);
-
-    while (mask) {
-        if (mask & 8) {
-            uint8_t d = cpu_ldub_data_ra(env, addr, ra);
-            uint8_t r = extract32(r1, 24, 8);
-            HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d,
-                       addr);
-            if (r < d) {
-                cc = 1;
-                break;
-            } else if (r > d) {
-                cc = 2;
-                break;
-            }
-            addr++;
-        }
-        mask = (mask << 1) & 0xf;
-        r1 <<= 8;
-    }
-
-    HELPER_LOG("\n");
-    return cc;
-}
-
-static inline uint64_t get_address(CPUS390XState *env, int reg)
-{
-    return wrap_address(env, env->regs[reg]);
-}
-
-/*
- * Store the address to the given register, zeroing out unused leftmost
- * bits in bit positions 32-63 (24-bit and 31-bit mode only).
- */
-static inline void set_address_zero(CPUS390XState *env, int reg,
-                                    uint64_t address)
-{
-    if (env->psw.mask & PSW_MASK_64) {
-        env->regs[reg] = address;
-    } else {
-        if (!(env->psw.mask & PSW_MASK_32)) {
-            address &= 0x00ffffff;
-        } else {
-            address &= 0x7fffffff;
-        }
-        env->regs[reg] = deposit64(env->regs[reg], 0, 32, address);
-    }
-}
-
-static inline void set_address(CPUS390XState *env, int reg, uint64_t address)
-{
-    if (env->psw.mask & PSW_MASK_64) {
-        /* 64-Bit mode */
-        env->regs[reg] = address;
-    } else {
-        if (!(env->psw.mask & PSW_MASK_32)) {
-            /* 24-Bit mode. According to the PoO it is implementation
-            dependent if bits 32-39 remain unchanged or are set to
-            zeros.  Choose the former so that the function can also be
-            used for TRT.  */
-            env->regs[reg] = deposit64(env->regs[reg], 0, 24, address);
-        } else {
-            /* 31-Bit mode. According to the PoO it is implementation
-            dependent if bit 32 remains unchanged or is set to zero.
-            Choose the latter so that the function can also be used for
-            TRT.  */
-            address &= 0x7fffffff;
-            env->regs[reg] = deposit64(env->regs[reg], 0, 32, address);
-        }
-    }
-}
-
-static inline uint64_t wrap_length32(CPUS390XState *env, uint64_t length)
-{
-    if (!(env->psw.mask & PSW_MASK_64)) {
-        return (uint32_t)length;
-    }
-    return length;
-}
-
-static inline uint64_t wrap_length31(CPUS390XState *env, uint64_t length)
-{
-    if (!(env->psw.mask & PSW_MASK_64)) {
-        /* 24-Bit and 31-Bit mode */
-        length &= 0x7fffffff;
-    }
-    return length;
-}
-
-static inline uint64_t get_length(CPUS390XState *env, int reg)
-{
-    return wrap_length31(env, env->regs[reg]);
-}
-
-static inline void set_length(CPUS390XState *env, int reg, uint64_t length)
-{
-    if (env->psw.mask & PSW_MASK_64) {
-        /* 64-Bit mode */
-        env->regs[reg] = length;
-    } else {
-        /* 24-Bit and 31-Bit mode */
-        env->regs[reg] = deposit64(env->regs[reg], 0, 32, length);
-    }
-}
-
-/* search string (c is byte to search, r2 is string, r1 end of string) */
-void HELPER(srst)(CPUS390XState *env, uint32_t r1, uint32_t r2)
-{
-    uintptr_t ra = GETPC();
-    uint64_t end, str;
-    uint32_t len;
-    uint8_t v, c = env->regs[0];
-
-    /* Bits 32-55 must contain all 0.  */
-    if (env->regs[0] & 0xffffff00u) {
-        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
-    }
-
-    str = get_address(env, r2);
-    end = get_address(env, r1);
-
-    /* Lest we fail to service interrupts in a timely manner, limit the
-       amount of work we're willing to do.  For now, let's cap at 8k.  */
-    for (len = 0; len < 0x2000; ++len) {
-        if (str + len == end) {
-            /* Character not found.  R1 & R2 are unmodified.  */
-            env->cc_op = 2;
-            return;
-        }
-        v = cpu_ldub_data_ra(env, str + len, ra);
-        if (v == c) {
-            /* Character found.  Set R1 to the location; R2 is unmodified.  */
-            env->cc_op = 1;
-            set_address(env, r1, str + len);
-            return;
-        }
-    }
-
-    /* CPU-determined bytes processed.  Advance R2 to next byte to process.  */
-    env->cc_op = 3;
-    set_address(env, r2, str + len);
-}
-
-void HELPER(srstu)(CPUS390XState *env, uint32_t r1, uint32_t r2)
-{
-    uintptr_t ra = GETPC();
-    uint32_t len;
-    uint16_t v, c = env->regs[0];
-    uint64_t end, str, adj_end;
-
-    /* Bits 32-47 of R0 must be zero.  */
-    if (env->regs[0] & 0xffff0000u) {
-        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
-    }
-
-    str = get_address(env, r2);
-    end = get_address(env, r1);
-
-    /* If the LSB of the two addresses differ, use one extra byte.  */
-    adj_end = end + ((str ^ end) & 1);
-
-    /* Lest we fail to service interrupts in a timely manner, limit the
-       amount of work we're willing to do.  For now, let's cap at 8k.  */
-    for (len = 0; len < 0x2000; len += 2) {
-        if (str + len == adj_end) {
-            /* End of input found.  */
-            env->cc_op = 2;
-            return;
-        }
-        v = cpu_lduw_data_ra(env, str + len, ra);
-        if (v == c) {
-            /* Character found.  Set R1 to the location; R2 is unmodified.  */
-            env->cc_op = 1;
-            set_address(env, r1, str + len);
-            return;
-        }
-    }
-
-    /* CPU-determined bytes processed.  Advance R2 to next byte to process.  */
-    env->cc_op = 3;
-    set_address(env, r2, str + len);
-}
-
-/* unsigned string compare (c is string terminator) */
-uint64_t HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2)
-{
-    uintptr_t ra = GETPC();
-    uint32_t len;
-
-    c = c & 0xff;
-    s1 = wrap_address(env, s1);
-    s2 = wrap_address(env, s2);
-
-    /* Lest we fail to service interrupts in a timely manner, limit the
-       amount of work we're willing to do.  For now, let's cap at 8k.  */
-    for (len = 0; len < 0x2000; ++len) {
-        uint8_t v1 = cpu_ldub_data_ra(env, s1 + len, ra);
-        uint8_t v2 = cpu_ldub_data_ra(env, s2 + len, ra);
-        if (v1 == v2) {
-            if (v1 == c) {
-                /* Equal.  CC=0, and don't advance the registers.  */
-                env->cc_op = 0;
-                env->retxl = s2;
-                return s1;
-            }
-        } else {
-            /* Unequal.  CC={1,2}, and advance the registers.  Note that
-               the terminator need not be zero, but the string that contains
-               the terminator is by definition "low".  */
-            env->cc_op = (v1 == c ? 1 : v2 == c ? 2 : v1 < v2 ? 1 : 2);
-            env->retxl = s2 + len;
-            return s1 + len;
-        }
-    }
-
-    /* CPU-determined bytes equal; advance the registers.  */
-    env->cc_op = 3;
-    env->retxl = s2 + len;
-    return s1 + len;
-}
-
-/* move page */
-uint32_t HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint32_t r1, uint32_t r2)
-{
-    const uint64_t src = get_address(env, r2) & TARGET_PAGE_MASK;
-    const uint64_t dst = get_address(env, r1) & TARGET_PAGE_MASK;
-    const int mmu_idx = cpu_mmu_index(env, false);
-    const bool f = extract64(r0, 11, 1);
-    const bool s = extract64(r0, 10, 1);
-    const bool cco = extract64(r0, 8, 1);
-    uintptr_t ra = GETPC();
-    S390Access srca, desta;
-    int exc;
-
-    if ((f && s) || extract64(r0, 12, 4)) {
-        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
-    }
-
-    /*
-     * We always manually handle exceptions such that we can properly store
-     * r1/r2 to the lowcore on page-translation exceptions.
-     *
-     * TODO: Access key handling
-     */
-    exc = access_prepare_nf(&srca, env, true, src, TARGET_PAGE_SIZE,
-                            MMU_DATA_LOAD, mmu_idx, ra);
-    if (exc) {
-        if (cco) {
-            return 2;
-        }
-        goto inject_exc;
-    }
-    exc = access_prepare_nf(&desta, env, true, dst, TARGET_PAGE_SIZE,
-                            MMU_DATA_STORE, mmu_idx, ra);
-    if (exc) {
-        if (cco && exc != PGM_PROTECTION) {
-            return 1;
-        }
-        goto inject_exc;
-    }
-    access_memmove(env, &desta, &srca, ra);
-    return 0; /* data moved */
-inject_exc:
-#if !defined(CONFIG_USER_ONLY)
-    if (exc != PGM_ADDRESSING) {
-        stq_phys(env_cpu(env)->as, env->psa + offsetof(LowCore, trans_exc_code),
-                 env->tlb_fill_tec);
-    }
-    if (exc == PGM_PAGE_TRANS) {
-        stb_phys(env_cpu(env)->as, env->psa + offsetof(LowCore, op_access_id),
-                 r1 << 4 | r2);
-    }
-#endif
-    tcg_s390_program_interrupt(env, exc, ra);
-}
-
-/* string copy */
-uint32_t HELPER(mvst)(CPUS390XState *env, uint32_t r1, uint32_t r2)
-{
-    const int mmu_idx = cpu_mmu_index(env, false);
-    const uint64_t d = get_address(env, r1);
-    const uint64_t s = get_address(env, r2);
-    const uint8_t c = env->regs[0];
-    const int len = MIN(-(d | TARGET_PAGE_MASK), -(s | TARGET_PAGE_MASK));
-    S390Access srca, desta;
-    uintptr_t ra = GETPC();
-    int i;
-
-    if (env->regs[0] & 0xffffff00ull) {
-        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
-    }
-
-    /*
-     * Our access should not exceed single pages, as we must not report access
-     * exceptions exceeding the actually copied range (which we don't know at
-     * this point). We might over-indicate watchpoints within the pages
-     * (if we ever care, we have to limit processing to a single byte).
-     */
-    srca = access_prepare(env, s, len, MMU_DATA_LOAD, mmu_idx, ra);
-    desta = access_prepare(env, d, len, MMU_DATA_STORE, mmu_idx, ra);
-    for (i = 0; i < len; i++) {
-        const uint8_t v = access_get_byte(env, &srca, i, ra);
-
-        access_set_byte(env, &desta, i, v, ra);
-        if (v == c) {
-            set_address_zero(env, r1, d + i);
-            return 1;
-        }
-    }
-    set_address_zero(env, r1, d + len);
-    set_address_zero(env, r2, s + len);
-    return 3;
-}
-
-/* load access registers r1 to r3 from memory at a2 */
-void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
-{
-    uintptr_t ra = GETPC();
-    int i;
-
-    if (a2 & 0x3) {
-        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
-    }
-
-    for (i = r1;; i = (i + 1) % 16) {
-        env->aregs[i] = cpu_ldl_data_ra(env, a2, ra);
-        a2 += 4;
-
-        if (i == r3) {
-            break;
-        }
-    }
-}
-
-/* store access registers r1 to r3 in memory at a2 */
-void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
-{
-    uintptr_t ra = GETPC();
-    int i;
-
-    if (a2 & 0x3) {
-        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
-    }
-
-    for (i = r1;; i = (i + 1) % 16) {
-        cpu_stl_data_ra(env, a2, env->aregs[i], ra);
-        a2 += 4;
-
-        if (i == r3) {
-            break;
-        }
-    }
-}
-
-/* move long helper */
-static inline uint32_t do_mvcl(CPUS390XState *env,
-                               uint64_t *dest, uint64_t *destlen,
-                               uint64_t *src, uint64_t *srclen,
-                               uint16_t pad, int wordsize, uintptr_t ra)
-{
-    const int mmu_idx = cpu_mmu_index(env, false);
-    int len = MIN(*destlen, -(*dest | TARGET_PAGE_MASK));
-    S390Access srca, desta;
-    int i, cc;
-
-    if (*destlen == *srclen) {
-        cc = 0;
-    } else if (*destlen < *srclen) {
-        cc = 1;
-    } else {
-        cc = 2;
-    }
-
-    if (!*destlen) {
-        return cc;
-    }
-
-    /*
-     * Only perform one type of type of operation (move/pad) at a time.
-     * Stay within single pages.
-     */
-    if (*srclen) {
-        /* Copy the src array */
-        len = MIN(MIN(*srclen, -(*src | TARGET_PAGE_MASK)), len);
-        *destlen -= len;
-        *srclen -= len;
-        srca = access_prepare(env, *src, len, MMU_DATA_LOAD, mmu_idx, ra);
-        desta = access_prepare(env, *dest, len, MMU_DATA_STORE, mmu_idx, ra);
-        access_memmove(env, &desta, &srca, ra);
-        *src = wrap_address(env, *src + len);
-        *dest = wrap_address(env, *dest + len);
-    } else if (wordsize == 1) {
-        /* Pad the remaining area */
-        *destlen -= len;
-        desta = access_prepare(env, *dest, len, MMU_DATA_STORE, mmu_idx, ra);
-        access_memset(env, &desta, pad, ra);
-        *dest = wrap_address(env, *dest + len);
-    } else {
-        desta = access_prepare(env, *dest, len, MMU_DATA_STORE, mmu_idx, ra);
-
-        /* The remaining length selects the padding byte. */
-        for (i = 0; i < len; (*destlen)--, i++) {
-            if (*destlen & 1) {
-                access_set_byte(env, &desta, i, pad, ra);
-            } else {
-                access_set_byte(env, &desta, i, pad >> 8, ra);
-            }
-        }
-        *dest = wrap_address(env, *dest + len);
-    }
-
-    return *destlen ? 3 : cc;
-}
-
-/* move long */
-uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
-{
-    const int mmu_idx = cpu_mmu_index(env, false);
-    uintptr_t ra = GETPC();
-    uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
-    uint64_t dest = get_address(env, r1);
-    uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
-    uint64_t src = get_address(env, r2);
-    uint8_t pad = env->regs[r2 + 1] >> 24;
-    CPUState *cs = env_cpu(env);
-    S390Access srca, desta;
-    uint32_t cc, cur_len;
-
-    if (is_destructive_overlap(env, dest, src, MIN(srclen, destlen))) {
-        cc = 3;
-    } else if (srclen == destlen) {
-        cc = 0;
-    } else if (destlen < srclen) {
-        cc = 1;
-    } else {
-        cc = 2;
-    }
-
-    /* We might have to zero-out some bits even if there was no action. */
-    if (unlikely(!destlen || cc == 3)) {
-        set_address_zero(env, r2, src);
-        set_address_zero(env, r1, dest);
-        return cc;
-    } else if (!srclen) {
-        set_address_zero(env, r2, src);
-    }
-
-    /*
-     * Only perform one type of type of operation (move/pad) in one step.
-     * Stay within single pages.
-     */
-    while (destlen) {
-        cur_len = MIN(destlen, -(dest | TARGET_PAGE_MASK));
-        if (!srclen) {
-            desta = access_prepare(env, dest, cur_len, MMU_DATA_STORE, mmu_idx,
-                                   ra);
-            access_memset(env, &desta, pad, ra);
-        } else {
-            cur_len = MIN(MIN(srclen, -(src | TARGET_PAGE_MASK)), cur_len);
-
-            srca = access_prepare(env, src, cur_len, MMU_DATA_LOAD, mmu_idx,
-                                  ra);
-            desta = access_prepare(env, dest, cur_len, MMU_DATA_STORE, mmu_idx,
-                                   ra);
-            access_memmove(env, &desta, &srca, ra);
-            src = wrap_address(env, src + cur_len);
-            srclen -= cur_len;
-            env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, srclen);
-            set_address_zero(env, r2, src);
-        }
-        dest = wrap_address(env, dest + cur_len);
-        destlen -= cur_len;
-        env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, destlen);
-        set_address_zero(env, r1, dest);
-
-        /*
-         * MVCL is interruptible. Return to the main loop if requested after
-         * writing back all state to registers. If no interrupt will get
-         * injected, we'll end up back in this handler and continue processing
-         * the remaining parts.
-         */
-        if (destlen && unlikely(cpu_loop_exit_requested(cs))) {
-            cpu_loop_exit_restore(cs, ra);
-        }
-    }
-    return cc;
-}
-
-/* move long extended */
-uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
-                       uint32_t r3)
-{
-    uintptr_t ra = GETPC();
-    uint64_t destlen = get_length(env, r1 + 1);
-    uint64_t dest = get_address(env, r1);
-    uint64_t srclen = get_length(env, r3 + 1);
-    uint64_t src = get_address(env, r3);
-    uint8_t pad = a2;
-    uint32_t cc;
-
-    cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 1, ra);
-
-    set_length(env, r1 + 1, destlen);
-    set_length(env, r3 + 1, srclen);
-    set_address(env, r1, dest);
-    set_address(env, r3, src);
-
-    return cc;
-}
-
-/* move long unicode */
-uint32_t HELPER(mvclu)(CPUS390XState *env, uint32_t r1, uint64_t a2,
-                       uint32_t r3)
-{
-    uintptr_t ra = GETPC();
-    uint64_t destlen = get_length(env, r1 + 1);
-    uint64_t dest = get_address(env, r1);
-    uint64_t srclen = get_length(env, r3 + 1);
-    uint64_t src = get_address(env, r3);
-    uint16_t pad = a2;
-    uint32_t cc;
-
-    cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 2, ra);
-
-    set_length(env, r1 + 1, destlen);
-    set_length(env, r3 + 1, srclen);
-    set_address(env, r1, dest);
-    set_address(env, r3, src);
-
-    return cc;
-}
-
-/* compare logical long helper */
-static inline uint32_t do_clcl(CPUS390XState *env,
-                               uint64_t *src1, uint64_t *src1len,
-                               uint64_t *src3, uint64_t *src3len,
-                               uint16_t pad, uint64_t limit,
-                               int wordsize, uintptr_t ra)
-{
-    uint64_t len = MAX(*src1len, *src3len);
-    uint32_t cc = 0;
-
-    check_alignment(env, *src1len | *src3len, wordsize, ra);
-
-    if (!len) {
-        return cc;
-    }
-
-    /* Lest we fail to service interrupts in a timely manner, limit the
-       amount of work we're willing to do.  */
-    if (len > limit) {
-        len = limit;
-        cc = 3;
-    }
-
-    for (; len; len -= wordsize) {
-        uint16_t v1 = pad;
-        uint16_t v3 = pad;
-
-        if (*src1len) {
-            v1 = cpu_ldusize_data_ra(env, *src1, wordsize, ra);
-        }
-        if (*src3len) {
-            v3 = cpu_ldusize_data_ra(env, *src3, wordsize, ra);
-        }
-
-        if (v1 != v3) {
-            cc = (v1 < v3) ? 1 : 2;
-            break;
-        }
-
-        if (*src1len) {
-            *src1 += wordsize;
-            *src1len -= wordsize;
-        }
-        if (*src3len) {
-            *src3 += wordsize;
-            *src3len -= wordsize;
-        }
-    }
-
-    return cc;
-}
-
-
-/* compare logical long */
-uint32_t HELPER(clcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
-{
-    uintptr_t ra = GETPC();
-    uint64_t src1len = extract64(env->regs[r1 + 1], 0, 24);
-    uint64_t src1 = get_address(env, r1);
-    uint64_t src3len = extract64(env->regs[r2 + 1], 0, 24);
-    uint64_t src3 = get_address(env, r2);
-    uint8_t pad = env->regs[r2 + 1] >> 24;
-    uint32_t cc;
-
-    cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, -1, 1, ra);
-
-    env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, src1len);
-    env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, src3len);
-    set_address(env, r1, src1);
-    set_address(env, r2, src3);
-
-    return cc;
-}
-
-/* compare logical long extended memcompare insn with padding */
-uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
-                       uint32_t r3)
-{
-    uintptr_t ra = GETPC();
-    uint64_t src1len = get_length(env, r1 + 1);
-    uint64_t src1 = get_address(env, r1);
-    uint64_t src3len = get_length(env, r3 + 1);
-    uint64_t src3 = get_address(env, r3);
-    uint8_t pad = a2;
-    uint32_t cc;
-
-    cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, 0x2000, 1, ra);
-
-    set_length(env, r1 + 1, src1len);
-    set_length(env, r3 + 1, src3len);
-    set_address(env, r1, src1);
-    set_address(env, r3, src3);
-
-    return cc;
-}
-
-/* compare logical long unicode memcompare insn with padding */
-uint32_t HELPER(clclu)(CPUS390XState *env, uint32_t r1, uint64_t a2,
-                       uint32_t r3)
-{
-    uintptr_t ra = GETPC();
-    uint64_t src1len = get_length(env, r1 + 1);
-    uint64_t src1 = get_address(env, r1);
-    uint64_t src3len = get_length(env, r3 + 1);
-    uint64_t src3 = get_address(env, r3);
-    uint16_t pad = a2;
-    uint32_t cc = 0;
-
-    cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, 0x1000, 2, ra);
-
-    set_length(env, r1 + 1, src1len);
-    set_length(env, r3 + 1, src3len);
-    set_address(env, r1, src1);
-    set_address(env, r3, src3);
-
-    return cc;
-}
-
-/* checksum */
-uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1,
-                      uint64_t src, uint64_t src_len)
-{
-    uintptr_t ra = GETPC();
-    uint64_t max_len, len;
-    uint64_t cksm = (uint32_t)r1;
-
-    /* Lest we fail to service interrupts in a timely manner, limit the
-       amount of work we're willing to do.  For now, let's cap at 8k.  */
-    max_len = (src_len > 0x2000 ? 0x2000 : src_len);
-
-    /* Process full words as available.  */
-    for (len = 0; len + 4 <= max_len; len += 4, src += 4) {
-        cksm += (uint32_t)cpu_ldl_data_ra(env, src, ra);
-    }
-
-    switch (max_len - len) {
-    case 1:
-        cksm += cpu_ldub_data_ra(env, src, ra) << 24;
-        len += 1;
-        break;
-    case 2:
-        cksm += cpu_lduw_data_ra(env, src, ra) << 16;
-        len += 2;
-        break;
-    case 3:
-        cksm += cpu_lduw_data_ra(env, src, ra) << 16;
-        cksm += cpu_ldub_data_ra(env, src + 2, ra) << 8;
-        len += 3;
-        break;
-    }
-
-    /* Fold the carry from the checksum.  Note that we can see carry-out
-       during folding more than once (but probably not more than twice).  */
-    while (cksm > 0xffffffffull) {
-        cksm = (uint32_t)cksm + (cksm >> 32);
-    }
-
-    /* Indicate whether or not we've processed everything.  */
-    env->cc_op = (len == src_len ? 0 : 3);
-
-    /* Return both cksm and processed length.  */
-    env->retxl = cksm;
-    return len;
-}
-
-void HELPER(pack)(CPUS390XState *env, uint32_t len, uint64_t dest, uint64_t src)
-{
-    uintptr_t ra = GETPC();
-    int len_dest = len >> 4;
-    int len_src = len & 0xf;
-    uint8_t b;
-
-    dest += len_dest;
-    src += len_src;
-
-    /* last byte is special, it only flips the nibbles */
-    b = cpu_ldub_data_ra(env, src, ra);
-    cpu_stb_data_ra(env, dest, (b << 4) | (b >> 4), ra);
-    src--;
-    len_src--;
-
-    /* now pack every value */
-    while (len_dest > 0) {
-        b = 0;
-
-        if (len_src >= 0) {
-            b = cpu_ldub_data_ra(env, src, ra) & 0x0f;
-            src--;
-            len_src--;
-        }
-        if (len_src >= 0) {
-            b |= cpu_ldub_data_ra(env, src, ra) << 4;
-            src--;
-            len_src--;
-        }
-
-        len_dest--;
-        dest--;
-        cpu_stb_data_ra(env, dest, b, ra);
-    }
-}
-
-static inline void do_pkau(CPUS390XState *env, uint64_t dest, uint64_t src,
-                           uint32_t srclen, int ssize, uintptr_t ra)
-{
-    int i;
-    /* The destination operand is always 16 bytes long.  */
-    const int destlen = 16;
-
-    /* The operands are processed from right to left.  */
-    src += srclen - 1;
-    dest += destlen - 1;
-
-    for (i = 0; i < destlen; i++) {
-        uint8_t b = 0;
-
-        /* Start with a positive sign */
-        if (i == 0) {
-            b = 0xc;
-        } else if (srclen > ssize) {
-            b = cpu_ldub_data_ra(env, src, ra) & 0x0f;
-            src -= ssize;
-            srclen -= ssize;
-        }
-
-        if (srclen > ssize) {
-            b |= cpu_ldub_data_ra(env, src, ra) << 4;
-            src -= ssize;
-            srclen -= ssize;
-        }
-
-        cpu_stb_data_ra(env, dest, b, ra);
-        dest--;
-    }
-}
-
-
-void HELPER(pka)(CPUS390XState *env, uint64_t dest, uint64_t src,
-                 uint32_t srclen)
-{
-    do_pkau(env, dest, src, srclen, 1, GETPC());
-}
-
-void HELPER(pku)(CPUS390XState *env, uint64_t dest, uint64_t src,
-                 uint32_t srclen)
-{
-    do_pkau(env, dest, src, srclen, 2, GETPC());
-}
-
-void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest,
-                  uint64_t src)
-{
-    uintptr_t ra = GETPC();
-    int len_dest = len >> 4;
-    int len_src = len & 0xf;
-    uint8_t b;
-    int second_nibble = 0;
-
-    dest += len_dest;
-    src += len_src;
-
-    /* last byte is special, it only flips the nibbles */
-    b = cpu_ldub_data_ra(env, src, ra);
-    cpu_stb_data_ra(env, dest, (b << 4) | (b >> 4), ra);
-    src--;
-    len_src--;
-
-    /* now pad every nibble with 0xf0 */
-
-    while (len_dest > 0) {
-        uint8_t cur_byte = 0;
-
-        if (len_src > 0) {
-            cur_byte = cpu_ldub_data_ra(env, src, ra);
-        }
-
-        len_dest--;
-        dest--;
-
-        /* only advance one nibble at a time */
-        if (second_nibble) {
-            cur_byte >>= 4;
-            len_src--;
-            src--;
-        }
-        second_nibble = !second_nibble;
-
-        /* digit */
-        cur_byte = (cur_byte & 0xf);
-        /* zone bits */
-        cur_byte |= 0xf0;
-
-        cpu_stb_data_ra(env, dest, cur_byte, ra);
-    }
-}
-
-static inline uint32_t do_unpkau(CPUS390XState *env, uint64_t dest,
-                                 uint32_t destlen, int dsize, uint64_t src,
-                                 uintptr_t ra)
-{
-    int i;
-    uint32_t cc;
-    uint8_t b;
-    /* The source operand is always 16 bytes long.  */
-    const int srclen = 16;
-
-    /* The operands are processed from right to left.  */
-    src += srclen - 1;
-    dest += destlen - dsize;
-
-    /* Check for the sign.  */
-    b = cpu_ldub_data_ra(env, src, ra);
-    src--;
-    switch (b & 0xf) {
-    case 0xa:
-    case 0xc:
-    case 0xe ... 0xf:
-        cc = 0;  /* plus */
-        break;
-    case 0xb:
-    case 0xd:
-        cc = 1;  /* minus */
-        break;
-    default:
-    case 0x0 ... 0x9:
-        cc = 3;  /* invalid */
-        break;
-    }
-
-    /* Now pad every nibble with 0x30, advancing one nibble at a time. */
-    for (i = 0; i < destlen; i += dsize) {
-        if (i == (31 * dsize)) {
-            /* If length is 32/64 bytes, the leftmost byte is 0. */
-            b = 0;
-        } else if (i % (2 * dsize)) {
-            b = cpu_ldub_data_ra(env, src, ra);
-            src--;
-        } else {
-            b >>= 4;
-        }
-        cpu_stsize_data_ra(env, dest, 0x30 + (b & 0xf), dsize, ra);
-        dest -= dsize;
-    }
-
-    return cc;
-}
-
-uint32_t HELPER(unpka)(CPUS390XState *env, uint64_t dest, uint32_t destlen,
-                       uint64_t src)
-{
-    return do_unpkau(env, dest, destlen, 1, src, GETPC());
-}
-
-uint32_t HELPER(unpku)(CPUS390XState *env, uint64_t dest, uint32_t destlen,
-                       uint64_t src)
-{
-    return do_unpkau(env, dest, destlen, 2, src, GETPC());
-}
-
-uint32_t HELPER(tp)(CPUS390XState *env, uint64_t dest, uint32_t destlen)
-{
-    uintptr_t ra = GETPC();
-    uint32_t cc = 0;
-    int i;
-
-    for (i = 0; i < destlen; i++) {
-        uint8_t b = cpu_ldub_data_ra(env, dest + i, ra);
-        /* digit */
-        cc |= (b & 0xf0) > 0x90 ? 2 : 0;
-
-        if (i == (destlen - 1)) {
-            /* sign */
-            cc |= (b & 0xf) < 0xa ? 1 : 0;
-        } else {
-            /* digit */
-            cc |= (b & 0xf) > 0x9 ? 2 : 0;
-        }
-    }
-
-    return cc;
-}
-
-static uint32_t do_helper_tr(CPUS390XState *env, uint32_t len, uint64_t array,
-                             uint64_t trans, uintptr_t ra)
-{
-    uint32_t i;
-
-    for (i = 0; i <= len; i++) {
-        uint8_t byte = cpu_ldub_data_ra(env, array + i, ra);
-        uint8_t new_byte = cpu_ldub_data_ra(env, trans + byte, ra);
-        cpu_stb_data_ra(env, array + i, new_byte, ra);
-    }
-
-    return env->cc_op;
-}
-
-void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array,
-                uint64_t trans)
-{
-    do_helper_tr(env, len, array, trans, GETPC());
-}
-
-uint64_t HELPER(tre)(CPUS390XState *env, uint64_t array,
-                     uint64_t len, uint64_t trans)
-{
-    uintptr_t ra = GETPC();
-    uint8_t end = env->regs[0] & 0xff;
-    uint64_t l = len;
-    uint64_t i;
-    uint32_t cc = 0;
-
-    if (!(env->psw.mask & PSW_MASK_64)) {
-        array &= 0x7fffffff;
-        l = (uint32_t)l;
-    }
-
-    /* Lest we fail to service interrupts in a timely manner, limit the
-       amount of work we're willing to do.  For now, let's cap at 8k.  */
-    if (l > 0x2000) {
-        l = 0x2000;
-        cc = 3;
-    }
-
-    for (i = 0; i < l; i++) {
-        uint8_t byte, new_byte;
-
-        byte = cpu_ldub_data_ra(env, array + i, ra);
-
-        if (byte == end) {
-            cc = 1;
-            break;
-        }
-
-        new_byte = cpu_ldub_data_ra(env, trans + byte, ra);
-        cpu_stb_data_ra(env, array + i, new_byte, ra);
-    }
-
-    env->cc_op = cc;
-    env->retxl = len - i;
-    return array + i;
-}
-
-static inline uint32_t do_helper_trt(CPUS390XState *env, int len,
-                                     uint64_t array, uint64_t trans,
-                                     int inc, uintptr_t ra)
-{
-    int i;
-
-    for (i = 0; i <= len; i++) {
-        uint8_t byte = cpu_ldub_data_ra(env, array + i * inc, ra);
-        uint8_t sbyte = cpu_ldub_data_ra(env, trans + byte, ra);
-
-        if (sbyte != 0) {
-            set_address(env, 1, array + i * inc);
-            env->regs[2] = deposit64(env->regs[2], 0, 8, sbyte);
-            return (i == len) ? 2 : 1;
-        }
-    }
-
-    return 0;
-}
-
-static uint32_t do_helper_trt_fwd(CPUS390XState *env, uint32_t len,
-                                  uint64_t array, uint64_t trans,
-                                  uintptr_t ra)
-{
-    return do_helper_trt(env, len, array, trans, 1, ra);
-}
-
-uint32_t HELPER(trt)(CPUS390XState *env, uint32_t len, uint64_t array,
-                     uint64_t trans)
-{
-    return do_helper_trt(env, len, array, trans, 1, GETPC());
-}
-
-static uint32_t do_helper_trt_bkwd(CPUS390XState *env, uint32_t len,
-                                   uint64_t array, uint64_t trans,
-                                   uintptr_t ra)
-{
-    return do_helper_trt(env, len, array, trans, -1, ra);
-}
-
-uint32_t HELPER(trtr)(CPUS390XState *env, uint32_t len, uint64_t array,
-                      uint64_t trans)
-{
-    return do_helper_trt(env, len, array, trans, -1, GETPC());
-}
-
-/* Translate one/two to one/two */
-uint32_t HELPER(trXX)(CPUS390XState *env, uint32_t r1, uint32_t r2,
-                      uint32_t tst, uint32_t sizes)
-{
-    uintptr_t ra = GETPC();
-    int dsize = (sizes & 1) ? 1 : 2;
-    int ssize = (sizes & 2) ? 1 : 2;
-    uint64_t tbl = get_address(env, 1);
-    uint64_t dst = get_address(env, r1);
-    uint64_t len = get_length(env, r1 + 1);
-    uint64_t src = get_address(env, r2);
-    uint32_t cc = 3;
-    int i;
-
-    /* The lower address bits of TBL are ignored.  For TROO, TROT, it's
-       the low 3 bits (double-word aligned).  For TRTO, TRTT, it's either
-       the low 12 bits (4K, without ETF2-ENH) or 3 bits (with ETF2-ENH).  */
-    if (ssize == 2 && !s390_has_feat(S390_FEAT_ETF2_ENH)) {
-        tbl &= -4096;
-    } else {
-        tbl &= -8;
-    }
-
-    check_alignment(env, len, ssize, ra);
-
-    /* Lest we fail to service interrupts in a timely manner, */
-    /* limit the amount of work we're willing to do.   */
-    for (i = 0; i < 0x2000; i++) {
-        uint16_t sval = cpu_ldusize_data_ra(env, src, ssize, ra);
-        uint64_t tble = tbl + (sval * dsize);
-        uint16_t dval = cpu_ldusize_data_ra(env, tble, dsize, ra);
-        if (dval == tst) {
-            cc = 1;
-            break;
-        }
-        cpu_stsize_data_ra(env, dst, dval, dsize, ra);
-
-        len -= ssize;
-        src += ssize;
-        dst += dsize;
-
-        if (len == 0) {
-            cc = 0;
-            break;
-        }
-    }
-
-    set_address(env, r1, dst);
-    set_length(env, r1 + 1, len);
-    set_address(env, r2, src);
-
-    return cc;
-}
-
-void HELPER(cdsg)(CPUS390XState *env, uint64_t addr,
-                  uint32_t r1, uint32_t r3)
-{
-    uintptr_t ra = GETPC();
-    Int128 cmpv = int128_make128(env->regs[r1 + 1], env->regs[r1]);
-    Int128 newv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
-    Int128 oldv;
-    uint64_t oldh, oldl;
-    bool fail;
-
-    check_alignment(env, addr, 16, ra);
-
-    oldh = cpu_ldq_data_ra(env, addr + 0, ra);
-    oldl = cpu_ldq_data_ra(env, addr + 8, ra);
-
-    oldv = int128_make128(oldl, oldh);
-    fail = !int128_eq(oldv, cmpv);
-    if (fail) {
-        newv = oldv;
-    }
-
-    cpu_stq_data_ra(env, addr + 0, int128_gethi(newv), ra);
-    cpu_stq_data_ra(env, addr + 8, int128_getlo(newv), ra);
-
-    env->cc_op = fail;
-    env->regs[r1] = int128_gethi(oldv);
-    env->regs[r1 + 1] = int128_getlo(oldv);
-}
-
-void HELPER(cdsg_parallel)(CPUS390XState *env, uint64_t addr,
-                           uint32_t r1, uint32_t r3)
-{
-    uintptr_t ra = GETPC();
-    Int128 cmpv = int128_make128(env->regs[r1 + 1], env->regs[r1]);
-    Int128 newv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
-    int mem_idx;
-    TCGMemOpIdx oi;
-    Int128 oldv;
-    bool fail;
-
-    assert(HAVE_CMPXCHG128);
-
-    mem_idx = cpu_mmu_index(env, false);
-    oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
-    oldv = helper_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra);
-    fail = !int128_eq(oldv, cmpv);
-
-    env->cc_op = fail;
-    env->regs[r1] = int128_gethi(oldv);
-    env->regs[r1 + 1] = int128_getlo(oldv);
-}
-
-static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1,
-                        uint64_t a2, bool parallel)
-{
-    uint32_t mem_idx = cpu_mmu_index(env, false);
-    uintptr_t ra = GETPC();
-    uint32_t fc = extract32(env->regs[0], 0, 8);
-    uint32_t sc = extract32(env->regs[0], 8, 8);
-    uint64_t pl = get_address(env, 1) & -16;
-    uint64_t svh, svl;
-    uint32_t cc;
-
-    /* Sanity check the function code and storage characteristic.  */
-    if (fc > 1 || sc > 3) {
-        if (!s390_has_feat(S390_FEAT_COMPARE_AND_SWAP_AND_STORE_2)) {
-            goto spec_exception;
-        }
-        if (fc > 2 || sc > 4 || (fc == 2 && (r3 & 1))) {
-            goto spec_exception;
-        }
-    }
-
-    /* Sanity check the alignments.  */
-    if (extract32(a1, 0, fc + 2) || extract32(a2, 0, sc)) {
-        goto spec_exception;
-    }
-
-    /* Sanity check writability of the store address.  */
-    probe_write(env, a2, 1 << sc, mem_idx, ra);
-
-    /*
-     * Note that the compare-and-swap is atomic, and the store is atomic,
-     * but the complete operation is not.  Therefore we do not need to
-     * assert serial context in order to implement this.  That said,
-     * restart early if we can't support either operation that is supposed
-     * to be atomic.
-     */
-    if (parallel) {
-        uint32_t max = 2;
-#ifdef CONFIG_ATOMIC64
-        max = 3;
-#endif
-        if ((HAVE_CMPXCHG128 ? 0 : fc + 2 > max) ||
-            (HAVE_ATOMIC128  ? 0 : sc > max)) {
-            cpu_loop_exit_atomic(env_cpu(env), ra);
-        }
-    }
-
-    /* All loads happen before all stores.  For simplicity, load the entire
-       store value area from the parameter list.  */
-    svh = cpu_ldq_data_ra(env, pl + 16, ra);
-    svl = cpu_ldq_data_ra(env, pl + 24, ra);
-
-    switch (fc) {
-    case 0:
-        {
-            uint32_t nv = cpu_ldl_data_ra(env, pl, ra);
-            uint32_t cv = env->regs[r3];
-            uint32_t ov;
-
-            if (parallel) {
-#ifdef CONFIG_USER_ONLY
-                uint32_t *haddr = g2h(env_cpu(env), a1);
-                ov = qatomic_cmpxchg__nocheck(haddr, cv, nv);
-#else
-                TCGMemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mem_idx);
-                ov = helper_atomic_cmpxchgl_be_mmu(env, a1, cv, nv, oi, ra);
-#endif
-            } else {
-                ov = cpu_ldl_data_ra(env, a1, ra);
-                cpu_stl_data_ra(env, a1, (ov == cv ? nv : ov), ra);
-            }
-            cc = (ov != cv);
-            env->regs[r3] = deposit64(env->regs[r3], 32, 32, ov);
-        }
-        break;
-
-    case 1:
-        {
-            uint64_t nv = cpu_ldq_data_ra(env, pl, ra);
-            uint64_t cv = env->regs[r3];
-            uint64_t ov;
-
-            if (parallel) {
-#ifdef CONFIG_ATOMIC64
-# ifdef CONFIG_USER_ONLY
-                uint64_t *haddr = g2h(env_cpu(env), a1);
-                ov = qatomic_cmpxchg__nocheck(haddr, cv, nv);
-# else
-                TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN, mem_idx);
-                ov = helper_atomic_cmpxchgq_be_mmu(env, a1, cv, nv, oi, ra);
-# endif
-#else
-                /* Note that we asserted !parallel above.  */
-                g_assert_not_reached();
-#endif
-            } else {
-                ov = cpu_ldq_data_ra(env, a1, ra);
-                cpu_stq_data_ra(env, a1, (ov == cv ? nv : ov), ra);
-            }
-            cc = (ov != cv);
-            env->regs[r3] = ov;
-        }
-        break;
-
-    case 2:
-        {
-            uint64_t nvh = cpu_ldq_data_ra(env, pl, ra);
-            uint64_t nvl = cpu_ldq_data_ra(env, pl + 8, ra);
-            Int128 nv = int128_make128(nvl, nvh);
-            Int128 cv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
-            Int128 ov;
-
-            if (!parallel) {
-                uint64_t oh = cpu_ldq_data_ra(env, a1 + 0, ra);
-                uint64_t ol = cpu_ldq_data_ra(env, a1 + 8, ra);
-
-                ov = int128_make128(ol, oh);
-                cc = !int128_eq(ov, cv);
-                if (cc) {
-                    nv = ov;
-                }
-
-                cpu_stq_data_ra(env, a1 + 0, int128_gethi(nv), ra);
-                cpu_stq_data_ra(env, a1 + 8, int128_getlo(nv), ra);
-            } else if (HAVE_CMPXCHG128) {
-                TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
-                ov = helper_atomic_cmpxchgo_be_mmu(env, a1, cv, nv, oi, ra);
-                cc = !int128_eq(ov, cv);
-            } else {
-                /* Note that we asserted !parallel above.  */
-                g_assert_not_reached();
-            }
-
-            env->regs[r3 + 0] = int128_gethi(ov);
-            env->regs[r3 + 1] = int128_getlo(ov);
-        }
-        break;
-
-    default:
-        g_assert_not_reached();
-    }
-
-    /* Store only if the comparison succeeded.  Note that above we use a pair
-       of 64-bit big-endian loads, so for sc < 3 we must extract the value
-       from the most-significant bits of svh.  */
-    if (cc == 0) {
-        switch (sc) {
-        case 0:
-            cpu_stb_data_ra(env, a2, svh >> 56, ra);
-            break;
-        case 1:
-            cpu_stw_data_ra(env, a2, svh >> 48, ra);
-            break;
-        case 2:
-            cpu_stl_data_ra(env, a2, svh >> 32, ra);
-            break;
-        case 3:
-            cpu_stq_data_ra(env, a2, svh, ra);
-            break;
-        case 4:
-            if (!parallel) {
-                cpu_stq_data_ra(env, a2 + 0, svh, ra);
-                cpu_stq_data_ra(env, a2 + 8, svl, ra);
-            } else if (HAVE_ATOMIC128) {
-                TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
-                Int128 sv = int128_make128(svl, svh);
-                helper_atomic_sto_be_mmu(env, a2, sv, oi, ra);
-            } else {
-                /* Note that we asserted !parallel above.  */
-                g_assert_not_reached();
-            }
-            break;
-        default:
-            g_assert_not_reached();
-        }
-    }
-
-    return cc;
-
- spec_exception:
-    tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
-}
-
-uint32_t HELPER(csst)(CPUS390XState *env, uint32_t r3, uint64_t a1, uint64_t a2)
-{
-    return do_csst(env, r3, a1, a2, false);
-}
-
-uint32_t HELPER(csst_parallel)(CPUS390XState *env, uint32_t r3, uint64_t a1,
-                               uint64_t a2)
-{
-    return do_csst(env, r3, a1, a2, true);
-}
-
-#if !defined(CONFIG_USER_ONLY)
-void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
-{
-    uintptr_t ra = GETPC();
-    bool PERchanged = false;
-    uint64_t src = a2;
-    uint32_t i;
-
-    if (src & 0x7) {
-        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
-    }
-
-    for (i = r1;; i = (i + 1) % 16) {
-        uint64_t val = cpu_ldq_data_ra(env, src, ra);
-        if (env->cregs[i] != val && i >= 9 && i <= 11) {
-            PERchanged = true;
-        }
-        env->cregs[i] = val;
-        HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
-                   i, src, val);
-        src += sizeof(uint64_t);
-
-        if (i == r3) {
-            break;
-        }
-    }
-
-    if (PERchanged && env->psw.mask & PSW_MASK_PER) {
-        s390_cpu_recompute_watchpoints(env_cpu(env));
-    }
-
-    tlb_flush(env_cpu(env));
-}
-
-void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
-{
-    uintptr_t ra = GETPC();
-    bool PERchanged = false;
-    uint64_t src = a2;
-    uint32_t i;
-
-    if (src & 0x3) {
-        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
-    }
-
-    for (i = r1;; i = (i + 1) % 16) {
-        uint32_t val = cpu_ldl_data_ra(env, src, ra);
-        if ((uint32_t)env->cregs[i] != val && i >= 9 && i <= 11) {
-            PERchanged = true;
-        }
-        env->cregs[i] = deposit64(env->cregs[i], 0, 32, val);
-        HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%x\n", i, src, val);
-        src += sizeof(uint32_t);
-
-        if (i == r3) {
-            break;
-        }
-    }
-
-    if (PERchanged && env->psw.mask & PSW_MASK_PER) {
-        s390_cpu_recompute_watchpoints(env_cpu(env));
-    }
-
-    tlb_flush(env_cpu(env));
-}
-
-void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
-{
-    uintptr_t ra = GETPC();
-    uint64_t dest = a2;
-    uint32_t i;
-
-    if (dest & 0x7) {
-        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
-    }
-
-    for (i = r1;; i = (i + 1) % 16) {
-        cpu_stq_data_ra(env, dest, env->cregs[i], ra);
-        dest += sizeof(uint64_t);
-
-        if (i == r3) {
-            break;
-        }
-    }
-}
-
-void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
-{
-    uintptr_t ra = GETPC();
-    uint64_t dest = a2;
-    uint32_t i;
-
-    if (dest & 0x3) {
-        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
-    }
-
-    for (i = r1;; i = (i + 1) % 16) {
-        cpu_stl_data_ra(env, dest, env->cregs[i], ra);
-        dest += sizeof(uint32_t);
-
-        if (i == r3) {
-            break;
-        }
-    }
-}
-
-uint32_t HELPER(testblock)(CPUS390XState *env, uint64_t real_addr)
-{
-    uintptr_t ra = GETPC();
-    int i;
-
-    real_addr = wrap_address(env, real_addr) & TARGET_PAGE_MASK;
-
-    for (i = 0; i < TARGET_PAGE_SIZE; i += 8) {
-        cpu_stq_mmuidx_ra(env, real_addr + i, 0, MMU_REAL_IDX, ra);
-    }
-
-    return 0;
-}
-
-uint32_t HELPER(tprot)(CPUS390XState *env, uint64_t a1, uint64_t a2)
-{
-    S390CPU *cpu = env_archcpu(env);
-    CPUState *cs = env_cpu(env);
-
-    /*
-     * TODO: we currently don't handle all access protection types
-     * (including access-list and key-controlled) as well as AR mode.
-     */
-    if (!s390_cpu_virt_mem_check_write(cpu, a1, 0, 1)) {
-        /* Fetching permitted; storing permitted */
-        return 0;
-    }
-
-    if (env->int_pgm_code == PGM_PROTECTION) {
-        /* retry if reading is possible */
-        cs->exception_index = -1;
-        if (!s390_cpu_virt_mem_check_read(cpu, a1, 0, 1)) {
-            /* Fetching permitted; storing not permitted */
-            return 1;
-        }
-    }
-
-    switch (env->int_pgm_code) {
-    case PGM_PROTECTION:
-        /* Fetching not permitted; storing not permitted */
-        cs->exception_index = -1;
-        return 2;
-    case PGM_ADDRESSING:
-    case PGM_TRANS_SPEC:
-        /* exceptions forwarded to the guest */
-        s390_cpu_virt_mem_handle_exc(cpu, GETPC());
-        return 0;
-    }
-
-    /* Translation not available */
-    cs->exception_index = -1;
-    return 3;
-}
-
-/* insert storage key extended */
-uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
-{
-    MachineState *ms = MACHINE(qdev_get_machine());
-    static S390SKeysState *ss;
-    static S390SKeysClass *skeyclass;
-    uint64_t addr = wrap_address(env, r2);
-    uint8_t key;
-
-    if (addr > ms->ram_size) {
-        return 0;
-    }
-
-    if (unlikely(!ss)) {
-        ss = s390_get_skeys_device();
-        skeyclass = S390_SKEYS_GET_CLASS(ss);
-    }
-
-    if (skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key)) {
-        return 0;
-    }
-    return key;
-}
-
-/* set storage key extended */
-void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2)
-{
-    MachineState *ms = MACHINE(qdev_get_machine());
-    static S390SKeysState *ss;
-    static S390SKeysClass *skeyclass;
-    uint64_t addr = wrap_address(env, r2);
-    uint8_t key;
-
-    if (addr > ms->ram_size) {
-        return;
-    }
-
-    if (unlikely(!ss)) {
-        ss = s390_get_skeys_device();
-        skeyclass = S390_SKEYS_GET_CLASS(ss);
-    }
-
-    key = (uint8_t) r1;
-    skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
-   /*
-    * As we can only flush by virtual address and not all the entries
-    * that point to a physical address we have to flush the whole TLB.
-    */
-    tlb_flush_all_cpus_synced(env_cpu(env));
-}
-
-/* reset reference bit extended */
-uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2)
-{
-    MachineState *ms = MACHINE(qdev_get_machine());
-    static S390SKeysState *ss;
-    static S390SKeysClass *skeyclass;
-    uint8_t re, key;
-
-    if (r2 > ms->ram_size) {
-        return 0;
-    }
-
-    if (unlikely(!ss)) {
-        ss = s390_get_skeys_device();
-        skeyclass = S390_SKEYS_GET_CLASS(ss);
-    }
-
-    if (skeyclass->get_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
-        return 0;
-    }
-
-    re = key & (SK_R | SK_C);
-    key &= ~SK_R;
-
-    if (skeyclass->set_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
-        return 0;
-    }
-   /*
-    * As we can only flush by virtual address and not all the entries
-    * that point to a physical address we have to flush the whole TLB.
-    */
-    tlb_flush_all_cpus_synced(env_cpu(env));
-
-    /*
-     * cc
-     *
-     * 0  Reference bit zero; change bit zero
-     * 1  Reference bit zero; change bit one
-     * 2  Reference bit one; change bit zero
-     * 3  Reference bit one; change bit one
-     */
-
-    return re >> 1;
-}
-
-uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
-{
-    const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC;
-    S390Access srca, desta;
-    uintptr_t ra = GETPC();
-    int cc = 0;
-
-    HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
-               __func__, l, a1, a2);
-
-    if (!(env->psw.mask & PSW_MASK_DAT) || !(env->cregs[0] & CR0_SECONDARY) ||
-        psw_as == AS_HOME || psw_as == AS_ACCREG) {
-        s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
-    }
-
-    l = wrap_length32(env, l);
-    if (l > 256) {
-        /* max 256 */
-        l = 256;
-        cc = 3;
-    } else if (!l) {
-        return cc;
-    }
-
-    /* TODO: Access key handling */
-    srca = access_prepare(env, a2, l, MMU_DATA_LOAD, MMU_PRIMARY_IDX, ra);
-    desta = access_prepare(env, a1, l, MMU_DATA_STORE, MMU_SECONDARY_IDX, ra);
-    access_memmove(env, &desta, &srca, ra);
-    return cc;
-}
-
-uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
-{
-    const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC;
-    S390Access srca, desta;
-    uintptr_t ra = GETPC();
-    int cc = 0;
-
-    HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
-               __func__, l, a1, a2);
-
-    if (!(env->psw.mask & PSW_MASK_DAT) || !(env->cregs[0] & CR0_SECONDARY) ||
-        psw_as == AS_HOME || psw_as == AS_ACCREG) {
-        s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
-    }
-
-    l = wrap_length32(env, l);
-    if (l > 256) {
-        /* max 256 */
-        l = 256;
-        cc = 3;
-    } else if (!l) {
-        return cc;
-    }
-
-    /* TODO: Access key handling */
-    srca = access_prepare(env, a2, l, MMU_DATA_LOAD, MMU_SECONDARY_IDX, ra);
-    desta = access_prepare(env, a1, l, MMU_DATA_STORE, MMU_PRIMARY_IDX, ra);
-    access_memmove(env, &desta, &srca, ra);
-    return cc;
-}
-
-void HELPER(idte)(CPUS390XState *env, uint64_t r1, uint64_t r2, uint32_t m4)
-{
-    CPUState *cs = env_cpu(env);
-    const uintptr_t ra = GETPC();
-    uint64_t table, entry, raddr;
-    uint16_t entries, i, index = 0;
-
-    if (r2 & 0xff000) {
-        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
-    }
-
-    if (!(r2 & 0x800)) {
-        /* invalidation-and-clearing operation */
-        table = r1 & ASCE_ORIGIN;
-        entries = (r2 & 0x7ff) + 1;
-
-        switch (r1 & ASCE_TYPE_MASK) {
-        case ASCE_TYPE_REGION1:
-            index = (r2 >> 53) & 0x7ff;
-            break;
-        case ASCE_TYPE_REGION2:
-            index = (r2 >> 42) & 0x7ff;
-            break;
-        case ASCE_TYPE_REGION3:
-            index = (r2 >> 31) & 0x7ff;
-            break;
-        case ASCE_TYPE_SEGMENT:
-            index = (r2 >> 20) & 0x7ff;
-            break;
-        }
-        for (i = 0; i < entries; i++) {
-            /* addresses are not wrapped in 24/31bit mode but table index is */
-            raddr = table + ((index + i) & 0x7ff) * sizeof(entry);
-            entry = cpu_ldq_mmuidx_ra(env, raddr, MMU_REAL_IDX, ra);
-            if (!(entry & REGION_ENTRY_I)) {
-                /* we are allowed to not store if already invalid */
-                entry |= REGION_ENTRY_I;
-                cpu_stq_mmuidx_ra(env, raddr, entry, MMU_REAL_IDX, ra);
-            }
-        }
-    }
-
-    /* We simply flush the complete tlb, therefore we can ignore r3. */
-    if (m4 & 1) {
-        tlb_flush(cs);
-    } else {
-        tlb_flush_all_cpus_synced(cs);
-    }
-}
-
-/* invalidate pte */
-void HELPER(ipte)(CPUS390XState *env, uint64_t pto, uint64_t vaddr,
-                  uint32_t m4)
-{
-    CPUState *cs = env_cpu(env);
-    const uintptr_t ra = GETPC();
-    uint64_t page = vaddr & TARGET_PAGE_MASK;
-    uint64_t pte_addr, pte;
-
-    /* Compute the page table entry address */
-    pte_addr = (pto & SEGMENT_ENTRY_ORIGIN);
-    pte_addr += VADDR_PAGE_TX(vaddr) * 8;
-
-    /* Mark the page table entry as invalid */
-    pte = cpu_ldq_mmuidx_ra(env, pte_addr, MMU_REAL_IDX, ra);
-    pte |= PAGE_ENTRY_I;
-    cpu_stq_mmuidx_ra(env, pte_addr, pte, MMU_REAL_IDX, ra);
-
-    /* XXX we exploit the fact that Linux passes the exact virtual
-       address here - it's not obliged to! */
-    if (m4 & 1) {
-        if (vaddr & ~VADDR_PAGE_TX_MASK) {
-            tlb_flush_page(cs, page);
-            /* XXX 31-bit hack */
-            tlb_flush_page(cs, page ^ 0x80000000);
-        } else {
-            /* looks like we don't have a valid virtual address */
-            tlb_flush(cs);
-        }
-    } else {
-        if (vaddr & ~VADDR_PAGE_TX_MASK) {
-            tlb_flush_page_all_cpus_synced(cs, page);
-            /* XXX 31-bit hack */
-            tlb_flush_page_all_cpus_synced(cs, page ^ 0x80000000);
-        } else {
-            /* looks like we don't have a valid virtual address */
-            tlb_flush_all_cpus_synced(cs);
-        }
-    }
-}
-
-/* flush local tlb */
-void HELPER(ptlb)(CPUS390XState *env)
-{
-    tlb_flush(env_cpu(env));
-}
-
-/* flush global tlb */
-void HELPER(purge)(CPUS390XState *env)
-{
-    tlb_flush_all_cpus_synced(env_cpu(env));
-}
-
-/* load real address */
-uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
-{
-    uint64_t asc = env->psw.mask & PSW_MASK_ASC;
-    uint64_t ret, tec;
-    int flags, exc, cc;
-
-    /* XXX incomplete - has more corner cases */
-    if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
-        tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, GETPC());
-    }
-
-    exc = mmu_translate(env, addr, 0, asc, &ret, &flags, &tec);
-    if (exc) {
-        cc = 3;
-        ret = exc | 0x80000000;
-    } else {
-        cc = 0;
-        ret |= addr & ~TARGET_PAGE_MASK;
-    }
-
-    env->cc_op = cc;
-    return ret;
-}
-#endif
-
-/* load pair from quadword */
-uint64_t HELPER(lpq)(CPUS390XState *env, uint64_t addr)
-{
-    uintptr_t ra = GETPC();
-    uint64_t hi, lo;
-
-    check_alignment(env, addr, 16, ra);
-    hi = cpu_ldq_data_ra(env, addr + 0, ra);
-    lo = cpu_ldq_data_ra(env, addr + 8, ra);
-
-    env->retxl = lo;
-    return hi;
-}
-
-uint64_t HELPER(lpq_parallel)(CPUS390XState *env, uint64_t addr)
-{
-    uintptr_t ra = GETPC();
-    uint64_t hi, lo;
-    int mem_idx;
-    TCGMemOpIdx oi;
-    Int128 v;
-
-    assert(HAVE_ATOMIC128);
-
-    mem_idx = cpu_mmu_index(env, false);
-    oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
-    v = helper_atomic_ldo_be_mmu(env, addr, oi, ra);
-    hi = int128_gethi(v);
-    lo = int128_getlo(v);
-
-    env->retxl = lo;
-    return hi;
-}
-
-/* store pair to quadword */
-void HELPER(stpq)(CPUS390XState *env, uint64_t addr,
-                  uint64_t low, uint64_t high)
-{
-    uintptr_t ra = GETPC();
-
-    check_alignment(env, addr, 16, ra);
-    cpu_stq_data_ra(env, addr + 0, high, ra);
-    cpu_stq_data_ra(env, addr + 8, low, ra);
-}
-
-void HELPER(stpq_parallel)(CPUS390XState *env, uint64_t addr,
-                           uint64_t low, uint64_t high)
-{
-    uintptr_t ra = GETPC();
-    int mem_idx;
-    TCGMemOpIdx oi;
-    Int128 v;
-
-    assert(HAVE_ATOMIC128);
-
-    mem_idx = cpu_mmu_index(env, false);
-    oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
-    v = int128_make128(low, high);
-    helper_atomic_sto_be_mmu(env, addr, v, oi, ra);
-}
-
-/* Execute instruction.  This instruction executes an insn modified with
-   the contents of r1.  It does not change the executed instruction in memory;
-   it does not change the program counter.
-
-   Perform this by recording the modified instruction in env->ex_value.
-   This will be noticed by cpu_get_tb_cpu_state and thus tb translation.
-*/
-void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr)
-{
-    uint64_t insn = cpu_lduw_code(env, addr);
-    uint8_t opc = insn >> 8;
-
-    /* Or in the contents of R1[56:63].  */
-    insn |= r1 & 0xff;
-
-    /* Load the rest of the instruction.  */
-    insn <<= 48;
-    switch (get_ilen(opc)) {
-    case 2:
-        break;
-    case 4:
-        insn |= (uint64_t)cpu_lduw_code(env, addr + 2) << 32;
-        break;
-    case 6:
-        insn |= (uint64_t)(uint32_t)cpu_ldl_code(env, addr + 2) << 16;
-        break;
-    default:
-        g_assert_not_reached();
-    }
-
-    /* The very most common cases can be sped up by avoiding a new TB.  */
-    if ((opc & 0xf0) == 0xd0) {
-        typedef uint32_t (*dx_helper)(CPUS390XState *, uint32_t, uint64_t,
-                                      uint64_t, uintptr_t);
-        static const dx_helper dx[16] = {
-            [0x0] = do_helper_trt_bkwd,
-            [0x2] = do_helper_mvc,
-            [0x4] = do_helper_nc,
-            [0x5] = do_helper_clc,
-            [0x6] = do_helper_oc,
-            [0x7] = do_helper_xc,
-            [0xc] = do_helper_tr,
-            [0xd] = do_helper_trt_fwd,
-        };
-        dx_helper helper = dx[opc & 0xf];
-
-        if (helper) {
-            uint32_t l = extract64(insn, 48, 8);
-            uint32_t b1 = extract64(insn, 44, 4);
-            uint32_t d1 = extract64(insn, 32, 12);
-            uint32_t b2 = extract64(insn, 28, 4);
-            uint32_t d2 = extract64(insn, 16, 12);
-            uint64_t a1 = wrap_address(env, (b1 ? env->regs[b1] : 0) + d1);
-            uint64_t a2 = wrap_address(env, (b2 ? env->regs[b2] : 0) + d2);
-
-            env->cc_op = helper(env, l, a1, a2, 0);
-            env->psw.addr += ilen;
-            return;
-        }
-    } else if (opc == 0x0a) {
-        env->int_svc_code = extract64(insn, 48, 8);
-        env->int_svc_ilen = ilen;
-        helper_exception(env, EXCP_SVC);
-        g_assert_not_reached();
-    }
-
-    /* Record the insn we want to execute as well as the ilen to use
-       during the execution of the target insn.  This will also ensure
-       that ex_value is non-zero, which flags that we are in a state
-       that requires such execution.  */
-    env->ex_value = insn | ilen;
-}
-
-uint32_t HELPER(mvcos)(CPUS390XState *env, uint64_t dest, uint64_t src,
-                       uint64_t len)
-{
-    const uint8_t psw_key = (env->psw.mask & PSW_MASK_KEY) >> PSW_SHIFT_KEY;
-    const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC;
-    const uint64_t r0 = env->regs[0];
-    const uintptr_t ra = GETPC();
-    uint8_t dest_key, dest_as, dest_k, dest_a;
-    uint8_t src_key, src_as, src_k, src_a;
-    uint64_t val;
-    int cc = 0;
-
-    HELPER_LOG("%s dest %" PRIx64 ", src %" PRIx64 ", len %" PRIx64 "\n",
-               __func__, dest, src, len);
-
-    if (!(env->psw.mask & PSW_MASK_DAT)) {
-        tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
-    }
-
-    /* OAC (operand access control) for the first operand -> dest */
-    val = (r0 & 0xffff0000ULL) >> 16;
-    dest_key = (val >> 12) & 0xf;
-    dest_as = (val >> 6) & 0x3;
-    dest_k = (val >> 1) & 0x1;
-    dest_a = val & 0x1;
-
-    /* OAC (operand access control) for the second operand -> src */
-    val = (r0 & 0x0000ffffULL);
-    src_key = (val >> 12) & 0xf;
-    src_as = (val >> 6) & 0x3;
-    src_k = (val >> 1) & 0x1;
-    src_a = val & 0x1;
-
-    if (!dest_k) {
-        dest_key = psw_key;
-    }
-    if (!src_k) {
-        src_key = psw_key;
-    }
-    if (!dest_a) {
-        dest_as = psw_as;
-    }
-    if (!src_a) {
-        src_as = psw_as;
-    }
-
-    if (dest_a && dest_as == AS_HOME && (env->psw.mask & PSW_MASK_PSTATE)) {
-        tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
-    }
-    if (!(env->cregs[0] & CR0_SECONDARY) &&
-        (dest_as == AS_SECONDARY || src_as == AS_SECONDARY)) {
-        tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
-    }
-    if (!psw_key_valid(env, dest_key) || !psw_key_valid(env, src_key)) {
-        tcg_s390_program_interrupt(env, PGM_PRIVILEGED, ra);
-    }
-
-    len = wrap_length32(env, len);
-    if (len > 4096) {
-        cc = 3;
-        len = 4096;
-    }
-
-    /* FIXME: AR-mode and proper problem state mode (using PSW keys) missing */
-    if (src_as == AS_ACCREG || dest_as == AS_ACCREG ||
-        (env->psw.mask & PSW_MASK_PSTATE)) {
-        qemu_log_mask(LOG_UNIMP, "%s: AR-mode and PSTATE support missing\n",
-                      __func__);
-        tcg_s390_program_interrupt(env, PGM_ADDRESSING, ra);
-    }
-
-    /* FIXME: Access using correct keys and AR-mode */
-    if (len) {
-        S390Access srca = access_prepare(env, src, len, MMU_DATA_LOAD,
-                                         mmu_idx_from_as(src_as), ra);
-        S390Access desta = access_prepare(env, dest, len, MMU_DATA_STORE,
-                                          mmu_idx_from_as(dest_as), ra);
-
-        access_memmove(env, &desta, &srca, ra);
-    }
-
-    return cc;
-}
-
-/* Decode a Unicode character.  A return value < 0 indicates success, storing
-   the UTF-32 result into OCHAR and the input length into OLEN.  A return
-   value >= 0 indicates failure, and the CC value to be returned.  */
-typedef int (*decode_unicode_fn)(CPUS390XState *env, uint64_t addr,
-                                 uint64_t ilen, bool enh_check, uintptr_t ra,
-                                 uint32_t *ochar, uint32_t *olen);
-
-/* Encode a Unicode character.  A return value < 0 indicates success, storing
-   the bytes into ADDR and the output length into OLEN.  A return value >= 0
-   indicates failure, and the CC value to be returned.  */
-typedef int (*encode_unicode_fn)(CPUS390XState *env, uint64_t addr,
-                                 uint64_t ilen, uintptr_t ra, uint32_t c,
-                                 uint32_t *olen);
-
-static int decode_utf8(CPUS390XState *env, uint64_t addr, uint64_t ilen,
-                       bool enh_check, uintptr_t ra,
-                       uint32_t *ochar, uint32_t *olen)
-{
-    uint8_t s0, s1, s2, s3;
-    uint32_t c, l;
-
-    if (ilen < 1) {
-        return 0;
-    }
-    s0 = cpu_ldub_data_ra(env, addr, ra);
-    if (s0 <= 0x7f) {
-        /* one byte character */
-        l = 1;
-        c = s0;
-    } else if (s0 <= (enh_check ? 0xc1 : 0xbf)) {
-        /* invalid character */
-        return 2;
-    } else if (s0 <= 0xdf) {
-        /* two byte character */
-        l = 2;
-        if (ilen < 2) {
-            return 0;
-        }
-        s1 = cpu_ldub_data_ra(env, addr + 1, ra);
-        c = s0 & 0x1f;
-        c = (c << 6) | (s1 & 0x3f);
-        if (enh_check && (s1 & 0xc0) != 0x80) {
-            return 2;
-        }
-    } else if (s0 <= 0xef) {
-        /* three byte character */
-        l = 3;
-        if (ilen < 3) {
-            return 0;
-        }
-        s1 = cpu_ldub_data_ra(env, addr + 1, ra);
-        s2 = cpu_ldub_data_ra(env, addr + 2, ra);
-        c = s0 & 0x0f;
-        c = (c << 6) | (s1 & 0x3f);
-        c = (c << 6) | (s2 & 0x3f);
-        /* Fold the byte-by-byte range descriptions in the PoO into
-           tests against the complete value.  It disallows encodings
-           that could be smaller, and the UTF-16 surrogates.  */
-        if (enh_check
-            && ((s1 & 0xc0) != 0x80
-                || (s2 & 0xc0) != 0x80
-                || c < 0x1000
-                || (c >= 0xd800 && c <= 0xdfff))) {
-            return 2;
-        }
-    } else if (s0 <= (enh_check ? 0xf4 : 0xf7)) {
-        /* four byte character */
-        l = 4;
-        if (ilen < 4) {
-            return 0;
-        }
-        s1 = cpu_ldub_data_ra(env, addr + 1, ra);
-        s2 = cpu_ldub_data_ra(env, addr + 2, ra);
-        s3 = cpu_ldub_data_ra(env, addr + 3, ra);
-        c = s0 & 0x07;
-        c = (c << 6) | (s1 & 0x3f);
-        c = (c << 6) | (s2 & 0x3f);
-        c = (c << 6) | (s3 & 0x3f);
-        /* See above.  */
-        if (enh_check
-            && ((s1 & 0xc0) != 0x80
-                || (s2 & 0xc0) != 0x80
-                || (s3 & 0xc0) != 0x80
-                || c < 0x010000
-                || c > 0x10ffff)) {
-            return 2;
-        }
-    } else {
-        /* invalid character */
-        return 2;
-    }
-
-    *ochar = c;
-    *olen = l;
-    return -1;
-}
-
-static int decode_utf16(CPUS390XState *env, uint64_t addr, uint64_t ilen,
-                        bool enh_check, uintptr_t ra,
-                        uint32_t *ochar, uint32_t *olen)
-{
-    uint16_t s0, s1;
-    uint32_t c, l;
-
-    if (ilen < 2) {
-        return 0;
-    }
-    s0 = cpu_lduw_data_ra(env, addr, ra);
-    if ((s0 & 0xfc00) != 0xd800) {
-        /* one word character */
-        l = 2;
-        c = s0;
-    } else {
-        /* two word character */
-        l = 4;
-        if (ilen < 4) {
-            return 0;
-        }
-        s1 = cpu_lduw_data_ra(env, addr + 2, ra);
-        c = extract32(s0, 6, 4) + 1;
-        c = (c << 6) | (s0 & 0x3f);
-        c = (c << 10) | (s1 & 0x3ff);
-        if (enh_check && (s1 & 0xfc00) != 0xdc00) {
-            /* invalid surrogate character */
-            return 2;
-        }
-    }
-
-    *ochar = c;
-    *olen = l;
-    return -1;
-}
-
-static int decode_utf32(CPUS390XState *env, uint64_t addr, uint64_t ilen,
-                        bool enh_check, uintptr_t ra,
-                        uint32_t *ochar, uint32_t *olen)
-{
-    uint32_t c;
-
-    if (ilen < 4) {
-        return 0;
-    }
-    c = cpu_ldl_data_ra(env, addr, ra);
-    if ((c >= 0xd800 && c <= 0xdbff) || c > 0x10ffff) {
-        /* invalid unicode character */
-        return 2;
-    }
-
-    *ochar = c;
-    *olen = 4;
-    return -1;
-}
-
-static int encode_utf8(CPUS390XState *env, uint64_t addr, uint64_t ilen,
-                       uintptr_t ra, uint32_t c, uint32_t *olen)
-{
-    uint8_t d[4];
-    uint32_t l, i;
-
-    if (c <= 0x7f) {
-        /* one byte character */
-        l = 1;
-        d[0] = c;
-    } else if (c <= 0x7ff) {
-        /* two byte character */
-        l = 2;
-        d[1] = 0x80 | extract32(c, 0, 6);
-        d[0] = 0xc0 | extract32(c, 6, 5);
-    } else if (c <= 0xffff) {
-        /* three byte character */
-        l = 3;
-        d[2] = 0x80 | extract32(c, 0, 6);
-        d[1] = 0x80 | extract32(c, 6, 6);
-        d[0] = 0xe0 | extract32(c, 12, 4);
-    } else {
-        /* four byte character */
-        l = 4;
-        d[3] = 0x80 | extract32(c, 0, 6);
-        d[2] = 0x80 | extract32(c, 6, 6);
-        d[1] = 0x80 | extract32(c, 12, 6);
-        d[0] = 0xf0 | extract32(c, 18, 3);
-    }
-
-    if (ilen < l) {
-        return 1;
-    }
-    for (i = 0; i < l; ++i) {
-        cpu_stb_data_ra(env, addr + i, d[i], ra);
-    }
-
-    *olen = l;
-    return -1;
-}
-
-static int encode_utf16(CPUS390XState *env, uint64_t addr, uint64_t ilen,
-                        uintptr_t ra, uint32_t c, uint32_t *olen)
-{
-    uint16_t d0, d1;
-
-    if (c <= 0xffff) {
-        /* one word character */
-        if (ilen < 2) {
-            return 1;
-        }
-        cpu_stw_data_ra(env, addr, c, ra);
-        *olen = 2;
-    } else {
-        /* two word character */
-        if (ilen < 4) {
-            return 1;
-        }
-        d1 = 0xdc00 | extract32(c, 0, 10);
-        d0 = 0xd800 | extract32(c, 10, 6);
-        d0 = deposit32(d0, 6, 4, extract32(c, 16, 5) - 1);
-        cpu_stw_data_ra(env, addr + 0, d0, ra);
-        cpu_stw_data_ra(env, addr + 2, d1, ra);
-        *olen = 4;
-    }
-
-    return -1;
-}
-
-static int encode_utf32(CPUS390XState *env, uint64_t addr, uint64_t ilen,
-                        uintptr_t ra, uint32_t c, uint32_t *olen)
-{
-    if (ilen < 4) {
-        return 1;
-    }
-    cpu_stl_data_ra(env, addr, c, ra);
-    *olen = 4;
-    return -1;
-}
-
-static inline uint32_t convert_unicode(CPUS390XState *env, uint32_t r1,
-                                       uint32_t r2, uint32_t m3, uintptr_t ra,
-                                       decode_unicode_fn decode,
-                                       encode_unicode_fn encode)
-{
-    uint64_t dst = get_address(env, r1);
-    uint64_t dlen = get_length(env, r1 + 1);
-    uint64_t src = get_address(env, r2);
-    uint64_t slen = get_length(env, r2 + 1);
-    bool enh_check = m3 & 1;
-    int cc, i;
-
-    /* Lest we fail to service interrupts in a timely manner, limit the
-       amount of work we're willing to do.  For now, let's cap at 256.  */
-    for (i = 0; i < 256; ++i) {
-        uint32_t c, ilen, olen;
-
-        cc = decode(env, src, slen, enh_check, ra, &c, &ilen);
-        if (unlikely(cc >= 0)) {
-            break;
-        }
-        cc = encode(env, dst, dlen, ra, c, &olen);
-        if (unlikely(cc >= 0)) {
-            break;
-        }
-
-        src += ilen;
-        slen -= ilen;
-        dst += olen;
-        dlen -= olen;
-        cc = 3;
-    }
-
-    set_address(env, r1, dst);
-    set_length(env, r1 + 1, dlen);
-    set_address(env, r2, src);
-    set_length(env, r2 + 1, slen);
-
-    return cc;
-}
-
-uint32_t HELPER(cu12)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
-{
-    return convert_unicode(env, r1, r2, m3, GETPC(),
-                           decode_utf8, encode_utf16);
-}
-
-uint32_t HELPER(cu14)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
-{
-    return convert_unicode(env, r1, r2, m3, GETPC(),
-                           decode_utf8, encode_utf32);
-}
-
-uint32_t HELPER(cu21)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
-{
-    return convert_unicode(env, r1, r2, m3, GETPC(),
-                           decode_utf16, encode_utf8);
-}
-
-uint32_t HELPER(cu24)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
-{
-    return convert_unicode(env, r1, r2, m3, GETPC(),
-                           decode_utf16, encode_utf32);
-}
-
-uint32_t HELPER(cu41)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
-{
-    return convert_unicode(env, r1, r2, m3, GETPC(),
-                           decode_utf32, encode_utf8);
-}
-
-uint32_t HELPER(cu42)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
-{
-    return convert_unicode(env, r1, r2, m3, GETPC(),
-                           decode_utf32, encode_utf16);
-}
-
-void probe_write_access(CPUS390XState *env, uint64_t addr, uint64_t len,
-                        uintptr_t ra)
-{
-    /* test the actual access, not just any access to the page due to LAP */
-    while (len) {
-        const uint64_t pagelen = -(addr | TARGET_PAGE_MASK);
-        const uint64_t curlen = MIN(pagelen, len);
-
-        probe_write(env, addr, curlen, cpu_mmu_index(env, false), ra);
-        addr = wrap_address(env, addr + curlen);
-        len -= curlen;
-    }
-}
-
-void HELPER(probe_write_access)(CPUS390XState *env, uint64_t addr, uint64_t len)
-{
-    probe_write_access(env, addr, len, GETPC());
-}
index c42eadb7d245439967082c75fd63337a468c7d23..84c1402a6a1ac547c0621a824ee3e3e1cc0d37d4 100644 (file)
@@ -4,27 +4,10 @@ s390x_ss.add(files(
   'cpu_features.c',
   'cpu_models.c',
   'gdbstub.c',
-  'helper.c',
   'interrupt.c',
+  'cpu-dump.c',
 ))
 
-s390x_ss.add(when: 'CONFIG_TCG', if_true: files(
-  'cc_helper.c',
-  'crypto_helper.c',
-  'excp_helper.c',
-  'fpu_helper.c',
-  'int_helper.c',
-  'mem_helper.c',
-  'misc_helper.c',
-  'translate.c',
-  'vec_fpu_helper.c',
-  'vec_helper.c',
-  'vec_int_helper.c',
-  'vec_string_helper.c',
-), if_false: files('tcg-stub.c'))
-
-s390x_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c'), if_false: files('kvm-stub.c'))
-
 gen_features = executable('gen-features', 'gen-features.c', native: true,
                           build_by_default: false)
 
@@ -37,26 +20,25 @@ s390x_ss.add(gen_features_h)
 
 s390x_softmmu_ss = ss.source_set()
 s390x_softmmu_ss.add(files(
+  'helper.c',
   'arch_dump.c',
   'diag.c',
   'ioinst.c',
   'machine.c',
   'mmu_helper.c',
   'sigp.c',
+  'cpu-sysemu.c',
+  'cpu_models_sysemu.c',
+))
+
+s390x_user_ss = ss.source_set()
+s390x_user_ss.add(files(
+  'cpu_models_user.c',
 ))
 
-# Newer kernels on s390 check for an S390_PGSTE program header and
-# enable the pgste page table extensions in that case. This makes
-# the vm.allocate_pgste sysctl unnecessary. We enable this program
-# header if
-#  - we build on s390x
-#  - we build the system emulation for s390x (qemu-system-s390x)
-#  - KVM is enabled
-#  - the linker supports --s390-pgste
-if host_machine.cpu_family() == 's390x' and cc.has_link_argument('-Wl,--s390-pgste')
-  s390x_softmmu_ss.add(when: 'CONFIG_KVM',
-                       if_true: declare_dependency(link_args: ['-Wl,--s390-pgste']))
-endif
+subdir('tcg')
+subdir('kvm')
 
 target_arch += {'s390x': s390x_ss}
 target_softmmu_arch += {'s390x': s390x_softmmu_ss}
+target_user_arch += {'s390x': s390x_user_ss}
diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c
deleted file mode 100644 (file)
index 7ea90d4..0000000
+++ /dev/null
@@ -1,785 +0,0 @@
-/*
- *  S/390 misc helper routines
- *
- *  Copyright (c) 2009 Ulrich Hecht
- *  Copyright (c) 2009 Alexander Graf
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/cutils.h"
-#include "qemu/main-loop.h"
-#include "cpu.h"
-#include "internal.h"
-#include "exec/memory.h"
-#include "qemu/host-utils.h"
-#include "exec/helper-proto.h"
-#include "qemu/timer.h"
-#include "exec/exec-all.h"
-#include "exec/cpu_ldst.h"
-#include "qapi/error.h"
-#include "tcg_s390x.h"
-#include "s390-tod.h"
-
-#if !defined(CONFIG_USER_ONLY)
-#include "sysemu/cpus.h"
-#include "sysemu/sysemu.h"
-#include "hw/s390x/ebcdic.h"
-#include "hw/s390x/s390-virtio-hcall.h"
-#include "hw/s390x/sclp.h"
-#include "hw/s390x/s390_flic.h"
-#include "hw/s390x/ioinst.h"
-#include "hw/s390x/s390-pci-inst.h"
-#include "hw/boards.h"
-#include "hw/s390x/tod.h"
-#endif
-
-/* #define DEBUG_HELPER */
-#ifdef DEBUG_HELPER
-#define HELPER_LOG(x...) qemu_log(x)
-#else
-#define HELPER_LOG(x...)
-#endif
-
-/* Raise an exception statically from a TB.  */
-void HELPER(exception)(CPUS390XState *env, uint32_t excp)
-{
-    CPUState *cs = env_cpu(env);
-
-    HELPER_LOG("%s: exception %d\n", __func__, excp);
-    cs->exception_index = excp;
-    cpu_loop_exit(cs);
-}
-
-/* Store CPU Timer (also used for EXTRACT CPU TIME) */
-uint64_t HELPER(stpt)(CPUS390XState *env)
-{
-#if defined(CONFIG_USER_ONLY)
-    /*
-     * Fake a descending CPU timer. We could get negative values here,
-     * but we don't care as it is up to the OS when to process that
-     * interrupt and reset to > 0.
-     */
-    return UINT64_MAX - (uint64_t)cpu_get_host_ticks();
-#else
-    return time2tod(env->cputm - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
-#endif
-}
-
-/* Store Clock */
-uint64_t HELPER(stck)(CPUS390XState *env)
-{
-#ifdef CONFIG_USER_ONLY
-    struct timespec ts;
-    uint64_t ns;
-
-    clock_gettime(CLOCK_REALTIME, &ts);
-    ns = ts.tv_sec * NANOSECONDS_PER_SECOND + ts.tv_nsec;
-
-    return TOD_UNIX_EPOCH + time2tod(ns);
-#else
-    S390TODState *td = s390_get_todstate();
-    S390TODClass *tdc = S390_TOD_GET_CLASS(td);
-    S390TOD tod;
-
-    tdc->get(td, &tod, &error_abort);
-    return tod.low;
-#endif
-}
-
-#ifndef CONFIG_USER_ONLY
-/* SCLP service call */
-uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2)
-{
-    qemu_mutex_lock_iothread();
-    int r = sclp_service_call(env, r1, r2);
-    qemu_mutex_unlock_iothread();
-    if (r < 0) {
-        tcg_s390_program_interrupt(env, -r, GETPC());
-    }
-    return r;
-}
-
-void HELPER(diag)(CPUS390XState *env, uint32_t r1, uint32_t r3, uint32_t num)
-{
-    uint64_t r;
-
-    switch (num) {
-    case 0x500:
-        /* KVM hypercall */
-        qemu_mutex_lock_iothread();
-        r = s390_virtio_hypercall(env);
-        qemu_mutex_unlock_iothread();
-        break;
-    case 0x44:
-        /* yield */
-        r = 0;
-        break;
-    case 0x308:
-        /* ipl */
-        qemu_mutex_lock_iothread();
-        handle_diag_308(env, r1, r3, GETPC());
-        qemu_mutex_unlock_iothread();
-        r = 0;
-        break;
-    case 0x288:
-        /* time bomb (watchdog) */
-        r = handle_diag_288(env, r1, r3);
-        break;
-    default:
-        r = -1;
-        break;
-    }
-
-    if (r) {
-        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
-    }
-}
-
-/* Set Prefix */
-void HELPER(spx)(CPUS390XState *env, uint64_t a1)
-{
-    CPUState *cs = env_cpu(env);
-    uint32_t prefix = a1 & 0x7fffe000;
-
-    env->psa = prefix;
-    HELPER_LOG("prefix: %#x\n", prefix);
-    tlb_flush_page(cs, 0);
-    tlb_flush_page(cs, TARGET_PAGE_SIZE);
-}
-
-static void update_ckc_timer(CPUS390XState *env)
-{
-    S390TODState *td = s390_get_todstate();
-    uint64_t time;
-
-    /* stop the timer and remove pending CKC IRQs */
-    timer_del(env->tod_timer);
-    g_assert(qemu_mutex_iothread_locked());
-    env->pending_int &= ~INTERRUPT_EXT_CLOCK_COMPARATOR;
-
-    /* the tod has to exceed the ckc, this can never happen if ckc is all 1's */
-    if (env->ckc == -1ULL) {
-        return;
-    }
-
-    /* difference between origins */
-    time = env->ckc - td->base.low;
-
-    /* nanoseconds */
-    time = tod2time(time);
-
-    timer_mod(env->tod_timer, time);
-}
-
-/* Set Clock Comparator */
-void HELPER(sckc)(CPUS390XState *env, uint64_t ckc)
-{
-    env->ckc = ckc;
-
-    qemu_mutex_lock_iothread();
-    update_ckc_timer(env);
-    qemu_mutex_unlock_iothread();
-}
-
-void tcg_s390_tod_updated(CPUState *cs, run_on_cpu_data opaque)
-{
-    S390CPU *cpu = S390_CPU(cs);
-
-    update_ckc_timer(&cpu->env);
-}
-
-/* Set Clock */
-uint32_t HELPER(sck)(CPUS390XState *env, uint64_t tod_low)
-{
-    S390TODState *td = s390_get_todstate();
-    S390TODClass *tdc = S390_TOD_GET_CLASS(td);
-    S390TOD tod = {
-        .high = 0,
-        .low = tod_low,
-    };
-
-    qemu_mutex_lock_iothread();
-    tdc->set(td, &tod, &error_abort);
-    qemu_mutex_unlock_iothread();
-    return 0;
-}
-
-/* Set Tod Programmable Field */
-void HELPER(sckpf)(CPUS390XState *env, uint64_t r0)
-{
-    uint32_t val = r0;
-
-    if (val & 0xffff0000) {
-        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
-    }
-    env->todpr = val;
-}
-
-/* Store Clock Comparator */
-uint64_t HELPER(stckc)(CPUS390XState *env)
-{
-    return env->ckc;
-}
-
-/* Set CPU Timer */
-void HELPER(spt)(CPUS390XState *env, uint64_t time)
-{
-    if (time == -1ULL) {
-        return;
-    }
-
-    /* nanoseconds */
-    time = tod2time(time);
-
-    env->cputm = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time;
-
-    timer_mod(env->cpu_timer, env->cputm);
-}
-
-/* Store System Information */
-uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, uint64_t r0, uint64_t r1)
-{
-    const uintptr_t ra = GETPC();
-    const uint32_t sel1 = r0 & STSI_R0_SEL1_MASK;
-    const uint32_t sel2 = r1 & STSI_R1_SEL2_MASK;
-    const MachineState *ms = MACHINE(qdev_get_machine());
-    uint16_t total_cpus = 0, conf_cpus = 0, reserved_cpus = 0;
-    S390CPU *cpu = env_archcpu(env);
-    SysIB sysib = { };
-    int i, cc = 0;
-
-    if ((r0 & STSI_R0_FC_MASK) > STSI_R0_FC_LEVEL_3) {
-        /* invalid function code: no other checks are performed */
-        return 3;
-    }
-
-    if ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK)) {
-        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
-    }
-
-    if ((r0 & STSI_R0_FC_MASK) == STSI_R0_FC_CURRENT) {
-        /* query the current level: no further checks are performed */
-        env->regs[0] = STSI_R0_FC_LEVEL_3;
-        return 0;
-    }
-
-    if (a0 & ~TARGET_PAGE_MASK) {
-        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
-    }
-
-    /* count the cpus and split them into configured and reserved ones */
-    for (i = 0; i < ms->possible_cpus->len; i++) {
-        total_cpus++;
-        if (ms->possible_cpus->cpus[i].cpu) {
-            conf_cpus++;
-        } else {
-            reserved_cpus++;
-        }
-    }
-
-    /*
-     * In theory, we could report Level 1 / Level 2 as current. However,
-     * the Linux kernel will detect this as running under LPAR and assume
-     * that we have a sclp linemode console (which is always present on
-     * LPAR, but not the default for QEMU), therefore not displaying boot
-     * messages and making booting a Linux kernel under TCG harder.
-     *
-     * For now we fake the same SMP configuration on all levels.
-     *
-     * TODO: We could later make the level configurable via the machine
-     *       and change defaults (linemode console) based on machine type
-     *       and accelerator.
-     */
-    switch (r0 & STSI_R0_FC_MASK) {
-    case STSI_R0_FC_LEVEL_1:
-        if ((sel1 == 1) && (sel2 == 1)) {
-            /* Basic Machine Configuration */
-            char type[5] = {};
-
-            ebcdic_put(sysib.sysib_111.manuf, "QEMU            ", 16);
-            /* same as machine type number in STORE CPU ID, but in EBCDIC */
-            snprintf(type, ARRAY_SIZE(type), "%X", cpu->model->def->type);
-            ebcdic_put(sysib.sysib_111.type, type, 4);
-            /* model number (not stored in STORE CPU ID for z/Architecure) */
-            ebcdic_put(sysib.sysib_111.model, "QEMU            ", 16);
-            ebcdic_put(sysib.sysib_111.sequence, "QEMU            ", 16);
-            ebcdic_put(sysib.sysib_111.plant, "QEMU", 4);
-        } else if ((sel1 == 2) && (sel2 == 1)) {
-            /* Basic Machine CPU */
-            ebcdic_put(sysib.sysib_121.sequence, "QEMUQEMUQEMUQEMU", 16);
-            ebcdic_put(sysib.sysib_121.plant, "QEMU", 4);
-            sysib.sysib_121.cpu_addr = cpu_to_be16(env->core_id);
-        } else if ((sel1 == 2) && (sel2 == 2)) {
-            /* Basic Machine CPUs */
-            sysib.sysib_122.capability = cpu_to_be32(0x443afc29);
-            sysib.sysib_122.total_cpus = cpu_to_be16(total_cpus);
-            sysib.sysib_122.conf_cpus = cpu_to_be16(conf_cpus);
-            sysib.sysib_122.reserved_cpus = cpu_to_be16(reserved_cpus);
-        } else {
-            cc = 3;
-        }
-        break;
-    case STSI_R0_FC_LEVEL_2:
-        if ((sel1 == 2) && (sel2 == 1)) {
-            /* LPAR CPU */
-            ebcdic_put(sysib.sysib_221.sequence, "QEMUQEMUQEMUQEMU", 16);
-            ebcdic_put(sysib.sysib_221.plant, "QEMU", 4);
-            sysib.sysib_221.cpu_addr = cpu_to_be16(env->core_id);
-        } else if ((sel1 == 2) && (sel2 == 2)) {
-            /* LPAR CPUs */
-            sysib.sysib_222.lcpuc = 0x80; /* dedicated */
-            sysib.sysib_222.total_cpus = cpu_to_be16(total_cpus);
-            sysib.sysib_222.conf_cpus = cpu_to_be16(conf_cpus);
-            sysib.sysib_222.reserved_cpus = cpu_to_be16(reserved_cpus);
-            ebcdic_put(sysib.sysib_222.name, "QEMU    ", 8);
-            sysib.sysib_222.caf = cpu_to_be32(1000);
-            sysib.sysib_222.dedicated_cpus = cpu_to_be16(conf_cpus);
-        } else {
-            cc = 3;
-        }
-        break;
-    case STSI_R0_FC_LEVEL_3:
-        if ((sel1 == 2) && (sel2 == 2)) {
-            /* VM CPUs */
-            sysib.sysib_322.count = 1;
-            sysib.sysib_322.vm[0].total_cpus = cpu_to_be16(total_cpus);
-            sysib.sysib_322.vm[0].conf_cpus = cpu_to_be16(conf_cpus);
-            sysib.sysib_322.vm[0].reserved_cpus = cpu_to_be16(reserved_cpus);
-            sysib.sysib_322.vm[0].caf = cpu_to_be32(1000);
-            /* Linux kernel uses this to distinguish us from z/VM */
-            ebcdic_put(sysib.sysib_322.vm[0].cpi, "KVM/Linux       ", 16);
-            sysib.sysib_322.vm[0].ext_name_encoding = 2; /* UTF-8 */
-
-            /* If our VM has a name, use the real name */
-            if (qemu_name) {
-                memset(sysib.sysib_322.vm[0].name, 0x40,
-                       sizeof(sysib.sysib_322.vm[0].name));
-                ebcdic_put(sysib.sysib_322.vm[0].name, qemu_name,
-                           MIN(sizeof(sysib.sysib_322.vm[0].name),
-                               strlen(qemu_name)));
-                strpadcpy((char *)sysib.sysib_322.ext_names[0],
-                          sizeof(sysib.sysib_322.ext_names[0]),
-                          qemu_name, '\0');
-
-            } else {
-                ebcdic_put(sysib.sysib_322.vm[0].name, "TCGguest", 8);
-                strcpy((char *)sysib.sysib_322.ext_names[0], "TCGguest");
-            }
-
-            /* add the uuid */
-            memcpy(sysib.sysib_322.vm[0].uuid, &qemu_uuid,
-                   sizeof(sysib.sysib_322.vm[0].uuid));
-        } else {
-            cc = 3;
-        }
-        break;
-    }
-
-    if (cc == 0) {
-        if (s390_cpu_virt_mem_write(cpu, a0, 0, &sysib, sizeof(sysib))) {
-            s390_cpu_virt_mem_handle_exc(cpu, ra);
-        }
-    }
-
-    return cc;
-}
-
-uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
-                      uint32_t r3)
-{
-    int cc;
-
-    /* TODO: needed to inject interrupts  - push further down */
-    qemu_mutex_lock_iothread();
-    cc = handle_sigp(env, order_code & SIGP_ORDER_MASK, r1, r3);
-    qemu_mutex_unlock_iothread();
-
-    return cc;
-}
-#endif
-
-#ifndef CONFIG_USER_ONLY
-void HELPER(xsch)(CPUS390XState *env, uint64_t r1)
-{
-    S390CPU *cpu = env_archcpu(env);
-    qemu_mutex_lock_iothread();
-    ioinst_handle_xsch(cpu, r1, GETPC());
-    qemu_mutex_unlock_iothread();
-}
-
-void HELPER(csch)(CPUS390XState *env, uint64_t r1)
-{
-    S390CPU *cpu = env_archcpu(env);
-    qemu_mutex_lock_iothread();
-    ioinst_handle_csch(cpu, r1, GETPC());
-    qemu_mutex_unlock_iothread();
-}
-
-void HELPER(hsch)(CPUS390XState *env, uint64_t r1)
-{
-    S390CPU *cpu = env_archcpu(env);
-    qemu_mutex_lock_iothread();
-    ioinst_handle_hsch(cpu, r1, GETPC());
-    qemu_mutex_unlock_iothread();
-}
-
-void HELPER(msch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
-{
-    S390CPU *cpu = env_archcpu(env);
-    qemu_mutex_lock_iothread();
-    ioinst_handle_msch(cpu, r1, inst >> 16, GETPC());
-    qemu_mutex_unlock_iothread();
-}
-
-void HELPER(rchp)(CPUS390XState *env, uint64_t r1)
-{
-    S390CPU *cpu = env_archcpu(env);
-    qemu_mutex_lock_iothread();
-    ioinst_handle_rchp(cpu, r1, GETPC());
-    qemu_mutex_unlock_iothread();
-}
-
-void HELPER(rsch)(CPUS390XState *env, uint64_t r1)
-{
-    S390CPU *cpu = env_archcpu(env);
-    qemu_mutex_lock_iothread();
-    ioinst_handle_rsch(cpu, r1, GETPC());
-    qemu_mutex_unlock_iothread();
-}
-
-void HELPER(sal)(CPUS390XState *env, uint64_t r1)
-{
-    S390CPU *cpu = env_archcpu(env);
-
-    qemu_mutex_lock_iothread();
-    ioinst_handle_sal(cpu, r1, GETPC());
-    qemu_mutex_unlock_iothread();
-}
-
-void HELPER(schm)(CPUS390XState *env, uint64_t r1, uint64_t r2, uint64_t inst)
-{
-    S390CPU *cpu = env_archcpu(env);
-
-    qemu_mutex_lock_iothread();
-    ioinst_handle_schm(cpu, r1, r2, inst >> 16, GETPC());
-    qemu_mutex_unlock_iothread();
-}
-
-void HELPER(ssch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
-{
-    S390CPU *cpu = env_archcpu(env);
-    qemu_mutex_lock_iothread();
-    ioinst_handle_ssch(cpu, r1, inst >> 16, GETPC());
-    qemu_mutex_unlock_iothread();
-}
-
-void HELPER(stcrw)(CPUS390XState *env, uint64_t inst)
-{
-    S390CPU *cpu = env_archcpu(env);
-
-    qemu_mutex_lock_iothread();
-    ioinst_handle_stcrw(cpu, inst >> 16, GETPC());
-    qemu_mutex_unlock_iothread();
-}
-
-void HELPER(stsch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
-{
-    S390CPU *cpu = env_archcpu(env);
-    qemu_mutex_lock_iothread();
-    ioinst_handle_stsch(cpu, r1, inst >> 16, GETPC());
-    qemu_mutex_unlock_iothread();
-}
-
-uint32_t HELPER(tpi)(CPUS390XState *env, uint64_t addr)
-{
-    const uintptr_t ra = GETPC();
-    S390CPU *cpu = env_archcpu(env);
-    QEMUS390FLICState *flic = s390_get_qemu_flic(s390_get_flic());
-    QEMUS390FlicIO *io = NULL;
-    LowCore *lowcore;
-
-    if (addr & 0x3) {
-        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
-    }
-
-    qemu_mutex_lock_iothread();
-    io = qemu_s390_flic_dequeue_io(flic, env->cregs[6]);
-    if (!io) {
-        qemu_mutex_unlock_iothread();
-        return 0;
-    }
-
-    if (addr) {
-        struct {
-            uint16_t id;
-            uint16_t nr;
-            uint32_t parm;
-        } intc = {
-            .id = cpu_to_be16(io->id),
-            .nr = cpu_to_be16(io->nr),
-            .parm = cpu_to_be32(io->parm),
-        };
-
-        if (s390_cpu_virt_mem_write(cpu, addr, 0, &intc, sizeof(intc))) {
-            /* writing failed, reinject and properly clean up */
-            s390_io_interrupt(io->id, io->nr, io->parm, io->word);
-            qemu_mutex_unlock_iothread();
-            g_free(io);
-            s390_cpu_virt_mem_handle_exc(cpu, ra);
-            return 0;
-        }
-    } else {
-        /* no protection applies */
-        lowcore = cpu_map_lowcore(env);
-        lowcore->subchannel_id = cpu_to_be16(io->id);
-        lowcore->subchannel_nr = cpu_to_be16(io->nr);
-        lowcore->io_int_parm = cpu_to_be32(io->parm);
-        lowcore->io_int_word = cpu_to_be32(io->word);
-        cpu_unmap_lowcore(lowcore);
-    }
-
-    g_free(io);
-    qemu_mutex_unlock_iothread();
-    return 1;
-}
-
-void HELPER(tsch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
-{
-    S390CPU *cpu = env_archcpu(env);
-    qemu_mutex_lock_iothread();
-    ioinst_handle_tsch(cpu, r1, inst >> 16, GETPC());
-    qemu_mutex_unlock_iothread();
-}
-
-void HELPER(chsc)(CPUS390XState *env, uint64_t inst)
-{
-    S390CPU *cpu = env_archcpu(env);
-    qemu_mutex_lock_iothread();
-    ioinst_handle_chsc(cpu, inst >> 16, GETPC());
-    qemu_mutex_unlock_iothread();
-}
-#endif
-
-#ifndef CONFIG_USER_ONLY
-void HELPER(per_check_exception)(CPUS390XState *env)
-{
-    if (env->per_perc_atmid) {
-        tcg_s390_program_interrupt(env, PGM_PER, GETPC());
-    }
-}
-
-/* Check if an address is within the PER starting address and the PER
-   ending address.  The address range might loop.  */
-static inline bool get_per_in_range(CPUS390XState *env, uint64_t addr)
-{
-    if (env->cregs[10] <= env->cregs[11]) {
-        return env->cregs[10] <= addr && addr <= env->cregs[11];
-    } else {
-        return env->cregs[10] <= addr || addr <= env->cregs[11];
-    }
-}
-
-void HELPER(per_branch)(CPUS390XState *env, uint64_t from, uint64_t to)
-{
-    if ((env->cregs[9] & PER_CR9_EVENT_BRANCH)) {
-        if (!(env->cregs[9] & PER_CR9_CONTROL_BRANCH_ADDRESS)
-            || get_per_in_range(env, to)) {
-            env->per_address = from;
-            env->per_perc_atmid = PER_CODE_EVENT_BRANCH | get_per_atmid(env);
-        }
-    }
-}
-
-void HELPER(per_ifetch)(CPUS390XState *env, uint64_t addr)
-{
-    if ((env->cregs[9] & PER_CR9_EVENT_IFETCH) && get_per_in_range(env, addr)) {
-        env->per_address = addr;
-        env->per_perc_atmid = PER_CODE_EVENT_IFETCH | get_per_atmid(env);
-
-        /* If the instruction has to be nullified, trigger the
-           exception immediately. */
-        if (env->cregs[9] & PER_CR9_EVENT_NULLIFICATION) {
-            CPUState *cs = env_cpu(env);
-
-            env->per_perc_atmid |= PER_CODE_EVENT_NULLIFICATION;
-            env->int_pgm_code = PGM_PER;
-            env->int_pgm_ilen = get_ilen(cpu_ldub_code(env, addr));
-
-            cs->exception_index = EXCP_PGM;
-            cpu_loop_exit(cs);
-        }
-    }
-}
-
-void HELPER(per_store_real)(CPUS390XState *env)
-{
-    if ((env->cregs[9] & PER_CR9_EVENT_STORE) &&
-        (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
-        /* PSW is saved just before calling the helper.  */
-        env->per_address = env->psw.addr;
-        env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
-    }
-}
-#endif
-
-static uint8_t stfl_bytes[2048];
-static unsigned int used_stfl_bytes;
-
-static void prepare_stfl(void)
-{
-    static bool initialized;
-    int i;
-
-    /* racy, but we don't care, the same values are always written */
-    if (initialized) {
-        return;
-    }
-
-    s390_get_feat_block(S390_FEAT_TYPE_STFL, stfl_bytes);
-    for (i = 0; i < sizeof(stfl_bytes); i++) {
-        if (stfl_bytes[i]) {
-            used_stfl_bytes = i + 1;
-        }
-    }
-    initialized = true;
-}
-
-#ifndef CONFIG_USER_ONLY
-void HELPER(stfl)(CPUS390XState *env)
-{
-    LowCore *lowcore;
-
-    lowcore = cpu_map_lowcore(env);
-    prepare_stfl();
-    memcpy(&lowcore->stfl_fac_list, stfl_bytes, sizeof(lowcore->stfl_fac_list));
-    cpu_unmap_lowcore(lowcore);
-}
-#endif
-
-uint32_t HELPER(stfle)(CPUS390XState *env, uint64_t addr)
-{
-    const uintptr_t ra = GETPC();
-    const int count_bytes = ((env->regs[0] & 0xff) + 1) * 8;
-    int max_bytes;
-    int i;
-
-    if (addr & 0x7) {
-        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
-    }
-
-    prepare_stfl();
-    max_bytes = ROUND_UP(used_stfl_bytes, 8);
-
-    /*
-     * The PoP says that doublewords beyond the highest-numbered facility
-     * bit may or may not be stored.  However, existing hardware appears to
-     * not store the words, and existing software depend on that.
-     */
-    for (i = 0; i < MIN(count_bytes, max_bytes); ++i) {
-        cpu_stb_data_ra(env, addr + i, stfl_bytes[i], ra);
-    }
-
-    env->regs[0] = deposit64(env->regs[0], 0, 8, (max_bytes / 8) - 1);
-    return count_bytes >= max_bytes ? 0 : 3;
-}
-
-#ifndef CONFIG_USER_ONLY
-/*
- * Note: we ignore any return code of the functions called for the pci
- * instructions, as the only time they return !0 is when the stub is
- * called, and in that case we didn't even offer the zpci facility.
- * The only exception is SIC, where program checks need to be handled
- * by the caller.
- */
-void HELPER(clp)(CPUS390XState *env, uint32_t r2)
-{
-    S390CPU *cpu = env_archcpu(env);
-
-    qemu_mutex_lock_iothread();
-    clp_service_call(cpu, r2, GETPC());
-    qemu_mutex_unlock_iothread();
-}
-
-void HELPER(pcilg)(CPUS390XState *env, uint32_t r1, uint32_t r2)
-{
-    S390CPU *cpu = env_archcpu(env);
-
-    qemu_mutex_lock_iothread();
-    pcilg_service_call(cpu, r1, r2, GETPC());
-    qemu_mutex_unlock_iothread();
-}
-
-void HELPER(pcistg)(CPUS390XState *env, uint32_t r1, uint32_t r2)
-{
-    S390CPU *cpu = env_archcpu(env);
-
-    qemu_mutex_lock_iothread();
-    pcistg_service_call(cpu, r1, r2, GETPC());
-    qemu_mutex_unlock_iothread();
-}
-
-void HELPER(stpcifc)(CPUS390XState *env, uint32_t r1, uint64_t fiba,
-                     uint32_t ar)
-{
-    S390CPU *cpu = env_archcpu(env);
-
-    qemu_mutex_lock_iothread();
-    stpcifc_service_call(cpu, r1, fiba, ar, GETPC());
-    qemu_mutex_unlock_iothread();
-}
-
-void HELPER(sic)(CPUS390XState *env, uint64_t r1, uint64_t r3)
-{
-    int r;
-
-    qemu_mutex_lock_iothread();
-    r = css_do_sic(env, (r3 >> 27) & 0x7, r1 & 0xffff);
-    qemu_mutex_unlock_iothread();
-    /* css_do_sic() may actually return a PGM_xxx value to inject */
-    if (r) {
-        tcg_s390_program_interrupt(env, -r, GETPC());
-    }
-}
-
-void HELPER(rpcit)(CPUS390XState *env, uint32_t r1, uint32_t r2)
-{
-    S390CPU *cpu = env_archcpu(env);
-
-    qemu_mutex_lock_iothread();
-    rpcit_service_call(cpu, r1, r2, GETPC());
-    qemu_mutex_unlock_iothread();
-}
-
-void HELPER(pcistb)(CPUS390XState *env, uint32_t r1, uint32_t r3,
-                    uint64_t gaddr, uint32_t ar)
-{
-    S390CPU *cpu = env_archcpu(env);
-
-    qemu_mutex_lock_iothread();
-    pcistb_service_call(cpu, r1, r3, gaddr, ar, GETPC());
-    qemu_mutex_unlock_iothread();
-}
-
-void HELPER(mpcifc)(CPUS390XState *env, uint32_t r1, uint64_t fiba,
-                    uint32_t ar)
-{
-    S390CPU *cpu = env_archcpu(env);
-
-    qemu_mutex_lock_iothread();
-    mpcifc_service_call(cpu, r1, fiba, ar, GETPC());
-    qemu_mutex_unlock_iothread();
-}
-#endif
index d492b23a177680f938dcdd154beecaf6d76f8702..d779a9fc51fd3587c02f6f503ea97d5fd612b0ef 100644 (file)
@@ -19,8 +19,8 @@
 #include "qemu/error-report.h"
 #include "exec/address-spaces.h"
 #include "cpu.h"
-#include "internal.h"
-#include "kvm_s390x.h"
+#include "s390x-internal.h"
+#include "kvm/kvm_s390x.h"
 #include "sysemu/kvm.h"
 #include "sysemu/tcg.h"
 #include "exec/exec-all.h"
diff --git a/target/s390x/s390-tod.h b/target/s390x/s390-tod.h
deleted file mode 100644 (file)
index 8b74d6a..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * TOD (Time Of Day) clock
- *
- * Copyright 2018 Red Hat, Inc.
- * Author(s): David Hildenbrand <david@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#ifndef TARGET_S390_TOD_H
-#define TARGET_S390_TOD_H
-
-/* The value of the TOD clock for 1.1.1970. */
-#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL
-
-/* Converts ns to s390's clock format */
-static inline uint64_t time2tod(uint64_t ns)
-{
-    return (ns << 9) / 125 + (((ns & 0xff80000000000000ull) / 125) << 9);
-}
-
-/* Converts s390's clock format to ns */
-static inline uint64_t tod2time(uint64_t t)
-{
-    return ((t >> 9) * 125) + (((t & 0x1ff) * 125) >> 9);
-}
-
-#endif
diff --git a/target/s390x/s390x-internal.h b/target/s390x/s390x-internal.h
new file mode 100644 (file)
index 0000000..5506f18
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * s390x internal definitions and helpers
+ *
+ * Copyright (c) 2009 Ulrich Hecht
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef S390X_INTERNAL_H
+#define S390X_INTERNAL_H
+
+#include "cpu.h"
+
+#ifndef CONFIG_USER_ONLY
+typedef struct LowCore {
+    /* prefix area: defined by architecture */
+    uint32_t        ccw1[2];                  /* 0x000 */
+    uint32_t        ccw2[4];                  /* 0x008 */
+    uint8_t         pad1[0x80 - 0x18];        /* 0x018 */
+    uint32_t        ext_params;               /* 0x080 */
+    uint16_t        cpu_addr;                 /* 0x084 */
+    uint16_t        ext_int_code;             /* 0x086 */
+    uint16_t        svc_ilen;                 /* 0x088 */
+    uint16_t        svc_code;                 /* 0x08a */
+    uint16_t        pgm_ilen;                 /* 0x08c */
+    uint16_t        pgm_code;                 /* 0x08e */
+    uint32_t        data_exc_code;            /* 0x090 */
+    uint16_t        mon_class_num;            /* 0x094 */
+    uint16_t        per_perc_atmid;           /* 0x096 */
+    uint64_t        per_address;              /* 0x098 */
+    uint8_t         exc_access_id;            /* 0x0a0 */
+    uint8_t         per_access_id;            /* 0x0a1 */
+    uint8_t         op_access_id;             /* 0x0a2 */
+    uint8_t         ar_access_id;             /* 0x0a3 */
+    uint8_t         pad2[0xA8 - 0xA4];        /* 0x0a4 */
+    uint64_t        trans_exc_code;           /* 0x0a8 */
+    uint64_t        monitor_code;             /* 0x0b0 */
+    uint16_t        subchannel_id;            /* 0x0b8 */
+    uint16_t        subchannel_nr;            /* 0x0ba */
+    uint32_t        io_int_parm;              /* 0x0bc */
+    uint32_t        io_int_word;              /* 0x0c0 */
+    uint8_t         pad3[0xc8 - 0xc4];        /* 0x0c4 */
+    uint32_t        stfl_fac_list;            /* 0x0c8 */
+    uint8_t         pad4[0xe8 - 0xcc];        /* 0x0cc */
+    uint64_t        mcic;                     /* 0x0e8 */
+    uint8_t         pad5[0xf4 - 0xf0];        /* 0x0f0 */
+    uint32_t        external_damage_code;     /* 0x0f4 */
+    uint64_t        failing_storage_address;  /* 0x0f8 */
+    uint8_t         pad6[0x110 - 0x100];      /* 0x100 */
+    uint64_t        per_breaking_event_addr;  /* 0x110 */
+    uint8_t         pad7[0x120 - 0x118];      /* 0x118 */
+    PSW             restart_old_psw;          /* 0x120 */
+    PSW             external_old_psw;         /* 0x130 */
+    PSW             svc_old_psw;              /* 0x140 */
+    PSW             program_old_psw;          /* 0x150 */
+    PSW             mcck_old_psw;             /* 0x160 */
+    PSW             io_old_psw;               /* 0x170 */
+    uint8_t         pad8[0x1a0 - 0x180];      /* 0x180 */
+    PSW             restart_new_psw;          /* 0x1a0 */
+    PSW             external_new_psw;         /* 0x1b0 */
+    PSW             svc_new_psw;              /* 0x1c0 */
+    PSW             program_new_psw;          /* 0x1d0 */
+    PSW             mcck_new_psw;             /* 0x1e0 */
+    PSW             io_new_psw;               /* 0x1f0 */
+    uint8_t         pad13[0x11b0 - 0x200];    /* 0x200 */
+
+    uint64_t        mcesad;                    /* 0x11B0 */
+
+    /* 64 bit extparam used for pfault, diag 250 etc  */
+    uint64_t        ext_params2;               /* 0x11B8 */
+
+    uint8_t         pad14[0x1200 - 0x11C0];    /* 0x11C0 */
+
+    /* System info area */
+
+    uint64_t        floating_pt_save_area[16]; /* 0x1200 */
+    uint64_t        gpregs_save_area[16];      /* 0x1280 */
+    uint32_t        st_status_fixed_logout[4]; /* 0x1300 */
+    uint8_t         pad15[0x1318 - 0x1310];    /* 0x1310 */
+    uint32_t        prefixreg_save_area;       /* 0x1318 */
+    uint32_t        fpt_creg_save_area;        /* 0x131c */
+    uint8_t         pad16[0x1324 - 0x1320];    /* 0x1320 */
+    uint32_t        tod_progreg_save_area;     /* 0x1324 */
+    uint64_t        cpu_timer_save_area;       /* 0x1328 */
+    uint64_t        clock_comp_save_area;      /* 0x1330 */
+    uint8_t         pad17[0x1340 - 0x1338];    /* 0x1338 */
+    uint32_t        access_regs_save_area[16]; /* 0x1340 */
+    uint64_t        cregs_save_area[16];       /* 0x1380 */
+
+    /* align to the top of the prefix area */
+
+    uint8_t         pad18[0x2000 - 0x1400];    /* 0x1400 */
+} QEMU_PACKED LowCore;
+QEMU_BUILD_BUG_ON(sizeof(LowCore) != 8192);
+#endif /* CONFIG_USER_ONLY */
+
+#define MAX_ILEN 6
+
+/* While the PoO talks about ILC (a number between 1-3) what is actually
+   stored in LowCore is shifted left one bit (an even between 2-6).  As
+   this is the actual length of the insn and therefore more useful, that
+   is what we want to pass around and manipulate.  To make sure that we
+   have applied this distinction universally, rename the "ILC" to "ILEN".  */
+static inline int get_ilen(uint8_t opc)
+{
+    switch (opc >> 6) {
+    case 0:
+        return 2;
+    case 1:
+    case 2:
+        return 4;
+    default:
+        return 6;
+    }
+}
+
+/* Compute the ATMID field that is stored in the per_perc_atmid lowcore
+   entry when a PER exception is triggered.  */
+static inline uint8_t get_per_atmid(CPUS390XState *env)
+{
+    return ((env->psw.mask & PSW_MASK_64) ?       (1 << 7) : 0) |
+                                                  (1 << 6)      |
+           ((env->psw.mask & PSW_MASK_32) ?       (1 << 5) : 0) |
+           ((env->psw.mask & PSW_MASK_DAT) ?      (1 << 4) : 0) |
+           ((env->psw.mask & PSW_ASC_SECONDARY) ? (1 << 3) : 0) |
+           ((env->psw.mask & PSW_ASC_ACCREG) ?    (1 << 2) : 0);
+}
+
+static inline uint64_t wrap_address(CPUS390XState *env, uint64_t a)
+{
+    if (!(env->psw.mask & PSW_MASK_64)) {
+        if (!(env->psw.mask & PSW_MASK_32)) {
+            /* 24-Bit mode */
+            a &= 0x00ffffff;
+        } else {
+            /* 31-Bit mode */
+            a &= 0x7fffffff;
+        }
+    }
+    return a;
+}
+
+/* CC optimization */
+
+/* Instead of computing the condition codes after each x86 instruction,
+ * QEMU just stores the result (called CC_DST), the type of operation
+ * (called CC_OP) and whatever operands are needed (CC_SRC and possibly
+ * CC_VR). When the condition codes are needed, the condition codes can
+ * be calculated using this information. Condition codes are not generated
+ * if they are only needed for conditional branches.
+ */
+enum cc_op {
+    CC_OP_CONST0 = 0,           /* CC is 0 */
+    CC_OP_CONST1,               /* CC is 1 */
+    CC_OP_CONST2,               /* CC is 2 */
+    CC_OP_CONST3,               /* CC is 3 */
+
+    CC_OP_DYNAMIC,              /* CC calculation defined by env->cc_op */
+    CC_OP_STATIC,               /* CC value is env->cc_op */
+
+    CC_OP_NZ,                   /* env->cc_dst != 0 */
+    CC_OP_ADDU,                 /* dst != 0, src = carry out (0,1) */
+    CC_OP_SUBU,                 /* dst != 0, src = borrow out (0,-1) */
+
+    CC_OP_LTGT_32,              /* signed less/greater than (32bit) */
+    CC_OP_LTGT_64,              /* signed less/greater than (64bit) */
+    CC_OP_LTUGTU_32,            /* unsigned less/greater than (32bit) */
+    CC_OP_LTUGTU_64,            /* unsigned less/greater than (64bit) */
+    CC_OP_LTGT0_32,             /* signed less/greater than 0 (32bit) */
+    CC_OP_LTGT0_64,             /* signed less/greater than 0 (64bit) */
+
+    CC_OP_ADD_64,               /* overflow on add (64bit) */
+    CC_OP_SUB_64,               /* overflow on subtraction (64bit) */
+    CC_OP_ABS_64,               /* sign eval on abs (64bit) */
+    CC_OP_NABS_64,              /* sign eval on nabs (64bit) */
+    CC_OP_MULS_64,              /* overflow on signed multiply (64bit) */
+
+    CC_OP_ADD_32,               /* overflow on add (32bit) */
+    CC_OP_SUB_32,               /* overflow on subtraction (32bit) */
+    CC_OP_ABS_32,               /* sign eval on abs (64bit) */
+    CC_OP_NABS_32,              /* sign eval on nabs (64bit) */
+    CC_OP_MULS_32,              /* overflow on signed multiply (32bit) */
+
+    CC_OP_COMP_32,              /* complement */
+    CC_OP_COMP_64,              /* complement */
+
+    CC_OP_TM_32,                /* test under mask (32bit) */
+    CC_OP_TM_64,                /* test under mask (64bit) */
+
+    CC_OP_NZ_F32,               /* FP dst != 0 (32bit) */
+    CC_OP_NZ_F64,               /* FP dst != 0 (64bit) */
+    CC_OP_NZ_F128,              /* FP dst != 0 (128bit) */
+
+    CC_OP_ICM,                  /* insert characters under mask */
+    CC_OP_SLA_32,               /* Calculate shift left signed (32bit) */
+    CC_OP_SLA_64,               /* Calculate shift left signed (64bit) */
+    CC_OP_FLOGR,                /* find leftmost one */
+    CC_OP_LCBB,                 /* load count to block boundary */
+    CC_OP_VC,                   /* vector compare result */
+    CC_OP_MAX
+};
+
+#ifndef CONFIG_USER_ONLY
+
+static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb,
+                                       uint8_t *ar)
+{
+    hwaddr addr = 0;
+    uint8_t reg;
+
+    reg = ipb >> 28;
+    if (reg > 0) {
+        addr = env->regs[reg];
+    }
+    addr += (ipb >> 16) & 0xfff;
+    if (ar) {
+        *ar = reg;
+    }
+
+    return addr;
+}
+
+/* Base/displacement are at the same locations. */
+#define decode_basedisp_rs decode_basedisp_s
+
+#endif /* CONFIG_USER_ONLY */
+
+/* arch_dump.c */
+int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
+                              int cpuid, void *opaque);
+
+
+/* cc_helper.c */
+const char *cc_name(enum cc_op cc_op);
+uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
+                 uint64_t vr);
+
+/* cpu.c */
+#ifndef CONFIG_USER_ONLY
+unsigned int s390_cpu_halt(S390CPU *cpu);
+void s390_cpu_unhalt(S390CPU *cpu);
+void s390_cpu_init_sysemu(Object *obj);
+bool s390_cpu_realize_sysemu(DeviceState *dev, Error **errp);
+void s390_cpu_finalize(Object *obj);
+void s390_cpu_class_init_sysemu(CPUClass *cc);
+void s390_cpu_machine_reset_cb(void *opaque);
+
+#else
+static inline unsigned int s390_cpu_halt(S390CPU *cpu)
+{
+    return 0;
+}
+
+static inline void s390_cpu_unhalt(S390CPU *cpu)
+{
+}
+#endif /* CONFIG_USER_ONLY */
+
+
+/* cpu_models.c */
+void s390_cpu_model_class_register_props(ObjectClass *oc);
+void s390_realize_cpu_model(CPUState *cs, Error **errp);
+S390CPUModel *get_max_cpu_model(Error **errp);
+void apply_cpu_model(const S390CPUModel *model, Error **errp);
+ObjectClass *s390_cpu_class_by_name(const char *name);
+
+
+/* excp_helper.c */
+void s390x_cpu_debug_excp_handler(CPUState *cs);
+void s390_cpu_do_interrupt(CPUState *cpu);
+bool s390_cpu_exec_interrupt(CPUState *cpu, int int_req);
+bool s390_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+                       MMUAccessType access_type, int mmu_idx,
+                       bool probe, uintptr_t retaddr);
+void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
+                                   MMUAccessType access_type,
+                                   int mmu_idx, uintptr_t retaddr);
+
+
+/* fpu_helper.c */
+uint32_t set_cc_nz_f32(float32 v);
+uint32_t set_cc_nz_f64(float64 v);
+uint32_t set_cc_nz_f128(float128 v);
+#define S390_IEEE_MASK_INVALID   0x80
+#define S390_IEEE_MASK_DIVBYZERO 0x40
+#define S390_IEEE_MASK_OVERFLOW  0x20
+#define S390_IEEE_MASK_UNDERFLOW 0x10
+#define S390_IEEE_MASK_INEXACT   0x08
+#define S390_IEEE_MASK_QUANTUM   0x04
+uint8_t s390_softfloat_exc_to_ieee(unsigned int exc);
+int s390_swap_bfp_rounding_mode(CPUS390XState *env, int m3);
+void s390_restore_bfp_rounding_mode(CPUS390XState *env, int old_mode);
+int float_comp_to_cc(CPUS390XState *env, int float_compare);
+
+#define DCMASK_ZERO             0x0c00
+#define DCMASK_NORMAL           0x0300
+#define DCMASK_SUBNORMAL        0x00c0
+#define DCMASK_INFINITY         0x0030
+#define DCMASK_QUIET_NAN        0x000c
+#define DCMASK_SIGNALING_NAN    0x0003
+#define DCMASK_NAN              0x000f
+#define DCMASK_NEGATIVE         0x0555
+uint16_t float32_dcmask(CPUS390XState *env, float32 f1);
+uint16_t float64_dcmask(CPUS390XState *env, float64 f1);
+uint16_t float128_dcmask(CPUS390XState *env, float128 f1);
+
+
+/* gdbstub.c */
+int s390_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
+int s390_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
+void s390_cpu_gdb_init(CPUState *cs);
+
+
+/* helper.c */
+void s390_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
+void do_restart_interrupt(CPUS390XState *env);
+#ifndef CONFIG_USER_ONLY
+void s390_cpu_recompute_watchpoints(CPUState *cs);
+void s390x_tod_timer(void *opaque);
+void s390x_cpu_timer(void *opaque);
+void s390_handle_wait(S390CPU *cpu);
+hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+hwaddr s390_cpu_get_phys_addr_debug(CPUState *cpu, vaddr addr);
+#define S390_STORE_STATUS_DEF_ADDR offsetof(LowCore, floating_pt_save_area)
+int s390_store_status(S390CPU *cpu, hwaddr addr, bool store_arch);
+int s390_store_adtl_status(S390CPU *cpu, hwaddr addr, hwaddr len);
+LowCore *cpu_map_lowcore(CPUS390XState *env);
+void cpu_unmap_lowcore(LowCore *lowcore);
+#endif /* CONFIG_USER_ONLY */
+
+
+/* interrupt.c */
+void trigger_pgm_exception(CPUS390XState *env, uint32_t code);
+void cpu_inject_clock_comparator(S390CPU *cpu);
+void cpu_inject_cpu_timer(S390CPU *cpu);
+void cpu_inject_emergency_signal(S390CPU *cpu, uint16_t src_cpu_addr);
+int cpu_inject_external_call(S390CPU *cpu, uint16_t src_cpu_addr);
+bool s390_cpu_has_io_int(S390CPU *cpu);
+bool s390_cpu_has_ext_int(S390CPU *cpu);
+bool s390_cpu_has_mcck_int(S390CPU *cpu);
+bool s390_cpu_has_int(S390CPU *cpu);
+bool s390_cpu_has_restart_int(S390CPU *cpu);
+bool s390_cpu_has_stop_int(S390CPU *cpu);
+void cpu_inject_restart(S390CPU *cpu);
+void cpu_inject_stop(S390CPU *cpu);
+
+
+/* ioinst.c */
+void ioinst_handle_xsch(S390CPU *cpu, uint64_t reg1, uintptr_t ra);
+void ioinst_handle_csch(S390CPU *cpu, uint64_t reg1, uintptr_t ra);
+void ioinst_handle_hsch(S390CPU *cpu, uint64_t reg1, uintptr_t ra);
+void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb,
+                        uintptr_t ra);
+void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb,
+                        uintptr_t ra);
+void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb, uintptr_t ra);
+void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb,
+                         uintptr_t ra);
+int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra);
+void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra);
+void ioinst_handle_schm(S390CPU *cpu, uint64_t reg1, uint64_t reg2,
+                        uint32_t ipb, uintptr_t ra);
+void ioinst_handle_rsch(S390CPU *cpu, uint64_t reg1, uintptr_t ra);
+void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1, uintptr_t ra);
+void ioinst_handle_sal(S390CPU *cpu, uint64_t reg1, uintptr_t ra);
+
+
+/* mem_helper.c */
+target_ulong mmu_real2abs(CPUS390XState *env, target_ulong raddr);
+void probe_write_access(CPUS390XState *env, uint64_t addr, uint64_t len,
+                        uintptr_t ra);
+
+
+/* mmu_helper.c */
+int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
+                  target_ulong *raddr, int *flags, uint64_t *tec);
+int mmu_translate_real(CPUS390XState *env, target_ulong raddr, int rw,
+                       target_ulong *addr, int *flags, uint64_t *tec);
+
+
+/* misc_helper.c */
+int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3);
+void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3,
+                     uintptr_t ra);
+
+
+/* translate.c */
+void s390x_translate_init(void);
+
+
+/* sigp.c */
+int handle_sigp(CPUS390XState *env, uint8_t order, uint64_t r1, uint64_t r3);
+void do_stop_interrupt(CPUS390XState *env);
+
+#endif /* S390X_INTERNAL_H */
index c2d5cdf0613334b079dd3db8625c837128671dd3..d57427ced84d9d6a1ce5500eedc989d16e03503f 100644 (file)
@@ -10,7 +10,7 @@
 
 #include "qemu/osdep.h"
 #include "cpu.h"
-#include "internal.h"
+#include "s390x-internal.h"
 #include "sysemu/hw_accel.h"
 #include "sysemu/runstate.h"
 #include "exec/address-spaces.h"
diff --git a/target/s390x/tcg-stub.c b/target/s390x/tcg-stub.c
deleted file mode 100644 (file)
index d22c898..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * QEMU TCG support -- s390x specific function stubs.
- *
- * Copyright (C) 2018 Red Hat Inc
- *
- * Authors:
- *   David Hildenbrand <david@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "tcg_s390x.h"
-
-void tcg_s390_tod_updated(CPUState *cs, run_on_cpu_data opaque)
-{
-}
-void QEMU_NORETURN tcg_s390_program_interrupt(CPUS390XState *env,
-                                              uint32_t code, uintptr_t ra)
-{
-    g_assert_not_reached();
-}
-void QEMU_NORETURN tcg_s390_data_exception(CPUS390XState *env, uint32_t dxc,
-                                           uintptr_t ra)
-{
-    g_assert_not_reached();
-}
diff --git a/target/s390x/tcg/cc_helper.c b/target/s390x/tcg/cc_helper.c
new file mode 100644 (file)
index 0000000..c2c96c3
--- /dev/null
@@ -0,0 +1,538 @@
+/*
+ *  S/390 condition code helper routines
+ *
+ *  Copyright (c) 2009 Ulrich Hecht
+ *  Copyright (c) 2009 Alexander Graf
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "s390x-internal.h"
+#include "tcg_s390x.h"
+#include "exec/exec-all.h"
+#include "exec/helper-proto.h"
+#include "qemu/host-utils.h"
+
+/* #define DEBUG_HELPER */
+#ifdef DEBUG_HELPER
+#define HELPER_LOG(x...) qemu_log(x)
+#else
+#define HELPER_LOG(x...)
+#endif
+
+static uint32_t cc_calc_ltgt_32(int32_t src, int32_t dst)
+{
+    if (src == dst) {
+        return 0;
+    } else if (src < dst) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+
+static uint32_t cc_calc_ltgt0_32(int32_t dst)
+{
+    return cc_calc_ltgt_32(dst, 0);
+}
+
+static uint32_t cc_calc_ltgt_64(int64_t src, int64_t dst)
+{
+    if (src == dst) {
+        return 0;
+    } else if (src < dst) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+
+static uint32_t cc_calc_ltgt0_64(int64_t dst)
+{
+    return cc_calc_ltgt_64(dst, 0);
+}
+
+static uint32_t cc_calc_ltugtu_32(uint32_t src, uint32_t dst)
+{
+    if (src == dst) {
+        return 0;
+    } else if (src < dst) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+
+static uint32_t cc_calc_ltugtu_64(uint64_t src, uint64_t dst)
+{
+    if (src == dst) {
+        return 0;
+    } else if (src < dst) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+
+static uint32_t cc_calc_tm_32(uint32_t val, uint32_t mask)
+{
+    uint32_t r = val & mask;
+
+    if (r == 0) {
+        return 0;
+    } else if (r == mask) {
+        return 3;
+    } else {
+        return 1;
+    }
+}
+
+static uint32_t cc_calc_tm_64(uint64_t val, uint64_t mask)
+{
+    uint64_t r = val & mask;
+
+    if (r == 0) {
+        return 0;
+    } else if (r == mask) {
+        return 3;
+    } else {
+        int top = clz64(mask);
+        if ((int64_t)(val << top) < 0) {
+            return 2;
+        } else {
+            return 1;
+        }
+    }
+}
+
+static uint32_t cc_calc_nz(uint64_t dst)
+{
+    return !!dst;
+}
+
+static uint32_t cc_calc_addu(uint64_t carry_out, uint64_t result)
+{
+    g_assert(carry_out <= 1);
+    return (result != 0) + 2 * carry_out;
+}
+
+static uint32_t cc_calc_subu(uint64_t borrow_out, uint64_t result)
+{
+    return cc_calc_addu(borrow_out + 1, result);
+}
+
+static uint32_t cc_calc_add_64(int64_t a1, int64_t a2, int64_t ar)
+{
+    if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
+        return 3; /* overflow */
+    } else {
+        if (ar < 0) {
+            return 1;
+        } else if (ar > 0) {
+            return 2;
+        } else {
+            return 0;
+        }
+    }
+}
+
+static uint32_t cc_calc_sub_64(int64_t a1, int64_t a2, int64_t ar)
+{
+    if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
+        return 3; /* overflow */
+    } else {
+        if (ar < 0) {
+            return 1;
+        } else if (ar > 0) {
+            return 2;
+        } else {
+            return 0;
+        }
+    }
+}
+
+static uint32_t cc_calc_abs_64(int64_t dst)
+{
+    if ((uint64_t)dst == 0x8000000000000000ULL) {
+        return 3;
+    } else if (dst) {
+        return 2;
+    } else {
+        return 0;
+    }
+}
+
+static uint32_t cc_calc_nabs_64(int64_t dst)
+{
+    return !!dst;
+}
+
+static uint32_t cc_calc_comp_64(int64_t dst)
+{
+    if ((uint64_t)dst == 0x8000000000000000ULL) {
+        return 3;
+    } else if (dst < 0) {
+        return 1;
+    } else if (dst > 0) {
+        return 2;
+    } else {
+        return 0;
+    }
+}
+
+
+static uint32_t cc_calc_add_32(int32_t a1, int32_t a2, int32_t ar)
+{
+    if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
+        return 3; /* overflow */
+    } else {
+        if (ar < 0) {
+            return 1;
+        } else if (ar > 0) {
+            return 2;
+        } else {
+            return 0;
+        }
+    }
+}
+
+static uint32_t cc_calc_sub_32(int32_t a1, int32_t a2, int32_t ar)
+{
+    if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
+        return 3; /* overflow */
+    } else {
+        if (ar < 0) {
+            return 1;
+        } else if (ar > 0) {
+            return 2;
+        } else {
+            return 0;
+        }
+    }
+}
+
+static uint32_t cc_calc_abs_32(int32_t dst)
+{
+    if ((uint32_t)dst == 0x80000000UL) {
+        return 3;
+    } else if (dst) {
+        return 2;
+    } else {
+        return 0;
+    }
+}
+
+static uint32_t cc_calc_nabs_32(int32_t dst)
+{
+    return !!dst;
+}
+
+static uint32_t cc_calc_comp_32(int32_t dst)
+{
+    if ((uint32_t)dst == 0x80000000UL) {
+        return 3;
+    } else if (dst < 0) {
+        return 1;
+    } else if (dst > 0) {
+        return 2;
+    } else {
+        return 0;
+    }
+}
+
+/* calculate condition code for insert character under mask insn */
+static uint32_t cc_calc_icm(uint64_t mask, uint64_t val)
+{
+    if ((val & mask) == 0) {
+        return 0;
+    } else {
+        int top = clz64(mask);
+        if ((int64_t)(val << top) < 0) {
+            return 1;
+        } else {
+            return 2;
+        }
+    }
+}
+
+static uint32_t cc_calc_sla_32(uint32_t src, int shift)
+{
+    uint32_t mask = ((1U << shift) - 1U) << (32 - shift);
+    uint32_t sign = 1U << 31;
+    uint32_t match;
+    int32_t r;
+
+    /* Check if the sign bit stays the same.  */
+    if (src & sign) {
+        match = mask;
+    } else {
+        match = 0;
+    }
+    if ((src & mask) != match) {
+        /* Overflow.  */
+        return 3;
+    }
+
+    r = ((src << shift) & ~sign) | (src & sign);
+    if (r == 0) {
+        return 0;
+    } else if (r < 0) {
+        return 1;
+    }
+    return 2;
+}
+
+static uint32_t cc_calc_sla_64(uint64_t src, int shift)
+{
+    uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift);
+    uint64_t sign = 1ULL << 63;
+    uint64_t match;
+    int64_t r;
+
+    /* Check if the sign bit stays the same.  */
+    if (src & sign) {
+        match = mask;
+    } else {
+        match = 0;
+    }
+    if ((src & mask) != match) {
+        /* Overflow.  */
+        return 3;
+    }
+
+    r = ((src << shift) & ~sign) | (src & sign);
+    if (r == 0) {
+        return 0;
+    } else if (r < 0) {
+        return 1;
+    }
+    return 2;
+}
+
+static uint32_t cc_calc_flogr(uint64_t dst)
+{
+    return dst ? 2 : 0;
+}
+
+static uint32_t cc_calc_lcbb(uint64_t dst)
+{
+    return dst == 16 ? 0 : 3;
+}
+
+static uint32_t cc_calc_vc(uint64_t low, uint64_t high)
+{
+    if (high == -1ull && low == -1ull) {
+        /* all elements match */
+        return 0;
+    } else if (high == 0 && low == 0) {
+        /* no elements match */
+        return 3;
+    } else {
+        /* some elements but not all match */
+        return 1;
+    }
+}
+
+static uint32_t cc_calc_muls_32(int64_t res)
+{
+    const int64_t tmp = res >> 31;
+
+    if (!res) {
+        return 0;
+    } else if (tmp && tmp != -1) {
+        return 3;
+    } else if (res < 0) {
+        return 1;
+    }
+    return 2;
+}
+
+static uint64_t cc_calc_muls_64(int64_t res_high, uint64_t res_low)
+{
+    if (!res_high && !res_low) {
+        return 0;
+    } else if (res_high + (res_low >> 63) != 0) {
+        return 3;
+    } else if (res_high < 0) {
+        return 1;
+    }
+    return 2;
+}
+
+static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op,
+                                  uint64_t src, uint64_t dst, uint64_t vr)
+{
+    uint32_t r = 0;
+
+    switch (cc_op) {
+    case CC_OP_CONST0:
+    case CC_OP_CONST1:
+    case CC_OP_CONST2:
+    case CC_OP_CONST3:
+        /* cc_op value _is_ cc */
+        r = cc_op;
+        break;
+    case CC_OP_LTGT0_32:
+        r = cc_calc_ltgt0_32(dst);
+        break;
+    case CC_OP_LTGT0_64:
+        r =  cc_calc_ltgt0_64(dst);
+        break;
+    case CC_OP_LTGT_32:
+        r =  cc_calc_ltgt_32(src, dst);
+        break;
+    case CC_OP_LTGT_64:
+        r =  cc_calc_ltgt_64(src, dst);
+        break;
+    case CC_OP_LTUGTU_32:
+        r =  cc_calc_ltugtu_32(src, dst);
+        break;
+    case CC_OP_LTUGTU_64:
+        r =  cc_calc_ltugtu_64(src, dst);
+        break;
+    case CC_OP_TM_32:
+        r =  cc_calc_tm_32(src, dst);
+        break;
+    case CC_OP_TM_64:
+        r =  cc_calc_tm_64(src, dst);
+        break;
+    case CC_OP_NZ:
+        r =  cc_calc_nz(dst);
+        break;
+    case CC_OP_ADDU:
+        r = cc_calc_addu(src, dst);
+        break;
+    case CC_OP_SUBU:
+        r = cc_calc_subu(src, dst);
+        break;
+    case CC_OP_ADD_64:
+        r =  cc_calc_add_64(src, dst, vr);
+        break;
+    case CC_OP_SUB_64:
+        r =  cc_calc_sub_64(src, dst, vr);
+        break;
+    case CC_OP_ABS_64:
+        r =  cc_calc_abs_64(dst);
+        break;
+    case CC_OP_NABS_64:
+        r =  cc_calc_nabs_64(dst);
+        break;
+    case CC_OP_COMP_64:
+        r =  cc_calc_comp_64(dst);
+        break;
+    case CC_OP_MULS_64:
+        r = cc_calc_muls_64(src, dst);
+        break;
+
+    case CC_OP_ADD_32:
+        r =  cc_calc_add_32(src, dst, vr);
+        break;
+    case CC_OP_SUB_32:
+        r =  cc_calc_sub_32(src, dst, vr);
+        break;
+    case CC_OP_ABS_32:
+        r =  cc_calc_abs_32(dst);
+        break;
+    case CC_OP_NABS_32:
+        r =  cc_calc_nabs_32(dst);
+        break;
+    case CC_OP_COMP_32:
+        r =  cc_calc_comp_32(dst);
+        break;
+    case CC_OP_MULS_32:
+        r = cc_calc_muls_32(dst);
+        break;
+
+    case CC_OP_ICM:
+        r =  cc_calc_icm(src, dst);
+        break;
+    case CC_OP_SLA_32:
+        r =  cc_calc_sla_32(src, dst);
+        break;
+    case CC_OP_SLA_64:
+        r =  cc_calc_sla_64(src, dst);
+        break;
+    case CC_OP_FLOGR:
+        r = cc_calc_flogr(dst);
+        break;
+    case CC_OP_LCBB:
+        r = cc_calc_lcbb(dst);
+        break;
+    case CC_OP_VC:
+        r = cc_calc_vc(src, dst);
+        break;
+
+    case CC_OP_NZ_F32:
+        r = set_cc_nz_f32(dst);
+        break;
+    case CC_OP_NZ_F64:
+        r = set_cc_nz_f64(dst);
+        break;
+    case CC_OP_NZ_F128:
+        r = set_cc_nz_f128(make_float128(src, dst));
+        break;
+
+    default:
+        cpu_abort(env_cpu(env), "Unknown CC operation: %s\n", cc_name(cc_op));
+    }
+
+    HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __func__,
+               cc_name(cc_op), src, dst, vr, r);
+    return r;
+}
+
+uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
+                 uint64_t vr)
+{
+    return do_calc_cc(env, cc_op, src, dst, vr);
+}
+
+uint32_t HELPER(calc_cc)(CPUS390XState *env, uint32_t cc_op, uint64_t src,
+                         uint64_t dst, uint64_t vr)
+{
+    return do_calc_cc(env, cc_op, src, dst, vr);
+}
+
+#ifndef CONFIG_USER_ONLY
+void HELPER(load_psw)(CPUS390XState *env, uint64_t mask, uint64_t addr)
+{
+    s390_cpu_set_psw(env, mask, addr);
+    cpu_loop_exit(env_cpu(env));
+}
+
+void HELPER(sacf)(CPUS390XState *env, uint64_t a1)
+{
+    HELPER_LOG("%s: %16" PRIx64 "\n", __func__, a1);
+
+    switch (a1 & 0xf00) {
+    case 0x000:
+        env->psw.mask &= ~PSW_MASK_ASC;
+        env->psw.mask |= PSW_ASC_PRIMARY;
+        break;
+    case 0x100:
+        env->psw.mask &= ~PSW_MASK_ASC;
+        env->psw.mask |= PSW_ASC_SECONDARY;
+        break;
+    case 0x300:
+        env->psw.mask &= ~PSW_MASK_ASC;
+        env->psw.mask |= PSW_ASC_HOME;
+        break;
+    default:
+        HELPER_LOG("unknown sacf mode: %" PRIx64 "\n", a1);
+        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
+    }
+}
+#endif
diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c
new file mode 100644 (file)
index 0000000..138d9e7
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ *  s390x crypto helpers
+ *
+ *  Copyright (c) 2017 Red Hat Inc
+ *
+ *  Authors:
+ *   David Hildenbrand <david@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/main-loop.h"
+#include "s390x-internal.h"
+#include "tcg_s390x.h"
+#include "exec/helper-proto.h"
+#include "exec/exec-all.h"
+#include "exec/cpu_ldst.h"
+
+uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3,
+                     uint32_t type)
+{
+    const uintptr_t ra = GETPC();
+    const uint8_t mod = env->regs[0] & 0x80ULL;
+    const uint8_t fc = env->regs[0] & 0x7fULL;
+    uint8_t subfunc[16] = { 0 };
+    uint64_t param_addr;
+    int i;
+
+    switch (type) {
+    case S390_FEAT_TYPE_KMAC:
+    case S390_FEAT_TYPE_KIMD:
+    case S390_FEAT_TYPE_KLMD:
+    case S390_FEAT_TYPE_PCKMO:
+    case S390_FEAT_TYPE_PCC:
+        if (mod) {
+            tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+        }
+        break;
+    }
+
+    s390_get_feat_block(type, subfunc);
+    if (!test_be_bit(fc, subfunc)) {
+        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+    }
+
+    switch (fc) {
+    case 0: /* query subfunction */
+        for (i = 0; i < 16; i++) {
+            param_addr = wrap_address(env, env->regs[1] + i);
+            cpu_stb_data_ra(env, param_addr, subfunc[i], ra);
+        }
+        break;
+    default:
+        /* we don't implement any other subfunction yet */
+        g_assert_not_reached();
+    }
+
+    return 0;
+}
diff --git a/target/s390x/tcg/excp_helper.c b/target/s390x/tcg/excp_helper.c
new file mode 100644 (file)
index 0000000..a61917d
--- /dev/null
@@ -0,0 +1,641 @@
+/*
+ * s390x exception / interrupt helpers
+ *
+ *  Copyright (c) 2009 Ulrich Hecht
+ *  Copyright (c) 2011 Alexander Graf
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "s390x-internal.h"
+#include "exec/helper-proto.h"
+#include "qemu/timer.h"
+#include "exec/exec-all.h"
+#include "exec/cpu_ldst.h"
+#include "hw/s390x/ioinst.h"
+#include "exec/address-spaces.h"
+#include "tcg_s390x.h"
+#ifndef CONFIG_USER_ONLY
+#include "hw/s390x/s390_flic.h"
+#include "hw/boards.h"
+#endif
+
+void QEMU_NORETURN tcg_s390_program_interrupt(CPUS390XState *env,
+                                              uint32_t code, uintptr_t ra)
+{
+    CPUState *cs = env_cpu(env);
+
+    cpu_restore_state(cs, ra, true);
+    qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
+                  env->psw.addr);
+    trigger_pgm_exception(env, code);
+    cpu_loop_exit(cs);
+}
+
+void QEMU_NORETURN tcg_s390_data_exception(CPUS390XState *env, uint32_t dxc,
+                                           uintptr_t ra)
+{
+    g_assert(dxc <= 0xff);
+#if !defined(CONFIG_USER_ONLY)
+    /* Store the DXC into the lowcore */
+    stl_phys(env_cpu(env)->as,
+             env->psa + offsetof(LowCore, data_exc_code), dxc);
+#endif
+
+    /* Store the DXC into the FPC if AFP is enabled */
+    if (env->cregs[0] & CR0_AFP) {
+        env->fpc = deposit32(env->fpc, 8, 8, dxc);
+    }
+    tcg_s390_program_interrupt(env, PGM_DATA, ra);
+}
+
+void QEMU_NORETURN tcg_s390_vector_exception(CPUS390XState *env, uint32_t vxc,
+                                             uintptr_t ra)
+{
+    g_assert(vxc <= 0xff);
+#if !defined(CONFIG_USER_ONLY)
+    /* Always store the VXC into the lowcore, without AFP it is undefined */
+    stl_phys(env_cpu(env)->as,
+             env->psa + offsetof(LowCore, data_exc_code), vxc);
+#endif
+
+    /* Always store the VXC into the FPC, without AFP it is undefined */
+    env->fpc = deposit32(env->fpc, 8, 8, vxc);
+    tcg_s390_program_interrupt(env, PGM_VECTOR_PROCESSING, ra);
+}
+
+void HELPER(data_exception)(CPUS390XState *env, uint32_t dxc)
+{
+    tcg_s390_data_exception(env, dxc, GETPC());
+}
+
+#if defined(CONFIG_USER_ONLY)
+
+void s390_cpu_do_interrupt(CPUState *cs)
+{
+    cs->exception_index = -1;
+}
+
+bool s390_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+                       MMUAccessType access_type, int mmu_idx,
+                       bool probe, uintptr_t retaddr)
+{
+    S390CPU *cpu = S390_CPU(cs);
+
+    trigger_pgm_exception(&cpu->env, PGM_ADDRESSING);
+    /* On real machines this value is dropped into LowMem.  Since this
+       is userland, simply put this someplace that cpu_loop can find it.  */
+    cpu->env.__excp_addr = address;
+    cpu_loop_exit_restore(cs, retaddr);
+}
+
+#else /* !CONFIG_USER_ONLY */
+
+static inline uint64_t cpu_mmu_idx_to_asc(int mmu_idx)
+{
+    switch (mmu_idx) {
+    case MMU_PRIMARY_IDX:
+        return PSW_ASC_PRIMARY;
+    case MMU_SECONDARY_IDX:
+        return PSW_ASC_SECONDARY;
+    case MMU_HOME_IDX:
+        return PSW_ASC_HOME;
+    default:
+        abort();
+    }
+}
+
+bool s390_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+                       MMUAccessType access_type, int mmu_idx,
+                       bool probe, uintptr_t retaddr)
+{
+    S390CPU *cpu = S390_CPU(cs);
+    CPUS390XState *env = &cpu->env;
+    target_ulong vaddr, raddr;
+    uint64_t asc, tec;
+    int prot, excp;
+
+    qemu_log_mask(CPU_LOG_MMU, "%s: addr 0x%" VADDR_PRIx " rw %d mmu_idx %d\n",
+                  __func__, address, access_type, mmu_idx);
+
+    vaddr = address;
+
+    if (mmu_idx < MMU_REAL_IDX) {
+        asc = cpu_mmu_idx_to_asc(mmu_idx);
+        /* 31-Bit mode */
+        if (!(env->psw.mask & PSW_MASK_64)) {
+            vaddr &= 0x7fffffff;
+        }
+        excp = mmu_translate(env, vaddr, access_type, asc, &raddr, &prot, &tec);
+    } else if (mmu_idx == MMU_REAL_IDX) {
+        /* 31-Bit mode */
+        if (!(env->psw.mask & PSW_MASK_64)) {
+            vaddr &= 0x7fffffff;
+        }
+        excp = mmu_translate_real(env, vaddr, access_type, &raddr, &prot, &tec);
+    } else {
+        g_assert_not_reached();
+    }
+
+    /* check out of RAM access */
+    if (!excp &&
+        !address_space_access_valid(&address_space_memory, raddr,
+                                    TARGET_PAGE_SIZE, access_type,
+                                    MEMTXATTRS_UNSPECIFIED)) {
+        MachineState *ms = MACHINE(qdev_get_machine());
+        qemu_log_mask(CPU_LOG_MMU,
+                      "%s: raddr %" PRIx64 " > ram_size %" PRIx64 "\n",
+                      __func__, (uint64_t)raddr, (uint64_t)ms->ram_size);
+        excp = PGM_ADDRESSING;
+        tec = 0; /* unused */
+    }
+
+    env->tlb_fill_exc = excp;
+    env->tlb_fill_tec = tec;
+
+    if (!excp) {
+        qemu_log_mask(CPU_LOG_MMU,
+                      "%s: set tlb %" PRIx64 " -> %" PRIx64 " (%x)\n",
+                      __func__, (uint64_t)vaddr, (uint64_t)raddr, prot);
+        tlb_set_page(cs, address & TARGET_PAGE_MASK, raddr, prot,
+                     mmu_idx, TARGET_PAGE_SIZE);
+        return true;
+    }
+    if (probe) {
+        return false;
+    }
+
+    if (excp != PGM_ADDRESSING) {
+        stq_phys(env_cpu(env)->as,
+                 env->psa + offsetof(LowCore, trans_exc_code), tec);
+    }
+
+    /*
+     * For data accesses, ILEN will be filled in from the unwind info,
+     * within cpu_loop_exit_restore.  For code accesses, retaddr == 0,
+     * and so unwinding will not occur.  However, ILEN is also undefined
+     * for that case -- we choose to set ILEN = 2.
+     */
+    env->int_pgm_ilen = 2;
+    trigger_pgm_exception(env, excp);
+    cpu_loop_exit_restore(cs, retaddr);
+}
+
+static void do_program_interrupt(CPUS390XState *env)
+{
+    uint64_t mask, addr;
+    LowCore *lowcore;
+    int ilen = env->int_pgm_ilen;
+
+    assert(ilen == 2 || ilen == 4 || ilen == 6);
+
+    switch (env->int_pgm_code) {
+    case PGM_PER:
+        if (env->per_perc_atmid & PER_CODE_EVENT_NULLIFICATION) {
+            break;
+        }
+        /* FALL THROUGH */
+    case PGM_OPERATION:
+    case PGM_PRIVILEGED:
+    case PGM_EXECUTE:
+    case PGM_PROTECTION:
+    case PGM_ADDRESSING:
+    case PGM_SPECIFICATION:
+    case PGM_DATA:
+    case PGM_FIXPT_OVERFLOW:
+    case PGM_FIXPT_DIVIDE:
+    case PGM_DEC_OVERFLOW:
+    case PGM_DEC_DIVIDE:
+    case PGM_HFP_EXP_OVERFLOW:
+    case PGM_HFP_EXP_UNDERFLOW:
+    case PGM_HFP_SIGNIFICANCE:
+    case PGM_HFP_DIVIDE:
+    case PGM_TRANS_SPEC:
+    case PGM_SPECIAL_OP:
+    case PGM_OPERAND:
+    case PGM_HFP_SQRT:
+    case PGM_PC_TRANS_SPEC:
+    case PGM_ALET_SPEC:
+    case PGM_MONITOR:
+        /* advance the PSW if our exception is not nullifying */
+        env->psw.addr += ilen;
+        break;
+    }
+
+    qemu_log_mask(CPU_LOG_INT,
+                  "%s: code=0x%x ilen=%d psw: %" PRIx64 " %" PRIx64 "\n",
+                  __func__, env->int_pgm_code, ilen, env->psw.mask,
+                  env->psw.addr);
+
+    lowcore = cpu_map_lowcore(env);
+
+    /* Signal PER events with the exception.  */
+    if (env->per_perc_atmid) {
+        env->int_pgm_code |= PGM_PER;
+        lowcore->per_address = cpu_to_be64(env->per_address);
+        lowcore->per_perc_atmid = cpu_to_be16(env->per_perc_atmid);
+        env->per_perc_atmid = 0;
+    }
+
+    lowcore->pgm_ilen = cpu_to_be16(ilen);
+    lowcore->pgm_code = cpu_to_be16(env->int_pgm_code);
+    lowcore->program_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
+    lowcore->program_old_psw.addr = cpu_to_be64(env->psw.addr);
+    mask = be64_to_cpu(lowcore->program_new_psw.mask);
+    addr = be64_to_cpu(lowcore->program_new_psw.addr);
+    lowcore->per_breaking_event_addr = cpu_to_be64(env->gbea);
+
+    cpu_unmap_lowcore(lowcore);
+
+    s390_cpu_set_psw(env, mask, addr);
+}
+
+static void do_svc_interrupt(CPUS390XState *env)
+{
+    uint64_t mask, addr;
+    LowCore *lowcore;
+
+    lowcore = cpu_map_lowcore(env);
+
+    lowcore->svc_code = cpu_to_be16(env->int_svc_code);
+    lowcore->svc_ilen = cpu_to_be16(env->int_svc_ilen);
+    lowcore->svc_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
+    lowcore->svc_old_psw.addr = cpu_to_be64(env->psw.addr + env->int_svc_ilen);
+    mask = be64_to_cpu(lowcore->svc_new_psw.mask);
+    addr = be64_to_cpu(lowcore->svc_new_psw.addr);
+
+    cpu_unmap_lowcore(lowcore);
+
+    s390_cpu_set_psw(env, mask, addr);
+
+    /* When a PER event is pending, the PER exception has to happen
+       immediately after the SERVICE CALL one.  */
+    if (env->per_perc_atmid) {
+        env->int_pgm_code = PGM_PER;
+        env->int_pgm_ilen = env->int_svc_ilen;
+        do_program_interrupt(env);
+    }
+}
+
+#define VIRTIO_SUBCODE_64 0x0D00
+
+static void do_ext_interrupt(CPUS390XState *env)
+{
+    QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic());
+    S390CPU *cpu = env_archcpu(env);
+    uint64_t mask, addr;
+    uint16_t cpu_addr;
+    LowCore *lowcore;
+
+    if (!(env->psw.mask & PSW_MASK_EXT)) {
+        cpu_abort(CPU(cpu), "Ext int w/o ext mask\n");
+    }
+
+    lowcore = cpu_map_lowcore(env);
+
+    if ((env->pending_int & INTERRUPT_EMERGENCY_SIGNAL) &&
+        (env->cregs[0] & CR0_EMERGENCY_SIGNAL_SC)) {
+        MachineState *ms = MACHINE(qdev_get_machine());
+        unsigned int max_cpus = ms->smp.max_cpus;
+
+        lowcore->ext_int_code = cpu_to_be16(EXT_EMERGENCY);
+        cpu_addr = find_first_bit(env->emergency_signals, S390_MAX_CPUS);
+        g_assert(cpu_addr < S390_MAX_CPUS);
+        lowcore->cpu_addr = cpu_to_be16(cpu_addr);
+        clear_bit(cpu_addr, env->emergency_signals);
+        if (bitmap_empty(env->emergency_signals, max_cpus)) {
+            env->pending_int &= ~INTERRUPT_EMERGENCY_SIGNAL;
+        }
+    } else if ((env->pending_int & INTERRUPT_EXTERNAL_CALL) &&
+               (env->cregs[0] & CR0_EXTERNAL_CALL_SC)) {
+        lowcore->ext_int_code = cpu_to_be16(EXT_EXTERNAL_CALL);
+        lowcore->cpu_addr = cpu_to_be16(env->external_call_addr);
+        env->pending_int &= ~INTERRUPT_EXTERNAL_CALL;
+    } else if ((env->pending_int & INTERRUPT_EXT_CLOCK_COMPARATOR) &&
+               (env->cregs[0] & CR0_CKC_SC)) {
+        lowcore->ext_int_code = cpu_to_be16(EXT_CLOCK_COMP);
+        lowcore->cpu_addr = 0;
+        env->pending_int &= ~INTERRUPT_EXT_CLOCK_COMPARATOR;
+    } else if ((env->pending_int & INTERRUPT_EXT_CPU_TIMER) &&
+               (env->cregs[0] & CR0_CPU_TIMER_SC)) {
+        lowcore->ext_int_code = cpu_to_be16(EXT_CPU_TIMER);
+        lowcore->cpu_addr = 0;
+        env->pending_int &= ~INTERRUPT_EXT_CPU_TIMER;
+    } else if (qemu_s390_flic_has_service(flic) &&
+               (env->cregs[0] & CR0_SERVICE_SC)) {
+        uint32_t param;
+
+        param = qemu_s390_flic_dequeue_service(flic);
+        lowcore->ext_int_code = cpu_to_be16(EXT_SERVICE);
+        lowcore->ext_params = cpu_to_be32(param);
+        lowcore->cpu_addr = 0;
+    } else {
+        g_assert_not_reached();
+    }
+
+    mask = be64_to_cpu(lowcore->external_new_psw.mask);
+    addr = be64_to_cpu(lowcore->external_new_psw.addr);
+    lowcore->external_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
+    lowcore->external_old_psw.addr = cpu_to_be64(env->psw.addr);
+
+    cpu_unmap_lowcore(lowcore);
+
+    s390_cpu_set_psw(env, mask, addr);
+}
+
+static void do_io_interrupt(CPUS390XState *env)
+{
+    QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic());
+    uint64_t mask, addr;
+    QEMUS390FlicIO *io;
+    LowCore *lowcore;
+
+    g_assert(env->psw.mask & PSW_MASK_IO);
+    io = qemu_s390_flic_dequeue_io(flic, env->cregs[6]);
+    g_assert(io);
+
+    lowcore = cpu_map_lowcore(env);
+
+    lowcore->subchannel_id = cpu_to_be16(io->id);
+    lowcore->subchannel_nr = cpu_to_be16(io->nr);
+    lowcore->io_int_parm = cpu_to_be32(io->parm);
+    lowcore->io_int_word = cpu_to_be32(io->word);
+    lowcore->io_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
+    lowcore->io_old_psw.addr = cpu_to_be64(env->psw.addr);
+    mask = be64_to_cpu(lowcore->io_new_psw.mask);
+    addr = be64_to_cpu(lowcore->io_new_psw.addr);
+
+    cpu_unmap_lowcore(lowcore);
+    g_free(io);
+
+    s390_cpu_set_psw(env, mask, addr);
+}
+
+typedef struct MchkExtSaveArea {
+    uint64_t    vregs[32][2];                     /* 0x0000 */
+    uint8_t     pad_0x0200[0x0400 - 0x0200];      /* 0x0200 */
+} MchkExtSaveArea;
+QEMU_BUILD_BUG_ON(sizeof(MchkExtSaveArea) != 1024);
+
+static int mchk_store_vregs(CPUS390XState *env, uint64_t mcesao)
+{
+    hwaddr len = sizeof(MchkExtSaveArea);
+    MchkExtSaveArea *sa;
+    int i;
+
+    sa = cpu_physical_memory_map(mcesao, &len, true);
+    if (!sa) {
+        return -EFAULT;
+    }
+    if (len != sizeof(MchkExtSaveArea)) {
+        cpu_physical_memory_unmap(sa, len, 1, 0);
+        return -EFAULT;
+    }
+
+    for (i = 0; i < 32; i++) {
+        sa->vregs[i][0] = cpu_to_be64(env->vregs[i][0]);
+        sa->vregs[i][1] = cpu_to_be64(env->vregs[i][1]);
+    }
+
+    cpu_physical_memory_unmap(sa, len, 1, len);
+    return 0;
+}
+
+static void do_mchk_interrupt(CPUS390XState *env)
+{
+    QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic());
+    uint64_t mcic = s390_build_validity_mcic() | MCIC_SC_CP;
+    uint64_t mask, addr, mcesao = 0;
+    LowCore *lowcore;
+    int i;
+
+    /* for now we only support channel report machine checks (floating) */
+    g_assert(env->psw.mask & PSW_MASK_MCHECK);
+    g_assert(env->cregs[14] & CR14_CHANNEL_REPORT_SC);
+
+    qemu_s390_flic_dequeue_crw_mchk(flic);
+
+    lowcore = cpu_map_lowcore(env);
+
+    /* extended save area */
+    if (mcic & MCIC_VB_VR) {
+        /* length and alignment is 1024 bytes */
+        mcesao = be64_to_cpu(lowcore->mcesad) & ~0x3ffull;
+    }
+
+    /* try to store vector registers */
+    if (!mcesao || mchk_store_vregs(env, mcesao)) {
+        mcic &= ~MCIC_VB_VR;
+    }
+
+    /* we are always in z/Architecture mode */
+    lowcore->ar_access_id = 1;
+
+    for (i = 0; i < 16; i++) {
+        lowcore->floating_pt_save_area[i] = cpu_to_be64(*get_freg(env, i));
+        lowcore->gpregs_save_area[i] = cpu_to_be64(env->regs[i]);
+        lowcore->access_regs_save_area[i] = cpu_to_be32(env->aregs[i]);
+        lowcore->cregs_save_area[i] = cpu_to_be64(env->cregs[i]);
+    }
+    lowcore->prefixreg_save_area = cpu_to_be32(env->psa);
+    lowcore->fpt_creg_save_area = cpu_to_be32(env->fpc);
+    lowcore->tod_progreg_save_area = cpu_to_be32(env->todpr);
+    lowcore->cpu_timer_save_area = cpu_to_be64(env->cputm);
+    lowcore->clock_comp_save_area = cpu_to_be64(env->ckc >> 8);
+
+    lowcore->mcic = cpu_to_be64(mcic);
+    lowcore->mcck_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
+    lowcore->mcck_old_psw.addr = cpu_to_be64(env->psw.addr);
+    mask = be64_to_cpu(lowcore->mcck_new_psw.mask);
+    addr = be64_to_cpu(lowcore->mcck_new_psw.addr);
+
+    cpu_unmap_lowcore(lowcore);
+
+    s390_cpu_set_psw(env, mask, addr);
+}
+
+void s390_cpu_do_interrupt(CPUState *cs)
+{
+    QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic());
+    S390CPU *cpu = S390_CPU(cs);
+    CPUS390XState *env = &cpu->env;
+    bool stopped = false;
+
+    qemu_log_mask(CPU_LOG_INT, "%s: %d at psw=%" PRIx64 ":%" PRIx64 "\n",
+                  __func__, cs->exception_index, env->psw.mask, env->psw.addr);
+
+try_deliver:
+    /* handle machine checks */
+    if (cs->exception_index == -1 && s390_cpu_has_mcck_int(cpu)) {
+        cs->exception_index = EXCP_MCHK;
+    }
+    /* handle external interrupts */
+    if (cs->exception_index == -1 && s390_cpu_has_ext_int(cpu)) {
+        cs->exception_index = EXCP_EXT;
+    }
+    /* handle I/O interrupts */
+    if (cs->exception_index == -1 && s390_cpu_has_io_int(cpu)) {
+        cs->exception_index = EXCP_IO;
+    }
+    /* RESTART interrupt */
+    if (cs->exception_index == -1 && s390_cpu_has_restart_int(cpu)) {
+        cs->exception_index = EXCP_RESTART;
+    }
+    /* STOP interrupt has least priority */
+    if (cs->exception_index == -1 && s390_cpu_has_stop_int(cpu)) {
+        cs->exception_index = EXCP_STOP;
+    }
+
+    switch (cs->exception_index) {
+    case EXCP_PGM:
+        do_program_interrupt(env);
+        break;
+    case EXCP_SVC:
+        do_svc_interrupt(env);
+        break;
+    case EXCP_EXT:
+        do_ext_interrupt(env);
+        break;
+    case EXCP_IO:
+        do_io_interrupt(env);
+        break;
+    case EXCP_MCHK:
+        do_mchk_interrupt(env);
+        break;
+    case EXCP_RESTART:
+        do_restart_interrupt(env);
+        break;
+    case EXCP_STOP:
+        do_stop_interrupt(env);
+        stopped = true;
+        break;
+    }
+
+    if (cs->exception_index != -1 && !stopped) {
+        /* check if there are more pending interrupts to deliver */
+        cs->exception_index = -1;
+        goto try_deliver;
+    }
+    cs->exception_index = -1;
+
+    /* we might still have pending interrupts, but not deliverable */
+    if (!env->pending_int && !qemu_s390_flic_has_any(flic)) {
+        cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
+    }
+
+    /* WAIT PSW during interrupt injection or STOP interrupt */
+    if ((env->psw.mask & PSW_MASK_WAIT) || stopped) {
+        /* don't trigger a cpu_loop_exit(), use an interrupt instead */
+        cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HALT);
+    } else if (cs->halted) {
+        /* unhalt if we had a WAIT PSW somehwere in our injection chain */
+        s390_cpu_unhalt(cpu);
+    }
+}
+
+bool s390_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
+{
+    if (interrupt_request & CPU_INTERRUPT_HARD) {
+        S390CPU *cpu = S390_CPU(cs);
+        CPUS390XState *env = &cpu->env;
+
+        if (env->ex_value) {
+            /* Execution of the target insn is indivisible from
+               the parent EXECUTE insn.  */
+            return false;
+        }
+        if (s390_cpu_has_int(cpu)) {
+            s390_cpu_do_interrupt(cs);
+            return true;
+        }
+        if (env->psw.mask & PSW_MASK_WAIT) {
+            /* Woken up because of a floating interrupt but it has already
+             * been delivered. Go back to sleep. */
+            cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HALT);
+        }
+    }
+    return false;
+}
+
+void s390x_cpu_debug_excp_handler(CPUState *cs)
+{
+    S390CPU *cpu = S390_CPU(cs);
+    CPUS390XState *env = &cpu->env;
+    CPUWatchpoint *wp_hit = cs->watchpoint_hit;
+
+    if (wp_hit && wp_hit->flags & BP_CPU) {
+        /* FIXME: When the storage-alteration-space control bit is set,
+           the exception should only be triggered if the memory access
+           is done using an address space with the storage-alteration-event
+           bit set.  We have no way to detect that with the current
+           watchpoint code.  */
+        cs->watchpoint_hit = NULL;
+
+        env->per_address = env->psw.addr;
+        env->per_perc_atmid |= PER_CODE_EVENT_STORE | get_per_atmid(env);
+        /* FIXME: We currently no way to detect the address space used
+           to trigger the watchpoint.  For now just consider it is the
+           current default ASC. This turn to be true except when MVCP
+           and MVCS instrutions are not used.  */
+        env->per_perc_atmid |= env->psw.mask & (PSW_MASK_ASC) >> 46;
+
+        /*
+         * Remove all watchpoints to re-execute the code.  A PER exception
+         * will be triggered, it will call s390_cpu_set_psw which will
+         * recompute the watchpoints.
+         */
+        cpu_watchpoint_remove_all(cs, BP_CPU);
+        cpu_loop_exit_noexc(cs);
+    }
+}
+
+/* Unaligned accesses are only diagnosed with MO_ALIGN.  At the moment,
+   this is only for the atomic operations, for which we want to raise a
+   specification exception.  */
+void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
+                                   MMUAccessType access_type,
+                                   int mmu_idx, uintptr_t retaddr)
+{
+    S390CPU *cpu = S390_CPU(cs);
+    CPUS390XState *env = &cpu->env;
+
+    tcg_s390_program_interrupt(env, PGM_SPECIFICATION, retaddr);
+}
+
+static void QEMU_NORETURN monitor_event(CPUS390XState *env,
+                                        uint64_t monitor_code,
+                                        uint8_t monitor_class, uintptr_t ra)
+{
+    /* Store the Monitor Code and the Monitor Class Number into the lowcore */
+    stq_phys(env_cpu(env)->as,
+             env->psa + offsetof(LowCore, monitor_code), monitor_code);
+    stw_phys(env_cpu(env)->as,
+             env->psa + offsetof(LowCore, mon_class_num), monitor_class);
+
+    tcg_s390_program_interrupt(env, PGM_MONITOR, ra);
+}
+
+void HELPER(monitor_call)(CPUS390XState *env, uint64_t monitor_code,
+                          uint32_t monitor_class)
+{
+    g_assert(monitor_class <= 0xff);
+
+    if (env->cregs[8] & (0x8000 >> monitor_class)) {
+        monitor_event(env, monitor_code, monitor_class, GETPC());
+    }
+}
+
+#endif /* !CONFIG_USER_ONLY */
diff --git a/target/s390x/tcg/fpu_helper.c b/target/s390x/tcg/fpu_helper.c
new file mode 100644 (file)
index 0000000..4067205
--- /dev/null
@@ -0,0 +1,976 @@
+/*
+ *  S/390 FPU helper routines
+ *
+ *  Copyright (c) 2009 Ulrich Hecht
+ *  Copyright (c) 2009 Alexander Graf
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "s390x-internal.h"
+#include "tcg_s390x.h"
+#include "exec/exec-all.h"
+#include "exec/cpu_ldst.h"
+#include "exec/helper-proto.h"
+#include "fpu/softfloat.h"
+
+/* #define DEBUG_HELPER */
+#ifdef DEBUG_HELPER
+#define HELPER_LOG(x...) qemu_log(x)
+#else
+#define HELPER_LOG(x...)
+#endif
+
+#define RET128(F) (env->retxl = F.low, F.high)
+
+uint8_t s390_softfloat_exc_to_ieee(unsigned int exc)
+{
+    uint8_t s390_exc = 0;
+
+    s390_exc |= (exc & float_flag_invalid) ? S390_IEEE_MASK_INVALID : 0;
+    s390_exc |= (exc & float_flag_divbyzero) ? S390_IEEE_MASK_DIVBYZERO : 0;
+    s390_exc |= (exc & float_flag_overflow) ? S390_IEEE_MASK_OVERFLOW : 0;
+    s390_exc |= (exc & float_flag_underflow) ? S390_IEEE_MASK_UNDERFLOW : 0;
+    s390_exc |= (exc & float_flag_inexact) ? S390_IEEE_MASK_INEXACT : 0;
+
+    return s390_exc;
+}
+
+/* Should be called after any operation that may raise IEEE exceptions.  */
+static void handle_exceptions(CPUS390XState *env, bool XxC, uintptr_t retaddr)
+{
+    unsigned s390_exc, qemu_exc;
+
+    /* Get the exceptions raised by the current operation.  Reset the
+       fpu_status contents so that the next operation has a clean slate.  */
+    qemu_exc = env->fpu_status.float_exception_flags;
+    if (qemu_exc == 0) {
+        return;
+    }
+    env->fpu_status.float_exception_flags = 0;
+    s390_exc = s390_softfloat_exc_to_ieee(qemu_exc);
+
+    /*
+     * IEEE-Underflow exception recognition exists if a tininess condition
+     * (underflow) exists and
+     * - The mask bit in the FPC is zero and the result is inexact
+     * - The mask bit in the FPC is one
+     * So tininess conditions that are not inexact don't trigger any
+     * underflow action in case the mask bit is not one.
+     */
+    if (!(s390_exc & S390_IEEE_MASK_INEXACT) &&
+        !((env->fpc >> 24) & S390_IEEE_MASK_UNDERFLOW)) {
+        s390_exc &= ~S390_IEEE_MASK_UNDERFLOW;
+    }
+
+    /*
+     * FIXME:
+     * 1. Right now, all inexact conditions are inidicated as
+     *    "truncated" (0) and never as "incremented" (1) in the DXC.
+     * 2. Only traps due to invalid/divbyzero are suppressing. Other traps
+     *    are completing, meaning the target register has to be written!
+     *    This, however will mean that we have to write the register before
+     *    triggering the trap - impossible right now.
+     */
+
+    /*
+     * invalid/divbyzero cannot coexist with other conditions.
+     * overflow/underflow however can coexist with inexact, we have to
+     * handle it separatly.
+     */
+    if (s390_exc & ~S390_IEEE_MASK_INEXACT) {
+        if (s390_exc & ~S390_IEEE_MASK_INEXACT & env->fpc >> 24) {
+            /* trap condition - inexact reported along */
+            tcg_s390_data_exception(env, s390_exc, retaddr);
+        }
+        /* nontrap condition - inexact handled differently */
+        env->fpc |= (s390_exc & ~S390_IEEE_MASK_INEXACT) << 16;
+    }
+
+    /* inexact handling */
+    if (s390_exc & S390_IEEE_MASK_INEXACT && !XxC) {
+        /* trap condition - overflow/underflow _not_ reported along */
+        if (s390_exc & S390_IEEE_MASK_INEXACT & env->fpc >> 24) {
+            tcg_s390_data_exception(env, s390_exc & S390_IEEE_MASK_INEXACT,
+                                    retaddr);
+        }
+        /* nontrap condition */
+        env->fpc |= (s390_exc & S390_IEEE_MASK_INEXACT) << 16;
+    }
+}
+
+int float_comp_to_cc(CPUS390XState *env, FloatRelation float_compare)
+{
+    switch (float_compare) {
+    case float_relation_equal:
+        return 0;
+    case float_relation_less:
+        return 1;
+    case float_relation_greater:
+        return 2;
+    case float_relation_unordered:
+        return 3;
+    default:
+        cpu_abort(env_cpu(env), "unknown return value for float compare\n");
+    }
+}
+
+/* condition codes for unary FP ops */
+uint32_t set_cc_nz_f32(float32 v)
+{
+    if (float32_is_any_nan(v)) {
+        return 3;
+    } else if (float32_is_zero(v)) {
+        return 0;
+    } else if (float32_is_neg(v)) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+
+uint32_t set_cc_nz_f64(float64 v)
+{
+    if (float64_is_any_nan(v)) {
+        return 3;
+    } else if (float64_is_zero(v)) {
+        return 0;
+    } else if (float64_is_neg(v)) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+
+uint32_t set_cc_nz_f128(float128 v)
+{
+    if (float128_is_any_nan(v)) {
+        return 3;
+    } else if (float128_is_zero(v)) {
+        return 0;
+    } else if (float128_is_neg(v)) {
+        return 1;
+    } else {
+        return 2;
+    }
+}
+
+/* condition codes for FP to integer conversion ops */
+static uint32_t set_cc_conv_f32(float32 v, float_status *stat)
+{
+    if (stat->float_exception_flags & float_flag_invalid) {
+        return 3;
+    } else {
+        return set_cc_nz_f32(v);
+    }
+}
+
+static uint32_t set_cc_conv_f64(float64 v, float_status *stat)
+{
+    if (stat->float_exception_flags & float_flag_invalid) {
+        return 3;
+    } else {
+        return set_cc_nz_f64(v);
+    }
+}
+
+static uint32_t set_cc_conv_f128(float128 v, float_status *stat)
+{
+    if (stat->float_exception_flags & float_flag_invalid) {
+        return 3;
+    } else {
+        return set_cc_nz_f128(v);
+    }
+}
+
+static inline uint8_t round_from_m34(uint32_t m34)
+{
+    return extract32(m34, 0, 4);
+}
+
+static inline bool xxc_from_m34(uint32_t m34)
+{
+    /* XxC is bit 1 of m4 */
+    return extract32(m34, 4 + 3 - 1, 1);
+}
+
+/* 32-bit FP addition */
+uint64_t HELPER(aeb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
+{
+    float32 ret = float32_add(f1, f2, &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return ret;
+}
+
+/* 64-bit FP addition */
+uint64_t HELPER(adb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
+{
+    float64 ret = float64_add(f1, f2, &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return ret;
+}
+
+/* 128-bit FP addition */
+uint64_t HELPER(axb)(CPUS390XState *env, uint64_t ah, uint64_t al,
+                     uint64_t bh, uint64_t bl)
+{
+    float128 ret = float128_add(make_float128(ah, al),
+                                make_float128(bh, bl),
+                                &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return RET128(ret);
+}
+
+/* 32-bit FP subtraction */
+uint64_t HELPER(seb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
+{
+    float32 ret = float32_sub(f1, f2, &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return ret;
+}
+
+/* 64-bit FP subtraction */
+uint64_t HELPER(sdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
+{
+    float64 ret = float64_sub(f1, f2, &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return ret;
+}
+
+/* 128-bit FP subtraction */
+uint64_t HELPER(sxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
+                     uint64_t bh, uint64_t bl)
+{
+    float128 ret = float128_sub(make_float128(ah, al),
+                                make_float128(bh, bl),
+                                &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return RET128(ret);
+}
+
+/* 32-bit FP division */
+uint64_t HELPER(deb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
+{
+    float32 ret = float32_div(f1, f2, &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return ret;
+}
+
+/* 64-bit FP division */
+uint64_t HELPER(ddb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
+{
+    float64 ret = float64_div(f1, f2, &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return ret;
+}
+
+/* 128-bit FP division */
+uint64_t HELPER(dxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
+                     uint64_t bh, uint64_t bl)
+{
+    float128 ret = float128_div(make_float128(ah, al),
+                                make_float128(bh, bl),
+                                &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return RET128(ret);
+}
+
+/* 32-bit FP multiplication */
+uint64_t HELPER(meeb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
+{
+    float32 ret = float32_mul(f1, f2, &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return ret;
+}
+
+/* 64-bit FP multiplication */
+uint64_t HELPER(mdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
+{
+    float64 ret = float64_mul(f1, f2, &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return ret;
+}
+
+/* 64/32-bit FP multiplication */
+uint64_t HELPER(mdeb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
+{
+    float64 ret = float32_to_float64(f2, &env->fpu_status);
+    ret = float64_mul(f1, ret, &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return ret;
+}
+
+/* 128-bit FP multiplication */
+uint64_t HELPER(mxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
+                     uint64_t bh, uint64_t bl)
+{
+    float128 ret = float128_mul(make_float128(ah, al),
+                                make_float128(bh, bl),
+                                &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return RET128(ret);
+}
+
+/* 128/64-bit FP multiplication */
+uint64_t HELPER(mxdb)(CPUS390XState *env, uint64_t ah, uint64_t al,
+                      uint64_t f2)
+{
+    float128 ret = float64_to_float128(f2, &env->fpu_status);
+    ret = float128_mul(make_float128(ah, al), ret, &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return RET128(ret);
+}
+
+/* convert 32-bit float to 64-bit float */
+uint64_t HELPER(ldeb)(CPUS390XState *env, uint64_t f2)
+{
+    float64 ret = float32_to_float64(f2, &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return ret;
+}
+
+/* convert 128-bit float to 64-bit float */
+uint64_t HELPER(ldxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
+                      uint32_t m34)
+{
+    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
+    float64 ret = float128_to_float64(make_float128(ah, al), &env->fpu_status);
+
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_exceptions(env, xxc_from_m34(m34), GETPC());
+    return ret;
+}
+
+/* convert 64-bit float to 128-bit float */
+uint64_t HELPER(lxdb)(CPUS390XState *env, uint64_t f2)
+{
+    float128 ret = float64_to_float128(f2, &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return RET128(ret);
+}
+
+/* convert 32-bit float to 128-bit float */
+uint64_t HELPER(lxeb)(CPUS390XState *env, uint64_t f2)
+{
+    float128 ret = float32_to_float128(f2, &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return RET128(ret);
+}
+
+/* convert 64-bit float to 32-bit float */
+uint64_t HELPER(ledb)(CPUS390XState *env, uint64_t f2, uint32_t m34)
+{
+    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
+    float32 ret = float64_to_float32(f2, &env->fpu_status);
+
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_exceptions(env, xxc_from_m34(m34), GETPC());
+    return ret;
+}
+
+/* convert 128-bit float to 32-bit float */
+uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al,
+                      uint32_t m34)
+{
+    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
+    float32 ret = float128_to_float32(make_float128(ah, al), &env->fpu_status);
+
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_exceptions(env, xxc_from_m34(m34), GETPC());
+    return ret;
+}
+
+/* 32-bit FP compare */
+uint32_t HELPER(ceb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
+{
+    FloatRelation cmp = float32_compare_quiet(f1, f2, &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return float_comp_to_cc(env, cmp);
+}
+
+/* 64-bit FP compare */
+uint32_t HELPER(cdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
+{
+    FloatRelation cmp = float64_compare_quiet(f1, f2, &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return float_comp_to_cc(env, cmp);
+}
+
+/* 128-bit FP compare */
+uint32_t HELPER(cxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
+                     uint64_t bh, uint64_t bl)
+{
+    FloatRelation cmp = float128_compare_quiet(make_float128(ah, al),
+                                               make_float128(bh, bl),
+                                               &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return float_comp_to_cc(env, cmp);
+}
+
+int s390_swap_bfp_rounding_mode(CPUS390XState *env, int m3)
+{
+    int ret = env->fpu_status.float_rounding_mode;
+
+    switch (m3) {
+    case 0:
+        /* current mode */
+        break;
+    case 1:
+        /* round to nearest with ties away from 0 */
+        set_float_rounding_mode(float_round_ties_away, &env->fpu_status);
+        break;
+    case 3:
+        /* round to prepare for shorter precision */
+        set_float_rounding_mode(float_round_to_odd, &env->fpu_status);
+        break;
+    case 4:
+        /* round to nearest with ties to even */
+        set_float_rounding_mode(float_round_nearest_even, &env->fpu_status);
+        break;
+    case 5:
+        /* round to zero */
+        set_float_rounding_mode(float_round_to_zero, &env->fpu_status);
+        break;
+    case 6:
+        /* round to +inf */
+        set_float_rounding_mode(float_round_up, &env->fpu_status);
+        break;
+    case 7:
+        /* round to -inf */
+        set_float_rounding_mode(float_round_down, &env->fpu_status);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+    return ret;
+}
+
+void s390_restore_bfp_rounding_mode(CPUS390XState *env, int old_mode)
+{
+    set_float_rounding_mode(old_mode, &env->fpu_status);
+}
+
+/* convert 64-bit int to 32-bit float */
+uint64_t HELPER(cegb)(CPUS390XState *env, int64_t v2, uint32_t m34)
+{
+    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
+    float32 ret = int64_to_float32(v2, &env->fpu_status);
+
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_exceptions(env, xxc_from_m34(m34), GETPC());
+    return ret;
+}
+
+/* convert 64-bit int to 64-bit float */
+uint64_t HELPER(cdgb)(CPUS390XState *env, int64_t v2, uint32_t m34)
+{
+    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
+    float64 ret = int64_to_float64(v2, &env->fpu_status);
+
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_exceptions(env, xxc_from_m34(m34), GETPC());
+    return ret;
+}
+
+/* convert 64-bit int to 128-bit float */
+uint64_t HELPER(cxgb)(CPUS390XState *env, int64_t v2, uint32_t m34)
+{
+    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
+    float128 ret = int64_to_float128(v2, &env->fpu_status);
+
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_exceptions(env, xxc_from_m34(m34), GETPC());
+    return RET128(ret);
+}
+
+/* convert 64-bit uint to 32-bit float */
+uint64_t HELPER(celgb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
+{
+    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
+    float32 ret = uint64_to_float32(v2, &env->fpu_status);
+
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_exceptions(env, xxc_from_m34(m34), GETPC());
+    return ret;
+}
+
+/* convert 64-bit uint to 64-bit float */
+uint64_t HELPER(cdlgb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
+{
+    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
+    float64 ret = uint64_to_float64(v2, &env->fpu_status);
+
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_exceptions(env, xxc_from_m34(m34), GETPC());
+    return ret;
+}
+
+/* convert 64-bit uint to 128-bit float */
+uint64_t HELPER(cxlgb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
+{
+    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
+    float128 ret = uint64_to_float128(v2, &env->fpu_status);
+
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_exceptions(env, xxc_from_m34(m34), GETPC());
+    return RET128(ret);
+}
+
+/* convert 32-bit float to 64-bit int */
+uint64_t HELPER(cgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
+{
+    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
+    int64_t ret = float32_to_int64(v2, &env->fpu_status);
+    uint32_t cc = set_cc_conv_f32(v2, &env->fpu_status);
+
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_exceptions(env, xxc_from_m34(m34), GETPC());
+    env->cc_op = cc;
+    if (float32_is_any_nan(v2)) {
+        return INT64_MIN;
+    }
+    return ret;
+}
+
+/* convert 64-bit float to 64-bit int */
+uint64_t HELPER(cgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
+{
+    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
+    int64_t ret = float64_to_int64(v2, &env->fpu_status);
+    uint32_t cc = set_cc_conv_f64(v2, &env->fpu_status);
+
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_exceptions(env, xxc_from_m34(m34), GETPC());
+    env->cc_op = cc;
+    if (float64_is_any_nan(v2)) {
+        return INT64_MIN;
+    }
+    return ret;
+}
+
+/* convert 128-bit float to 64-bit int */
+uint64_t HELPER(cgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
+{
+    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
+    float128 v2 = make_float128(h, l);
+    int64_t ret = float128_to_int64(v2, &env->fpu_status);
+    uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status);
+
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_exceptions(env, xxc_from_m34(m34), GETPC());
+    env->cc_op = cc;
+    if (float128_is_any_nan(v2)) {
+        return INT64_MIN;
+    }
+    return ret;
+}
+
+/* convert 32-bit float to 32-bit int */
+uint64_t HELPER(cfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
+{
+    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
+    int32_t ret = float32_to_int32(v2, &env->fpu_status);
+    uint32_t cc = set_cc_conv_f32(v2, &env->fpu_status);
+
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_exceptions(env, xxc_from_m34(m34), GETPC());
+    env->cc_op = cc;
+    if (float32_is_any_nan(v2)) {
+        return INT32_MIN;
+    }
+    return ret;
+}
+
+/* convert 64-bit float to 32-bit int */
+uint64_t HELPER(cfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
+{
+    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
+    int32_t ret = float64_to_int32(v2, &env->fpu_status);
+    uint32_t cc = set_cc_conv_f64(v2, &env->fpu_status);
+
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_exceptions(env, xxc_from_m34(m34), GETPC());
+    env->cc_op = cc;
+    if (float64_is_any_nan(v2)) {
+        return INT32_MIN;
+    }
+    return ret;
+}
+
+/* convert 128-bit float to 32-bit int */
+uint64_t HELPER(cfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
+{
+    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
+    float128 v2 = make_float128(h, l);
+    int32_t ret = float128_to_int32(v2, &env->fpu_status);
+    uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status);
+
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_exceptions(env, xxc_from_m34(m34), GETPC());
+    env->cc_op = cc;
+    if (float128_is_any_nan(v2)) {
+        return INT32_MIN;
+    }
+    return ret;
+}
+
+/* convert 32-bit float to 64-bit uint */
+uint64_t HELPER(clgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
+{
+    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
+    uint64_t ret = float32_to_uint64(v2, &env->fpu_status);
+    uint32_t cc = set_cc_conv_f32(v2, &env->fpu_status);
+
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_exceptions(env, xxc_from_m34(m34), GETPC());
+    env->cc_op = cc;
+    if (float32_is_any_nan(v2)) {
+        return 0;
+    }
+    return ret;
+}
+
+/* convert 64-bit float to 64-bit uint */
+uint64_t HELPER(clgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
+{
+    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
+    uint64_t ret = float64_to_uint64(v2, &env->fpu_status);
+    uint32_t cc = set_cc_conv_f64(v2, &env->fpu_status);
+
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_exceptions(env, xxc_from_m34(m34), GETPC());
+    env->cc_op = cc;
+    if (float64_is_any_nan(v2)) {
+        return 0;
+    }
+    return ret;
+}
+
+/* convert 128-bit float to 64-bit uint */
+uint64_t HELPER(clgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
+{
+    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
+    float128 v2 = make_float128(h, l);
+    uint64_t ret = float128_to_uint64(v2, &env->fpu_status);
+    uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status);
+
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_exceptions(env, xxc_from_m34(m34), GETPC());
+    env->cc_op = cc;
+    if (float128_is_any_nan(v2)) {
+        return 0;
+    }
+    return ret;
+}
+
+/* convert 32-bit float to 32-bit uint */
+uint64_t HELPER(clfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
+{
+    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
+    uint32_t ret = float32_to_uint32(v2, &env->fpu_status);
+    uint32_t cc = set_cc_conv_f32(v2, &env->fpu_status);
+
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_exceptions(env, xxc_from_m34(m34), GETPC());
+    env->cc_op = cc;
+    if (float32_is_any_nan(v2)) {
+        return 0;
+    }
+    return ret;
+}
+
+/* convert 64-bit float to 32-bit uint */
+uint64_t HELPER(clfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
+{
+    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
+    uint32_t ret = float64_to_uint32(v2, &env->fpu_status);
+    uint32_t cc = set_cc_conv_f64(v2, &env->fpu_status);
+
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_exceptions(env, xxc_from_m34(m34), GETPC());
+    env->cc_op = cc;
+    if (float64_is_any_nan(v2)) {
+        return 0;
+    }
+    return ret;
+}
+
+/* convert 128-bit float to 32-bit uint */
+uint64_t HELPER(clfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
+{
+    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
+    float128 v2 = make_float128(h, l);
+    uint32_t ret = float128_to_uint32(v2, &env->fpu_status);
+    uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status);
+
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_exceptions(env, xxc_from_m34(m34), GETPC());
+    env->cc_op = cc;
+    if (float128_is_any_nan(v2)) {
+        return 0;
+    }
+    return ret;
+}
+
+/* round to integer 32-bit */
+uint64_t HELPER(fieb)(CPUS390XState *env, uint64_t f2, uint32_t m34)
+{
+    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
+    float32 ret = float32_round_to_int(f2, &env->fpu_status);
+
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_exceptions(env, xxc_from_m34(m34), GETPC());
+    return ret;
+}
+
+/* round to integer 64-bit */
+uint64_t HELPER(fidb)(CPUS390XState *env, uint64_t f2, uint32_t m34)
+{
+    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
+    float64 ret = float64_round_to_int(f2, &env->fpu_status);
+
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_exceptions(env, xxc_from_m34(m34), GETPC());
+    return ret;
+}
+
+/* round to integer 128-bit */
+uint64_t HELPER(fixb)(CPUS390XState *env, uint64_t ah, uint64_t al,
+                      uint32_t m34)
+{
+    int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
+    float128 ret = float128_round_to_int(make_float128(ah, al),
+                                         &env->fpu_status);
+
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_exceptions(env, xxc_from_m34(m34), GETPC());
+    return RET128(ret);
+}
+
+/* 32-bit FP compare and signal */
+uint32_t HELPER(keb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
+{
+    FloatRelation cmp = float32_compare(f1, f2, &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return float_comp_to_cc(env, cmp);
+}
+
+/* 64-bit FP compare and signal */
+uint32_t HELPER(kdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
+{
+    FloatRelation cmp = float64_compare(f1, f2, &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return float_comp_to_cc(env, cmp);
+}
+
+/* 128-bit FP compare and signal */
+uint32_t HELPER(kxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
+                     uint64_t bh, uint64_t bl)
+{
+    FloatRelation cmp = float128_compare(make_float128(ah, al),
+                                         make_float128(bh, bl),
+                                         &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return float_comp_to_cc(env, cmp);
+}
+
+/* 32-bit FP multiply and add */
+uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1,
+                      uint64_t f2, uint64_t f3)
+{
+    float32 ret = float32_muladd(f2, f3, f1, 0, &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return ret;
+}
+
+/* 64-bit FP multiply and add */
+uint64_t HELPER(madb)(CPUS390XState *env, uint64_t f1,
+                      uint64_t f2, uint64_t f3)
+{
+    float64 ret = float64_muladd(f2, f3, f1, 0, &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return ret;
+}
+
+/* 32-bit FP multiply and subtract */
+uint64_t HELPER(mseb)(CPUS390XState *env, uint64_t f1,
+                      uint64_t f2, uint64_t f3)
+{
+    float32 ret = float32_muladd(f2, f3, f1, float_muladd_negate_c,
+                                 &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return ret;
+}
+
+/* 64-bit FP multiply and subtract */
+uint64_t HELPER(msdb)(CPUS390XState *env, uint64_t f1,
+                      uint64_t f2, uint64_t f3)
+{
+    float64 ret = float64_muladd(f2, f3, f1, float_muladd_negate_c,
+                                 &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return ret;
+}
+
+/* The rightmost bit has the number 11. */
+static inline uint16_t dcmask(int bit, bool neg)
+{
+    return 1 << (11 - bit - neg);
+}
+
+#define DEF_FLOAT_DCMASK(_TYPE) \
+uint16_t _TYPE##_dcmask(CPUS390XState *env, _TYPE f1)              \
+{                                                                  \
+    const bool neg = _TYPE##_is_neg(f1);                           \
+                                                                   \
+    /* Sorted by most common cases - only one class is possible */ \
+    if (_TYPE##_is_normal(f1)) {                                   \
+        return dcmask(2, neg);                                     \
+    } else if (_TYPE##_is_zero(f1)) {                              \
+        return dcmask(0, neg);                                     \
+    } else if (_TYPE##_is_denormal(f1)) {                          \
+        return dcmask(4, neg);                                     \
+    } else if (_TYPE##_is_infinity(f1)) {                          \
+        return dcmask(6, neg);                                     \
+    } else if (_TYPE##_is_quiet_nan(f1, &env->fpu_status)) {       \
+        return dcmask(8, neg);                                     \
+    }                                                              \
+    /* signaling nan, as last remaining case */                    \
+    return dcmask(10, neg);                                        \
+}
+DEF_FLOAT_DCMASK(float32)
+DEF_FLOAT_DCMASK(float64)
+DEF_FLOAT_DCMASK(float128)
+
+/* test data class 32-bit */
+uint32_t HELPER(tceb)(CPUS390XState *env, uint64_t f1, uint64_t m2)
+{
+    return (m2 & float32_dcmask(env, f1)) != 0;
+}
+
+/* test data class 64-bit */
+uint32_t HELPER(tcdb)(CPUS390XState *env, uint64_t v1, uint64_t m2)
+{
+    return (m2 & float64_dcmask(env, v1)) != 0;
+}
+
+/* test data class 128-bit */
+uint32_t HELPER(tcxb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t m2)
+{
+    return (m2 & float128_dcmask(env, make_float128(ah, al))) != 0;
+}
+
+/* square root 32-bit */
+uint64_t HELPER(sqeb)(CPUS390XState *env, uint64_t f2)
+{
+    float32 ret = float32_sqrt(f2, &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return ret;
+}
+
+/* square root 64-bit */
+uint64_t HELPER(sqdb)(CPUS390XState *env, uint64_t f2)
+{
+    float64 ret = float64_sqrt(f2, &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return ret;
+}
+
+/* square root 128-bit */
+uint64_t HELPER(sqxb)(CPUS390XState *env, uint64_t ah, uint64_t al)
+{
+    float128 ret = float128_sqrt(make_float128(ah, al), &env->fpu_status);
+    handle_exceptions(env, false, GETPC());
+    return RET128(ret);
+}
+
+static const int fpc_to_rnd[8] = {
+    float_round_nearest_even,
+    float_round_to_zero,
+    float_round_up,
+    float_round_down,
+    -1,
+    -1,
+    -1,
+    float_round_to_odd,
+};
+
+/* set fpc */
+void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc)
+{
+    if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u ||
+        (!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) {
+        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
+    }
+
+    /* Install everything in the main FPC.  */
+    env->fpc = fpc;
+
+    /* Install the rounding mode in the shadow fpu_status.  */
+    set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status);
+}
+
+/* set fpc and signal */
+void HELPER(sfas)(CPUS390XState *env, uint64_t fpc)
+{
+    uint32_t signalling = env->fpc;
+    uint32_t s390_exc;
+
+    if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u ||
+        (!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) {
+        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
+    }
+
+    /*
+     * FPC is set to the FPC operand with a bitwise OR of the signalling
+     * flags.
+     */
+    env->fpc = fpc | (signalling & 0x00ff0000);
+    set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status);
+
+    /*
+     * If any signaling flag is enabled in the new FPC mask, a
+     * simulated-iee-exception exception occurs.
+     */
+    s390_exc = (signalling >> 16) & (fpc >> 24);
+    if (s390_exc) {
+        if (s390_exc & S390_IEEE_MASK_INVALID) {
+            s390_exc = S390_IEEE_MASK_INVALID;
+        } else if (s390_exc & S390_IEEE_MASK_DIVBYZERO) {
+            s390_exc = S390_IEEE_MASK_DIVBYZERO;
+        } else if (s390_exc & S390_IEEE_MASK_OVERFLOW) {
+            s390_exc &= (S390_IEEE_MASK_OVERFLOW | S390_IEEE_MASK_INEXACT);
+        } else if (s390_exc & S390_IEEE_MASK_UNDERFLOW) {
+            s390_exc &= (S390_IEEE_MASK_UNDERFLOW | S390_IEEE_MASK_INEXACT);
+        } else if (s390_exc & S390_IEEE_MASK_INEXACT) {
+            s390_exc = S390_IEEE_MASK_INEXACT;
+        } else if (s390_exc & S390_IEEE_MASK_QUANTUM) {
+            s390_exc = S390_IEEE_MASK_QUANTUM;
+        }
+        tcg_s390_data_exception(env, s390_exc | 3, GETPC());
+    }
+}
+
+/* set bfp rounding mode */
+void HELPER(srnm)(CPUS390XState *env, uint64_t rnd)
+{
+    if (rnd > 0x7 || fpc_to_rnd[rnd & 0x7] == -1) {
+        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
+    }
+
+    env->fpc = deposit32(env->fpc, 0, 3, rnd);
+    set_float_rounding_mode(fpc_to_rnd[rnd & 0x7], &env->fpu_status);
+}
diff --git a/target/s390x/tcg/insn-data.def b/target/s390x/tcg/insn-data.def
new file mode 100644 (file)
index 0000000..3e55942
--- /dev/null
@@ -0,0 +1,1398 @@
+/*
+ *  Arguments to the opcode prototypes
+ *
+ *  C(OPC,    NAME,    FMT,   FAC, I1, I2, P, W, OP, CC)
+ *  D(OPC,    NAME,    FMT,   FAC, I1, I2, P, W, OP, CC, DATA)
+ *  E(OPC,    NAME,    FMT,   FAC, I1, I2, P, W, OP, CC, DATA, FLAGS)
+ *  F(OPC,    NAME,    FMT,   FAC, I1, I2, P, W, OP, CC, FLAGS)
+ *
+ *  OPC  = (op << 8) | op2 where op is the major, op2 the minor opcode
+ *  NAME = name of the opcode, used internally
+ *  FMT  = format of the opcode (defined in insn-format.def)
+ *  FAC  = facility the opcode is available in (defined in DisasFacility)
+ *  I1   = func in1_xx fills o->in1
+ *  I2   = func in2_xx fills o->in2
+ *  P    = func prep_xx initializes o->*out*
+ *  W    = func wout_xx writes o->*out* somewhere
+ *  OP   = func op_xx does the bulk of the operation
+ *  CC   = func cout_xx defines how cc should get set
+ *  DATA = immediate argument to op_xx function
+ *  FLAGS = categorize the type of instruction (e.g. for advanced checks)
+ *
+ *  The helpers get called in order: I1, I2, P, OP, W, CC
+ */
+
+/* ADD */
+    C(0x1a00, AR,      RR_a,  Z,   r1, r2, new, r1_32, add, adds32)
+    C(0xb9f8, ARK,     RRF_a, DO,  r2, r3, new, r1_32, add, adds32)
+    C(0x5a00, A,       RX_a,  Z,   r1, m2_32s, new, r1_32, add, adds32)
+    C(0xe35a, AY,      RXY_a, LD,  r1, m2_32s, new, r1_32, add, adds32)
+    C(0xb908, AGR,     RRE,   Z,   r1, r2, r1, 0, add, adds64)
+    C(0xb918, AGFR,    RRE,   Z,   r1, r2_32s, r1, 0, add, adds64)
+    C(0xb9e8, AGRK,    RRF_a, DO,  r2, r3, r1, 0, add, adds64)
+    C(0xe308, AG,      RXY_a, Z,   r1, m2_64, r1, 0, add, adds64)
+    C(0xe318, AGF,     RXY_a, Z,   r1, m2_32s, r1, 0, add, adds64)
+    F(0xb30a, AEBR,    RRE,   Z,   e1, e2, new, e1, aeb, f32, IF_BFP)
+    F(0xb31a, ADBR,    RRE,   Z,   f1, f2, new, f1, adb, f64, IF_BFP)
+    F(0xb34a, AXBR,    RRE,   Z,   x2h, x2l, x1, x1, axb, f128, IF_BFP)
+    F(0xed0a, AEB,     RXE,   Z,   e1, m2_32u, new, e1, aeb, f32, IF_BFP)
+    F(0xed1a, ADB,     RXE,   Z,   f1, m2_64, new, f1, adb, f64, IF_BFP)
+/* ADD HIGH */
+    C(0xb9c8, AHHHR,   RRF_a, HW,  r2_sr32, r3_sr32, new, r1_32h, add, adds32)
+    C(0xb9d8, AHHLR,   RRF_a, HW,  r2_sr32, r3, new, r1_32h, add, adds32)
+/* ADD IMMEDIATE */
+    C(0xc209, AFI,     RIL_a, EI,  r1, i2, new, r1_32, add, adds32)
+    D(0xeb6a, ASI,     SIY,   GIE, la1, i2, new, 0, asi, adds32, MO_TESL)
+    C(0xecd8, AHIK,    RIE_d, DO,  r3, i2, new, r1_32, add, adds32)
+    C(0xc208, AGFI,    RIL_a, EI,  r1, i2, r1, 0, add, adds64)
+    D(0xeb7a, AGSI,    SIY,   GIE, la1, i2, new, 0, asi, adds64, MO_TEQ)
+    C(0xecd9, AGHIK,   RIE_d, DO,  r3, i2, r1, 0, add, adds64)
+/* ADD IMMEDIATE HIGH */
+    C(0xcc08, AIH,     RIL_a, HW,  r1_sr32, i2, new, r1_32h, add, adds32)
+/* ADD HALFWORD */
+    C(0x4a00, AH,      RX_a,  Z,   r1, m2_16s, new, r1_32, add, adds32)
+    C(0xe37a, AHY,     RXY_a, LD,  r1, m2_16s, new, r1_32, add, adds32)
+    C(0xe338, AGH,     RXY_a, MIE2,r1, m2_16s, r1, 0, add, adds64)
+/* ADD HALFWORD IMMEDIATE */
+    C(0xa70a, AHI,     RI_a,  Z,   r1, i2, new, r1_32, add, adds32)
+    C(0xa70b, AGHI,    RI_a,  Z,   r1, i2, r1, 0, add, adds64)
+
+/* ADD LOGICAL */
+    C(0x1e00, ALR,     RR_a,  Z,   r1_32u, r2_32u, new, r1_32, add, addu32)
+    C(0xb9fa, ALRK,    RRF_a, DO,  r2_32u, r3_32u, new, r1_32, add, addu32)
+    C(0x5e00, AL,      RX_a,  Z,   r1_32u, m2_32u, new, r1_32, add, addu32)
+    C(0xe35e, ALY,     RXY_a, LD,  r1_32u, m2_32u, new, r1_32, add, addu32)
+    C(0xb90a, ALGR,    RRE,   Z,   r1, r2, r1, 0, addu64, addu64)
+    C(0xb91a, ALGFR,   RRE,   Z,   r1, r2_32u, r1, 0, addu64, addu64)
+    C(0xb9ea, ALGRK,   RRF_a, DO,  r2, r3, r1, 0, addu64, addu64)
+    C(0xe30a, ALG,     RXY_a, Z,   r1, m2_64, r1, 0, addu64, addu64)
+    C(0xe31a, ALGF,    RXY_a, Z,   r1, m2_32u, r1, 0, addu64, addu64)
+/* ADD LOGICAL HIGH */
+    C(0xb9ca, ALHHHR,  RRF_a, HW,  r2_sr32, r3_sr32, new, r1_32h, add, addu32)
+    C(0xb9da, ALHHLR,  RRF_a, HW,  r2_sr32, r3_32u, new, r1_32h, add, addu32)
+/* ADD LOGICAL IMMEDIATE */
+    C(0xc20b, ALFI,    RIL_a, EI,  r1_32u, i2_32u, new, r1_32, add, addu32)
+    C(0xc20a, ALGFI,   RIL_a, EI,  r1, i2_32u, r1, 0, addu64, addu64)
+/* ADD LOGICAL WITH SIGNED IMMEDIATE */
+    D(0xeb6e, ALSI,    SIY,   GIE, la1, i2_32u, new, 0, asi, addu32, MO_TEUL)
+    C(0xecda, ALHSIK,  RIE_d, DO,  r3_32u, i2_32u, new, r1_32, add, addu32)
+    D(0xeb7e, ALGSI,   SIY,   GIE, la1, i2, new, 0, asiu64, addu64, MO_TEQ)
+    C(0xecdb, ALGHSIK, RIE_d, DO,  r3, i2, r1, 0, addu64, addu64)
+/* ADD LOGICAL WITH SIGNED IMMEDIATE HIGH */
+    C(0xcc0a, ALSIH,   RIL_a, HW,  r1_sr32, i2_32u, new, r1_32h, add, addu32)
+    C(0xcc0b, ALSIHN,  RIL_a, HW,  r1_sr32, i2_32u, new, r1_32h, add, 0)
+/* ADD LOGICAL WITH CARRY */
+    C(0xb998, ALCR,    RRE,   Z,   r1_32u, r2_32u, new, r1_32, addc32, addu32)
+    C(0xb988, ALCGR,   RRE,   Z,   r1, r2, r1, 0, addc64, addu64)
+    C(0xe398, ALC,     RXY_a, Z,   r1_32u, m2_32u, new, r1_32, addc32, addu32)
+    C(0xe388, ALCG,    RXY_a, Z,   r1, m2_64, r1, 0, addc64, addu64)
+
+/* AND */
+    C(0x1400, NR,      RR_a,  Z,   r1, r2, new, r1_32, and, nz32)
+    C(0xb9f4, NRK,     RRF_a, DO,  r2, r3, new, r1_32, and, nz32)
+    C(0x5400, N,       RX_a,  Z,   r1, m2_32s, new, r1_32, and, nz32)
+    C(0xe354, NY,      RXY_a, LD,  r1, m2_32s, new, r1_32, and, nz32)
+    C(0xb980, NGR,     RRE,   Z,   r1, r2, r1, 0, and, nz64)
+    C(0xb9e4, NGRK,    RRF_a, DO,  r2, r3, r1, 0, and, nz64)
+    C(0xe380, NG,      RXY_a, Z,   r1, m2_64, r1, 0, and, nz64)
+    C(0xd400, NC,      SS_a,  Z,   la1, a2, 0, 0, nc, 0)
+/* AND IMMEDIATE */
+    D(0xc00a, NIHF,    RIL_a, EI,  r1_o, i2_32u, r1, 0, andi, 0, 0x2020)
+    D(0xc00b, NILF,    RIL_a, EI,  r1_o, i2_32u, r1, 0, andi, 0, 0x2000)
+    D(0xa504, NIHH,    RI_a,  Z,   r1_o, i2_16u, r1, 0, andi, 0, 0x1030)
+    D(0xa505, NIHL,    RI_a,  Z,   r1_o, i2_16u, r1, 0, andi, 0, 0x1020)
+    D(0xa506, NILH,    RI_a,  Z,   r1_o, i2_16u, r1, 0, andi, 0, 0x1010)
+    D(0xa507, NILL,    RI_a,  Z,   r1_o, i2_16u, r1, 0, andi, 0, 0x1000)
+    D(0x9400, NI,      SI,    Z,   la1, i2_8u, new, 0, ni, nz64, MO_UB)
+    D(0xeb54, NIY,     SIY,   LD,  la1, i2_8u, new, 0, ni, nz64, MO_UB)
+
+/* BRANCH AND LINK */
+    C(0x0500, BALR,    RR_a,  Z,   0, r2_nz, r1, 0, bal, 0)
+    C(0x4500, BAL,     RX_a,  Z,   0, a2, r1, 0, bal, 0)
+/* BRANCH AND SAVE */
+    C(0x0d00, BASR,    RR_a,  Z,   0, r2_nz, r1, 0, bas, 0)
+    C(0x4d00, BAS,     RX_a,  Z,   0, a2, r1, 0, bas, 0)
+/* BRANCH RELATIVE AND SAVE */
+    C(0xa705, BRAS,    RI_b,  Z,   0, 0, r1, 0, basi, 0)
+    C(0xc005, BRASL,   RIL_b, Z,   0, 0, r1, 0, basi, 0)
+/* BRANCH INDIRECT ON CONDITION */
+    C(0xe347, BIC,     RXY_b, MIE2,0, m2_64w, 0, 0, bc, 0)
+/* BRANCH ON CONDITION */
+    C(0x0700, BCR,     RR_b,  Z,   0, r2_nz, 0, 0, bc, 0)
+    C(0x4700, BC,      RX_b,  Z,   0, a2, 0, 0, bc, 0)
+/* BRANCH RELATIVE ON CONDITION */
+    C(0xa704, BRC,     RI_c,  Z,   0, 0, 0, 0, bc, 0)
+    C(0xc004, BRCL,    RIL_c, Z,   0, 0, 0, 0, bc, 0)
+/* BRANCH ON COUNT */
+    C(0x0600, BCTR,    RR_a,  Z,   0, r2_nz, 0, 0, bct32, 0)
+    C(0xb946, BCTGR,   RRE,   Z,   0, r2_nz, 0, 0, bct64, 0)
+    C(0x4600, BCT,     RX_a,  Z,   0, a2, 0, 0, bct32, 0)
+    C(0xe346, BCTG,    RXY_a, Z,   0, a2, 0, 0, bct64, 0)
+/* BRANCH RELATIVE ON COUNT */
+    C(0xa706, BRCT,    RI_b,  Z,   0, 0, 0, 0, bct32, 0)
+    C(0xa707, BRCTG,   RI_b,  Z,   0, 0, 0, 0, bct64, 0)
+/* BRANCH RELATIVE ON COUNT HIGH */
+    C(0xcc06, BRCTH,   RIL_b, HW,  0, 0, 0, 0, bcth, 0)
+/* BRANCH ON INDEX */
+    D(0x8600, BXH,     RS_a,  Z,   0, a2, 0, 0, bx32, 0, 0)
+    D(0x8700, BXLE,    RS_a,  Z,   0, a2, 0, 0, bx32, 0, 1)
+    D(0xeb44, BXHG,    RSY_a, Z,   0, a2, 0, 0, bx64, 0, 0)
+    D(0xeb45, BXLEG,   RSY_a, Z,   0, a2, 0, 0, bx64, 0, 1)
+/* BRANCH RELATIVE ON INDEX */
+    D(0x8400, BRXH,    RSI,   Z,   0, 0, 0, 0, bx32, 0, 0)
+    D(0x8500, BRXLE,   RSI,   Z,   0, 0, 0, 0, bx32, 0, 1)
+    D(0xec44, BRXHG,   RIE_e, Z,   0, 0, 0, 0, bx64, 0, 0)
+    D(0xec45, BRXHLE,  RIE_e, Z,   0, 0, 0, 0, bx64, 0, 1)
+/* BRANCH PREDICTION PRELOAD */
+    /* ??? Format is SMI, but implemented as NOP, so we need no fields.  */
+    C(0xc700, BPP,     E,     EH,  0, 0, 0, 0, 0, 0)
+/* BRANCH PREDICTION RELATIVE PRELOAD */
+    /* ??? Format is MII, but implemented as NOP, so we need no fields.  */
+    C(0xc500, BPRP,    E,     EH,  0, 0, 0, 0, 0, 0)
+/* NEXT INSTRUCTION ACCESS INTENT */
+    /* ??? Format is IE, but implemented as NOP, so we need no fields.  */
+    C(0xb2fa, NIAI,    E,     EH,  0, 0, 0, 0, 0, 0)
+
+/* CHECKSUM */
+    C(0xb241, CKSM,    RRE,   Z,   r1_o, ra2, new, r1_32, cksm, 0)
+
+/* COPY SIGN */
+    F(0xb372, CPSDR,   RRF_b, FPSSH, f3, f2, new, f1, cps, 0, IF_AFP1 | IF_AFP2 | IF_AFP3)
+
+/* COMPARE */
+    C(0x1900, CR,      RR_a,  Z,   r1_o, r2_o, 0, 0, 0, cmps32)
+    C(0x5900, C,       RX_a,  Z,   r1_o, m2_32s, 0, 0, 0, cmps32)
+    C(0xe359, CY,      RXY_a, LD,  r1_o, m2_32s, 0, 0, 0, cmps32)
+    C(0xb920, CGR,     RRE,   Z,   r1_o, r2_o, 0, 0, 0, cmps64)
+    C(0xb930, CGFR,    RRE,   Z,   r1_o, r2_32s, 0, 0, 0, cmps64)
+    C(0xe320, CG,      RXY_a, Z,   r1_o, m2_64, 0, 0, 0, cmps64)
+    C(0xe330, CGF,     RXY_a, Z,   r1_o, m2_32s, 0, 0, 0, cmps64)
+    F(0xb309, CEBR,    RRE,   Z,   e1, e2, 0, 0, ceb, 0, IF_BFP)
+    F(0xb319, CDBR,    RRE,   Z,   f1, f2, 0, 0, cdb, 0, IF_BFP)
+    F(0xb349, CXBR,    RRE,   Z,   x2h, x2l, x1, 0, cxb, 0, IF_BFP)
+    F(0xed09, CEB,     RXE,   Z,   e1, m2_32u, 0, 0, ceb, 0, IF_BFP)
+    F(0xed19, CDB,     RXE,   Z,   f1, m2_64, 0, 0, cdb, 0, IF_BFP)
+/* COMPARE AND SIGNAL */
+    F(0xb308, KEBR,    RRE,   Z,   e1, e2, 0, 0, keb, 0, IF_BFP)
+    F(0xb318, KDBR,    RRE,   Z,   f1, f2, 0, 0, kdb, 0, IF_BFP)
+    F(0xb348, KXBR,    RRE,   Z,   x2h, x2l, x1, 0, kxb, 0, IF_BFP)
+    F(0xed08, KEB,     RXE,   Z,   e1, m2_32u, 0, 0, keb, 0, IF_BFP)
+    F(0xed18, KDB,     RXE,   Z,   f1, m2_64, 0, 0, kdb, 0, IF_BFP)
+/* COMPARE IMMEDIATE */
+    C(0xc20d, CFI,     RIL_a, EI,  r1, i2, 0, 0, 0, cmps32)
+    C(0xc20c, CGFI,    RIL_a, EI,  r1, i2, 0, 0, 0, cmps64)
+/* COMPARE RELATIVE LONG */
+    C(0xc60d, CRL,     RIL_b, GIE, r1, mri2_32s, 0, 0, 0, cmps32)
+    C(0xc608, CGRL,    RIL_b, GIE, r1, mri2_64, 0, 0, 0, cmps64)
+    C(0xc60c, CGFRL,   RIL_b, GIE, r1, mri2_32s, 0, 0, 0, cmps64)
+/* COMPARE HALFWORD */
+    C(0x4900, CH,      RX_a,  Z,   r1_o, m2_16s, 0, 0, 0, cmps32)
+    C(0xe379, CHY,     RXY_a, LD,  r1_o, m2_16s, 0, 0, 0, cmps32)
+    C(0xe334, CGH,     RXY_a, GIE, r1_o, m2_16s, 0, 0, 0, cmps64)
+/* COMPARE HALFWORD IMMEDIATE */
+    C(0xa70e, CHI,     RI_a,  Z,   r1_o, i2, 0, 0, 0, cmps32)
+    C(0xa70f, CGHI,    RI_a,  Z,   r1_o, i2, 0, 0, 0, cmps64)
+    C(0xe554, CHHSI,   SIL,   GIE, m1_16s, i2, 0, 0, 0, cmps64)
+    C(0xe55c, CHSI,    SIL,   GIE, m1_32s, i2, 0, 0, 0, cmps64)
+    C(0xe558, CGHSI,   SIL,   GIE, m1_64, i2, 0, 0, 0, cmps64)
+/* COMPARE HALFWORD RELATIVE LONG */
+    C(0xc605, CHRL,    RIL_b, GIE, r1_o, mri2_32s, 0, 0, 0, cmps32)
+    C(0xc604, CGHRL,   RIL_b, GIE, r1_o, mri2_64, 0, 0, 0, cmps64)
+/* COMPARE HIGH */
+    C(0xb9cd, CHHR,    RRE,   HW,  r1_sr32, r2_sr32, 0, 0, 0, cmps32)
+    C(0xb9dd, CHLR,    RRE,   HW,  r1_sr32, r2_o, 0, 0, 0, cmps32)
+    C(0xe3cd, CHF,     RXY_a, HW,  r1_sr32, m2_32s, 0, 0, 0, cmps32)
+/* COMPARE IMMEDIATE HIGH */
+    C(0xcc0d, CIH,     RIL_a, HW,  r1_sr32, i2, 0, 0, 0, cmps32)
+
+/* COMPARE LOGICAL */
+    C(0x1500, CLR,     RR_a,  Z,   r1, r2, 0, 0, 0, cmpu32)
+    C(0x5500, CL,      RX_a,  Z,   r1, m2_32s, 0, 0, 0, cmpu32)
+    C(0xe355, CLY,     RXY_a, LD,  r1, m2_32s, 0, 0, 0, cmpu32)
+    C(0xb921, CLGR,    RRE,   Z,   r1, r2, 0, 0, 0, cmpu64)
+    C(0xb931, CLGFR,   RRE,   Z,   r1, r2_32u, 0, 0, 0, cmpu64)
+    C(0xe321, CLG,     RXY_a, Z,   r1, m2_64, 0, 0, 0, cmpu64)
+    C(0xe331, CLGF,    RXY_a, Z,   r1, m2_32u, 0, 0, 0, cmpu64)
+    C(0xd500, CLC,     SS_a,  Z,   la1, a2, 0, 0, clc, 0)
+/* COMPARE LOGICAL HIGH */
+    C(0xb9cf, CLHHR,   RRE,   HW,  r1_sr32, r2_sr32, 0, 0, 0, cmpu32)
+    C(0xb9df, CLHLR,   RRE,   HW,  r1_sr32, r2_o, 0, 0, 0, cmpu32)
+    C(0xe3cf, CLHF,    RXY_a, HW,  r1_sr32, m2_32s, 0, 0, 0, cmpu32)
+/* COMPARE LOGICAL IMMEDIATE */
+    C(0xc20f, CLFI,    RIL_a, EI,  r1, i2, 0, 0, 0, cmpu32)
+    C(0xc20e, CLGFI,   RIL_a, EI,  r1, i2_32u, 0, 0, 0, cmpu64)
+    C(0x9500, CLI,     SI,    Z,   m1_8u, i2_8u, 0, 0, 0, cmpu64)
+    C(0xeb55, CLIY,    SIY,   LD,  m1_8u, i2_8u, 0, 0, 0, cmpu64)
+    C(0xe555, CLHHSI,  SIL,   GIE, m1_16u, i2_16u, 0, 0, 0, cmpu64)
+    C(0xe55d, CLFHSI,  SIL,   GIE, m1_32u, i2_16u, 0, 0, 0, cmpu64)
+    C(0xe559, CLGHSI,  SIL,   GIE, m1_64, i2_16u, 0, 0, 0, cmpu64)
+/* COMPARE LOGICAL IMMEDIATE HIGH */
+    C(0xcc0f, CLIH,    RIL_a, HW,  r1_sr32, i2, 0, 0, 0, cmpu32)
+/* COMPARE LOGICAL RELATIVE LONG */
+    C(0xc60f, CLRL,    RIL_b, GIE, r1_o, mri2_32u, 0, 0, 0, cmpu32)
+    C(0xc60a, CLGRL,   RIL_b, GIE, r1_o, mri2_64, 0, 0, 0, cmpu64)
+    C(0xc60e, CLGFRL,  RIL_b, GIE, r1_o, mri2_32u, 0, 0, 0, cmpu64)
+    C(0xc607, CLHRL,   RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu32)
+    C(0xc606, CLGHRL,  RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu64)
+/* COMPARE LOGICAL LONG */
+    C(0x0f00, CLCL,    RR_a,  Z,   0, 0, 0, 0, clcl, 0)
+/* COMPARE LOGICAL LONG EXTENDED */
+    C(0xa900, CLCLE,   RS_a,  Z,   0, a2, 0, 0, clcle, 0)
+/* COMPARE LOGICAL LONG UNICODE */
+    C(0xeb8f, CLCLU,   RSY_a, E2,  0, a2, 0, 0, clclu, 0)
+/* COMPARE LOGICAL CHARACTERS UNDER MASK */
+    C(0xbd00, CLM,     RS_b,  Z,   r1_o, a2, 0, 0, clm, 0)
+    C(0xeb21, CLMY,    RSY_b, LD,  r1_o, a2, 0, 0, clm, 0)
+    C(0xeb20, CLMH,    RSY_b, Z,   r1_sr32, a2, 0, 0, clm, 0)
+/* COMPARE LOGICAL STRING */
+    C(0xb25d, CLST,    RRE,   Z,   r1_o, r2_o, 0, 0, clst, 0)
+
+/* COMPARE AND BRANCH */
+    D(0xecf6, CRB,     RRS,   GIE, r1_32s, r2_32s, 0, 0, cj, 0, 0)
+    D(0xece4, CGRB,    RRS,   GIE, r1_o, r2_o, 0, 0, cj, 0, 0)
+    D(0xec76, CRJ,     RIE_b, GIE, r1_32s, r2_32s, 0, 0, cj, 0, 0)
+    D(0xec64, CGRJ,    RIE_b, GIE, r1_o, r2_o, 0, 0, cj, 0, 0)
+    D(0xecfe, CIB,     RIS,   GIE, r1_32s, i2, 0, 0, cj, 0, 0)
+    D(0xecfc, CGIB,    RIS,   GIE, r1_o, i2, 0, 0, cj, 0, 0)
+    D(0xec7e, CIJ,     RIE_c, GIE, r1_32s, i2, 0, 0, cj, 0, 0)
+    D(0xec7c, CGIJ,    RIE_c, GIE, r1_o, i2, 0, 0, cj, 0, 0)
+/* COMPARE LOGICAL AND BRANCH */
+    D(0xecf7, CLRB,    RRS,   GIE, r1_32u, r2_32u, 0, 0, cj, 0, 1)
+    D(0xece5, CLGRB,   RRS,   GIE, r1_o, r2_o, 0, 0, cj, 0, 1)
+    D(0xec77, CLRJ,    RIE_b, GIE, r1_32u, r2_32u, 0, 0, cj, 0, 1)
+    D(0xec65, CLGRJ,   RIE_b, GIE, r1_o, r2_o, 0, 0, cj, 0, 1)
+    D(0xecff, CLIB,    RIS,   GIE, r1_32u, i2_8u, 0, 0, cj, 0, 1)
+    D(0xecfd, CLGIB,   RIS,   GIE, r1_o, i2_8u, 0, 0, cj, 0, 1)
+    D(0xec7f, CLIJ,    RIE_c, GIE, r1_32u, i2_8u, 0, 0, cj, 0, 1)
+    D(0xec7d, CLGIJ,   RIE_c, GIE, r1_o, i2_8u, 0, 0, cj, 0, 1)
+
+/* COMPARE AND SWAP */
+    D(0xba00, CS,      RS_a,  Z,   r3_32u, r1_32u, new, r1_32, cs, 0, MO_TEUL)
+    D(0xeb14, CSY,     RSY_a, LD,  r3_32u, r1_32u, new, r1_32, cs, 0, MO_TEUL)
+    D(0xeb30, CSG,     RSY_a, Z,   r3_o, r1_o, new, r1, cs, 0, MO_TEQ)
+/* COMPARE DOUBLE AND SWAP */
+    D(0xbb00, CDS,     RS_a,  Z,   r3_D32, r1_D32, new, r1_D32, cs, 0, MO_TEQ)
+    D(0xeb31, CDSY,    RSY_a, LD,  r3_D32, r1_D32, new, r1_D32, cs, 0, MO_TEQ)
+    C(0xeb3e, CDSG,    RSY_a, Z,   0, 0, 0, 0, cdsg, 0)
+/* COMPARE AND SWAP AND STORE */
+    C(0xc802, CSST,    SSF,   CASS, la1, a2, 0, 0, csst, 0)
+
+/* COMPARE AND TRAP */
+    D(0xb972, CRT,     RRF_c, GIE, r1_32s, r2_32s, 0, 0, ct, 0, 0)
+    D(0xb960, CGRT,    RRF_c, GIE, r1_o, r2_o, 0, 0, ct, 0, 0)
+    D(0xec72, CIT,     RIE_a, GIE, r1_32s, i2, 0, 0, ct, 0, 0)
+    D(0xec70, CGIT,    RIE_a, GIE, r1_o, i2, 0, 0, ct, 0, 0)
+/* COMPARE LOGICAL AND TRAP */
+    D(0xb973, CLRT,    RRF_c, GIE, r1_32u, r2_32u, 0, 0, ct, 0, 1)
+    D(0xb961, CLGRT,   RRF_c, GIE, r1_o, r2_o, 0, 0, ct, 0, 1)
+    D(0xeb23, CLT,     RSY_b, MIE, r1_32u, m2_32u, 0, 0, ct, 0, 1)
+    D(0xeb2b, CLGT,    RSY_b, MIE, r1_o, m2_64, 0, 0, ct, 0, 1)
+    D(0xec73, CLFIT,   RIE_a, GIE, r1_32u, i2_32u, 0, 0, ct, 0, 1)
+    D(0xec71, CLGIT,   RIE_a, GIE, r1_o, i2_32u, 0, 0, ct, 0, 1)
+
+/* CONVERT TO DECIMAL */
+    C(0x4e00, CVD,     RX_a,  Z,   r1_o, a2, 0, 0, cvd, 0)
+    C(0xe326, CVDY,    RXY_a, LD,  r1_o, a2, 0, 0, cvd, 0)
+/* CONVERT TO FIXED */
+    F(0xb398, CFEBR,   RRF_e, Z,   0, e2, new, r1_32, cfeb, 0, IF_BFP)
+    F(0xb399, CFDBR,   RRF_e, Z,   0, f2, new, r1_32, cfdb, 0, IF_BFP)
+    F(0xb39a, CFXBR,   RRF_e, Z,   x2h, x2l, new, r1_32, cfxb, 0, IF_BFP)
+    F(0xb3a8, CGEBR,   RRF_e, Z,   0, e2, r1, 0, cgeb, 0, IF_BFP)
+    F(0xb3a9, CGDBR,   RRF_e, Z,   0, f2, r1, 0, cgdb, 0, IF_BFP)
+    F(0xb3aa, CGXBR,   RRF_e, Z,   x2h, x2l, r1, 0, cgxb, 0, IF_BFP)
+/* CONVERT FROM FIXED */
+    F(0xb394, CEFBR,   RRF_e, Z,   0, r2_32s, new, e1, cegb, 0, IF_BFP)
+    F(0xb395, CDFBR,   RRF_e, Z,   0, r2_32s, new, f1, cdgb, 0, IF_BFP)
+    F(0xb396, CXFBR,   RRF_e, Z,   0, r2_32s, new_P, x1, cxgb, 0, IF_BFP)
+    F(0xb3a4, CEGBR,   RRF_e, Z,   0, r2_o, new, e1, cegb, 0, IF_BFP)
+    F(0xb3a5, CDGBR,   RRF_e, Z,   0, r2_o, new, f1, cdgb, 0, IF_BFP)
+    F(0xb3a6, CXGBR,   RRF_e, Z,   0, r2_o, new_P, x1, cxgb, 0, IF_BFP)
+/* CONVERT TO LOGICAL */
+    F(0xb39c, CLFEBR,  RRF_e, FPE, 0, e2, new, r1_32, clfeb, 0, IF_BFP)
+    F(0xb39d, CLFDBR,  RRF_e, FPE, 0, f2, new, r1_32, clfdb, 0, IF_BFP)
+    F(0xb39e, CLFXBR,  RRF_e, FPE, x2h, x2l, new, r1_32, clfxb, 0, IF_BFP)
+    F(0xb3ac, CLGEBR,  RRF_e, FPE, 0, e2, r1, 0, clgeb, 0, IF_BFP)
+    F(0xb3ad, CLGDBR,  RRF_e, FPE, 0, f2, r1, 0, clgdb, 0, IF_BFP)
+    F(0xb3ae, CLGXBR,  RRF_e, FPE, x2h, x2l, r1, 0, clgxb, 0, IF_BFP)
+/* CONVERT FROM LOGICAL */
+    F(0xb390, CELFBR,  RRF_e, FPE, 0, r2_32u, new, e1, celgb, 0, IF_BFP)
+    F(0xb391, CDLFBR,  RRF_e, FPE, 0, r2_32u, new, f1, cdlgb, 0, IF_BFP)
+    F(0xb392, CXLFBR,  RRF_e, FPE, 0, r2_32u, new_P, x1, cxlgb, 0, IF_BFP)
+    F(0xb3a0, CELGBR,  RRF_e, FPE, 0, r2_o, new, e1, celgb, 0, IF_BFP)
+    F(0xb3a1, CDLGBR,  RRF_e, FPE, 0, r2_o, new, f1, cdlgb, 0, IF_BFP)
+    F(0xb3a2, CXLGBR,  RRF_e, FPE, 0, r2_o, new_P, x1, cxlgb, 0, IF_BFP)
+
+/* CONVERT UTF-8 TO UTF-16 */
+    D(0xb2a7, CU12,    RRF_c, Z,   0, 0, 0, 0, cuXX, 0, 12)
+/* CONVERT UTF-8 TO UTF-32 */
+    D(0xb9b0, CU14,    RRF_c, ETF3, 0, 0, 0, 0, cuXX, 0, 14)
+/* CONVERT UTF-16 to UTF-8 */
+    D(0xb2a6, CU21,    RRF_c, Z,   0, 0, 0, 0, cuXX, 0, 21)
+/* CONVERT UTF-16 to UTF-32 */
+    D(0xb9b1, CU24,    RRF_c, ETF3, 0, 0, 0, 0, cuXX, 0, 24)
+/* CONVERT UTF-32 to UTF-8 */
+    D(0xb9b2, CU41,    RRF_c, ETF3, 0, 0, 0, 0, cuXX, 0, 41)
+/* CONVERT UTF-32 to UTF-16 */
+    D(0xb9b3, CU42,    RRF_c, ETF3, 0, 0, 0, 0, cuXX, 0, 42)
+
+/* DIVIDE */
+    C(0x1d00, DR,      RR_a,  Z,   r1_D32, r2_32s, new_P, r1_P32, divs32, 0)
+    C(0x5d00, D,       RX_a,  Z,   r1_D32, m2_32s, new_P, r1_P32, divs32, 0)
+    F(0xb30d, DEBR,    RRE,   Z,   e1, e2, new, e1, deb, 0, IF_BFP)
+    F(0xb31d, DDBR,    RRE,   Z,   f1, f2, new, f1, ddb, 0, IF_BFP)
+    F(0xb34d, DXBR,    RRE,   Z,   x2h, x2l, x1, x1, dxb, 0, IF_BFP)
+    F(0xed0d, DEB,     RXE,   Z,   e1, m2_32u, new, e1, deb, 0, IF_BFP)
+    F(0xed1d, DDB,     RXE,   Z,   f1, m2_64, new, f1, ddb, 0, IF_BFP)
+/* DIVIDE LOGICAL */
+    C(0xb997, DLR,     RRE,   Z,   r1_D32, r2_32u, new_P, r1_P32, divu32, 0)
+    C(0xe397, DL,      RXY_a, Z,   r1_D32, m2_32u, new_P, r1_P32, divu32, 0)
+    C(0xb987, DLGR,    RRE,   Z,   0, r2_o, r1_P, 0, divu64, 0)
+    C(0xe387, DLG,     RXY_a, Z,   0, m2_64, r1_P, 0, divu64, 0)
+/* DIVIDE SINGLE */
+    C(0xb90d, DSGR,    RRE,   Z,   r1p1, r2, r1_P, 0, divs64, 0)
+    C(0xb91d, DSGFR,   RRE,   Z,   r1p1, r2_32s, r1_P, 0, divs64, 0)
+    C(0xe30d, DSG,     RXY_a, Z,   r1p1, m2_64, r1_P, 0, divs64, 0)
+    C(0xe31d, DSGF,    RXY_a, Z,   r1p1, m2_32s, r1_P, 0, divs64, 0)
+
+/* EXCLUSIVE OR */
+    C(0x1700, XR,      RR_a,  Z,   r1, r2, new, r1_32, xor, nz32)
+    C(0xb9f7, XRK,     RRF_a, DO,  r2, r3, new, r1_32, xor, nz32)
+    C(0x5700, X,       RX_a,  Z,   r1, m2_32s, new, r1_32, xor, nz32)
+    C(0xe357, XY,      RXY_a, LD,  r1, m2_32s, new, r1_32, xor, nz32)
+    C(0xb982, XGR,     RRE,   Z,   r1, r2, r1, 0, xor, nz64)
+    C(0xb9e7, XGRK,    RRF_a, DO,  r2, r3, r1, 0, xor, nz64)
+    C(0xe382, XG,      RXY_a, Z,   r1, m2_64, r1, 0, xor, nz64)
+    C(0xd700, XC,      SS_a,  Z,   0, 0, 0, 0, xc, 0)
+/* EXCLUSIVE OR IMMEDIATE */
+    D(0xc006, XIHF,    RIL_a, EI,  r1_o, i2_32u, r1, 0, xori, 0, 0x2020)
+    D(0xc007, XILF,    RIL_a, EI,  r1_o, i2_32u, r1, 0, xori, 0, 0x2000)
+    D(0x9700, XI,      SI,    Z,   la1, i2_8u, new, 0, xi, nz64, MO_UB)
+    D(0xeb57, XIY,     SIY,   LD,  la1, i2_8u, new, 0, xi, nz64, MO_UB)
+
+/* EXECUTE */
+    C(0x4400, EX,      RX_a,  Z,   0, a2, 0, 0, ex, 0)
+/* EXECUTE RELATIVE LONG */
+    C(0xc600, EXRL,    RIL_b, EE,  0, ri2, 0, 0, ex, 0)
+
+/* EXTRACT ACCESS */
+    C(0xb24f, EAR,     RRE,   Z,   0, 0, new, r1_32, ear, 0)
+/* EXTRACT CPU ATTRIBUTE */
+    C(0xeb4c, ECAG,    RSY_a, GIE, 0, a2, r1, 0, ecag, 0)
+/* EXTRACT CPU TIME */
+    F(0xc801, ECTG,    SSF,   ECT, 0, 0, 0, 0, ectg, 0, IF_IO)
+/* EXTRACT FPC */
+    F(0xb38c, EFPC,    RRE,   Z,   0, 0, new, r1_32, efpc, 0, IF_BFP)
+/* EXTRACT PSW */
+    C(0xb98d, EPSW,    RRE,   Z,   0, 0, 0, 0, epsw, 0)
+
+/* FIND LEFTMOST ONE */
+    C(0xb983, FLOGR,   RRE,   EI,  0, r2_o, r1_P, 0, flogr, 0)
+
+/* INSERT CHARACTER */
+    C(0x4300, IC,      RX_a,  Z,   0, m2_8u, 0, r1_8, mov2, 0)
+    C(0xe373, ICY,     RXY_a, LD,  0, m2_8u, 0, r1_8, mov2, 0)
+/* INSERT CHARACTERS UNDER MASK */
+    D(0xbf00, ICM,     RS_b,  Z,   0, a2, r1, 0, icm, 0, 0)
+    D(0xeb81, ICMY,    RSY_b, LD,  0, a2, r1, 0, icm, 0, 0)
+    D(0xeb80, ICMH,    RSY_b, Z,   0, a2, r1, 0, icm, 0, 32)
+/* INSERT IMMEDIATE */
+    D(0xc008, IIHF,    RIL_a, EI,  r1_o, i2_32u, r1, 0, insi, 0, 0x2020)
+    D(0xc009, IILF,    RIL_a, EI,  r1_o, i2_32u, r1, 0, insi, 0, 0x2000)
+    D(0xa500, IIHH,    RI_a,  Z,   r1_o, i2_16u, r1, 0, insi, 0, 0x1030)
+    D(0xa501, IIHL,    RI_a,  Z,   r1_o, i2_16u, r1, 0, insi, 0, 0x1020)
+    D(0xa502, IILH,    RI_a,  Z,   r1_o, i2_16u, r1, 0, insi, 0, 0x1010)
+    D(0xa503, IILL,    RI_a,  Z,   r1_o, i2_16u, r1, 0, insi, 0, 0x1000)
+/* INSERT PROGRAM MASK */
+    C(0xb222, IPM,     RRE,   Z,   0, 0, r1, 0, ipm, 0)
+
+/* LOAD */
+    C(0x1800, LR,      RR_a,  Z,   0, r2_o, 0, cond_r1r2_32, mov2, 0)
+    C(0x5800, L,       RX_a,  Z,   0, a2, new, r1_32, ld32s, 0)
+    C(0xe358, LY,      RXY_a, LD,  0, a2, new, r1_32, ld32s, 0)
+    C(0xb904, LGR,     RRE,   Z,   0, r2_o, 0, r1, mov2, 0)
+    C(0xb914, LGFR,    RRE,   Z,   0, r2_32s, 0, r1, mov2, 0)
+    C(0xe304, LG,      RXY_a, Z,   0, a2, r1, 0, ld64, 0)
+    C(0xe314, LGF,     RXY_a, Z,   0, a2, r1, 0, ld32s, 0)
+    F(0x2800, LDR,     RR_a,  Z,   0, f2, 0, f1, mov2, 0, IF_AFP1 | IF_AFP2)
+    F(0x6800, LD,      RX_a,  Z,   0, m2_64, 0, f1, mov2, 0, IF_AFP1)
+    F(0xed65, LDY,     RXY_a, LD,  0, m2_64, 0, f1, mov2, 0, IF_AFP1)
+    F(0x3800, LER,     RR_a,  Z,   0, e2, 0, cond_e1e2, mov2, 0, IF_AFP1 | IF_AFP2)
+    F(0x7800, LE,      RX_a,  Z,   0, m2_32u, 0, e1, mov2, 0, IF_AFP1)
+    F(0xed64, LEY,     RXY_a, LD,  0, m2_32u, 0, e1, mov2, 0, IF_AFP1)
+    F(0xb365, LXR,     RRE,   Z,   x2h, x2l, 0, x1, movx, 0, IF_AFP1)
+/* LOAD IMMEDIATE */
+    C(0xc001, LGFI,    RIL_a, EI,  0, i2, 0, r1, mov2, 0)
+/* LOAD RELATIVE LONG */
+    C(0xc40d, LRL,     RIL_b, GIE, 0, ri2, new, r1_32, ld32s, 0)
+    C(0xc408, LGRL,    RIL_b, GIE, 0, ri2, r1, 0, ld64, 0)
+    C(0xc40c, LGFRL,   RIL_b, GIE, 0, ri2, r1, 0, ld32s, 0)
+/* LOAD ADDRESS */
+    C(0x4100, LA,      RX_a,  Z,   0, a2, 0, r1, mov2, 0)
+    C(0xe371, LAY,     RXY_a, LD,  0, a2, 0, r1, mov2, 0)
+/* LOAD ADDRESS EXTENDED */
+    C(0x5100, LAE,     RX_a,  Z,   0, a2, 0, r1, mov2e, 0)
+    C(0xe375, LAEY,    RXY_a, GIE, 0, a2, 0, r1, mov2e, 0)
+/* LOAD ADDRESS RELATIVE LONG */
+    C(0xc000, LARL,    RIL_b, Z,   0, ri2, 0, r1, mov2, 0)
+/* LOAD AND ADD */
+    D(0xebf8, LAA,     RSY_a, ILA, r3_32s, a2, new, in2_r1_32, laa, adds32, MO_TESL)
+    D(0xebe8, LAAG,    RSY_a, ILA, r3, a2, new, in2_r1, laa, adds64, MO_TEQ)
+/* LOAD AND ADD LOGICAL */
+    D(0xebfa, LAAL,    RSY_a, ILA, r3_32u, a2, new, in2_r1_32, laa, addu32, MO_TEUL)
+    D(0xebea, LAALG,   RSY_a, ILA, r3, a2, new, in2_r1, laa, addu64, MO_TEQ)
+/* LOAD AND AND */
+    D(0xebf4, LAN,     RSY_a, ILA, r3_32s, a2, new, in2_r1_32, lan, nz32, MO_TESL)
+    D(0xebe4, LANG,    RSY_a, ILA, r3, a2, new, in2_r1, lan, nz64, MO_TEQ)
+/* LOAD AND EXCLUSIVE OR */
+    D(0xebf7, LAX,     RSY_a, ILA, r3_32s, a2, new, in2_r1_32, lax, nz32, MO_TESL)
+    D(0xebe7, LAXG,    RSY_a, ILA, r3, a2, new, in2_r1, lax, nz64, MO_TEQ)
+/* LOAD AND OR */
+    D(0xebf6, LAO,     RSY_a, ILA, r3_32s, a2, new, in2_r1_32, lao, nz32, MO_TESL)
+    D(0xebe6, LAOG,    RSY_a, ILA, r3, a2, new, in2_r1, lao, nz64, MO_TEQ)
+/* LOAD AND TEST */
+    C(0x1200, LTR,     RR_a,  Z,   0, r2_o, 0, cond_r1r2_32, mov2, s32)
+    C(0xb902, LTGR,    RRE,   Z,   0, r2_o, 0, r1, mov2, s64)
+    C(0xb912, LTGFR,   RRE,   Z,   0, r2_32s, 0, r1, mov2, s64)
+    C(0xe312, LT,      RXY_a, EI,  0, a2, new, r1_32, ld32s, s64)
+    C(0xe302, LTG,     RXY_a, EI,  0, a2, r1, 0, ld64, s64)
+    C(0xe332, LTGF,    RXY_a, GIE, 0, a2, r1, 0, ld32s, s64)
+    F(0xb302, LTEBR,   RRE,   Z,   0, e2, 0, cond_e1e2, mov2, f32, IF_BFP)
+    F(0xb312, LTDBR,   RRE,   Z,   0, f2, 0, f1, mov2, f64, IF_BFP)
+    F(0xb342, LTXBR,   RRE,   Z,   x2h, x2l, 0, x1, movx, f128, IF_BFP)
+/* LOAD AND TRAP */
+    C(0xe39f, LAT,     RXY_a, LAT, 0, m2_32u, r1, 0, lat, 0)
+    C(0xe385, LGAT,    RXY_a, LAT, 0, a2, r1, 0, lgat, 0)
+/* LOAD AND ZERO RIGHTMOST BYTE */
+    C(0xe3eb, LZRF,    RXY_a, LZRB, 0, m2_32u, new, r1_32, lzrb, 0)
+    C(0xe32a, LZRG,    RXY_a, LZRB, 0, m2_64, r1, 0, lzrb, 0)
+/* LOAD LOGICAL AND ZERO RIGHTMOST BYTE */
+    C(0xe33a, LLZRGF,  RXY_a, LZRB, 0, m2_32u, r1, 0, lzrb, 0)
+/* LOAD BYTE */
+    C(0xb926, LBR,     RRE,   EI,  0, r2_8s, 0, r1_32, mov2, 0)
+    C(0xb906, LGBR,    RRE,   EI,  0, r2_8s, 0, r1, mov2, 0)
+    C(0xe376, LB,      RXY_a, LD,  0, a2, new, r1_32, ld8s, 0)
+    C(0xe377, LGB,     RXY_a, LD,  0, a2, r1, 0, ld8s, 0)
+/* LOAD BYTE HIGH */
+    C(0xe3c0, LBH,     RXY_a, HW,  0, a2, new, r1_32h, ld8s, 0)
+/* LOAD COMPLEMENT */
+    C(0x1300, LCR,     RR_a,  Z,   0, r2, new, r1_32, neg, neg32)
+    C(0xb903, LCGR,    RRE,   Z,   0, r2, r1, 0, neg, neg64)
+    C(0xb913, LCGFR,   RRE,   Z,   0, r2_32s, r1, 0, neg, neg64)
+    F(0xb303, LCEBR,   RRE,   Z,   0, e2, new, e1, negf32, f32, IF_BFP)
+    F(0xb313, LCDBR,   RRE,   Z,   0, f2, new, f1, negf64, f64, IF_BFP)
+    F(0xb343, LCXBR,   RRE,   Z,   x2h, x2l, new_P, x1, negf128, f128, IF_BFP)
+    F(0xb373, LCDFR,   RRE,   FPSSH, 0, f2, new, f1, negf64, 0, IF_AFP1 | IF_AFP2)
+/* LOAD COUNT TO BLOCK BOUNDARY */
+    C(0xe727, LCBB,    RXE,   V,   la2, 0, r1, 0, lcbb, 0)
+/* LOAD HALFWORD */
+    C(0xb927, LHR,     RRE,   EI,  0, r2_16s, 0, r1_32, mov2, 0)
+    C(0xb907, LGHR,    RRE,   EI,  0, r2_16s, 0, r1, mov2, 0)
+    C(0x4800, LH,      RX_a,  Z,   0, a2, new, r1_32, ld16s, 0)
+    C(0xe378, LHY,     RXY_a, LD,  0, a2, new, r1_32, ld16s, 0)
+    C(0xe315, LGH,     RXY_a, Z,   0, a2, r1, 0, ld16s, 0)
+/* LOAD HALFWORD HIGH */
+    C(0xe3c4, LHH,     RXY_a, HW,  0, a2, new, r1_32h, ld16s, 0)
+/* LOAD HALFWORD IMMEDIATE */
+    C(0xa708, LHI,     RI_a,  Z,   0, i2, 0, r1_32, mov2, 0)
+    C(0xa709, LGHI,    RI_a,  Z,   0, i2, 0, r1, mov2, 0)
+/* LOAD HALFWORD RELATIVE LONG */
+    C(0xc405, LHRL,    RIL_b, GIE, 0, ri2, new, r1_32, ld16s, 0)
+    C(0xc404, LGHRL,   RIL_b, GIE, 0, ri2, r1, 0, ld16s, 0)
+/* LOAD HIGH */
+    C(0xe3ca, LFH,     RXY_a, HW,  0, a2, new, r1_32h, ld32u, 0)
+/* LOAG HIGH AND TRAP */
+    C(0xe3c8, LFHAT,   RXY_a, LAT, 0, m2_32u, r1, 0, lfhat, 0)
+/* LOAD LOGICAL */
+    C(0xb916, LLGFR,   RRE,   Z,   0, r2_32u, 0, r1, mov2, 0)
+    C(0xe316, LLGF,    RXY_a, Z,   0, a2, r1, 0, ld32u, 0)
+/* LOAD LOGICAL AND TRAP */
+    C(0xe39d, LLGFAT,  RXY_a, LAT, 0, a2, r1, 0, llgfat, 0)
+/* LOAD LOGICAL RELATIVE LONG */
+    C(0xc40e, LLGFRL,  RIL_b, GIE, 0, ri2, r1, 0, ld32u, 0)
+/* LOAD LOGICAL CHARACTER */
+    C(0xb994, LLCR,    RRE,   EI,  0, r2_8u, 0, r1_32, mov2, 0)
+    C(0xb984, LLGCR,   RRE,   EI,  0, r2_8u, 0, r1, mov2, 0)
+    C(0xe394, LLC,     RXY_a, EI,  0, a2, new, r1_32, ld8u, 0)
+    C(0xe390, LLGC,    RXY_a, Z,   0, a2, r1, 0, ld8u, 0)
+/* LOAD LOGICAL CHARACTER HIGH */
+    C(0xe3c2, LLCH,    RXY_a, HW,  0, a2, new, r1_32h, ld8u, 0)
+/* LOAD LOGICAL HALFWORD */
+    C(0xb995, LLHR,    RRE,   EI,  0, r2_16u, 0, r1_32, mov2, 0)
+    C(0xb985, LLGHR,   RRE,   EI,  0, r2_16u, 0, r1, mov2, 0)
+    C(0xe395, LLH,     RXY_a, EI,  0, a2, new, r1_32, ld16u, 0)
+    C(0xe391, LLGH,    RXY_a, Z,   0, a2, r1, 0, ld16u, 0)
+/* LOAD LOGICAL HALFWORD HIGH */
+    C(0xe3c6, LLHH,    RXY_a, HW,  0, a2, new, r1_32h, ld16u, 0)
+/* LOAD LOGICAL HALFWORD RELATIVE LONG */
+    C(0xc402, LLHRL,   RIL_b, GIE, 0, ri2, new, r1_32, ld16u, 0)
+    C(0xc406, LLGHRL,  RIL_b, GIE, 0, ri2, r1, 0, ld16u, 0)
+/* LOAD LOGICAL IMMEDATE */
+    D(0xc00e, LLIHF,   RIL_a, EI, 0, i2_32u_shl, 0, r1, mov2, 0, 32)
+    D(0xc00f, LLILF,   RIL_a, EI, 0, i2_32u_shl, 0, r1, mov2, 0, 0)
+    D(0xa50c, LLIHH,   RI_a,  Z,  0, i2_16u_shl, 0, r1, mov2, 0, 48)
+    D(0xa50d, LLIHL,   RI_a,  Z,  0, i2_16u_shl, 0, r1, mov2, 0, 32)
+    D(0xa50e, LLILH,   RI_a,  Z,  0, i2_16u_shl, 0, r1, mov2, 0, 16)
+    D(0xa50f, LLILL,   RI_a,  Z,  0, i2_16u_shl, 0, r1, mov2, 0, 0)
+/* LOAD LOGICAL THIRTY ONE BITS */
+    C(0xb917, LLGTR,   RRE,   Z,  0, r2_o, r1, 0, llgt, 0)
+    C(0xe317, LLGT,    RXY_a, Z,  0, m2_32u, r1, 0, llgt, 0)
+/* LOAD LOGICAL THIRTY ONE BITS AND TRAP */
+    C(0xe39c, LLGTAT,  RXY_a, LAT, 0, m2_32u, r1, 0, llgtat, 0)
+
+/* LOAD FPR FROM GR */
+    F(0xb3c1, LDGR,    RRE,   FPRGR, 0, r2_o, 0, f1, mov2, 0, IF_AFP1)
+/* LOAD GR FROM FPR */
+    F(0xb3cd, LGDR,    RRE,   FPRGR, 0, f2, 0, r1, mov2, 0, IF_AFP2)
+/* LOAD NEGATIVE */
+    C(0x1100, LNR,     RR_a,  Z,   0, r2_32s, new, r1_32, nabs, nabs32)
+    C(0xb901, LNGR,    RRE,   Z,   0, r2, r1, 0, nabs, nabs64)
+    C(0xb911, LNGFR,   RRE,   Z,   0, r2_32s, r1, 0, nabs, nabs64)
+    F(0xb301, LNEBR,   RRE,   Z,   0, e2, new, e1, nabsf32, f32, IF_BFP)
+    F(0xb311, LNDBR,   RRE,   Z,   0, f2, new, f1, nabsf64, f64, IF_BFP)
+    F(0xb341, LNXBR,   RRE,   Z,   x2h, x2l, new_P, x1, nabsf128, f128, IF_BFP)
+    F(0xb371, LNDFR,   RRE,   FPSSH, 0, f2, new, f1, nabsf64, 0, IF_AFP1 | IF_AFP2)
+/* LOAD ON CONDITION */
+    C(0xb9f2, LOCR,    RRF_c, LOC, r1, r2, new, r1_32, loc, 0)
+    C(0xb9e2, LOCGR,   RRF_c, LOC, r1, r2, r1, 0, loc, 0)
+    C(0xebf2, LOC,     RSY_b, LOC, r1, m2_32u, new, r1_32, loc, 0)
+    C(0xebe2, LOCG,    RSY_b, LOC, r1, m2_64, r1, 0, loc, 0)
+/* LOAD HALFWORD IMMEDIATE ON CONDITION */
+    C(0xec42, LOCHI,   RIE_g, LOC2, r1, i2, new, r1_32, loc, 0)
+    C(0xec46, LOCGHI,  RIE_g, LOC2, r1, i2, r1, 0, loc, 0)
+    C(0xec4e, LOCHHI,  RIE_g, LOC2, r1_sr32, i2, new, r1_32h, loc, 0)
+/* LOAD HIGH ON CONDITION */
+    C(0xb9e0, LOCFHR,  RRF_c, LOC2, r1_sr32, r2, new, r1_32h, loc, 0)
+    C(0xebe0, LOCFH,   RSY_b, LOC2, r1_sr32, m2_32u, new, r1_32h, loc, 0)
+/* LOAD PAIR DISJOINT */
+    D(0xc804, LPD,     SSF,   ILA, 0, 0, new_P, r3_P32, lpd, 0, MO_TEUL)
+    D(0xc805, LPDG,    SSF,   ILA, 0, 0, new_P, r3_P64, lpd, 0, MO_TEQ)
+/* LOAD PAIR FROM QUADWORD */
+    C(0xe38f, LPQ,     RXY_a, Z,   0, a2, r1_P, 0, lpq, 0)
+/* LOAD POSITIVE */
+    C(0x1000, LPR,     RR_a,  Z,   0, r2_32s, new, r1_32, abs, abs32)
+    C(0xb900, LPGR,    RRE,   Z,   0, r2, r1, 0, abs, abs64)
+    C(0xb910, LPGFR,   RRE,   Z,   0, r2_32s, r1, 0, abs, abs64)
+    F(0xb300, LPEBR,   RRE,   Z,   0, e2, new, e1, absf32, f32, IF_BFP)
+    F(0xb310, LPDBR,   RRE,   Z,   0, f2, new, f1, absf64, f64, IF_BFP)
+    F(0xb340, LPXBR,   RRE,   Z,   x2h, x2l, new_P, x1, absf128, f128, IF_BFP)
+    F(0xb370, LPDFR,   RRE,   FPSSH, 0, f2, new, f1, absf64, 0, IF_AFP1 | IF_AFP2)
+/* LOAD REVERSED */
+    C(0xb91f, LRVR,    RRE,   Z,   0, r2_32u, new, r1_32, rev32, 0)
+    C(0xb90f, LRVGR,   RRE,   Z,   0, r2_o, r1, 0, rev64, 0)
+    C(0xe31f, LRVH,    RXY_a, Z,   0, m2_16u, new, r1_16, rev16, 0)
+    C(0xe31e, LRV,     RXY_a, Z,   0, m2_32u, new, r1_32, rev32, 0)
+    C(0xe30f, LRVG,    RXY_a, Z,   0, m2_64, r1, 0, rev64, 0)
+/* LOAD ZERO */
+    F(0xb374, LZER,    RRE,   Z,   0, 0, 0, e1, zero, 0, IF_AFP1)
+    F(0xb375, LZDR,    RRE,   Z,   0, 0, 0, f1, zero, 0, IF_AFP1)
+    F(0xb376, LZXR,    RRE,   Z,   0, 0, 0, x1, zero2, 0, IF_AFP1)
+
+/* LOAD FPC */
+    F(0xb29d, LFPC,    S,     Z,   0, m2_32u, 0, 0, sfpc, 0, IF_BFP)
+/* LOAD FPC AND SIGNAL */
+    F(0xb2bd, LFAS,    S,     IEEEE_SIM, 0, m2_32u, 0, 0, sfas, 0, IF_DFP)
+/* LOAD FP INTEGER */
+    F(0xb357, FIEBR,   RRF_e, Z,   0, e2, new, e1, fieb, 0, IF_BFP)
+    F(0xb35f, FIDBR,   RRF_e, Z,   0, f2, new, f1, fidb, 0, IF_BFP)
+    F(0xb347, FIXBR,   RRF_e, Z,   x2h, x2l, new_P, x1, fixb, 0, IF_BFP)
+
+/* LOAD LENGTHENED */
+    F(0xb304, LDEBR,   RRE,   Z,   0, e2, new, f1, ldeb, 0, IF_BFP)
+    F(0xb305, LXDBR,   RRE,   Z,   0, f2, new_P, x1, lxdb, 0, IF_BFP)
+    F(0xb306, LXEBR,   RRE,   Z,   0, e2, new_P, x1, lxeb, 0, IF_BFP)
+    F(0xed04, LDEB,    RXE,   Z,   0, m2_32u, new, f1, ldeb, 0, IF_BFP)
+    F(0xed05, LXDB,    RXE,   Z,   0, m2_64, new_P, x1, lxdb, 0, IF_BFP)
+    F(0xed06, LXEB,    RXE,   Z,   0, m2_32u, new_P, x1, lxeb, 0, IF_BFP)
+    F(0xb324, LDER,    RXE,   Z,   0, e2, new, f1, lde, 0, IF_AFP1)
+    F(0xed24, LDE,     RXE,   Z,   0, m2_32u, new, f1, lde, 0, IF_AFP1)
+/* LOAD ROUNDED */
+    F(0xb344, LEDBR,   RRF_e, Z,   0, f2, new, e1, ledb, 0, IF_BFP)
+    F(0xb345, LDXBR,   RRF_e, Z,   x2h, x2l, new, f1, ldxb, 0, IF_BFP)
+    F(0xb346, LEXBR,   RRF_e, Z,   x2h, x2l, new, e1, lexb, 0, IF_BFP)
+
+/* LOAD MULTIPLE */
+    C(0x9800, LM,      RS_a,  Z,   0, a2, 0, 0, lm32, 0)
+    C(0xeb98, LMY,     RSY_a, LD,  0, a2, 0, 0, lm32, 0)
+    C(0xeb04, LMG,     RSY_a, Z,   0, a2, 0, 0, lm64, 0)
+/* LOAD MULTIPLE HIGH */
+    C(0xeb96, LMH,     RSY_a, Z,   0, a2, 0, 0, lmh, 0)
+/* LOAD ACCESS MULTIPLE */
+    C(0x9a00, LAM,     RS_a,  Z,   0, a2, 0, 0, lam, 0)
+    C(0xeb9a, LAMY,    RSY_a, LD,  0, a2, 0, 0, lam, 0)
+
+/* MONITOR CALL */
+    C(0xaf00, MC,      SI,    Z,   la1, 0, 0, 0, mc, 0)
+
+/* MOVE */
+    C(0xd200, MVC,     SS_a,  Z,   la1, a2, 0, 0, mvc, 0)
+    C(0xe544, MVHHI,   SIL,   GIE, la1, i2, 0, m1_16, mov2, 0)
+    C(0xe54c, MVHI,    SIL,   GIE, la1, i2, 0, m1_32, mov2, 0)
+    C(0xe548, MVGHI,   SIL,   GIE, la1, i2, 0, m1_64, mov2, 0)
+    C(0x9200, MVI,     SI,    Z,   la1, i2, 0, m1_8, mov2, 0)
+    C(0xeb52, MVIY,    SIY,   LD,  la1, i2, 0, m1_8, mov2, 0)
+/* MOVE INVERSE */
+    C(0xe800, MVCIN,   SS_a,  Z,   la1, a2, 0, 0, mvcin, 0)
+/* MOVE LONG */
+    C(0x0e00, MVCL,    RR_a,  Z,   0, 0, 0, 0, mvcl, 0)
+/* MOVE LONG EXTENDED */
+    C(0xa800, MVCLE,   RS_a,  Z,   0, a2, 0, 0, mvcle, 0)
+/* MOVE LONG UNICODE */
+    C(0xeb8e, MVCLU,   RSY_a, E2,  0, a2, 0, 0, mvclu, 0)
+/* MOVE NUMERICS */
+    C(0xd100, MVN,     SS_a,  Z,   la1, a2, 0, 0, mvn, 0)
+/* MOVE PAGE */
+    C(0xb254, MVPG,    RRE,   Z,   0, 0, 0, 0, mvpg, 0)
+/* MOVE STRING */
+    C(0xb255, MVST,    RRE,   Z,   0, 0, 0, 0, mvst, 0)
+/* MOVE WITH OPTIONAL SPECIFICATION */
+    C(0xc800, MVCOS,   SSF,   MVCOS, la1, a2, 0, 0, mvcos, 0)
+/* MOVE WITH OFFSET */
+    /* Really format SS_b, but we pack both lengths into one argument
+       for the helper call, so we might as well leave one 8-bit field.  */
+    C(0xf100, MVO,     SS_a,  Z,   la1, a2, 0, 0, mvo, 0)
+/* MOVE ZONES */
+    C(0xd300, MVZ,     SS_a,  Z,   la1, a2, 0, 0, mvz, 0)
+
+/* MULTIPLY */
+    C(0x1c00, MR,      RR_a,  Z,   r1p1_32s, r2_32s, new, r1_D32, mul, 0)
+    C(0xb9ec, MGRK,    RRF_a, MIE2,r3_o, r2_o, r1_P, 0, muls128, 0)
+    C(0x5c00, M,       RX_a,  Z,   r1p1_32s, m2_32s, new, r1_D32, mul, 0)
+    C(0xe35c, MFY,     RXY_a, GIE, r1p1_32s, m2_32s, new, r1_D32, mul, 0)
+    C(0xe384, MG,      RXY_a, MIE2,r1p1_o, m2_64, r1_P, 0, muls128, 0)
+    F(0xb317, MEEBR,   RRE,   Z,   e1, e2, new, e1, meeb, 0, IF_BFP)
+    F(0xb31c, MDBR,    RRE,   Z,   f1, f2, new, f1, mdb, 0, IF_BFP)
+    F(0xb34c, MXBR,    RRE,   Z,   x2h, x2l, x1, x1, mxb, 0, IF_BFP)
+    F(0xb30c, MDEBR,   RRE,   Z,   f1, e2, new, f1, mdeb, 0, IF_BFP)
+    F(0xb307, MXDBR,   RRE,   Z,   0, f2, x1, x1, mxdb, 0, IF_BFP)
+    F(0xed17, MEEB,    RXE,   Z,   e1, m2_32u, new, e1, meeb, 0, IF_BFP)
+    F(0xed1c, MDB,     RXE,   Z,   f1, m2_64, new, f1, mdb, 0, IF_BFP)
+    F(0xed0c, MDEB,    RXE,   Z,   f1, m2_32u, new, f1, mdeb, 0, IF_BFP)
+    F(0xed07, MXDB,    RXE,   Z,   0, m2_64, x1, x1, mxdb, 0, IF_BFP)
+/* MULTIPLY HALFWORD */
+    C(0x4c00, MH,      RX_a,  Z,   r1_o, m2_16s, new, r1_32, mul, 0)
+    C(0xe37c, MHY,     RXY_a, GIE, r1_o, m2_16s, new, r1_32, mul, 0)
+    C(0xe33c, MGH,     RXY_a, MIE2,r1_o, m2_16s, r1, 0, mul, 0)
+/* MULTIPLY HALFWORD IMMEDIATE */
+    C(0xa70c, MHI,     RI_a,  Z,   r1_o, i2, new, r1_32, mul, 0)
+    C(0xa70d, MGHI,    RI_a,  Z,   r1_o, i2, r1, 0, mul, 0)
+/* MULTIPLY LOGICAL */
+    C(0xb996, MLR,     RRE,   Z,   r1p1_32u, r2_32u, new, r1_D32, mul, 0)
+    C(0xe396, ML,      RXY_a, Z,   r1p1_32u, m2_32u, new, r1_D32, mul, 0)
+    C(0xb986, MLGR,    RRE,   Z,   r1p1, r2_o, r1_P, 0, mul128, 0)
+    C(0xe386, MLG,     RXY_a, Z,   r1p1, m2_64, r1_P, 0, mul128, 0)
+/* MULTIPLY SINGLE */
+    C(0xb252, MSR,     RRE,   Z,   r1_o, r2_o, new, r1_32, mul, 0)
+    C(0xb9fd, MSRKC,   RRF_a, MIE2,r3_32s, r2_32s, new, r1_32, mul, muls32)
+    C(0x7100, MS,      RX_a,  Z,   r1_o, m2_32s, new, r1_32, mul, 0)
+    C(0xe351, MSY,     RXY_a, LD,  r1_o, m2_32s, new, r1_32, mul, 0)
+    C(0xe353, MSC,     RXY_a, MIE2,r1_32s, m2_32s, new, r1_32, mul, muls32)
+    C(0xb90c, MSGR,    RRE,   Z,   r1_o, r2_o, r1, 0, mul, 0)
+    C(0xb9ed, MSGRKC,  RRF_a, MIE2,r3_o, r2_o, new_P, out2_r1, muls128, muls64)
+    C(0xb91c, MSGFR,   RRE,   Z,   r1_o, r2_32s, r1, 0, mul, 0)
+    C(0xe30c, MSG,     RXY_a, Z,   r1_o, m2_64, r1, 0, mul, 0)
+    C(0xe383, MSGC,    RXY_a, MIE2,r1_o, m2_64, new_P, out2_r1, muls128, muls64)
+    C(0xe31c, MSGF,    RXY_a, Z,   r1_o, m2_32s, r1, 0, mul, 0)
+/* MULTIPLY SINGLE IMMEDIATE */
+    C(0xc201, MSFI,    RIL_a, GIE, r1_o, i2, new, r1_32, mul, 0)
+    C(0xc200, MSGFI,   RIL_a, GIE, r1_o, i2, r1, 0, mul, 0)
+
+/* MULTIPLY AND ADD */
+    F(0xb30e, MAEBR,   RRD,   Z,   e1, e2, new, e1, maeb, 0, IF_BFP)
+    F(0xb31e, MADBR,   RRD,   Z,   f1, f2, new, f1, madb, 0, IF_BFP)
+    F(0xed0e, MAEB,    RXF,   Z,   e1, m2_32u, new, e1, maeb, 0, IF_BFP)
+    F(0xed1e, MADB,    RXF,   Z,   f1, m2_64, new, f1, madb, 0, IF_BFP)
+/* MULTIPLY AND SUBTRACT */
+    F(0xb30f, MSEBR,   RRD,   Z,   e1, e2, new, e1, mseb, 0, IF_BFP)
+    F(0xb31f, MSDBR,   RRD,   Z,   f1, f2, new, f1, msdb, 0, IF_BFP)
+    F(0xed0f, MSEB,    RXF,   Z,   e1, m2_32u, new, e1, mseb, 0, IF_BFP)
+    F(0xed1f, MSDB,    RXF,   Z,   f1, m2_64, new, f1, msdb, 0, IF_BFP)
+
+/* OR */
+    C(0x1600, OR,      RR_a,  Z,   r1, r2, new, r1_32, or, nz32)
+    C(0xb9f6, ORK,     RRF_a, DO,  r2, r3, new, r1_32, or, nz32)
+    C(0x5600, O,       RX_a,  Z,   r1, m2_32s, new, r1_32, or, nz32)
+    C(0xe356, OY,      RXY_a, LD,  r1, m2_32s, new, r1_32, or, nz32)
+    C(0xb981, OGR,     RRE,   Z,   r1, r2, r1, 0, or, nz64)
+    C(0xb9e6, OGRK,    RRF_a, DO,  r2, r3, r1, 0, or, nz64)
+    C(0xe381, OG,      RXY_a, Z,   r1, m2_64, r1, 0, or, nz64)
+    C(0xd600, OC,      SS_a,  Z,   la1, a2, 0, 0, oc, 0)
+/* OR IMMEDIATE */
+    D(0xc00c, OIHF,    RIL_a, EI,  r1_o, i2_32u, r1, 0, ori, 0, 0x2020)
+    D(0xc00d, OILF,    RIL_a, EI,  r1_o, i2_32u, r1, 0, ori, 0, 0x2000)
+    D(0xa508, OIHH,    RI_a,  Z,   r1_o, i2_16u, r1, 0, ori, 0, 0x1030)
+    D(0xa509, OIHL,    RI_a,  Z,   r1_o, i2_16u, r1, 0, ori, 0, 0x1020)
+    D(0xa50a, OILH,    RI_a,  Z,   r1_o, i2_16u, r1, 0, ori, 0, 0x1010)
+    D(0xa50b, OILL,    RI_a,  Z,   r1_o, i2_16u, r1, 0, ori, 0, 0x1000)
+    D(0x9600, OI,      SI,    Z,   la1, i2_8u, new, 0, oi, nz64, MO_UB)
+    D(0xeb56, OIY,     SIY,   LD,  la1, i2_8u, new, 0, oi, nz64, MO_UB)
+
+/* PACK */
+    /* Really format SS_b, but we pack both lengths into one argument
+       for the helper call, so we might as well leave one 8-bit field.  */
+    C(0xf200, PACK,    SS_a,  Z,   la1, a2, 0, 0, pack, 0)
+/* PACK ASCII */
+    C(0xe900, PKA,     SS_f,  E2,  la1, a2, 0, 0, pka, 0)
+/* PACK UNICODE */
+    C(0xe100, PKU,     SS_f,  E2,  la1, a2, 0, 0, pku, 0)
+
+/* PREFETCH */
+    /* Implemented as nops of course.  */
+    C(0xe336, PFD,     RXY_b, GIE, 0, 0, 0, 0, 0, 0)
+    C(0xc602, PFDRL,   RIL_c, GIE, 0, 0, 0, 0, 0, 0)
+/* PERFORM PROCESSOR ASSIST */
+    /* Implemented as nop of course.  */
+    C(0xb2e8, PPA,     RRF_c, PPA, 0, 0, 0, 0, 0, 0)
+
+/* POPULATION COUNT */
+    C(0xb9e1, POPCNT,  RRE,   PC,  0, r2_o, r1, 0, popcnt, nz64)
+
+/* ROTATE LEFT SINGLE LOGICAL */
+    C(0xeb1d, RLL,     RSY_a, Z,   r3_o, sh32, new, r1_32, rll32, 0)
+    C(0xeb1c, RLLG,    RSY_a, Z,   r3_o, sh64, r1, 0, rll64, 0)
+
+/* ROTATE THEN INSERT SELECTED BITS */
+    C(0xec55, RISBG,   RIE_f, GIE, 0, r2, r1, 0, risbg, s64)
+    C(0xec59, RISBGN,  RIE_f, MIE, 0, r2, r1, 0, risbg, 0)
+    C(0xec5d, RISBHG,  RIE_f, HW,  0, r2, r1, 0, risbg, 0)
+    C(0xec51, RISBLG,  RIE_f, HW,  0, r2, r1, 0, risbg, 0)
+/* ROTATE_THEN <OP> SELECTED BITS */
+    C(0xec54, RNSBG,   RIE_f, GIE, 0, r2, r1, 0, rosbg, 0)
+    C(0xec56, ROSBG,   RIE_f, GIE, 0, r2, r1, 0, rosbg, 0)
+    C(0xec57, RXSBG,   RIE_f, GIE, 0, r2, r1, 0, rosbg, 0)
+
+/* SEARCH STRING */
+    C(0xb25e, SRST,    RRE,   Z,   0, 0, 0, 0, srst, 0)
+/* SEARCH STRING UNICODE */
+    C(0xb9be, SRSTU,   RRE,   ETF3, 0, 0, 0, 0, srstu, 0)
+
+/* SET ACCESS */
+    C(0xb24e, SAR,     RRE,   Z,   0, r2_o, 0, 0, sar, 0)
+/* SET ADDRESSING MODE */
+    D(0x010c, SAM24,   E,     Z,   0, 0, 0, 0, sam, 0, 0)
+    D(0x010d, SAM31,   E,     Z,   0, 0, 0, 0, sam, 0, 1)
+    D(0x010e, SAM64,   E,     Z,   0, 0, 0, 0, sam, 0, 3)
+/* SET FPC */
+    F(0xb384, SFPC,    RRE,   Z,   0, r1_o, 0, 0, sfpc, 0, IF_BFP)
+/* SET FPC AND SIGNAL */
+    F(0xb385, SFASR,   RRE,   IEEEE_SIM, 0, r1_o, 0, 0, sfas, 0, IF_DFP)
+/* SET BFP ROUNDING MODE */
+    F(0xb299, SRNM,    S,     Z,   la2, 0, 0, 0, srnm, 0, IF_BFP)
+    F(0xb2b8, SRNMB,   S,     FPE, la2, 0, 0, 0, srnmb, 0, IF_BFP)
+/* SET DFP ROUNDING MODE */
+    F(0xb2b9, SRNMT,   S,     DFPR, la2, 0, 0, 0, srnmt, 0, IF_DFP)
+/* SET PROGRAM MASK */
+    C(0x0400, SPM,     RR_a,  Z,   r1, 0, 0, 0, spm, 0)
+
+/* SHIFT LEFT SINGLE */
+    D(0x8b00, SLA,     RS_a,  Z,   r1, sh32, new, r1_32, sla, 0, 31)
+    D(0xebdd, SLAK,    RSY_a, DO,  r3, sh32, new, r1_32, sla, 0, 31)
+    D(0xeb0b, SLAG,    RSY_a, Z,   r3, sh64, r1, 0, sla, 0, 63)
+/* SHIFT LEFT SINGLE LOGICAL */
+    C(0x8900, SLL,     RS_a,  Z,   r1_o, sh32, new, r1_32, sll, 0)
+    C(0xebdf, SLLK,    RSY_a, DO,  r3_o, sh32, new, r1_32, sll, 0)
+    C(0xeb0d, SLLG,    RSY_a, Z,   r3_o, sh64, r1, 0, sll, 0)
+/* SHIFT RIGHT SINGLE */
+    C(0x8a00, SRA,     RS_a,  Z,   r1_32s, sh32, new, r1_32, sra, s32)
+    C(0xebdc, SRAK,    RSY_a, DO,  r3_32s, sh32, new, r1_32, sra, s32)
+    C(0xeb0a, SRAG,    RSY_a, Z,   r3_o, sh64, r1, 0, sra, s64)
+/* SHIFT RIGHT SINGLE LOGICAL */
+    C(0x8800, SRL,     RS_a,  Z,   r1_32u, sh32, new, r1_32, srl, 0)
+    C(0xebde, SRLK,    RSY_a, DO,  r3_32u, sh32, new, r1_32, srl, 0)
+    C(0xeb0c, SRLG,    RSY_a, Z,   r3_o, sh64, r1, 0, srl, 0)
+/* SHIFT LEFT DOUBLE */
+    D(0x8f00, SLDA,    RS_a,  Z,   r1_D32, sh64, new, r1_D32, sla, 0, 31)
+/* SHIFT LEFT DOUBLE LOGICAL */
+    C(0x8d00, SLDL,    RS_a,  Z,   r1_D32, sh64, new, r1_D32, sll, 0)
+/* SHIFT RIGHT DOUBLE */
+    C(0x8e00, SRDA,    RS_a,  Z,   r1_D32, sh64, new, r1_D32, sra, s64)
+/* SHIFT RIGHT DOUBLE LOGICAL */
+    C(0x8c00, SRDL,    RS_a,  Z,   r1_D32, sh64, new, r1_D32, srl, 0)
+
+/* SQUARE ROOT */
+    F(0xb314, SQEBR,   RRE,   Z,   0, e2, new, e1, sqeb, 0, IF_BFP)
+    F(0xb315, SQDBR,   RRE,   Z,   0, f2, new, f1, sqdb, 0, IF_BFP)
+    F(0xb316, SQXBR,   RRE,   Z,   x2h, x2l, new_P, x1, sqxb, 0, IF_BFP)
+    F(0xed14, SQEB,    RXE,   Z,   0, m2_32u, new, e1, sqeb, 0, IF_BFP)
+    F(0xed15, SQDB,    RXE,   Z,   0, m2_64, new, f1, sqdb, 0, IF_BFP)
+
+/* STORE */
+    C(0x5000, ST,      RX_a,  Z,   r1_o, a2, 0, 0, st32, 0)
+    C(0xe350, STY,     RXY_a, LD,  r1_o, a2, 0, 0, st32, 0)
+    C(0xe324, STG,     RXY_a, Z,   r1_o, a2, 0, 0, st64, 0)
+    F(0x6000, STD,     RX_a,  Z,   f1, a2, 0, 0, st64, 0, IF_AFP1)
+    F(0xed67, STDY,    RXY_a, LD,  f1, a2, 0, 0, st64, 0, IF_AFP1)
+    F(0x7000, STE,     RX_a,  Z,   e1, a2, 0, 0, st32, 0, IF_AFP1)
+    F(0xed66, STEY,    RXY_a, LD,  e1, a2, 0, 0, st32, 0, IF_AFP1)
+/* STORE RELATIVE LONG */
+    C(0xc40f, STRL,    RIL_b, GIE, r1_o, ri2, 0, 0, st32, 0)
+    C(0xc40b, STGRL,   RIL_b, GIE, r1_o, ri2, 0, 0, st64, 0)
+/* STORE CHARACTER */
+    C(0x4200, STC,     RX_a,  Z,   r1_o, a2, 0, 0, st8, 0)
+    C(0xe372, STCY,    RXY_a, LD,  r1_o, a2, 0, 0, st8, 0)
+/* STORE CHARACTER HIGH */
+    C(0xe3c3, STCH,    RXY_a, HW,  r1_sr32, a2, 0, 0, st8, 0)
+/* STORE CHARACTERS UNDER MASK */
+    D(0xbe00, STCM,    RS_b,  Z,   r1_o, a2, 0, 0, stcm, 0, 0)
+    D(0xeb2d, STCMY,   RSY_b, LD,  r1_o, a2, 0, 0, stcm, 0, 0)
+    D(0xeb2c, STCMH,   RSY_b, Z,   r1_o, a2, 0, 0, stcm, 0, 32)
+/* STORE HALFWORD */
+    C(0x4000, STH,     RX_a,  Z,   r1_o, a2, 0, 0, st16, 0)
+    C(0xe370, STHY,    RXY_a, LD,  r1_o, a2, 0, 0, st16, 0)
+/* STORE HALFWORD HIGH */
+    C(0xe3c7, STHH,    RXY_a, HW,  r1_sr32, a2, 0, 0, st16, 0)
+/* STORE HALFWORD RELATIVE LONG */
+    C(0xc407, STHRL,   RIL_b, GIE, r1_o, ri2, 0, 0, st16, 0)
+/* STORE HIGH */
+    C(0xe3cb, STFH,    RXY_a, HW,  r1_sr32, a2, 0, 0, st32, 0)
+/* STORE ON CONDITION */
+    D(0xebf3, STOC,    RSY_b, LOC, 0, 0, 0, 0, soc, 0, 0)
+    D(0xebe3, STOCG,   RSY_b, LOC, 0, 0, 0, 0, soc, 0, 1)
+/* STORE HIGH ON CONDITION */
+    D(0xebe1, STOCFH,  RSY_b, LOC2, 0, 0, 0, 0, soc, 0, 2)
+/* STORE REVERSED */
+    C(0xe33f, STRVH,   RXY_a, Z,   la2, r1_16u, new, m1_16, rev16, 0)
+    C(0xe33e, STRV,    RXY_a, Z,   la2, r1_32u, new, m1_32, rev32, 0)
+    C(0xe32f, STRVG,   RXY_a, Z,   la2, r1_o, new, m1_64, rev64, 0)
+
+/* STORE CLOCK */
+    F(0xb205, STCK,    S,     Z,   la2, 0, new, m1_64, stck, 0, IF_IO)
+    F(0xb27c, STCKF,   S,     SCF, la2, 0, new, m1_64, stck, 0, IF_IO)
+/* STORE CLOCK EXTENDED */
+    F(0xb278, STCKE,   S,     Z,   0, a2, 0, 0, stcke, 0, IF_IO)
+
+/* STORE FACILITY LIST EXTENDED */
+    C(0xb2b0, STFLE,   S,  SFLE,   0, a2, 0, 0, stfle, 0)
+/* STORE FPC */
+    F(0xb29c, STFPC,   S,     Z,   0, a2, new, m2_32, efpc, 0, IF_BFP)
+
+/* STORE MULTIPLE */
+    D(0x9000, STM,     RS_a,  Z,   0, a2, 0, 0, stm, 0, 4)
+    D(0xeb90, STMY,    RSY_a, LD,  0, a2, 0, 0, stm, 0, 4)
+    D(0xeb24, STMG,    RSY_a, Z,   0, a2, 0, 0, stm, 0, 8)
+/* STORE MULTIPLE HIGH */
+    C(0xeb26, STMH,    RSY_a, Z,   0, a2, 0, 0, stmh, 0)
+/* STORE ACCESS MULTIPLE */
+    C(0x9b00, STAM,    RS_a,  Z,   0, a2, 0, 0, stam, 0)
+    C(0xeb9b, STAMY,   RSY_a, LD,  0, a2, 0, 0, stam, 0)
+/* STORE PAIR TO QUADWORD */
+    C(0xe38e, STPQ,    RXY_a, Z,   0, a2, r1_P, 0, stpq, 0)
+
+/* SUBTRACT */
+    C(0x1b00, SR,      RR_a,  Z,   r1, r2, new, r1_32, sub, subs32)
+    C(0xb9f9, SRK,     RRF_a, DO,  r2, r3, new, r1_32, sub, subs32)
+    C(0x5b00, S,       RX_a,  Z,   r1, m2_32s, new, r1_32, sub, subs32)
+    C(0xe35b, SY,      RXY_a, LD,  r1, m2_32s, new, r1_32, sub, subs32)
+    C(0xb909, SGR,     RRE,   Z,   r1, r2, r1, 0, sub, subs64)
+    C(0xb919, SGFR,    RRE,   Z,   r1, r2_32s, r1, 0, sub, subs64)
+    C(0xb9e9, SGRK,    RRF_a, DO,  r2, r3, r1, 0, sub, subs64)
+    C(0xe309, SG,      RXY_a, Z,   r1, m2_64, r1, 0, sub, subs64)
+    C(0xe319, SGF,     RXY_a, Z,   r1, m2_32s, r1, 0, sub, subs64)
+    F(0xb30b, SEBR,    RRE,   Z,   e1, e2, new, e1, seb, f32, IF_BFP)
+    F(0xb31b, SDBR,    RRE,   Z,   f1, f2, new, f1, sdb, f64, IF_BFP)
+    F(0xb34b, SXBR,    RRE,   Z,   x2h, x2l, x1, x1, sxb, f128, IF_BFP)
+    F(0xed0b, SEB,     RXE,   Z,   e1, m2_32u, new, e1, seb, f32, IF_BFP)
+    F(0xed1b, SDB,     RXE,   Z,   f1, m2_64, new, f1, sdb, f64, IF_BFP)
+/* SUBTRACT HALFWORD */
+    C(0x4b00, SH,      RX_a,  Z,   r1, m2_16s, new, r1_32, sub, subs32)
+    C(0xe37b, SHY,     RXY_a, LD,  r1, m2_16s, new, r1_32, sub, subs32)
+    C(0xe339, SGH,     RXY_a, MIE2,r1, m2_16s, r1, 0, sub, subs64)
+/* SUBTRACT HIGH */
+    C(0xb9c9, SHHHR,   RRF_a, HW,  r2_sr32, r3_sr32, new, r1_32h, sub, subs32)
+    C(0xb9d9, SHHLR,   RRF_a, HW,  r2_sr32, r3, new, r1_32h, sub, subs32)
+/* SUBTRACT LOGICAL */
+    C(0x1f00, SLR,     RR_a,  Z,   r1_32u, r2_32u, new, r1_32, sub, subu32)
+    C(0xb9fb, SLRK,    RRF_a, DO,  r2_32u, r3_32u, new, r1_32, sub, subu32)
+    C(0x5f00, SL,      RX_a,  Z,   r1_32u, m2_32u, new, r1_32, sub, subu32)
+    C(0xe35f, SLY,     RXY_a, LD,  r1_32u, m2_32u, new, r1_32, sub, subu32)
+    C(0xb90b, SLGR,    RRE,   Z,   r1, r2, r1, 0, subu64, subu64)
+    C(0xb91b, SLGFR,   RRE,   Z,   r1, r2_32u, r1, 0, subu64, subu64)
+    C(0xb9eb, SLGRK,   RRF_a, DO,  r2, r3, r1, 0, subu64, subu64)
+    C(0xe30b, SLG,     RXY_a, Z,   r1, m2_64, r1, 0, subu64, subu64)
+    C(0xe31b, SLGF,    RXY_a, Z,   r1, m2_32u, r1, 0, subu64, subu64)
+/* SUBTRACT LOCICAL HIGH */
+    C(0xb9cb, SLHHHR,  RRF_a, HW,  r2_sr32, r3_sr32, new, r1_32h, sub, subu32)
+    C(0xb9db, SLHHLR,  RRF_a, HW,  r2_sr32, r3_32u, new, r1_32h, sub, subu32)
+/* SUBTRACT LOGICAL IMMEDIATE */
+    C(0xc205, SLFI,    RIL_a, EI,  r1_32u, i2_32u, new, r1_32, sub, subu32)
+    C(0xc204, SLGFI,   RIL_a, EI,  r1, i2_32u, r1, 0, subu64, subu64)
+/* SUBTRACT LOGICAL WITH BORROW */
+    C(0xb999, SLBR,    RRE,   Z,   r1_32u, r2_32u, new, r1_32, subb32, subu32)
+    C(0xb989, SLBGR,   RRE,   Z,   r1, r2, r1, 0, subb64, subu64)
+    C(0xe399, SLB,     RXY_a, Z,   r1_32u, m2_32u, new, r1_32, subb32, subu32)
+    C(0xe389, SLBG,    RXY_a, Z,   r1, m2_64, r1, 0, subb64, subu64)
+
+/* SUPERVISOR CALL */
+    C(0x0a00, SVC,     I,     Z,   0, 0, 0, 0, svc, 0)
+
+/* TEST ADDRESSING MODE */
+    C(0x010b, TAM,     E,     Z,   0, 0, 0, 0, tam, 0)
+
+/* TEST AND SET */
+    C(0x9300, TS,      S,     Z,   0, a2, 0, 0, ts, 0)
+
+/* TEST DATA CLASS */
+    F(0xed10, TCEB,    RXE,   Z,   e1, a2, 0, 0, tceb, 0, IF_BFP)
+    F(0xed11, TCDB,    RXE,   Z,   f1, a2, 0, 0, tcdb, 0, IF_BFP)
+    F(0xed12, TCXB,    RXE,   Z,   0, a2, x1, 0, tcxb, 0, IF_BFP)
+
+/* TEST DECIMAL */
+    C(0xebc0, TP,      RSL,   E2,  la1, 0, 0, 0, tp, 0)
+
+/* TEST UNDER MASK */
+    C(0x9100, TM,      SI,    Z,   m1_8u, i2_8u, 0, 0, 0, tm32)
+    C(0xeb51, TMY,     SIY,   LD,  m1_8u, i2_8u, 0, 0, 0, tm32)
+    D(0xa702, TMHH,    RI_a,  Z,   r1_o, i2_16u_shl, 0, 0, 0, tm64, 48)
+    D(0xa703, TMHL,    RI_a,  Z,   r1_o, i2_16u_shl, 0, 0, 0, tm64, 32)
+    D(0xa700, TMLH,    RI_a,  Z,   r1_o, i2_16u_shl, 0, 0, 0, tm64, 16)
+    D(0xa701, TMLL,    RI_a,  Z,   r1_o, i2_16u_shl, 0, 0, 0, tm64, 0)
+
+/* TRANSLATE */
+    C(0xdc00, TR,      SS_a,  Z,   la1, a2, 0, 0, tr, 0)
+/* TRANSLATE AND TEST */
+    C(0xdd00, TRT,     SS_a,  Z,   la1, a2, 0, 0, trt, 0)
+/* TRANSLATE AND TEST REVERSE */
+    C(0xd000, TRTR,    SS_a,  ETF3, la1, a2, 0, 0, trtr, 0)
+/* TRANSLATE EXTENDED */
+    C(0xb2a5, TRE,     RRE,   Z,   0, r2, r1_P, 0, tre, 0)
+
+/* TRANSLATE ONE TO ONE */
+    C(0xb993, TROO,    RRF_c, E2,  0, 0, 0, 0, trXX, 0)
+/* TRANSLATE ONE TO TWO */
+    C(0xb992, TROT,    RRF_c, E2,  0, 0, 0, 0, trXX, 0)
+/* TRANSLATE TWO TO ONE */
+    C(0xb991, TRTO,    RRF_c, E2,  0, 0, 0, 0, trXX, 0)
+/* TRANSLATE TWO TO TWO */
+    C(0xb990, TRTT,    RRF_c, E2,  0, 0, 0, 0, trXX, 0)
+
+/* UNPACK */
+    /* Really format SS_b, but we pack both lengths into one argument
+       for the helper call, so we might as well leave one 8-bit field.  */
+    C(0xf300, UNPK,    SS_a,  Z,   la1, a2, 0, 0, unpk, 0)
+/* UNPACK ASCII */
+    C(0xea00, UNPKA,   SS_a,  E2,  la1, a2, 0, 0, unpka, 0)
+/* UNPACK UNICODE */
+    C(0xe200, UNPKU,   SS_a,  E2,  la1, a2, 0, 0, unpku, 0)
+
+/* MSA Instructions */
+    D(0xb91e, KMAC,    RRE,   MSA,  0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMAC)
+    D(0xb928, PCKMO,   RRE,   MSA3, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_PCKMO)
+    D(0xb92a, KMF,     RRE,   MSA4, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMF)
+    D(0xb92b, KMO,     RRE,   MSA4, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMO)
+    D(0xb92c, PCC,     RRE,   MSA4, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_PCC)
+    D(0xb92d, KMCTR,   RRF_b, MSA4, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMCTR)
+    D(0xb92e, KM,      RRE,   MSA,  0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KM)
+    D(0xb92f, KMC,     RRE,   MSA,  0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMC)
+    D(0xb929, KMA,     RRF_b, MSA8, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KMA)
+    D(0xb93c, PPNO,    RRE,   MSA5, 0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_PPNO)
+    D(0xb93e, KIMD,    RRE,   MSA,  0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KIMD)
+    D(0xb93f, KLMD,    RRE,   MSA,  0, 0, 0, 0, msa, 0, S390_FEAT_TYPE_KLMD)
+
+/* === Vector Support Instructions === */
+
+/* VECTOR BIT PERMUTE */
+    E(0xe785, VBPERM,  VRR_c, VE,  0, 0, 0, 0, vbperm, 0, 0, IF_VEC)
+/* VECTOR GATHER ELEMENT */
+    E(0xe713, VGEF,    VRV,   V,   la2, 0, 0, 0, vge, 0, ES_32, IF_VEC)
+    E(0xe712, VGEG,    VRV,   V,   la2, 0, 0, 0, vge, 0, ES_64, IF_VEC)
+/* VECTOR GENERATE BYTE MASK */
+    F(0xe744, VGBM,    VRI_a, V,   0, 0, 0, 0, vgbm, 0, IF_VEC)
+/* VECTOR GENERATE MASK */
+    F(0xe746, VGM,     VRI_b, V,   0, 0, 0, 0, vgm, 0, IF_VEC)
+/* VECTOR LOAD */
+    F(0xe706, VL,      VRX,   V,   la2, 0, 0, 0, vl, 0, IF_VEC)
+    F(0xe756, VLR,     VRR_a, V,   0, 0, 0, 0, vlr, 0, IF_VEC)
+/* VECTOR LOAD AND REPLICATE */
+    F(0xe705, VLREP,   VRX,   V,   la2, 0, 0, 0, vlrep, 0, IF_VEC)
+/* VECTOR LOAD ELEMENT */
+    E(0xe700, VLEB,    VRX,   V,   la2, 0, 0, 0, vle, 0, ES_8, IF_VEC)
+    E(0xe701, VLEH,    VRX,   V,   la2, 0, 0, 0, vle, 0, ES_16, IF_VEC)
+    E(0xe703, VLEF,    VRX,   V,   la2, 0, 0, 0, vle, 0, ES_32, IF_VEC)
+    E(0xe702, VLEG,    VRX,   V,   la2, 0, 0, 0, vle, 0, ES_64, IF_VEC)
+/* VECTOR LOAD ELEMENT IMMEDIATE */
+    E(0xe740, VLEIB,   VRI_a, V,   0, 0, 0, 0, vlei, 0, ES_8, IF_VEC)
+    E(0xe741, VLEIH,   VRI_a, V,   0, 0, 0, 0, vlei, 0, ES_16, IF_VEC)
+    E(0xe743, VLEIF,   VRI_a, V,   0, 0, 0, 0, vlei, 0, ES_32, IF_VEC)
+    E(0xe742, VLEIG,   VRI_a, V,   0, 0, 0, 0, vlei, 0, ES_64, IF_VEC)
+/* VECTOR LOAD GR FROM VR ELEMENT */
+    F(0xe721, VLGV,    VRS_c, V,   la2, 0, r1, 0, vlgv, 0, IF_VEC)
+/* VECTOR LOAD LOGICAL ELEMENT AND ZERO */
+    F(0xe704, VLLEZ,   VRX,   V,   la2, 0, 0, 0, vllez, 0, IF_VEC)
+/* VECTOR LOAD MULTIPLE */
+    F(0xe736, VLM,     VRS_a, V,   la2, 0, 0, 0, vlm, 0, IF_VEC)
+/* VECTOR LOAD TO BLOCK BOUNDARY */
+    F(0xe707, VLBB,    VRX,   V,   la2, 0, 0, 0, vlbb, 0, IF_VEC)
+/* VECTOR LOAD VR ELEMENT FROM GR */
+    F(0xe722, VLVG,    VRS_b, V,   la2, r3, 0, 0, vlvg, 0, IF_VEC)
+/* VECTOR LOAD VR FROM GRS DISJOINT */
+    F(0xe762, VLVGP,   VRR_f, V,   r2, r3, 0, 0, vlvgp, 0, IF_VEC)
+/* VECTOR LOAD WITH LENGTH */
+    F(0xe737, VLL,     VRS_b, V,   la2, r3_32u, 0, 0, vll, 0, IF_VEC)
+/* VECTOR MERGE HIGH */
+    F(0xe761, VMRH,    VRR_c, V,   0, 0, 0, 0, vmr, 0, IF_VEC)
+/* VECTOR MERGE LOW */
+    F(0xe760, VMRL,    VRR_c, V,   0, 0, 0, 0, vmr, 0, IF_VEC)
+/* VECTOR PACK */
+    F(0xe794, VPK,     VRR_c, V,   0, 0, 0, 0, vpk, 0, IF_VEC)
+/* VECTOR PACK SATURATE */
+    F(0xe797, VPKS,    VRR_b, V,   0, 0, 0, 0, vpk, 0, IF_VEC)
+/* VECTOR PACK LOGICAL SATURATE */
+    F(0xe795, VPKLS,   VRR_b, V,   0, 0, 0, 0, vpk, 0, IF_VEC)
+    F(0xe78c, VPERM,   VRR_e, V,   0, 0, 0, 0, vperm, 0, IF_VEC)
+/* VECTOR PERMUTE DOUBLEWORD IMMEDIATE */
+    F(0xe784, VPDI,    VRR_c, V,   0, 0, 0, 0, vpdi, 0, IF_VEC)
+/* VECTOR REPLICATE */
+    F(0xe74d, VREP,    VRI_c, V,   0, 0, 0, 0, vrep, 0, IF_VEC)
+/* VECTOR REPLICATE IMMEDIATE */
+    F(0xe745, VREPI,   VRI_a, V,   0, 0, 0, 0, vrepi, 0, IF_VEC)
+/* VECTOR SCATTER ELEMENT */
+    E(0xe71b, VSCEF,   VRV,   V,   la2, 0, 0, 0, vsce, 0, ES_32, IF_VEC)
+    E(0xe71a, VSCEG,   VRV,   V,   la2, 0, 0, 0, vsce, 0, ES_64, IF_VEC)
+/* VECTOR SELECT */
+    F(0xe78d, VSEL,    VRR_e, V,   0, 0, 0, 0, vsel, 0, IF_VEC)
+/* VECTOR SIGN EXTEND TO DOUBLEWORD */
+    F(0xe75f, VSEG,    VRR_a, V,   0, 0, 0, 0, vseg, 0, IF_VEC)
+/* VECTOR STORE */
+    F(0xe70e, VST,     VRX,   V,   la2, 0, 0, 0, vst, 0, IF_VEC)
+/* VECTOR STORE ELEMENT */
+    E(0xe708, VSTEB,   VRX,   V,   la2, 0, 0, 0, vste, 0, ES_8, IF_VEC)
+    E(0xe709, VSTEH,   VRX,   V,   la2, 0, 0, 0, vste, 0, ES_16, IF_VEC)
+    E(0xe70b, VSTEF,   VRX,   V,   la2, 0, 0, 0, vste, 0, ES_32, IF_VEC)
+    E(0xe70a, VSTEG,   VRX,   V,   la2, 0, 0, 0, vste, 0, ES_64, IF_VEC)
+/* VECTOR STORE MULTIPLE */
+    F(0xe73e, VSTM,    VRS_a, V,   la2, 0, 0, 0, vstm, 0, IF_VEC)
+/* VECTOR STORE WITH LENGTH */
+    F(0xe73f, VSTL,    VRS_b, V,   la2, r3_32u, 0, 0, vstl, 0, IF_VEC)
+/* VECTOR UNPACK HIGH */
+    F(0xe7d7, VUPH,    VRR_a, V,   0, 0, 0, 0, vup, 0, IF_VEC)
+/* VECTOR UNPACK LOGICAL HIGH */
+    F(0xe7d5, VUPLH,   VRR_a, V,   0, 0, 0, 0, vup, 0, IF_VEC)
+/* VECTOR UNPACK LOW */
+    F(0xe7d6, VUPL,    VRR_a, V,   0, 0, 0, 0, vup, 0, IF_VEC)
+/* VECTOR UNPACK LOGICAL LOW */
+    F(0xe7d4, VUPLL,   VRR_a, V,   0, 0, 0, 0, vup, 0, IF_VEC)
+
+/* === Vector Integer Instructions === */
+
+/* VECTOR ADD */
+    F(0xe7f3, VA,      VRR_c, V,   0, 0, 0, 0, va, 0, IF_VEC)
+/* VECTOR ADD COMPUTE CARRY */
+    F(0xe7f1, VACC,    VRR_c, V,   0, 0, 0, 0, vacc, 0, IF_VEC)
+/* VECTOR ADD WITH CARRY */
+    F(0xe7bb, VAC,     VRR_d, V,   0, 0, 0, 0, vac, 0, IF_VEC)
+/* VECTOR ADD WITH CARRY COMPUTE CARRY */
+    F(0xe7b9, VACCC,   VRR_d, V,   0, 0, 0, 0, vaccc, 0, IF_VEC)
+/* VECTOR AND */
+    F(0xe768, VN,      VRR_c, V,   0, 0, 0, 0, vn, 0, IF_VEC)
+/* VECTOR AND WITH COMPLEMENT */
+    F(0xe769, VNC,     VRR_c, V,   0, 0, 0, 0, vnc, 0, IF_VEC)
+/* VECTOR AVERAGE */
+    F(0xe7f2, VAVG,    VRR_c, V,   0, 0, 0, 0, vavg, 0, IF_VEC)
+/* VECTOR AVERAGE LOGICAL */
+    F(0xe7f0, VAVGL,   VRR_c, V,   0, 0, 0, 0, vavgl, 0, IF_VEC)
+/* VECTOR CHECKSUM */
+    F(0xe766, VCKSM,   VRR_c, V,   0, 0, 0, 0, vcksm, 0, IF_VEC)
+/* VECTOR ELEMENT COMPARE */
+    F(0xe7db, VEC,     VRR_a, V,   0, 0, 0, 0, vec, cmps64, IF_VEC)
+/* VECTOR ELEMENT COMPARE LOGICAL */
+    F(0xe7d9, VECL,    VRR_a, V,   0, 0, 0, 0, vec, cmpu64, IF_VEC)
+/* VECTOR COMPARE EQUAL */
+    E(0xe7f8, VCEQ,    VRR_b, V,   0, 0, 0, 0, vc, 0, TCG_COND_EQ, IF_VEC)
+/* VECTOR COMPARE HIGH */
+    E(0xe7fb, VCH,     VRR_b, V,   0, 0, 0, 0, vc, 0, TCG_COND_GT, IF_VEC)
+/* VECTOR COMPARE HIGH LOGICAL */
+    E(0xe7f9, VCHL,    VRR_b, V,   0, 0, 0, 0, vc, 0, TCG_COND_GTU, IF_VEC)
+/* VECTOR COUNT LEADING ZEROS */
+    F(0xe753, VCLZ,    VRR_a, V,   0, 0, 0, 0, vclz, 0, IF_VEC)
+/* VECTOR COUNT TRAILING ZEROS */
+    F(0xe752, VCTZ,    VRR_a, V,   0, 0, 0, 0, vctz, 0, IF_VEC)
+/* VECTOR EXCLUSIVE OR */
+    F(0xe76d, VX,      VRR_c, V,   0, 0, 0, 0, vx, 0, IF_VEC)
+/* VECTOR GALOIS FIELD MULTIPLY SUM */
+    F(0xe7b4, VGFM,    VRR_c, V,   0, 0, 0, 0, vgfm, 0, IF_VEC)
+/* VECTOR GALOIS FIELD MULTIPLY SUM AND ACCUMULATE */
+    F(0xe7bc, VGFMA,   VRR_d, V,   0, 0, 0, 0, vgfma, 0, IF_VEC)
+/* VECTOR LOAD COMPLEMENT */
+    F(0xe7de, VLC,     VRR_a, V,   0, 0, 0, 0, vlc, 0, IF_VEC)
+/* VECTOR LOAD POSITIVE */
+    F(0xe7df, VLP,     VRR_a, V,   0, 0, 0, 0, vlp, 0, IF_VEC)
+/* VECTOR MAXIMUM */
+    F(0xe7ff, VMX,     VRR_c, V,   0, 0, 0, 0, vmx, 0, IF_VEC)
+/* VECTOR MAXIMUM LOGICAL */
+    F(0xe7fd, VMXL,    VRR_c, V,   0, 0, 0, 0, vmx, 0, IF_VEC)
+/* VECTOR MINIMUM */
+    F(0xe7fe, VMN,     VRR_c, V,   0, 0, 0, 0, vmx, 0, IF_VEC)
+/* VECTOR MINIMUM LOGICAL */
+    F(0xe7fc, VMNL,    VRR_c, V,   0, 0, 0, 0, vmx, 0, IF_VEC)
+/* VECTOR MULTIPLY AND ADD LOW */
+    F(0xe7aa, VMAL,    VRR_d, V,   0, 0, 0, 0, vma, 0, IF_VEC)
+/* VECTOR MULTIPLY AND ADD HIGH */
+    F(0xe7ab, VMAH,    VRR_d, V,   0, 0, 0, 0, vma, 0, IF_VEC)
+/* VECTOR MULTIPLY AND ADD LOGICAL HIGH */
+    F(0xe7a9, VMALH,   VRR_d, V,   0, 0, 0, 0, vma, 0, IF_VEC)
+/* VECTOR MULTIPLY AND ADD EVEN */
+    F(0xe7ae, VMAE,    VRR_d, V,   0, 0, 0, 0, vma, 0, IF_VEC)
+/* VECTOR MULTIPLY AND ADD LOGICAL EVEN */
+    F(0xe7ac, VMALE,   VRR_d, V,   0, 0, 0, 0, vma, 0, IF_VEC)
+/* VECTOR MULTIPLY AND ADD ODD */
+    F(0xe7af, VMAO,    VRR_d, V,   0, 0, 0, 0, vma, 0, IF_VEC)
+/* VECTOR MULTIPLY AND ADD LOGICAL ODD */
+    F(0xe7ad, VMALO,   VRR_d, V,   0, 0, 0, 0, vma, 0, IF_VEC)
+/* VECTOR MULTIPLY HIGH */
+    F(0xe7a3, VMH,     VRR_c, V,   0, 0, 0, 0, vm, 0, IF_VEC)
+/* VECTOR MULTIPLY LOGICAL HIGH */
+    F(0xe7a1, VMLH,    VRR_c, V,   0, 0, 0, 0, vm, 0, IF_VEC)
+/* VECTOR MULTIPLY LOW */
+    F(0xe7a2, VML,     VRR_c, V,   0, 0, 0, 0, vm, 0, IF_VEC)
+/* VECTOR MULTIPLY EVEN */
+    F(0xe7a6, VME,     VRR_c, V,   0, 0, 0, 0, vm, 0, IF_VEC)
+/* VECTOR MULTIPLY LOGICAL EVEN */
+    F(0xe7a4, VMLE,    VRR_c, V,   0, 0, 0, 0, vm, 0, IF_VEC)
+/* VECTOR MULTIPLY ODD */
+    F(0xe7a7, VMO,     VRR_c, V,   0, 0, 0, 0, vm, 0, IF_VEC)
+/* VECTOR MULTIPLY LOGICAL ODD */
+    F(0xe7a5, VMLO,    VRR_c, V,   0, 0, 0, 0, vm, 0, IF_VEC)
+/* VECTOR MULTIPLY SUM LOGICAL */
+    F(0xe7b8, VMSL,    VRR_d, VE,  0, 0, 0, 0, vmsl, 0, IF_VEC)
+/* VECTOR NAND */
+    F(0xe76e, VNN,     VRR_c, VE,  0, 0, 0, 0, vnn, 0, IF_VEC)
+/* VECTOR NOR */
+    F(0xe76b, VNO,     VRR_c, V,   0, 0, 0, 0, vno, 0, IF_VEC)
+/* VECTOR NOT EXCLUSIVE OR */
+    F(0xe76c, VNX,     VRR_c, VE,  0, 0, 0, 0, vnx, 0, IF_VEC)
+/* VECTOR OR */
+    F(0xe76a, VO,      VRR_c, V,   0, 0, 0, 0, vo, 0, IF_VEC)
+/* VECTOR OR WITH COMPLEMENT */
+    F(0xe76f, VOC,     VRR_c, VE,  0, 0, 0, 0, voc, 0, IF_VEC)
+/* VECTOR POPULATION COUNT */
+    F(0xe750, VPOPCT,  VRR_a, V,   0, 0, 0, 0, vpopct, 0, IF_VEC)
+/* VECTOR ELEMENT ROTATE LEFT LOGICAL */
+    F(0xe773, VERLLV,  VRR_c, V,   0, 0, 0, 0, vesv, 0, IF_VEC)
+    F(0xe733, VERLL,   VRS_a, V,   la2, 0, 0, 0, ves, 0, IF_VEC)
+/* VECTOR ELEMENT ROTATE AND INSERT UNDER MASK */
+    F(0xe772, VERIM,   VRI_d, V,   0, 0, 0, 0, verim, 0, IF_VEC)
+/* VECTOR ELEMENT SHIFT LEFT */
+    F(0xe770, VESLV,   VRR_c, V,   0, 0, 0, 0, vesv, 0, IF_VEC)
+    F(0xe730, VESL,    VRS_a, V,   la2, 0, 0, 0, ves, 0, IF_VEC)
+/* VECTOR ELEMENT SHIFT RIGHT ARITHMETIC */
+    F(0xe77a, VESRAV,  VRR_c, V,   0, 0, 0, 0, vesv, 0, IF_VEC)
+    F(0xe73a, VESRA,   VRS_a, V,   la2, 0, 0, 0, ves, 0, IF_VEC)
+/* VECTOR ELEMENT SHIFT RIGHT LOGICAL */
+    F(0xe778, VESRLV,  VRR_c, V,   0, 0, 0, 0, vesv, 0, IF_VEC)
+    F(0xe738, VESRL,   VRS_a, V,   la2, 0, 0, 0, ves, 0, IF_VEC)
+/* VECTOR SHIFT LEFT */
+    F(0xe774, VSL,     VRR_c, V,   0, 0, 0, 0, vsl, 0, IF_VEC)
+/* VECTOR SHIFT LEFT BY BYTE */
+    F(0xe775, VSLB,    VRR_c, V,   0, 0, 0, 0, vsl, 0, IF_VEC)
+/* VECTOR SHIFT LEFT DOUBLE BY BYTE */
+    F(0xe777, VSLDB,   VRI_d, V,   0, 0, 0, 0, vsldb, 0, IF_VEC)
+/* VECTOR SHIFT RIGHT ARITHMETIC */
+    F(0xe77e, VSRA,    VRR_c, V,   0, 0, 0, 0, vsra, 0, IF_VEC)
+/* VECTOR SHIFT RIGHT ARITHMETIC BY BYTE */
+    F(0xe77f, VSRAB,   VRR_c, V,   0, 0, 0, 0, vsra, 0, IF_VEC)
+/* VECTOR SHIFT RIGHT LOGICAL */
+    F(0xe77c, VSRL,    VRR_c, V,   0, 0, 0, 0, vsrl, 0, IF_VEC)
+/* VECTOR SHIFT RIGHT LOGICAL BY BYTE */
+    F(0xe77d, VSRLB,   VRR_c, V,   0, 0, 0, 0, vsrl, 0, IF_VEC)
+/* VECTOR SUBTRACT */
+    F(0xe7f7, VS,      VRR_c, V,   0, 0, 0, 0, vs, 0, IF_VEC)
+/* VECTOR SUBTRACT COMPUTE BORROW INDICATION */
+    F(0xe7f5, VSCBI,   VRR_c, V,   0, 0, 0, 0, vscbi, 0, IF_VEC)
+/* VECTOR SUBTRACT WITH BORROW INDICATION */
+    F(0xe7bf, VSBI,    VRR_d, V,   0, 0, 0, 0, vsbi, 0, IF_VEC)
+/* VECTOR SUBTRACT WITH BORROW COMPUTE BORROW INDICATION */
+    F(0xe7bd, VSBCBI,  VRR_d, V,   0, 0, 0, 0, vsbcbi, 0, IF_VEC)
+/* VECTOR SUM ACROSS DOUBLEWORD */
+    F(0xe765, VSUMG,   VRR_c, V,   0, 0, 0, 0, vsumg, 0, IF_VEC)
+/* VECTOR SUM ACROSS QUADWORD */
+    F(0xe767, VSUMQ,   VRR_c, V,   0, 0, 0, 0, vsumq, 0, IF_VEC)
+/* VECTOR SUM ACROSS WORD */
+    F(0xe764, VSUM,    VRR_c, V,   0, 0, 0, 0, vsum, 0, IF_VEC)
+/* VECTOR TEST UNDER MASK */
+    F(0xe7d8, VTM,     VRR_a, V,   0, 0, 0, 0, vtm, 0, IF_VEC)
+
+/* === Vector String Instructions === */
+
+/* VECTOR FIND ANY ELEMENT EQUAL */
+    F(0xe782, VFAE,    VRR_b, V,   0, 0, 0, 0, vfae, 0, IF_VEC)
+/* VECTOR FIND ELEMENT EQUAL */
+    F(0xe780, VFEE,    VRR_b, V,   0, 0, 0, 0, vfee, 0, IF_VEC)
+/* VECTOR FIND ELEMENT NOT EQUAL */
+    F(0xe781, VFENE,   VRR_b, V,   0, 0, 0, 0, vfene, 0, IF_VEC)
+/* VECTOR ISOLATE STRING */
+    F(0xe75c, VISTR,   VRR_a, V,   0, 0, 0, 0, vistr, 0, IF_VEC)
+/* VECTOR STRING RANGE COMPARE */
+    F(0xe78a, VSTRC,   VRR_d, V,   0, 0, 0, 0, vstrc, 0, IF_VEC)
+
+/* === Vector Floating-Point Instructions */
+
+/* VECTOR FP ADD */
+    F(0xe7e3, VFA,     VRR_c, V,   0, 0, 0, 0, vfa, 0, IF_VEC)
+/* VECTOR FP COMPARE SCALAR */
+    F(0xe7cb, WFC,     VRR_a, V,   0, 0, 0, 0, wfc, 0, IF_VEC)
+/* VECTOR FP COMPARE AND SIGNAL SCALAR */
+    F(0xe7ca, WFK,     VRR_a, V,   0, 0, 0, 0, wfc, 0, IF_VEC)
+/* VECTOR FP COMPARE EQUAL */
+    F(0xe7e8, VFCE,    VRR_c, V,   0, 0, 0, 0, vfc, 0, IF_VEC)
+/* VECTOR FP COMPARE HIGH */
+    F(0xe7eb, VFCH,    VRR_c, V,   0, 0, 0, 0, vfc, 0, IF_VEC)
+/* VECTOR FP COMPARE HIGH OR EQUAL */
+    F(0xe7ea, VFCHE,   VRR_c, V,   0, 0, 0, 0, vfc, 0, IF_VEC)
+/* VECTOR FP CONVERT FROM FIXED 64-BIT */
+    F(0xe7c3, VCDG,    VRR_a, V,   0, 0, 0, 0, vcdg, 0, IF_VEC)
+/* VECTOR FP CONVERT FROM LOGICAL 64-BIT */
+    F(0xe7c1, VCDLG,   VRR_a, V,   0, 0, 0, 0, vcdg, 0, IF_VEC)
+/* VECTOR FP CONVERT TO FIXED 64-BIT */
+    F(0xe7c2, VCGD,    VRR_a, V,   0, 0, 0, 0, vcdg, 0, IF_VEC)
+/* VECTOR FP CONVERT TO LOGICAL 64-BIT */
+    F(0xe7c0, VCLGD,   VRR_a, V,   0, 0, 0, 0, vcdg, 0, IF_VEC)
+/* VECTOR FP DIVIDE */
+    F(0xe7e5, VFD,     VRR_c, V,   0, 0, 0, 0, vfa, 0, IF_VEC)
+/* VECTOR LOAD FP INTEGER */
+    F(0xe7c7, VFI,     VRR_a, V,   0, 0, 0, 0, vcdg, 0, IF_VEC)
+/* VECTOR FP LOAD LENGTHENED */
+    F(0xe7c4, VFLL,    VRR_a, V,   0, 0, 0, 0, vfll, 0, IF_VEC)
+/* VECTOR FP LOAD ROUNDED */
+    F(0xe7c5, VFLR,    VRR_a, V,   0, 0, 0, 0, vcdg, 0, IF_VEC)
+/* VECTOR FP MAXIMUM */
+    F(0xe7ef, VFMAX,   VRR_c, VE,  0, 0, 0, 0, vfmax, 0, IF_VEC)
+/* VECTOR FP MINIMUM */
+    F(0xe7ee, VFMIN,   VRR_c, VE,  0, 0, 0, 0, vfmax, 0, IF_VEC)
+/* VECTOR FP MULTIPLY */
+    F(0xe7e7, VFM,     VRR_c, V,   0, 0, 0, 0, vfa, 0, IF_VEC)
+/* VECTOR FP MULTIPLY AND ADD */
+    F(0xe78f, VFMA,    VRR_e, V,   0, 0, 0, 0, vfma, 0, IF_VEC)
+/* VECTOR FP MULTIPLY AND SUBTRACT */
+    F(0xe78e, VFMS,    VRR_e, V,   0, 0, 0, 0, vfma, 0, IF_VEC)
+/* VECTOR FP NEGATIVE MULTIPLY AND ADD */
+    F(0xe79f, VFNMA,   VRR_e, VE,  0, 0, 0, 0, vfma, 0, IF_VEC)
+/* VECTOR FP NEGATIVE MULTIPLY AND SUBTRACT */
+    F(0xe79e, VFNMS,   VRR_e, VE,   0, 0, 0, 0, vfma, 0, IF_VEC)
+/* VECTOR FP PERFORM SIGN OPERATION */
+    F(0xe7cc, VFPSO,   VRR_a, V,   0, 0, 0, 0, vfpso, 0, IF_VEC)
+/* VECTOR FP SQUARE ROOT */
+    F(0xe7ce, VFSQ,    VRR_a, V,   0, 0, 0, 0, vfsq, 0, IF_VEC)
+/* VECTOR FP SUBTRACT */
+    F(0xe7e2, VFS,     VRR_c, V,   0, 0, 0, 0, vfa, 0, IF_VEC)
+/* VECTOR FP TEST DATA CLASS IMMEDIATE */
+    F(0xe74a, VFTCI,   VRI_e, V,   0, 0, 0, 0, vftci, 0, IF_VEC)
+
+#ifndef CONFIG_USER_ONLY
+/* COMPARE AND SWAP AND PURGE */
+    E(0xb250, CSP,     RRE,   Z,   r1_32u, ra2, r1_P, 0, csp, 0, MO_TEUL, IF_PRIV)
+    E(0xb98a, CSPG,    RRE, DAT_ENH, r1_o, ra2, r1_P, 0, csp, 0, MO_TEQ, IF_PRIV)
+/* DIAGNOSE (KVM hypercall) */
+    F(0x8300, DIAG,    RSI,   Z,   0, 0, 0, 0, diag, 0, IF_PRIV | IF_IO)
+/* INSERT STORAGE KEY EXTENDED */
+    F(0xb229, ISKE,    RRE,   Z,   0, r2_o, new, r1_8, iske, 0, IF_PRIV)
+/* INVALIDATE DAT TABLE ENTRY */
+    F(0xb98e, IPDE,    RRF_b, Z,   r1_o, r2_o, 0, 0, idte, 0, IF_PRIV)
+/* INVALIDATE PAGE TABLE ENTRY */
+    F(0xb221, IPTE,    RRF_a, Z,   r1_o, r2_o, 0, 0, ipte, 0, IF_PRIV)
+/* LOAD CONTROL */
+    F(0xb700, LCTL,    RS_a,  Z,   0, a2, 0, 0, lctl, 0, IF_PRIV)
+    F(0xeb2f, LCTLG,   RSY_a, Z,   0, a2, 0, 0, lctlg, 0, IF_PRIV)
+/* LOAD PROGRAM PARAMETER */
+    F(0xb280, LPP,     S,   LPP,   0, m2_64, 0, 0, lpp, 0, IF_PRIV)
+/* LOAD PSW */
+    F(0x8200, LPSW,    S,     Z,   0, a2, 0, 0, lpsw, 0, IF_PRIV)
+/* LOAD PSW EXTENDED */
+    F(0xb2b2, LPSWE,   S,     Z,   0, a2, 0, 0, lpswe, 0, IF_PRIV)
+/* LOAD REAL ADDRESS */
+    F(0xb100, LRA,     RX_a,  Z,   0, a2, r1, 0, lra, 0, IF_PRIV)
+    F(0xe313, LRAY,    RXY_a, LD,  0, a2, r1, 0, lra, 0, IF_PRIV)
+    F(0xe303, LRAG,    RXY_a, Z,   0, a2, r1, 0, lra, 0, IF_PRIV)
+/* LOAD USING REAL ADDRESS */
+    E(0xb24b, LURA,    RRE,   Z,   0, ra2, new, r1_32, lura, 0, MO_TEUL, IF_PRIV)
+    E(0xb905, LURAG,   RRE,   Z,   0, ra2, r1, 0, lura, 0, MO_TEQ, IF_PRIV)
+/* MOVE TO PRIMARY */
+    F(0xda00, MVCP,    SS_d,  Z,   la1, a2, 0, 0, mvcp, 0, IF_PRIV)
+/* MOVE TO SECONDARY */
+    F(0xdb00, MVCS,    SS_d,  Z,   la1, a2, 0, 0, mvcs, 0, IF_PRIV)
+/* PURGE TLB */
+    F(0xb20d, PTLB,    S,     Z,   0, 0, 0, 0, ptlb, 0, IF_PRIV)
+/* RESET REFERENCE BIT EXTENDED */
+    F(0xb22a, RRBE,    RRE,   Z,   0, r2_o, 0, 0, rrbe, 0, IF_PRIV)
+/* SERVICE CALL LOGICAL PROCESSOR (PV hypercall) */
+    F(0xb220, SERVC,   RRE,   Z,   r1_o, r2_o, 0, 0, servc, 0, IF_PRIV | IF_IO)
+/* SET ADDRESS SPACE CONTROL FAST */
+    F(0xb279, SACF,    S,     Z,   0, a2, 0, 0, sacf, 0, IF_PRIV)
+/* SET CLOCK */
+    F(0xb204, SCK,     S,     Z,   la2, 0, 0, 0, sck, 0, IF_PRIV | IF_IO)
+/* SET CLOCK COMPARATOR */
+    F(0xb206, SCKC,    S,     Z,   0, m2_64a, 0, 0, sckc, 0, IF_PRIV | IF_IO)
+/* SET CLOCK PROGRAMMABLE FIELD */
+    F(0x0107, SCKPF,   E,     Z,   0, 0, 0, 0, sckpf, 0, IF_PRIV)
+/* SET CPU TIMER */
+    F(0xb208, SPT,     S,     Z,   0, m2_64a, 0, 0, spt, 0, IF_PRIV | IF_IO)
+/* SET PREFIX */
+    F(0xb210, SPX,     S,     Z,   0, m2_32ua, 0, 0, spx, 0, IF_PRIV)
+/* SET PSW KEY FROM ADDRESS */
+    F(0xb20a, SPKA,    S,     Z,   0, a2, 0, 0, spka, 0, IF_PRIV)
+/* SET STORAGE KEY EXTENDED */
+    F(0xb22b, SSKE,    RRF_c, Z,   r1_o, r2_o, 0, 0, sske, 0, IF_PRIV)
+/* SET SYSTEM MASK */
+    F(0x8000, SSM,     S,     Z,   0, m2_8u, 0, 0, ssm, 0, IF_PRIV)
+/* SIGNAL PROCESSOR */
+    F(0xae00, SIGP,    RS_a,  Z,   0, a2, 0, 0, sigp, 0, IF_PRIV | IF_IO)
+/* STORE CLOCK COMPARATOR */
+    F(0xb207, STCKC,   S,     Z,   la2, 0, new, m1_64a, stckc, 0, IF_PRIV)
+/* STORE CONTROL */
+    F(0xb600, STCTL,   RS_a,  Z,   0, a2, 0, 0, stctl, 0, IF_PRIV)
+    F(0xeb25, STCTG,   RSY_a, Z,   0, a2, 0, 0, stctg, 0, IF_PRIV)
+/* STORE CPU ADDRESS */
+    F(0xb212, STAP,    S,     Z,   la2, 0, new, m1_16a, stap, 0, IF_PRIV)
+/* STORE CPU ID */
+    F(0xb202, STIDP,   S,     Z,   la2, 0, new, m1_64a, stidp, 0, IF_PRIV)
+/* STORE CPU TIMER */
+    F(0xb209, STPT,    S,     Z,   la2, 0, new, m1_64a, stpt, 0, IF_PRIV | IF_IO)
+/* STORE FACILITY LIST */
+    F(0xb2b1, STFL,    S,     Z,   0, 0, 0, 0, stfl, 0, IF_PRIV)
+/* STORE PREFIX */
+    F(0xb211, STPX,    S,     Z,   la2, 0, new, m1_32a, stpx, 0, IF_PRIV)
+/* STORE SYSTEM INFORMATION */
+    F(0xb27d, STSI,    S,     Z,   0, a2, 0, 0, stsi, 0, IF_PRIV)
+/* STORE THEN AND SYSTEM MASK */
+    F(0xac00, STNSM,   SI,    Z,   la1, 0, 0, 0, stnosm, 0, IF_PRIV)
+/* STORE THEN OR SYSTEM MASK */
+    F(0xad00, STOSM,   SI,    Z,   la1, 0, 0, 0, stnosm, 0, IF_PRIV)
+/* STORE USING REAL ADDRESS */
+    E(0xb246, STURA,   RRE,   Z,   r1_o, ra2, 0, 0, stura, 0, MO_TEUL, IF_PRIV)
+    E(0xb925, STURG,   RRE,   Z,   r1_o, ra2, 0, 0, stura, 0, MO_TEQ, IF_PRIV)
+/* TEST BLOCK */
+    F(0xb22c, TB,      RRE,   Z,   0, r2_o, 0, 0, testblock, 0, IF_PRIV)
+/* TEST PROTECTION */
+    C(0xe501, TPROT,   SSE,   Z,   la1, a2, 0, 0, tprot, 0)
+
+/* CCW I/O Instructions */
+    F(0xb276, XSCH,    S,     Z,   0, 0, 0, 0, xsch, 0, IF_PRIV | IF_IO)
+    F(0xb230, CSCH,    S,     Z,   0, 0, 0, 0, csch, 0, IF_PRIV | IF_IO)
+    F(0xb231, HSCH,    S,     Z,   0, 0, 0, 0, hsch, 0, IF_PRIV | IF_IO)
+    F(0xb232, MSCH,    S,     Z,   0, insn, 0, 0, msch, 0, IF_PRIV | IF_IO)
+    F(0xb23b, RCHP,    S,     Z,   0, 0, 0, 0, rchp, 0, IF_PRIV | IF_IO)
+    F(0xb238, RSCH,    S,     Z,   0, 0, 0, 0, rsch, 0, IF_PRIV | IF_IO)
+    F(0xb237, SAL,     S,     Z,   0, 0, 0, 0, sal, 0, IF_PRIV | IF_IO)
+    F(0xb23c, SCHM,    S,     Z,   0, insn, 0, 0, schm, 0, IF_PRIV | IF_IO)
+    F(0xb274, SIGA,    S,     Z,   0, 0, 0, 0, siga, 0, IF_PRIV | IF_IO)
+    F(0xb23a, STCPS,   S,     Z,   0, 0, 0, 0, stcps, 0, IF_PRIV | IF_IO)
+    F(0xb233, SSCH,    S,     Z,   0, insn, 0, 0, ssch, 0, IF_PRIV | IF_IO)
+    F(0xb239, STCRW,   S,     Z,   0, insn, 0, 0, stcrw, 0, IF_PRIV | IF_IO)
+    F(0xb234, STSCH,   S,     Z,   0, insn, 0, 0, stsch, 0, IF_PRIV | IF_IO)
+    F(0xb236, TPI ,    S,     Z,   la2, 0, 0, 0, tpi, 0, IF_PRIV | IF_IO)
+    F(0xb235, TSCH,    S,     Z,   0, insn, 0, 0, tsch, 0, IF_PRIV | IF_IO)
+    /* ??? Not listed in PoO ninth edition, but there's a linux driver that
+       uses it: "A CHSC subchannel is usually present on LPAR only."  */
+    F(0xb25f, CHSC,  RRE,     Z,   0, insn, 0, 0, chsc, 0, IF_PRIV | IF_IO)
+
+/* zPCI Instructions */
+    /* None of these instructions are documented in the PoP, so this is all
+       based upon target/s390x/kvm.c and Linux code and likely incomplete */
+    F(0xebd0, PCISTB, RSY_a, PCI, la2, 0, 0, 0, pcistb, 0, IF_PRIV | IF_IO)
+    F(0xebd1, SIC, RSY_a, AIS, r1, r3, 0, 0, sic, 0, IF_PRIV | IF_IO)
+    F(0xb9a0, CLP, RRF_c, PCI, 0, 0, 0, 0, clp, 0, IF_PRIV | IF_IO)
+    F(0xb9d0, PCISTG, RRE, PCI, 0, 0, 0, 0, pcistg, 0, IF_PRIV | IF_IO)
+    F(0xb9d2, PCILG, RRE, PCI, 0, 0, 0, 0, pcilg, 0, IF_PRIV | IF_IO)
+    F(0xb9d3, RPCIT, RRE, PCI, 0, 0, 0, 0, rpcit, 0, IF_PRIV | IF_IO)
+    F(0xe3d0, MPCIFC, RXY_a, PCI, la2, 0, 0, 0, mpcifc, 0, IF_PRIV | IF_IO)
+    F(0xe3d4, STPCIFC, RXY_a, PCI, la2, 0, 0, 0, stpcifc, 0, IF_PRIV | IF_IO)
+
+#endif /* CONFIG_USER_ONLY */
diff --git a/target/s390x/tcg/insn-format.def b/target/s390x/tcg/insn-format.def
new file mode 100644 (file)
index 0000000..6253edb
--- /dev/null
@@ -0,0 +1,81 @@
+/* Description of s390 insn formats.  */
+/* NAME   F1,          F2... */
+F0(E)
+F1(I,     I(1, 8, 8))
+F2(RI_a,  R(1, 8),     I(2,16,16))
+F2(RI_b,  R(1, 8),     I(2,16,16))
+F2(RI_c,  M(1, 8),     I(2,16,16))
+F3(RIE_a, R(1, 8),     I(2,16,16),  M(3,32))
+F4(RIE_b, R(1, 8),     R(2,12),     M(3,32),   I(4,16,16))
+F4(RIE_c, R(1, 8),     I(2,32, 8),  M(3,12),   I(4,16,16))
+F3(RIE_d, R(1, 8),     I(2,16,16),  R(3,12))
+F3(RIE_e, R(1, 8),     I(2,16,16),  R(3,12))
+F5(RIE_f, R(1, 8),     R(2,12),     I(3,16,8), I(4,24,8),  I(5,32,8))
+F3(RIE_g, R(1, 8),     I(2,16,16),  M(3,12))
+F2(RIL_a, R(1, 8),     I(2,16,32))
+F2(RIL_b, R(1, 8),     I(2,16,32))
+F2(RIL_c, M(1, 8),     I(2,16,32))
+F4(RIS,   R(1, 8),     I(2,32, 8),  M(3,12),   BD(4,16,20))
+/* ??? The PoO does not call out subtypes _a and _b for RR, as it does
+   for e.g. RX.  Our checking requires this for e.g. BCR.  */
+F2(RR_a,  R(1, 8),     R(2,12))
+F2(RR_b,  M(1, 8),     R(2,12))
+F2(RRE,   R(1,24),     R(2,28))
+F3(RRD,   R(1,16),     R(2,28),     R(3,24))
+F4(RRF_a, R(1,24),     R(2,28),     R(3,16),   M(4,20))
+F4(RRF_b, R(1,24),     R(2,28),     R(3,16),   M(4,20))
+F4(RRF_c, R(1,24),     R(2,28),     M(3,16),   M(4,20))
+F4(RRF_d, R(1,24),     R(2,28),     M(3,16),   M(4,20))
+F4(RRF_e, R(1,24),     R(2,28),     M(3,16),   M(4,20))
+F4(RRS,   R(1, 8),     R(2,12),     M(3,32),   BD(4,16,20))
+F3(RS_a,  R(1, 8),     BD(2,16,20), R(3,12))
+F3(RS_b,  R(1, 8),     BD(2,16,20), M(3,12))
+F3(RSI,   R(1, 8),     I(2,16,16),  R(3,12))
+F2(RSL,   L(1, 8, 4),  BD(1,16,20))
+F3(RSY_a, R(1, 8),     BDL(2),      R(3,12))
+F3(RSY_b, R(1, 8),     BDL(2),      M(3,12))
+F2(RX_a,  R(1, 8),     BXD(2))
+F2(RX_b,  M(1, 8),     BXD(2))
+F3(RXE,   R(1, 8),     BXD(2),      M(3,32))
+F3(RXF,   R(1,32),     BXD(2),      R(3, 8))
+F2(RXY_a, R(1, 8),     BXDL(2))
+F2(RXY_b, M(1, 8),     BXDL(2))
+F1(S,     BD(2,16,20))
+F2(SI,    BD(1,16,20), I(2,8,8))
+F2(SIL,   BD(1,16,20), I(2,32,16))
+F2(SIY,   BDL(1),      I(2, 8, 8))
+F3(SS_a,  L(1, 8, 8),  BD(1,16,20), BD(2,32,36))
+F4(SS_b,  L(1, 8, 4),  BD(1,16,20), L(2,12,4),   BD(2,32,36))
+F4(SS_c,  L(1, 8, 4),  BD(1,16,20), BD(2,32,36), I(3,12, 4))
+/* ??? Odd man out.  The L1 field here is really a register, but the
+   easy way to compress the fields has R1 and B1 overlap.  */
+F4(SS_d,  L(1, 8, 4),  BD(1,16,20), BD(2,32,36), R(3,12))
+F4(SS_e,  R(1, 8),     BD(2,16,20), R(3,12),     BD(4,32,36))
+F3(SS_f,  BD(1,16,20), L(2,8,8),    BD(2,32,36))
+F2(SSE,   BD(1,16,20), BD(2,32,36))
+F3(SSF,   BD(1,16,20), BD(2,32,36), R(3,8))
+F3(VRI_a, V(1,8),      I(2,16,16),  M(3,32))
+F4(VRI_b, V(1,8),      I(2,16,8),   I(3,24,8),   M(4,32))
+F4(VRI_c, V(1,8),      V(3,12),     I(2,16,16),  M(4,32))
+F5(VRI_d, V(1,8),      V(2,12),     V(3,16),     I(4,24,8),   M(5,32))
+F5(VRI_e, V(1,8),      V(2,12),     I(3,16,12),  M(5,28),     M(4,32))
+F5(VRI_f, V(1,8),      V(2,12),     V(3,16),     M(5,24),     I(4,28,8))
+F5(VRI_g, V(1,8),      V(2,12),     I(4,16,8),   M(5,24),     I(3,28,8))
+F3(VRI_h, V(1,8),      I(2,16,16),  I(3,32,4))
+F4(VRI_i, V(1,8),      R(2,12),     M(4,24),     I(3,28,8))
+F5(VRR_a, V(1,8),      V(2,12),     M(5,24),     M(4,28),     M(3,32))
+F5(VRR_b, V(1,8),      V(2,12),     V(3,16),     M(5,24),     M(4,32))
+F6(VRR_c, V(1,8),      V(2,12),     V(3,16),     M(6,24),     M(5,28),  M(4,32))
+F6(VRR_d, V(1,8),      V(2,12),     V(3,16),     M(5,20),     M(6,24),  V(4,32))
+F6(VRR_e, V(1,8),      V(2,12),     V(3,16),     M(6,20),     M(5,28),  V(4,32))
+F3(VRR_f, V(1,8),      R(2,12),     R(3,16))
+F1(VRR_g, V(1,12))
+F3(VRR_h, V(1,12),     V(2,16),     M(3,24))
+F3(VRR_i, R(1,8),      V(2,12),     M(3,24))
+F4(VRS_a, V(1,8),      V(3,12),     BD(2,16,20), M(4,32))
+F4(VRS_b, V(1,8),      R(3,12),     BD(2,16,20), M(4,32))
+F4(VRS_c, R(1,8),      V(3,12),     BD(2,16,20), M(4,32))
+F3(VRS_d, R(3,12),     BD(2,16,20), V(1,32))
+F4(VRV,   V(1,8),      V(2,12),     BD(2,16,20), M(3,32))
+F3(VRX,   V(1,8),      BXD(2),      M(3,32))
+F3(VSI,   I(3,8,8),    BD(2,16,20), V(1,32))
diff --git a/target/s390x/tcg/int_helper.c b/target/s390x/tcg/int_helper.c
new file mode 100644 (file)
index 0000000..9545423
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ *  S/390 integer helper routines
+ *
+ *  Copyright (c) 2009 Ulrich Hecht
+ *  Copyright (c) 2009 Alexander Graf
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "s390x-internal.h"
+#include "tcg_s390x.h"
+#include "exec/exec-all.h"
+#include "qemu/host-utils.h"
+#include "exec/helper-proto.h"
+
+/* #define DEBUG_HELPER */
+#ifdef DEBUG_HELPER
+#define HELPER_LOG(x...) qemu_log(x)
+#else
+#define HELPER_LOG(x...)
+#endif
+
+/* 64/32 -> 32 signed division */
+int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64)
+{
+    int32_t ret, b = b64;
+    int64_t q;
+
+    if (b == 0) {
+        tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
+    }
+
+    ret = q = a / b;
+    env->retxl = a % b;
+
+    /* Catch non-representable quotient.  */
+    if (ret != q) {
+        tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
+    }
+
+    return ret;
+}
+
+/* 64/32 -> 32 unsigned division */
+uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b64)
+{
+    uint32_t ret, b = b64;
+    uint64_t q;
+
+    if (b == 0) {
+        tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
+    }
+
+    ret = q = a / b;
+    env->retxl = a % b;
+
+    /* Catch non-representable quotient.  */
+    if (ret != q) {
+        tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
+    }
+
+    return ret;
+}
+
+/* 64/64 -> 64 signed division */
+int64_t HELPER(divs64)(CPUS390XState *env, int64_t a, int64_t b)
+{
+    /* Catch divide by zero, and non-representable quotient (MIN / -1).  */
+    if (b == 0 || (b == -1 && a == (1ll << 63))) {
+        tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
+    }
+    env->retxl = a % b;
+    return a / b;
+}
+
+/* 128 -> 64/64 unsigned division */
+uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al,
+                        uint64_t b)
+{
+    uint64_t ret;
+    /* Signal divide by zero.  */
+    if (b == 0) {
+        tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
+    }
+    if (ah == 0) {
+        /* 64 -> 64/64 case */
+        env->retxl = al % b;
+        ret = al / b;
+    } else {
+        /* ??? Move i386 idivq helper to host-utils.  */
+#ifdef CONFIG_INT128
+        __uint128_t a = ((__uint128_t)ah << 64) | al;
+        __uint128_t q = a / b;
+        env->retxl = a % b;
+        ret = q;
+        if (ret != q) {
+            tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
+        }
+#else
+        /* 32-bit hosts would need special wrapper functionality - just abort if
+           we encounter such a case; it's very unlikely anyways. */
+        cpu_abort(env_cpu(env), "128 -> 64/64 division not implemented\n");
+#endif
+    }
+    return ret;
+}
+
+uint64_t HELPER(cvd)(int32_t reg)
+{
+    /* positive 0 */
+    uint64_t dec = 0x0c;
+    int64_t bin = reg;
+    int shift;
+
+    if (bin < 0) {
+        bin = -bin;
+        dec = 0x0d;
+    }
+
+    for (shift = 4; (shift < 64) && bin; shift += 4) {
+        dec |= (bin % 10) << shift;
+        bin /= 10;
+    }
+
+    return dec;
+}
+
+uint64_t HELPER(popcnt)(uint64_t val)
+{
+    /* Note that we don't fold past bytes. */
+    val = (val & 0x5555555555555555ULL) + ((val >> 1) & 0x5555555555555555ULL);
+    val = (val & 0x3333333333333333ULL) + ((val >> 2) & 0x3333333333333333ULL);
+    val = (val + (val >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
+    return val;
+}
diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c
new file mode 100644 (file)
index 0000000..9bae13e
--- /dev/null
@@ -0,0 +1,3008 @@
+/*
+ *  S/390 memory access helper routines
+ *
+ *  Copyright (c) 2009 Ulrich Hecht
+ *  Copyright (c) 2009 Alexander Graf
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "s390x-internal.h"
+#include "tcg_s390x.h"
+#include "exec/helper-proto.h"
+#include "exec/exec-all.h"
+#include "exec/cpu_ldst.h"
+#include "qemu/int128.h"
+#include "qemu/atomic128.h"
+#include "tcg/tcg.h"
+
+#if !defined(CONFIG_USER_ONLY)
+#include "hw/s390x/storage-keys.h"
+#include "hw/boards.h"
+#endif
+
+/*****************************************************************************/
+/* Softmmu support */
+
+/* #define DEBUG_HELPER */
+#ifdef DEBUG_HELPER
+#define HELPER_LOG(x...) qemu_log(x)
+#else
+#define HELPER_LOG(x...)
+#endif
+
+static inline bool psw_key_valid(CPUS390XState *env, uint8_t psw_key)
+{
+    uint16_t pkm = env->cregs[3] >> 16;
+
+    if (env->psw.mask & PSW_MASK_PSTATE) {
+        /* PSW key has range 0..15, it is valid if the bit is 1 in the PKM */
+        return pkm & (0x80 >> psw_key);
+    }
+    return true;
+}
+
+static bool is_destructive_overlap(CPUS390XState *env, uint64_t dest,
+                                   uint64_t src, uint32_t len)
+{
+    if (!len || src == dest) {
+        return false;
+    }
+    /* Take care of wrapping at the end of address space. */
+    if (unlikely(wrap_address(env, src + len - 1) < src)) {
+        return dest > src || dest <= wrap_address(env, src + len - 1);
+    }
+    return dest > src && dest <= src + len - 1;
+}
+
+/* Trigger a SPECIFICATION exception if an address or a length is not
+   naturally aligned.  */
+static inline void check_alignment(CPUS390XState *env, uint64_t v,
+                                   int wordsize, uintptr_t ra)
+{
+    if (v % wordsize) {
+        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+    }
+}
+
+/* Load a value from memory according to its size.  */
+static inline uint64_t cpu_ldusize_data_ra(CPUS390XState *env, uint64_t addr,
+                                           int wordsize, uintptr_t ra)
+{
+    switch (wordsize) {
+    case 1:
+        return cpu_ldub_data_ra(env, addr, ra);
+    case 2:
+        return cpu_lduw_data_ra(env, addr, ra);
+    default:
+        abort();
+    }
+}
+
+/* Store a to memory according to its size.  */
+static inline void cpu_stsize_data_ra(CPUS390XState *env, uint64_t addr,
+                                      uint64_t value, int wordsize,
+                                      uintptr_t ra)
+{
+    switch (wordsize) {
+    case 1:
+        cpu_stb_data_ra(env, addr, value, ra);
+        break;
+    case 2:
+        cpu_stw_data_ra(env, addr, value, ra);
+        break;
+    default:
+        abort();
+    }
+}
+
+/* An access covers at most 4096 bytes and therefore at most two pages. */
+typedef struct S390Access {
+    target_ulong vaddr1;
+    target_ulong vaddr2;
+    char *haddr1;
+    char *haddr2;
+    uint16_t size1;
+    uint16_t size2;
+    /*
+     * If we can't access the host page directly, we'll have to do I/O access
+     * via ld/st helpers. These are internal details, so we store the
+     * mmu idx to do the access here instead of passing it around in the
+     * helpers. Maybe, one day we can get rid of ld/st access - once we can
+     * handle TLB_NOTDIRTY differently. We don't expect these special accesses
+     * to trigger exceptions - only if we would have TLB_NOTDIRTY on LAP
+     * pages, we might trigger a new MMU translation - very unlikely that
+     * the mapping changes in between and we would trigger a fault.
+     */
+    int mmu_idx;
+} S390Access;
+
+/*
+ * With nonfault=1, return the PGM_ exception that would have been injected
+ * into the guest; return 0 if no exception was detected.
+ *
+ * For !CONFIG_USER_ONLY, the TEC is stored stored to env->tlb_fill_tec.
+ * For CONFIG_USER_ONLY, the faulting address is stored to env->__excp_addr.
+ */
+static int s390_probe_access(CPUArchState *env, target_ulong addr, int size,
+                             MMUAccessType access_type, int mmu_idx,
+                             bool nonfault, void **phost, uintptr_t ra)
+{
+    int flags;
+
+#if defined(CONFIG_USER_ONLY)
+    flags = page_get_flags(addr);
+    if (!(flags & (access_type == MMU_DATA_LOAD ?  PAGE_READ : PAGE_WRITE_ORG))) {
+        env->__excp_addr = addr;
+        flags = (flags & PAGE_VALID) ? PGM_PROTECTION : PGM_ADDRESSING;
+        if (nonfault) {
+            return flags;
+        }
+        tcg_s390_program_interrupt(env, flags, ra);
+    }
+    *phost = g2h(env_cpu(env), addr);
+#else
+    /*
+     * For !CONFIG_USER_ONLY, we cannot rely on TLB_INVALID_MASK or haddr==NULL
+     * to detect if there was an exception during tlb_fill().
+     */
+    env->tlb_fill_exc = 0;
+    flags = probe_access_flags(env, addr, access_type, mmu_idx, nonfault, phost,
+                               ra);
+    if (env->tlb_fill_exc) {
+        return env->tlb_fill_exc;
+    }
+
+    if (unlikely(flags & TLB_WATCHPOINT)) {
+        /* S390 does not presently use transaction attributes. */
+        cpu_check_watchpoint(env_cpu(env), addr, size,
+                             MEMTXATTRS_UNSPECIFIED,
+                             (access_type == MMU_DATA_STORE
+                              ? BP_MEM_WRITE : BP_MEM_READ), ra);
+    }
+#endif
+    return 0;
+}
+
+static int access_prepare_nf(S390Access *access, CPUS390XState *env,
+                             bool nonfault, vaddr vaddr1, int size,
+                             MMUAccessType access_type,
+                             int mmu_idx, uintptr_t ra)
+{
+    void *haddr1, *haddr2 = NULL;
+    int size1, size2, exc;
+    vaddr vaddr2 = 0;
+
+    assert(size > 0 && size <= 4096);
+
+    size1 = MIN(size, -(vaddr1 | TARGET_PAGE_MASK)),
+    size2 = size - size1;
+
+    exc = s390_probe_access(env, vaddr1, size1, access_type, mmu_idx, nonfault,
+                            &haddr1, ra);
+    if (exc) {
+        return exc;
+    }
+    if (unlikely(size2)) {
+        /* The access crosses page boundaries. */
+        vaddr2 = wrap_address(env, vaddr1 + size1);
+        exc = s390_probe_access(env, vaddr2, size2, access_type, mmu_idx,
+                                nonfault, &haddr2, ra);
+        if (exc) {
+            return exc;
+        }
+    }
+
+    *access = (S390Access) {
+        .vaddr1 = vaddr1,
+        .vaddr2 = vaddr2,
+        .haddr1 = haddr1,
+        .haddr2 = haddr2,
+        .size1 = size1,
+        .size2 = size2,
+        .mmu_idx = mmu_idx
+    };
+    return 0;
+}
+
+static S390Access access_prepare(CPUS390XState *env, vaddr vaddr, int size,
+                                 MMUAccessType access_type, int mmu_idx,
+                                 uintptr_t ra)
+{
+    S390Access ret;
+    int exc = access_prepare_nf(&ret, env, false, vaddr, size,
+                                access_type, mmu_idx, ra);
+    assert(!exc);
+    return ret;
+}
+
+/* Helper to handle memset on a single page. */
+static void do_access_memset(CPUS390XState *env, vaddr vaddr, char *haddr,
+                             uint8_t byte, uint16_t size, int mmu_idx,
+                             uintptr_t ra)
+{
+#ifdef CONFIG_USER_ONLY
+    g_assert(haddr);
+    memset(haddr, byte, size);
+#else
+    TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
+    int i;
+
+    if (likely(haddr)) {
+        memset(haddr, byte, size);
+    } else {
+        /*
+         * Do a single access and test if we can then get access to the
+         * page. This is especially relevant to speed up TLB_NOTDIRTY.
+         */
+        g_assert(size > 0);
+        helper_ret_stb_mmu(env, vaddr, byte, oi, ra);
+        haddr = tlb_vaddr_to_host(env, vaddr, MMU_DATA_STORE, mmu_idx);
+        if (likely(haddr)) {
+            memset(haddr + 1, byte, size - 1);
+        } else {
+            for (i = 1; i < size; i++) {
+                helper_ret_stb_mmu(env, vaddr + i, byte, oi, ra);
+            }
+        }
+    }
+#endif
+}
+
+static void access_memset(CPUS390XState *env, S390Access *desta,
+                          uint8_t byte, uintptr_t ra)
+{
+
+    do_access_memset(env, desta->vaddr1, desta->haddr1, byte, desta->size1,
+                     desta->mmu_idx, ra);
+    if (likely(!desta->size2)) {
+        return;
+    }
+    do_access_memset(env, desta->vaddr2, desta->haddr2, byte, desta->size2,
+                     desta->mmu_idx, ra);
+}
+
+static uint8_t do_access_get_byte(CPUS390XState *env, vaddr vaddr, char **haddr,
+                                  int offset, int mmu_idx, uintptr_t ra)
+{
+#ifdef CONFIG_USER_ONLY
+    return ldub_p(*haddr + offset);
+#else
+    TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
+    uint8_t byte;
+
+    if (likely(*haddr)) {
+        return ldub_p(*haddr + offset);
+    }
+    /*
+     * Do a single access and test if we can then get access to the
+     * page. This is especially relevant to speed up TLB_NOTDIRTY.
+     */
+    byte = helper_ret_ldub_mmu(env, vaddr + offset, oi, ra);
+    *haddr = tlb_vaddr_to_host(env, vaddr, MMU_DATA_LOAD, mmu_idx);
+    return byte;
+#endif
+}
+
+static uint8_t access_get_byte(CPUS390XState *env, S390Access *access,
+                               int offset, uintptr_t ra)
+{
+    if (offset < access->size1) {
+        return do_access_get_byte(env, access->vaddr1, &access->haddr1,
+                                  offset, access->mmu_idx, ra);
+    }
+    return do_access_get_byte(env, access->vaddr2, &access->haddr2,
+                              offset - access->size1, access->mmu_idx, ra);
+}
+
+static void do_access_set_byte(CPUS390XState *env, vaddr vaddr, char **haddr,
+                               int offset, uint8_t byte, int mmu_idx,
+                               uintptr_t ra)
+{
+#ifdef CONFIG_USER_ONLY
+    stb_p(*haddr + offset, byte);
+#else
+    TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
+
+    if (likely(*haddr)) {
+        stb_p(*haddr + offset, byte);
+        return;
+    }
+    /*
+     * Do a single access and test if we can then get access to the
+     * page. This is especially relevant to speed up TLB_NOTDIRTY.
+     */
+    helper_ret_stb_mmu(env, vaddr + offset, byte, oi, ra);
+    *haddr = tlb_vaddr_to_host(env, vaddr, MMU_DATA_STORE, mmu_idx);
+#endif
+}
+
+static void access_set_byte(CPUS390XState *env, S390Access *access,
+                            int offset, uint8_t byte, uintptr_t ra)
+{
+    if (offset < access->size1) {
+        do_access_set_byte(env, access->vaddr1, &access->haddr1, offset, byte,
+                           access->mmu_idx, ra);
+    } else {
+        do_access_set_byte(env, access->vaddr2, &access->haddr2,
+                           offset - access->size1, byte, access->mmu_idx, ra);
+    }
+}
+
+/*
+ * Move data with the same semantics as memmove() in case ranges don't overlap
+ * or src > dest. Undefined behavior on destructive overlaps.
+ */
+static void access_memmove(CPUS390XState *env, S390Access *desta,
+                           S390Access *srca, uintptr_t ra)
+{
+    int diff;
+
+    g_assert(desta->size1 + desta->size2 == srca->size1 + srca->size2);
+
+    /* Fallback to slow access in case we don't have access to all host pages */
+    if (unlikely(!desta->haddr1 || (desta->size2 && !desta->haddr2) ||
+                 !srca->haddr1 || (srca->size2 && !srca->haddr2))) {
+        int i;
+
+        for (i = 0; i < desta->size1 + desta->size2; i++) {
+            uint8_t byte = access_get_byte(env, srca, i, ra);
+
+            access_set_byte(env, desta, i, byte, ra);
+        }
+        return;
+    }
+
+    if (srca->size1 == desta->size1) {
+        memmove(desta->haddr1, srca->haddr1, srca->size1);
+        if (unlikely(srca->size2)) {
+            memmove(desta->haddr2, srca->haddr2, srca->size2);
+        }
+    } else if (srca->size1 < desta->size1) {
+        diff = desta->size1 - srca->size1;
+        memmove(desta->haddr1, srca->haddr1, srca->size1);
+        memmove(desta->haddr1 + srca->size1, srca->haddr2, diff);
+        if (likely(desta->size2)) {
+            memmove(desta->haddr2, srca->haddr2 + diff, desta->size2);
+        }
+    } else {
+        diff = srca->size1 - desta->size1;
+        memmove(desta->haddr1, srca->haddr1, desta->size1);
+        memmove(desta->haddr2, srca->haddr1 + desta->size1, diff);
+        if (likely(srca->size2)) {
+            memmove(desta->haddr2 + diff, srca->haddr2, srca->size2);
+        }
+    }
+}
+
+static int mmu_idx_from_as(uint8_t as)
+{
+    switch (as) {
+    case AS_PRIMARY:
+        return MMU_PRIMARY_IDX;
+    case AS_SECONDARY:
+        return MMU_SECONDARY_IDX;
+    case AS_HOME:
+        return MMU_HOME_IDX;
+    default:
+        /* FIXME AS_ACCREG */
+        g_assert_not_reached();
+    }
+}
+
+/* and on array */
+static uint32_t do_helper_nc(CPUS390XState *env, uint32_t l, uint64_t dest,
+                             uint64_t src, uintptr_t ra)
+{
+    const int mmu_idx = cpu_mmu_index(env, false);
+    S390Access srca1, srca2, desta;
+    uint32_t i;
+    uint8_t c = 0;
+
+    HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
+               __func__, l, dest, src);
+
+    /* NC always processes one more byte than specified - maximum is 256 */
+    l++;
+
+    srca1 = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
+    srca2 = access_prepare(env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
+    desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
+    for (i = 0; i < l; i++) {
+        const uint8_t x = access_get_byte(env, &srca1, i, ra) &
+                          access_get_byte(env, &srca2, i, ra);
+
+        c |= x;
+        access_set_byte(env, &desta, i, x, ra);
+    }
+    return c != 0;
+}
+
+uint32_t HELPER(nc)(CPUS390XState *env, uint32_t l, uint64_t dest,
+                    uint64_t src)
+{
+    return do_helper_nc(env, l, dest, src, GETPC());
+}
+
+/* xor on array */
+static uint32_t do_helper_xc(CPUS390XState *env, uint32_t l, uint64_t dest,
+                             uint64_t src, uintptr_t ra)
+{
+    const int mmu_idx = cpu_mmu_index(env, false);
+    S390Access srca1, srca2, desta;
+    uint32_t i;
+    uint8_t c = 0;
+
+    HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
+               __func__, l, dest, src);
+
+    /* XC always processes one more byte than specified - maximum is 256 */
+    l++;
+
+    srca1 = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
+    srca2 = access_prepare(env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
+    desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
+
+    /* xor with itself is the same as memset(0) */
+    if (src == dest) {
+        access_memset(env, &desta, 0, ra);
+        return 0;
+    }
+
+    for (i = 0; i < l; i++) {
+        const uint8_t x = access_get_byte(env, &srca1, i, ra) ^
+                          access_get_byte(env, &srca2, i, ra);
+
+        c |= x;
+        access_set_byte(env, &desta, i, x, ra);
+    }
+    return c != 0;
+}
+
+uint32_t HELPER(xc)(CPUS390XState *env, uint32_t l, uint64_t dest,
+                    uint64_t src)
+{
+    return do_helper_xc(env, l, dest, src, GETPC());
+}
+
+/* or on array */
+static uint32_t do_helper_oc(CPUS390XState *env, uint32_t l, uint64_t dest,
+                             uint64_t src, uintptr_t ra)
+{
+    const int mmu_idx = cpu_mmu_index(env, false);
+    S390Access srca1, srca2, desta;
+    uint32_t i;
+    uint8_t c = 0;
+
+    HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
+               __func__, l, dest, src);
+
+    /* OC always processes one more byte than specified - maximum is 256 */
+    l++;
+
+    srca1 = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
+    srca2 = access_prepare(env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
+    desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
+    for (i = 0; i < l; i++) {
+        const uint8_t x = access_get_byte(env, &srca1, i, ra) |
+                          access_get_byte(env, &srca2, i, ra);
+
+        c |= x;
+        access_set_byte(env, &desta, i, x, ra);
+    }
+    return c != 0;
+}
+
+uint32_t HELPER(oc)(CPUS390XState *env, uint32_t l, uint64_t dest,
+                    uint64_t src)
+{
+    return do_helper_oc(env, l, dest, src, GETPC());
+}
+
+/* memmove */
+static uint32_t do_helper_mvc(CPUS390XState *env, uint32_t l, uint64_t dest,
+                              uint64_t src, uintptr_t ra)
+{
+    const int mmu_idx = cpu_mmu_index(env, false);
+    S390Access srca, desta;
+    uint32_t i;
+
+    HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
+               __func__, l, dest, src);
+
+    /* MVC always copies one more byte than specified - maximum is 256 */
+    l++;
+
+    srca = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
+    desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
+
+    /*
+     * "When the operands overlap, the result is obtained as if the operands
+     * were processed one byte at a time". Only non-destructive overlaps
+     * behave like memmove().
+     */
+    if (dest == src + 1) {
+        access_memset(env, &desta, access_get_byte(env, &srca, 0, ra), ra);
+    } else if (!is_destructive_overlap(env, dest, src, l)) {
+        access_memmove(env, &desta, &srca, ra);
+    } else {
+        for (i = 0; i < l; i++) {
+            uint8_t byte = access_get_byte(env, &srca, i, ra);
+
+            access_set_byte(env, &desta, i, byte, ra);
+        }
+    }
+
+    return env->cc_op;
+}
+
+void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
+{
+    do_helper_mvc(env, l, dest, src, GETPC());
+}
+
+/* move inverse  */
+void HELPER(mvcin)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
+{
+    const int mmu_idx = cpu_mmu_index(env, false);
+    S390Access srca, desta;
+    uintptr_t ra = GETPC();
+    int i;
+
+    /* MVCIN always copies one more byte than specified - maximum is 256 */
+    l++;
+
+    src = wrap_address(env, src - l + 1);
+    srca = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
+    desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
+    for (i = 0; i < l; i++) {
+        const uint8_t x = access_get_byte(env, &srca, l - i - 1, ra);
+
+        access_set_byte(env, &desta, i, x, ra);
+    }
+}
+
+/* move numerics  */
+void HELPER(mvn)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
+{
+    const int mmu_idx = cpu_mmu_index(env, false);
+    S390Access srca1, srca2, desta;
+    uintptr_t ra = GETPC();
+    int i;
+
+    /* MVN always copies one more byte than specified - maximum is 256 */
+    l++;
+
+    srca1 = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
+    srca2 = access_prepare(env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
+    desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
+    for (i = 0; i < l; i++) {
+        const uint8_t x = (access_get_byte(env, &srca1, i, ra) & 0x0f) |
+                          (access_get_byte(env, &srca2, i, ra) & 0xf0);
+
+        access_set_byte(env, &desta, i, x, ra);
+    }
+}
+
+/* move with offset  */
+void HELPER(mvo)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
+{
+    const int mmu_idx = cpu_mmu_index(env, false);
+    /* MVO always processes one more byte than specified - maximum is 16 */
+    const int len_dest = (l >> 4) + 1;
+    const int len_src = (l & 0xf) + 1;
+    uintptr_t ra = GETPC();
+    uint8_t byte_dest, byte_src;
+    S390Access srca, desta;
+    int i, j;
+
+    srca = access_prepare(env, src, len_src, MMU_DATA_LOAD, mmu_idx, ra);
+    desta = access_prepare(env, dest, len_dest, MMU_DATA_STORE, mmu_idx, ra);
+
+    /* Handle rightmost byte */
+    byte_dest = cpu_ldub_data_ra(env, dest + len_dest - 1, ra);
+    byte_src = access_get_byte(env, &srca, len_src - 1, ra);
+    byte_dest = (byte_dest & 0x0f) | (byte_src << 4);
+    access_set_byte(env, &desta, len_dest - 1, byte_dest, ra);
+
+    /* Process remaining bytes from right to left */
+    for (i = len_dest - 2, j = len_src - 2; i >= 0; i--, j--) {
+        byte_dest = byte_src >> 4;
+        if (j >= 0) {
+            byte_src = access_get_byte(env, &srca, j, ra);
+        } else {
+            byte_src = 0;
+        }
+        byte_dest |= byte_src << 4;
+        access_set_byte(env, &desta, i, byte_dest, ra);
+    }
+}
+
+/* move zones  */
+void HELPER(mvz)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
+{
+    const int mmu_idx = cpu_mmu_index(env, false);
+    S390Access srca1, srca2, desta;
+    uintptr_t ra = GETPC();
+    int i;
+
+    /* MVZ always copies one more byte than specified - maximum is 256 */
+    l++;
+
+    srca1 = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
+    srca2 = access_prepare(env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
+    desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
+    for (i = 0; i < l; i++) {
+        const uint8_t x = (access_get_byte(env, &srca1, i, ra) & 0xf0) |
+                          (access_get_byte(env, &srca2, i, ra) & 0x0f);
+
+        access_set_byte(env, &desta, i, x, ra);
+    }
+}
+
+/* compare unsigned byte arrays */
+static uint32_t do_helper_clc(CPUS390XState *env, uint32_t l, uint64_t s1,
+                              uint64_t s2, uintptr_t ra)
+{
+    uint32_t i;
+    uint32_t cc = 0;
+
+    HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n",
+               __func__, l, s1, s2);
+
+    for (i = 0; i <= l; i++) {
+        uint8_t x = cpu_ldub_data_ra(env, s1 + i, ra);
+        uint8_t y = cpu_ldub_data_ra(env, s2 + i, ra);
+        HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y);
+        if (x < y) {
+            cc = 1;
+            break;
+        } else if (x > y) {
+            cc = 2;
+            break;
+        }
+    }
+
+    HELPER_LOG("\n");
+    return cc;
+}
+
+uint32_t HELPER(clc)(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2)
+{
+    return do_helper_clc(env, l, s1, s2, GETPC());
+}
+
+/* compare logical under mask */
+uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask,
+                     uint64_t addr)
+{
+    uintptr_t ra = GETPC();
+    uint32_t cc = 0;
+
+    HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1,
+               mask, addr);
+
+    while (mask) {
+        if (mask & 8) {
+            uint8_t d = cpu_ldub_data_ra(env, addr, ra);
+            uint8_t r = extract32(r1, 24, 8);
+            HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d,
+                       addr);
+            if (r < d) {
+                cc = 1;
+                break;
+            } else if (r > d) {
+                cc = 2;
+                break;
+            }
+            addr++;
+        }
+        mask = (mask << 1) & 0xf;
+        r1 <<= 8;
+    }
+
+    HELPER_LOG("\n");
+    return cc;
+}
+
+static inline uint64_t get_address(CPUS390XState *env, int reg)
+{
+    return wrap_address(env, env->regs[reg]);
+}
+
+/*
+ * Store the address to the given register, zeroing out unused leftmost
+ * bits in bit positions 32-63 (24-bit and 31-bit mode only).
+ */
+static inline void set_address_zero(CPUS390XState *env, int reg,
+                                    uint64_t address)
+{
+    if (env->psw.mask & PSW_MASK_64) {
+        env->regs[reg] = address;
+    } else {
+        if (!(env->psw.mask & PSW_MASK_32)) {
+            address &= 0x00ffffff;
+        } else {
+            address &= 0x7fffffff;
+        }
+        env->regs[reg] = deposit64(env->regs[reg], 0, 32, address);
+    }
+}
+
+static inline void set_address(CPUS390XState *env, int reg, uint64_t address)
+{
+    if (env->psw.mask & PSW_MASK_64) {
+        /* 64-Bit mode */
+        env->regs[reg] = address;
+    } else {
+        if (!(env->psw.mask & PSW_MASK_32)) {
+            /* 24-Bit mode. According to the PoO it is implementation
+            dependent if bits 32-39 remain unchanged or are set to
+            zeros.  Choose the former so that the function can also be
+            used for TRT.  */
+            env->regs[reg] = deposit64(env->regs[reg], 0, 24, address);
+        } else {
+            /* 31-Bit mode. According to the PoO it is implementation
+            dependent if bit 32 remains unchanged or is set to zero.
+            Choose the latter so that the function can also be used for
+            TRT.  */
+            address &= 0x7fffffff;
+            env->regs[reg] = deposit64(env->regs[reg], 0, 32, address);
+        }
+    }
+}
+
+static inline uint64_t wrap_length32(CPUS390XState *env, uint64_t length)
+{
+    if (!(env->psw.mask & PSW_MASK_64)) {
+        return (uint32_t)length;
+    }
+    return length;
+}
+
+static inline uint64_t wrap_length31(CPUS390XState *env, uint64_t length)
+{
+    if (!(env->psw.mask & PSW_MASK_64)) {
+        /* 24-Bit and 31-Bit mode */
+        length &= 0x7fffffff;
+    }
+    return length;
+}
+
+static inline uint64_t get_length(CPUS390XState *env, int reg)
+{
+    return wrap_length31(env, env->regs[reg]);
+}
+
+static inline void set_length(CPUS390XState *env, int reg, uint64_t length)
+{
+    if (env->psw.mask & PSW_MASK_64) {
+        /* 64-Bit mode */
+        env->regs[reg] = length;
+    } else {
+        /* 24-Bit and 31-Bit mode */
+        env->regs[reg] = deposit64(env->regs[reg], 0, 32, length);
+    }
+}
+
+/* search string (c is byte to search, r2 is string, r1 end of string) */
+void HELPER(srst)(CPUS390XState *env, uint32_t r1, uint32_t r2)
+{
+    uintptr_t ra = GETPC();
+    uint64_t end, str;
+    uint32_t len;
+    uint8_t v, c = env->regs[0];
+
+    /* Bits 32-55 must contain all 0.  */
+    if (env->regs[0] & 0xffffff00u) {
+        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+    }
+
+    str = get_address(env, r2);
+    end = get_address(env, r1);
+
+    /* Lest we fail to service interrupts in a timely manner, limit the
+       amount of work we're willing to do.  For now, let's cap at 8k.  */
+    for (len = 0; len < 0x2000; ++len) {
+        if (str + len == end) {
+            /* Character not found.  R1 & R2 are unmodified.  */
+            env->cc_op = 2;
+            return;
+        }
+        v = cpu_ldub_data_ra(env, str + len, ra);
+        if (v == c) {
+            /* Character found.  Set R1 to the location; R2 is unmodified.  */
+            env->cc_op = 1;
+            set_address(env, r1, str + len);
+            return;
+        }
+    }
+
+    /* CPU-determined bytes processed.  Advance R2 to next byte to process.  */
+    env->cc_op = 3;
+    set_address(env, r2, str + len);
+}
+
+void HELPER(srstu)(CPUS390XState *env, uint32_t r1, uint32_t r2)
+{
+    uintptr_t ra = GETPC();
+    uint32_t len;
+    uint16_t v, c = env->regs[0];
+    uint64_t end, str, adj_end;
+
+    /* Bits 32-47 of R0 must be zero.  */
+    if (env->regs[0] & 0xffff0000u) {
+        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+    }
+
+    str = get_address(env, r2);
+    end = get_address(env, r1);
+
+    /* If the LSB of the two addresses differ, use one extra byte.  */
+    adj_end = end + ((str ^ end) & 1);
+
+    /* Lest we fail to service interrupts in a timely manner, limit the
+       amount of work we're willing to do.  For now, let's cap at 8k.  */
+    for (len = 0; len < 0x2000; len += 2) {
+        if (str + len == adj_end) {
+            /* End of input found.  */
+            env->cc_op = 2;
+            return;
+        }
+        v = cpu_lduw_data_ra(env, str + len, ra);
+        if (v == c) {
+            /* Character found.  Set R1 to the location; R2 is unmodified.  */
+            env->cc_op = 1;
+            set_address(env, r1, str + len);
+            return;
+        }
+    }
+
+    /* CPU-determined bytes processed.  Advance R2 to next byte to process.  */
+    env->cc_op = 3;
+    set_address(env, r2, str + len);
+}
+
+/* unsigned string compare (c is string terminator) */
+uint64_t HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2)
+{
+    uintptr_t ra = GETPC();
+    uint32_t len;
+
+    c = c & 0xff;
+    s1 = wrap_address(env, s1);
+    s2 = wrap_address(env, s2);
+
+    /* Lest we fail to service interrupts in a timely manner, limit the
+       amount of work we're willing to do.  For now, let's cap at 8k.  */
+    for (len = 0; len < 0x2000; ++len) {
+        uint8_t v1 = cpu_ldub_data_ra(env, s1 + len, ra);
+        uint8_t v2 = cpu_ldub_data_ra(env, s2 + len, ra);
+        if (v1 == v2) {
+            if (v1 == c) {
+                /* Equal.  CC=0, and don't advance the registers.  */
+                env->cc_op = 0;
+                env->retxl = s2;
+                return s1;
+            }
+        } else {
+            /* Unequal.  CC={1,2}, and advance the registers.  Note that
+               the terminator need not be zero, but the string that contains
+               the terminator is by definition "low".  */
+            env->cc_op = (v1 == c ? 1 : v2 == c ? 2 : v1 < v2 ? 1 : 2);
+            env->retxl = s2 + len;
+            return s1 + len;
+        }
+    }
+
+    /* CPU-determined bytes equal; advance the registers.  */
+    env->cc_op = 3;
+    env->retxl = s2 + len;
+    return s1 + len;
+}
+
+/* move page */
+uint32_t HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint32_t r1, uint32_t r2)
+{
+    const uint64_t src = get_address(env, r2) & TARGET_PAGE_MASK;
+    const uint64_t dst = get_address(env, r1) & TARGET_PAGE_MASK;
+    const int mmu_idx = cpu_mmu_index(env, false);
+    const bool f = extract64(r0, 11, 1);
+    const bool s = extract64(r0, 10, 1);
+    const bool cco = extract64(r0, 8, 1);
+    uintptr_t ra = GETPC();
+    S390Access srca, desta;
+    int exc;
+
+    if ((f && s) || extract64(r0, 12, 4)) {
+        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
+    }
+
+    /*
+     * We always manually handle exceptions such that we can properly store
+     * r1/r2 to the lowcore on page-translation exceptions.
+     *
+     * TODO: Access key handling
+     */
+    exc = access_prepare_nf(&srca, env, true, src, TARGET_PAGE_SIZE,
+                            MMU_DATA_LOAD, mmu_idx, ra);
+    if (exc) {
+        if (cco) {
+            return 2;
+        }
+        goto inject_exc;
+    }
+    exc = access_prepare_nf(&desta, env, true, dst, TARGET_PAGE_SIZE,
+                            MMU_DATA_STORE, mmu_idx, ra);
+    if (exc) {
+        if (cco && exc != PGM_PROTECTION) {
+            return 1;
+        }
+        goto inject_exc;
+    }
+    access_memmove(env, &desta, &srca, ra);
+    return 0; /* data moved */
+inject_exc:
+#if !defined(CONFIG_USER_ONLY)
+    if (exc != PGM_ADDRESSING) {
+        stq_phys(env_cpu(env)->as, env->psa + offsetof(LowCore, trans_exc_code),
+                 env->tlb_fill_tec);
+    }
+    if (exc == PGM_PAGE_TRANS) {
+        stb_phys(env_cpu(env)->as, env->psa + offsetof(LowCore, op_access_id),
+                 r1 << 4 | r2);
+    }
+#endif
+    tcg_s390_program_interrupt(env, exc, ra);
+}
+
+/* string copy */
+uint32_t HELPER(mvst)(CPUS390XState *env, uint32_t r1, uint32_t r2)
+{
+    const int mmu_idx = cpu_mmu_index(env, false);
+    const uint64_t d = get_address(env, r1);
+    const uint64_t s = get_address(env, r2);
+    const uint8_t c = env->regs[0];
+    const int len = MIN(-(d | TARGET_PAGE_MASK), -(s | TARGET_PAGE_MASK));
+    S390Access srca, desta;
+    uintptr_t ra = GETPC();
+    int i;
+
+    if (env->regs[0] & 0xffffff00ull) {
+        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+    }
+
+    /*
+     * Our access should not exceed single pages, as we must not report access
+     * exceptions exceeding the actually copied range (which we don't know at
+     * this point). We might over-indicate watchpoints within the pages
+     * (if we ever care, we have to limit processing to a single byte).
+     */
+    srca = access_prepare(env, s, len, MMU_DATA_LOAD, mmu_idx, ra);
+    desta = access_prepare(env, d, len, MMU_DATA_STORE, mmu_idx, ra);
+    for (i = 0; i < len; i++) {
+        const uint8_t v = access_get_byte(env, &srca, i, ra);
+
+        access_set_byte(env, &desta, i, v, ra);
+        if (v == c) {
+            set_address_zero(env, r1, d + i);
+            return 1;
+        }
+    }
+    set_address_zero(env, r1, d + len);
+    set_address_zero(env, r2, s + len);
+    return 3;
+}
+
+/* load access registers r1 to r3 from memory at a2 */
+void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    uintptr_t ra = GETPC();
+    int i;
+
+    if (a2 & 0x3) {
+        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+    }
+
+    for (i = r1;; i = (i + 1) % 16) {
+        env->aregs[i] = cpu_ldl_data_ra(env, a2, ra);
+        a2 += 4;
+
+        if (i == r3) {
+            break;
+        }
+    }
+}
+
+/* store access registers r1 to r3 in memory at a2 */
+void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    uintptr_t ra = GETPC();
+    int i;
+
+    if (a2 & 0x3) {
+        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+    }
+
+    for (i = r1;; i = (i + 1) % 16) {
+        cpu_stl_data_ra(env, a2, env->aregs[i], ra);
+        a2 += 4;
+
+        if (i == r3) {
+            break;
+        }
+    }
+}
+
+/* move long helper */
+static inline uint32_t do_mvcl(CPUS390XState *env,
+                               uint64_t *dest, uint64_t *destlen,
+                               uint64_t *src, uint64_t *srclen,
+                               uint16_t pad, int wordsize, uintptr_t ra)
+{
+    const int mmu_idx = cpu_mmu_index(env, false);
+    int len = MIN(*destlen, -(*dest | TARGET_PAGE_MASK));
+    S390Access srca, desta;
+    int i, cc;
+
+    if (*destlen == *srclen) {
+        cc = 0;
+    } else if (*destlen < *srclen) {
+        cc = 1;
+    } else {
+        cc = 2;
+    }
+
+    if (!*destlen) {
+        return cc;
+    }
+
+    /*
+     * Only perform one type of type of operation (move/pad) at a time.
+     * Stay within single pages.
+     */
+    if (*srclen) {
+        /* Copy the src array */
+        len = MIN(MIN(*srclen, -(*src | TARGET_PAGE_MASK)), len);
+        *destlen -= len;
+        *srclen -= len;
+        srca = access_prepare(env, *src, len, MMU_DATA_LOAD, mmu_idx, ra);
+        desta = access_prepare(env, *dest, len, MMU_DATA_STORE, mmu_idx, ra);
+        access_memmove(env, &desta, &srca, ra);
+        *src = wrap_address(env, *src + len);
+        *dest = wrap_address(env, *dest + len);
+    } else if (wordsize == 1) {
+        /* Pad the remaining area */
+        *destlen -= len;
+        desta = access_prepare(env, *dest, len, MMU_DATA_STORE, mmu_idx, ra);
+        access_memset(env, &desta, pad, ra);
+        *dest = wrap_address(env, *dest + len);
+    } else {
+        desta = access_prepare(env, *dest, len, MMU_DATA_STORE, mmu_idx, ra);
+
+        /* The remaining length selects the padding byte. */
+        for (i = 0; i < len; (*destlen)--, i++) {
+            if (*destlen & 1) {
+                access_set_byte(env, &desta, i, pad, ra);
+            } else {
+                access_set_byte(env, &desta, i, pad >> 8, ra);
+            }
+        }
+        *dest = wrap_address(env, *dest + len);
+    }
+
+    return *destlen ? 3 : cc;
+}
+
+/* move long */
+uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
+{
+    const int mmu_idx = cpu_mmu_index(env, false);
+    uintptr_t ra = GETPC();
+    uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
+    uint64_t dest = get_address(env, r1);
+    uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
+    uint64_t src = get_address(env, r2);
+    uint8_t pad = env->regs[r2 + 1] >> 24;
+    CPUState *cs = env_cpu(env);
+    S390Access srca, desta;
+    uint32_t cc, cur_len;
+
+    if (is_destructive_overlap(env, dest, src, MIN(srclen, destlen))) {
+        cc = 3;
+    } else if (srclen == destlen) {
+        cc = 0;
+    } else if (destlen < srclen) {
+        cc = 1;
+    } else {
+        cc = 2;
+    }
+
+    /* We might have to zero-out some bits even if there was no action. */
+    if (unlikely(!destlen || cc == 3)) {
+        set_address_zero(env, r2, src);
+        set_address_zero(env, r1, dest);
+        return cc;
+    } else if (!srclen) {
+        set_address_zero(env, r2, src);
+    }
+
+    /*
+     * Only perform one type of type of operation (move/pad) in one step.
+     * Stay within single pages.
+     */
+    while (destlen) {
+        cur_len = MIN(destlen, -(dest | TARGET_PAGE_MASK));
+        if (!srclen) {
+            desta = access_prepare(env, dest, cur_len, MMU_DATA_STORE, mmu_idx,
+                                   ra);
+            access_memset(env, &desta, pad, ra);
+        } else {
+            cur_len = MIN(MIN(srclen, -(src | TARGET_PAGE_MASK)), cur_len);
+
+            srca = access_prepare(env, src, cur_len, MMU_DATA_LOAD, mmu_idx,
+                                  ra);
+            desta = access_prepare(env, dest, cur_len, MMU_DATA_STORE, mmu_idx,
+                                   ra);
+            access_memmove(env, &desta, &srca, ra);
+            src = wrap_address(env, src + cur_len);
+            srclen -= cur_len;
+            env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, srclen);
+            set_address_zero(env, r2, src);
+        }
+        dest = wrap_address(env, dest + cur_len);
+        destlen -= cur_len;
+        env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, destlen);
+        set_address_zero(env, r1, dest);
+
+        /*
+         * MVCL is interruptible. Return to the main loop if requested after
+         * writing back all state to registers. If no interrupt will get
+         * injected, we'll end up back in this handler and continue processing
+         * the remaining parts.
+         */
+        if (destlen && unlikely(cpu_loop_exit_requested(cs))) {
+            cpu_loop_exit_restore(cs, ra);
+        }
+    }
+    return cc;
+}
+
+/* move long extended */
+uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
+                       uint32_t r3)
+{
+    uintptr_t ra = GETPC();
+    uint64_t destlen = get_length(env, r1 + 1);
+    uint64_t dest = get_address(env, r1);
+    uint64_t srclen = get_length(env, r3 + 1);
+    uint64_t src = get_address(env, r3);
+    uint8_t pad = a2;
+    uint32_t cc;
+
+    cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 1, ra);
+
+    set_length(env, r1 + 1, destlen);
+    set_length(env, r3 + 1, srclen);
+    set_address(env, r1, dest);
+    set_address(env, r3, src);
+
+    return cc;
+}
+
+/* move long unicode */
+uint32_t HELPER(mvclu)(CPUS390XState *env, uint32_t r1, uint64_t a2,
+                       uint32_t r3)
+{
+    uintptr_t ra = GETPC();
+    uint64_t destlen = get_length(env, r1 + 1);
+    uint64_t dest = get_address(env, r1);
+    uint64_t srclen = get_length(env, r3 + 1);
+    uint64_t src = get_address(env, r3);
+    uint16_t pad = a2;
+    uint32_t cc;
+
+    cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 2, ra);
+
+    set_length(env, r1 + 1, destlen);
+    set_length(env, r3 + 1, srclen);
+    set_address(env, r1, dest);
+    set_address(env, r3, src);
+
+    return cc;
+}
+
+/* compare logical long helper */
+static inline uint32_t do_clcl(CPUS390XState *env,
+                               uint64_t *src1, uint64_t *src1len,
+                               uint64_t *src3, uint64_t *src3len,
+                               uint16_t pad, uint64_t limit,
+                               int wordsize, uintptr_t ra)
+{
+    uint64_t len = MAX(*src1len, *src3len);
+    uint32_t cc = 0;
+
+    check_alignment(env, *src1len | *src3len, wordsize, ra);
+
+    if (!len) {
+        return cc;
+    }
+
+    /* Lest we fail to service interrupts in a timely manner, limit the
+       amount of work we're willing to do.  */
+    if (len > limit) {
+        len = limit;
+        cc = 3;
+    }
+
+    for (; len; len -= wordsize) {
+        uint16_t v1 = pad;
+        uint16_t v3 = pad;
+
+        if (*src1len) {
+            v1 = cpu_ldusize_data_ra(env, *src1, wordsize, ra);
+        }
+        if (*src3len) {
+            v3 = cpu_ldusize_data_ra(env, *src3, wordsize, ra);
+        }
+
+        if (v1 != v3) {
+            cc = (v1 < v3) ? 1 : 2;
+            break;
+        }
+
+        if (*src1len) {
+            *src1 += wordsize;
+            *src1len -= wordsize;
+        }
+        if (*src3len) {
+            *src3 += wordsize;
+            *src3len -= wordsize;
+        }
+    }
+
+    return cc;
+}
+
+
+/* compare logical long */
+uint32_t HELPER(clcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
+{
+    uintptr_t ra = GETPC();
+    uint64_t src1len = extract64(env->regs[r1 + 1], 0, 24);
+    uint64_t src1 = get_address(env, r1);
+    uint64_t src3len = extract64(env->regs[r2 + 1], 0, 24);
+    uint64_t src3 = get_address(env, r2);
+    uint8_t pad = env->regs[r2 + 1] >> 24;
+    uint32_t cc;
+
+    cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, -1, 1, ra);
+
+    env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, src1len);
+    env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, src3len);
+    set_address(env, r1, src1);
+    set_address(env, r2, src3);
+
+    return cc;
+}
+
+/* compare logical long extended memcompare insn with padding */
+uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
+                       uint32_t r3)
+{
+    uintptr_t ra = GETPC();
+    uint64_t src1len = get_length(env, r1 + 1);
+    uint64_t src1 = get_address(env, r1);
+    uint64_t src3len = get_length(env, r3 + 1);
+    uint64_t src3 = get_address(env, r3);
+    uint8_t pad = a2;
+    uint32_t cc;
+
+    cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, 0x2000, 1, ra);
+
+    set_length(env, r1 + 1, src1len);
+    set_length(env, r3 + 1, src3len);
+    set_address(env, r1, src1);
+    set_address(env, r3, src3);
+
+    return cc;
+}
+
+/* compare logical long unicode memcompare insn with padding */
+uint32_t HELPER(clclu)(CPUS390XState *env, uint32_t r1, uint64_t a2,
+                       uint32_t r3)
+{
+    uintptr_t ra = GETPC();
+    uint64_t src1len = get_length(env, r1 + 1);
+    uint64_t src1 = get_address(env, r1);
+    uint64_t src3len = get_length(env, r3 + 1);
+    uint64_t src3 = get_address(env, r3);
+    uint16_t pad = a2;
+    uint32_t cc = 0;
+
+    cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, 0x1000, 2, ra);
+
+    set_length(env, r1 + 1, src1len);
+    set_length(env, r3 + 1, src3len);
+    set_address(env, r1, src1);
+    set_address(env, r3, src3);
+
+    return cc;
+}
+
+/* checksum */
+uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1,
+                      uint64_t src, uint64_t src_len)
+{
+    uintptr_t ra = GETPC();
+    uint64_t max_len, len;
+    uint64_t cksm = (uint32_t)r1;
+
+    /* Lest we fail to service interrupts in a timely manner, limit the
+       amount of work we're willing to do.  For now, let's cap at 8k.  */
+    max_len = (src_len > 0x2000 ? 0x2000 : src_len);
+
+    /* Process full words as available.  */
+    for (len = 0; len + 4 <= max_len; len += 4, src += 4) {
+        cksm += (uint32_t)cpu_ldl_data_ra(env, src, ra);
+    }
+
+    switch (max_len - len) {
+    case 1:
+        cksm += cpu_ldub_data_ra(env, src, ra) << 24;
+        len += 1;
+        break;
+    case 2:
+        cksm += cpu_lduw_data_ra(env, src, ra) << 16;
+        len += 2;
+        break;
+    case 3:
+        cksm += cpu_lduw_data_ra(env, src, ra) << 16;
+        cksm += cpu_ldub_data_ra(env, src + 2, ra) << 8;
+        len += 3;
+        break;
+    }
+
+    /* Fold the carry from the checksum.  Note that we can see carry-out
+       during folding more than once (but probably not more than twice).  */
+    while (cksm > 0xffffffffull) {
+        cksm = (uint32_t)cksm + (cksm >> 32);
+    }
+
+    /* Indicate whether or not we've processed everything.  */
+    env->cc_op = (len == src_len ? 0 : 3);
+
+    /* Return both cksm and processed length.  */
+    env->retxl = cksm;
+    return len;
+}
+
+void HELPER(pack)(CPUS390XState *env, uint32_t len, uint64_t dest, uint64_t src)
+{
+    uintptr_t ra = GETPC();
+    int len_dest = len >> 4;
+    int len_src = len & 0xf;
+    uint8_t b;
+
+    dest += len_dest;
+    src += len_src;
+
+    /* last byte is special, it only flips the nibbles */
+    b = cpu_ldub_data_ra(env, src, ra);
+    cpu_stb_data_ra(env, dest, (b << 4) | (b >> 4), ra);
+    src--;
+    len_src--;
+
+    /* now pack every value */
+    while (len_dest > 0) {
+        b = 0;
+
+        if (len_src >= 0) {
+            b = cpu_ldub_data_ra(env, src, ra) & 0x0f;
+            src--;
+            len_src--;
+        }
+        if (len_src >= 0) {
+            b |= cpu_ldub_data_ra(env, src, ra) << 4;
+            src--;
+            len_src--;
+        }
+
+        len_dest--;
+        dest--;
+        cpu_stb_data_ra(env, dest, b, ra);
+    }
+}
+
+static inline void do_pkau(CPUS390XState *env, uint64_t dest, uint64_t src,
+                           uint32_t srclen, int ssize, uintptr_t ra)
+{
+    int i;
+    /* The destination operand is always 16 bytes long.  */
+    const int destlen = 16;
+
+    /* The operands are processed from right to left.  */
+    src += srclen - 1;
+    dest += destlen - 1;
+
+    for (i = 0; i < destlen; i++) {
+        uint8_t b = 0;
+
+        /* Start with a positive sign */
+        if (i == 0) {
+            b = 0xc;
+        } else if (srclen > ssize) {
+            b = cpu_ldub_data_ra(env, src, ra) & 0x0f;
+            src -= ssize;
+            srclen -= ssize;
+        }
+
+        if (srclen > ssize) {
+            b |= cpu_ldub_data_ra(env, src, ra) << 4;
+            src -= ssize;
+            srclen -= ssize;
+        }
+
+        cpu_stb_data_ra(env, dest, b, ra);
+        dest--;
+    }
+}
+
+
+void HELPER(pka)(CPUS390XState *env, uint64_t dest, uint64_t src,
+                 uint32_t srclen)
+{
+    do_pkau(env, dest, src, srclen, 1, GETPC());
+}
+
+void HELPER(pku)(CPUS390XState *env, uint64_t dest, uint64_t src,
+                 uint32_t srclen)
+{
+    do_pkau(env, dest, src, srclen, 2, GETPC());
+}
+
+void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest,
+                  uint64_t src)
+{
+    uintptr_t ra = GETPC();
+    int len_dest = len >> 4;
+    int len_src = len & 0xf;
+    uint8_t b;
+    int second_nibble = 0;
+
+    dest += len_dest;
+    src += len_src;
+
+    /* last byte is special, it only flips the nibbles */
+    b = cpu_ldub_data_ra(env, src, ra);
+    cpu_stb_data_ra(env, dest, (b << 4) | (b >> 4), ra);
+    src--;
+    len_src--;
+
+    /* now pad every nibble with 0xf0 */
+
+    while (len_dest > 0) {
+        uint8_t cur_byte = 0;
+
+        if (len_src > 0) {
+            cur_byte = cpu_ldub_data_ra(env, src, ra);
+        }
+
+        len_dest--;
+        dest--;
+
+        /* only advance one nibble at a time */
+        if (second_nibble) {
+            cur_byte >>= 4;
+            len_src--;
+            src--;
+        }
+        second_nibble = !second_nibble;
+
+        /* digit */
+        cur_byte = (cur_byte & 0xf);
+        /* zone bits */
+        cur_byte |= 0xf0;
+
+        cpu_stb_data_ra(env, dest, cur_byte, ra);
+    }
+}
+
+static inline uint32_t do_unpkau(CPUS390XState *env, uint64_t dest,
+                                 uint32_t destlen, int dsize, uint64_t src,
+                                 uintptr_t ra)
+{
+    int i;
+    uint32_t cc;
+    uint8_t b;
+    /* The source operand is always 16 bytes long.  */
+    const int srclen = 16;
+
+    /* The operands are processed from right to left.  */
+    src += srclen - 1;
+    dest += destlen - dsize;
+
+    /* Check for the sign.  */
+    b = cpu_ldub_data_ra(env, src, ra);
+    src--;
+    switch (b & 0xf) {
+    case 0xa:
+    case 0xc:
+    case 0xe ... 0xf:
+        cc = 0;  /* plus */
+        break;
+    case 0xb:
+    case 0xd:
+        cc = 1;  /* minus */
+        break;
+    default:
+    case 0x0 ... 0x9:
+        cc = 3;  /* invalid */
+        break;
+    }
+
+    /* Now pad every nibble with 0x30, advancing one nibble at a time. */
+    for (i = 0; i < destlen; i += dsize) {
+        if (i == (31 * dsize)) {
+            /* If length is 32/64 bytes, the leftmost byte is 0. */
+            b = 0;
+        } else if (i % (2 * dsize)) {
+            b = cpu_ldub_data_ra(env, src, ra);
+            src--;
+        } else {
+            b >>= 4;
+        }
+        cpu_stsize_data_ra(env, dest, 0x30 + (b & 0xf), dsize, ra);
+        dest -= dsize;
+    }
+
+    return cc;
+}
+
+uint32_t HELPER(unpka)(CPUS390XState *env, uint64_t dest, uint32_t destlen,
+                       uint64_t src)
+{
+    return do_unpkau(env, dest, destlen, 1, src, GETPC());
+}
+
+uint32_t HELPER(unpku)(CPUS390XState *env, uint64_t dest, uint32_t destlen,
+                       uint64_t src)
+{
+    return do_unpkau(env, dest, destlen, 2, src, GETPC());
+}
+
+uint32_t HELPER(tp)(CPUS390XState *env, uint64_t dest, uint32_t destlen)
+{
+    uintptr_t ra = GETPC();
+    uint32_t cc = 0;
+    int i;
+
+    for (i = 0; i < destlen; i++) {
+        uint8_t b = cpu_ldub_data_ra(env, dest + i, ra);
+        /* digit */
+        cc |= (b & 0xf0) > 0x90 ? 2 : 0;
+
+        if (i == (destlen - 1)) {
+            /* sign */
+            cc |= (b & 0xf) < 0xa ? 1 : 0;
+        } else {
+            /* digit */
+            cc |= (b & 0xf) > 0x9 ? 2 : 0;
+        }
+    }
+
+    return cc;
+}
+
+static uint32_t do_helper_tr(CPUS390XState *env, uint32_t len, uint64_t array,
+                             uint64_t trans, uintptr_t ra)
+{
+    uint32_t i;
+
+    for (i = 0; i <= len; i++) {
+        uint8_t byte = cpu_ldub_data_ra(env, array + i, ra);
+        uint8_t new_byte = cpu_ldub_data_ra(env, trans + byte, ra);
+        cpu_stb_data_ra(env, array + i, new_byte, ra);
+    }
+
+    return env->cc_op;
+}
+
+void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array,
+                uint64_t trans)
+{
+    do_helper_tr(env, len, array, trans, GETPC());
+}
+
+uint64_t HELPER(tre)(CPUS390XState *env, uint64_t array,
+                     uint64_t len, uint64_t trans)
+{
+    uintptr_t ra = GETPC();
+    uint8_t end = env->regs[0] & 0xff;
+    uint64_t l = len;
+    uint64_t i;
+    uint32_t cc = 0;
+
+    if (!(env->psw.mask & PSW_MASK_64)) {
+        array &= 0x7fffffff;
+        l = (uint32_t)l;
+    }
+
+    /* Lest we fail to service interrupts in a timely manner, limit the
+       amount of work we're willing to do.  For now, let's cap at 8k.  */
+    if (l > 0x2000) {
+        l = 0x2000;
+        cc = 3;
+    }
+
+    for (i = 0; i < l; i++) {
+        uint8_t byte, new_byte;
+
+        byte = cpu_ldub_data_ra(env, array + i, ra);
+
+        if (byte == end) {
+            cc = 1;
+            break;
+        }
+
+        new_byte = cpu_ldub_data_ra(env, trans + byte, ra);
+        cpu_stb_data_ra(env, array + i, new_byte, ra);
+    }
+
+    env->cc_op = cc;
+    env->retxl = len - i;
+    return array + i;
+}
+
+static inline uint32_t do_helper_trt(CPUS390XState *env, int len,
+                                     uint64_t array, uint64_t trans,
+                                     int inc, uintptr_t ra)
+{
+    int i;
+
+    for (i = 0; i <= len; i++) {
+        uint8_t byte = cpu_ldub_data_ra(env, array + i * inc, ra);
+        uint8_t sbyte = cpu_ldub_data_ra(env, trans + byte, ra);
+
+        if (sbyte != 0) {
+            set_address(env, 1, array + i * inc);
+            env->regs[2] = deposit64(env->regs[2], 0, 8, sbyte);
+            return (i == len) ? 2 : 1;
+        }
+    }
+
+    return 0;
+}
+
+static uint32_t do_helper_trt_fwd(CPUS390XState *env, uint32_t len,
+                                  uint64_t array, uint64_t trans,
+                                  uintptr_t ra)
+{
+    return do_helper_trt(env, len, array, trans, 1, ra);
+}
+
+uint32_t HELPER(trt)(CPUS390XState *env, uint32_t len, uint64_t array,
+                     uint64_t trans)
+{
+    return do_helper_trt(env, len, array, trans, 1, GETPC());
+}
+
+static uint32_t do_helper_trt_bkwd(CPUS390XState *env, uint32_t len,
+                                   uint64_t array, uint64_t trans,
+                                   uintptr_t ra)
+{
+    return do_helper_trt(env, len, array, trans, -1, ra);
+}
+
+uint32_t HELPER(trtr)(CPUS390XState *env, uint32_t len, uint64_t array,
+                      uint64_t trans)
+{
+    return do_helper_trt(env, len, array, trans, -1, GETPC());
+}
+
+/* Translate one/two to one/two */
+uint32_t HELPER(trXX)(CPUS390XState *env, uint32_t r1, uint32_t r2,
+                      uint32_t tst, uint32_t sizes)
+{
+    uintptr_t ra = GETPC();
+    int dsize = (sizes & 1) ? 1 : 2;
+    int ssize = (sizes & 2) ? 1 : 2;
+    uint64_t tbl = get_address(env, 1);
+    uint64_t dst = get_address(env, r1);
+    uint64_t len = get_length(env, r1 + 1);
+    uint64_t src = get_address(env, r2);
+    uint32_t cc = 3;
+    int i;
+
+    /* The lower address bits of TBL are ignored.  For TROO, TROT, it's
+       the low 3 bits (double-word aligned).  For TRTO, TRTT, it's either
+       the low 12 bits (4K, without ETF2-ENH) or 3 bits (with ETF2-ENH).  */
+    if (ssize == 2 && !s390_has_feat(S390_FEAT_ETF2_ENH)) {
+        tbl &= -4096;
+    } else {
+        tbl &= -8;
+    }
+
+    check_alignment(env, len, ssize, ra);
+
+    /* Lest we fail to service interrupts in a timely manner, */
+    /* limit the amount of work we're willing to do.   */
+    for (i = 0; i < 0x2000; i++) {
+        uint16_t sval = cpu_ldusize_data_ra(env, src, ssize, ra);
+        uint64_t tble = tbl + (sval * dsize);
+        uint16_t dval = cpu_ldusize_data_ra(env, tble, dsize, ra);
+        if (dval == tst) {
+            cc = 1;
+            break;
+        }
+        cpu_stsize_data_ra(env, dst, dval, dsize, ra);
+
+        len -= ssize;
+        src += ssize;
+        dst += dsize;
+
+        if (len == 0) {
+            cc = 0;
+            break;
+        }
+    }
+
+    set_address(env, r1, dst);
+    set_length(env, r1 + 1, len);
+    set_address(env, r2, src);
+
+    return cc;
+}
+
+void HELPER(cdsg)(CPUS390XState *env, uint64_t addr,
+                  uint32_t r1, uint32_t r3)
+{
+    uintptr_t ra = GETPC();
+    Int128 cmpv = int128_make128(env->regs[r1 + 1], env->regs[r1]);
+    Int128 newv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
+    Int128 oldv;
+    uint64_t oldh, oldl;
+    bool fail;
+
+    check_alignment(env, addr, 16, ra);
+
+    oldh = cpu_ldq_data_ra(env, addr + 0, ra);
+    oldl = cpu_ldq_data_ra(env, addr + 8, ra);
+
+    oldv = int128_make128(oldl, oldh);
+    fail = !int128_eq(oldv, cmpv);
+    if (fail) {
+        newv = oldv;
+    }
+
+    cpu_stq_data_ra(env, addr + 0, int128_gethi(newv), ra);
+    cpu_stq_data_ra(env, addr + 8, int128_getlo(newv), ra);
+
+    env->cc_op = fail;
+    env->regs[r1] = int128_gethi(oldv);
+    env->regs[r1 + 1] = int128_getlo(oldv);
+}
+
+void HELPER(cdsg_parallel)(CPUS390XState *env, uint64_t addr,
+                           uint32_t r1, uint32_t r3)
+{
+    uintptr_t ra = GETPC();
+    Int128 cmpv = int128_make128(env->regs[r1 + 1], env->regs[r1]);
+    Int128 newv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
+    int mem_idx;
+    TCGMemOpIdx oi;
+    Int128 oldv;
+    bool fail;
+
+    assert(HAVE_CMPXCHG128);
+
+    mem_idx = cpu_mmu_index(env, false);
+    oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
+    oldv = helper_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra);
+    fail = !int128_eq(oldv, cmpv);
+
+    env->cc_op = fail;
+    env->regs[r1] = int128_gethi(oldv);
+    env->regs[r1 + 1] = int128_getlo(oldv);
+}
+
+static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1,
+                        uint64_t a2, bool parallel)
+{
+    uint32_t mem_idx = cpu_mmu_index(env, false);
+    uintptr_t ra = GETPC();
+    uint32_t fc = extract32(env->regs[0], 0, 8);
+    uint32_t sc = extract32(env->regs[0], 8, 8);
+    uint64_t pl = get_address(env, 1) & -16;
+    uint64_t svh, svl;
+    uint32_t cc;
+
+    /* Sanity check the function code and storage characteristic.  */
+    if (fc > 1 || sc > 3) {
+        if (!s390_has_feat(S390_FEAT_COMPARE_AND_SWAP_AND_STORE_2)) {
+            goto spec_exception;
+        }
+        if (fc > 2 || sc > 4 || (fc == 2 && (r3 & 1))) {
+            goto spec_exception;
+        }
+    }
+
+    /* Sanity check the alignments.  */
+    if (extract32(a1, 0, fc + 2) || extract32(a2, 0, sc)) {
+        goto spec_exception;
+    }
+
+    /* Sanity check writability of the store address.  */
+    probe_write(env, a2, 1 << sc, mem_idx, ra);
+
+    /*
+     * Note that the compare-and-swap is atomic, and the store is atomic,
+     * but the complete operation is not.  Therefore we do not need to
+     * assert serial context in order to implement this.  That said,
+     * restart early if we can't support either operation that is supposed
+     * to be atomic.
+     */
+    if (parallel) {
+        uint32_t max = 2;
+#ifdef CONFIG_ATOMIC64
+        max = 3;
+#endif
+        if ((HAVE_CMPXCHG128 ? 0 : fc + 2 > max) ||
+            (HAVE_ATOMIC128  ? 0 : sc > max)) {
+            cpu_loop_exit_atomic(env_cpu(env), ra);
+        }
+    }
+
+    /* All loads happen before all stores.  For simplicity, load the entire
+       store value area from the parameter list.  */
+    svh = cpu_ldq_data_ra(env, pl + 16, ra);
+    svl = cpu_ldq_data_ra(env, pl + 24, ra);
+
+    switch (fc) {
+    case 0:
+        {
+            uint32_t nv = cpu_ldl_data_ra(env, pl, ra);
+            uint32_t cv = env->regs[r3];
+            uint32_t ov;
+
+            if (parallel) {
+#ifdef CONFIG_USER_ONLY
+                uint32_t *haddr = g2h(env_cpu(env), a1);
+                ov = qatomic_cmpxchg__nocheck(haddr, cv, nv);
+#else
+                TCGMemOpIdx oi = make_memop_idx(MO_TEUL | MO_ALIGN, mem_idx);
+                ov = helper_atomic_cmpxchgl_be_mmu(env, a1, cv, nv, oi, ra);
+#endif
+            } else {
+                ov = cpu_ldl_data_ra(env, a1, ra);
+                cpu_stl_data_ra(env, a1, (ov == cv ? nv : ov), ra);
+            }
+            cc = (ov != cv);
+            env->regs[r3] = deposit64(env->regs[r3], 32, 32, ov);
+        }
+        break;
+
+    case 1:
+        {
+            uint64_t nv = cpu_ldq_data_ra(env, pl, ra);
+            uint64_t cv = env->regs[r3];
+            uint64_t ov;
+
+            if (parallel) {
+#ifdef CONFIG_ATOMIC64
+# ifdef CONFIG_USER_ONLY
+                uint64_t *haddr = g2h(env_cpu(env), a1);
+                ov = qatomic_cmpxchg__nocheck(haddr, cv, nv);
+# else
+                TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN, mem_idx);
+                ov = helper_atomic_cmpxchgq_be_mmu(env, a1, cv, nv, oi, ra);
+# endif
+#else
+                /* Note that we asserted !parallel above.  */
+                g_assert_not_reached();
+#endif
+            } else {
+                ov = cpu_ldq_data_ra(env, a1, ra);
+                cpu_stq_data_ra(env, a1, (ov == cv ? nv : ov), ra);
+            }
+            cc = (ov != cv);
+            env->regs[r3] = ov;
+        }
+        break;
+
+    case 2:
+        {
+            uint64_t nvh = cpu_ldq_data_ra(env, pl, ra);
+            uint64_t nvl = cpu_ldq_data_ra(env, pl + 8, ra);
+            Int128 nv = int128_make128(nvl, nvh);
+            Int128 cv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
+            Int128 ov;
+
+            if (!parallel) {
+                uint64_t oh = cpu_ldq_data_ra(env, a1 + 0, ra);
+                uint64_t ol = cpu_ldq_data_ra(env, a1 + 8, ra);
+
+                ov = int128_make128(ol, oh);
+                cc = !int128_eq(ov, cv);
+                if (cc) {
+                    nv = ov;
+                }
+
+                cpu_stq_data_ra(env, a1 + 0, int128_gethi(nv), ra);
+                cpu_stq_data_ra(env, a1 + 8, int128_getlo(nv), ra);
+            } else if (HAVE_CMPXCHG128) {
+                TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
+                ov = helper_atomic_cmpxchgo_be_mmu(env, a1, cv, nv, oi, ra);
+                cc = !int128_eq(ov, cv);
+            } else {
+                /* Note that we asserted !parallel above.  */
+                g_assert_not_reached();
+            }
+
+            env->regs[r3 + 0] = int128_gethi(ov);
+            env->regs[r3 + 1] = int128_getlo(ov);
+        }
+        break;
+
+    default:
+        g_assert_not_reached();
+    }
+
+    /* Store only if the comparison succeeded.  Note that above we use a pair
+       of 64-bit big-endian loads, so for sc < 3 we must extract the value
+       from the most-significant bits of svh.  */
+    if (cc == 0) {
+        switch (sc) {
+        case 0:
+            cpu_stb_data_ra(env, a2, svh >> 56, ra);
+            break;
+        case 1:
+            cpu_stw_data_ra(env, a2, svh >> 48, ra);
+            break;
+        case 2:
+            cpu_stl_data_ra(env, a2, svh >> 32, ra);
+            break;
+        case 3:
+            cpu_stq_data_ra(env, a2, svh, ra);
+            break;
+        case 4:
+            if (!parallel) {
+                cpu_stq_data_ra(env, a2 + 0, svh, ra);
+                cpu_stq_data_ra(env, a2 + 8, svl, ra);
+            } else if (HAVE_ATOMIC128) {
+                TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
+                Int128 sv = int128_make128(svl, svh);
+                helper_atomic_sto_be_mmu(env, a2, sv, oi, ra);
+            } else {
+                /* Note that we asserted !parallel above.  */
+                g_assert_not_reached();
+            }
+            break;
+        default:
+            g_assert_not_reached();
+        }
+    }
+
+    return cc;
+
+ spec_exception:
+    tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+}
+
+uint32_t HELPER(csst)(CPUS390XState *env, uint32_t r3, uint64_t a1, uint64_t a2)
+{
+    return do_csst(env, r3, a1, a2, false);
+}
+
+uint32_t HELPER(csst_parallel)(CPUS390XState *env, uint32_t r3, uint64_t a1,
+                               uint64_t a2)
+{
+    return do_csst(env, r3, a1, a2, true);
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    uintptr_t ra = GETPC();
+    bool PERchanged = false;
+    uint64_t src = a2;
+    uint32_t i;
+
+    if (src & 0x7) {
+        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+    }
+
+    for (i = r1;; i = (i + 1) % 16) {
+        uint64_t val = cpu_ldq_data_ra(env, src, ra);
+        if (env->cregs[i] != val && i >= 9 && i <= 11) {
+            PERchanged = true;
+        }
+        env->cregs[i] = val;
+        HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
+                   i, src, val);
+        src += sizeof(uint64_t);
+
+        if (i == r3) {
+            break;
+        }
+    }
+
+    if (PERchanged && env->psw.mask & PSW_MASK_PER) {
+        s390_cpu_recompute_watchpoints(env_cpu(env));
+    }
+
+    tlb_flush(env_cpu(env));
+}
+
+void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    uintptr_t ra = GETPC();
+    bool PERchanged = false;
+    uint64_t src = a2;
+    uint32_t i;
+
+    if (src & 0x3) {
+        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+    }
+
+    for (i = r1;; i = (i + 1) % 16) {
+        uint32_t val = cpu_ldl_data_ra(env, src, ra);
+        if ((uint32_t)env->cregs[i] != val && i >= 9 && i <= 11) {
+            PERchanged = true;
+        }
+        env->cregs[i] = deposit64(env->cregs[i], 0, 32, val);
+        HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%x\n", i, src, val);
+        src += sizeof(uint32_t);
+
+        if (i == r3) {
+            break;
+        }
+    }
+
+    if (PERchanged && env->psw.mask & PSW_MASK_PER) {
+        s390_cpu_recompute_watchpoints(env_cpu(env));
+    }
+
+    tlb_flush(env_cpu(env));
+}
+
+void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    uintptr_t ra = GETPC();
+    uint64_t dest = a2;
+    uint32_t i;
+
+    if (dest & 0x7) {
+        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+    }
+
+    for (i = r1;; i = (i + 1) % 16) {
+        cpu_stq_data_ra(env, dest, env->cregs[i], ra);
+        dest += sizeof(uint64_t);
+
+        if (i == r3) {
+            break;
+        }
+    }
+}
+
+void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
+{
+    uintptr_t ra = GETPC();
+    uint64_t dest = a2;
+    uint32_t i;
+
+    if (dest & 0x3) {
+        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+    }
+
+    for (i = r1;; i = (i + 1) % 16) {
+        cpu_stl_data_ra(env, dest, env->cregs[i], ra);
+        dest += sizeof(uint32_t);
+
+        if (i == r3) {
+            break;
+        }
+    }
+}
+
+uint32_t HELPER(testblock)(CPUS390XState *env, uint64_t real_addr)
+{
+    uintptr_t ra = GETPC();
+    int i;
+
+    real_addr = wrap_address(env, real_addr) & TARGET_PAGE_MASK;
+
+    for (i = 0; i < TARGET_PAGE_SIZE; i += 8) {
+        cpu_stq_mmuidx_ra(env, real_addr + i, 0, MMU_REAL_IDX, ra);
+    }
+
+    return 0;
+}
+
+uint32_t HELPER(tprot)(CPUS390XState *env, uint64_t a1, uint64_t a2)
+{
+    S390CPU *cpu = env_archcpu(env);
+    CPUState *cs = env_cpu(env);
+
+    /*
+     * TODO: we currently don't handle all access protection types
+     * (including access-list and key-controlled) as well as AR mode.
+     */
+    if (!s390_cpu_virt_mem_check_write(cpu, a1, 0, 1)) {
+        /* Fetching permitted; storing permitted */
+        return 0;
+    }
+
+    if (env->int_pgm_code == PGM_PROTECTION) {
+        /* retry if reading is possible */
+        cs->exception_index = -1;
+        if (!s390_cpu_virt_mem_check_read(cpu, a1, 0, 1)) {
+            /* Fetching permitted; storing not permitted */
+            return 1;
+        }
+    }
+
+    switch (env->int_pgm_code) {
+    case PGM_PROTECTION:
+        /* Fetching not permitted; storing not permitted */
+        cs->exception_index = -1;
+        return 2;
+    case PGM_ADDRESSING:
+    case PGM_TRANS_SPEC:
+        /* exceptions forwarded to the guest */
+        s390_cpu_virt_mem_handle_exc(cpu, GETPC());
+        return 0;
+    }
+
+    /* Translation not available */
+    cs->exception_index = -1;
+    return 3;
+}
+
+/* insert storage key extended */
+uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
+{
+    MachineState *ms = MACHINE(qdev_get_machine());
+    static S390SKeysState *ss;
+    static S390SKeysClass *skeyclass;
+    uint64_t addr = wrap_address(env, r2);
+    uint8_t key;
+
+    if (addr > ms->ram_size) {
+        return 0;
+    }
+
+    if (unlikely(!ss)) {
+        ss = s390_get_skeys_device();
+        skeyclass = S390_SKEYS_GET_CLASS(ss);
+    }
+
+    if (skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key)) {
+        return 0;
+    }
+    return key;
+}
+
+/* set storage key extended */
+void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2)
+{
+    MachineState *ms = MACHINE(qdev_get_machine());
+    static S390SKeysState *ss;
+    static S390SKeysClass *skeyclass;
+    uint64_t addr = wrap_address(env, r2);
+    uint8_t key;
+
+    if (addr > ms->ram_size) {
+        return;
+    }
+
+    if (unlikely(!ss)) {
+        ss = s390_get_skeys_device();
+        skeyclass = S390_SKEYS_GET_CLASS(ss);
+    }
+
+    key = (uint8_t) r1;
+    skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
+   /*
+    * As we can only flush by virtual address and not all the entries
+    * that point to a physical address we have to flush the whole TLB.
+    */
+    tlb_flush_all_cpus_synced(env_cpu(env));
+}
+
+/* reset reference bit extended */
+uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2)
+{
+    MachineState *ms = MACHINE(qdev_get_machine());
+    static S390SKeysState *ss;
+    static S390SKeysClass *skeyclass;
+    uint8_t re, key;
+
+    if (r2 > ms->ram_size) {
+        return 0;
+    }
+
+    if (unlikely(!ss)) {
+        ss = s390_get_skeys_device();
+        skeyclass = S390_SKEYS_GET_CLASS(ss);
+    }
+
+    if (skeyclass->get_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
+        return 0;
+    }
+
+    re = key & (SK_R | SK_C);
+    key &= ~SK_R;
+
+    if (skeyclass->set_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
+        return 0;
+    }
+   /*
+    * As we can only flush by virtual address and not all the entries
+    * that point to a physical address we have to flush the whole TLB.
+    */
+    tlb_flush_all_cpus_synced(env_cpu(env));
+
+    /*
+     * cc
+     *
+     * 0  Reference bit zero; change bit zero
+     * 1  Reference bit zero; change bit one
+     * 2  Reference bit one; change bit zero
+     * 3  Reference bit one; change bit one
+     */
+
+    return re >> 1;
+}
+
+uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
+{
+    const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC;
+    S390Access srca, desta;
+    uintptr_t ra = GETPC();
+    int cc = 0;
+
+    HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
+               __func__, l, a1, a2);
+
+    if (!(env->psw.mask & PSW_MASK_DAT) || !(env->cregs[0] & CR0_SECONDARY) ||
+        psw_as == AS_HOME || psw_as == AS_ACCREG) {
+        s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
+    }
+
+    l = wrap_length32(env, l);
+    if (l > 256) {
+        /* max 256 */
+        l = 256;
+        cc = 3;
+    } else if (!l) {
+        return cc;
+    }
+
+    /* TODO: Access key handling */
+    srca = access_prepare(env, a2, l, MMU_DATA_LOAD, MMU_PRIMARY_IDX, ra);
+    desta = access_prepare(env, a1, l, MMU_DATA_STORE, MMU_SECONDARY_IDX, ra);
+    access_memmove(env, &desta, &srca, ra);
+    return cc;
+}
+
+uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
+{
+    const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC;
+    S390Access srca, desta;
+    uintptr_t ra = GETPC();
+    int cc = 0;
+
+    HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
+               __func__, l, a1, a2);
+
+    if (!(env->psw.mask & PSW_MASK_DAT) || !(env->cregs[0] & CR0_SECONDARY) ||
+        psw_as == AS_HOME || psw_as == AS_ACCREG) {
+        s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
+    }
+
+    l = wrap_length32(env, l);
+    if (l > 256) {
+        /* max 256 */
+        l = 256;
+        cc = 3;
+    } else if (!l) {
+        return cc;
+    }
+
+    /* TODO: Access key handling */
+    srca = access_prepare(env, a2, l, MMU_DATA_LOAD, MMU_SECONDARY_IDX, ra);
+    desta = access_prepare(env, a1, l, MMU_DATA_STORE, MMU_PRIMARY_IDX, ra);
+    access_memmove(env, &desta, &srca, ra);
+    return cc;
+}
+
+void HELPER(idte)(CPUS390XState *env, uint64_t r1, uint64_t r2, uint32_t m4)
+{
+    CPUState *cs = env_cpu(env);
+    const uintptr_t ra = GETPC();
+    uint64_t table, entry, raddr;
+    uint16_t entries, i, index = 0;
+
+    if (r2 & 0xff000) {
+        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+    }
+
+    if (!(r2 & 0x800)) {
+        /* invalidation-and-clearing operation */
+        table = r1 & ASCE_ORIGIN;
+        entries = (r2 & 0x7ff) + 1;
+
+        switch (r1 & ASCE_TYPE_MASK) {
+        case ASCE_TYPE_REGION1:
+            index = (r2 >> 53) & 0x7ff;
+            break;
+        case ASCE_TYPE_REGION2:
+            index = (r2 >> 42) & 0x7ff;
+            break;
+        case ASCE_TYPE_REGION3:
+            index = (r2 >> 31) & 0x7ff;
+            break;
+        case ASCE_TYPE_SEGMENT:
+            index = (r2 >> 20) & 0x7ff;
+            break;
+        }
+        for (i = 0; i < entries; i++) {
+            /* addresses are not wrapped in 24/31bit mode but table index is */
+            raddr = table + ((index + i) & 0x7ff) * sizeof(entry);
+            entry = cpu_ldq_mmuidx_ra(env, raddr, MMU_REAL_IDX, ra);
+            if (!(entry & REGION_ENTRY_I)) {
+                /* we are allowed to not store if already invalid */
+                entry |= REGION_ENTRY_I;
+                cpu_stq_mmuidx_ra(env, raddr, entry, MMU_REAL_IDX, ra);
+            }
+        }
+    }
+
+    /* We simply flush the complete tlb, therefore we can ignore r3. */
+    if (m4 & 1) {
+        tlb_flush(cs);
+    } else {
+        tlb_flush_all_cpus_synced(cs);
+    }
+}
+
+/* invalidate pte */
+void HELPER(ipte)(CPUS390XState *env, uint64_t pto, uint64_t vaddr,
+                  uint32_t m4)
+{
+    CPUState *cs = env_cpu(env);
+    const uintptr_t ra = GETPC();
+    uint64_t page = vaddr & TARGET_PAGE_MASK;
+    uint64_t pte_addr, pte;
+
+    /* Compute the page table entry address */
+    pte_addr = (pto & SEGMENT_ENTRY_ORIGIN);
+    pte_addr += VADDR_PAGE_TX(vaddr) * 8;
+
+    /* Mark the page table entry as invalid */
+    pte = cpu_ldq_mmuidx_ra(env, pte_addr, MMU_REAL_IDX, ra);
+    pte |= PAGE_ENTRY_I;
+    cpu_stq_mmuidx_ra(env, pte_addr, pte, MMU_REAL_IDX, ra);
+
+    /* XXX we exploit the fact that Linux passes the exact virtual
+       address here - it's not obliged to! */
+    if (m4 & 1) {
+        if (vaddr & ~VADDR_PAGE_TX_MASK) {
+            tlb_flush_page(cs, page);
+            /* XXX 31-bit hack */
+            tlb_flush_page(cs, page ^ 0x80000000);
+        } else {
+            /* looks like we don't have a valid virtual address */
+            tlb_flush(cs);
+        }
+    } else {
+        if (vaddr & ~VADDR_PAGE_TX_MASK) {
+            tlb_flush_page_all_cpus_synced(cs, page);
+            /* XXX 31-bit hack */
+            tlb_flush_page_all_cpus_synced(cs, page ^ 0x80000000);
+        } else {
+            /* looks like we don't have a valid virtual address */
+            tlb_flush_all_cpus_synced(cs);
+        }
+    }
+}
+
+/* flush local tlb */
+void HELPER(ptlb)(CPUS390XState *env)
+{
+    tlb_flush(env_cpu(env));
+}
+
+/* flush global tlb */
+void HELPER(purge)(CPUS390XState *env)
+{
+    tlb_flush_all_cpus_synced(env_cpu(env));
+}
+
+/* load real address */
+uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
+{
+    uint64_t asc = env->psw.mask & PSW_MASK_ASC;
+    uint64_t ret, tec;
+    int flags, exc, cc;
+
+    /* XXX incomplete - has more corner cases */
+    if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
+        tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, GETPC());
+    }
+
+    exc = mmu_translate(env, addr, 0, asc, &ret, &flags, &tec);
+    if (exc) {
+        cc = 3;
+        ret = exc | 0x80000000;
+    } else {
+        cc = 0;
+        ret |= addr & ~TARGET_PAGE_MASK;
+    }
+
+    env->cc_op = cc;
+    return ret;
+}
+#endif
+
+/* load pair from quadword */
+uint64_t HELPER(lpq)(CPUS390XState *env, uint64_t addr)
+{
+    uintptr_t ra = GETPC();
+    uint64_t hi, lo;
+
+    check_alignment(env, addr, 16, ra);
+    hi = cpu_ldq_data_ra(env, addr + 0, ra);
+    lo = cpu_ldq_data_ra(env, addr + 8, ra);
+
+    env->retxl = lo;
+    return hi;
+}
+
+uint64_t HELPER(lpq_parallel)(CPUS390XState *env, uint64_t addr)
+{
+    uintptr_t ra = GETPC();
+    uint64_t hi, lo;
+    int mem_idx;
+    TCGMemOpIdx oi;
+    Int128 v;
+
+    assert(HAVE_ATOMIC128);
+
+    mem_idx = cpu_mmu_index(env, false);
+    oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
+    v = helper_atomic_ldo_be_mmu(env, addr, oi, ra);
+    hi = int128_gethi(v);
+    lo = int128_getlo(v);
+
+    env->retxl = lo;
+    return hi;
+}
+
+/* store pair to quadword */
+void HELPER(stpq)(CPUS390XState *env, uint64_t addr,
+                  uint64_t low, uint64_t high)
+{
+    uintptr_t ra = GETPC();
+
+    check_alignment(env, addr, 16, ra);
+    cpu_stq_data_ra(env, addr + 0, high, ra);
+    cpu_stq_data_ra(env, addr + 8, low, ra);
+}
+
+void HELPER(stpq_parallel)(CPUS390XState *env, uint64_t addr,
+                           uint64_t low, uint64_t high)
+{
+    uintptr_t ra = GETPC();
+    int mem_idx;
+    TCGMemOpIdx oi;
+    Int128 v;
+
+    assert(HAVE_ATOMIC128);
+
+    mem_idx = cpu_mmu_index(env, false);
+    oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
+    v = int128_make128(low, high);
+    helper_atomic_sto_be_mmu(env, addr, v, oi, ra);
+}
+
+/* Execute instruction.  This instruction executes an insn modified with
+   the contents of r1.  It does not change the executed instruction in memory;
+   it does not change the program counter.
+
+   Perform this by recording the modified instruction in env->ex_value.
+   This will be noticed by cpu_get_tb_cpu_state and thus tb translation.
+*/
+void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr)
+{
+    uint64_t insn = cpu_lduw_code(env, addr);
+    uint8_t opc = insn >> 8;
+
+    /* Or in the contents of R1[56:63].  */
+    insn |= r1 & 0xff;
+
+    /* Load the rest of the instruction.  */
+    insn <<= 48;
+    switch (get_ilen(opc)) {
+    case 2:
+        break;
+    case 4:
+        insn |= (uint64_t)cpu_lduw_code(env, addr + 2) << 32;
+        break;
+    case 6:
+        insn |= (uint64_t)(uint32_t)cpu_ldl_code(env, addr + 2) << 16;
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    /* The very most common cases can be sped up by avoiding a new TB.  */
+    if ((opc & 0xf0) == 0xd0) {
+        typedef uint32_t (*dx_helper)(CPUS390XState *, uint32_t, uint64_t,
+                                      uint64_t, uintptr_t);
+        static const dx_helper dx[16] = {
+            [0x0] = do_helper_trt_bkwd,
+            [0x2] = do_helper_mvc,
+            [0x4] = do_helper_nc,
+            [0x5] = do_helper_clc,
+            [0x6] = do_helper_oc,
+            [0x7] = do_helper_xc,
+            [0xc] = do_helper_tr,
+            [0xd] = do_helper_trt_fwd,
+        };
+        dx_helper helper = dx[opc & 0xf];
+
+        if (helper) {
+            uint32_t l = extract64(insn, 48, 8);
+            uint32_t b1 = extract64(insn, 44, 4);
+            uint32_t d1 = extract64(insn, 32, 12);
+            uint32_t b2 = extract64(insn, 28, 4);
+            uint32_t d2 = extract64(insn, 16, 12);
+            uint64_t a1 = wrap_address(env, (b1 ? env->regs[b1] : 0) + d1);
+            uint64_t a2 = wrap_address(env, (b2 ? env->regs[b2] : 0) + d2);
+
+            env->cc_op = helper(env, l, a1, a2, 0);
+            env->psw.addr += ilen;
+            return;
+        }
+    } else if (opc == 0x0a) {
+        env->int_svc_code = extract64(insn, 48, 8);
+        env->int_svc_ilen = ilen;
+        helper_exception(env, EXCP_SVC);
+        g_assert_not_reached();
+    }
+
+    /* Record the insn we want to execute as well as the ilen to use
+       during the execution of the target insn.  This will also ensure
+       that ex_value is non-zero, which flags that we are in a state
+       that requires such execution.  */
+    env->ex_value = insn | ilen;
+}
+
+uint32_t HELPER(mvcos)(CPUS390XState *env, uint64_t dest, uint64_t src,
+                       uint64_t len)
+{
+    const uint8_t psw_key = (env->psw.mask & PSW_MASK_KEY) >> PSW_SHIFT_KEY;
+    const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC;
+    const uint64_t r0 = env->regs[0];
+    const uintptr_t ra = GETPC();
+    uint8_t dest_key, dest_as, dest_k, dest_a;
+    uint8_t src_key, src_as, src_k, src_a;
+    uint64_t val;
+    int cc = 0;
+
+    HELPER_LOG("%s dest %" PRIx64 ", src %" PRIx64 ", len %" PRIx64 "\n",
+               __func__, dest, src, len);
+
+    if (!(env->psw.mask & PSW_MASK_DAT)) {
+        tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
+    }
+
+    /* OAC (operand access control) for the first operand -> dest */
+    val = (r0 & 0xffff0000ULL) >> 16;
+    dest_key = (val >> 12) & 0xf;
+    dest_as = (val >> 6) & 0x3;
+    dest_k = (val >> 1) & 0x1;
+    dest_a = val & 0x1;
+
+    /* OAC (operand access control) for the second operand -> src */
+    val = (r0 & 0x0000ffffULL);
+    src_key = (val >> 12) & 0xf;
+    src_as = (val >> 6) & 0x3;
+    src_k = (val >> 1) & 0x1;
+    src_a = val & 0x1;
+
+    if (!dest_k) {
+        dest_key = psw_key;
+    }
+    if (!src_k) {
+        src_key = psw_key;
+    }
+    if (!dest_a) {
+        dest_as = psw_as;
+    }
+    if (!src_a) {
+        src_as = psw_as;
+    }
+
+    if (dest_a && dest_as == AS_HOME && (env->psw.mask & PSW_MASK_PSTATE)) {
+        tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
+    }
+    if (!(env->cregs[0] & CR0_SECONDARY) &&
+        (dest_as == AS_SECONDARY || src_as == AS_SECONDARY)) {
+        tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
+    }
+    if (!psw_key_valid(env, dest_key) || !psw_key_valid(env, src_key)) {
+        tcg_s390_program_interrupt(env, PGM_PRIVILEGED, ra);
+    }
+
+    len = wrap_length32(env, len);
+    if (len > 4096) {
+        cc = 3;
+        len = 4096;
+    }
+
+    /* FIXME: AR-mode and proper problem state mode (using PSW keys) missing */
+    if (src_as == AS_ACCREG || dest_as == AS_ACCREG ||
+        (env->psw.mask & PSW_MASK_PSTATE)) {
+        qemu_log_mask(LOG_UNIMP, "%s: AR-mode and PSTATE support missing\n",
+                      __func__);
+        tcg_s390_program_interrupt(env, PGM_ADDRESSING, ra);
+    }
+
+    /* FIXME: Access using correct keys and AR-mode */
+    if (len) {
+        S390Access srca = access_prepare(env, src, len, MMU_DATA_LOAD,
+                                         mmu_idx_from_as(src_as), ra);
+        S390Access desta = access_prepare(env, dest, len, MMU_DATA_STORE,
+                                          mmu_idx_from_as(dest_as), ra);
+
+        access_memmove(env, &desta, &srca, ra);
+    }
+
+    return cc;
+}
+
+/* Decode a Unicode character.  A return value < 0 indicates success, storing
+   the UTF-32 result into OCHAR and the input length into OLEN.  A return
+   value >= 0 indicates failure, and the CC value to be returned.  */
+typedef int (*decode_unicode_fn)(CPUS390XState *env, uint64_t addr,
+                                 uint64_t ilen, bool enh_check, uintptr_t ra,
+                                 uint32_t *ochar, uint32_t *olen);
+
+/* Encode a Unicode character.  A return value < 0 indicates success, storing
+   the bytes into ADDR and the output length into OLEN.  A return value >= 0
+   indicates failure, and the CC value to be returned.  */
+typedef int (*encode_unicode_fn)(CPUS390XState *env, uint64_t addr,
+                                 uint64_t ilen, uintptr_t ra, uint32_t c,
+                                 uint32_t *olen);
+
+static int decode_utf8(CPUS390XState *env, uint64_t addr, uint64_t ilen,
+                       bool enh_check, uintptr_t ra,
+                       uint32_t *ochar, uint32_t *olen)
+{
+    uint8_t s0, s1, s2, s3;
+    uint32_t c, l;
+
+    if (ilen < 1) {
+        return 0;
+    }
+    s0 = cpu_ldub_data_ra(env, addr, ra);
+    if (s0 <= 0x7f) {
+        /* one byte character */
+        l = 1;
+        c = s0;
+    } else if (s0 <= (enh_check ? 0xc1 : 0xbf)) {
+        /* invalid character */
+        return 2;
+    } else if (s0 <= 0xdf) {
+        /* two byte character */
+        l = 2;
+        if (ilen < 2) {
+            return 0;
+        }
+        s1 = cpu_ldub_data_ra(env, addr + 1, ra);
+        c = s0 & 0x1f;
+        c = (c << 6) | (s1 & 0x3f);
+        if (enh_check && (s1 & 0xc0) != 0x80) {
+            return 2;
+        }
+    } else if (s0 <= 0xef) {
+        /* three byte character */
+        l = 3;
+        if (ilen < 3) {
+            return 0;
+        }
+        s1 = cpu_ldub_data_ra(env, addr + 1, ra);
+        s2 = cpu_ldub_data_ra(env, addr + 2, ra);
+        c = s0 & 0x0f;
+        c = (c << 6) | (s1 & 0x3f);
+        c = (c << 6) | (s2 & 0x3f);
+        /* Fold the byte-by-byte range descriptions in the PoO into
+           tests against the complete value.  It disallows encodings
+           that could be smaller, and the UTF-16 surrogates.  */
+        if (enh_check
+            && ((s1 & 0xc0) != 0x80
+                || (s2 & 0xc0) != 0x80
+                || c < 0x1000
+                || (c >= 0xd800 && c <= 0xdfff))) {
+            return 2;
+        }
+    } else if (s0 <= (enh_check ? 0xf4 : 0xf7)) {
+        /* four byte character */
+        l = 4;
+        if (ilen < 4) {
+            return 0;
+        }
+        s1 = cpu_ldub_data_ra(env, addr + 1, ra);
+        s2 = cpu_ldub_data_ra(env, addr + 2, ra);
+        s3 = cpu_ldub_data_ra(env, addr + 3, ra);
+        c = s0 & 0x07;
+        c = (c << 6) | (s1 & 0x3f);
+        c = (c << 6) | (s2 & 0x3f);
+        c = (c << 6) | (s3 & 0x3f);
+        /* See above.  */
+        if (enh_check
+            && ((s1 & 0xc0) != 0x80
+                || (s2 & 0xc0) != 0x80
+                || (s3 & 0xc0) != 0x80
+                || c < 0x010000
+                || c > 0x10ffff)) {
+            return 2;
+        }
+    } else {
+        /* invalid character */
+        return 2;
+    }
+
+    *ochar = c;
+    *olen = l;
+    return -1;
+}
+
+static int decode_utf16(CPUS390XState *env, uint64_t addr, uint64_t ilen,
+                        bool enh_check, uintptr_t ra,
+                        uint32_t *ochar, uint32_t *olen)
+{
+    uint16_t s0, s1;
+    uint32_t c, l;
+
+    if (ilen < 2) {
+        return 0;
+    }
+    s0 = cpu_lduw_data_ra(env, addr, ra);
+    if ((s0 & 0xfc00) != 0xd800) {
+        /* one word character */
+        l = 2;
+        c = s0;
+    } else {
+        /* two word character */
+        l = 4;
+        if (ilen < 4) {
+            return 0;
+        }
+        s1 = cpu_lduw_data_ra(env, addr + 2, ra);
+        c = extract32(s0, 6, 4) + 1;
+        c = (c << 6) | (s0 & 0x3f);
+        c = (c << 10) | (s1 & 0x3ff);
+        if (enh_check && (s1 & 0xfc00) != 0xdc00) {
+            /* invalid surrogate character */
+            return 2;
+        }
+    }
+
+    *ochar = c;
+    *olen = l;
+    return -1;
+}
+
+static int decode_utf32(CPUS390XState *env, uint64_t addr, uint64_t ilen,
+                        bool enh_check, uintptr_t ra,
+                        uint32_t *ochar, uint32_t *olen)
+{
+    uint32_t c;
+
+    if (ilen < 4) {
+        return 0;
+    }
+    c = cpu_ldl_data_ra(env, addr, ra);
+    if ((c >= 0xd800 && c <= 0xdbff) || c > 0x10ffff) {
+        /* invalid unicode character */
+        return 2;
+    }
+
+    *ochar = c;
+    *olen = 4;
+    return -1;
+}
+
+static int encode_utf8(CPUS390XState *env, uint64_t addr, uint64_t ilen,
+                       uintptr_t ra, uint32_t c, uint32_t *olen)
+{
+    uint8_t d[4];
+    uint32_t l, i;
+
+    if (c <= 0x7f) {
+        /* one byte character */
+        l = 1;
+        d[0] = c;
+    } else if (c <= 0x7ff) {
+        /* two byte character */
+        l = 2;
+        d[1] = 0x80 | extract32(c, 0, 6);
+        d[0] = 0xc0 | extract32(c, 6, 5);
+    } else if (c <= 0xffff) {
+        /* three byte character */
+        l = 3;
+        d[2] = 0x80 | extract32(c, 0, 6);
+        d[1] = 0x80 | extract32(c, 6, 6);
+        d[0] = 0xe0 | extract32(c, 12, 4);
+    } else {
+        /* four byte character */
+        l = 4;
+        d[3] = 0x80 | extract32(c, 0, 6);
+        d[2] = 0x80 | extract32(c, 6, 6);
+        d[1] = 0x80 | extract32(c, 12, 6);
+        d[0] = 0xf0 | extract32(c, 18, 3);
+    }
+
+    if (ilen < l) {
+        return 1;
+    }
+    for (i = 0; i < l; ++i) {
+        cpu_stb_data_ra(env, addr + i, d[i], ra);
+    }
+
+    *olen = l;
+    return -1;
+}
+
+static int encode_utf16(CPUS390XState *env, uint64_t addr, uint64_t ilen,
+                        uintptr_t ra, uint32_t c, uint32_t *olen)
+{
+    uint16_t d0, d1;
+
+    if (c <= 0xffff) {
+        /* one word character */
+        if (ilen < 2) {
+            return 1;
+        }
+        cpu_stw_data_ra(env, addr, c, ra);
+        *olen = 2;
+    } else {
+        /* two word character */
+        if (ilen < 4) {
+            return 1;
+        }
+        d1 = 0xdc00 | extract32(c, 0, 10);
+        d0 = 0xd800 | extract32(c, 10, 6);
+        d0 = deposit32(d0, 6, 4, extract32(c, 16, 5) - 1);
+        cpu_stw_data_ra(env, addr + 0, d0, ra);
+        cpu_stw_data_ra(env, addr + 2, d1, ra);
+        *olen = 4;
+    }
+
+    return -1;
+}
+
+static int encode_utf32(CPUS390XState *env, uint64_t addr, uint64_t ilen,
+                        uintptr_t ra, uint32_t c, uint32_t *olen)
+{
+    if (ilen < 4) {
+        return 1;
+    }
+    cpu_stl_data_ra(env, addr, c, ra);
+    *olen = 4;
+    return -1;
+}
+
+static inline uint32_t convert_unicode(CPUS390XState *env, uint32_t r1,
+                                       uint32_t r2, uint32_t m3, uintptr_t ra,
+                                       decode_unicode_fn decode,
+                                       encode_unicode_fn encode)
+{
+    uint64_t dst = get_address(env, r1);
+    uint64_t dlen = get_length(env, r1 + 1);
+    uint64_t src = get_address(env, r2);
+    uint64_t slen = get_length(env, r2 + 1);
+    bool enh_check = m3 & 1;
+    int cc, i;
+
+    /* Lest we fail to service interrupts in a timely manner, limit the
+       amount of work we're willing to do.  For now, let's cap at 256.  */
+    for (i = 0; i < 256; ++i) {
+        uint32_t c, ilen, olen;
+
+        cc = decode(env, src, slen, enh_check, ra, &c, &ilen);
+        if (unlikely(cc >= 0)) {
+            break;
+        }
+        cc = encode(env, dst, dlen, ra, c, &olen);
+        if (unlikely(cc >= 0)) {
+            break;
+        }
+
+        src += ilen;
+        slen -= ilen;
+        dst += olen;
+        dlen -= olen;
+        cc = 3;
+    }
+
+    set_address(env, r1, dst);
+    set_length(env, r1 + 1, dlen);
+    set_address(env, r2, src);
+    set_length(env, r2 + 1, slen);
+
+    return cc;
+}
+
+uint32_t HELPER(cu12)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
+{
+    return convert_unicode(env, r1, r2, m3, GETPC(),
+                           decode_utf8, encode_utf16);
+}
+
+uint32_t HELPER(cu14)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
+{
+    return convert_unicode(env, r1, r2, m3, GETPC(),
+                           decode_utf8, encode_utf32);
+}
+
+uint32_t HELPER(cu21)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
+{
+    return convert_unicode(env, r1, r2, m3, GETPC(),
+                           decode_utf16, encode_utf8);
+}
+
+uint32_t HELPER(cu24)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
+{
+    return convert_unicode(env, r1, r2, m3, GETPC(),
+                           decode_utf16, encode_utf32);
+}
+
+uint32_t HELPER(cu41)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
+{
+    return convert_unicode(env, r1, r2, m3, GETPC(),
+                           decode_utf32, encode_utf8);
+}
+
+uint32_t HELPER(cu42)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
+{
+    return convert_unicode(env, r1, r2, m3, GETPC(),
+                           decode_utf32, encode_utf16);
+}
+
+void probe_write_access(CPUS390XState *env, uint64_t addr, uint64_t len,
+                        uintptr_t ra)
+{
+    /* test the actual access, not just any access to the page due to LAP */
+    while (len) {
+        const uint64_t pagelen = -(addr | TARGET_PAGE_MASK);
+        const uint64_t curlen = MIN(pagelen, len);
+
+        probe_write(env, addr, curlen, cpu_mmu_index(env, false), ra);
+        addr = wrap_address(env, addr + curlen);
+        len -= curlen;
+    }
+}
+
+void HELPER(probe_write_access)(CPUS390XState *env, uint64_t addr, uint64_t len)
+{
+    probe_write_access(env, addr, len, GETPC());
+}
diff --git a/target/s390x/tcg/meson.build b/target/s390x/tcg/meson.build
new file mode 100644 (file)
index 0000000..ee4e8fe
--- /dev/null
@@ -0,0 +1,14 @@
+s390x_ss.add(when: 'CONFIG_TCG', if_true: files(
+  'cc_helper.c',
+  'crypto_helper.c',
+  'excp_helper.c',
+  'fpu_helper.c',
+  'int_helper.c',
+  'mem_helper.c',
+  'misc_helper.c',
+  'translate.c',
+  'vec_fpu_helper.c',
+  'vec_helper.c',
+  'vec_int_helper.c',
+  'vec_string_helper.c',
+))
diff --git a/target/s390x/tcg/misc_helper.c b/target/s390x/tcg/misc_helper.c
new file mode 100644 (file)
index 0000000..33e6999
--- /dev/null
@@ -0,0 +1,785 @@
+/*
+ *  S/390 misc helper routines
+ *
+ *  Copyright (c) 2009 Ulrich Hecht
+ *  Copyright (c) 2009 Alexander Graf
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/cutils.h"
+#include "qemu/main-loop.h"
+#include "cpu.h"
+#include "s390x-internal.h"
+#include "exec/memory.h"
+#include "qemu/host-utils.h"
+#include "exec/helper-proto.h"
+#include "qemu/timer.h"
+#include "exec/exec-all.h"
+#include "exec/cpu_ldst.h"
+#include "qapi/error.h"
+#include "tcg_s390x.h"
+#include "s390-tod.h"
+
+#if !defined(CONFIG_USER_ONLY)
+#include "sysemu/cpus.h"
+#include "sysemu/sysemu.h"
+#include "hw/s390x/ebcdic.h"
+#include "hw/s390x/s390-virtio-hcall.h"
+#include "hw/s390x/sclp.h"
+#include "hw/s390x/s390_flic.h"
+#include "hw/s390x/ioinst.h"
+#include "hw/s390x/s390-pci-inst.h"
+#include "hw/boards.h"
+#include "hw/s390x/tod.h"
+#endif
+
+/* #define DEBUG_HELPER */
+#ifdef DEBUG_HELPER
+#define HELPER_LOG(x...) qemu_log(x)
+#else
+#define HELPER_LOG(x...)
+#endif
+
+/* Raise an exception statically from a TB.  */
+void HELPER(exception)(CPUS390XState *env, uint32_t excp)
+{
+    CPUState *cs = env_cpu(env);
+
+    HELPER_LOG("%s: exception %d\n", __func__, excp);
+    cs->exception_index = excp;
+    cpu_loop_exit(cs);
+}
+
+/* Store CPU Timer (also used for EXTRACT CPU TIME) */
+uint64_t HELPER(stpt)(CPUS390XState *env)
+{
+#if defined(CONFIG_USER_ONLY)
+    /*
+     * Fake a descending CPU timer. We could get negative values here,
+     * but we don't care as it is up to the OS when to process that
+     * interrupt and reset to > 0.
+     */
+    return UINT64_MAX - (uint64_t)cpu_get_host_ticks();
+#else
+    return time2tod(env->cputm - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
+#endif
+}
+
+/* Store Clock */
+uint64_t HELPER(stck)(CPUS390XState *env)
+{
+#ifdef CONFIG_USER_ONLY
+    struct timespec ts;
+    uint64_t ns;
+
+    clock_gettime(CLOCK_REALTIME, &ts);
+    ns = ts.tv_sec * NANOSECONDS_PER_SECOND + ts.tv_nsec;
+
+    return TOD_UNIX_EPOCH + time2tod(ns);
+#else
+    S390TODState *td = s390_get_todstate();
+    S390TODClass *tdc = S390_TOD_GET_CLASS(td);
+    S390TOD tod;
+
+    tdc->get(td, &tod, &error_abort);
+    return tod.low;
+#endif
+}
+
+#ifndef CONFIG_USER_ONLY
+/* SCLP service call */
+uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2)
+{
+    qemu_mutex_lock_iothread();
+    int r = sclp_service_call(env, r1, r2);
+    qemu_mutex_unlock_iothread();
+    if (r < 0) {
+        tcg_s390_program_interrupt(env, -r, GETPC());
+    }
+    return r;
+}
+
+void HELPER(diag)(CPUS390XState *env, uint32_t r1, uint32_t r3, uint32_t num)
+{
+    uint64_t r;
+
+    switch (num) {
+    case 0x500:
+        /* KVM hypercall */
+        qemu_mutex_lock_iothread();
+        r = s390_virtio_hypercall(env);
+        qemu_mutex_unlock_iothread();
+        break;
+    case 0x44:
+        /* yield */
+        r = 0;
+        break;
+    case 0x308:
+        /* ipl */
+        qemu_mutex_lock_iothread();
+        handle_diag_308(env, r1, r3, GETPC());
+        qemu_mutex_unlock_iothread();
+        r = 0;
+        break;
+    case 0x288:
+        /* time bomb (watchdog) */
+        r = handle_diag_288(env, r1, r3);
+        break;
+    default:
+        r = -1;
+        break;
+    }
+
+    if (r) {
+        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
+    }
+}
+
+/* Set Prefix */
+void HELPER(spx)(CPUS390XState *env, uint64_t a1)
+{
+    CPUState *cs = env_cpu(env);
+    uint32_t prefix = a1 & 0x7fffe000;
+
+    env->psa = prefix;
+    HELPER_LOG("prefix: %#x\n", prefix);
+    tlb_flush_page(cs, 0);
+    tlb_flush_page(cs, TARGET_PAGE_SIZE);
+}
+
+static void update_ckc_timer(CPUS390XState *env)
+{
+    S390TODState *td = s390_get_todstate();
+    uint64_t time;
+
+    /* stop the timer and remove pending CKC IRQs */
+    timer_del(env->tod_timer);
+    g_assert(qemu_mutex_iothread_locked());
+    env->pending_int &= ~INTERRUPT_EXT_CLOCK_COMPARATOR;
+
+    /* the tod has to exceed the ckc, this can never happen if ckc is all 1's */
+    if (env->ckc == -1ULL) {
+        return;
+    }
+
+    /* difference between origins */
+    time = env->ckc - td->base.low;
+
+    /* nanoseconds */
+    time = tod2time(time);
+
+    timer_mod(env->tod_timer, time);
+}
+
+/* Set Clock Comparator */
+void HELPER(sckc)(CPUS390XState *env, uint64_t ckc)
+{
+    env->ckc = ckc;
+
+    qemu_mutex_lock_iothread();
+    update_ckc_timer(env);
+    qemu_mutex_unlock_iothread();
+}
+
+void tcg_s390_tod_updated(CPUState *cs, run_on_cpu_data opaque)
+{
+    S390CPU *cpu = S390_CPU(cs);
+
+    update_ckc_timer(&cpu->env);
+}
+
+/* Set Clock */
+uint32_t HELPER(sck)(CPUS390XState *env, uint64_t tod_low)
+{
+    S390TODState *td = s390_get_todstate();
+    S390TODClass *tdc = S390_TOD_GET_CLASS(td);
+    S390TOD tod = {
+        .high = 0,
+        .low = tod_low,
+    };
+
+    qemu_mutex_lock_iothread();
+    tdc->set(td, &tod, &error_abort);
+    qemu_mutex_unlock_iothread();
+    return 0;
+}
+
+/* Set Tod Programmable Field */
+void HELPER(sckpf)(CPUS390XState *env, uint64_t r0)
+{
+    uint32_t val = r0;
+
+    if (val & 0xffff0000) {
+        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
+    }
+    env->todpr = val;
+}
+
+/* Store Clock Comparator */
+uint64_t HELPER(stckc)(CPUS390XState *env)
+{
+    return env->ckc;
+}
+
+/* Set CPU Timer */
+void HELPER(spt)(CPUS390XState *env, uint64_t time)
+{
+    if (time == -1ULL) {
+        return;
+    }
+
+    /* nanoseconds */
+    time = tod2time(time);
+
+    env->cputm = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time;
+
+    timer_mod(env->cpu_timer, env->cputm);
+}
+
+/* Store System Information */
+uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, uint64_t r0, uint64_t r1)
+{
+    const uintptr_t ra = GETPC();
+    const uint32_t sel1 = r0 & STSI_R0_SEL1_MASK;
+    const uint32_t sel2 = r1 & STSI_R1_SEL2_MASK;
+    const MachineState *ms = MACHINE(qdev_get_machine());
+    uint16_t total_cpus = 0, conf_cpus = 0, reserved_cpus = 0;
+    S390CPU *cpu = env_archcpu(env);
+    SysIB sysib = { };
+    int i, cc = 0;
+
+    if ((r0 & STSI_R0_FC_MASK) > STSI_R0_FC_LEVEL_3) {
+        /* invalid function code: no other checks are performed */
+        return 3;
+    }
+
+    if ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK)) {
+        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+    }
+
+    if ((r0 & STSI_R0_FC_MASK) == STSI_R0_FC_CURRENT) {
+        /* query the current level: no further checks are performed */
+        env->regs[0] = STSI_R0_FC_LEVEL_3;
+        return 0;
+    }
+
+    if (a0 & ~TARGET_PAGE_MASK) {
+        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+    }
+
+    /* count the cpus and split them into configured and reserved ones */
+    for (i = 0; i < ms->possible_cpus->len; i++) {
+        total_cpus++;
+        if (ms->possible_cpus->cpus[i].cpu) {
+            conf_cpus++;
+        } else {
+            reserved_cpus++;
+        }
+    }
+
+    /*
+     * In theory, we could report Level 1 / Level 2 as current. However,
+     * the Linux kernel will detect this as running under LPAR and assume
+     * that we have a sclp linemode console (which is always present on
+     * LPAR, but not the default for QEMU), therefore not displaying boot
+     * messages and making booting a Linux kernel under TCG harder.
+     *
+     * For now we fake the same SMP configuration on all levels.
+     *
+     * TODO: We could later make the level configurable via the machine
+     *       and change defaults (linemode console) based on machine type
+     *       and accelerator.
+     */
+    switch (r0 & STSI_R0_FC_MASK) {
+    case STSI_R0_FC_LEVEL_1:
+        if ((sel1 == 1) && (sel2 == 1)) {
+            /* Basic Machine Configuration */
+            char type[5] = {};
+
+            ebcdic_put(sysib.sysib_111.manuf, "QEMU            ", 16);
+            /* same as machine type number in STORE CPU ID, but in EBCDIC */
+            snprintf(type, ARRAY_SIZE(type), "%X", cpu->model->def->type);
+            ebcdic_put(sysib.sysib_111.type, type, 4);
+            /* model number (not stored in STORE CPU ID for z/Architecure) */
+            ebcdic_put(sysib.sysib_111.model, "QEMU            ", 16);
+            ebcdic_put(sysib.sysib_111.sequence, "QEMU            ", 16);
+            ebcdic_put(sysib.sysib_111.plant, "QEMU", 4);
+        } else if ((sel1 == 2) && (sel2 == 1)) {
+            /* Basic Machine CPU */
+            ebcdic_put(sysib.sysib_121.sequence, "QEMUQEMUQEMUQEMU", 16);
+            ebcdic_put(sysib.sysib_121.plant, "QEMU", 4);
+            sysib.sysib_121.cpu_addr = cpu_to_be16(env->core_id);
+        } else if ((sel1 == 2) && (sel2 == 2)) {
+            /* Basic Machine CPUs */
+            sysib.sysib_122.capability = cpu_to_be32(0x443afc29);
+            sysib.sysib_122.total_cpus = cpu_to_be16(total_cpus);
+            sysib.sysib_122.conf_cpus = cpu_to_be16(conf_cpus);
+            sysib.sysib_122.reserved_cpus = cpu_to_be16(reserved_cpus);
+        } else {
+            cc = 3;
+        }
+        break;
+    case STSI_R0_FC_LEVEL_2:
+        if ((sel1 == 2) && (sel2 == 1)) {
+            /* LPAR CPU */
+            ebcdic_put(sysib.sysib_221.sequence, "QEMUQEMUQEMUQEMU", 16);
+            ebcdic_put(sysib.sysib_221.plant, "QEMU", 4);
+            sysib.sysib_221.cpu_addr = cpu_to_be16(env->core_id);
+        } else if ((sel1 == 2) && (sel2 == 2)) {
+            /* LPAR CPUs */
+            sysib.sysib_222.lcpuc = 0x80; /* dedicated */
+            sysib.sysib_222.total_cpus = cpu_to_be16(total_cpus);
+            sysib.sysib_222.conf_cpus = cpu_to_be16(conf_cpus);
+            sysib.sysib_222.reserved_cpus = cpu_to_be16(reserved_cpus);
+            ebcdic_put(sysib.sysib_222.name, "QEMU    ", 8);
+            sysib.sysib_222.caf = cpu_to_be32(1000);
+            sysib.sysib_222.dedicated_cpus = cpu_to_be16(conf_cpus);
+        } else {
+            cc = 3;
+        }
+        break;
+    case STSI_R0_FC_LEVEL_3:
+        if ((sel1 == 2) && (sel2 == 2)) {
+            /* VM CPUs */
+            sysib.sysib_322.count = 1;
+            sysib.sysib_322.vm[0].total_cpus = cpu_to_be16(total_cpus);
+            sysib.sysib_322.vm[0].conf_cpus = cpu_to_be16(conf_cpus);
+            sysib.sysib_322.vm[0].reserved_cpus = cpu_to_be16(reserved_cpus);
+            sysib.sysib_322.vm[0].caf = cpu_to_be32(1000);
+            /* Linux kernel uses this to distinguish us from z/VM */
+            ebcdic_put(sysib.sysib_322.vm[0].cpi, "KVM/Linux       ", 16);
+            sysib.sysib_322.vm[0].ext_name_encoding = 2; /* UTF-8 */
+
+            /* If our VM has a name, use the real name */
+            if (qemu_name) {
+                memset(sysib.sysib_322.vm[0].name, 0x40,
+                       sizeof(sysib.sysib_322.vm[0].name));
+                ebcdic_put(sysib.sysib_322.vm[0].name, qemu_name,
+                           MIN(sizeof(sysib.sysib_322.vm[0].name),
+                               strlen(qemu_name)));
+                strpadcpy((char *)sysib.sysib_322.ext_names[0],
+                          sizeof(sysib.sysib_322.ext_names[0]),
+                          qemu_name, '\0');
+
+            } else {
+                ebcdic_put(sysib.sysib_322.vm[0].name, "TCGguest", 8);
+                strcpy((char *)sysib.sysib_322.ext_names[0], "TCGguest");
+            }
+
+            /* add the uuid */
+            memcpy(sysib.sysib_322.vm[0].uuid, &qemu_uuid,
+                   sizeof(sysib.sysib_322.vm[0].uuid));
+        } else {
+            cc = 3;
+        }
+        break;
+    }
+
+    if (cc == 0) {
+        if (s390_cpu_virt_mem_write(cpu, a0, 0, &sysib, sizeof(sysib))) {
+            s390_cpu_virt_mem_handle_exc(cpu, ra);
+        }
+    }
+
+    return cc;
+}
+
+uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
+                      uint32_t r3)
+{
+    int cc;
+
+    /* TODO: needed to inject interrupts  - push further down */
+    qemu_mutex_lock_iothread();
+    cc = handle_sigp(env, order_code & SIGP_ORDER_MASK, r1, r3);
+    qemu_mutex_unlock_iothread();
+
+    return cc;
+}
+#endif
+
+#ifndef CONFIG_USER_ONLY
+void HELPER(xsch)(CPUS390XState *env, uint64_t r1)
+{
+    S390CPU *cpu = env_archcpu(env);
+    qemu_mutex_lock_iothread();
+    ioinst_handle_xsch(cpu, r1, GETPC());
+    qemu_mutex_unlock_iothread();
+}
+
+void HELPER(csch)(CPUS390XState *env, uint64_t r1)
+{
+    S390CPU *cpu = env_archcpu(env);
+    qemu_mutex_lock_iothread();
+    ioinst_handle_csch(cpu, r1, GETPC());
+    qemu_mutex_unlock_iothread();
+}
+
+void HELPER(hsch)(CPUS390XState *env, uint64_t r1)
+{
+    S390CPU *cpu = env_archcpu(env);
+    qemu_mutex_lock_iothread();
+    ioinst_handle_hsch(cpu, r1, GETPC());
+    qemu_mutex_unlock_iothread();
+}
+
+void HELPER(msch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
+{
+    S390CPU *cpu = env_archcpu(env);
+    qemu_mutex_lock_iothread();
+    ioinst_handle_msch(cpu, r1, inst >> 16, GETPC());
+    qemu_mutex_unlock_iothread();
+}
+
+void HELPER(rchp)(CPUS390XState *env, uint64_t r1)
+{
+    S390CPU *cpu = env_archcpu(env);
+    qemu_mutex_lock_iothread();
+    ioinst_handle_rchp(cpu, r1, GETPC());
+    qemu_mutex_unlock_iothread();
+}
+
+void HELPER(rsch)(CPUS390XState *env, uint64_t r1)
+{
+    S390CPU *cpu = env_archcpu(env);
+    qemu_mutex_lock_iothread();
+    ioinst_handle_rsch(cpu, r1, GETPC());
+    qemu_mutex_unlock_iothread();
+}
+
+void HELPER(sal)(CPUS390XState *env, uint64_t r1)
+{
+    S390CPU *cpu = env_archcpu(env);
+
+    qemu_mutex_lock_iothread();
+    ioinst_handle_sal(cpu, r1, GETPC());
+    qemu_mutex_unlock_iothread();
+}
+
+void HELPER(schm)(CPUS390XState *env, uint64_t r1, uint64_t r2, uint64_t inst)
+{
+    S390CPU *cpu = env_archcpu(env);
+
+    qemu_mutex_lock_iothread();
+    ioinst_handle_schm(cpu, r1, r2, inst >> 16, GETPC());
+    qemu_mutex_unlock_iothread();
+}
+
+void HELPER(ssch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
+{
+    S390CPU *cpu = env_archcpu(env);
+    qemu_mutex_lock_iothread();
+    ioinst_handle_ssch(cpu, r1, inst >> 16, GETPC());
+    qemu_mutex_unlock_iothread();
+}
+
+void HELPER(stcrw)(CPUS390XState *env, uint64_t inst)
+{
+    S390CPU *cpu = env_archcpu(env);
+
+    qemu_mutex_lock_iothread();
+    ioinst_handle_stcrw(cpu, inst >> 16, GETPC());
+    qemu_mutex_unlock_iothread();
+}
+
+void HELPER(stsch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
+{
+    S390CPU *cpu = env_archcpu(env);
+    qemu_mutex_lock_iothread();
+    ioinst_handle_stsch(cpu, r1, inst >> 16, GETPC());
+    qemu_mutex_unlock_iothread();
+}
+
+uint32_t HELPER(tpi)(CPUS390XState *env, uint64_t addr)
+{
+    const uintptr_t ra = GETPC();
+    S390CPU *cpu = env_archcpu(env);
+    QEMUS390FLICState *flic = s390_get_qemu_flic(s390_get_flic());
+    QEMUS390FlicIO *io = NULL;
+    LowCore *lowcore;
+
+    if (addr & 0x3) {
+        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+    }
+
+    qemu_mutex_lock_iothread();
+    io = qemu_s390_flic_dequeue_io(flic, env->cregs[6]);
+    if (!io) {
+        qemu_mutex_unlock_iothread();
+        return 0;
+    }
+
+    if (addr) {
+        struct {
+            uint16_t id;
+            uint16_t nr;
+            uint32_t parm;
+        } intc = {
+            .id = cpu_to_be16(io->id),
+            .nr = cpu_to_be16(io->nr),
+            .parm = cpu_to_be32(io->parm),
+        };
+
+        if (s390_cpu_virt_mem_write(cpu, addr, 0, &intc, sizeof(intc))) {
+            /* writing failed, reinject and properly clean up */
+            s390_io_interrupt(io->id, io->nr, io->parm, io->word);
+            qemu_mutex_unlock_iothread();
+            g_free(io);
+            s390_cpu_virt_mem_handle_exc(cpu, ra);
+            return 0;
+        }
+    } else {
+        /* no protection applies */
+        lowcore = cpu_map_lowcore(env);
+        lowcore->subchannel_id = cpu_to_be16(io->id);
+        lowcore->subchannel_nr = cpu_to_be16(io->nr);
+        lowcore->io_int_parm = cpu_to_be32(io->parm);
+        lowcore->io_int_word = cpu_to_be32(io->word);
+        cpu_unmap_lowcore(lowcore);
+    }
+
+    g_free(io);
+    qemu_mutex_unlock_iothread();
+    return 1;
+}
+
+void HELPER(tsch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
+{
+    S390CPU *cpu = env_archcpu(env);
+    qemu_mutex_lock_iothread();
+    ioinst_handle_tsch(cpu, r1, inst >> 16, GETPC());
+    qemu_mutex_unlock_iothread();
+}
+
+void HELPER(chsc)(CPUS390XState *env, uint64_t inst)
+{
+    S390CPU *cpu = env_archcpu(env);
+    qemu_mutex_lock_iothread();
+    ioinst_handle_chsc(cpu, inst >> 16, GETPC());
+    qemu_mutex_unlock_iothread();
+}
+#endif
+
+#ifndef CONFIG_USER_ONLY
+void HELPER(per_check_exception)(CPUS390XState *env)
+{
+    if (env->per_perc_atmid) {
+        tcg_s390_program_interrupt(env, PGM_PER, GETPC());
+    }
+}
+
+/* Check if an address is within the PER starting address and the PER
+   ending address.  The address range might loop.  */
+static inline bool get_per_in_range(CPUS390XState *env, uint64_t addr)
+{
+    if (env->cregs[10] <= env->cregs[11]) {
+        return env->cregs[10] <= addr && addr <= env->cregs[11];
+    } else {
+        return env->cregs[10] <= addr || addr <= env->cregs[11];
+    }
+}
+
+void HELPER(per_branch)(CPUS390XState *env, uint64_t from, uint64_t to)
+{
+    if ((env->cregs[9] & PER_CR9_EVENT_BRANCH)) {
+        if (!(env->cregs[9] & PER_CR9_CONTROL_BRANCH_ADDRESS)
+            || get_per_in_range(env, to)) {
+            env->per_address = from;
+            env->per_perc_atmid = PER_CODE_EVENT_BRANCH | get_per_atmid(env);
+        }
+    }
+}
+
+void HELPER(per_ifetch)(CPUS390XState *env, uint64_t addr)
+{
+    if ((env->cregs[9] & PER_CR9_EVENT_IFETCH) && get_per_in_range(env, addr)) {
+        env->per_address = addr;
+        env->per_perc_atmid = PER_CODE_EVENT_IFETCH | get_per_atmid(env);
+
+        /* If the instruction has to be nullified, trigger the
+           exception immediately. */
+        if (env->cregs[9] & PER_CR9_EVENT_NULLIFICATION) {
+            CPUState *cs = env_cpu(env);
+
+            env->per_perc_atmid |= PER_CODE_EVENT_NULLIFICATION;
+            env->int_pgm_code = PGM_PER;
+            env->int_pgm_ilen = get_ilen(cpu_ldub_code(env, addr));
+
+            cs->exception_index = EXCP_PGM;
+            cpu_loop_exit(cs);
+        }
+    }
+}
+
+void HELPER(per_store_real)(CPUS390XState *env)
+{
+    if ((env->cregs[9] & PER_CR9_EVENT_STORE) &&
+        (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
+        /* PSW is saved just before calling the helper.  */
+        env->per_address = env->psw.addr;
+        env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
+    }
+}
+#endif
+
+static uint8_t stfl_bytes[2048];
+static unsigned int used_stfl_bytes;
+
+static void prepare_stfl(void)
+{
+    static bool initialized;
+    int i;
+
+    /* racy, but we don't care, the same values are always written */
+    if (initialized) {
+        return;
+    }
+
+    s390_get_feat_block(S390_FEAT_TYPE_STFL, stfl_bytes);
+    for (i = 0; i < sizeof(stfl_bytes); i++) {
+        if (stfl_bytes[i]) {
+            used_stfl_bytes = i + 1;
+        }
+    }
+    initialized = true;
+}
+
+#ifndef CONFIG_USER_ONLY
+void HELPER(stfl)(CPUS390XState *env)
+{
+    LowCore *lowcore;
+
+    lowcore = cpu_map_lowcore(env);
+    prepare_stfl();
+    memcpy(&lowcore->stfl_fac_list, stfl_bytes, sizeof(lowcore->stfl_fac_list));
+    cpu_unmap_lowcore(lowcore);
+}
+#endif
+
+uint32_t HELPER(stfle)(CPUS390XState *env, uint64_t addr)
+{
+    const uintptr_t ra = GETPC();
+    const int count_bytes = ((env->regs[0] & 0xff) + 1) * 8;
+    int max_bytes;
+    int i;
+
+    if (addr & 0x7) {
+        tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+    }
+
+    prepare_stfl();
+    max_bytes = ROUND_UP(used_stfl_bytes, 8);
+
+    /*
+     * The PoP says that doublewords beyond the highest-numbered facility
+     * bit may or may not be stored.  However, existing hardware appears to
+     * not store the words, and existing software depend on that.
+     */
+    for (i = 0; i < MIN(count_bytes, max_bytes); ++i) {
+        cpu_stb_data_ra(env, addr + i, stfl_bytes[i], ra);
+    }
+
+    env->regs[0] = deposit64(env->regs[0], 0, 8, (max_bytes / 8) - 1);
+    return count_bytes >= max_bytes ? 0 : 3;
+}
+
+#ifndef CONFIG_USER_ONLY
+/*
+ * Note: we ignore any return code of the functions called for the pci
+ * instructions, as the only time they return !0 is when the stub is
+ * called, and in that case we didn't even offer the zpci facility.
+ * The only exception is SIC, where program checks need to be handled
+ * by the caller.
+ */
+void HELPER(clp)(CPUS390XState *env, uint32_t r2)
+{
+    S390CPU *cpu = env_archcpu(env);
+
+    qemu_mutex_lock_iothread();
+    clp_service_call(cpu, r2, GETPC());
+    qemu_mutex_unlock_iothread();
+}
+
+void HELPER(pcilg)(CPUS390XState *env, uint32_t r1, uint32_t r2)
+{
+    S390CPU *cpu = env_archcpu(env);
+
+    qemu_mutex_lock_iothread();
+    pcilg_service_call(cpu, r1, r2, GETPC());
+    qemu_mutex_unlock_iothread();
+}
+
+void HELPER(pcistg)(CPUS390XState *env, uint32_t r1, uint32_t r2)
+{
+    S390CPU *cpu = env_archcpu(env);
+
+    qemu_mutex_lock_iothread();
+    pcistg_service_call(cpu, r1, r2, GETPC());
+    qemu_mutex_unlock_iothread();
+}
+
+void HELPER(stpcifc)(CPUS390XState *env, uint32_t r1, uint64_t fiba,
+                     uint32_t ar)
+{
+    S390CPU *cpu = env_archcpu(env);
+
+    qemu_mutex_lock_iothread();
+    stpcifc_service_call(cpu, r1, fiba, ar, GETPC());
+    qemu_mutex_unlock_iothread();
+}
+
+void HELPER(sic)(CPUS390XState *env, uint64_t r1, uint64_t r3)
+{
+    int r;
+
+    qemu_mutex_lock_iothread();
+    r = css_do_sic(env, (r3 >> 27) & 0x7, r1 & 0xffff);
+    qemu_mutex_unlock_iothread();
+    /* css_do_sic() may actually return a PGM_xxx value to inject */
+    if (r) {
+        tcg_s390_program_interrupt(env, -r, GETPC());
+    }
+}
+
+void HELPER(rpcit)(CPUS390XState *env, uint32_t r1, uint32_t r2)
+{
+    S390CPU *cpu = env_archcpu(env);
+
+    qemu_mutex_lock_iothread();
+    rpcit_service_call(cpu, r1, r2, GETPC());
+    qemu_mutex_unlock_iothread();
+}
+
+void HELPER(pcistb)(CPUS390XState *env, uint32_t r1, uint32_t r3,
+                    uint64_t gaddr, uint32_t ar)
+{
+    S390CPU *cpu = env_archcpu(env);
+
+    qemu_mutex_lock_iothread();
+    pcistb_service_call(cpu, r1, r3, gaddr, ar, GETPC());
+    qemu_mutex_unlock_iothread();
+}
+
+void HELPER(mpcifc)(CPUS390XState *env, uint32_t r1, uint64_t fiba,
+                    uint32_t ar)
+{
+    S390CPU *cpu = env_archcpu(env);
+
+    qemu_mutex_lock_iothread();
+    mpcifc_service_call(cpu, r1, fiba, ar, GETPC());
+    qemu_mutex_unlock_iothread();
+}
+#endif
diff --git a/target/s390x/tcg/s390-tod.h b/target/s390x/tcg/s390-tod.h
new file mode 100644 (file)
index 0000000..8b74d6a
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * TOD (Time Of Day) clock
+ *
+ * Copyright 2018 Red Hat, Inc.
+ * Author(s): David Hildenbrand <david@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef TARGET_S390_TOD_H
+#define TARGET_S390_TOD_H
+
+/* The value of the TOD clock for 1.1.1970. */
+#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL
+
+/* Converts ns to s390's clock format */
+static inline uint64_t time2tod(uint64_t ns)
+{
+    return (ns << 9) / 125 + (((ns & 0xff80000000000000ull) / 125) << 9);
+}
+
+/* Converts s390's clock format to ns */
+static inline uint64_t tod2time(uint64_t t)
+{
+    return ((t >> 9) * 125) + (((t & 0x1ff) * 125) >> 9);
+}
+
+#endif
diff --git a/target/s390x/tcg/tcg_s390x.h b/target/s390x/tcg/tcg_s390x.h
new file mode 100644 (file)
index 0000000..2f54ccb
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * QEMU TCG support -- s390x specific functions.
+ *
+ * Copyright 2018 Red Hat, Inc.
+ *
+ * Authors:
+ *   David Hildenbrand <david@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef TCG_S390X_H
+#define TCG_S390X_H
+
+void tcg_s390_tod_updated(CPUState *cs, run_on_cpu_data opaque);
+void QEMU_NORETURN tcg_s390_program_interrupt(CPUS390XState *env,
+                                              uint32_t code, uintptr_t ra);
+void QEMU_NORETURN tcg_s390_data_exception(CPUS390XState *env, uint32_t dxc,
+                                           uintptr_t ra);
+void QEMU_NORETURN tcg_s390_vector_exception(CPUS390XState *env, uint32_t vxc,
+                                             uintptr_t ra);
+
+#endif /* TCG_S390X_H */
diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c
new file mode 100644 (file)
index 0000000..92fa765
--- /dev/null
@@ -0,0 +1,6672 @@
+/*
+ *  S/390 translation
+ *
+ *  Copyright (c) 2009 Ulrich Hecht
+ *  Copyright (c) 2010 Alexander Graf
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* #define DEBUG_INLINE_BRANCHES */
+#define S390X_DEBUG_DISAS
+/* #define S390X_DEBUG_DISAS_VERBOSE */
+
+#ifdef S390X_DEBUG_DISAS_VERBOSE
+#  define LOG_DISAS(...) qemu_log(__VA_ARGS__)
+#else
+#  define LOG_DISAS(...) do { } while (0)
+#endif
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "s390x-internal.h"
+#include "disas/disas.h"
+#include "exec/exec-all.h"
+#include "tcg/tcg-op.h"
+#include "tcg/tcg-op-gvec.h"
+#include "qemu/log.h"
+#include "qemu/host-utils.h"
+#include "exec/cpu_ldst.h"
+#include "exec/gen-icount.h"
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
+
+#include "exec/translator.h"
+#include "exec/log.h"
+#include "qemu/atomic128.h"
+
+
+/* Information that (most) every instruction needs to manipulate.  */
+typedef struct DisasContext DisasContext;
+typedef struct DisasInsn DisasInsn;
+typedef struct DisasFields DisasFields;
+
+/*
+ * Define a structure to hold the decoded fields.  We'll store each inside
+ * an array indexed by an enum.  In order to conserve memory, we'll arrange
+ * for fields that do not exist at the same time to overlap, thus the "C"
+ * for compact.  For checking purposes there is an "O" for original index
+ * as well that will be applied to availability bitmaps.
+ */
+
+enum DisasFieldIndexO {
+    FLD_O_r1,
+    FLD_O_r2,
+    FLD_O_r3,
+    FLD_O_m1,
+    FLD_O_m3,
+    FLD_O_m4,
+    FLD_O_m5,
+    FLD_O_m6,
+    FLD_O_b1,
+    FLD_O_b2,
+    FLD_O_b4,
+    FLD_O_d1,
+    FLD_O_d2,
+    FLD_O_d4,
+    FLD_O_x2,
+    FLD_O_l1,
+    FLD_O_l2,
+    FLD_O_i1,
+    FLD_O_i2,
+    FLD_O_i3,
+    FLD_O_i4,
+    FLD_O_i5,
+    FLD_O_v1,
+    FLD_O_v2,
+    FLD_O_v3,
+    FLD_O_v4,
+};
+
+enum DisasFieldIndexC {
+    FLD_C_r1 = 0,
+    FLD_C_m1 = 0,
+    FLD_C_b1 = 0,
+    FLD_C_i1 = 0,
+    FLD_C_v1 = 0,
+
+    FLD_C_r2 = 1,
+    FLD_C_b2 = 1,
+    FLD_C_i2 = 1,
+
+    FLD_C_r3 = 2,
+    FLD_C_m3 = 2,
+    FLD_C_i3 = 2,
+    FLD_C_v3 = 2,
+
+    FLD_C_m4 = 3,
+    FLD_C_b4 = 3,
+    FLD_C_i4 = 3,
+    FLD_C_l1 = 3,
+    FLD_C_v4 = 3,
+
+    FLD_C_i5 = 4,
+    FLD_C_d1 = 4,
+    FLD_C_m5 = 4,
+
+    FLD_C_d2 = 5,
+    FLD_C_m6 = 5,
+
+    FLD_C_d4 = 6,
+    FLD_C_x2 = 6,
+    FLD_C_l2 = 6,
+    FLD_C_v2 = 6,
+
+    NUM_C_FIELD = 7
+};
+
+struct DisasFields {
+    uint64_t raw_insn;
+    unsigned op:8;
+    unsigned op2:8;
+    unsigned presentC:16;
+    unsigned int presentO;
+    int c[NUM_C_FIELD];
+};
+
+struct DisasContext {
+    DisasContextBase base;
+    const DisasInsn *insn;
+    DisasFields fields;
+    uint64_t ex_value;
+    /*
+     * During translate_one(), pc_tmp is used to determine the instruction
+     * to be executed after base.pc_next - e.g. next sequential instruction
+     * or a branch target.
+     */
+    uint64_t pc_tmp;
+    uint32_t ilen;
+    enum cc_op cc_op;
+    bool do_debug;
+};
+
+/* Information carried about a condition to be evaluated.  */
+typedef struct {
+    TCGCond cond:8;
+    bool is_64;
+    bool g1;
+    bool g2;
+    union {
+        struct { TCGv_i64 a, b; } s64;
+        struct { TCGv_i32 a, b; } s32;
+    } u;
+} DisasCompare;
+
+#ifdef DEBUG_INLINE_BRANCHES
+static uint64_t inline_branch_hit[CC_OP_MAX];
+static uint64_t inline_branch_miss[CC_OP_MAX];
+#endif
+
+static void pc_to_link_info(TCGv_i64 out, DisasContext *s, uint64_t pc)
+{
+    TCGv_i64 tmp;
+
+    if (s->base.tb->flags & FLAG_MASK_32) {
+        if (s->base.tb->flags & FLAG_MASK_64) {
+            tcg_gen_movi_i64(out, pc);
+            return;
+        }
+        pc |= 0x80000000;
+    }
+    assert(!(s->base.tb->flags & FLAG_MASK_64));
+    tmp = tcg_const_i64(pc);
+    tcg_gen_deposit_i64(out, out, tmp, 0, 32);
+    tcg_temp_free_i64(tmp);
+}
+
+static TCGv_i64 psw_addr;
+static TCGv_i64 psw_mask;
+static TCGv_i64 gbea;
+
+static TCGv_i32 cc_op;
+static TCGv_i64 cc_src;
+static TCGv_i64 cc_dst;
+static TCGv_i64 cc_vr;
+
+static char cpu_reg_names[16][4];
+static TCGv_i64 regs[16];
+
+void s390x_translate_init(void)
+{
+    int i;
+
+    psw_addr = tcg_global_mem_new_i64(cpu_env,
+                                      offsetof(CPUS390XState, psw.addr),
+                                      "psw_addr");
+    psw_mask = tcg_global_mem_new_i64(cpu_env,
+                                      offsetof(CPUS390XState, psw.mask),
+                                      "psw_mask");
+    gbea = tcg_global_mem_new_i64(cpu_env,
+                                  offsetof(CPUS390XState, gbea),
+                                  "gbea");
+
+    cc_op = tcg_global_mem_new_i32(cpu_env, offsetof(CPUS390XState, cc_op),
+                                   "cc_op");
+    cc_src = tcg_global_mem_new_i64(cpu_env, offsetof(CPUS390XState, cc_src),
+                                    "cc_src");
+    cc_dst = tcg_global_mem_new_i64(cpu_env, offsetof(CPUS390XState, cc_dst),
+                                    "cc_dst");
+    cc_vr = tcg_global_mem_new_i64(cpu_env, offsetof(CPUS390XState, cc_vr),
+                                   "cc_vr");
+
+    for (i = 0; i < 16; i++) {
+        snprintf(cpu_reg_names[i], sizeof(cpu_reg_names[0]), "r%d", i);
+        regs[i] = tcg_global_mem_new(cpu_env,
+                                     offsetof(CPUS390XState, regs[i]),
+                                     cpu_reg_names[i]);
+    }
+}
+
+static inline int vec_full_reg_offset(uint8_t reg)
+{
+    g_assert(reg < 32);
+    return offsetof(CPUS390XState, vregs[reg][0]);
+}
+
+static inline int vec_reg_offset(uint8_t reg, uint8_t enr, MemOp es)
+{
+    /* Convert element size (es) - e.g. MO_8 - to bytes */
+    const uint8_t bytes = 1 << es;
+    int offs = enr * bytes;
+
+    /*
+     * vregs[n][0] is the lowest 8 byte and vregs[n][1] the highest 8 byte
+     * of the 16 byte vector, on both, little and big endian systems.
+     *
+     * Big Endian (target/possible host)
+     * B:  [ 0][ 1][ 2][ 3][ 4][ 5][ 6][ 7] - [ 8][ 9][10][11][12][13][14][15]
+     * HW: [     0][     1][     2][     3] - [     4][     5][     6][     7]
+     * W:  [             0][             1] - [             2][             3]
+     * DW: [                             0] - [                             1]
+     *
+     * Little Endian (possible host)
+     * B:  [ 7][ 6][ 5][ 4][ 3][ 2][ 1][ 0] - [15][14][13][12][11][10][ 9][ 8]
+     * HW: [     3][     2][     1][     0] - [     7][     6][     5][     4]
+     * W:  [             1][             0] - [             3][             2]
+     * DW: [                             0] - [                             1]
+     *
+     * For 16 byte elements, the two 8 byte halves will not form a host
+     * int128 if the host is little endian, since they're in the wrong order.
+     * Some operations (e.g. xor) do not care. For operations like addition,
+     * the two 8 byte elements have to be loaded separately. Let's force all
+     * 16 byte operations to handle it in a special way.
+     */
+    g_assert(es <= MO_64);
+#ifndef HOST_WORDS_BIGENDIAN
+    offs ^= (8 - bytes);
+#endif
+    return offs + vec_full_reg_offset(reg);
+}
+
+static inline int freg64_offset(uint8_t reg)
+{
+    g_assert(reg < 16);
+    return vec_reg_offset(reg, 0, MO_64);
+}
+
+static inline int freg32_offset(uint8_t reg)
+{
+    g_assert(reg < 16);
+    return vec_reg_offset(reg, 0, MO_32);
+}
+
+static TCGv_i64 load_reg(int reg)
+{
+    TCGv_i64 r = tcg_temp_new_i64();
+    tcg_gen_mov_i64(r, regs[reg]);
+    return r;
+}
+
+static TCGv_i64 load_freg(int reg)
+{
+    TCGv_i64 r = tcg_temp_new_i64();
+
+    tcg_gen_ld_i64(r, cpu_env, freg64_offset(reg));
+    return r;
+}
+
+static TCGv_i64 load_freg32_i64(int reg)
+{
+    TCGv_i64 r = tcg_temp_new_i64();
+
+    tcg_gen_ld32u_i64(r, cpu_env, freg32_offset(reg));
+    return r;
+}
+
+static void store_reg(int reg, TCGv_i64 v)
+{
+    tcg_gen_mov_i64(regs[reg], v);
+}
+
+static void store_freg(int reg, TCGv_i64 v)
+{
+    tcg_gen_st_i64(v, cpu_env, freg64_offset(reg));
+}
+
+static void store_reg32_i64(int reg, TCGv_i64 v)
+{
+    /* 32 bit register writes keep the upper half */
+    tcg_gen_deposit_i64(regs[reg], regs[reg], v, 0, 32);
+}
+
+static void store_reg32h_i64(int reg, TCGv_i64 v)
+{
+    tcg_gen_deposit_i64(regs[reg], regs[reg], v, 32, 32);
+}
+
+static void store_freg32_i64(int reg, TCGv_i64 v)
+{
+    tcg_gen_st32_i64(v, cpu_env, freg32_offset(reg));
+}
+
+static void return_low128(TCGv_i64 dest)
+{
+    tcg_gen_ld_i64(dest, cpu_env, offsetof(CPUS390XState, retxl));
+}
+
+static void update_psw_addr(DisasContext *s)
+{
+    /* psw.addr */
+    tcg_gen_movi_i64(psw_addr, s->base.pc_next);
+}
+
+static void per_branch(DisasContext *s, bool to_next)
+{
+#ifndef CONFIG_USER_ONLY
+    tcg_gen_movi_i64(gbea, s->base.pc_next);
+
+    if (s->base.tb->flags & FLAG_MASK_PER) {
+        TCGv_i64 next_pc = to_next ? tcg_const_i64(s->pc_tmp) : psw_addr;
+        gen_helper_per_branch(cpu_env, gbea, next_pc);
+        if (to_next) {
+            tcg_temp_free_i64(next_pc);
+        }
+    }
+#endif
+}
+
+static void per_branch_cond(DisasContext *s, TCGCond cond,
+                            TCGv_i64 arg1, TCGv_i64 arg2)
+{
+#ifndef CONFIG_USER_ONLY
+    if (s->base.tb->flags & FLAG_MASK_PER) {
+        TCGLabel *lab = gen_new_label();
+        tcg_gen_brcond_i64(tcg_invert_cond(cond), arg1, arg2, lab);
+
+        tcg_gen_movi_i64(gbea, s->base.pc_next);
+        gen_helper_per_branch(cpu_env, gbea, psw_addr);
+
+        gen_set_label(lab);
+    } else {
+        TCGv_i64 pc = tcg_const_i64(s->base.pc_next);
+        tcg_gen_movcond_i64(cond, gbea, arg1, arg2, gbea, pc);
+        tcg_temp_free_i64(pc);
+    }
+#endif
+}
+
+static void per_breaking_event(DisasContext *s)
+{
+    tcg_gen_movi_i64(gbea, s->base.pc_next);
+}
+
+static void update_cc_op(DisasContext *s)
+{
+    if (s->cc_op != CC_OP_DYNAMIC && s->cc_op != CC_OP_STATIC) {
+        tcg_gen_movi_i32(cc_op, s->cc_op);
+    }
+}
+
+static inline uint64_t ld_code2(CPUS390XState *env, uint64_t pc)
+{
+    return (uint64_t)cpu_lduw_code(env, pc);
+}
+
+static inline uint64_t ld_code4(CPUS390XState *env, uint64_t pc)
+{
+    return (uint64_t)(uint32_t)cpu_ldl_code(env, pc);
+}
+
+static int get_mem_index(DisasContext *s)
+{
+#ifdef CONFIG_USER_ONLY
+    return MMU_USER_IDX;
+#else
+    if (!(s->base.tb->flags & FLAG_MASK_DAT)) {
+        return MMU_REAL_IDX;
+    }
+
+    switch (s->base.tb->flags & FLAG_MASK_ASC) {
+    case PSW_ASC_PRIMARY >> FLAG_MASK_PSW_SHIFT:
+        return MMU_PRIMARY_IDX;
+    case PSW_ASC_SECONDARY >> FLAG_MASK_PSW_SHIFT:
+        return MMU_SECONDARY_IDX;
+    case PSW_ASC_HOME >> FLAG_MASK_PSW_SHIFT:
+        return MMU_HOME_IDX;
+    default:
+        tcg_abort();
+        break;
+    }
+#endif
+}
+
+static void gen_exception(int excp)
+{
+    TCGv_i32 tmp = tcg_const_i32(excp);
+    gen_helper_exception(cpu_env, tmp);
+    tcg_temp_free_i32(tmp);
+}
+
+static void gen_program_exception(DisasContext *s, int code)
+{
+    TCGv_i32 tmp;
+
+    /* Remember what pgm exeption this was.  */
+    tmp = tcg_const_i32(code);
+    tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_code));
+    tcg_temp_free_i32(tmp);
+
+    tmp = tcg_const_i32(s->ilen);
+    tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_ilen));
+    tcg_temp_free_i32(tmp);
+
+    /* update the psw */
+    update_psw_addr(s);
+
+    /* Save off cc.  */
+    update_cc_op(s);
+
+    /* Trigger exception.  */
+    gen_exception(EXCP_PGM);
+}
+
+static inline void gen_illegal_opcode(DisasContext *s)
+{
+    gen_program_exception(s, PGM_OPERATION);
+}
+
+static inline void gen_data_exception(uint8_t dxc)
+{
+    TCGv_i32 tmp = tcg_const_i32(dxc);
+    gen_helper_data_exception(cpu_env, tmp);
+    tcg_temp_free_i32(tmp);
+}
+
+static inline void gen_trap(DisasContext *s)
+{
+    /* Set DXC to 0xff */
+    gen_data_exception(0xff);
+}
+
+static void gen_addi_and_wrap_i64(DisasContext *s, TCGv_i64 dst, TCGv_i64 src,
+                                  int64_t imm)
+{
+    tcg_gen_addi_i64(dst, src, imm);
+    if (!(s->base.tb->flags & FLAG_MASK_64)) {
+        if (s->base.tb->flags & FLAG_MASK_32) {
+            tcg_gen_andi_i64(dst, dst, 0x7fffffff);
+        } else {
+            tcg_gen_andi_i64(dst, dst, 0x00ffffff);
+        }
+    }
+}
+
+static TCGv_i64 get_address(DisasContext *s, int x2, int b2, int d2)
+{
+    TCGv_i64 tmp = tcg_temp_new_i64();
+
+    /*
+     * Note that d2 is limited to 20 bits, signed.  If we crop negative
+     * displacements early we create larger immedate addends.
+     */
+    if (b2 && x2) {
+        tcg_gen_add_i64(tmp, regs[b2], regs[x2]);
+        gen_addi_and_wrap_i64(s, tmp, tmp, d2);
+    } else if (b2) {
+        gen_addi_and_wrap_i64(s, tmp, regs[b2], d2);
+    } else if (x2) {
+        gen_addi_and_wrap_i64(s, tmp, regs[x2], d2);
+    } else if (!(s->base.tb->flags & FLAG_MASK_64)) {
+        if (s->base.tb->flags & FLAG_MASK_32) {
+            tcg_gen_movi_i64(tmp, d2 & 0x7fffffff);
+        } else {
+            tcg_gen_movi_i64(tmp, d2 & 0x00ffffff);
+        }
+    } else {
+        tcg_gen_movi_i64(tmp, d2);
+    }
+
+    return tmp;
+}
+
+static inline bool live_cc_data(DisasContext *s)
+{
+    return (s->cc_op != CC_OP_DYNAMIC
+            && s->cc_op != CC_OP_STATIC
+            && s->cc_op > 3);
+}
+
+static inline void gen_op_movi_cc(DisasContext *s, uint32_t val)
+{
+    if (live_cc_data(s)) {
+        tcg_gen_discard_i64(cc_src);
+        tcg_gen_discard_i64(cc_dst);
+        tcg_gen_discard_i64(cc_vr);
+    }
+    s->cc_op = CC_OP_CONST0 + val;
+}
+
+static void gen_op_update1_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 dst)
+{
+    if (live_cc_data(s)) {
+        tcg_gen_discard_i64(cc_src);
+        tcg_gen_discard_i64(cc_vr);
+    }
+    tcg_gen_mov_i64(cc_dst, dst);
+    s->cc_op = op;
+}
+
+static void gen_op_update2_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src,
+                                  TCGv_i64 dst)
+{
+    if (live_cc_data(s)) {
+        tcg_gen_discard_i64(cc_vr);
+    }
+    tcg_gen_mov_i64(cc_src, src);
+    tcg_gen_mov_i64(cc_dst, dst);
+    s->cc_op = op;
+}
+
+static void gen_op_update3_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src,
+                                  TCGv_i64 dst, TCGv_i64 vr)
+{
+    tcg_gen_mov_i64(cc_src, src);
+    tcg_gen_mov_i64(cc_dst, dst);
+    tcg_gen_mov_i64(cc_vr, vr);
+    s->cc_op = op;
+}
+
+static void set_cc_nz_u64(DisasContext *s, TCGv_i64 val)
+{
+    gen_op_update1_cc_i64(s, CC_OP_NZ, val);
+}
+
+/* CC value is in env->cc_op */
+static void set_cc_static(DisasContext *s)
+{
+    if (live_cc_data(s)) {
+        tcg_gen_discard_i64(cc_src);
+        tcg_gen_discard_i64(cc_dst);
+        tcg_gen_discard_i64(cc_vr);
+    }
+    s->cc_op = CC_OP_STATIC;
+}
+
+/* calculates cc into cc_op */
+static void gen_op_calc_cc(DisasContext *s)
+{
+    TCGv_i32 local_cc_op = NULL;
+    TCGv_i64 dummy = NULL;
+
+    switch (s->cc_op) {
+    default:
+        dummy = tcg_const_i64(0);
+        /* FALLTHRU */
+    case CC_OP_ADD_64:
+    case CC_OP_SUB_64:
+    case CC_OP_ADD_32:
+    case CC_OP_SUB_32:
+        local_cc_op = tcg_const_i32(s->cc_op);
+        break;
+    case CC_OP_CONST0:
+    case CC_OP_CONST1:
+    case CC_OP_CONST2:
+    case CC_OP_CONST3:
+    case CC_OP_STATIC:
+    case CC_OP_DYNAMIC:
+        break;
+    }
+
+    switch (s->cc_op) {
+    case CC_OP_CONST0:
+    case CC_OP_CONST1:
+    case CC_OP_CONST2:
+    case CC_OP_CONST3:
+        /* s->cc_op is the cc value */
+        tcg_gen_movi_i32(cc_op, s->cc_op - CC_OP_CONST0);
+        break;
+    case CC_OP_STATIC:
+        /* env->cc_op already is the cc value */
+        break;
+    case CC_OP_NZ:
+    case CC_OP_ABS_64:
+    case CC_OP_NABS_64:
+    case CC_OP_ABS_32:
+    case CC_OP_NABS_32:
+    case CC_OP_LTGT0_32:
+    case CC_OP_LTGT0_64:
+    case CC_OP_COMP_32:
+    case CC_OP_COMP_64:
+    case CC_OP_NZ_F32:
+    case CC_OP_NZ_F64:
+    case CC_OP_FLOGR:
+    case CC_OP_LCBB:
+    case CC_OP_MULS_32:
+        /* 1 argument */
+        gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, dummy, cc_dst, dummy);
+        break;
+    case CC_OP_ADDU:
+    case CC_OP_ICM:
+    case CC_OP_LTGT_32:
+    case CC_OP_LTGT_64:
+    case CC_OP_LTUGTU_32:
+    case CC_OP_LTUGTU_64:
+    case CC_OP_TM_32:
+    case CC_OP_TM_64:
+    case CC_OP_SLA_32:
+    case CC_OP_SLA_64:
+    case CC_OP_SUBU:
+    case CC_OP_NZ_F128:
+    case CC_OP_VC:
+    case CC_OP_MULS_64:
+        /* 2 arguments */
+        gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, dummy);
+        break;
+    case CC_OP_ADD_64:
+    case CC_OP_SUB_64:
+    case CC_OP_ADD_32:
+    case CC_OP_SUB_32:
+        /* 3 arguments */
+        gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, cc_vr);
+        break;
+    case CC_OP_DYNAMIC:
+        /* unknown operation - assume 3 arguments and cc_op in env */
+        gen_helper_calc_cc(cc_op, cpu_env, cc_op, cc_src, cc_dst, cc_vr);
+        break;
+    default:
+        tcg_abort();
+    }
+
+    if (local_cc_op) {
+        tcg_temp_free_i32(local_cc_op);
+    }
+    if (dummy) {
+        tcg_temp_free_i64(dummy);
+    }
+
+    /* We now have cc in cc_op as constant */
+    set_cc_static(s);
+}
+
+static bool use_goto_tb(DisasContext *s, uint64_t dest)
+{
+    if (unlikely(s->base.tb->flags & FLAG_MASK_PER)) {
+        return false;
+    }
+    return translator_use_goto_tb(&s->base, dest);
+}
+
+static void account_noninline_branch(DisasContext *s, int cc_op)
+{
+#ifdef DEBUG_INLINE_BRANCHES
+    inline_branch_miss[cc_op]++;
+#endif
+}
+
+static void account_inline_branch(DisasContext *s, int cc_op)
+{
+#ifdef DEBUG_INLINE_BRANCHES
+    inline_branch_hit[cc_op]++;
+#endif
+}
+
+/* Table of mask values to comparison codes, given a comparison as input.
+   For such, CC=3 should not be possible.  */
+static const TCGCond ltgt_cond[16] = {
+    TCG_COND_NEVER,  TCG_COND_NEVER,     /*    |    |    | x */
+    TCG_COND_GT,     TCG_COND_GT,        /*    |    | GT | x */
+    TCG_COND_LT,     TCG_COND_LT,        /*    | LT |    | x */
+    TCG_COND_NE,     TCG_COND_NE,        /*    | LT | GT | x */
+    TCG_COND_EQ,     TCG_COND_EQ,        /* EQ |    |    | x */
+    TCG_COND_GE,     TCG_COND_GE,        /* EQ |    | GT | x */
+    TCG_COND_LE,     TCG_COND_LE,        /* EQ | LT |    | x */
+    TCG_COND_ALWAYS, TCG_COND_ALWAYS,    /* EQ | LT | GT | x */
+};
+
+/* Table of mask values to comparison codes, given a logic op as input.
+   For such, only CC=0 and CC=1 should be possible.  */
+static const TCGCond nz_cond[16] = {
+    TCG_COND_NEVER, TCG_COND_NEVER,      /*    |    | x | x */
+    TCG_COND_NEVER, TCG_COND_NEVER,
+    TCG_COND_NE, TCG_COND_NE,            /*    | NE | x | x */
+    TCG_COND_NE, TCG_COND_NE,
+    TCG_COND_EQ, TCG_COND_EQ,            /* EQ |    | x | x */
+    TCG_COND_EQ, TCG_COND_EQ,
+    TCG_COND_ALWAYS, TCG_COND_ALWAYS,    /* EQ | NE | x | x */
+    TCG_COND_ALWAYS, TCG_COND_ALWAYS,
+};
+
+/* Interpret MASK in terms of S->CC_OP, and fill in C with all the
+   details required to generate a TCG comparison.  */
+static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask)
+{
+    TCGCond cond;
+    enum cc_op old_cc_op = s->cc_op;
+
+    if (mask == 15 || mask == 0) {
+        c->cond = (mask ? TCG_COND_ALWAYS : TCG_COND_NEVER);
+        c->u.s32.a = cc_op;
+        c->u.s32.b = cc_op;
+        c->g1 = c->g2 = true;
+        c->is_64 = false;
+        return;
+    }
+
+    /* Find the TCG condition for the mask + cc op.  */
+    switch (old_cc_op) {
+    case CC_OP_LTGT0_32:
+    case CC_OP_LTGT0_64:
+    case CC_OP_LTGT_32:
+    case CC_OP_LTGT_64:
+        cond = ltgt_cond[mask];
+        if (cond == TCG_COND_NEVER) {
+            goto do_dynamic;
+        }
+        account_inline_branch(s, old_cc_op);
+        break;
+
+    case CC_OP_LTUGTU_32:
+    case CC_OP_LTUGTU_64:
+        cond = tcg_unsigned_cond(ltgt_cond[mask]);
+        if (cond == TCG_COND_NEVER) {
+            goto do_dynamic;
+        }
+        account_inline_branch(s, old_cc_op);
+        break;
+
+    case CC_OP_NZ:
+        cond = nz_cond[mask];
+        if (cond == TCG_COND_NEVER) {
+            goto do_dynamic;
+        }
+        account_inline_branch(s, old_cc_op);
+        break;
+
+    case CC_OP_TM_32:
+    case CC_OP_TM_64:
+        switch (mask) {
+        case 8:
+            cond = TCG_COND_EQ;
+            break;
+        case 4 | 2 | 1:
+            cond = TCG_COND_NE;
+            break;
+        default:
+            goto do_dynamic;
+        }
+        account_inline_branch(s, old_cc_op);
+        break;
+
+    case CC_OP_ICM:
+        switch (mask) {
+        case 8:
+            cond = TCG_COND_EQ;
+            break;
+        case 4 | 2 | 1:
+        case 4 | 2:
+            cond = TCG_COND_NE;
+            break;
+        default:
+            goto do_dynamic;
+        }
+        account_inline_branch(s, old_cc_op);
+        break;
+
+    case CC_OP_FLOGR:
+        switch (mask & 0xa) {
+        case 8: /* src == 0 -> no one bit found */
+            cond = TCG_COND_EQ;
+            break;
+        case 2: /* src != 0 -> one bit found */
+            cond = TCG_COND_NE;
+            break;
+        default:
+            goto do_dynamic;
+        }
+        account_inline_branch(s, old_cc_op);
+        break;
+
+    case CC_OP_ADDU:
+    case CC_OP_SUBU:
+        switch (mask) {
+        case 8 | 2: /* result == 0 */
+            cond = TCG_COND_EQ;
+            break;
+        case 4 | 1: /* result != 0 */
+            cond = TCG_COND_NE;
+            break;
+        case 8 | 4: /* !carry (borrow) */
+            cond = old_cc_op == CC_OP_ADDU ? TCG_COND_EQ : TCG_COND_NE;
+            break;
+        case 2 | 1: /* carry (!borrow) */
+            cond = old_cc_op == CC_OP_ADDU ? TCG_COND_NE : TCG_COND_EQ;
+            break;
+        default:
+            goto do_dynamic;
+        }
+        account_inline_branch(s, old_cc_op);
+        break;
+
+    default:
+    do_dynamic:
+        /* Calculate cc value.  */
+        gen_op_calc_cc(s);
+        /* FALLTHRU */
+
+    case CC_OP_STATIC:
+        /* Jump based on CC.  We'll load up the real cond below;
+           the assignment here merely avoids a compiler warning.  */
+        account_noninline_branch(s, old_cc_op);
+        old_cc_op = CC_OP_STATIC;
+        cond = TCG_COND_NEVER;
+        break;
+    }
+
+    /* Load up the arguments of the comparison.  */
+    c->is_64 = true;
+    c->g1 = c->g2 = false;
+    switch (old_cc_op) {
+    case CC_OP_LTGT0_32:
+        c->is_64 = false;
+        c->u.s32.a = tcg_temp_new_i32();
+        tcg_gen_extrl_i64_i32(c->u.s32.a, cc_dst);
+        c->u.s32.b = tcg_const_i32(0);
+        break;
+    case CC_OP_LTGT_32:
+    case CC_OP_LTUGTU_32:
+        c->is_64 = false;
+        c->u.s32.a = tcg_temp_new_i32();
+        tcg_gen_extrl_i64_i32(c->u.s32.a, cc_src);
+        c->u.s32.b = tcg_temp_new_i32();
+        tcg_gen_extrl_i64_i32(c->u.s32.b, cc_dst);
+        break;
+
+    case CC_OP_LTGT0_64:
+    case CC_OP_NZ:
+    case CC_OP_FLOGR:
+        c->u.s64.a = cc_dst;
+        c->u.s64.b = tcg_const_i64(0);
+        c->g1 = true;
+        break;
+    case CC_OP_LTGT_64:
+    case CC_OP_LTUGTU_64:
+        c->u.s64.a = cc_src;
+        c->u.s64.b = cc_dst;
+        c->g1 = c->g2 = true;
+        break;
+
+    case CC_OP_TM_32:
+    case CC_OP_TM_64:
+    case CC_OP_ICM:
+        c->u.s64.a = tcg_temp_new_i64();
+        c->u.s64.b = tcg_const_i64(0);
+        tcg_gen_and_i64(c->u.s64.a, cc_src, cc_dst);
+        break;
+
+    case CC_OP_ADDU:
+    case CC_OP_SUBU:
+        c->is_64 = true;
+        c->u.s64.b = tcg_const_i64(0);
+        c->g1 = true;
+        switch (mask) {
+        case 8 | 2:
+        case 4 | 1: /* result */
+            c->u.s64.a = cc_dst;
+            break;
+        case 8 | 4:
+        case 2 | 1: /* carry */
+            c->u.s64.a = cc_src;
+            break;
+        default:
+            g_assert_not_reached();
+        }
+        break;
+
+    case CC_OP_STATIC:
+        c->is_64 = false;
+        c->u.s32.a = cc_op;
+        c->g1 = true;
+        switch (mask) {
+        case 0x8 | 0x4 | 0x2: /* cc != 3 */
+            cond = TCG_COND_NE;
+            c->u.s32.b = tcg_const_i32(3);
+            break;
+        case 0x8 | 0x4 | 0x1: /* cc != 2 */
+            cond = TCG_COND_NE;
+            c->u.s32.b = tcg_const_i32(2);
+            break;
+        case 0x8 | 0x2 | 0x1: /* cc != 1 */
+            cond = TCG_COND_NE;
+            c->u.s32.b = tcg_const_i32(1);
+            break;
+        case 0x8 | 0x2: /* cc == 0 || cc == 2 => (cc & 1) == 0 */
+            cond = TCG_COND_EQ;
+            c->g1 = false;
+            c->u.s32.a = tcg_temp_new_i32();
+            c->u.s32.b = tcg_const_i32(0);
+            tcg_gen_andi_i32(c->u.s32.a, cc_op, 1);
+            break;
+        case 0x8 | 0x4: /* cc < 2 */
+            cond = TCG_COND_LTU;
+            c->u.s32.b = tcg_const_i32(2);
+            break;
+        case 0x8: /* cc == 0 */
+            cond = TCG_COND_EQ;
+            c->u.s32.b = tcg_const_i32(0);
+            break;
+        case 0x4 | 0x2 | 0x1: /* cc != 0 */
+            cond = TCG_COND_NE;
+            c->u.s32.b = tcg_const_i32(0);
+            break;
+        case 0x4 | 0x1: /* cc == 1 || cc == 3 => (cc & 1) != 0 */
+            cond = TCG_COND_NE;
+            c->g1 = false;
+            c->u.s32.a = tcg_temp_new_i32();
+            c->u.s32.b = tcg_const_i32(0);
+            tcg_gen_andi_i32(c->u.s32.a, cc_op, 1);
+            break;
+        case 0x4: /* cc == 1 */
+            cond = TCG_COND_EQ;
+            c->u.s32.b = tcg_const_i32(1);
+            break;
+        case 0x2 | 0x1: /* cc > 1 */
+            cond = TCG_COND_GTU;
+            c->u.s32.b = tcg_const_i32(1);
+            break;
+        case 0x2: /* cc == 2 */
+            cond = TCG_COND_EQ;
+            c->u.s32.b = tcg_const_i32(2);
+            break;
+        case 0x1: /* cc == 3 */
+            cond = TCG_COND_EQ;
+            c->u.s32.b = tcg_const_i32(3);
+            break;
+        default:
+            /* CC is masked by something else: (8 >> cc) & mask.  */
+            cond = TCG_COND_NE;
+            c->g1 = false;
+            c->u.s32.a = tcg_const_i32(8);
+            c->u.s32.b = tcg_const_i32(0);
+            tcg_gen_shr_i32(c->u.s32.a, c->u.s32.a, cc_op);
+            tcg_gen_andi_i32(c->u.s32.a, c->u.s32.a, mask);
+            break;
+        }
+        break;
+
+    default:
+        abort();
+    }
+    c->cond = cond;
+}
+
+static void free_compare(DisasCompare *c)
+{
+    if (!c->g1) {
+        if (c->is_64) {
+            tcg_temp_free_i64(c->u.s64.a);
+        } else {
+            tcg_temp_free_i32(c->u.s32.a);
+        }
+    }
+    if (!c->g2) {
+        if (c->is_64) {
+            tcg_temp_free_i64(c->u.s64.b);
+        } else {
+            tcg_temp_free_i32(c->u.s32.b);
+        }
+    }
+}
+
+/* ====================================================================== */
+/* Define the insn format enumeration.  */
+#define F0(N)                         FMT_##N,
+#define F1(N, X1)                     F0(N)
+#define F2(N, X1, X2)                 F0(N)
+#define F3(N, X1, X2, X3)             F0(N)
+#define F4(N, X1, X2, X3, X4)         F0(N)
+#define F5(N, X1, X2, X3, X4, X5)     F0(N)
+#define F6(N, X1, X2, X3, X4, X5, X6) F0(N)
+
+typedef enum {
+#include "insn-format.def"
+} DisasFormat;
+
+#undef F0
+#undef F1
+#undef F2
+#undef F3
+#undef F4
+#undef F5
+#undef F6
+
+/* This is the way fields are to be accessed out of DisasFields.  */
+#define have_field(S, F)  have_field1((S), FLD_O_##F)
+#define get_field(S, F)   get_field1((S), FLD_O_##F, FLD_C_##F)
+
+static bool have_field1(const DisasContext *s, enum DisasFieldIndexO c)
+{
+    return (s->fields.presentO >> c) & 1;
+}
+
+static int get_field1(const DisasContext *s, enum DisasFieldIndexO o,
+                      enum DisasFieldIndexC c)
+{
+    assert(have_field1(s, o));
+    return s->fields.c[c];
+}
+
+/* Describe the layout of each field in each format.  */
+typedef struct DisasField {
+    unsigned int beg:8;
+    unsigned int size:8;
+    unsigned int type:2;
+    unsigned int indexC:6;
+    enum DisasFieldIndexO indexO:8;
+} DisasField;
+
+typedef struct DisasFormatInfo {
+    DisasField op[NUM_C_FIELD];
+} DisasFormatInfo;
+
+#define R(N, B)       {  B,  4, 0, FLD_C_r##N, FLD_O_r##N }
+#define M(N, B)       {  B,  4, 0, FLD_C_m##N, FLD_O_m##N }
+#define V(N, B)       {  B,  4, 3, FLD_C_v##N, FLD_O_v##N }
+#define BD(N, BB, BD) { BB,  4, 0, FLD_C_b##N, FLD_O_b##N }, \
+                      { BD, 12, 0, FLD_C_d##N, FLD_O_d##N }
+#define BXD(N)        { 16,  4, 0, FLD_C_b##N, FLD_O_b##N }, \
+                      { 12,  4, 0, FLD_C_x##N, FLD_O_x##N }, \
+                      { 20, 12, 0, FLD_C_d##N, FLD_O_d##N }
+#define BDL(N)        { 16,  4, 0, FLD_C_b##N, FLD_O_b##N }, \
+                      { 20, 20, 2, FLD_C_d##N, FLD_O_d##N }
+#define BXDL(N)       { 16,  4, 0, FLD_C_b##N, FLD_O_b##N }, \
+                      { 12,  4, 0, FLD_C_x##N, FLD_O_x##N }, \
+                      { 20, 20, 2, FLD_C_d##N, FLD_O_d##N }
+#define I(N, B, S)    {  B,  S, 1, FLD_C_i##N, FLD_O_i##N }
+#define L(N, B, S)    {  B,  S, 0, FLD_C_l##N, FLD_O_l##N }
+
+#define F0(N)                     { { } },
+#define F1(N, X1)                 { { X1 } },
+#define F2(N, X1, X2)             { { X1, X2 } },
+#define F3(N, X1, X2, X3)         { { X1, X2, X3 } },
+#define F4(N, X1, X2, X3, X4)     { { X1, X2, X3, X4 } },
+#define F5(N, X1, X2, X3, X4, X5) { { X1, X2, X3, X4, X5 } },
+#define F6(N, X1, X2, X3, X4, X5, X6)       { { X1, X2, X3, X4, X5, X6 } },
+
+static const DisasFormatInfo format_info[] = {
+#include "insn-format.def"
+};
+
+#undef F0
+#undef F1
+#undef F2
+#undef F3
+#undef F4
+#undef F5
+#undef F6
+#undef R
+#undef M
+#undef V
+#undef BD
+#undef BXD
+#undef BDL
+#undef BXDL
+#undef I
+#undef L
+
+/* Generally, we'll extract operands into this structures, operate upon
+   them, and store them back.  See the "in1", "in2", "prep", "wout" sets
+   of routines below for more details.  */
+typedef struct {
+    bool g_out, g_out2, g_in1, g_in2;
+    TCGv_i64 out, out2, in1, in2;
+    TCGv_i64 addr1;
+} DisasOps;
+
+/* Instructions can place constraints on their operands, raising specification
+   exceptions if they are violated.  To make this easy to automate, each "in1",
+   "in2", "prep", "wout" helper will have a SPEC_<name> define that equals one
+   of the following, or 0.  To make this easy to document, we'll put the
+   SPEC_<name> defines next to <name>.  */
+
+#define SPEC_r1_even    1
+#define SPEC_r2_even    2
+#define SPEC_r3_even    4
+#define SPEC_r1_f128    8
+#define SPEC_r2_f128    16
+
+/* Return values from translate_one, indicating the state of the TB.  */
+
+/* We are not using a goto_tb (for whatever reason), but have updated
+   the PC (for whatever reason), so there's no need to do it again on
+   exiting the TB.  */
+#define DISAS_PC_UPDATED        DISAS_TARGET_0
+
+/* We have emitted one or more goto_tb.  No fixup required.  */
+#define DISAS_GOTO_TB           DISAS_TARGET_1
+
+/* We have updated the PC and CC values.  */
+#define DISAS_PC_CC_UPDATED     DISAS_TARGET_2
+
+/* We are exiting the TB, but have neither emitted a goto_tb, nor
+   updated the PC for the next instruction to be executed.  */
+#define DISAS_PC_STALE          DISAS_TARGET_3
+
+/* We are exiting the TB to the main loop.  */
+#define DISAS_PC_STALE_NOCHAIN  DISAS_TARGET_4
+
+
+/* Instruction flags */
+#define IF_AFP1     0x0001      /* r1 is a fp reg for HFP/FPS instructions */
+#define IF_AFP2     0x0002      /* r2 is a fp reg for HFP/FPS instructions */
+#define IF_AFP3     0x0004      /* r3 is a fp reg for HFP/FPS instructions */
+#define IF_BFP      0x0008      /* binary floating point instruction */
+#define IF_DFP      0x0010      /* decimal floating point instruction */
+#define IF_PRIV     0x0020      /* privileged instruction */
+#define IF_VEC      0x0040      /* vector instruction */
+#define IF_IO       0x0080      /* input/output instruction */
+
+struct DisasInsn {
+    unsigned opc:16;
+    unsigned flags:16;
+    DisasFormat fmt:8;
+    unsigned fac:8;
+    unsigned spec:8;
+
+    const char *name;
+
+    /* Pre-process arguments before HELP_OP.  */
+    void (*help_in1)(DisasContext *, DisasOps *);
+    void (*help_in2)(DisasContext *, DisasOps *);
+    void (*help_prep)(DisasContext *, DisasOps *);
+
+    /*
+     * Post-process output after HELP_OP.
+     * Note that these are not called if HELP_OP returns DISAS_NORETURN.
+     */
+    void (*help_wout)(DisasContext *, DisasOps *);
+    void (*help_cout)(DisasContext *, DisasOps *);
+
+    /* Implement the operation itself.  */
+    DisasJumpType (*help_op)(DisasContext *, DisasOps *);
+
+    uint64_t data;
+};
+
+/* ====================================================================== */
+/* Miscellaneous helpers, used by several operations.  */
+
+static void help_l2_shift(DisasContext *s, DisasOps *o, int mask)
+{
+    int b2 = get_field(s, b2);
+    int d2 = get_field(s, d2);
+
+    if (b2 == 0) {
+        o->in2 = tcg_const_i64(d2 & mask);
+    } else {
+        o->in2 = get_address(s, 0, b2, d2);
+        tcg_gen_andi_i64(o->in2, o->in2, mask);
+    }
+}
+
+static DisasJumpType help_goto_direct(DisasContext *s, uint64_t dest)
+{
+    if (dest == s->pc_tmp) {
+        per_branch(s, true);
+        return DISAS_NEXT;
+    }
+    if (use_goto_tb(s, dest)) {
+        update_cc_op(s);
+        per_breaking_event(s);
+        tcg_gen_goto_tb(0);
+        tcg_gen_movi_i64(psw_addr, dest);
+        tcg_gen_exit_tb(s->base.tb, 0);
+        return DISAS_GOTO_TB;
+    } else {
+        tcg_gen_movi_i64(psw_addr, dest);
+        per_branch(s, false);
+        return DISAS_PC_UPDATED;
+    }
+}
+
+static DisasJumpType help_branch(DisasContext *s, DisasCompare *c,
+                                 bool is_imm, int imm, TCGv_i64 cdest)
+{
+    DisasJumpType ret;
+    uint64_t dest = s->base.pc_next + 2 * imm;
+    TCGLabel *lab;
+
+    /* Take care of the special cases first.  */
+    if (c->cond == TCG_COND_NEVER) {
+        ret = DISAS_NEXT;
+        goto egress;
+    }
+    if (is_imm) {
+        if (dest == s->pc_tmp) {
+            /* Branch to next.  */
+            per_branch(s, true);
+            ret = DISAS_NEXT;
+            goto egress;
+        }
+        if (c->cond == TCG_COND_ALWAYS) {
+            ret = help_goto_direct(s, dest);
+            goto egress;
+        }
+    } else {
+        if (!cdest) {
+            /* E.g. bcr %r0 -> no branch.  */
+            ret = DISAS_NEXT;
+            goto egress;
+        }
+        if (c->cond == TCG_COND_ALWAYS) {
+            tcg_gen_mov_i64(psw_addr, cdest);
+            per_branch(s, false);
+            ret = DISAS_PC_UPDATED;
+            goto egress;
+        }
+    }
+
+    if (use_goto_tb(s, s->pc_tmp)) {
+        if (is_imm && use_goto_tb(s, dest)) {
+            /* Both exits can use goto_tb.  */
+            update_cc_op(s);
+
+            lab = gen_new_label();
+            if (c->is_64) {
+                tcg_gen_brcond_i64(c->cond, c->u.s64.a, c->u.s64.b, lab);
+            } else {
+                tcg_gen_brcond_i32(c->cond, c->u.s32.a, c->u.s32.b, lab);
+            }
+
+            /* Branch not taken.  */
+            tcg_gen_goto_tb(0);
+            tcg_gen_movi_i64(psw_addr, s->pc_tmp);
+            tcg_gen_exit_tb(s->base.tb, 0);
+
+            /* Branch taken.  */
+            gen_set_label(lab);
+            per_breaking_event(s);
+            tcg_gen_goto_tb(1);
+            tcg_gen_movi_i64(psw_addr, dest);
+            tcg_gen_exit_tb(s->base.tb, 1);
+
+            ret = DISAS_GOTO_TB;
+        } else {
+            /* Fallthru can use goto_tb, but taken branch cannot.  */
+            /* Store taken branch destination before the brcond.  This
+               avoids having to allocate a new local temp to hold it.
+               We'll overwrite this in the not taken case anyway.  */
+            if (!is_imm) {
+                tcg_gen_mov_i64(psw_addr, cdest);
+            }
+
+            lab = gen_new_label();
+            if (c->is_64) {
+                tcg_gen_brcond_i64(c->cond, c->u.s64.a, c->u.s64.b, lab);
+            } else {
+                tcg_gen_brcond_i32(c->cond, c->u.s32.a, c->u.s32.b, lab);
+            }
+
+            /* Branch not taken.  */
+            update_cc_op(s);
+            tcg_gen_goto_tb(0);
+            tcg_gen_movi_i64(psw_addr, s->pc_tmp);
+            tcg_gen_exit_tb(s->base.tb, 0);
+
+            gen_set_label(lab);
+            if (is_imm) {
+                tcg_gen_movi_i64(psw_addr, dest);
+            }
+            per_breaking_event(s);
+            ret = DISAS_PC_UPDATED;
+        }
+    } else {
+        /* Fallthru cannot use goto_tb.  This by itself is vanishingly rare.
+           Most commonly we're single-stepping or some other condition that
+           disables all use of goto_tb.  Just update the PC and exit.  */
+
+        TCGv_i64 next = tcg_const_i64(s->pc_tmp);
+        if (is_imm) {
+            cdest = tcg_const_i64(dest);
+        }
+
+        if (c->is_64) {
+            tcg_gen_movcond_i64(c->cond, psw_addr, c->u.s64.a, c->u.s64.b,
+                                cdest, next);
+            per_branch_cond(s, c->cond, c->u.s64.a, c->u.s64.b);
+        } else {
+            TCGv_i32 t0 = tcg_temp_new_i32();
+            TCGv_i64 t1 = tcg_temp_new_i64();
+            TCGv_i64 z = tcg_const_i64(0);
+            tcg_gen_setcond_i32(c->cond, t0, c->u.s32.a, c->u.s32.b);
+            tcg_gen_extu_i32_i64(t1, t0);
+            tcg_temp_free_i32(t0);
+            tcg_gen_movcond_i64(TCG_COND_NE, psw_addr, t1, z, cdest, next);
+            per_branch_cond(s, TCG_COND_NE, t1, z);
+            tcg_temp_free_i64(t1);
+            tcg_temp_free_i64(z);
+        }
+
+        if (is_imm) {
+            tcg_temp_free_i64(cdest);
+        }
+        tcg_temp_free_i64(next);
+
+        ret = DISAS_PC_UPDATED;
+    }
+
+ egress:
+    free_compare(c);
+    return ret;
+}
+
+/* ====================================================================== */
+/* The operations.  These perform the bulk of the work for any insn,
+   usually after the operands have been loaded and output initialized.  */
+
+static DisasJumpType op_abs(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_abs_i64(o->out, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_absf32(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_andi_i64(o->out, o->in2, 0x7fffffffull);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_absf64(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_andi_i64(o->out, o->in2, 0x7fffffffffffffffull);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_absf128(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_andi_i64(o->out, o->in1, 0x7fffffffffffffffull);
+    tcg_gen_mov_i64(o->out2, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_add(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_add_i64(o->out, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_addu64(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_movi_i64(cc_src, 0);
+    tcg_gen_add2_i64(o->out, cc_src, o->in1, cc_src, o->in2, cc_src);
+    return DISAS_NEXT;
+}
+
+/* Compute carry into cc_src. */
+static void compute_carry(DisasContext *s)
+{
+    switch (s->cc_op) {
+    case CC_OP_ADDU:
+        /* The carry value is already in cc_src (1,0). */
+        break;
+    case CC_OP_SUBU:
+        tcg_gen_addi_i64(cc_src, cc_src, 1);
+        break;
+    default:
+        gen_op_calc_cc(s);
+        /* fall through */
+    case CC_OP_STATIC:
+        /* The carry flag is the msb of CC; compute into cc_src. */
+        tcg_gen_extu_i32_i64(cc_src, cc_op);
+        tcg_gen_shri_i64(cc_src, cc_src, 1);
+        break;
+    }
+}
+
+static DisasJumpType op_addc32(DisasContext *s, DisasOps *o)
+{
+    compute_carry(s);
+    tcg_gen_add_i64(o->out, o->in1, o->in2);
+    tcg_gen_add_i64(o->out, o->out, cc_src);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_addc64(DisasContext *s, DisasOps *o)
+{
+    compute_carry(s);
+
+    TCGv_i64 zero = tcg_const_i64(0);
+    tcg_gen_add2_i64(o->out, cc_src, o->in1, zero, cc_src, zero);
+    tcg_gen_add2_i64(o->out, cc_src, o->out, cc_src, o->in2, zero);
+    tcg_temp_free_i64(zero);
+
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_asi(DisasContext *s, DisasOps *o)
+{
+    bool non_atomic = !s390_has_feat(S390_FEAT_STFLE_45);
+
+    o->in1 = tcg_temp_new_i64();
+    if (non_atomic) {
+        tcg_gen_qemu_ld_tl(o->in1, o->addr1, get_mem_index(s), s->insn->data);
+    } else {
+        /* Perform the atomic addition in memory. */
+        tcg_gen_atomic_fetch_add_i64(o->in1, o->addr1, o->in2, get_mem_index(s),
+                                     s->insn->data);
+    }
+
+    /* Recompute also for atomic case: needed for setting CC. */
+    tcg_gen_add_i64(o->out, o->in1, o->in2);
+
+    if (non_atomic) {
+        tcg_gen_qemu_st_tl(o->out, o->addr1, get_mem_index(s), s->insn->data);
+    }
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_asiu64(DisasContext *s, DisasOps *o)
+{
+    bool non_atomic = !s390_has_feat(S390_FEAT_STFLE_45);
+
+    o->in1 = tcg_temp_new_i64();
+    if (non_atomic) {
+        tcg_gen_qemu_ld_tl(o->in1, o->addr1, get_mem_index(s), s->insn->data);
+    } else {
+        /* Perform the atomic addition in memory. */
+        tcg_gen_atomic_fetch_add_i64(o->in1, o->addr1, o->in2, get_mem_index(s),
+                                     s->insn->data);
+    }
+
+    /* Recompute also for atomic case: needed for setting CC. */
+    tcg_gen_movi_i64(cc_src, 0);
+    tcg_gen_add2_i64(o->out, cc_src, o->in1, cc_src, o->in2, cc_src);
+
+    if (non_atomic) {
+        tcg_gen_qemu_st_tl(o->out, o->addr1, get_mem_index(s), s->insn->data);
+    }
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_aeb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_aeb(o->out, cpu_env, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_adb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_adb(o->out, cpu_env, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_axb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_axb(o->out, cpu_env, o->out, o->out2, o->in1, o->in2);
+    return_low128(o->out2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_and(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_and_i64(o->out, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_andi(DisasContext *s, DisasOps *o)
+{
+    int shift = s->insn->data & 0xff;
+    int size = s->insn->data >> 8;
+    uint64_t mask = ((1ull << size) - 1) << shift;
+
+    assert(!o->g_in2);
+    tcg_gen_shli_i64(o->in2, o->in2, shift);
+    tcg_gen_ori_i64(o->in2, o->in2, ~mask);
+    tcg_gen_and_i64(o->out, o->in1, o->in2);
+
+    /* Produce the CC from only the bits manipulated.  */
+    tcg_gen_andi_i64(cc_dst, o->out, mask);
+    set_cc_nz_u64(s, cc_dst);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_ni(DisasContext *s, DisasOps *o)
+{
+    o->in1 = tcg_temp_new_i64();
+
+    if (!s390_has_feat(S390_FEAT_INTERLOCKED_ACCESS_2)) {
+        tcg_gen_qemu_ld_tl(o->in1, o->addr1, get_mem_index(s), s->insn->data);
+    } else {
+        /* Perform the atomic operation in memory. */
+        tcg_gen_atomic_fetch_and_i64(o->in1, o->addr1, o->in2, get_mem_index(s),
+                                     s->insn->data);
+    }
+
+    /* Recompute also for atomic case: needed for setting CC. */
+    tcg_gen_and_i64(o->out, o->in1, o->in2);
+
+    if (!s390_has_feat(S390_FEAT_INTERLOCKED_ACCESS_2)) {
+        tcg_gen_qemu_st_tl(o->out, o->addr1, get_mem_index(s), s->insn->data);
+    }
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_bas(DisasContext *s, DisasOps *o)
+{
+    pc_to_link_info(o->out, s, s->pc_tmp);
+    if (o->in2) {
+        tcg_gen_mov_i64(psw_addr, o->in2);
+        per_branch(s, false);
+        return DISAS_PC_UPDATED;
+    } else {
+        return DISAS_NEXT;
+    }
+}
+
+static void save_link_info(DisasContext *s, DisasOps *o)
+{
+    TCGv_i64 t;
+
+    if (s->base.tb->flags & (FLAG_MASK_32 | FLAG_MASK_64)) {
+        pc_to_link_info(o->out, s, s->pc_tmp);
+        return;
+    }
+    gen_op_calc_cc(s);
+    tcg_gen_andi_i64(o->out, o->out, 0xffffffff00000000ull);
+    tcg_gen_ori_i64(o->out, o->out, ((s->ilen / 2) << 30) | s->pc_tmp);
+    t = tcg_temp_new_i64();
+    tcg_gen_shri_i64(t, psw_mask, 16);
+    tcg_gen_andi_i64(t, t, 0x0f000000);
+    tcg_gen_or_i64(o->out, o->out, t);
+    tcg_gen_extu_i32_i64(t, cc_op);
+    tcg_gen_shli_i64(t, t, 28);
+    tcg_gen_or_i64(o->out, o->out, t);
+    tcg_temp_free_i64(t);
+}
+
+static DisasJumpType op_bal(DisasContext *s, DisasOps *o)
+{
+    save_link_info(s, o);
+    if (o->in2) {
+        tcg_gen_mov_i64(psw_addr, o->in2);
+        per_branch(s, false);
+        return DISAS_PC_UPDATED;
+    } else {
+        return DISAS_NEXT;
+    }
+}
+
+static DisasJumpType op_basi(DisasContext *s, DisasOps *o)
+{
+    pc_to_link_info(o->out, s, s->pc_tmp);
+    return help_goto_direct(s, s->base.pc_next + 2 * get_field(s, i2));
+}
+
+static DisasJumpType op_bc(DisasContext *s, DisasOps *o)
+{
+    int m1 = get_field(s, m1);
+    bool is_imm = have_field(s, i2);
+    int imm = is_imm ? get_field(s, i2) : 0;
+    DisasCompare c;
+
+    /* BCR with R2 = 0 causes no branching */
+    if (have_field(s, r2) && get_field(s, r2) == 0) {
+        if (m1 == 14) {
+            /* Perform serialization */
+            /* FIXME: check for fast-BCR-serialization facility */
+            tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
+        }
+        if (m1 == 15) {
+            /* Perform serialization */
+            /* FIXME: perform checkpoint-synchronisation */
+            tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
+        }
+        return DISAS_NEXT;
+    }
+
+    disas_jcc(s, &c, m1);
+    return help_branch(s, &c, is_imm, imm, o->in2);
+}
+
+static DisasJumpType op_bct32(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    bool is_imm = have_field(s, i2);
+    int imm = is_imm ? get_field(s, i2) : 0;
+    DisasCompare c;
+    TCGv_i64 t;
+
+    c.cond = TCG_COND_NE;
+    c.is_64 = false;
+    c.g1 = false;
+    c.g2 = false;
+
+    t = tcg_temp_new_i64();
+    tcg_gen_subi_i64(t, regs[r1], 1);
+    store_reg32_i64(r1, t);
+    c.u.s32.a = tcg_temp_new_i32();
+    c.u.s32.b = tcg_const_i32(0);
+    tcg_gen_extrl_i64_i32(c.u.s32.a, t);
+    tcg_temp_free_i64(t);
+
+    return help_branch(s, &c, is_imm, imm, o->in2);
+}
+
+static DisasJumpType op_bcth(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    int imm = get_field(s, i2);
+    DisasCompare c;
+    TCGv_i64 t;
+
+    c.cond = TCG_COND_NE;
+    c.is_64 = false;
+    c.g1 = false;
+    c.g2 = false;
+
+    t = tcg_temp_new_i64();
+    tcg_gen_shri_i64(t, regs[r1], 32);
+    tcg_gen_subi_i64(t, t, 1);
+    store_reg32h_i64(r1, t);
+    c.u.s32.a = tcg_temp_new_i32();
+    c.u.s32.b = tcg_const_i32(0);
+    tcg_gen_extrl_i64_i32(c.u.s32.a, t);
+    tcg_temp_free_i64(t);
+
+    return help_branch(s, &c, 1, imm, o->in2);
+}
+
+static DisasJumpType op_bct64(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    bool is_imm = have_field(s, i2);
+    int imm = is_imm ? get_field(s, i2) : 0;
+    DisasCompare c;
+
+    c.cond = TCG_COND_NE;
+    c.is_64 = true;
+    c.g1 = true;
+    c.g2 = false;
+
+    tcg_gen_subi_i64(regs[r1], regs[r1], 1);
+    c.u.s64.a = regs[r1];
+    c.u.s64.b = tcg_const_i64(0);
+
+    return help_branch(s, &c, is_imm, imm, o->in2);
+}
+
+static DisasJumpType op_bx32(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    int r3 = get_field(s, r3);
+    bool is_imm = have_field(s, i2);
+    int imm = is_imm ? get_field(s, i2) : 0;
+    DisasCompare c;
+    TCGv_i64 t;
+
+    c.cond = (s->insn->data ? TCG_COND_LE : TCG_COND_GT);
+    c.is_64 = false;
+    c.g1 = false;
+    c.g2 = false;
+
+    t = tcg_temp_new_i64();
+    tcg_gen_add_i64(t, regs[r1], regs[r3]);
+    c.u.s32.a = tcg_temp_new_i32();
+    c.u.s32.b = tcg_temp_new_i32();
+    tcg_gen_extrl_i64_i32(c.u.s32.a, t);
+    tcg_gen_extrl_i64_i32(c.u.s32.b, regs[r3 | 1]);
+    store_reg32_i64(r1, t);
+    tcg_temp_free_i64(t);
+
+    return help_branch(s, &c, is_imm, imm, o->in2);
+}
+
+static DisasJumpType op_bx64(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    int r3 = get_field(s, r3);
+    bool is_imm = have_field(s, i2);
+    int imm = is_imm ? get_field(s, i2) : 0;
+    DisasCompare c;
+
+    c.cond = (s->insn->data ? TCG_COND_LE : TCG_COND_GT);
+    c.is_64 = true;
+
+    if (r1 == (r3 | 1)) {
+        c.u.s64.b = load_reg(r3 | 1);
+        c.g2 = false;
+    } else {
+        c.u.s64.b = regs[r3 | 1];
+        c.g2 = true;
+    }
+
+    tcg_gen_add_i64(regs[r1], regs[r1], regs[r3]);
+    c.u.s64.a = regs[r1];
+    c.g1 = true;
+
+    return help_branch(s, &c, is_imm, imm, o->in2);
+}
+
+static DisasJumpType op_cj(DisasContext *s, DisasOps *o)
+{
+    int imm, m3 = get_field(s, m3);
+    bool is_imm;
+    DisasCompare c;
+
+    c.cond = ltgt_cond[m3];
+    if (s->insn->data) {
+        c.cond = tcg_unsigned_cond(c.cond);
+    }
+    c.is_64 = c.g1 = c.g2 = true;
+    c.u.s64.a = o->in1;
+    c.u.s64.b = o->in2;
+
+    is_imm = have_field(s, i4);
+    if (is_imm) {
+        imm = get_field(s, i4);
+    } else {
+        imm = 0;
+        o->out = get_address(s, 0, get_field(s, b4),
+                             get_field(s, d4));
+    }
+
+    return help_branch(s, &c, is_imm, imm, o->out);
+}
+
+static DisasJumpType op_ceb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_ceb(cc_op, cpu_env, o->in1, o->in2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_cdb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_cdb(cc_op, cpu_env, o->in1, o->in2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_cxb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_cxb(cc_op, cpu_env, o->out, o->out2, o->in1, o->in2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static TCGv_i32 fpinst_extract_m34(DisasContext *s, bool m3_with_fpe,
+                                   bool m4_with_fpe)
+{
+    const bool fpe = s390_has_feat(S390_FEAT_FLOATING_POINT_EXT);
+    uint8_t m3 = get_field(s, m3);
+    uint8_t m4 = get_field(s, m4);
+
+    /* m3 field was introduced with FPE */
+    if (!fpe && m3_with_fpe) {
+        m3 = 0;
+    }
+    /* m4 field was introduced with FPE */
+    if (!fpe && m4_with_fpe) {
+        m4 = 0;
+    }
+
+    /* Check for valid rounding modes. Mode 3 was introduced later. */
+    if (m3 == 2 || m3 > 7 || (!fpe && m3 == 3)) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return NULL;
+    }
+
+    return tcg_const_i32(deposit32(m3, 4, 4, m4));
+}
+
+static DisasJumpType op_cfeb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m34 = fpinst_extract_m34(s, false, true);
+
+    if (!m34) {
+        return DISAS_NORETURN;
+    }
+    gen_helper_cfeb(o->out, cpu_env, o->in2, m34);
+    tcg_temp_free_i32(m34);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_cfdb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m34 = fpinst_extract_m34(s, false, true);
+
+    if (!m34) {
+        return DISAS_NORETURN;
+    }
+    gen_helper_cfdb(o->out, cpu_env, o->in2, m34);
+    tcg_temp_free_i32(m34);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_cfxb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m34 = fpinst_extract_m34(s, false, true);
+
+    if (!m34) {
+        return DISAS_NORETURN;
+    }
+    gen_helper_cfxb(o->out, cpu_env, o->in1, o->in2, m34);
+    tcg_temp_free_i32(m34);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_cgeb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m34 = fpinst_extract_m34(s, false, true);
+
+    if (!m34) {
+        return DISAS_NORETURN;
+    }
+    gen_helper_cgeb(o->out, cpu_env, o->in2, m34);
+    tcg_temp_free_i32(m34);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_cgdb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m34 = fpinst_extract_m34(s, false, true);
+
+    if (!m34) {
+        return DISAS_NORETURN;
+    }
+    gen_helper_cgdb(o->out, cpu_env, o->in2, m34);
+    tcg_temp_free_i32(m34);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_cgxb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m34 = fpinst_extract_m34(s, false, true);
+
+    if (!m34) {
+        return DISAS_NORETURN;
+    }
+    gen_helper_cgxb(o->out, cpu_env, o->in1, o->in2, m34);
+    tcg_temp_free_i32(m34);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_clfeb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m34 = fpinst_extract_m34(s, false, false);
+
+    if (!m34) {
+        return DISAS_NORETURN;
+    }
+    gen_helper_clfeb(o->out, cpu_env, o->in2, m34);
+    tcg_temp_free_i32(m34);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_clfdb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m34 = fpinst_extract_m34(s, false, false);
+
+    if (!m34) {
+        return DISAS_NORETURN;
+    }
+    gen_helper_clfdb(o->out, cpu_env, o->in2, m34);
+    tcg_temp_free_i32(m34);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_clfxb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m34 = fpinst_extract_m34(s, false, false);
+
+    if (!m34) {
+        return DISAS_NORETURN;
+    }
+    gen_helper_clfxb(o->out, cpu_env, o->in1, o->in2, m34);
+    tcg_temp_free_i32(m34);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_clgeb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m34 = fpinst_extract_m34(s, false, false);
+
+    if (!m34) {
+        return DISAS_NORETURN;
+    }
+    gen_helper_clgeb(o->out, cpu_env, o->in2, m34);
+    tcg_temp_free_i32(m34);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_clgdb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m34 = fpinst_extract_m34(s, false, false);
+
+    if (!m34) {
+        return DISAS_NORETURN;
+    }
+    gen_helper_clgdb(o->out, cpu_env, o->in2, m34);
+    tcg_temp_free_i32(m34);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_clgxb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m34 = fpinst_extract_m34(s, false, false);
+
+    if (!m34) {
+        return DISAS_NORETURN;
+    }
+    gen_helper_clgxb(o->out, cpu_env, o->in1, o->in2, m34);
+    tcg_temp_free_i32(m34);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_cegb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m34 = fpinst_extract_m34(s, true, true);
+
+    if (!m34) {
+        return DISAS_NORETURN;
+    }
+    gen_helper_cegb(o->out, cpu_env, o->in2, m34);
+    tcg_temp_free_i32(m34);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_cdgb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m34 = fpinst_extract_m34(s, true, true);
+
+    if (!m34) {
+        return DISAS_NORETURN;
+    }
+    gen_helper_cdgb(o->out, cpu_env, o->in2, m34);
+    tcg_temp_free_i32(m34);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_cxgb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m34 = fpinst_extract_m34(s, true, true);
+
+    if (!m34) {
+        return DISAS_NORETURN;
+    }
+    gen_helper_cxgb(o->out, cpu_env, o->in2, m34);
+    tcg_temp_free_i32(m34);
+    return_low128(o->out2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_celgb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m34 = fpinst_extract_m34(s, false, false);
+
+    if (!m34) {
+        return DISAS_NORETURN;
+    }
+    gen_helper_celgb(o->out, cpu_env, o->in2, m34);
+    tcg_temp_free_i32(m34);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_cdlgb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m34 = fpinst_extract_m34(s, false, false);
+
+    if (!m34) {
+        return DISAS_NORETURN;
+    }
+    gen_helper_cdlgb(o->out, cpu_env, o->in2, m34);
+    tcg_temp_free_i32(m34);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_cxlgb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m34 = fpinst_extract_m34(s, false, false);
+
+    if (!m34) {
+        return DISAS_NORETURN;
+    }
+    gen_helper_cxlgb(o->out, cpu_env, o->in2, m34);
+    tcg_temp_free_i32(m34);
+    return_low128(o->out2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_cksm(DisasContext *s, DisasOps *o)
+{
+    int r2 = get_field(s, r2);
+    TCGv_i64 len = tcg_temp_new_i64();
+
+    gen_helper_cksm(len, cpu_env, o->in1, o->in2, regs[r2 + 1]);
+    set_cc_static(s);
+    return_low128(o->out);
+
+    tcg_gen_add_i64(regs[r2], regs[r2], len);
+    tcg_gen_sub_i64(regs[r2 + 1], regs[r2 + 1], len);
+    tcg_temp_free_i64(len);
+
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_clc(DisasContext *s, DisasOps *o)
+{
+    int l = get_field(s, l1);
+    TCGv_i32 vl;
+
+    switch (l + 1) {
+    case 1:
+        tcg_gen_qemu_ld8u(cc_src, o->addr1, get_mem_index(s));
+        tcg_gen_qemu_ld8u(cc_dst, o->in2, get_mem_index(s));
+        break;
+    case 2:
+        tcg_gen_qemu_ld16u(cc_src, o->addr1, get_mem_index(s));
+        tcg_gen_qemu_ld16u(cc_dst, o->in2, get_mem_index(s));
+        break;
+    case 4:
+        tcg_gen_qemu_ld32u(cc_src, o->addr1, get_mem_index(s));
+        tcg_gen_qemu_ld32u(cc_dst, o->in2, get_mem_index(s));
+        break;
+    case 8:
+        tcg_gen_qemu_ld64(cc_src, o->addr1, get_mem_index(s));
+        tcg_gen_qemu_ld64(cc_dst, o->in2, get_mem_index(s));
+        break;
+    default:
+        vl = tcg_const_i32(l);
+        gen_helper_clc(cc_op, cpu_env, vl, o->addr1, o->in2);
+        tcg_temp_free_i32(vl);
+        set_cc_static(s);
+        return DISAS_NEXT;
+    }
+    gen_op_update2_cc_i64(s, CC_OP_LTUGTU_64, cc_src, cc_dst);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_clcl(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    int r2 = get_field(s, r2);
+    TCGv_i32 t1, t2;
+
+    /* r1 and r2 must be even.  */
+    if (r1 & 1 || r2 & 1) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    t1 = tcg_const_i32(r1);
+    t2 = tcg_const_i32(r2);
+    gen_helper_clcl(cc_op, cpu_env, t1, t2);
+    tcg_temp_free_i32(t1);
+    tcg_temp_free_i32(t2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_clcle(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    int r3 = get_field(s, r3);
+    TCGv_i32 t1, t3;
+
+    /* r1 and r3 must be even.  */
+    if (r1 & 1 || r3 & 1) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    t1 = tcg_const_i32(r1);
+    t3 = tcg_const_i32(r3);
+    gen_helper_clcle(cc_op, cpu_env, t1, o->in2, t3);
+    tcg_temp_free_i32(t1);
+    tcg_temp_free_i32(t3);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_clclu(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    int r3 = get_field(s, r3);
+    TCGv_i32 t1, t3;
+
+    /* r1 and r3 must be even.  */
+    if (r1 & 1 || r3 & 1) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    t1 = tcg_const_i32(r1);
+    t3 = tcg_const_i32(r3);
+    gen_helper_clclu(cc_op, cpu_env, t1, o->in2, t3);
+    tcg_temp_free_i32(t1);
+    tcg_temp_free_i32(t3);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_clm(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m3 = tcg_const_i32(get_field(s, m3));
+    TCGv_i32 t1 = tcg_temp_new_i32();
+    tcg_gen_extrl_i64_i32(t1, o->in1);
+    gen_helper_clm(cc_op, cpu_env, t1, m3, o->in2);
+    set_cc_static(s);
+    tcg_temp_free_i32(t1);
+    tcg_temp_free_i32(m3);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_clst(DisasContext *s, DisasOps *o)
+{
+    gen_helper_clst(o->in1, cpu_env, regs[0], o->in1, o->in2);
+    set_cc_static(s);
+    return_low128(o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_cps(DisasContext *s, DisasOps *o)
+{
+    TCGv_i64 t = tcg_temp_new_i64();
+    tcg_gen_andi_i64(t, o->in1, 0x8000000000000000ull);
+    tcg_gen_andi_i64(o->out, o->in2, 0x7fffffffffffffffull);
+    tcg_gen_or_i64(o->out, o->out, t);
+    tcg_temp_free_i64(t);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_cs(DisasContext *s, DisasOps *o)
+{
+    int d2 = get_field(s, d2);
+    int b2 = get_field(s, b2);
+    TCGv_i64 addr, cc;
+
+    /* Note that in1 = R3 (new value) and
+       in2 = (zero-extended) R1 (expected value).  */
+
+    addr = get_address(s, 0, b2, d2);
+    tcg_gen_atomic_cmpxchg_i64(o->out, addr, o->in2, o->in1,
+                               get_mem_index(s), s->insn->data | MO_ALIGN);
+    tcg_temp_free_i64(addr);
+
+    /* Are the memory and expected values (un)equal?  Note that this setcond
+       produces the output CC value, thus the NE sense of the test.  */
+    cc = tcg_temp_new_i64();
+    tcg_gen_setcond_i64(TCG_COND_NE, cc, o->in2, o->out);
+    tcg_gen_extrl_i64_i32(cc_op, cc);
+    tcg_temp_free_i64(cc);
+    set_cc_static(s);
+
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_cdsg(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    int r3 = get_field(s, r3);
+    int d2 = get_field(s, d2);
+    int b2 = get_field(s, b2);
+    DisasJumpType ret = DISAS_NEXT;
+    TCGv_i64 addr;
+    TCGv_i32 t_r1, t_r3;
+
+    /* Note that R1:R1+1 = expected value and R3:R3+1 = new value.  */
+    addr = get_address(s, 0, b2, d2);
+    t_r1 = tcg_const_i32(r1);
+    t_r3 = tcg_const_i32(r3);
+    if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
+        gen_helper_cdsg(cpu_env, addr, t_r1, t_r3);
+    } else if (HAVE_CMPXCHG128) {
+        gen_helper_cdsg_parallel(cpu_env, addr, t_r1, t_r3);
+    } else {
+        gen_helper_exit_atomic(cpu_env);
+        ret = DISAS_NORETURN;
+    }
+    tcg_temp_free_i64(addr);
+    tcg_temp_free_i32(t_r1);
+    tcg_temp_free_i32(t_r3);
+
+    set_cc_static(s);
+    return ret;
+}
+
+static DisasJumpType op_csst(DisasContext *s, DisasOps *o)
+{
+    int r3 = get_field(s, r3);
+    TCGv_i32 t_r3 = tcg_const_i32(r3);
+
+    if (tb_cflags(s->base.tb) & CF_PARALLEL) {
+        gen_helper_csst_parallel(cc_op, cpu_env, t_r3, o->addr1, o->in2);
+    } else {
+        gen_helper_csst(cc_op, cpu_env, t_r3, o->addr1, o->in2);
+    }
+    tcg_temp_free_i32(t_r3);
+
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+#ifndef CONFIG_USER_ONLY
+static DisasJumpType op_csp(DisasContext *s, DisasOps *o)
+{
+    MemOp mop = s->insn->data;
+    TCGv_i64 addr, old, cc;
+    TCGLabel *lab = gen_new_label();
+
+    /* Note that in1 = R1 (zero-extended expected value),
+       out = R1 (original reg), out2 = R1+1 (new value).  */
+
+    addr = tcg_temp_new_i64();
+    old = tcg_temp_new_i64();
+    tcg_gen_andi_i64(addr, o->in2, -1ULL << (mop & MO_SIZE));
+    tcg_gen_atomic_cmpxchg_i64(old, addr, o->in1, o->out2,
+                               get_mem_index(s), mop | MO_ALIGN);
+    tcg_temp_free_i64(addr);
+
+    /* Are the memory and expected values (un)equal?  */
+    cc = tcg_temp_new_i64();
+    tcg_gen_setcond_i64(TCG_COND_NE, cc, o->in1, old);
+    tcg_gen_extrl_i64_i32(cc_op, cc);
+
+    /* Write back the output now, so that it happens before the
+       following branch, so that we don't need local temps.  */
+    if ((mop & MO_SIZE) == MO_32) {
+        tcg_gen_deposit_i64(o->out, o->out, old, 0, 32);
+    } else {
+        tcg_gen_mov_i64(o->out, old);
+    }
+    tcg_temp_free_i64(old);
+
+    /* If the comparison was equal, and the LSB of R2 was set,
+       then we need to flush the TLB (for all cpus).  */
+    tcg_gen_xori_i64(cc, cc, 1);
+    tcg_gen_and_i64(cc, cc, o->in2);
+    tcg_gen_brcondi_i64(TCG_COND_EQ, cc, 0, lab);
+    tcg_temp_free_i64(cc);
+
+    gen_helper_purge(cpu_env);
+    gen_set_label(lab);
+
+    return DISAS_NEXT;
+}
+#endif
+
+static DisasJumpType op_cvd(DisasContext *s, DisasOps *o)
+{
+    TCGv_i64 t1 = tcg_temp_new_i64();
+    TCGv_i32 t2 = tcg_temp_new_i32();
+    tcg_gen_extrl_i64_i32(t2, o->in1);
+    gen_helper_cvd(t1, t2);
+    tcg_temp_free_i32(t2);
+    tcg_gen_qemu_st64(t1, o->in2, get_mem_index(s));
+    tcg_temp_free_i64(t1);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_ct(DisasContext *s, DisasOps *o)
+{
+    int m3 = get_field(s, m3);
+    TCGLabel *lab = gen_new_label();
+    TCGCond c;
+
+    c = tcg_invert_cond(ltgt_cond[m3]);
+    if (s->insn->data) {
+        c = tcg_unsigned_cond(c);
+    }
+    tcg_gen_brcond_i64(c, o->in1, o->in2, lab);
+
+    /* Trap.  */
+    gen_trap(s);
+
+    gen_set_label(lab);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_cuXX(DisasContext *s, DisasOps *o)
+{
+    int m3 = get_field(s, m3);
+    int r1 = get_field(s, r1);
+    int r2 = get_field(s, r2);
+    TCGv_i32 tr1, tr2, chk;
+
+    /* R1 and R2 must both be even.  */
+    if ((r1 | r2) & 1) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+    if (!s390_has_feat(S390_FEAT_ETF3_ENH)) {
+        m3 = 0;
+    }
+
+    tr1 = tcg_const_i32(r1);
+    tr2 = tcg_const_i32(r2);
+    chk = tcg_const_i32(m3);
+
+    switch (s->insn->data) {
+    case 12:
+        gen_helper_cu12(cc_op, cpu_env, tr1, tr2, chk);
+        break;
+    case 14:
+        gen_helper_cu14(cc_op, cpu_env, tr1, tr2, chk);
+        break;
+    case 21:
+        gen_helper_cu21(cc_op, cpu_env, tr1, tr2, chk);
+        break;
+    case 24:
+        gen_helper_cu24(cc_op, cpu_env, tr1, tr2, chk);
+        break;
+    case 41:
+        gen_helper_cu41(cc_op, cpu_env, tr1, tr2, chk);
+        break;
+    case 42:
+        gen_helper_cu42(cc_op, cpu_env, tr1, tr2, chk);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    tcg_temp_free_i32(tr1);
+    tcg_temp_free_i32(tr2);
+    tcg_temp_free_i32(chk);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+#ifndef CONFIG_USER_ONLY
+static DisasJumpType op_diag(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
+    TCGv_i32 r3 = tcg_const_i32(get_field(s, r3));
+    TCGv_i32 func_code = tcg_const_i32(get_field(s, i2));
+
+    gen_helper_diag(cpu_env, r1, r3, func_code);
+
+    tcg_temp_free_i32(func_code);
+    tcg_temp_free_i32(r3);
+    tcg_temp_free_i32(r1);
+    return DISAS_NEXT;
+}
+#endif
+
+static DisasJumpType op_divs32(DisasContext *s, DisasOps *o)
+{
+    gen_helper_divs32(o->out2, cpu_env, o->in1, o->in2);
+    return_low128(o->out);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_divu32(DisasContext *s, DisasOps *o)
+{
+    gen_helper_divu32(o->out2, cpu_env, o->in1, o->in2);
+    return_low128(o->out);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_divs64(DisasContext *s, DisasOps *o)
+{
+    gen_helper_divs64(o->out2, cpu_env, o->in1, o->in2);
+    return_low128(o->out);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_divu64(DisasContext *s, DisasOps *o)
+{
+    gen_helper_divu64(o->out2, cpu_env, o->out, o->out2, o->in2);
+    return_low128(o->out);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_deb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_deb(o->out, cpu_env, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_ddb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_ddb(o->out, cpu_env, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_dxb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_dxb(o->out, cpu_env, o->out, o->out2, o->in1, o->in2);
+    return_low128(o->out2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_ear(DisasContext *s, DisasOps *o)
+{
+    int r2 = get_field(s, r2);
+    tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, aregs[r2]));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_ecag(DisasContext *s, DisasOps *o)
+{
+    /* No cache information provided.  */
+    tcg_gen_movi_i64(o->out, -1);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_efpc(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, fpc));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_epsw(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    int r2 = get_field(s, r2);
+    TCGv_i64 t = tcg_temp_new_i64();
+
+    /* Note the "subsequently" in the PoO, which implies a defined result
+       if r1 == r2.  Thus we cannot defer these writes to an output hook.  */
+    tcg_gen_shri_i64(t, psw_mask, 32);
+    store_reg32_i64(r1, t);
+    if (r2 != 0) {
+        store_reg32_i64(r2, psw_mask);
+    }
+
+    tcg_temp_free_i64(t);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_ex(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    TCGv_i32 ilen;
+    TCGv_i64 v1;
+
+    /* Nested EXECUTE is not allowed.  */
+    if (unlikely(s->ex_value)) {
+        gen_program_exception(s, PGM_EXECUTE);
+        return DISAS_NORETURN;
+    }
+
+    update_psw_addr(s);
+    update_cc_op(s);
+
+    if (r1 == 0) {
+        v1 = tcg_const_i64(0);
+    } else {
+        v1 = regs[r1];
+    }
+
+    ilen = tcg_const_i32(s->ilen);
+    gen_helper_ex(cpu_env, ilen, v1, o->in2);
+    tcg_temp_free_i32(ilen);
+
+    if (r1 == 0) {
+        tcg_temp_free_i64(v1);
+    }
+
+    return DISAS_PC_CC_UPDATED;
+}
+
+static DisasJumpType op_fieb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m34 = fpinst_extract_m34(s, false, true);
+
+    if (!m34) {
+        return DISAS_NORETURN;
+    }
+    gen_helper_fieb(o->out, cpu_env, o->in2, m34);
+    tcg_temp_free_i32(m34);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_fidb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m34 = fpinst_extract_m34(s, false, true);
+
+    if (!m34) {
+        return DISAS_NORETURN;
+    }
+    gen_helper_fidb(o->out, cpu_env, o->in2, m34);
+    tcg_temp_free_i32(m34);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_fixb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m34 = fpinst_extract_m34(s, false, true);
+
+    if (!m34) {
+        return DISAS_NORETURN;
+    }
+    gen_helper_fixb(o->out, cpu_env, o->in1, o->in2, m34);
+    return_low128(o->out2);
+    tcg_temp_free_i32(m34);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_flogr(DisasContext *s, DisasOps *o)
+{
+    /* We'll use the original input for cc computation, since we get to
+       compare that against 0, which ought to be better than comparing
+       the real output against 64.  It also lets cc_dst be a convenient
+       temporary during our computation.  */
+    gen_op_update1_cc_i64(s, CC_OP_FLOGR, o->in2);
+
+    /* R1 = IN ? CLZ(IN) : 64.  */
+    tcg_gen_clzi_i64(o->out, o->in2, 64);
+
+    /* R1+1 = IN & ~(found bit).  Note that we may attempt to shift this
+       value by 64, which is undefined.  But since the shift is 64 iff the
+       input is zero, we still get the correct result after and'ing.  */
+    tcg_gen_movi_i64(o->out2, 0x8000000000000000ull);
+    tcg_gen_shr_i64(o->out2, o->out2, o->out);
+    tcg_gen_andc_i64(o->out2, cc_dst, o->out2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_icm(DisasContext *s, DisasOps *o)
+{
+    int m3 = get_field(s, m3);
+    int pos, len, base = s->insn->data;
+    TCGv_i64 tmp = tcg_temp_new_i64();
+    uint64_t ccm;
+
+    switch (m3) {
+    case 0xf:
+        /* Effectively a 32-bit load.  */
+        tcg_gen_qemu_ld32u(tmp, o->in2, get_mem_index(s));
+        len = 32;
+        goto one_insert;
+
+    case 0xc:
+    case 0x6:
+    case 0x3:
+        /* Effectively a 16-bit load.  */
+        tcg_gen_qemu_ld16u(tmp, o->in2, get_mem_index(s));
+        len = 16;
+        goto one_insert;
+
+    case 0x8:
+    case 0x4:
+    case 0x2:
+    case 0x1:
+        /* Effectively an 8-bit load.  */
+        tcg_gen_qemu_ld8u(tmp, o->in2, get_mem_index(s));
+        len = 8;
+        goto one_insert;
+
+    one_insert:
+        pos = base + ctz32(m3) * 8;
+        tcg_gen_deposit_i64(o->out, o->out, tmp, pos, len);
+        ccm = ((1ull << len) - 1) << pos;
+        break;
+
+    default:
+        /* This is going to be a sequence of loads and inserts.  */
+        pos = base + 32 - 8;
+        ccm = 0;
+        while (m3) {
+            if (m3 & 0x8) {
+                tcg_gen_qemu_ld8u(tmp, o->in2, get_mem_index(s));
+                tcg_gen_addi_i64(o->in2, o->in2, 1);
+                tcg_gen_deposit_i64(o->out, o->out, tmp, pos, 8);
+                ccm |= 0xff << pos;
+            }
+            m3 = (m3 << 1) & 0xf;
+            pos -= 8;
+        }
+        break;
+    }
+
+    tcg_gen_movi_i64(tmp, ccm);
+    gen_op_update2_cc_i64(s, CC_OP_ICM, tmp, o->out);
+    tcg_temp_free_i64(tmp);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_insi(DisasContext *s, DisasOps *o)
+{
+    int shift = s->insn->data & 0xff;
+    int size = s->insn->data >> 8;
+    tcg_gen_deposit_i64(o->out, o->in1, o->in2, shift, size);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_ipm(DisasContext *s, DisasOps *o)
+{
+    TCGv_i64 t1, t2;
+
+    gen_op_calc_cc(s);
+    t1 = tcg_temp_new_i64();
+    tcg_gen_extract_i64(t1, psw_mask, 40, 4);
+    t2 = tcg_temp_new_i64();
+    tcg_gen_extu_i32_i64(t2, cc_op);
+    tcg_gen_deposit_i64(t1, t1, t2, 4, 60);
+    tcg_gen_deposit_i64(o->out, o->out, t1, 24, 8);
+    tcg_temp_free_i64(t1);
+    tcg_temp_free_i64(t2);
+    return DISAS_NEXT;
+}
+
+#ifndef CONFIG_USER_ONLY
+static DisasJumpType op_idte(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m4;
+
+    if (s390_has_feat(S390_FEAT_LOCAL_TLB_CLEARING)) {
+        m4 = tcg_const_i32(get_field(s, m4));
+    } else {
+        m4 = tcg_const_i32(0);
+    }
+    gen_helper_idte(cpu_env, o->in1, o->in2, m4);
+    tcg_temp_free_i32(m4);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_ipte(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m4;
+
+    if (s390_has_feat(S390_FEAT_LOCAL_TLB_CLEARING)) {
+        m4 = tcg_const_i32(get_field(s, m4));
+    } else {
+        m4 = tcg_const_i32(0);
+    }
+    gen_helper_ipte(cpu_env, o->in1, o->in2, m4);
+    tcg_temp_free_i32(m4);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_iske(DisasContext *s, DisasOps *o)
+{
+    gen_helper_iske(o->out, cpu_env, o->in2);
+    return DISAS_NEXT;
+}
+#endif
+
+static DisasJumpType op_msa(DisasContext *s, DisasOps *o)
+{
+    int r1 = have_field(s, r1) ? get_field(s, r1) : 0;
+    int r2 = have_field(s, r2) ? get_field(s, r2) : 0;
+    int r3 = have_field(s, r3) ? get_field(s, r3) : 0;
+    TCGv_i32 t_r1, t_r2, t_r3, type;
+
+    switch (s->insn->data) {
+    case S390_FEAT_TYPE_KMA:
+        if (r3 == r1 || r3 == r2) {
+            gen_program_exception(s, PGM_SPECIFICATION);
+            return DISAS_NORETURN;
+        }
+        /* FALL THROUGH */
+    case S390_FEAT_TYPE_KMCTR:
+        if (r3 & 1 || !r3) {
+            gen_program_exception(s, PGM_SPECIFICATION);
+            return DISAS_NORETURN;
+        }
+        /* FALL THROUGH */
+    case S390_FEAT_TYPE_PPNO:
+    case S390_FEAT_TYPE_KMF:
+    case S390_FEAT_TYPE_KMC:
+    case S390_FEAT_TYPE_KMO:
+    case S390_FEAT_TYPE_KM:
+        if (r1 & 1 || !r1) {
+            gen_program_exception(s, PGM_SPECIFICATION);
+            return DISAS_NORETURN;
+        }
+        /* FALL THROUGH */
+    case S390_FEAT_TYPE_KMAC:
+    case S390_FEAT_TYPE_KIMD:
+    case S390_FEAT_TYPE_KLMD:
+        if (r2 & 1 || !r2) {
+            gen_program_exception(s, PGM_SPECIFICATION);
+            return DISAS_NORETURN;
+        }
+        /* FALL THROUGH */
+    case S390_FEAT_TYPE_PCKMO:
+    case S390_FEAT_TYPE_PCC:
+        break;
+    default:
+        g_assert_not_reached();
+    };
+
+    t_r1 = tcg_const_i32(r1);
+    t_r2 = tcg_const_i32(r2);
+    t_r3 = tcg_const_i32(r3);
+    type = tcg_const_i32(s->insn->data);
+    gen_helper_msa(cc_op, cpu_env, t_r1, t_r2, t_r3, type);
+    set_cc_static(s);
+    tcg_temp_free_i32(t_r1);
+    tcg_temp_free_i32(t_r2);
+    tcg_temp_free_i32(t_r3);
+    tcg_temp_free_i32(type);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_keb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_keb(cc_op, cpu_env, o->in1, o->in2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_kdb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_kdb(cc_op, cpu_env, o->in1, o->in2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_kxb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_kxb(cc_op, cpu_env, o->out, o->out2, o->in1, o->in2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_laa(DisasContext *s, DisasOps *o)
+{
+    /* The real output is indeed the original value in memory;
+       recompute the addition for the computation of CC.  */
+    tcg_gen_atomic_fetch_add_i64(o->in2, o->in2, o->in1, get_mem_index(s),
+                                 s->insn->data | MO_ALIGN);
+    /* However, we need to recompute the addition for setting CC.  */
+    tcg_gen_add_i64(o->out, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_lan(DisasContext *s, DisasOps *o)
+{
+    /* The real output is indeed the original value in memory;
+       recompute the addition for the computation of CC.  */
+    tcg_gen_atomic_fetch_and_i64(o->in2, o->in2, o->in1, get_mem_index(s),
+                                 s->insn->data | MO_ALIGN);
+    /* However, we need to recompute the operation for setting CC.  */
+    tcg_gen_and_i64(o->out, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_lao(DisasContext *s, DisasOps *o)
+{
+    /* The real output is indeed the original value in memory;
+       recompute the addition for the computation of CC.  */
+    tcg_gen_atomic_fetch_or_i64(o->in2, o->in2, o->in1, get_mem_index(s),
+                                s->insn->data | MO_ALIGN);
+    /* However, we need to recompute the operation for setting CC.  */
+    tcg_gen_or_i64(o->out, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_lax(DisasContext *s, DisasOps *o)
+{
+    /* The real output is indeed the original value in memory;
+       recompute the addition for the computation of CC.  */
+    tcg_gen_atomic_fetch_xor_i64(o->in2, o->in2, o->in1, get_mem_index(s),
+                                 s->insn->data | MO_ALIGN);
+    /* However, we need to recompute the operation for setting CC.  */
+    tcg_gen_xor_i64(o->out, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_ldeb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_ldeb(o->out, cpu_env, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_ledb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m34 = fpinst_extract_m34(s, true, true);
+
+    if (!m34) {
+        return DISAS_NORETURN;
+    }
+    gen_helper_ledb(o->out, cpu_env, o->in2, m34);
+    tcg_temp_free_i32(m34);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_ldxb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m34 = fpinst_extract_m34(s, true, true);
+
+    if (!m34) {
+        return DISAS_NORETURN;
+    }
+    gen_helper_ldxb(o->out, cpu_env, o->in1, o->in2, m34);
+    tcg_temp_free_i32(m34);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_lexb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 m34 = fpinst_extract_m34(s, true, true);
+
+    if (!m34) {
+        return DISAS_NORETURN;
+    }
+    gen_helper_lexb(o->out, cpu_env, o->in1, o->in2, m34);
+    tcg_temp_free_i32(m34);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_lxdb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_lxdb(o->out, cpu_env, o->in2);
+    return_low128(o->out2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_lxeb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_lxeb(o->out, cpu_env, o->in2);
+    return_low128(o->out2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_lde(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_shli_i64(o->out, o->in2, 32);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_llgt(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_andi_i64(o->out, o->in2, 0x7fffffff);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_ld8s(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_qemu_ld8s(o->out, o->in2, get_mem_index(s));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_ld8u(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_qemu_ld8u(o->out, o->in2, get_mem_index(s));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_ld16s(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_qemu_ld16s(o->out, o->in2, get_mem_index(s));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_ld16u(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_qemu_ld16u(o->out, o->in2, get_mem_index(s));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_ld32s(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_qemu_ld32s(o->out, o->in2, get_mem_index(s));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_ld32u(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_qemu_ld32u(o->out, o->in2, get_mem_index(s));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_ld64(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_qemu_ld64(o->out, o->in2, get_mem_index(s));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_lat(DisasContext *s, DisasOps *o)
+{
+    TCGLabel *lab = gen_new_label();
+    store_reg32_i64(get_field(s, r1), o->in2);
+    /* The value is stored even in case of trap. */
+    tcg_gen_brcondi_i64(TCG_COND_NE, o->in2, 0, lab);
+    gen_trap(s);
+    gen_set_label(lab);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_lgat(DisasContext *s, DisasOps *o)
+{
+    TCGLabel *lab = gen_new_label();
+    tcg_gen_qemu_ld64(o->out, o->in2, get_mem_index(s));
+    /* The value is stored even in case of trap. */
+    tcg_gen_brcondi_i64(TCG_COND_NE, o->out, 0, lab);
+    gen_trap(s);
+    gen_set_label(lab);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_lfhat(DisasContext *s, DisasOps *o)
+{
+    TCGLabel *lab = gen_new_label();
+    store_reg32h_i64(get_field(s, r1), o->in2);
+    /* The value is stored even in case of trap. */
+    tcg_gen_brcondi_i64(TCG_COND_NE, o->in2, 0, lab);
+    gen_trap(s);
+    gen_set_label(lab);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_llgfat(DisasContext *s, DisasOps *o)
+{
+    TCGLabel *lab = gen_new_label();
+    tcg_gen_qemu_ld32u(o->out, o->in2, get_mem_index(s));
+    /* The value is stored even in case of trap. */
+    tcg_gen_brcondi_i64(TCG_COND_NE, o->out, 0, lab);
+    gen_trap(s);
+    gen_set_label(lab);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_llgtat(DisasContext *s, DisasOps *o)
+{
+    TCGLabel *lab = gen_new_label();
+    tcg_gen_andi_i64(o->out, o->in2, 0x7fffffff);
+    /* The value is stored even in case of trap. */
+    tcg_gen_brcondi_i64(TCG_COND_NE, o->out, 0, lab);
+    gen_trap(s);
+    gen_set_label(lab);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_loc(DisasContext *s, DisasOps *o)
+{
+    DisasCompare c;
+
+    disas_jcc(s, &c, get_field(s, m3));
+
+    if (c.is_64) {
+        tcg_gen_movcond_i64(c.cond, o->out, c.u.s64.a, c.u.s64.b,
+                            o->in2, o->in1);
+        free_compare(&c);
+    } else {
+        TCGv_i32 t32 = tcg_temp_new_i32();
+        TCGv_i64 t, z;
+
+        tcg_gen_setcond_i32(c.cond, t32, c.u.s32.a, c.u.s32.b);
+        free_compare(&c);
+
+        t = tcg_temp_new_i64();
+        tcg_gen_extu_i32_i64(t, t32);
+        tcg_temp_free_i32(t32);
+
+        z = tcg_const_i64(0);
+        tcg_gen_movcond_i64(TCG_COND_NE, o->out, t, z, o->in2, o->in1);
+        tcg_temp_free_i64(t);
+        tcg_temp_free_i64(z);
+    }
+
+    return DISAS_NEXT;
+}
+
+#ifndef CONFIG_USER_ONLY
+static DisasJumpType op_lctl(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
+    TCGv_i32 r3 = tcg_const_i32(get_field(s, r3));
+    gen_helper_lctl(cpu_env, r1, o->in2, r3);
+    tcg_temp_free_i32(r1);
+    tcg_temp_free_i32(r3);
+    /* Exit to main loop to reevaluate s390_cpu_exec_interrupt.  */
+    return DISAS_PC_STALE_NOCHAIN;
+}
+
+static DisasJumpType op_lctlg(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
+    TCGv_i32 r3 = tcg_const_i32(get_field(s, r3));
+    gen_helper_lctlg(cpu_env, r1, o->in2, r3);
+    tcg_temp_free_i32(r1);
+    tcg_temp_free_i32(r3);
+    /* Exit to main loop to reevaluate s390_cpu_exec_interrupt.  */
+    return DISAS_PC_STALE_NOCHAIN;
+}
+
+static DisasJumpType op_lra(DisasContext *s, DisasOps *o)
+{
+    gen_helper_lra(o->out, cpu_env, o->in2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_lpp(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_st_i64(o->in2, cpu_env, offsetof(CPUS390XState, pp));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_lpsw(DisasContext *s, DisasOps *o)
+{
+    TCGv_i64 t1, t2;
+
+    per_breaking_event(s);
+
+    t1 = tcg_temp_new_i64();
+    t2 = tcg_temp_new_i64();
+    tcg_gen_qemu_ld_i64(t1, o->in2, get_mem_index(s),
+                        MO_TEUL | MO_ALIGN_8);
+    tcg_gen_addi_i64(o->in2, o->in2, 4);
+    tcg_gen_qemu_ld32u(t2, o->in2, get_mem_index(s));
+    /* Convert the 32-bit PSW_MASK into the 64-bit PSW_MASK.  */
+    tcg_gen_shli_i64(t1, t1, 32);
+    gen_helper_load_psw(cpu_env, t1, t2);
+    tcg_temp_free_i64(t1);
+    tcg_temp_free_i64(t2);
+    return DISAS_NORETURN;
+}
+
+static DisasJumpType op_lpswe(DisasContext *s, DisasOps *o)
+{
+    TCGv_i64 t1, t2;
+
+    per_breaking_event(s);
+
+    t1 = tcg_temp_new_i64();
+    t2 = tcg_temp_new_i64();
+    tcg_gen_qemu_ld_i64(t1, o->in2, get_mem_index(s),
+                        MO_TEQ | MO_ALIGN_8);
+    tcg_gen_addi_i64(o->in2, o->in2, 8);
+    tcg_gen_qemu_ld64(t2, o->in2, get_mem_index(s));
+    gen_helper_load_psw(cpu_env, t1, t2);
+    tcg_temp_free_i64(t1);
+    tcg_temp_free_i64(t2);
+    return DISAS_NORETURN;
+}
+#endif
+
+static DisasJumpType op_lam(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
+    TCGv_i32 r3 = tcg_const_i32(get_field(s, r3));
+    gen_helper_lam(cpu_env, r1, o->in2, r3);
+    tcg_temp_free_i32(r1);
+    tcg_temp_free_i32(r3);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_lm32(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    int r3 = get_field(s, r3);
+    TCGv_i64 t1, t2;
+
+    /* Only one register to read. */
+    t1 = tcg_temp_new_i64();
+    if (unlikely(r1 == r3)) {
+        tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s));
+        store_reg32_i64(r1, t1);
+        tcg_temp_free(t1);
+        return DISAS_NEXT;
+    }
+
+    /* First load the values of the first and last registers to trigger
+       possible page faults. */
+    t2 = tcg_temp_new_i64();
+    tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s));
+    tcg_gen_addi_i64(t2, o->in2, 4 * ((r3 - r1) & 15));
+    tcg_gen_qemu_ld32u(t2, t2, get_mem_index(s));
+    store_reg32_i64(r1, t1);
+    store_reg32_i64(r3, t2);
+
+    /* Only two registers to read. */
+    if (((r1 + 1) & 15) == r3) {
+        tcg_temp_free(t2);
+        tcg_temp_free(t1);
+        return DISAS_NEXT;
+    }
+
+    /* Then load the remaining registers. Page fault can't occur. */
+    r3 = (r3 - 1) & 15;
+    tcg_gen_movi_i64(t2, 4);
+    while (r1 != r3) {
+        r1 = (r1 + 1) & 15;
+        tcg_gen_add_i64(o->in2, o->in2, t2);
+        tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s));
+        store_reg32_i64(r1, t1);
+    }
+    tcg_temp_free(t2);
+    tcg_temp_free(t1);
+
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_lmh(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    int r3 = get_field(s, r3);
+    TCGv_i64 t1, t2;
+
+    /* Only one register to read. */
+    t1 = tcg_temp_new_i64();
+    if (unlikely(r1 == r3)) {
+        tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s));
+        store_reg32h_i64(r1, t1);
+        tcg_temp_free(t1);
+        return DISAS_NEXT;
+    }
+
+    /* First load the values of the first and last registers to trigger
+       possible page faults. */
+    t2 = tcg_temp_new_i64();
+    tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s));
+    tcg_gen_addi_i64(t2, o->in2, 4 * ((r3 - r1) & 15));
+    tcg_gen_qemu_ld32u(t2, t2, get_mem_index(s));
+    store_reg32h_i64(r1, t1);
+    store_reg32h_i64(r3, t2);
+
+    /* Only two registers to read. */
+    if (((r1 + 1) & 15) == r3) {
+        tcg_temp_free(t2);
+        tcg_temp_free(t1);
+        return DISAS_NEXT;
+    }
+
+    /* Then load the remaining registers. Page fault can't occur. */
+    r3 = (r3 - 1) & 15;
+    tcg_gen_movi_i64(t2, 4);
+    while (r1 != r3) {
+        r1 = (r1 + 1) & 15;
+        tcg_gen_add_i64(o->in2, o->in2, t2);
+        tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s));
+        store_reg32h_i64(r1, t1);
+    }
+    tcg_temp_free(t2);
+    tcg_temp_free(t1);
+
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_lm64(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    int r3 = get_field(s, r3);
+    TCGv_i64 t1, t2;
+
+    /* Only one register to read. */
+    if (unlikely(r1 == r3)) {
+        tcg_gen_qemu_ld64(regs[r1], o->in2, get_mem_index(s));
+        return DISAS_NEXT;
+    }
+
+    /* First load the values of the first and last registers to trigger
+       possible page faults. */
+    t1 = tcg_temp_new_i64();
+    t2 = tcg_temp_new_i64();
+    tcg_gen_qemu_ld64(t1, o->in2, get_mem_index(s));
+    tcg_gen_addi_i64(t2, o->in2, 8 * ((r3 - r1) & 15));
+    tcg_gen_qemu_ld64(regs[r3], t2, get_mem_index(s));
+    tcg_gen_mov_i64(regs[r1], t1);
+    tcg_temp_free(t2);
+
+    /* Only two registers to read. */
+    if (((r1 + 1) & 15) == r3) {
+        tcg_temp_free(t1);
+        return DISAS_NEXT;
+    }
+
+    /* Then load the remaining registers. Page fault can't occur. */
+    r3 = (r3 - 1) & 15;
+    tcg_gen_movi_i64(t1, 8);
+    while (r1 != r3) {
+        r1 = (r1 + 1) & 15;
+        tcg_gen_add_i64(o->in2, o->in2, t1);
+        tcg_gen_qemu_ld64(regs[r1], o->in2, get_mem_index(s));
+    }
+    tcg_temp_free(t1);
+
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_lpd(DisasContext *s, DisasOps *o)
+{
+    TCGv_i64 a1, a2;
+    MemOp mop = s->insn->data;
+
+    /* In a parallel context, stop the world and single step.  */
+    if (tb_cflags(s->base.tb) & CF_PARALLEL) {
+        update_psw_addr(s);
+        update_cc_op(s);
+        gen_exception(EXCP_ATOMIC);
+        return DISAS_NORETURN;
+    }
+
+    /* In a serial context, perform the two loads ... */
+    a1 = get_address(s, 0, get_field(s, b1), get_field(s, d1));
+    a2 = get_address(s, 0, get_field(s, b2), get_field(s, d2));
+    tcg_gen_qemu_ld_i64(o->out, a1, get_mem_index(s), mop | MO_ALIGN);
+    tcg_gen_qemu_ld_i64(o->out2, a2, get_mem_index(s), mop | MO_ALIGN);
+    tcg_temp_free_i64(a1);
+    tcg_temp_free_i64(a2);
+
+    /* ... and indicate that we performed them while interlocked.  */
+    gen_op_movi_cc(s, 0);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_lpq(DisasContext *s, DisasOps *o)
+{
+    if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
+        gen_helper_lpq(o->out, cpu_env, o->in2);
+    } else if (HAVE_ATOMIC128) {
+        gen_helper_lpq_parallel(o->out, cpu_env, o->in2);
+    } else {
+        gen_helper_exit_atomic(cpu_env);
+        return DISAS_NORETURN;
+    }
+    return_low128(o->out2);
+    return DISAS_NEXT;
+}
+
+#ifndef CONFIG_USER_ONLY
+static DisasJumpType op_lura(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_qemu_ld_tl(o->out, o->in2, MMU_REAL_IDX, s->insn->data);
+    return DISAS_NEXT;
+}
+#endif
+
+static DisasJumpType op_lzrb(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_andi_i64(o->out, o->in2, -256);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_lcbb(DisasContext *s, DisasOps *o)
+{
+    const int64_t block_size = (1ull << (get_field(s, m3) + 6));
+
+    if (get_field(s, m3) > 6) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    tcg_gen_ori_i64(o->addr1, o->addr1, -block_size);
+    tcg_gen_neg_i64(o->addr1, o->addr1);
+    tcg_gen_movi_i64(o->out, 16);
+    tcg_gen_umin_i64(o->out, o->out, o->addr1);
+    gen_op_update1_cc_i64(s, CC_OP_LCBB, o->out);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_mc(DisasContext *s, DisasOps *o)
+{
+#if !defined(CONFIG_USER_ONLY)
+    TCGv_i32 i2;
+#endif
+    const uint16_t monitor_class = get_field(s, i2);
+
+    if (monitor_class & 0xff00) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+#if !defined(CONFIG_USER_ONLY)
+    i2 = tcg_const_i32(monitor_class);
+    gen_helper_monitor_call(cpu_env, o->addr1, i2);
+    tcg_temp_free_i32(i2);
+#endif
+    /* Defaults to a NOP. */
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_mov2(DisasContext *s, DisasOps *o)
+{
+    o->out = o->in2;
+    o->g_out = o->g_in2;
+    o->in2 = NULL;
+    o->g_in2 = false;
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_mov2e(DisasContext *s, DisasOps *o)
+{
+    int b2 = get_field(s, b2);
+    TCGv ar1 = tcg_temp_new_i64();
+
+    o->out = o->in2;
+    o->g_out = o->g_in2;
+    o->in2 = NULL;
+    o->g_in2 = false;
+
+    switch (s->base.tb->flags & FLAG_MASK_ASC) {
+    case PSW_ASC_PRIMARY >> FLAG_MASK_PSW_SHIFT:
+        tcg_gen_movi_i64(ar1, 0);
+        break;
+    case PSW_ASC_ACCREG >> FLAG_MASK_PSW_SHIFT:
+        tcg_gen_movi_i64(ar1, 1);
+        break;
+    case PSW_ASC_SECONDARY >> FLAG_MASK_PSW_SHIFT:
+        if (b2) {
+            tcg_gen_ld32u_i64(ar1, cpu_env, offsetof(CPUS390XState, aregs[b2]));
+        } else {
+            tcg_gen_movi_i64(ar1, 0);
+        }
+        break;
+    case PSW_ASC_HOME >> FLAG_MASK_PSW_SHIFT:
+        tcg_gen_movi_i64(ar1, 2);
+        break;
+    }
+
+    tcg_gen_st32_i64(ar1, cpu_env, offsetof(CPUS390XState, aregs[1]));
+    tcg_temp_free_i64(ar1);
+
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_movx(DisasContext *s, DisasOps *o)
+{
+    o->out = o->in1;
+    o->out2 = o->in2;
+    o->g_out = o->g_in1;
+    o->g_out2 = o->g_in2;
+    o->in1 = NULL;
+    o->in2 = NULL;
+    o->g_in1 = o->g_in2 = false;
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_mvc(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 l = tcg_const_i32(get_field(s, l1));
+    gen_helper_mvc(cpu_env, l, o->addr1, o->in2);
+    tcg_temp_free_i32(l);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_mvcin(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 l = tcg_const_i32(get_field(s, l1));
+    gen_helper_mvcin(cpu_env, l, o->addr1, o->in2);
+    tcg_temp_free_i32(l);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_mvcl(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    int r2 = get_field(s, r2);
+    TCGv_i32 t1, t2;
+
+    /* r1 and r2 must be even.  */
+    if (r1 & 1 || r2 & 1) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    t1 = tcg_const_i32(r1);
+    t2 = tcg_const_i32(r2);
+    gen_helper_mvcl(cc_op, cpu_env, t1, t2);
+    tcg_temp_free_i32(t1);
+    tcg_temp_free_i32(t2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_mvcle(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    int r3 = get_field(s, r3);
+    TCGv_i32 t1, t3;
+
+    /* r1 and r3 must be even.  */
+    if (r1 & 1 || r3 & 1) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    t1 = tcg_const_i32(r1);
+    t3 = tcg_const_i32(r3);
+    gen_helper_mvcle(cc_op, cpu_env, t1, o->in2, t3);
+    tcg_temp_free_i32(t1);
+    tcg_temp_free_i32(t3);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_mvclu(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    int r3 = get_field(s, r3);
+    TCGv_i32 t1, t3;
+
+    /* r1 and r3 must be even.  */
+    if (r1 & 1 || r3 & 1) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    t1 = tcg_const_i32(r1);
+    t3 = tcg_const_i32(r3);
+    gen_helper_mvclu(cc_op, cpu_env, t1, o->in2, t3);
+    tcg_temp_free_i32(t1);
+    tcg_temp_free_i32(t3);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_mvcos(DisasContext *s, DisasOps *o)
+{
+    int r3 = get_field(s, r3);
+    gen_helper_mvcos(cc_op, cpu_env, o->addr1, o->in2, regs[r3]);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+#ifndef CONFIG_USER_ONLY
+static DisasJumpType op_mvcp(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, l1);
+    gen_helper_mvcp(cc_op, cpu_env, regs[r1], o->addr1, o->in2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_mvcs(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, l1);
+    gen_helper_mvcs(cc_op, cpu_env, regs[r1], o->addr1, o->in2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+#endif
+
+static DisasJumpType op_mvn(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 l = tcg_const_i32(get_field(s, l1));
+    gen_helper_mvn(cpu_env, l, o->addr1, o->in2);
+    tcg_temp_free_i32(l);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_mvo(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 l = tcg_const_i32(get_field(s, l1));
+    gen_helper_mvo(cpu_env, l, o->addr1, o->in2);
+    tcg_temp_free_i32(l);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_mvpg(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 t1 = tcg_const_i32(get_field(s, r1));
+    TCGv_i32 t2 = tcg_const_i32(get_field(s, r2));
+
+    gen_helper_mvpg(cc_op, cpu_env, regs[0], t1, t2);
+    tcg_temp_free_i32(t1);
+    tcg_temp_free_i32(t2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_mvst(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 t1 = tcg_const_i32(get_field(s, r1));
+    TCGv_i32 t2 = tcg_const_i32(get_field(s, r2));
+
+    gen_helper_mvst(cc_op, cpu_env, t1, t2);
+    tcg_temp_free_i32(t1);
+    tcg_temp_free_i32(t2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_mvz(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 l = tcg_const_i32(get_field(s, l1));
+    gen_helper_mvz(cpu_env, l, o->addr1, o->in2);
+    tcg_temp_free_i32(l);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_mul(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_mul_i64(o->out, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_mul128(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_mulu2_i64(o->out2, o->out, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_muls128(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_muls2_i64(o->out2, o->out, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_meeb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_meeb(o->out, cpu_env, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_mdeb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_mdeb(o->out, cpu_env, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_mdb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_mdb(o->out, cpu_env, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_mxb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_mxb(o->out, cpu_env, o->out, o->out2, o->in1, o->in2);
+    return_low128(o->out2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_mxdb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_mxdb(o->out, cpu_env, o->out, o->out2, o->in2);
+    return_low128(o->out2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_maeb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i64 r3 = load_freg32_i64(get_field(s, r3));
+    gen_helper_maeb(o->out, cpu_env, o->in1, o->in2, r3);
+    tcg_temp_free_i64(r3);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_madb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i64 r3 = load_freg(get_field(s, r3));
+    gen_helper_madb(o->out, cpu_env, o->in1, o->in2, r3);
+    tcg_temp_free_i64(r3);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_mseb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i64 r3 = load_freg32_i64(get_field(s, r3));
+    gen_helper_mseb(o->out, cpu_env, o->in1, o->in2, r3);
+    tcg_temp_free_i64(r3);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_msdb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i64 r3 = load_freg(get_field(s, r3));
+    gen_helper_msdb(o->out, cpu_env, o->in1, o->in2, r3);
+    tcg_temp_free_i64(r3);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_nabs(DisasContext *s, DisasOps *o)
+{
+    TCGv_i64 z, n;
+    z = tcg_const_i64(0);
+    n = tcg_temp_new_i64();
+    tcg_gen_neg_i64(n, o->in2);
+    tcg_gen_movcond_i64(TCG_COND_GE, o->out, o->in2, z, n, o->in2);
+    tcg_temp_free_i64(n);
+    tcg_temp_free_i64(z);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_nabsf32(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_ori_i64(o->out, o->in2, 0x80000000ull);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_nabsf64(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_ori_i64(o->out, o->in2, 0x8000000000000000ull);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_nabsf128(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_ori_i64(o->out, o->in1, 0x8000000000000000ull);
+    tcg_gen_mov_i64(o->out2, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_nc(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 l = tcg_const_i32(get_field(s, l1));
+    gen_helper_nc(cc_op, cpu_env, l, o->addr1, o->in2);
+    tcg_temp_free_i32(l);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_neg(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_neg_i64(o->out, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_negf32(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_xori_i64(o->out, o->in2, 0x80000000ull);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_negf64(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_xori_i64(o->out, o->in2, 0x8000000000000000ull);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_negf128(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_xori_i64(o->out, o->in1, 0x8000000000000000ull);
+    tcg_gen_mov_i64(o->out2, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_oc(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 l = tcg_const_i32(get_field(s, l1));
+    gen_helper_oc(cc_op, cpu_env, l, o->addr1, o->in2);
+    tcg_temp_free_i32(l);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_or(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_or_i64(o->out, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_ori(DisasContext *s, DisasOps *o)
+{
+    int shift = s->insn->data & 0xff;
+    int size = s->insn->data >> 8;
+    uint64_t mask = ((1ull << size) - 1) << shift;
+
+    assert(!o->g_in2);
+    tcg_gen_shli_i64(o->in2, o->in2, shift);
+    tcg_gen_or_i64(o->out, o->in1, o->in2);
+
+    /* Produce the CC from only the bits manipulated.  */
+    tcg_gen_andi_i64(cc_dst, o->out, mask);
+    set_cc_nz_u64(s, cc_dst);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_oi(DisasContext *s, DisasOps *o)
+{
+    o->in1 = tcg_temp_new_i64();
+
+    if (!s390_has_feat(S390_FEAT_INTERLOCKED_ACCESS_2)) {
+        tcg_gen_qemu_ld_tl(o->in1, o->addr1, get_mem_index(s), s->insn->data);
+    } else {
+        /* Perform the atomic operation in memory. */
+        tcg_gen_atomic_fetch_or_i64(o->in1, o->addr1, o->in2, get_mem_index(s),
+                                    s->insn->data);
+    }
+
+    /* Recompute also for atomic case: needed for setting CC. */
+    tcg_gen_or_i64(o->out, o->in1, o->in2);
+
+    if (!s390_has_feat(S390_FEAT_INTERLOCKED_ACCESS_2)) {
+        tcg_gen_qemu_st_tl(o->out, o->addr1, get_mem_index(s), s->insn->data);
+    }
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_pack(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 l = tcg_const_i32(get_field(s, l1));
+    gen_helper_pack(cpu_env, l, o->addr1, o->in2);
+    tcg_temp_free_i32(l);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_pka(DisasContext *s, DisasOps *o)
+{
+    int l2 = get_field(s, l2) + 1;
+    TCGv_i32 l;
+
+    /* The length must not exceed 32 bytes.  */
+    if (l2 > 32) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+    l = tcg_const_i32(l2);
+    gen_helper_pka(cpu_env, o->addr1, o->in2, l);
+    tcg_temp_free_i32(l);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_pku(DisasContext *s, DisasOps *o)
+{
+    int l2 = get_field(s, l2) + 1;
+    TCGv_i32 l;
+
+    /* The length must be even and should not exceed 64 bytes.  */
+    if ((l2 & 1) || (l2 > 64)) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+    l = tcg_const_i32(l2);
+    gen_helper_pku(cpu_env, o->addr1, o->in2, l);
+    tcg_temp_free_i32(l);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_popcnt(DisasContext *s, DisasOps *o)
+{
+    gen_helper_popcnt(o->out, o->in2);
+    return DISAS_NEXT;
+}
+
+#ifndef CONFIG_USER_ONLY
+static DisasJumpType op_ptlb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_ptlb(cpu_env);
+    return DISAS_NEXT;
+}
+#endif
+
+static DisasJumpType op_risbg(DisasContext *s, DisasOps *o)
+{
+    int i3 = get_field(s, i3);
+    int i4 = get_field(s, i4);
+    int i5 = get_field(s, i5);
+    int do_zero = i4 & 0x80;
+    uint64_t mask, imask, pmask;
+    int pos, len, rot;
+
+    /* Adjust the arguments for the specific insn.  */
+    switch (s->fields.op2) {
+    case 0x55: /* risbg */
+    case 0x59: /* risbgn */
+        i3 &= 63;
+        i4 &= 63;
+        pmask = ~0;
+        break;
+    case 0x5d: /* risbhg */
+        i3 &= 31;
+        i4 &= 31;
+        pmask = 0xffffffff00000000ull;
+        break;
+    case 0x51: /* risblg */
+        i3 = (i3 & 31) + 32;
+        i4 = (i4 & 31) + 32;
+        pmask = 0x00000000ffffffffull;
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    /* MASK is the set of bits to be inserted from R2. */
+    if (i3 <= i4) {
+        /* [0...i3---i4...63] */
+        mask = (-1ull >> i3) & (-1ull << (63 - i4));
+    } else {
+        /* [0---i4...i3---63] */
+        mask = (-1ull >> i3) | (-1ull << (63 - i4));
+    }
+    /* For RISBLG/RISBHG, the wrapping is limited to the high/low doubleword. */
+    mask &= pmask;
+
+    /* IMASK is the set of bits to be kept from R1.  In the case of the high/low
+       insns, we need to keep the other half of the register.  */
+    imask = ~mask | ~pmask;
+    if (do_zero) {
+        imask = ~pmask;
+    }
+
+    len = i4 - i3 + 1;
+    pos = 63 - i4;
+    rot = i5 & 63;
+
+    /* In some cases we can implement this with extract.  */
+    if (imask == 0 && pos == 0 && len > 0 && len <= rot) {
+        tcg_gen_extract_i64(o->out, o->in2, 64 - rot, len);
+        return DISAS_NEXT;
+    }
+
+    /* In some cases we can implement this with deposit.  */
+    if (len > 0 && (imask == 0 || ~mask == imask)) {
+        /* Note that we rotate the bits to be inserted to the lsb, not to
+           the position as described in the PoO.  */
+        rot = (rot - pos) & 63;
+    } else {
+        pos = -1;
+    }
+
+    /* Rotate the input as necessary.  */
+    tcg_gen_rotli_i64(o->in2, o->in2, rot);
+
+    /* Insert the selected bits into the output.  */
+    if (pos >= 0) {
+        if (imask == 0) {
+            tcg_gen_deposit_z_i64(o->out, o->in2, pos, len);
+        } else {
+            tcg_gen_deposit_i64(o->out, o->out, o->in2, pos, len);
+        }
+    } else if (imask == 0) {
+        tcg_gen_andi_i64(o->out, o->in2, mask);
+    } else {
+        tcg_gen_andi_i64(o->in2, o->in2, mask);
+        tcg_gen_andi_i64(o->out, o->out, imask);
+        tcg_gen_or_i64(o->out, o->out, o->in2);
+    }
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_rosbg(DisasContext *s, DisasOps *o)
+{
+    int i3 = get_field(s, i3);
+    int i4 = get_field(s, i4);
+    int i5 = get_field(s, i5);
+    uint64_t mask;
+
+    /* If this is a test-only form, arrange to discard the result.  */
+    if (i3 & 0x80) {
+        o->out = tcg_temp_new_i64();
+        o->g_out = false;
+    }
+
+    i3 &= 63;
+    i4 &= 63;
+    i5 &= 63;
+
+    /* MASK is the set of bits to be operated on from R2.
+       Take care for I3/I4 wraparound.  */
+    mask = ~0ull >> i3;
+    if (i3 <= i4) {
+        mask ^= ~0ull >> i4 >> 1;
+    } else {
+        mask |= ~(~0ull >> i4 >> 1);
+    }
+
+    /* Rotate the input as necessary.  */
+    tcg_gen_rotli_i64(o->in2, o->in2, i5);
+
+    /* Operate.  */
+    switch (s->fields.op2) {
+    case 0x54: /* AND */
+        tcg_gen_ori_i64(o->in2, o->in2, ~mask);
+        tcg_gen_and_i64(o->out, o->out, o->in2);
+        break;
+    case 0x56: /* OR */
+        tcg_gen_andi_i64(o->in2, o->in2, mask);
+        tcg_gen_or_i64(o->out, o->out, o->in2);
+        break;
+    case 0x57: /* XOR */
+        tcg_gen_andi_i64(o->in2, o->in2, mask);
+        tcg_gen_xor_i64(o->out, o->out, o->in2);
+        break;
+    default:
+        abort();
+    }
+
+    /* Set the CC.  */
+    tcg_gen_andi_i64(cc_dst, o->out, mask);
+    set_cc_nz_u64(s, cc_dst);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_rev16(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_bswap16_i64(o->out, o->in2, TCG_BSWAP_IZ | TCG_BSWAP_OZ);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_rev32(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_bswap32_i64(o->out, o->in2, TCG_BSWAP_IZ | TCG_BSWAP_OZ);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_rev64(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_bswap64_i64(o->out, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_rll32(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 t1 = tcg_temp_new_i32();
+    TCGv_i32 t2 = tcg_temp_new_i32();
+    TCGv_i32 to = tcg_temp_new_i32();
+    tcg_gen_extrl_i64_i32(t1, o->in1);
+    tcg_gen_extrl_i64_i32(t2, o->in2);
+    tcg_gen_rotl_i32(to, t1, t2);
+    tcg_gen_extu_i32_i64(o->out, to);
+    tcg_temp_free_i32(t1);
+    tcg_temp_free_i32(t2);
+    tcg_temp_free_i32(to);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_rll64(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_rotl_i64(o->out, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+#ifndef CONFIG_USER_ONLY
+static DisasJumpType op_rrbe(DisasContext *s, DisasOps *o)
+{
+    gen_helper_rrbe(cc_op, cpu_env, o->in2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_sacf(DisasContext *s, DisasOps *o)
+{
+    gen_helper_sacf(cpu_env, o->in2);
+    /* Addressing mode has changed, so end the block.  */
+    return DISAS_PC_STALE;
+}
+#endif
+
+static DisasJumpType op_sam(DisasContext *s, DisasOps *o)
+{
+    int sam = s->insn->data;
+    TCGv_i64 tsam;
+    uint64_t mask;
+
+    switch (sam) {
+    case 0:
+        mask = 0xffffff;
+        break;
+    case 1:
+        mask = 0x7fffffff;
+        break;
+    default:
+        mask = -1;
+        break;
+    }
+
+    /* Bizarre but true, we check the address of the current insn for the
+       specification exception, not the next to be executed.  Thus the PoO
+       documents that Bad Things Happen two bytes before the end.  */
+    if (s->base.pc_next & ~mask) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+    s->pc_tmp &= mask;
+
+    tsam = tcg_const_i64(sam);
+    tcg_gen_deposit_i64(psw_mask, psw_mask, tsam, 31, 2);
+    tcg_temp_free_i64(tsam);
+
+    /* Always exit the TB, since we (may have) changed execution mode.  */
+    return DISAS_PC_STALE;
+}
+
+static DisasJumpType op_sar(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    tcg_gen_st32_i64(o->in2, cpu_env, offsetof(CPUS390XState, aregs[r1]));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_seb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_seb(o->out, cpu_env, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_sdb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_sdb(o->out, cpu_env, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_sxb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_sxb(o->out, cpu_env, o->out, o->out2, o->in1, o->in2);
+    return_low128(o->out2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_sqeb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_sqeb(o->out, cpu_env, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_sqdb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_sqdb(o->out, cpu_env, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_sqxb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_sqxb(o->out, cpu_env, o->in1, o->in2);
+    return_low128(o->out2);
+    return DISAS_NEXT;
+}
+
+#ifndef CONFIG_USER_ONLY
+static DisasJumpType op_servc(DisasContext *s, DisasOps *o)
+{
+    gen_helper_servc(cc_op, cpu_env, o->in2, o->in1);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_sigp(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
+    TCGv_i32 r3 = tcg_const_i32(get_field(s, r3));
+    gen_helper_sigp(cc_op, cpu_env, o->in2, r1, r3);
+    set_cc_static(s);
+    tcg_temp_free_i32(r1);
+    tcg_temp_free_i32(r3);
+    return DISAS_NEXT;
+}
+#endif
+
+static DisasJumpType op_soc(DisasContext *s, DisasOps *o)
+{
+    DisasCompare c;
+    TCGv_i64 a, h;
+    TCGLabel *lab;
+    int r1;
+
+    disas_jcc(s, &c, get_field(s, m3));
+
+    /* We want to store when the condition is fulfilled, so branch
+       out when it's not */
+    c.cond = tcg_invert_cond(c.cond);
+
+    lab = gen_new_label();
+    if (c.is_64) {
+        tcg_gen_brcond_i64(c.cond, c.u.s64.a, c.u.s64.b, lab);
+    } else {
+        tcg_gen_brcond_i32(c.cond, c.u.s32.a, c.u.s32.b, lab);
+    }
+    free_compare(&c);
+
+    r1 = get_field(s, r1);
+    a = get_address(s, 0, get_field(s, b2), get_field(s, d2));
+    switch (s->insn->data) {
+    case 1: /* STOCG */
+        tcg_gen_qemu_st64(regs[r1], a, get_mem_index(s));
+        break;
+    case 0: /* STOC */
+        tcg_gen_qemu_st32(regs[r1], a, get_mem_index(s));
+        break;
+    case 2: /* STOCFH */
+        h = tcg_temp_new_i64();
+        tcg_gen_shri_i64(h, regs[r1], 32);
+        tcg_gen_qemu_st32(h, a, get_mem_index(s));
+        tcg_temp_free_i64(h);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+    tcg_temp_free_i64(a);
+
+    gen_set_label(lab);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_sla(DisasContext *s, DisasOps *o)
+{
+    uint64_t sign = 1ull << s->insn->data;
+    enum cc_op cco = s->insn->data == 31 ? CC_OP_SLA_32 : CC_OP_SLA_64;
+    gen_op_update2_cc_i64(s, cco, o->in1, o->in2);
+    tcg_gen_shl_i64(o->out, o->in1, o->in2);
+    /* The arithmetic left shift is curious in that it does not affect
+       the sign bit.  Copy that over from the source unchanged.  */
+    tcg_gen_andi_i64(o->out, o->out, ~sign);
+    tcg_gen_andi_i64(o->in1, o->in1, sign);
+    tcg_gen_or_i64(o->out, o->out, o->in1);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_sll(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_shl_i64(o->out, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_sra(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_sar_i64(o->out, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_srl(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_shr_i64(o->out, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_sfpc(DisasContext *s, DisasOps *o)
+{
+    gen_helper_sfpc(cpu_env, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_sfas(DisasContext *s, DisasOps *o)
+{
+    gen_helper_sfas(cpu_env, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_srnm(DisasContext *s, DisasOps *o)
+{
+    /* Bits other than 62 and 63 are ignored. Bit 29 is set to zero. */
+    tcg_gen_andi_i64(o->addr1, o->addr1, 0x3ull);
+    gen_helper_srnm(cpu_env, o->addr1);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_srnmb(DisasContext *s, DisasOps *o)
+{
+    /* Bits 0-55 are are ignored. */
+    tcg_gen_andi_i64(o->addr1, o->addr1, 0xffull);
+    gen_helper_srnm(cpu_env, o->addr1);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_srnmt(DisasContext *s, DisasOps *o)
+{
+    TCGv_i64 tmp = tcg_temp_new_i64();
+
+    /* Bits other than 61-63 are ignored. */
+    tcg_gen_andi_i64(o->addr1, o->addr1, 0x7ull);
+
+    /* No need to call a helper, we don't implement dfp */
+    tcg_gen_ld32u_i64(tmp, cpu_env, offsetof(CPUS390XState, fpc));
+    tcg_gen_deposit_i64(tmp, tmp, o->addr1, 4, 3);
+    tcg_gen_st32_i64(tmp, cpu_env, offsetof(CPUS390XState, fpc));
+
+    tcg_temp_free_i64(tmp);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_spm(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_extrl_i64_i32(cc_op, o->in1);
+    tcg_gen_extract_i32(cc_op, cc_op, 28, 2);
+    set_cc_static(s);
+
+    tcg_gen_shri_i64(o->in1, o->in1, 24);
+    tcg_gen_deposit_i64(psw_mask, psw_mask, o->in1, PSW_SHIFT_MASK_PM, 4);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_ectg(DisasContext *s, DisasOps *o)
+{
+    int b1 = get_field(s, b1);
+    int d1 = get_field(s, d1);
+    int b2 = get_field(s, b2);
+    int d2 = get_field(s, d2);
+    int r3 = get_field(s, r3);
+    TCGv_i64 tmp = tcg_temp_new_i64();
+
+    /* fetch all operands first */
+    o->in1 = tcg_temp_new_i64();
+    tcg_gen_addi_i64(o->in1, regs[b1], d1);
+    o->in2 = tcg_temp_new_i64();
+    tcg_gen_addi_i64(o->in2, regs[b2], d2);
+    o->addr1 = tcg_temp_new_i64();
+    gen_addi_and_wrap_i64(s, o->addr1, regs[r3], 0);
+
+    /* load the third operand into r3 before modifying anything */
+    tcg_gen_qemu_ld64(regs[r3], o->addr1, get_mem_index(s));
+
+    /* subtract CPU timer from first operand and store in GR0 */
+    gen_helper_stpt(tmp, cpu_env);
+    tcg_gen_sub_i64(regs[0], o->in1, tmp);
+
+    /* store second operand in GR1 */
+    tcg_gen_mov_i64(regs[1], o->in2);
+
+    tcg_temp_free_i64(tmp);
+    return DISAS_NEXT;
+}
+
+#ifndef CONFIG_USER_ONLY
+static DisasJumpType op_spka(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_shri_i64(o->in2, o->in2, 4);
+    tcg_gen_deposit_i64(psw_mask, psw_mask, o->in2, PSW_SHIFT_KEY, 4);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_sske(DisasContext *s, DisasOps *o)
+{
+    gen_helper_sske(cpu_env, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_ssm(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_deposit_i64(psw_mask, psw_mask, o->in2, 56, 8);
+    /* Exit to main loop to reevaluate s390_cpu_exec_interrupt.  */
+    return DISAS_PC_STALE_NOCHAIN;
+}
+
+static DisasJumpType op_stap(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, core_id));
+    return DISAS_NEXT;
+}
+#endif
+
+static DisasJumpType op_stck(DisasContext *s, DisasOps *o)
+{
+    gen_helper_stck(o->out, cpu_env);
+    /* ??? We don't implement clock states.  */
+    gen_op_movi_cc(s, 0);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_stcke(DisasContext *s, DisasOps *o)
+{
+    TCGv_i64 c1 = tcg_temp_new_i64();
+    TCGv_i64 c2 = tcg_temp_new_i64();
+    TCGv_i64 todpr = tcg_temp_new_i64();
+    gen_helper_stck(c1, cpu_env);
+    /* 16 bit value store in an uint32_t (only valid bits set) */
+    tcg_gen_ld32u_i64(todpr, cpu_env, offsetof(CPUS390XState, todpr));
+    /* Shift the 64-bit value into its place as a zero-extended
+       104-bit value.  Note that "bit positions 64-103 are always
+       non-zero so that they compare differently to STCK"; we set
+       the least significant bit to 1.  */
+    tcg_gen_shli_i64(c2, c1, 56);
+    tcg_gen_shri_i64(c1, c1, 8);
+    tcg_gen_ori_i64(c2, c2, 0x10000);
+    tcg_gen_or_i64(c2, c2, todpr);
+    tcg_gen_qemu_st64(c1, o->in2, get_mem_index(s));
+    tcg_gen_addi_i64(o->in2, o->in2, 8);
+    tcg_gen_qemu_st64(c2, o->in2, get_mem_index(s));
+    tcg_temp_free_i64(c1);
+    tcg_temp_free_i64(c2);
+    tcg_temp_free_i64(todpr);
+    /* ??? We don't implement clock states.  */
+    gen_op_movi_cc(s, 0);
+    return DISAS_NEXT;
+}
+
+#ifndef CONFIG_USER_ONLY
+static DisasJumpType op_sck(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_qemu_ld_i64(o->in1, o->addr1, get_mem_index(s), MO_TEQ | MO_ALIGN);
+    gen_helper_sck(cc_op, cpu_env, o->in1);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_sckc(DisasContext *s, DisasOps *o)
+{
+    gen_helper_sckc(cpu_env, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_sckpf(DisasContext *s, DisasOps *o)
+{
+    gen_helper_sckpf(cpu_env, regs[0]);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_stckc(DisasContext *s, DisasOps *o)
+{
+    gen_helper_stckc(o->out, cpu_env);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_stctg(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
+    TCGv_i32 r3 = tcg_const_i32(get_field(s, r3));
+    gen_helper_stctg(cpu_env, r1, o->in2, r3);
+    tcg_temp_free_i32(r1);
+    tcg_temp_free_i32(r3);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_stctl(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
+    TCGv_i32 r3 = tcg_const_i32(get_field(s, r3));
+    gen_helper_stctl(cpu_env, r1, o->in2, r3);
+    tcg_temp_free_i32(r1);
+    tcg_temp_free_i32(r3);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_stidp(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_ld_i64(o->out, cpu_env, offsetof(CPUS390XState, cpuid));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_spt(DisasContext *s, DisasOps *o)
+{
+    gen_helper_spt(cpu_env, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_stfl(DisasContext *s, DisasOps *o)
+{
+    gen_helper_stfl(cpu_env);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_stpt(DisasContext *s, DisasOps *o)
+{
+    gen_helper_stpt(o->out, cpu_env);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_stsi(DisasContext *s, DisasOps *o)
+{
+    gen_helper_stsi(cc_op, cpu_env, o->in2, regs[0], regs[1]);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_spx(DisasContext *s, DisasOps *o)
+{
+    gen_helper_spx(cpu_env, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_xsch(DisasContext *s, DisasOps *o)
+{
+    gen_helper_xsch(cpu_env, regs[1]);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_csch(DisasContext *s, DisasOps *o)
+{
+    gen_helper_csch(cpu_env, regs[1]);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_hsch(DisasContext *s, DisasOps *o)
+{
+    gen_helper_hsch(cpu_env, regs[1]);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_msch(DisasContext *s, DisasOps *o)
+{
+    gen_helper_msch(cpu_env, regs[1], o->in2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_rchp(DisasContext *s, DisasOps *o)
+{
+    gen_helper_rchp(cpu_env, regs[1]);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_rsch(DisasContext *s, DisasOps *o)
+{
+    gen_helper_rsch(cpu_env, regs[1]);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_sal(DisasContext *s, DisasOps *o)
+{
+    gen_helper_sal(cpu_env, regs[1]);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_schm(DisasContext *s, DisasOps *o)
+{
+    gen_helper_schm(cpu_env, regs[1], regs[2], o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_siga(DisasContext *s, DisasOps *o)
+{
+    /* From KVM code: Not provided, set CC = 3 for subchannel not operational */
+    gen_op_movi_cc(s, 3);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_stcps(DisasContext *s, DisasOps *o)
+{
+    /* The instruction is suppressed if not provided. */
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_ssch(DisasContext *s, DisasOps *o)
+{
+    gen_helper_ssch(cpu_env, regs[1], o->in2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_stsch(DisasContext *s, DisasOps *o)
+{
+    gen_helper_stsch(cpu_env, regs[1], o->in2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_stcrw(DisasContext *s, DisasOps *o)
+{
+    gen_helper_stcrw(cpu_env, o->in2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_tpi(DisasContext *s, DisasOps *o)
+{
+    gen_helper_tpi(cc_op, cpu_env, o->addr1);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_tsch(DisasContext *s, DisasOps *o)
+{
+    gen_helper_tsch(cpu_env, regs[1], o->in2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_chsc(DisasContext *s, DisasOps *o)
+{
+    gen_helper_chsc(cpu_env, o->in2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_stpx(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_ld_i64(o->out, cpu_env, offsetof(CPUS390XState, psa));
+    tcg_gen_andi_i64(o->out, o->out, 0x7fffe000);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_stnosm(DisasContext *s, DisasOps *o)
+{
+    uint64_t i2 = get_field(s, i2);
+    TCGv_i64 t;
+
+    /* It is important to do what the instruction name says: STORE THEN.
+       If we let the output hook perform the store then if we fault and
+       restart, we'll have the wrong SYSTEM MASK in place.  */
+    t = tcg_temp_new_i64();
+    tcg_gen_shri_i64(t, psw_mask, 56);
+    tcg_gen_qemu_st8(t, o->addr1, get_mem_index(s));
+    tcg_temp_free_i64(t);
+
+    if (s->fields.op == 0xac) {
+        tcg_gen_andi_i64(psw_mask, psw_mask,
+                         (i2 << 56) | 0x00ffffffffffffffull);
+    } else {
+        tcg_gen_ori_i64(psw_mask, psw_mask, i2 << 56);
+    }
+
+    /* Exit to main loop to reevaluate s390_cpu_exec_interrupt.  */
+    return DISAS_PC_STALE_NOCHAIN;
+}
+
+static DisasJumpType op_stura(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_qemu_st_tl(o->in1, o->in2, MMU_REAL_IDX, s->insn->data);
+
+    if (s->base.tb->flags & FLAG_MASK_PER) {
+        update_psw_addr(s);
+        gen_helper_per_store_real(cpu_env);
+    }
+    return DISAS_NEXT;
+}
+#endif
+
+static DisasJumpType op_stfle(DisasContext *s, DisasOps *o)
+{
+    gen_helper_stfle(cc_op, cpu_env, o->in2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_st8(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_qemu_st8(o->in1, o->in2, get_mem_index(s));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_st16(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_qemu_st16(o->in1, o->in2, get_mem_index(s));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_st32(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_qemu_st32(o->in1, o->in2, get_mem_index(s));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_st64(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_qemu_st64(o->in1, o->in2, get_mem_index(s));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_stam(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
+    TCGv_i32 r3 = tcg_const_i32(get_field(s, r3));
+    gen_helper_stam(cpu_env, r1, o->in2, r3);
+    tcg_temp_free_i32(r1);
+    tcg_temp_free_i32(r3);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_stcm(DisasContext *s, DisasOps *o)
+{
+    int m3 = get_field(s, m3);
+    int pos, base = s->insn->data;
+    TCGv_i64 tmp = tcg_temp_new_i64();
+
+    pos = base + ctz32(m3) * 8;
+    switch (m3) {
+    case 0xf:
+        /* Effectively a 32-bit store.  */
+        tcg_gen_shri_i64(tmp, o->in1, pos);
+        tcg_gen_qemu_st32(tmp, o->in2, get_mem_index(s));
+        break;
+
+    case 0xc:
+    case 0x6:
+    case 0x3:
+        /* Effectively a 16-bit store.  */
+        tcg_gen_shri_i64(tmp, o->in1, pos);
+        tcg_gen_qemu_st16(tmp, o->in2, get_mem_index(s));
+        break;
+
+    case 0x8:
+    case 0x4:
+    case 0x2:
+    case 0x1:
+        /* Effectively an 8-bit store.  */
+        tcg_gen_shri_i64(tmp, o->in1, pos);
+        tcg_gen_qemu_st8(tmp, o->in2, get_mem_index(s));
+        break;
+
+    default:
+        /* This is going to be a sequence of shifts and stores.  */
+        pos = base + 32 - 8;
+        while (m3) {
+            if (m3 & 0x8) {
+                tcg_gen_shri_i64(tmp, o->in1, pos);
+                tcg_gen_qemu_st8(tmp, o->in2, get_mem_index(s));
+                tcg_gen_addi_i64(o->in2, o->in2, 1);
+            }
+            m3 = (m3 << 1) & 0xf;
+            pos -= 8;
+        }
+        break;
+    }
+    tcg_temp_free_i64(tmp);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_stm(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    int r3 = get_field(s, r3);
+    int size = s->insn->data;
+    TCGv_i64 tsize = tcg_const_i64(size);
+
+    while (1) {
+        if (size == 8) {
+            tcg_gen_qemu_st64(regs[r1], o->in2, get_mem_index(s));
+        } else {
+            tcg_gen_qemu_st32(regs[r1], o->in2, get_mem_index(s));
+        }
+        if (r1 == r3) {
+            break;
+        }
+        tcg_gen_add_i64(o->in2, o->in2, tsize);
+        r1 = (r1 + 1) & 15;
+    }
+
+    tcg_temp_free_i64(tsize);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_stmh(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    int r3 = get_field(s, r3);
+    TCGv_i64 t = tcg_temp_new_i64();
+    TCGv_i64 t4 = tcg_const_i64(4);
+    TCGv_i64 t32 = tcg_const_i64(32);
+
+    while (1) {
+        tcg_gen_shl_i64(t, regs[r1], t32);
+        tcg_gen_qemu_st32(t, o->in2, get_mem_index(s));
+        if (r1 == r3) {
+            break;
+        }
+        tcg_gen_add_i64(o->in2, o->in2, t4);
+        r1 = (r1 + 1) & 15;
+    }
+
+    tcg_temp_free_i64(t);
+    tcg_temp_free_i64(t4);
+    tcg_temp_free_i64(t32);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_stpq(DisasContext *s, DisasOps *o)
+{
+    if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
+        gen_helper_stpq(cpu_env, o->in2, o->out2, o->out);
+    } else if (HAVE_ATOMIC128) {
+        gen_helper_stpq_parallel(cpu_env, o->in2, o->out2, o->out);
+    } else {
+        gen_helper_exit_atomic(cpu_env);
+        return DISAS_NORETURN;
+    }
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_srst(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
+    TCGv_i32 r2 = tcg_const_i32(get_field(s, r2));
+
+    gen_helper_srst(cpu_env, r1, r2);
+
+    tcg_temp_free_i32(r1);
+    tcg_temp_free_i32(r2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_srstu(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
+    TCGv_i32 r2 = tcg_const_i32(get_field(s, r2));
+
+    gen_helper_srstu(cpu_env, r1, r2);
+
+    tcg_temp_free_i32(r1);
+    tcg_temp_free_i32(r2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_sub(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_sub_i64(o->out, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_subu64(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_movi_i64(cc_src, 0);
+    tcg_gen_sub2_i64(o->out, cc_src, o->in1, cc_src, o->in2, cc_src);
+    return DISAS_NEXT;
+}
+
+/* Compute borrow (0, -1) into cc_src. */
+static void compute_borrow(DisasContext *s)
+{
+    switch (s->cc_op) {
+    case CC_OP_SUBU:
+        /* The borrow value is already in cc_src (0,-1). */
+        break;
+    default:
+        gen_op_calc_cc(s);
+        /* fall through */
+    case CC_OP_STATIC:
+        /* The carry flag is the msb of CC; compute into cc_src. */
+        tcg_gen_extu_i32_i64(cc_src, cc_op);
+        tcg_gen_shri_i64(cc_src, cc_src, 1);
+        /* fall through */
+    case CC_OP_ADDU:
+        /* Convert carry (1,0) to borrow (0,-1). */
+        tcg_gen_subi_i64(cc_src, cc_src, 1);
+        break;
+    }
+}
+
+static DisasJumpType op_subb32(DisasContext *s, DisasOps *o)
+{
+    compute_borrow(s);
+
+    /* Borrow is {0, -1}, so add to subtract. */
+    tcg_gen_add_i64(o->out, o->in1, cc_src);
+    tcg_gen_sub_i64(o->out, o->out, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_subb64(DisasContext *s, DisasOps *o)
+{
+    compute_borrow(s);
+
+    /*
+     * Borrow is {0, -1}, so add to subtract; replicate the
+     * borrow input to produce 128-bit -1 for the addition.
+     */
+    TCGv_i64 zero = tcg_const_i64(0);
+    tcg_gen_add2_i64(o->out, cc_src, o->in1, zero, cc_src, cc_src);
+    tcg_gen_sub2_i64(o->out, cc_src, o->out, cc_src, o->in2, zero);
+    tcg_temp_free_i64(zero);
+
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_svc(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 t;
+
+    update_psw_addr(s);
+    update_cc_op(s);
+
+    t = tcg_const_i32(get_field(s, i1) & 0xff);
+    tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, int_svc_code));
+    tcg_temp_free_i32(t);
+
+    t = tcg_const_i32(s->ilen);
+    tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, int_svc_ilen));
+    tcg_temp_free_i32(t);
+
+    gen_exception(EXCP_SVC);
+    return DISAS_NORETURN;
+}
+
+static DisasJumpType op_tam(DisasContext *s, DisasOps *o)
+{
+    int cc = 0;
+
+    cc |= (s->base.tb->flags & FLAG_MASK_64) ? 2 : 0;
+    cc |= (s->base.tb->flags & FLAG_MASK_32) ? 1 : 0;
+    gen_op_movi_cc(s, cc);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_tceb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_tceb(cc_op, cpu_env, o->in1, o->in2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_tcdb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_tcdb(cc_op, cpu_env, o->in1, o->in2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_tcxb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_tcxb(cc_op, cpu_env, o->out, o->out2, o->in2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+#ifndef CONFIG_USER_ONLY
+
+static DisasJumpType op_testblock(DisasContext *s, DisasOps *o)
+{
+    gen_helper_testblock(cc_op, cpu_env, o->in2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_tprot(DisasContext *s, DisasOps *o)
+{
+    gen_helper_tprot(cc_op, cpu_env, o->addr1, o->in2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+#endif
+
+static DisasJumpType op_tp(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 l1 = tcg_const_i32(get_field(s, l1) + 1);
+    gen_helper_tp(cc_op, cpu_env, o->addr1, l1);
+    tcg_temp_free_i32(l1);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_tr(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 l = tcg_const_i32(get_field(s, l1));
+    gen_helper_tr(cpu_env, l, o->addr1, o->in2);
+    tcg_temp_free_i32(l);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_tre(DisasContext *s, DisasOps *o)
+{
+    gen_helper_tre(o->out, cpu_env, o->out, o->out2, o->in2);
+    return_low128(o->out2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_trt(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 l = tcg_const_i32(get_field(s, l1));
+    gen_helper_trt(cc_op, cpu_env, l, o->addr1, o->in2);
+    tcg_temp_free_i32(l);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_trtr(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 l = tcg_const_i32(get_field(s, l1));
+    gen_helper_trtr(cc_op, cpu_env, l, o->addr1, o->in2);
+    tcg_temp_free_i32(l);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_trXX(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
+    TCGv_i32 r2 = tcg_const_i32(get_field(s, r2));
+    TCGv_i32 sizes = tcg_const_i32(s->insn->opc & 3);
+    TCGv_i32 tst = tcg_temp_new_i32();
+    int m3 = get_field(s, m3);
+
+    if (!s390_has_feat(S390_FEAT_ETF2_ENH)) {
+        m3 = 0;
+    }
+    if (m3 & 1) {
+        tcg_gen_movi_i32(tst, -1);
+    } else {
+        tcg_gen_extrl_i64_i32(tst, regs[0]);
+        if (s->insn->opc & 3) {
+            tcg_gen_ext8u_i32(tst, tst);
+        } else {
+            tcg_gen_ext16u_i32(tst, tst);
+        }
+    }
+    gen_helper_trXX(cc_op, cpu_env, r1, r2, tst, sizes);
+
+    tcg_temp_free_i32(r1);
+    tcg_temp_free_i32(r2);
+    tcg_temp_free_i32(sizes);
+    tcg_temp_free_i32(tst);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_ts(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 t1 = tcg_const_i32(0xff);
+    tcg_gen_atomic_xchg_i32(t1, o->in2, t1, get_mem_index(s), MO_UB);
+    tcg_gen_extract_i32(cc_op, t1, 7, 1);
+    tcg_temp_free_i32(t1);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_unpk(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 l = tcg_const_i32(get_field(s, l1));
+    gen_helper_unpk(cpu_env, l, o->addr1, o->in2);
+    tcg_temp_free_i32(l);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_unpka(DisasContext *s, DisasOps *o)
+{
+    int l1 = get_field(s, l1) + 1;
+    TCGv_i32 l;
+
+    /* The length must not exceed 32 bytes.  */
+    if (l1 > 32) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+    l = tcg_const_i32(l1);
+    gen_helper_unpka(cc_op, cpu_env, o->addr1, l, o->in2);
+    tcg_temp_free_i32(l);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_unpku(DisasContext *s, DisasOps *o)
+{
+    int l1 = get_field(s, l1) + 1;
+    TCGv_i32 l;
+
+    /* The length must be even and should not exceed 64 bytes.  */
+    if ((l1 & 1) || (l1 > 64)) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+    l = tcg_const_i32(l1);
+    gen_helper_unpku(cc_op, cpu_env, o->addr1, l, o->in2);
+    tcg_temp_free_i32(l);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+
+static DisasJumpType op_xc(DisasContext *s, DisasOps *o)
+{
+    int d1 = get_field(s, d1);
+    int d2 = get_field(s, d2);
+    int b1 = get_field(s, b1);
+    int b2 = get_field(s, b2);
+    int l = get_field(s, l1);
+    TCGv_i32 t32;
+
+    o->addr1 = get_address(s, 0, b1, d1);
+
+    /* If the addresses are identical, this is a store/memset of zero.  */
+    if (b1 == b2 && d1 == d2 && (l + 1) <= 32) {
+        o->in2 = tcg_const_i64(0);
+
+        l++;
+        while (l >= 8) {
+            tcg_gen_qemu_st64(o->in2, o->addr1, get_mem_index(s));
+            l -= 8;
+            if (l > 0) {
+                tcg_gen_addi_i64(o->addr1, o->addr1, 8);
+            }
+        }
+        if (l >= 4) {
+            tcg_gen_qemu_st32(o->in2, o->addr1, get_mem_index(s));
+            l -= 4;
+            if (l > 0) {
+                tcg_gen_addi_i64(o->addr1, o->addr1, 4);
+            }
+        }
+        if (l >= 2) {
+            tcg_gen_qemu_st16(o->in2, o->addr1, get_mem_index(s));
+            l -= 2;
+            if (l > 0) {
+                tcg_gen_addi_i64(o->addr1, o->addr1, 2);
+            }
+        }
+        if (l) {
+            tcg_gen_qemu_st8(o->in2, o->addr1, get_mem_index(s));
+        }
+        gen_op_movi_cc(s, 0);
+        return DISAS_NEXT;
+    }
+
+    /* But in general we'll defer to a helper.  */
+    o->in2 = get_address(s, 0, b2, d2);
+    t32 = tcg_const_i32(l);
+    gen_helper_xc(cc_op, cpu_env, t32, o->addr1, o->in2);
+    tcg_temp_free_i32(t32);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_xor(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_xor_i64(o->out, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_xori(DisasContext *s, DisasOps *o)
+{
+    int shift = s->insn->data & 0xff;
+    int size = s->insn->data >> 8;
+    uint64_t mask = ((1ull << size) - 1) << shift;
+
+    assert(!o->g_in2);
+    tcg_gen_shli_i64(o->in2, o->in2, shift);
+    tcg_gen_xor_i64(o->out, o->in1, o->in2);
+
+    /* Produce the CC from only the bits manipulated.  */
+    tcg_gen_andi_i64(cc_dst, o->out, mask);
+    set_cc_nz_u64(s, cc_dst);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_xi(DisasContext *s, DisasOps *o)
+{
+    o->in1 = tcg_temp_new_i64();
+
+    if (!s390_has_feat(S390_FEAT_INTERLOCKED_ACCESS_2)) {
+        tcg_gen_qemu_ld_tl(o->in1, o->addr1, get_mem_index(s), s->insn->data);
+    } else {
+        /* Perform the atomic operation in memory. */
+        tcg_gen_atomic_fetch_xor_i64(o->in1, o->addr1, o->in2, get_mem_index(s),
+                                     s->insn->data);
+    }
+
+    /* Recompute also for atomic case: needed for setting CC. */
+    tcg_gen_xor_i64(o->out, o->in1, o->in2);
+
+    if (!s390_has_feat(S390_FEAT_INTERLOCKED_ACCESS_2)) {
+        tcg_gen_qemu_st_tl(o->out, o->addr1, get_mem_index(s), s->insn->data);
+    }
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_zero(DisasContext *s, DisasOps *o)
+{
+    o->out = tcg_const_i64(0);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_zero2(DisasContext *s, DisasOps *o)
+{
+    o->out = tcg_const_i64(0);
+    o->out2 = o->out;
+    o->g_out2 = true;
+    return DISAS_NEXT;
+}
+
+#ifndef CONFIG_USER_ONLY
+static DisasJumpType op_clp(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 r2 = tcg_const_i32(get_field(s, r2));
+
+    gen_helper_clp(cpu_env, r2);
+    tcg_temp_free_i32(r2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_pcilg(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
+    TCGv_i32 r2 = tcg_const_i32(get_field(s, r2));
+
+    gen_helper_pcilg(cpu_env, r1, r2);
+    tcg_temp_free_i32(r1);
+    tcg_temp_free_i32(r2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_pcistg(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
+    TCGv_i32 r2 = tcg_const_i32(get_field(s, r2));
+
+    gen_helper_pcistg(cpu_env, r1, r2);
+    tcg_temp_free_i32(r1);
+    tcg_temp_free_i32(r2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_stpcifc(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
+    TCGv_i32 ar = tcg_const_i32(get_field(s, b2));
+
+    gen_helper_stpcifc(cpu_env, r1, o->addr1, ar);
+    tcg_temp_free_i32(ar);
+    tcg_temp_free_i32(r1);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_sic(DisasContext *s, DisasOps *o)
+{
+    gen_helper_sic(cpu_env, o->in1, o->in2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_rpcit(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
+    TCGv_i32 r2 = tcg_const_i32(get_field(s, r2));
+
+    gen_helper_rpcit(cpu_env, r1, r2);
+    tcg_temp_free_i32(r1);
+    tcg_temp_free_i32(r2);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_pcistb(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
+    TCGv_i32 r3 = tcg_const_i32(get_field(s, r3));
+    TCGv_i32 ar = tcg_const_i32(get_field(s, b2));
+
+    gen_helper_pcistb(cpu_env, r1, r3, o->addr1, ar);
+    tcg_temp_free_i32(ar);
+    tcg_temp_free_i32(r1);
+    tcg_temp_free_i32(r3);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_mpcifc(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
+    TCGv_i32 ar = tcg_const_i32(get_field(s, b2));
+
+    gen_helper_mpcifc(cpu_env, r1, o->addr1, ar);
+    tcg_temp_free_i32(ar);
+    tcg_temp_free_i32(r1);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+#endif
+
+#include "translate_vx.c.inc"
+
+/* ====================================================================== */
+/* The "Cc OUTput" generators.  Given the generated output (and in some cases
+   the original inputs), update the various cc data structures in order to
+   be able to compute the new condition code.  */
+
+static void cout_abs32(DisasContext *s, DisasOps *o)
+{
+    gen_op_update1_cc_i64(s, CC_OP_ABS_32, o->out);
+}
+
+static void cout_abs64(DisasContext *s, DisasOps *o)
+{
+    gen_op_update1_cc_i64(s, CC_OP_ABS_64, o->out);
+}
+
+static void cout_adds32(DisasContext *s, DisasOps *o)
+{
+    gen_op_update3_cc_i64(s, CC_OP_ADD_32, o->in1, o->in2, o->out);
+}
+
+static void cout_adds64(DisasContext *s, DisasOps *o)
+{
+    gen_op_update3_cc_i64(s, CC_OP_ADD_64, o->in1, o->in2, o->out);
+}
+
+static void cout_addu32(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_shri_i64(cc_src, o->out, 32);
+    tcg_gen_ext32u_i64(cc_dst, o->out);
+    gen_op_update2_cc_i64(s, CC_OP_ADDU, cc_src, cc_dst);
+}
+
+static void cout_addu64(DisasContext *s, DisasOps *o)
+{
+    gen_op_update2_cc_i64(s, CC_OP_ADDU, cc_src, o->out);
+}
+
+static void cout_cmps32(DisasContext *s, DisasOps *o)
+{
+    gen_op_update2_cc_i64(s, CC_OP_LTGT_32, o->in1, o->in2);
+}
+
+static void cout_cmps64(DisasContext *s, DisasOps *o)
+{
+    gen_op_update2_cc_i64(s, CC_OP_LTGT_64, o->in1, o->in2);
+}
+
+static void cout_cmpu32(DisasContext *s, DisasOps *o)
+{
+    gen_op_update2_cc_i64(s, CC_OP_LTUGTU_32, o->in1, o->in2);
+}
+
+static void cout_cmpu64(DisasContext *s, DisasOps *o)
+{
+    gen_op_update2_cc_i64(s, CC_OP_LTUGTU_64, o->in1, o->in2);
+}
+
+static void cout_f32(DisasContext *s, DisasOps *o)
+{
+    gen_op_update1_cc_i64(s, CC_OP_NZ_F32, o->out);
+}
+
+static void cout_f64(DisasContext *s, DisasOps *o)
+{
+    gen_op_update1_cc_i64(s, CC_OP_NZ_F64, o->out);
+}
+
+static void cout_f128(DisasContext *s, DisasOps *o)
+{
+    gen_op_update2_cc_i64(s, CC_OP_NZ_F128, o->out, o->out2);
+}
+
+static void cout_nabs32(DisasContext *s, DisasOps *o)
+{
+    gen_op_update1_cc_i64(s, CC_OP_NABS_32, o->out);
+}
+
+static void cout_nabs64(DisasContext *s, DisasOps *o)
+{
+    gen_op_update1_cc_i64(s, CC_OP_NABS_64, o->out);
+}
+
+static void cout_neg32(DisasContext *s, DisasOps *o)
+{
+    gen_op_update1_cc_i64(s, CC_OP_COMP_32, o->out);
+}
+
+static void cout_neg64(DisasContext *s, DisasOps *o)
+{
+    gen_op_update1_cc_i64(s, CC_OP_COMP_64, o->out);
+}
+
+static void cout_nz32(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_ext32u_i64(cc_dst, o->out);
+    gen_op_update1_cc_i64(s, CC_OP_NZ, cc_dst);
+}
+
+static void cout_nz64(DisasContext *s, DisasOps *o)
+{
+    gen_op_update1_cc_i64(s, CC_OP_NZ, o->out);
+}
+
+static void cout_s32(DisasContext *s, DisasOps *o)
+{
+    gen_op_update1_cc_i64(s, CC_OP_LTGT0_32, o->out);
+}
+
+static void cout_s64(DisasContext *s, DisasOps *o)
+{
+    gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, o->out);
+}
+
+static void cout_subs32(DisasContext *s, DisasOps *o)
+{
+    gen_op_update3_cc_i64(s, CC_OP_SUB_32, o->in1, o->in2, o->out);
+}
+
+static void cout_subs64(DisasContext *s, DisasOps *o)
+{
+    gen_op_update3_cc_i64(s, CC_OP_SUB_64, o->in1, o->in2, o->out);
+}
+
+static void cout_subu32(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_sari_i64(cc_src, o->out, 32);
+    tcg_gen_ext32u_i64(cc_dst, o->out);
+    gen_op_update2_cc_i64(s, CC_OP_SUBU, cc_src, cc_dst);
+}
+
+static void cout_subu64(DisasContext *s, DisasOps *o)
+{
+    gen_op_update2_cc_i64(s, CC_OP_SUBU, cc_src, o->out);
+}
+
+static void cout_tm32(DisasContext *s, DisasOps *o)
+{
+    gen_op_update2_cc_i64(s, CC_OP_TM_32, o->in1, o->in2);
+}
+
+static void cout_tm64(DisasContext *s, DisasOps *o)
+{
+    gen_op_update2_cc_i64(s, CC_OP_TM_64, o->in1, o->in2);
+}
+
+static void cout_muls32(DisasContext *s, DisasOps *o)
+{
+    gen_op_update1_cc_i64(s, CC_OP_MULS_32, o->out);
+}
+
+static void cout_muls64(DisasContext *s, DisasOps *o)
+{
+    /* out contains "high" part, out2 contains "low" part of 128 bit result */
+    gen_op_update2_cc_i64(s, CC_OP_MULS_64, o->out, o->out2);
+}
+
+/* ====================================================================== */
+/* The "PREParation" generators.  These initialize the DisasOps.OUT fields
+   with the TCG register to which we will write.  Used in combination with
+   the "wout" generators, in some cases we need a new temporary, and in
+   some cases we can write to a TCG global.  */
+
+static void prep_new(DisasContext *s, DisasOps *o)
+{
+    o->out = tcg_temp_new_i64();
+}
+#define SPEC_prep_new 0
+
+static void prep_new_P(DisasContext *s, DisasOps *o)
+{
+    o->out = tcg_temp_new_i64();
+    o->out2 = tcg_temp_new_i64();
+}
+#define SPEC_prep_new_P 0
+
+static void prep_r1(DisasContext *s, DisasOps *o)
+{
+    o->out = regs[get_field(s, r1)];
+    o->g_out = true;
+}
+#define SPEC_prep_r1 0
+
+static void prep_r1_P(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    o->out = regs[r1];
+    o->out2 = regs[r1 + 1];
+    o->g_out = o->g_out2 = true;
+}
+#define SPEC_prep_r1_P SPEC_r1_even
+
+/* Whenever we need x1 in addition to other inputs, we'll load it to out/out2 */
+static void prep_x1(DisasContext *s, DisasOps *o)
+{
+    o->out = load_freg(get_field(s, r1));
+    o->out2 = load_freg(get_field(s, r1) + 2);
+}
+#define SPEC_prep_x1 SPEC_r1_f128
+
+/* ====================================================================== */
+/* The "Write OUTput" generators.  These generally perform some non-trivial
+   copy of data to TCG globals, or to main memory.  The trivial cases are
+   generally handled by having a "prep" generator install the TCG global
+   as the destination of the operation.  */
+
+static void wout_r1(DisasContext *s, DisasOps *o)
+{
+    store_reg(get_field(s, r1), o->out);
+}
+#define SPEC_wout_r1 0
+
+static void wout_out2_r1(DisasContext *s, DisasOps *o)
+{
+    store_reg(get_field(s, r1), o->out2);
+}
+#define SPEC_wout_out2_r1 0
+
+static void wout_r1_8(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    tcg_gen_deposit_i64(regs[r1], regs[r1], o->out, 0, 8);
+}
+#define SPEC_wout_r1_8 0
+
+static void wout_r1_16(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    tcg_gen_deposit_i64(regs[r1], regs[r1], o->out, 0, 16);
+}
+#define SPEC_wout_r1_16 0
+
+static void wout_r1_32(DisasContext *s, DisasOps *o)
+{
+    store_reg32_i64(get_field(s, r1), o->out);
+}
+#define SPEC_wout_r1_32 0
+
+static void wout_r1_32h(DisasContext *s, DisasOps *o)
+{
+    store_reg32h_i64(get_field(s, r1), o->out);
+}
+#define SPEC_wout_r1_32h 0
+
+static void wout_r1_P32(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    store_reg32_i64(r1, o->out);
+    store_reg32_i64(r1 + 1, o->out2);
+}
+#define SPEC_wout_r1_P32 SPEC_r1_even
+
+static void wout_r1_D32(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    store_reg32_i64(r1 + 1, o->out);
+    tcg_gen_shri_i64(o->out, o->out, 32);
+    store_reg32_i64(r1, o->out);
+}
+#define SPEC_wout_r1_D32 SPEC_r1_even
+
+static void wout_r3_P32(DisasContext *s, DisasOps *o)
+{
+    int r3 = get_field(s, r3);
+    store_reg32_i64(r3, o->out);
+    store_reg32_i64(r3 + 1, o->out2);
+}
+#define SPEC_wout_r3_P32 SPEC_r3_even
+
+static void wout_r3_P64(DisasContext *s, DisasOps *o)
+{
+    int r3 = get_field(s, r3);
+    store_reg(r3, o->out);
+    store_reg(r3 + 1, o->out2);
+}
+#define SPEC_wout_r3_P64 SPEC_r3_even
+
+static void wout_e1(DisasContext *s, DisasOps *o)
+{
+    store_freg32_i64(get_field(s, r1), o->out);
+}
+#define SPEC_wout_e1 0
+
+static void wout_f1(DisasContext *s, DisasOps *o)
+{
+    store_freg(get_field(s, r1), o->out);
+}
+#define SPEC_wout_f1 0
+
+static void wout_x1(DisasContext *s, DisasOps *o)
+{
+    int f1 = get_field(s, r1);
+    store_freg(f1, o->out);
+    store_freg(f1 + 2, o->out2);
+}
+#define SPEC_wout_x1 SPEC_r1_f128
+
+static void wout_cond_r1r2_32(DisasContext *s, DisasOps *o)
+{
+    if (get_field(s, r1) != get_field(s, r2)) {
+        store_reg32_i64(get_field(s, r1), o->out);
+    }
+}
+#define SPEC_wout_cond_r1r2_32 0
+
+static void wout_cond_e1e2(DisasContext *s, DisasOps *o)
+{
+    if (get_field(s, r1) != get_field(s, r2)) {
+        store_freg32_i64(get_field(s, r1), o->out);
+    }
+}
+#define SPEC_wout_cond_e1e2 0
+
+static void wout_m1_8(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_qemu_st8(o->out, o->addr1, get_mem_index(s));
+}
+#define SPEC_wout_m1_8 0
+
+static void wout_m1_16(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_qemu_st16(o->out, o->addr1, get_mem_index(s));
+}
+#define SPEC_wout_m1_16 0
+
+#ifndef CONFIG_USER_ONLY
+static void wout_m1_16a(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_qemu_st_tl(o->out, o->addr1, get_mem_index(s), MO_TEUW | MO_ALIGN);
+}
+#define SPEC_wout_m1_16a 0
+#endif
+
+static void wout_m1_32(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_qemu_st32(o->out, o->addr1, get_mem_index(s));
+}
+#define SPEC_wout_m1_32 0
+
+#ifndef CONFIG_USER_ONLY
+static void wout_m1_32a(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_qemu_st_tl(o->out, o->addr1, get_mem_index(s), MO_TEUL | MO_ALIGN);
+}
+#define SPEC_wout_m1_32a 0
+#endif
+
+static void wout_m1_64(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_qemu_st64(o->out, o->addr1, get_mem_index(s));
+}
+#define SPEC_wout_m1_64 0
+
+#ifndef CONFIG_USER_ONLY
+static void wout_m1_64a(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_qemu_st_i64(o->out, o->addr1, get_mem_index(s), MO_TEQ | MO_ALIGN);
+}
+#define SPEC_wout_m1_64a 0
+#endif
+
+static void wout_m2_32(DisasContext *s, DisasOps *o)
+{
+    tcg_gen_qemu_st32(o->out, o->in2, get_mem_index(s));
+}
+#define SPEC_wout_m2_32 0
+
+static void wout_in2_r1(DisasContext *s, DisasOps *o)
+{
+    store_reg(get_field(s, r1), o->in2);
+}
+#define SPEC_wout_in2_r1 0
+
+static void wout_in2_r1_32(DisasContext *s, DisasOps *o)
+{
+    store_reg32_i64(get_field(s, r1), o->in2);
+}
+#define SPEC_wout_in2_r1_32 0
+
+/* ====================================================================== */
+/* The "INput 1" generators.  These load the first operand to an insn.  */
+
+static void in1_r1(DisasContext *s, DisasOps *o)
+{
+    o->in1 = load_reg(get_field(s, r1));
+}
+#define SPEC_in1_r1 0
+
+static void in1_r1_o(DisasContext *s, DisasOps *o)
+{
+    o->in1 = regs[get_field(s, r1)];
+    o->g_in1 = true;
+}
+#define SPEC_in1_r1_o 0
+
+static void in1_r1_32s(DisasContext *s, DisasOps *o)
+{
+    o->in1 = tcg_temp_new_i64();
+    tcg_gen_ext32s_i64(o->in1, regs[get_field(s, r1)]);
+}
+#define SPEC_in1_r1_32s 0
+
+static void in1_r1_32u(DisasContext *s, DisasOps *o)
+{
+    o->in1 = tcg_temp_new_i64();
+    tcg_gen_ext32u_i64(o->in1, regs[get_field(s, r1)]);
+}
+#define SPEC_in1_r1_32u 0
+
+static void in1_r1_sr32(DisasContext *s, DisasOps *o)
+{
+    o->in1 = tcg_temp_new_i64();
+    tcg_gen_shri_i64(o->in1, regs[get_field(s, r1)], 32);
+}
+#define SPEC_in1_r1_sr32 0
+
+static void in1_r1p1(DisasContext *s, DisasOps *o)
+{
+    o->in1 = load_reg(get_field(s, r1) + 1);
+}
+#define SPEC_in1_r1p1 SPEC_r1_even
+
+static void in1_r1p1_o(DisasContext *s, DisasOps *o)
+{
+    o->in1 = regs[get_field(s, r1) + 1];
+    o->g_in1 = true;
+}
+#define SPEC_in1_r1p1_o SPEC_r1_even
+
+static void in1_r1p1_32s(DisasContext *s, DisasOps *o)
+{
+    o->in1 = tcg_temp_new_i64();
+    tcg_gen_ext32s_i64(o->in1, regs[get_field(s, r1) + 1]);
+}
+#define SPEC_in1_r1p1_32s SPEC_r1_even
+
+static void in1_r1p1_32u(DisasContext *s, DisasOps *o)
+{
+    o->in1 = tcg_temp_new_i64();
+    tcg_gen_ext32u_i64(o->in1, regs[get_field(s, r1) + 1]);
+}
+#define SPEC_in1_r1p1_32u SPEC_r1_even
+
+static void in1_r1_D32(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    o->in1 = tcg_temp_new_i64();
+    tcg_gen_concat32_i64(o->in1, regs[r1 + 1], regs[r1]);
+}
+#define SPEC_in1_r1_D32 SPEC_r1_even
+
+static void in1_r2(DisasContext *s, DisasOps *o)
+{
+    o->in1 = load_reg(get_field(s, r2));
+}
+#define SPEC_in1_r2 0
+
+static void in1_r2_sr32(DisasContext *s, DisasOps *o)
+{
+    o->in1 = tcg_temp_new_i64();
+    tcg_gen_shri_i64(o->in1, regs[get_field(s, r2)], 32);
+}
+#define SPEC_in1_r2_sr32 0
+
+static void in1_r2_32u(DisasContext *s, DisasOps *o)
+{
+    o->in1 = tcg_temp_new_i64();
+    tcg_gen_ext32u_i64(o->in1, regs[get_field(s, r2)]);
+}
+#define SPEC_in1_r2_32u 0
+
+static void in1_r3(DisasContext *s, DisasOps *o)
+{
+    o->in1 = load_reg(get_field(s, r3));
+}
+#define SPEC_in1_r3 0
+
+static void in1_r3_o(DisasContext *s, DisasOps *o)
+{
+    o->in1 = regs[get_field(s, r3)];
+    o->g_in1 = true;
+}
+#define SPEC_in1_r3_o 0
+
+static void in1_r3_32s(DisasContext *s, DisasOps *o)
+{
+    o->in1 = tcg_temp_new_i64();
+    tcg_gen_ext32s_i64(o->in1, regs[get_field(s, r3)]);
+}
+#define SPEC_in1_r3_32s 0
+
+static void in1_r3_32u(DisasContext *s, DisasOps *o)
+{
+    o->in1 = tcg_temp_new_i64();
+    tcg_gen_ext32u_i64(o->in1, regs[get_field(s, r3)]);
+}
+#define SPEC_in1_r3_32u 0
+
+static void in1_r3_D32(DisasContext *s, DisasOps *o)
+{
+    int r3 = get_field(s, r3);
+    o->in1 = tcg_temp_new_i64();
+    tcg_gen_concat32_i64(o->in1, regs[r3 + 1], regs[r3]);
+}
+#define SPEC_in1_r3_D32 SPEC_r3_even
+
+static void in1_e1(DisasContext *s, DisasOps *o)
+{
+    o->in1 = load_freg32_i64(get_field(s, r1));
+}
+#define SPEC_in1_e1 0
+
+static void in1_f1(DisasContext *s, DisasOps *o)
+{
+    o->in1 = load_freg(get_field(s, r1));
+}
+#define SPEC_in1_f1 0
+
+/* Load the high double word of an extended (128-bit) format FP number */
+static void in1_x2h(DisasContext *s, DisasOps *o)
+{
+    o->in1 = load_freg(get_field(s, r2));
+}
+#define SPEC_in1_x2h SPEC_r2_f128
+
+static void in1_f3(DisasContext *s, DisasOps *o)
+{
+    o->in1 = load_freg(get_field(s, r3));
+}
+#define SPEC_in1_f3 0
+
+static void in1_la1(DisasContext *s, DisasOps *o)
+{
+    o->addr1 = get_address(s, 0, get_field(s, b1), get_field(s, d1));
+}
+#define SPEC_in1_la1 0
+
+static void in1_la2(DisasContext *s, DisasOps *o)
+{
+    int x2 = have_field(s, x2) ? get_field(s, x2) : 0;
+    o->addr1 = get_address(s, x2, get_field(s, b2), get_field(s, d2));
+}
+#define SPEC_in1_la2 0
+
+static void in1_m1_8u(DisasContext *s, DisasOps *o)
+{
+    in1_la1(s, o);
+    o->in1 = tcg_temp_new_i64();
+    tcg_gen_qemu_ld8u(o->in1, o->addr1, get_mem_index(s));
+}
+#define SPEC_in1_m1_8u 0
+
+static void in1_m1_16s(DisasContext *s, DisasOps *o)
+{
+    in1_la1(s, o);
+    o->in1 = tcg_temp_new_i64();
+    tcg_gen_qemu_ld16s(o->in1, o->addr1, get_mem_index(s));
+}
+#define SPEC_in1_m1_16s 0
+
+static void in1_m1_16u(DisasContext *s, DisasOps *o)
+{
+    in1_la1(s, o);
+    o->in1 = tcg_temp_new_i64();
+    tcg_gen_qemu_ld16u(o->in1, o->addr1, get_mem_index(s));
+}
+#define SPEC_in1_m1_16u 0
+
+static void in1_m1_32s(DisasContext *s, DisasOps *o)
+{
+    in1_la1(s, o);
+    o->in1 = tcg_temp_new_i64();
+    tcg_gen_qemu_ld32s(o->in1, o->addr1, get_mem_index(s));
+}
+#define SPEC_in1_m1_32s 0
+
+static void in1_m1_32u(DisasContext *s, DisasOps *o)
+{
+    in1_la1(s, o);
+    o->in1 = tcg_temp_new_i64();
+    tcg_gen_qemu_ld32u(o->in1, o->addr1, get_mem_index(s));
+}
+#define SPEC_in1_m1_32u 0
+
+static void in1_m1_64(DisasContext *s, DisasOps *o)
+{
+    in1_la1(s, o);
+    o->in1 = tcg_temp_new_i64();
+    tcg_gen_qemu_ld64(o->in1, o->addr1, get_mem_index(s));
+}
+#define SPEC_in1_m1_64 0
+
+/* ====================================================================== */
+/* The "INput 2" generators.  These load the second operand to an insn.  */
+
+static void in2_r1_o(DisasContext *s, DisasOps *o)
+{
+    o->in2 = regs[get_field(s, r1)];
+    o->g_in2 = true;
+}
+#define SPEC_in2_r1_o 0
+
+static void in2_r1_16u(DisasContext *s, DisasOps *o)
+{
+    o->in2 = tcg_temp_new_i64();
+    tcg_gen_ext16u_i64(o->in2, regs[get_field(s, r1)]);
+}
+#define SPEC_in2_r1_16u 0
+
+static void in2_r1_32u(DisasContext *s, DisasOps *o)
+{
+    o->in2 = tcg_temp_new_i64();
+    tcg_gen_ext32u_i64(o->in2, regs[get_field(s, r1)]);
+}
+#define SPEC_in2_r1_32u 0
+
+static void in2_r1_D32(DisasContext *s, DisasOps *o)
+{
+    int r1 = get_field(s, r1);
+    o->in2 = tcg_temp_new_i64();
+    tcg_gen_concat32_i64(o->in2, regs[r1 + 1], regs[r1]);
+}
+#define SPEC_in2_r1_D32 SPEC_r1_even
+
+static void in2_r2(DisasContext *s, DisasOps *o)
+{
+    o->in2 = load_reg(get_field(s, r2));
+}
+#define SPEC_in2_r2 0
+
+static void in2_r2_o(DisasContext *s, DisasOps *o)
+{
+    o->in2 = regs[get_field(s, r2)];
+    o->g_in2 = true;
+}
+#define SPEC_in2_r2_o 0
+
+static void in2_r2_nz(DisasContext *s, DisasOps *o)
+{
+    int r2 = get_field(s, r2);
+    if (r2 != 0) {
+        o->in2 = load_reg(r2);
+    }
+}
+#define SPEC_in2_r2_nz 0
+
+static void in2_r2_8s(DisasContext *s, DisasOps *o)
+{
+    o->in2 = tcg_temp_new_i64();
+    tcg_gen_ext8s_i64(o->in2, regs[get_field(s, r2)]);
+}
+#define SPEC_in2_r2_8s 0
+
+static void in2_r2_8u(DisasContext *s, DisasOps *o)
+{
+    o->in2 = tcg_temp_new_i64();
+    tcg_gen_ext8u_i64(o->in2, regs[get_field(s, r2)]);
+}
+#define SPEC_in2_r2_8u 0
+
+static void in2_r2_16s(DisasContext *s, DisasOps *o)
+{
+    o->in2 = tcg_temp_new_i64();
+    tcg_gen_ext16s_i64(o->in2, regs[get_field(s, r2)]);
+}
+#define SPEC_in2_r2_16s 0
+
+static void in2_r2_16u(DisasContext *s, DisasOps *o)
+{
+    o->in2 = tcg_temp_new_i64();
+    tcg_gen_ext16u_i64(o->in2, regs[get_field(s, r2)]);
+}
+#define SPEC_in2_r2_16u 0
+
+static void in2_r3(DisasContext *s, DisasOps *o)
+{
+    o->in2 = load_reg(get_field(s, r3));
+}
+#define SPEC_in2_r3 0
+
+static void in2_r3_sr32(DisasContext *s, DisasOps *o)
+{
+    o->in2 = tcg_temp_new_i64();
+    tcg_gen_shri_i64(o->in2, regs[get_field(s, r3)], 32);
+}
+#define SPEC_in2_r3_sr32 0
+
+static void in2_r3_32u(DisasContext *s, DisasOps *o)
+{
+    o->in2 = tcg_temp_new_i64();
+    tcg_gen_ext32u_i64(o->in2, regs[get_field(s, r3)]);
+}
+#define SPEC_in2_r3_32u 0
+
+static void in2_r2_32s(DisasContext *s, DisasOps *o)
+{
+    o->in2 = tcg_temp_new_i64();
+    tcg_gen_ext32s_i64(o->in2, regs[get_field(s, r2)]);
+}
+#define SPEC_in2_r2_32s 0
+
+static void in2_r2_32u(DisasContext *s, DisasOps *o)
+{
+    o->in2 = tcg_temp_new_i64();
+    tcg_gen_ext32u_i64(o->in2, regs[get_field(s, r2)]);
+}
+#define SPEC_in2_r2_32u 0
+
+static void in2_r2_sr32(DisasContext *s, DisasOps *o)
+{
+    o->in2 = tcg_temp_new_i64();
+    tcg_gen_shri_i64(o->in2, regs[get_field(s, r2)], 32);
+}
+#define SPEC_in2_r2_sr32 0
+
+static void in2_e2(DisasContext *s, DisasOps *o)
+{
+    o->in2 = load_freg32_i64(get_field(s, r2));
+}
+#define SPEC_in2_e2 0
+
+static void in2_f2(DisasContext *s, DisasOps *o)
+{
+    o->in2 = load_freg(get_field(s, r2));
+}
+#define SPEC_in2_f2 0
+
+/* Load the low double word of an extended (128-bit) format FP number */
+static void in2_x2l(DisasContext *s, DisasOps *o)
+{
+    o->in2 = load_freg(get_field(s, r2) + 2);
+}
+#define SPEC_in2_x2l SPEC_r2_f128
+
+static void in2_ra2(DisasContext *s, DisasOps *o)
+{
+    int r2 = get_field(s, r2);
+
+    /* Note: *don't* treat !r2 as 0, use the reg value. */
+    o->in2 = tcg_temp_new_i64();
+    gen_addi_and_wrap_i64(s, o->in2, regs[r2], 0);
+}
+#define SPEC_in2_ra2 0
+
+static void in2_a2(DisasContext *s, DisasOps *o)
+{
+    int x2 = have_field(s, x2) ? get_field(s, x2) : 0;
+    o->in2 = get_address(s, x2, get_field(s, b2), get_field(s, d2));
+}
+#define SPEC_in2_a2 0
+
+static void in2_ri2(DisasContext *s, DisasOps *o)
+{
+    o->in2 = tcg_const_i64(s->base.pc_next + (int64_t)get_field(s, i2) * 2);
+}
+#define SPEC_in2_ri2 0
+
+static void in2_sh32(DisasContext *s, DisasOps *o)
+{
+    help_l2_shift(s, o, 31);
+}
+#define SPEC_in2_sh32 0
+
+static void in2_sh64(DisasContext *s, DisasOps *o)
+{
+    help_l2_shift(s, o, 63);
+}
+#define SPEC_in2_sh64 0
+
+static void in2_m2_8u(DisasContext *s, DisasOps *o)
+{
+    in2_a2(s, o);
+    tcg_gen_qemu_ld8u(o->in2, o->in2, get_mem_index(s));
+}
+#define SPEC_in2_m2_8u 0
+
+static void in2_m2_16s(DisasContext *s, DisasOps *o)
+{
+    in2_a2(s, o);
+    tcg_gen_qemu_ld16s(o->in2, o->in2, get_mem_index(s));
+}
+#define SPEC_in2_m2_16s 0
+
+static void in2_m2_16u(DisasContext *s, DisasOps *o)
+{
+    in2_a2(s, o);
+    tcg_gen_qemu_ld16u(o->in2, o->in2, get_mem_index(s));
+}
+#define SPEC_in2_m2_16u 0
+
+static void in2_m2_32s(DisasContext *s, DisasOps *o)
+{
+    in2_a2(s, o);
+    tcg_gen_qemu_ld32s(o->in2, o->in2, get_mem_index(s));
+}
+#define SPEC_in2_m2_32s 0
+
+static void in2_m2_32u(DisasContext *s, DisasOps *o)
+{
+    in2_a2(s, o);
+    tcg_gen_qemu_ld32u(o->in2, o->in2, get_mem_index(s));
+}
+#define SPEC_in2_m2_32u 0
+
+#ifndef CONFIG_USER_ONLY
+static void in2_m2_32ua(DisasContext *s, DisasOps *o)
+{
+    in2_a2(s, o);
+    tcg_gen_qemu_ld_tl(o->in2, o->in2, get_mem_index(s), MO_TEUL | MO_ALIGN);
+}
+#define SPEC_in2_m2_32ua 0
+#endif
+
+static void in2_m2_64(DisasContext *s, DisasOps *o)
+{
+    in2_a2(s, o);
+    tcg_gen_qemu_ld64(o->in2, o->in2, get_mem_index(s));
+}
+#define SPEC_in2_m2_64 0
+
+static void in2_m2_64w(DisasContext *s, DisasOps *o)
+{
+    in2_a2(s, o);
+    tcg_gen_qemu_ld64(o->in2, o->in2, get_mem_index(s));
+    gen_addi_and_wrap_i64(s, o->in2, o->in2, 0);
+}
+#define SPEC_in2_m2_64w 0
+
+#ifndef CONFIG_USER_ONLY
+static void in2_m2_64a(DisasContext *s, DisasOps *o)
+{
+    in2_a2(s, o);
+    tcg_gen_qemu_ld_i64(o->in2, o->in2, get_mem_index(s), MO_TEQ | MO_ALIGN);
+}
+#define SPEC_in2_m2_64a 0
+#endif
+
+static void in2_mri2_16u(DisasContext *s, DisasOps *o)
+{
+    in2_ri2(s, o);
+    tcg_gen_qemu_ld16u(o->in2, o->in2, get_mem_index(s));
+}
+#define SPEC_in2_mri2_16u 0
+
+static void in2_mri2_32s(DisasContext *s, DisasOps *o)
+{
+    in2_ri2(s, o);
+    tcg_gen_qemu_ld32s(o->in2, o->in2, get_mem_index(s));
+}
+#define SPEC_in2_mri2_32s 0
+
+static void in2_mri2_32u(DisasContext *s, DisasOps *o)
+{
+    in2_ri2(s, o);
+    tcg_gen_qemu_ld32u(o->in2, o->in2, get_mem_index(s));
+}
+#define SPEC_in2_mri2_32u 0
+
+static void in2_mri2_64(DisasContext *s, DisasOps *o)
+{
+    in2_ri2(s, o);
+    tcg_gen_qemu_ld64(o->in2, o->in2, get_mem_index(s));
+}
+#define SPEC_in2_mri2_64 0
+
+static void in2_i2(DisasContext *s, DisasOps *o)
+{
+    o->in2 = tcg_const_i64(get_field(s, i2));
+}
+#define SPEC_in2_i2 0
+
+static void in2_i2_8u(DisasContext *s, DisasOps *o)
+{
+    o->in2 = tcg_const_i64((uint8_t)get_field(s, i2));
+}
+#define SPEC_in2_i2_8u 0
+
+static void in2_i2_16u(DisasContext *s, DisasOps *o)
+{
+    o->in2 = tcg_const_i64((uint16_t)get_field(s, i2));
+}
+#define SPEC_in2_i2_16u 0
+
+static void in2_i2_32u(DisasContext *s, DisasOps *o)
+{
+    o->in2 = tcg_const_i64((uint32_t)get_field(s, i2));
+}
+#define SPEC_in2_i2_32u 0
+
+static void in2_i2_16u_shl(DisasContext *s, DisasOps *o)
+{
+    uint64_t i2 = (uint16_t)get_field(s, i2);
+    o->in2 = tcg_const_i64(i2 << s->insn->data);
+}
+#define SPEC_in2_i2_16u_shl 0
+
+static void in2_i2_32u_shl(DisasContext *s, DisasOps *o)
+{
+    uint64_t i2 = (uint32_t)get_field(s, i2);
+    o->in2 = tcg_const_i64(i2 << s->insn->data);
+}
+#define SPEC_in2_i2_32u_shl 0
+
+#ifndef CONFIG_USER_ONLY
+static void in2_insn(DisasContext *s, DisasOps *o)
+{
+    o->in2 = tcg_const_i64(s->fields.raw_insn);
+}
+#define SPEC_in2_insn 0
+#endif
+
+/* ====================================================================== */
+
+/* Find opc within the table of insns.  This is formulated as a switch
+   statement so that (1) we get compile-time notice of cut-paste errors
+   for duplicated opcodes, and (2) the compiler generates the binary
+   search tree, rather than us having to post-process the table.  */
+
+#define C(OPC, NM, FT, FC, I1, I2, P, W, OP, CC) \
+    E(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, 0, 0)
+
+#define D(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D) \
+    E(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D, 0)
+
+#define F(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, FL) \
+    E(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, 0, FL)
+
+#define E(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D, FL) insn_ ## NM,
+
+enum DisasInsnEnum {
+#include "insn-data.def"
+};
+
+#undef E
+#define E(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D, FL) {                   \
+    .opc = OPC,                                                             \
+    .flags = FL,                                                            \
+    .fmt = FMT_##FT,                                                        \
+    .fac = FAC_##FC,                                                        \
+    .spec = SPEC_in1_##I1 | SPEC_in2_##I2 | SPEC_prep_##P | SPEC_wout_##W,  \
+    .name = #NM,                                                            \
+    .help_in1 = in1_##I1,                                                   \
+    .help_in2 = in2_##I2,                                                   \
+    .help_prep = prep_##P,                                                  \
+    .help_wout = wout_##W,                                                  \
+    .help_cout = cout_##CC,                                                 \
+    .help_op = op_##OP,                                                     \
+    .data = D                                                               \
+ },
+
+/* Allow 0 to be used for NULL in the table below.  */
+#define in1_0  NULL
+#define in2_0  NULL
+#define prep_0  NULL
+#define wout_0  NULL
+#define cout_0  NULL
+#define op_0  NULL
+
+#define SPEC_in1_0 0
+#define SPEC_in2_0 0
+#define SPEC_prep_0 0
+#define SPEC_wout_0 0
+
+/* Give smaller names to the various facilities.  */
+#define FAC_Z           S390_FEAT_ZARCH
+#define FAC_CASS        S390_FEAT_COMPARE_AND_SWAP_AND_STORE
+#define FAC_DFP         S390_FEAT_DFP
+#define FAC_DFPR        S390_FEAT_FLOATING_POINT_SUPPPORT_ENH /* DFP-rounding */
+#define FAC_DO          S390_FEAT_STFLE_45 /* distinct-operands */
+#define FAC_EE          S390_FEAT_EXECUTE_EXT
+#define FAC_EI          S390_FEAT_EXTENDED_IMMEDIATE
+#define FAC_FPE         S390_FEAT_FLOATING_POINT_EXT
+#define FAC_FPSSH       S390_FEAT_FLOATING_POINT_SUPPPORT_ENH /* FPS-sign-handling */
+#define FAC_FPRGR       S390_FEAT_FLOATING_POINT_SUPPPORT_ENH /* FPR-GR-transfer */
+#define FAC_GIE         S390_FEAT_GENERAL_INSTRUCTIONS_EXT
+#define FAC_HFP_MA      S390_FEAT_HFP_MADDSUB
+#define FAC_HW          S390_FEAT_STFLE_45 /* high-word */
+#define FAC_IEEEE_SIM   S390_FEAT_FLOATING_POINT_SUPPPORT_ENH /* IEEE-exception-simulation */
+#define FAC_MIE         S390_FEAT_STFLE_49 /* misc-instruction-extensions */
+#define FAC_LAT         S390_FEAT_STFLE_49 /* load-and-trap */
+#define FAC_LOC         S390_FEAT_STFLE_45 /* load/store on condition 1 */
+#define FAC_LOC2        S390_FEAT_STFLE_53 /* load/store on condition 2 */
+#define FAC_LD          S390_FEAT_LONG_DISPLACEMENT
+#define FAC_PC          S390_FEAT_STFLE_45 /* population count */
+#define FAC_SCF         S390_FEAT_STORE_CLOCK_FAST
+#define FAC_SFLE        S390_FEAT_STFLE
+#define FAC_ILA         S390_FEAT_STFLE_45 /* interlocked-access-facility 1 */
+#define FAC_MVCOS       S390_FEAT_MOVE_WITH_OPTIONAL_SPEC
+#define FAC_LPP         S390_FEAT_SET_PROGRAM_PARAMETERS /* load-program-parameter */
+#define FAC_DAT_ENH     S390_FEAT_DAT_ENH
+#define FAC_E2          S390_FEAT_EXTENDED_TRANSLATION_2
+#define FAC_EH          S390_FEAT_STFLE_49 /* execution-hint */
+#define FAC_PPA         S390_FEAT_STFLE_49 /* processor-assist */
+#define FAC_LZRB        S390_FEAT_STFLE_53 /* load-and-zero-rightmost-byte */
+#define FAC_ETF3        S390_FEAT_EXTENDED_TRANSLATION_3
+#define FAC_MSA         S390_FEAT_MSA /* message-security-assist facility */
+#define FAC_MSA3        S390_FEAT_MSA_EXT_3 /* msa-extension-3 facility */
+#define FAC_MSA4        S390_FEAT_MSA_EXT_4 /* msa-extension-4 facility */
+#define FAC_MSA5        S390_FEAT_MSA_EXT_5 /* msa-extension-5 facility */
+#define FAC_MSA8        S390_FEAT_MSA_EXT_8 /* msa-extension-8 facility */
+#define FAC_ECT         S390_FEAT_EXTRACT_CPU_TIME
+#define FAC_PCI         S390_FEAT_ZPCI /* z/PCI facility */
+#define FAC_AIS         S390_FEAT_ADAPTER_INT_SUPPRESSION
+#define FAC_V           S390_FEAT_VECTOR /* vector facility */
+#define FAC_VE          S390_FEAT_VECTOR_ENH /* vector enhancements facility 1 */
+#define FAC_MIE2        S390_FEAT_MISC_INSTRUCTION_EXT2 /* miscellaneous-instruction-extensions facility 2 */
+
+static const DisasInsn insn_info[] = {
+#include "insn-data.def"
+};
+
+#undef E
+#define E(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D, FL) \
+    case OPC: return &insn_info[insn_ ## NM];
+
+static const DisasInsn *lookup_opc(uint16_t opc)
+{
+    switch (opc) {
+#include "insn-data.def"
+    default:
+        return NULL;
+    }
+}
+
+#undef F
+#undef E
+#undef D
+#undef C
+
+/* Extract a field from the insn.  The INSN should be left-aligned in
+   the uint64_t so that we can more easily utilize the big-bit-endian
+   definitions we extract from the Principals of Operation.  */
+
+static void extract_field(DisasFields *o, const DisasField *f, uint64_t insn)
+{
+    uint32_t r, m;
+
+    if (f->size == 0) {
+        return;
+    }
+
+    /* Zero extract the field from the insn.  */
+    r = (insn << f->beg) >> (64 - f->size);
+
+    /* Sign-extend, or un-swap the field as necessary.  */
+    switch (f->type) {
+    case 0: /* unsigned */
+        break;
+    case 1: /* signed */
+        assert(f->size <= 32);
+        m = 1u << (f->size - 1);
+        r = (r ^ m) - m;
+        break;
+    case 2: /* dl+dh split, signed 20 bit. */
+        r = ((int8_t)r << 12) | (r >> 8);
+        break;
+    case 3: /* MSB stored in RXB */
+        g_assert(f->size == 4);
+        switch (f->beg) {
+        case 8:
+            r |= extract64(insn, 63 - 36, 1) << 4;
+            break;
+        case 12:
+            r |= extract64(insn, 63 - 37, 1) << 4;
+            break;
+        case 16:
+            r |= extract64(insn, 63 - 38, 1) << 4;
+            break;
+        case 32:
+            r |= extract64(insn, 63 - 39, 1) << 4;
+            break;
+        default:
+            g_assert_not_reached();
+        }
+        break;
+    default:
+        abort();
+    }
+
+    /*
+     * Validate that the "compressed" encoding we selected above is valid.
+     * I.e. we haven't made two different original fields overlap.
+     */
+    assert(((o->presentC >> f->indexC) & 1) == 0);
+    o->presentC |= 1 << f->indexC;
+    o->presentO |= 1 << f->indexO;
+
+    o->c[f->indexC] = r;
+}
+
+/* Lookup the insn at the current PC, extracting the operands into O and
+   returning the info struct for the insn.  Returns NULL for invalid insn.  */
+
+static const DisasInsn *extract_insn(CPUS390XState *env, DisasContext *s)
+{
+    uint64_t insn, pc = s->base.pc_next;
+    int op, op2, ilen;
+    const DisasInsn *info;
+
+    if (unlikely(s->ex_value)) {
+        /* Drop the EX data now, so that it's clear on exception paths.  */
+        TCGv_i64 zero = tcg_const_i64(0);
+        tcg_gen_st_i64(zero, cpu_env, offsetof(CPUS390XState, ex_value));
+        tcg_temp_free_i64(zero);
+
+        /* Extract the values saved by EXECUTE.  */
+        insn = s->ex_value & 0xffffffffffff0000ull;
+        ilen = s->ex_value & 0xf;
+        op = insn >> 56;
+    } else {
+        insn = ld_code2(env, pc);
+        op = (insn >> 8) & 0xff;
+        ilen = get_ilen(op);
+        switch (ilen) {
+        case 2:
+            insn = insn << 48;
+            break;
+        case 4:
+            insn = ld_code4(env, pc) << 32;
+            break;
+        case 6:
+            insn = (insn << 48) | (ld_code4(env, pc + 2) << 16);
+            break;
+        default:
+            g_assert_not_reached();
+        }
+    }
+    s->pc_tmp = s->base.pc_next + ilen;
+    s->ilen = ilen;
+
+    /* We can't actually determine the insn format until we've looked up
+       the full insn opcode.  Which we can't do without locating the
+       secondary opcode.  Assume by default that OP2 is at bit 40; for
+       those smaller insns that don't actually have a secondary opcode
+       this will correctly result in OP2 = 0. */
+    switch (op) {
+    case 0x01: /* E */
+    case 0x80: /* S */
+    case 0x82: /* S */
+    case 0x93: /* S */
+    case 0xb2: /* S, RRF, RRE, IE */
+    case 0xb3: /* RRE, RRD, RRF */
+    case 0xb9: /* RRE, RRF */
+    case 0xe5: /* SSE, SIL */
+        op2 = (insn << 8) >> 56;
+        break;
+    case 0xa5: /* RI */
+    case 0xa7: /* RI */
+    case 0xc0: /* RIL */
+    case 0xc2: /* RIL */
+    case 0xc4: /* RIL */
+    case 0xc6: /* RIL */
+    case 0xc8: /* SSF */
+    case 0xcc: /* RIL */
+        op2 = (insn << 12) >> 60;
+        break;
+    case 0xc5: /* MII */
+    case 0xc7: /* SMI */
+    case 0xd0 ... 0xdf: /* SS */
+    case 0xe1: /* SS */
+    case 0xe2: /* SS */
+    case 0xe8: /* SS */
+    case 0xe9: /* SS */
+    case 0xea: /* SS */
+    case 0xee ... 0xf3: /* SS */
+    case 0xf8 ... 0xfd: /* SS */
+        op2 = 0;
+        break;
+    default:
+        op2 = (insn << 40) >> 56;
+        break;
+    }
+
+    memset(&s->fields, 0, sizeof(s->fields));
+    s->fields.raw_insn = insn;
+    s->fields.op = op;
+    s->fields.op2 = op2;
+
+    /* Lookup the instruction.  */
+    info = lookup_opc(op << 8 | op2);
+    s->insn = info;
+
+    /* If we found it, extract the operands.  */
+    if (info != NULL) {
+        DisasFormat fmt = info->fmt;
+        int i;
+
+        for (i = 0; i < NUM_C_FIELD; ++i) {
+            extract_field(&s->fields, &format_info[fmt].op[i], insn);
+        }
+    }
+    return info;
+}
+
+static bool is_afp_reg(int reg)
+{
+    return reg % 2 || reg > 6;
+}
+
+static bool is_fp_pair(int reg)
+{
+    /* 0,1,4,5,8,9,12,13: to exclude the others, check for single bit */
+    return !(reg & 0x2);
+}
+
+static DisasJumpType translate_one(CPUS390XState *env, DisasContext *s)
+{
+    const DisasInsn *insn;
+    DisasJumpType ret = DISAS_NEXT;
+    DisasOps o = {};
+    bool icount = false;
+
+    /* Search for the insn in the table.  */
+    insn = extract_insn(env, s);
+
+    /* Emit insn_start now that we know the ILEN.  */
+    tcg_gen_insn_start(s->base.pc_next, s->cc_op, s->ilen);
+
+    /* Not found means unimplemented/illegal opcode.  */
+    if (insn == NULL) {
+        qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%02x%02x\n",
+                      s->fields.op, s->fields.op2);
+        gen_illegal_opcode(s);
+        ret = DISAS_NORETURN;
+        goto out;
+    }
+
+#ifndef CONFIG_USER_ONLY
+    if (s->base.tb->flags & FLAG_MASK_PER) {
+        TCGv_i64 addr = tcg_const_i64(s->base.pc_next);
+        gen_helper_per_ifetch(cpu_env, addr);
+        tcg_temp_free_i64(addr);
+    }
+#endif
+
+    /* process flags */
+    if (insn->flags) {
+        /* privileged instruction */
+        if ((s->base.tb->flags & FLAG_MASK_PSTATE) && (insn->flags & IF_PRIV)) {
+            gen_program_exception(s, PGM_PRIVILEGED);
+            ret = DISAS_NORETURN;
+            goto out;
+        }
+
+        /* if AFP is not enabled, instructions and registers are forbidden */
+        if (!(s->base.tb->flags & FLAG_MASK_AFP)) {
+            uint8_t dxc = 0;
+
+            if ((insn->flags & IF_AFP1) && is_afp_reg(get_field(s, r1))) {
+                dxc = 1;
+            }
+            if ((insn->flags & IF_AFP2) && is_afp_reg(get_field(s, r2))) {
+                dxc = 1;
+            }
+            if ((insn->flags & IF_AFP3) && is_afp_reg(get_field(s, r3))) {
+                dxc = 1;
+            }
+            if (insn->flags & IF_BFP) {
+                dxc = 2;
+            }
+            if (insn->flags & IF_DFP) {
+                dxc = 3;
+            }
+            if (insn->flags & IF_VEC) {
+                dxc = 0xfe;
+            }
+            if (dxc) {
+                gen_data_exception(dxc);
+                ret = DISAS_NORETURN;
+                goto out;
+            }
+        }
+
+        /* if vector instructions not enabled, executing them is forbidden */
+        if (insn->flags & IF_VEC) {
+            if (!((s->base.tb->flags & FLAG_MASK_VECTOR))) {
+                gen_data_exception(0xfe);
+                ret = DISAS_NORETURN;
+                goto out;
+            }
+        }
+
+        /* input/output is the special case for icount mode */
+        if (unlikely(insn->flags & IF_IO)) {
+            icount = tb_cflags(s->base.tb) & CF_USE_ICOUNT;
+            if (icount) {
+                gen_io_start();
+            }
+        }
+    }
+
+    /* Check for insn specification exceptions.  */
+    if (insn->spec) {
+        if ((insn->spec & SPEC_r1_even && get_field(s, r1) & 1) ||
+            (insn->spec & SPEC_r2_even && get_field(s, r2) & 1) ||
+            (insn->spec & SPEC_r3_even && get_field(s, r3) & 1) ||
+            (insn->spec & SPEC_r1_f128 && !is_fp_pair(get_field(s, r1))) ||
+            (insn->spec & SPEC_r2_f128 && !is_fp_pair(get_field(s, r2)))) {
+            gen_program_exception(s, PGM_SPECIFICATION);
+            ret = DISAS_NORETURN;
+            goto out;
+        }
+    }
+
+    /* Implement the instruction.  */
+    if (insn->help_in1) {
+        insn->help_in1(s, &o);
+    }
+    if (insn->help_in2) {
+        insn->help_in2(s, &o);
+    }
+    if (insn->help_prep) {
+        insn->help_prep(s, &o);
+    }
+    if (insn->help_op) {
+        ret = insn->help_op(s, &o);
+    }
+    if (ret != DISAS_NORETURN) {
+        if (insn->help_wout) {
+            insn->help_wout(s, &o);
+        }
+        if (insn->help_cout) {
+            insn->help_cout(s, &o);
+        }
+    }
+
+    /* Free any temporaries created by the helpers.  */
+    if (o.out && !o.g_out) {
+        tcg_temp_free_i64(o.out);
+    }
+    if (o.out2 && !o.g_out2) {
+        tcg_temp_free_i64(o.out2);
+    }
+    if (o.in1 && !o.g_in1) {
+        tcg_temp_free_i64(o.in1);
+    }
+    if (o.in2 && !o.g_in2) {
+        tcg_temp_free_i64(o.in2);
+    }
+    if (o.addr1) {
+        tcg_temp_free_i64(o.addr1);
+    }
+
+    /* io should be the last instruction in tb when icount is enabled */
+    if (unlikely(icount && ret == DISAS_NEXT)) {
+        ret = DISAS_PC_STALE;
+    }
+
+#ifndef CONFIG_USER_ONLY
+    if (s->base.tb->flags & FLAG_MASK_PER) {
+        /* An exception might be triggered, save PSW if not already done.  */
+        if (ret == DISAS_NEXT || ret == DISAS_PC_STALE) {
+            tcg_gen_movi_i64(psw_addr, s->pc_tmp);
+        }
+
+        /* Call the helper to check for a possible PER exception.  */
+        gen_helper_per_check_exception(cpu_env);
+    }
+#endif
+
+out:
+    /* Advance to the next instruction.  */
+    s->base.pc_next = s->pc_tmp;
+    return ret;
+}
+
+static void s390x_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
+{
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+
+    /* 31-bit mode */
+    if (!(dc->base.tb->flags & FLAG_MASK_64)) {
+        dc->base.pc_first &= 0x7fffffff;
+        dc->base.pc_next = dc->base.pc_first;
+    }
+
+    dc->cc_op = CC_OP_DYNAMIC;
+    dc->ex_value = dc->base.tb->cs_base;
+    dc->do_debug = dc->base.singlestep_enabled;
+}
+
+static void s390x_tr_tb_start(DisasContextBase *db, CPUState *cs)
+{
+}
+
+static void s390x_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
+{
+}
+
+static bool s390x_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs,
+                                      const CPUBreakpoint *bp)
+{
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+
+    /*
+     * Emit an insn_start to accompany the breakpoint exception.
+     * The ILEN value is a dummy, since this does not result in
+     * an s390x exception, but an internal qemu exception which
+     * brings us back to interact with the gdbstub.
+     */
+    tcg_gen_insn_start(dc->base.pc_next, dc->cc_op, 2);
+
+    dc->base.is_jmp = DISAS_PC_STALE;
+    dc->do_debug = true;
+    /* The address covered by the breakpoint must be included in
+       [tb->pc, tb->pc + tb->size) in order to for it to be
+       properly cleared -- thus we increment the PC here so that
+       the logic setting tb->size does the right thing.  */
+    dc->base.pc_next += 2;
+    return true;
+}
+
+static void s390x_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
+{
+    CPUS390XState *env = cs->env_ptr;
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+
+    dc->base.is_jmp = translate_one(env, dc);
+    if (dc->base.is_jmp == DISAS_NEXT) {
+        uint64_t page_start;
+
+        page_start = dc->base.pc_first & TARGET_PAGE_MASK;
+        if (dc->base.pc_next - page_start >= TARGET_PAGE_SIZE || dc->ex_value) {
+            dc->base.is_jmp = DISAS_TOO_MANY;
+        }
+    }
+}
+
+static void s390x_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
+{
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+
+    switch (dc->base.is_jmp) {
+    case DISAS_GOTO_TB:
+    case DISAS_NORETURN:
+        break;
+    case DISAS_TOO_MANY:
+    case DISAS_PC_STALE:
+    case DISAS_PC_STALE_NOCHAIN:
+        update_psw_addr(dc);
+        /* FALLTHRU */
+    case DISAS_PC_UPDATED:
+        /* Next TB starts off with CC_OP_DYNAMIC, so make sure the
+           cc op type is in env */
+        update_cc_op(dc);
+        /* FALLTHRU */
+    case DISAS_PC_CC_UPDATED:
+        /* Exit the TB, either by raising a debug exception or by return.  */
+        if (dc->do_debug) {
+            gen_exception(EXCP_DEBUG);
+        } else if ((dc->base.tb->flags & FLAG_MASK_PER) ||
+                   dc->base.is_jmp == DISAS_PC_STALE_NOCHAIN) {
+            tcg_gen_exit_tb(NULL, 0);
+        } else {
+            tcg_gen_lookup_and_goto_ptr();
+        }
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+static void s390x_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs)
+{
+    DisasContext *dc = container_of(dcbase, DisasContext, base);
+
+    if (unlikely(dc->ex_value)) {
+        /* ??? Unfortunately log_target_disas can't use host memory.  */
+        qemu_log("IN: EXECUTE %016" PRIx64, dc->ex_value);
+    } else {
+        qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
+        log_target_disas(cs, dc->base.pc_first, dc->base.tb->size);
+    }
+}
+
+static const TranslatorOps s390x_tr_ops = {
+    .init_disas_context = s390x_tr_init_disas_context,
+    .tb_start           = s390x_tr_tb_start,
+    .insn_start         = s390x_tr_insn_start,
+    .breakpoint_check   = s390x_tr_breakpoint_check,
+    .translate_insn     = s390x_tr_translate_insn,
+    .tb_stop            = s390x_tr_tb_stop,
+    .disas_log          = s390x_tr_disas_log,
+};
+
+void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
+{
+    DisasContext dc;
+
+    translator_loop(&s390x_tr_ops, &dc.base, cs, tb, max_insns);
+}
+
+void restore_state_to_opc(CPUS390XState *env, TranslationBlock *tb,
+                          target_ulong *data)
+{
+    int cc_op = data[1];
+
+    env->psw.addr = data[0];
+
+    /* Update the CC opcode if it is not already up-to-date.  */
+    if ((cc_op != CC_OP_DYNAMIC) && (cc_op != CC_OP_STATIC)) {
+        env->cc_op = cc_op;
+    }
+
+    /* Record ILEN.  */
+    env->int_pgm_ilen = data[2];
+}
diff --git a/target/s390x/tcg/translate_vx.c.inc b/target/s390x/tcg/translate_vx.c.inc
new file mode 100644 (file)
index 0000000..0afa46e
--- /dev/null
@@ -0,0 +1,3109 @@
+/*
+ * QEMU TCG support -- s390x vector instruction translation functions
+ *
+ * Copyright (C) 2019 Red Hat Inc
+ *
+ * Authors:
+ *   David Hildenbrand <david@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+/*
+ * For most instructions that use the same element size for reads and
+ * writes, we can use real gvec vector expansion, which potantially uses
+ * real host vector instructions. As they only work up to 64 bit elements,
+ * 128 bit elements (vector is a single element) have to be handled
+ * differently. Operations that are too complicated to encode via TCG ops
+ * are handled via gvec ool (out-of-line) handlers.
+ *
+ * As soon as instructions use different element sizes for reads and writes
+ * or access elements "out of their element scope" we expand them manually
+ * in fancy loops, as gvec expansion does not deal with actual element
+ * numbers and does also not support access to other elements.
+ *
+ * 128 bit elements:
+ *  As we only have i32/i64, such elements have to be loaded into two
+ *  i64 values and can then be processed e.g. by tcg_gen_add2_i64.
+ *
+ * Sizes:
+ *  On s390x, the operand size (oprsz) and the maximum size (maxsz) are
+ *  always 16 (128 bit). What gvec code calls "vece", s390x calls "es",
+ *  a.k.a. "element size". These values nicely map to MO_8 ... MO_64. Only
+ *  128 bit element size has to be treated in a special way (MO_64 + 1).
+ *  We will use ES_* instead of MO_* for this reason in this file.
+ *
+ * CC handling:
+ *  As gvec ool-helpers can currently not return values (besides via
+ *  pointers like vectors or cpu_env), whenever we have to set the CC and
+ *  can't conclude the value from the result vector, we will directly
+ *  set it in "env->cc_op" and mark it as static via set_cc_static()".
+ *  Whenever this is done, the helper writes globals (cc_op).
+ */
+
+#define NUM_VEC_ELEMENT_BYTES(es) (1 << (es))
+#define NUM_VEC_ELEMENTS(es) (16 / NUM_VEC_ELEMENT_BYTES(es))
+#define NUM_VEC_ELEMENT_BITS(es) (NUM_VEC_ELEMENT_BYTES(es) * BITS_PER_BYTE)
+
+#define ES_8    MO_8
+#define ES_16   MO_16
+#define ES_32   MO_32
+#define ES_64   MO_64
+#define ES_128  4
+
+/* Floating-Point Format */
+#define FPF_SHORT       2
+#define FPF_LONG        3
+#define FPF_EXT         4
+
+static inline bool valid_vec_element(uint8_t enr, MemOp es)
+{
+    return !(enr & ~(NUM_VEC_ELEMENTS(es) - 1));
+}
+
+static void read_vec_element_i64(TCGv_i64 dst, uint8_t reg, uint8_t enr,
+                                 MemOp memop)
+{
+    const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
+
+    switch (memop) {
+    case ES_8:
+        tcg_gen_ld8u_i64(dst, cpu_env, offs);
+        break;
+    case ES_16:
+        tcg_gen_ld16u_i64(dst, cpu_env, offs);
+        break;
+    case ES_32:
+        tcg_gen_ld32u_i64(dst, cpu_env, offs);
+        break;
+    case ES_8 | MO_SIGN:
+        tcg_gen_ld8s_i64(dst, cpu_env, offs);
+        break;
+    case ES_16 | MO_SIGN:
+        tcg_gen_ld16s_i64(dst, cpu_env, offs);
+        break;
+    case ES_32 | MO_SIGN:
+        tcg_gen_ld32s_i64(dst, cpu_env, offs);
+        break;
+    case ES_64:
+    case ES_64 | MO_SIGN:
+        tcg_gen_ld_i64(dst, cpu_env, offs);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+static void read_vec_element_i32(TCGv_i32 dst, uint8_t reg, uint8_t enr,
+                                 MemOp memop)
+{
+    const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
+
+    switch (memop) {
+    case ES_8:
+        tcg_gen_ld8u_i32(dst, cpu_env, offs);
+        break;
+    case ES_16:
+        tcg_gen_ld16u_i32(dst, cpu_env, offs);
+        break;
+    case ES_8 | MO_SIGN:
+        tcg_gen_ld8s_i32(dst, cpu_env, offs);
+        break;
+    case ES_16 | MO_SIGN:
+        tcg_gen_ld16s_i32(dst, cpu_env, offs);
+        break;
+    case ES_32:
+    case ES_32 | MO_SIGN:
+        tcg_gen_ld_i32(dst, cpu_env, offs);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+static void write_vec_element_i64(TCGv_i64 src, int reg, uint8_t enr,
+                                  MemOp memop)
+{
+    const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
+
+    switch (memop) {
+    case ES_8:
+        tcg_gen_st8_i64(src, cpu_env, offs);
+        break;
+    case ES_16:
+        tcg_gen_st16_i64(src, cpu_env, offs);
+        break;
+    case ES_32:
+        tcg_gen_st32_i64(src, cpu_env, offs);
+        break;
+    case ES_64:
+        tcg_gen_st_i64(src, cpu_env, offs);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+static void write_vec_element_i32(TCGv_i32 src, int reg, uint8_t enr,
+                                  MemOp memop)
+{
+    const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
+
+    switch (memop) {
+    case ES_8:
+        tcg_gen_st8_i32(src, cpu_env, offs);
+        break;
+    case ES_16:
+        tcg_gen_st16_i32(src, cpu_env, offs);
+        break;
+    case ES_32:
+        tcg_gen_st_i32(src, cpu_env, offs);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+static void get_vec_element_ptr_i64(TCGv_ptr ptr, uint8_t reg, TCGv_i64 enr,
+                                    uint8_t es)
+{
+    TCGv_i64 tmp = tcg_temp_new_i64();
+
+    /* mask off invalid parts from the element nr */
+    tcg_gen_andi_i64(tmp, enr, NUM_VEC_ELEMENTS(es) - 1);
+
+    /* convert it to an element offset relative to cpu_env (vec_reg_offset() */
+    tcg_gen_shli_i64(tmp, tmp, es);
+#ifndef HOST_WORDS_BIGENDIAN
+    tcg_gen_xori_i64(tmp, tmp, 8 - NUM_VEC_ELEMENT_BYTES(es));
+#endif
+    tcg_gen_addi_i64(tmp, tmp, vec_full_reg_offset(reg));
+
+    /* generate the final ptr by adding cpu_env */
+    tcg_gen_trunc_i64_ptr(ptr, tmp);
+    tcg_gen_add_ptr(ptr, ptr, cpu_env);
+
+    tcg_temp_free_i64(tmp);
+}
+
+#define gen_gvec_2(v1, v2, gen) \
+    tcg_gen_gvec_2(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
+                   16, 16, gen)
+#define gen_gvec_2s(v1, v2, c, gen) \
+    tcg_gen_gvec_2s(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
+                    16, 16, c, gen)
+#define gen_gvec_2_ool(v1, v2, data, fn) \
+    tcg_gen_gvec_2_ool(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
+                       16, 16, data, fn)
+#define gen_gvec_2i_ool(v1, v2, c, data, fn) \
+    tcg_gen_gvec_2i_ool(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
+                        c, 16, 16, data, fn)
+#define gen_gvec_2_ptr(v1, v2, ptr, data, fn) \
+    tcg_gen_gvec_2_ptr(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
+                       ptr, 16, 16, data, fn)
+#define gen_gvec_3(v1, v2, v3, gen) \
+    tcg_gen_gvec_3(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
+                   vec_full_reg_offset(v3), 16, 16, gen)
+#define gen_gvec_3_ool(v1, v2, v3, data, fn) \
+    tcg_gen_gvec_3_ool(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
+                       vec_full_reg_offset(v3), 16, 16, data, fn)
+#define gen_gvec_3_ptr(v1, v2, v3, ptr, data, fn) \
+    tcg_gen_gvec_3_ptr(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
+                       vec_full_reg_offset(v3), ptr, 16, 16, data, fn)
+#define gen_gvec_3i(v1, v2, v3, c, gen) \
+    tcg_gen_gvec_3i(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
+                    vec_full_reg_offset(v3), 16, 16, c, gen)
+#define gen_gvec_4(v1, v2, v3, v4, gen) \
+    tcg_gen_gvec_4(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
+                   vec_full_reg_offset(v3), vec_full_reg_offset(v4), \
+                   16, 16, gen)
+#define gen_gvec_4_ool(v1, v2, v3, v4, data, fn) \
+    tcg_gen_gvec_4_ool(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
+                       vec_full_reg_offset(v3), vec_full_reg_offset(v4), \
+                       16, 16, data, fn)
+#define gen_gvec_4_ptr(v1, v2, v3, v4, ptr, data, fn) \
+    tcg_gen_gvec_4_ptr(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
+                       vec_full_reg_offset(v3), vec_full_reg_offset(v4), \
+                       ptr, 16, 16, data, fn)
+#define gen_gvec_dup_i64(es, v1, c) \
+    tcg_gen_gvec_dup_i64(es, vec_full_reg_offset(v1), 16, 16, c)
+#define gen_gvec_mov(v1, v2) \
+    tcg_gen_gvec_mov(0, vec_full_reg_offset(v1), vec_full_reg_offset(v2), 16, \
+                     16)
+#define gen_gvec_dup_imm(es, v1, c) \
+    tcg_gen_gvec_dup_imm(es, vec_full_reg_offset(v1), 16, 16, c);
+#define gen_gvec_fn_2(fn, es, v1, v2) \
+    tcg_gen_gvec_##fn(es, vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
+                      16, 16)
+#define gen_gvec_fn_2i(fn, es, v1, v2, c) \
+    tcg_gen_gvec_##fn(es, vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
+                      c, 16, 16)
+#define gen_gvec_fn_2s(fn, es, v1, v2, s) \
+    tcg_gen_gvec_##fn(es, vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
+                      s, 16, 16)
+#define gen_gvec_fn_3(fn, es, v1, v2, v3) \
+    tcg_gen_gvec_##fn(es, vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
+                      vec_full_reg_offset(v3), 16, 16)
+#define gen_gvec_fn_4(fn, es, v1, v2, v3, v4) \
+    tcg_gen_gvec_##fn(es, vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
+                      vec_full_reg_offset(v3), vec_full_reg_offset(v4), 16, 16)
+
+/*
+ * Helper to carry out a 128 bit vector computation using 2 i64 values per
+ * vector.
+ */
+typedef void (*gen_gvec128_3_i64_fn)(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
+                                     TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh);
+static void gen_gvec128_3_i64(gen_gvec128_3_i64_fn fn, uint8_t d, uint8_t a,
+                              uint8_t b)
+{
+        TCGv_i64 dh = tcg_temp_new_i64();
+        TCGv_i64 dl = tcg_temp_new_i64();
+        TCGv_i64 ah = tcg_temp_new_i64();
+        TCGv_i64 al = tcg_temp_new_i64();
+        TCGv_i64 bh = tcg_temp_new_i64();
+        TCGv_i64 bl = tcg_temp_new_i64();
+
+        read_vec_element_i64(ah, a, 0, ES_64);
+        read_vec_element_i64(al, a, 1, ES_64);
+        read_vec_element_i64(bh, b, 0, ES_64);
+        read_vec_element_i64(bl, b, 1, ES_64);
+        fn(dl, dh, al, ah, bl, bh);
+        write_vec_element_i64(dh, d, 0, ES_64);
+        write_vec_element_i64(dl, d, 1, ES_64);
+
+        tcg_temp_free_i64(dh);
+        tcg_temp_free_i64(dl);
+        tcg_temp_free_i64(ah);
+        tcg_temp_free_i64(al);
+        tcg_temp_free_i64(bh);
+        tcg_temp_free_i64(bl);
+}
+
+typedef void (*gen_gvec128_4_i64_fn)(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
+                                     TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh,
+                                     TCGv_i64 cl, TCGv_i64 ch);
+static void gen_gvec128_4_i64(gen_gvec128_4_i64_fn fn, uint8_t d, uint8_t a,
+                              uint8_t b, uint8_t c)
+{
+        TCGv_i64 dh = tcg_temp_new_i64();
+        TCGv_i64 dl = tcg_temp_new_i64();
+        TCGv_i64 ah = tcg_temp_new_i64();
+        TCGv_i64 al = tcg_temp_new_i64();
+        TCGv_i64 bh = tcg_temp_new_i64();
+        TCGv_i64 bl = tcg_temp_new_i64();
+        TCGv_i64 ch = tcg_temp_new_i64();
+        TCGv_i64 cl = tcg_temp_new_i64();
+
+        read_vec_element_i64(ah, a, 0, ES_64);
+        read_vec_element_i64(al, a, 1, ES_64);
+        read_vec_element_i64(bh, b, 0, ES_64);
+        read_vec_element_i64(bl, b, 1, ES_64);
+        read_vec_element_i64(ch, c, 0, ES_64);
+        read_vec_element_i64(cl, c, 1, ES_64);
+        fn(dl, dh, al, ah, bl, bh, cl, ch);
+        write_vec_element_i64(dh, d, 0, ES_64);
+        write_vec_element_i64(dl, d, 1, ES_64);
+
+        tcg_temp_free_i64(dh);
+        tcg_temp_free_i64(dl);
+        tcg_temp_free_i64(ah);
+        tcg_temp_free_i64(al);
+        tcg_temp_free_i64(bh);
+        tcg_temp_free_i64(bl);
+        tcg_temp_free_i64(ch);
+        tcg_temp_free_i64(cl);
+}
+
+static void gen_addi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
+                          uint64_t b)
+{
+    TCGv_i64 bl = tcg_const_i64(b);
+    TCGv_i64 bh = tcg_const_i64(0);
+
+    tcg_gen_add2_i64(dl, dh, al, ah, bl, bh);
+    tcg_temp_free_i64(bl);
+    tcg_temp_free_i64(bh);
+}
+
+static DisasJumpType op_vbperm(DisasContext *s, DisasOps *o)
+{
+    gen_gvec_3_ool(get_field(s, v1), get_field(s, v2), get_field(s, v3), 0,
+                   gen_helper_gvec_vbperm);
+
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vge(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = s->insn->data;
+    const uint8_t enr = get_field(s, m3);
+    TCGv_i64 tmp;
+
+    if (!valid_vec_element(enr, es)) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    tmp = tcg_temp_new_i64();
+    read_vec_element_i64(tmp, get_field(s, v2), enr, es);
+    tcg_gen_add_i64(o->addr1, o->addr1, tmp);
+    gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 0);
+
+    tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
+    write_vec_element_i64(tmp, get_field(s, v1), enr, es);
+    tcg_temp_free_i64(tmp);
+    return DISAS_NEXT;
+}
+
+static uint64_t generate_byte_mask(uint8_t mask)
+{
+    uint64_t r = 0;
+    int i;
+
+    for (i = 0; i < 8; i++) {
+        if ((mask >> i) & 1) {
+            r |= 0xffull << (i * 8);
+        }
+    }
+    return r;
+}
+
+static DisasJumpType op_vgbm(DisasContext *s, DisasOps *o)
+{
+    const uint16_t i2 = get_field(s, i2);
+
+    if (i2 == (i2 & 0xff) * 0x0101) {
+        /*
+         * Masks for both 64 bit elements of the vector are the same.
+         * Trust tcg to produce a good constant loading.
+         */
+        gen_gvec_dup_imm(ES_64, get_field(s, v1),
+                         generate_byte_mask(i2 & 0xff));
+    } else {
+        TCGv_i64 t = tcg_temp_new_i64();
+
+        tcg_gen_movi_i64(t, generate_byte_mask(i2 >> 8));
+        write_vec_element_i64(t, get_field(s, v1), 0, ES_64);
+        tcg_gen_movi_i64(t, generate_byte_mask(i2));
+        write_vec_element_i64(t, get_field(s, v1), 1, ES_64);
+        tcg_temp_free_i64(t);
+    }
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vgm(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m4);
+    const uint8_t bits = NUM_VEC_ELEMENT_BITS(es);
+    const uint8_t i2 = get_field(s, i2) & (bits - 1);
+    const uint8_t i3 = get_field(s, i3) & (bits - 1);
+    uint64_t mask = 0;
+    int i;
+
+    if (es > ES_64) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    /* generate the mask - take care of wrapping */
+    for (i = i2; ; i = (i + 1) % bits) {
+        mask |= 1ull << (bits - i - 1);
+        if (i == i3) {
+            break;
+        }
+    }
+
+    gen_gvec_dup_imm(es, get_field(s, v1), mask);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vl(DisasContext *s, DisasOps *o)
+{
+    TCGv_i64 t0 = tcg_temp_new_i64();
+    TCGv_i64 t1 = tcg_temp_new_i64();
+
+    tcg_gen_qemu_ld_i64(t0, o->addr1, get_mem_index(s), MO_TEQ);
+    gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
+    tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEQ);
+    write_vec_element_i64(t0, get_field(s, v1), 0, ES_64);
+    write_vec_element_i64(t1, get_field(s, v1), 1, ES_64);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vlr(DisasContext *s, DisasOps *o)
+{
+    gen_gvec_mov(get_field(s, v1), get_field(s, v2));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vlrep(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m3);
+    TCGv_i64 tmp;
+
+    if (es > ES_64) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    tmp = tcg_temp_new_i64();
+    tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
+    gen_gvec_dup_i64(es, get_field(s, v1), tmp);
+    tcg_temp_free_i64(tmp);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vle(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = s->insn->data;
+    const uint8_t enr = get_field(s, m3);
+    TCGv_i64 tmp;
+
+    if (!valid_vec_element(enr, es)) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    tmp = tcg_temp_new_i64();
+    tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
+    write_vec_element_i64(tmp, get_field(s, v1), enr, es);
+    tcg_temp_free_i64(tmp);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vlei(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = s->insn->data;
+    const uint8_t enr = get_field(s, m3);
+    TCGv_i64 tmp;
+
+    if (!valid_vec_element(enr, es)) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    tmp = tcg_const_i64((int16_t)get_field(s, i2));
+    write_vec_element_i64(tmp, get_field(s, v1), enr, es);
+    tcg_temp_free_i64(tmp);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vlgv(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m4);
+    TCGv_ptr ptr;
+
+    if (es > ES_64) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    /* fast path if we don't need the register content */
+    if (!get_field(s, b2)) {
+        uint8_t enr = get_field(s, d2) & (NUM_VEC_ELEMENTS(es) - 1);
+
+        read_vec_element_i64(o->out, get_field(s, v3), enr, es);
+        return DISAS_NEXT;
+    }
+
+    ptr = tcg_temp_new_ptr();
+    get_vec_element_ptr_i64(ptr, get_field(s, v3), o->addr1, es);
+    switch (es) {
+    case ES_8:
+        tcg_gen_ld8u_i64(o->out, ptr, 0);
+        break;
+    case ES_16:
+        tcg_gen_ld16u_i64(o->out, ptr, 0);
+        break;
+    case ES_32:
+        tcg_gen_ld32u_i64(o->out, ptr, 0);
+        break;
+    case ES_64:
+        tcg_gen_ld_i64(o->out, ptr, 0);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+    tcg_temp_free_ptr(ptr);
+
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vllez(DisasContext *s, DisasOps *o)
+{
+    uint8_t es = get_field(s, m3);
+    uint8_t enr;
+    TCGv_i64 t;
+
+    switch (es) {
+    /* rightmost sub-element of leftmost doubleword */
+    case ES_8:
+        enr = 7;
+        break;
+    case ES_16:
+        enr = 3;
+        break;
+    case ES_32:
+        enr = 1;
+        break;
+    case ES_64:
+        enr = 0;
+        break;
+    /* leftmost sub-element of leftmost doubleword */
+    case 6:
+        if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
+            es = ES_32;
+            enr = 0;
+            break;
+        }
+        /* fallthrough */
+    default:
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    t = tcg_temp_new_i64();
+    tcg_gen_qemu_ld_i64(t, o->addr1, get_mem_index(s), MO_TE | es);
+    gen_gvec_dup_imm(es, get_field(s, v1), 0);
+    write_vec_element_i64(t, get_field(s, v1), enr, es);
+    tcg_temp_free_i64(t);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vlm(DisasContext *s, DisasOps *o)
+{
+    const uint8_t v3 = get_field(s, v3);
+    uint8_t v1 = get_field(s, v1);
+    TCGv_i64 t0, t1;
+
+    if (v3 < v1 || (v3 - v1 + 1) > 16) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    /*
+     * Check for possible access exceptions by trying to load the last
+     * element. The first element will be checked first next.
+     */
+    t0 = tcg_temp_new_i64();
+    t1 = tcg_temp_new_i64();
+    gen_addi_and_wrap_i64(s, t0, o->addr1, (v3 - v1) * 16 + 8);
+    tcg_gen_qemu_ld_i64(t0, t0, get_mem_index(s), MO_TEQ);
+
+    for (;; v1++) {
+        tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEQ);
+        write_vec_element_i64(t1, v1, 0, ES_64);
+        if (v1 == v3) {
+            break;
+        }
+        gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
+        tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEQ);
+        write_vec_element_i64(t1, v1, 1, ES_64);
+        gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
+    }
+
+    /* Store the last element, loaded first */
+    write_vec_element_i64(t0, v1, 1, ES_64);
+
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i64(t1);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vlbb(DisasContext *s, DisasOps *o)
+{
+    const int64_t block_size = (1ull << (get_field(s, m3) + 6));
+    const int v1_offs = vec_full_reg_offset(get_field(s, v1));
+    TCGv_ptr a0;
+    TCGv_i64 bytes;
+
+    if (get_field(s, m3) > 6) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    bytes = tcg_temp_new_i64();
+    a0 = tcg_temp_new_ptr();
+    /* calculate the number of bytes until the next block boundary */
+    tcg_gen_ori_i64(bytes, o->addr1, -block_size);
+    tcg_gen_neg_i64(bytes, bytes);
+
+    tcg_gen_addi_ptr(a0, cpu_env, v1_offs);
+    gen_helper_vll(cpu_env, a0, o->addr1, bytes);
+    tcg_temp_free_i64(bytes);
+    tcg_temp_free_ptr(a0);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vlvg(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m4);
+    TCGv_ptr ptr;
+
+    if (es > ES_64) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    /* fast path if we don't need the register content */
+    if (!get_field(s, b2)) {
+        uint8_t enr = get_field(s, d2) & (NUM_VEC_ELEMENTS(es) - 1);
+
+        write_vec_element_i64(o->in2, get_field(s, v1), enr, es);
+        return DISAS_NEXT;
+    }
+
+    ptr = tcg_temp_new_ptr();
+    get_vec_element_ptr_i64(ptr, get_field(s, v1), o->addr1, es);
+    switch (es) {
+    case ES_8:
+        tcg_gen_st8_i64(o->in2, ptr, 0);
+        break;
+    case ES_16:
+        tcg_gen_st16_i64(o->in2, ptr, 0);
+        break;
+    case ES_32:
+        tcg_gen_st32_i64(o->in2, ptr, 0);
+        break;
+    case ES_64:
+        tcg_gen_st_i64(o->in2, ptr, 0);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+    tcg_temp_free_ptr(ptr);
+
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vlvgp(DisasContext *s, DisasOps *o)
+{
+    write_vec_element_i64(o->in1, get_field(s, v1), 0, ES_64);
+    write_vec_element_i64(o->in2, get_field(s, v1), 1, ES_64);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vll(DisasContext *s, DisasOps *o)
+{
+    const int v1_offs = vec_full_reg_offset(get_field(s, v1));
+    TCGv_ptr a0 = tcg_temp_new_ptr();
+
+    /* convert highest index into an actual length */
+    tcg_gen_addi_i64(o->in2, o->in2, 1);
+    tcg_gen_addi_ptr(a0, cpu_env, v1_offs);
+    gen_helper_vll(cpu_env, a0, o->addr1, o->in2);
+    tcg_temp_free_ptr(a0);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vmr(DisasContext *s, DisasOps *o)
+{
+    const uint8_t v1 = get_field(s, v1);
+    const uint8_t v2 = get_field(s, v2);
+    const uint8_t v3 = get_field(s, v3);
+    const uint8_t es = get_field(s, m4);
+    int dst_idx, src_idx;
+    TCGv_i64 tmp;
+
+    if (es > ES_64) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    tmp = tcg_temp_new_i64();
+    if (s->fields.op2 == 0x61) {
+        /* iterate backwards to avoid overwriting data we might need later */
+        for (dst_idx = NUM_VEC_ELEMENTS(es) - 1; dst_idx >= 0; dst_idx--) {
+            src_idx = dst_idx / 2;
+            if (dst_idx % 2 == 0) {
+                read_vec_element_i64(tmp, v2, src_idx, es);
+            } else {
+                read_vec_element_i64(tmp, v3, src_idx, es);
+            }
+            write_vec_element_i64(tmp, v1, dst_idx, es);
+        }
+    } else {
+        /* iterate forward to avoid overwriting data we might need later */
+        for (dst_idx = 0; dst_idx < NUM_VEC_ELEMENTS(es); dst_idx++) {
+            src_idx = (dst_idx + NUM_VEC_ELEMENTS(es)) / 2;
+            if (dst_idx % 2 == 0) {
+                read_vec_element_i64(tmp, v2, src_idx, es);
+            } else {
+                read_vec_element_i64(tmp, v3, src_idx, es);
+            }
+            write_vec_element_i64(tmp, v1, dst_idx, es);
+        }
+    }
+    tcg_temp_free_i64(tmp);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vpk(DisasContext *s, DisasOps *o)
+{
+    const uint8_t v1 = get_field(s, v1);
+    const uint8_t v2 = get_field(s, v2);
+    const uint8_t v3 = get_field(s, v3);
+    const uint8_t es = get_field(s, m4);
+    static gen_helper_gvec_3 * const vpk[3] = {
+        gen_helper_gvec_vpk16,
+        gen_helper_gvec_vpk32,
+        gen_helper_gvec_vpk64,
+    };
+     static gen_helper_gvec_3 * const vpks[3] = {
+        gen_helper_gvec_vpks16,
+        gen_helper_gvec_vpks32,
+        gen_helper_gvec_vpks64,
+    };
+    static gen_helper_gvec_3_ptr * const vpks_cc[3] = {
+        gen_helper_gvec_vpks_cc16,
+        gen_helper_gvec_vpks_cc32,
+        gen_helper_gvec_vpks_cc64,
+    };
+    static gen_helper_gvec_3 * const vpkls[3] = {
+        gen_helper_gvec_vpkls16,
+        gen_helper_gvec_vpkls32,
+        gen_helper_gvec_vpkls64,
+    };
+    static gen_helper_gvec_3_ptr * const vpkls_cc[3] = {
+        gen_helper_gvec_vpkls_cc16,
+        gen_helper_gvec_vpkls_cc32,
+        gen_helper_gvec_vpkls_cc64,
+    };
+
+    if (es == ES_8 || es > ES_64) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    switch (s->fields.op2) {
+    case 0x97:
+        if (get_field(s, m5) & 0x1) {
+            gen_gvec_3_ptr(v1, v2, v3, cpu_env, 0, vpks_cc[es - 1]);
+            set_cc_static(s);
+        } else {
+            gen_gvec_3_ool(v1, v2, v3, 0, vpks[es - 1]);
+        }
+        break;
+    case 0x95:
+        if (get_field(s, m5) & 0x1) {
+            gen_gvec_3_ptr(v1, v2, v3, cpu_env, 0, vpkls_cc[es - 1]);
+            set_cc_static(s);
+        } else {
+            gen_gvec_3_ool(v1, v2, v3, 0, vpkls[es - 1]);
+        }
+        break;
+    case 0x94:
+        /* If sources and destination dont't overlap -> fast path */
+        if (v1 != v2 && v1 != v3) {
+            const uint8_t src_es = get_field(s, m4);
+            const uint8_t dst_es = src_es - 1;
+            TCGv_i64 tmp = tcg_temp_new_i64();
+            int dst_idx, src_idx;
+
+            for (dst_idx = 0; dst_idx < NUM_VEC_ELEMENTS(dst_es); dst_idx++) {
+                src_idx = dst_idx;
+                if (src_idx < NUM_VEC_ELEMENTS(src_es)) {
+                    read_vec_element_i64(tmp, v2, src_idx, src_es);
+                } else {
+                    src_idx -= NUM_VEC_ELEMENTS(src_es);
+                    read_vec_element_i64(tmp, v3, src_idx, src_es);
+                }
+                write_vec_element_i64(tmp, v1, dst_idx, dst_es);
+            }
+            tcg_temp_free_i64(tmp);
+        } else {
+            gen_gvec_3_ool(v1, v2, v3, 0, vpk[es - 1]);
+        }
+        break;
+    default:
+        g_assert_not_reached();
+    }
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vperm(DisasContext *s, DisasOps *o)
+{
+    gen_gvec_4_ool(get_field(s, v1), get_field(s, v2),
+                   get_field(s, v3), get_field(s, v4),
+                   0, gen_helper_gvec_vperm);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vpdi(DisasContext *s, DisasOps *o)
+{
+    const uint8_t i2 = extract32(get_field(s, m4), 2, 1);
+    const uint8_t i3 = extract32(get_field(s, m4), 0, 1);
+    TCGv_i64 t0 = tcg_temp_new_i64();
+    TCGv_i64 t1 = tcg_temp_new_i64();
+
+    read_vec_element_i64(t0, get_field(s, v2), i2, ES_64);
+    read_vec_element_i64(t1, get_field(s, v3), i3, ES_64);
+    write_vec_element_i64(t0, get_field(s, v1), 0, ES_64);
+    write_vec_element_i64(t1, get_field(s, v1), 1, ES_64);
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i64(t1);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vrep(DisasContext *s, DisasOps *o)
+{
+    const uint8_t enr = get_field(s, i2);
+    const uint8_t es = get_field(s, m4);
+
+    if (es > ES_64 || !valid_vec_element(enr, es)) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    tcg_gen_gvec_dup_mem(es, vec_full_reg_offset(get_field(s, v1)),
+                         vec_reg_offset(get_field(s, v3), enr, es),
+                         16, 16);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vrepi(DisasContext *s, DisasOps *o)
+{
+    const int64_t data = (int16_t)get_field(s, i2);
+    const uint8_t es = get_field(s, m3);
+
+    if (es > ES_64) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    gen_gvec_dup_imm(es, get_field(s, v1), data);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vsce(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = s->insn->data;
+    const uint8_t enr = get_field(s, m3);
+    TCGv_i64 tmp;
+
+    if (!valid_vec_element(enr, es)) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    tmp = tcg_temp_new_i64();
+    read_vec_element_i64(tmp, get_field(s, v2), enr, es);
+    tcg_gen_add_i64(o->addr1, o->addr1, tmp);
+    gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 0);
+
+    read_vec_element_i64(tmp, get_field(s, v1), enr, es);
+    tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
+    tcg_temp_free_i64(tmp);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vsel(DisasContext *s, DisasOps *o)
+{
+    gen_gvec_fn_4(bitsel, ES_8, get_field(s, v1),
+                  get_field(s, v4), get_field(s, v2),
+                  get_field(s, v3));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vseg(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m3);
+    int idx1, idx2;
+    TCGv_i64 tmp;
+
+    switch (es) {
+    case ES_8:
+        idx1 = 7;
+        idx2 = 15;
+        break;
+    case ES_16:
+        idx1 = 3;
+        idx2 = 7;
+        break;
+    case ES_32:
+        idx1 = 1;
+        idx2 = 3;
+        break;
+    default:
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    tmp = tcg_temp_new_i64();
+    read_vec_element_i64(tmp, get_field(s, v2), idx1, es | MO_SIGN);
+    write_vec_element_i64(tmp, get_field(s, v1), 0, ES_64);
+    read_vec_element_i64(tmp, get_field(s, v2), idx2, es | MO_SIGN);
+    write_vec_element_i64(tmp, get_field(s, v1), 1, ES_64);
+    tcg_temp_free_i64(tmp);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vst(DisasContext *s, DisasOps *o)
+{
+    TCGv_i64 tmp = tcg_const_i64(16);
+
+    /* Probe write access before actually modifying memory */
+    gen_helper_probe_write_access(cpu_env, o->addr1, tmp);
+
+    read_vec_element_i64(tmp,  get_field(s, v1), 0, ES_64);
+    tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
+    gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
+    read_vec_element_i64(tmp,  get_field(s, v1), 1, ES_64);
+    tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
+    tcg_temp_free_i64(tmp);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vste(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = s->insn->data;
+    const uint8_t enr = get_field(s, m3);
+    TCGv_i64 tmp;
+
+    if (!valid_vec_element(enr, es)) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    tmp = tcg_temp_new_i64();
+    read_vec_element_i64(tmp, get_field(s, v1), enr, es);
+    tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
+    tcg_temp_free_i64(tmp);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vstm(DisasContext *s, DisasOps *o)
+{
+    const uint8_t v3 = get_field(s, v3);
+    uint8_t v1 = get_field(s, v1);
+    TCGv_i64 tmp;
+
+    while (v3 < v1 || (v3 - v1 + 1) > 16) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    /* Probe write access before actually modifying memory */
+    tmp = tcg_const_i64((v3 - v1 + 1) * 16);
+    gen_helper_probe_write_access(cpu_env, o->addr1, tmp);
+
+    for (;; v1++) {
+        read_vec_element_i64(tmp, v1, 0, ES_64);
+        tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
+        gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
+        read_vec_element_i64(tmp, v1, 1, ES_64);
+        tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
+        if (v1 == v3) {
+            break;
+        }
+        gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
+    }
+    tcg_temp_free_i64(tmp);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vstl(DisasContext *s, DisasOps *o)
+{
+    const int v1_offs = vec_full_reg_offset(get_field(s, v1));
+    TCGv_ptr a0 = tcg_temp_new_ptr();
+
+    /* convert highest index into an actual length */
+    tcg_gen_addi_i64(o->in2, o->in2, 1);
+    tcg_gen_addi_ptr(a0, cpu_env, v1_offs);
+    gen_helper_vstl(cpu_env, a0, o->addr1, o->in2);
+    tcg_temp_free_ptr(a0);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vup(DisasContext *s, DisasOps *o)
+{
+    const bool logical = s->fields.op2 == 0xd4 || s->fields.op2 == 0xd5;
+    const uint8_t v1 = get_field(s, v1);
+    const uint8_t v2 = get_field(s, v2);
+    const uint8_t src_es = get_field(s, m3);
+    const uint8_t dst_es = src_es + 1;
+    int dst_idx, src_idx;
+    TCGv_i64 tmp;
+
+    if (src_es > ES_32) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    tmp = tcg_temp_new_i64();
+    if (s->fields.op2 == 0xd7 || s->fields.op2 == 0xd5) {
+        /* iterate backwards to avoid overwriting data we might need later */
+        for (dst_idx = NUM_VEC_ELEMENTS(dst_es) - 1; dst_idx >= 0; dst_idx--) {
+            src_idx = dst_idx;
+            read_vec_element_i64(tmp, v2, src_idx,
+                                 src_es | (logical ? 0 : MO_SIGN));
+            write_vec_element_i64(tmp, v1, dst_idx, dst_es);
+        }
+
+    } else {
+        /* iterate forward to avoid overwriting data we might need later */
+        for (dst_idx = 0; dst_idx < NUM_VEC_ELEMENTS(dst_es); dst_idx++) {
+            src_idx = dst_idx + NUM_VEC_ELEMENTS(src_es) / 2;
+            read_vec_element_i64(tmp, v2, src_idx,
+                                 src_es | (logical ? 0 : MO_SIGN));
+            write_vec_element_i64(tmp, v1, dst_idx, dst_es);
+        }
+    }
+    tcg_temp_free_i64(tmp);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_va(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m4);
+
+    if (es > ES_128) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    } else if (es == ES_128) {
+        gen_gvec128_3_i64(tcg_gen_add2_i64, get_field(s, v1),
+                          get_field(s, v2), get_field(s, v3));
+        return DISAS_NEXT;
+    }
+    gen_gvec_fn_3(add, es, get_field(s, v1), get_field(s, v2),
+                  get_field(s, v3));
+    return DISAS_NEXT;
+}
+
+static void gen_acc(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b, uint8_t es)
+{
+    const uint8_t msb_bit_nr = NUM_VEC_ELEMENT_BITS(es) - 1;
+    TCGv_i64 msb_mask = tcg_const_i64(dup_const(es, 1ull << msb_bit_nr));
+    TCGv_i64 t1 = tcg_temp_new_i64();
+    TCGv_i64 t2 = tcg_temp_new_i64();
+    TCGv_i64 t3 = tcg_temp_new_i64();
+
+    /* Calculate the carry into the MSB, ignoring the old MSBs */
+    tcg_gen_andc_i64(t1, a, msb_mask);
+    tcg_gen_andc_i64(t2, b, msb_mask);
+    tcg_gen_add_i64(t1, t1, t2);
+    /* Calculate the MSB without any carry into it */
+    tcg_gen_xor_i64(t3, a, b);
+    /* Calculate the carry out of the MSB in the MSB bit position */
+    tcg_gen_and_i64(d, a, b);
+    tcg_gen_and_i64(t1, t1, t3);
+    tcg_gen_or_i64(d, d, t1);
+    /* Isolate and shift the carry into position */
+    tcg_gen_and_i64(d, d, msb_mask);
+    tcg_gen_shri_i64(d, d, msb_bit_nr);
+
+    tcg_temp_free_i64(t1);
+    tcg_temp_free_i64(t2);
+    tcg_temp_free_i64(t3);
+}
+
+static void gen_acc8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
+{
+    gen_acc(d, a, b, ES_8);
+}
+
+static void gen_acc16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
+{
+    gen_acc(d, a, b, ES_16);
+}
+
+static void gen_acc_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
+{
+    TCGv_i32 t = tcg_temp_new_i32();
+
+    tcg_gen_add_i32(t, a, b);
+    tcg_gen_setcond_i32(TCG_COND_LTU, d, t, b);
+    tcg_temp_free_i32(t);
+}
+
+static void gen_acc_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
+{
+    TCGv_i64 t = tcg_temp_new_i64();
+
+    tcg_gen_add_i64(t, a, b);
+    tcg_gen_setcond_i64(TCG_COND_LTU, d, t, b);
+    tcg_temp_free_i64(t);
+}
+
+static void gen_acc2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
+                         TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh)
+{
+    TCGv_i64 th = tcg_temp_new_i64();
+    TCGv_i64 tl = tcg_temp_new_i64();
+    TCGv_i64 zero = tcg_const_i64(0);
+
+    tcg_gen_add2_i64(tl, th, al, zero, bl, zero);
+    tcg_gen_add2_i64(tl, th, th, zero, ah, zero);
+    tcg_gen_add2_i64(tl, dl, tl, th, bh, zero);
+    tcg_gen_mov_i64(dh, zero);
+
+    tcg_temp_free_i64(th);
+    tcg_temp_free_i64(tl);
+    tcg_temp_free_i64(zero);
+}
+
+static DisasJumpType op_vacc(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m4);
+    static const GVecGen3 g[4] = {
+        { .fni8 = gen_acc8_i64, },
+        { .fni8 = gen_acc16_i64, },
+        { .fni4 = gen_acc_i32, },
+        { .fni8 = gen_acc_i64, },
+    };
+
+    if (es > ES_128) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    } else if (es == ES_128) {
+        gen_gvec128_3_i64(gen_acc2_i64, get_field(s, v1),
+                          get_field(s, v2), get_field(s, v3));
+        return DISAS_NEXT;
+    }
+    gen_gvec_3(get_field(s, v1), get_field(s, v2),
+               get_field(s, v3), &g[es]);
+    return DISAS_NEXT;
+}
+
+static void gen_ac2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
+                        TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
+{
+    TCGv_i64 tl = tcg_temp_new_i64();
+    TCGv_i64 th = tcg_const_i64(0);
+
+    /* extract the carry only */
+    tcg_gen_extract_i64(tl, cl, 0, 1);
+    tcg_gen_add2_i64(dl, dh, al, ah, bl, bh);
+    tcg_gen_add2_i64(dl, dh, dl, dh, tl, th);
+
+    tcg_temp_free_i64(tl);
+    tcg_temp_free_i64(th);
+}
+
+static DisasJumpType op_vac(DisasContext *s, DisasOps *o)
+{
+    if (get_field(s, m5) != ES_128) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    gen_gvec128_4_i64(gen_ac2_i64, get_field(s, v1),
+                      get_field(s, v2), get_field(s, v3),
+                      get_field(s, v4));
+    return DISAS_NEXT;
+}
+
+static void gen_accc2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
+                          TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
+{
+    TCGv_i64 tl = tcg_temp_new_i64();
+    TCGv_i64 th = tcg_temp_new_i64();
+    TCGv_i64 zero = tcg_const_i64(0);
+
+    tcg_gen_andi_i64(tl, cl, 1);
+    tcg_gen_add2_i64(tl, th, tl, zero, al, zero);
+    tcg_gen_add2_i64(tl, th, tl, th, bl, zero);
+    tcg_gen_add2_i64(tl, th, th, zero, ah, zero);
+    tcg_gen_add2_i64(tl, dl, tl, th, bh, zero);
+    tcg_gen_mov_i64(dh, zero);
+
+    tcg_temp_free_i64(tl);
+    tcg_temp_free_i64(th);
+    tcg_temp_free_i64(zero);
+}
+
+static DisasJumpType op_vaccc(DisasContext *s, DisasOps *o)
+{
+    if (get_field(s, m5) != ES_128) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    gen_gvec128_4_i64(gen_accc2_i64, get_field(s, v1),
+                      get_field(s, v2), get_field(s, v3),
+                      get_field(s, v4));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vn(DisasContext *s, DisasOps *o)
+{
+    gen_gvec_fn_3(and, ES_8, get_field(s, v1), get_field(s, v2),
+                  get_field(s, v3));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vnc(DisasContext *s, DisasOps *o)
+{
+    gen_gvec_fn_3(andc, ES_8, get_field(s, v1),
+                  get_field(s, v2), get_field(s, v3));
+    return DISAS_NEXT;
+}
+
+static void gen_avg_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
+{
+    TCGv_i64 t0 = tcg_temp_new_i64();
+    TCGv_i64 t1 = tcg_temp_new_i64();
+
+    tcg_gen_ext_i32_i64(t0, a);
+    tcg_gen_ext_i32_i64(t1, b);
+    tcg_gen_add_i64(t0, t0, t1);
+    tcg_gen_addi_i64(t0, t0, 1);
+    tcg_gen_shri_i64(t0, t0, 1);
+    tcg_gen_extrl_i64_i32(d, t0);
+
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+static void gen_avg_i64(TCGv_i64 dl, TCGv_i64 al, TCGv_i64 bl)
+{
+    TCGv_i64 dh = tcg_temp_new_i64();
+    TCGv_i64 ah = tcg_temp_new_i64();
+    TCGv_i64 bh = tcg_temp_new_i64();
+
+    /* extending the sign by one bit is sufficient */
+    tcg_gen_extract_i64(ah, al, 63, 1);
+    tcg_gen_extract_i64(bh, bl, 63, 1);
+    tcg_gen_add2_i64(dl, dh, al, ah, bl, bh);
+    gen_addi2_i64(dl, dh, dl, dh, 1);
+    tcg_gen_extract2_i64(dl, dl, dh, 1);
+
+    tcg_temp_free_i64(dh);
+    tcg_temp_free_i64(ah);
+    tcg_temp_free_i64(bh);
+}
+
+static DisasJumpType op_vavg(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m4);
+    static const GVecGen3 g[4] = {
+        { .fno = gen_helper_gvec_vavg8, },
+        { .fno = gen_helper_gvec_vavg16, },
+        { .fni4 = gen_avg_i32, },
+        { .fni8 = gen_avg_i64, },
+    };
+
+    if (es > ES_64) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+    gen_gvec_3(get_field(s, v1), get_field(s, v2),
+               get_field(s, v3), &g[es]);
+    return DISAS_NEXT;
+}
+
+static void gen_avgl_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
+{
+    TCGv_i64 t0 = tcg_temp_new_i64();
+    TCGv_i64 t1 = tcg_temp_new_i64();
+
+    tcg_gen_extu_i32_i64(t0, a);
+    tcg_gen_extu_i32_i64(t1, b);
+    tcg_gen_add_i64(t0, t0, t1);
+    tcg_gen_addi_i64(t0, t0, 1);
+    tcg_gen_shri_i64(t0, t0, 1);
+    tcg_gen_extrl_i64_i32(d, t0);
+
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+static void gen_avgl_i64(TCGv_i64 dl, TCGv_i64 al, TCGv_i64 bl)
+{
+    TCGv_i64 dh = tcg_temp_new_i64();
+    TCGv_i64 zero = tcg_const_i64(0);
+
+    tcg_gen_add2_i64(dl, dh, al, zero, bl, zero);
+    gen_addi2_i64(dl, dh, dl, dh, 1);
+    tcg_gen_extract2_i64(dl, dl, dh, 1);
+
+    tcg_temp_free_i64(dh);
+    tcg_temp_free_i64(zero);
+}
+
+static DisasJumpType op_vavgl(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m4);
+    static const GVecGen3 g[4] = {
+        { .fno = gen_helper_gvec_vavgl8, },
+        { .fno = gen_helper_gvec_vavgl16, },
+        { .fni4 = gen_avgl_i32, },
+        { .fni8 = gen_avgl_i64, },
+    };
+
+    if (es > ES_64) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+    gen_gvec_3(get_field(s, v1), get_field(s, v2),
+               get_field(s, v3), &g[es]);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vcksm(DisasContext *s, DisasOps *o)
+{
+    TCGv_i32 tmp = tcg_temp_new_i32();
+    TCGv_i32 sum = tcg_temp_new_i32();
+    int i;
+
+    read_vec_element_i32(sum, get_field(s, v3), 1, ES_32);
+    for (i = 0; i < 4; i++) {
+        read_vec_element_i32(tmp, get_field(s, v2), i, ES_32);
+        tcg_gen_add2_i32(tmp, sum, sum, sum, tmp, tmp);
+    }
+    gen_gvec_dup_imm(ES_32, get_field(s, v1), 0);
+    write_vec_element_i32(sum, get_field(s, v1), 1, ES_32);
+
+    tcg_temp_free_i32(tmp);
+    tcg_temp_free_i32(sum);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vec(DisasContext *s, DisasOps *o)
+{
+    uint8_t es = get_field(s, m3);
+    const uint8_t enr = NUM_VEC_ELEMENTS(es) / 2 - 1;
+
+    if (es > ES_64) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+    if (s->fields.op2 == 0xdb) {
+        es |= MO_SIGN;
+    }
+
+    o->in1 = tcg_temp_new_i64();
+    o->in2 = tcg_temp_new_i64();
+    read_vec_element_i64(o->in1, get_field(s, v1), enr, es);
+    read_vec_element_i64(o->in2, get_field(s, v2), enr, es);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vc(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m4);
+    TCGCond cond = s->insn->data;
+
+    if (es > ES_64) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    tcg_gen_gvec_cmp(cond, es,
+                     vec_full_reg_offset(get_field(s, v1)),
+                     vec_full_reg_offset(get_field(s, v2)),
+                     vec_full_reg_offset(get_field(s, v3)), 16, 16);
+    if (get_field(s, m5) & 0x1) {
+        TCGv_i64 low = tcg_temp_new_i64();
+        TCGv_i64 high = tcg_temp_new_i64();
+
+        read_vec_element_i64(high, get_field(s, v1), 0, ES_64);
+        read_vec_element_i64(low, get_field(s, v1), 1, ES_64);
+        gen_op_update2_cc_i64(s, CC_OP_VC, low, high);
+
+        tcg_temp_free_i64(low);
+        tcg_temp_free_i64(high);
+    }
+    return DISAS_NEXT;
+}
+
+static void gen_clz_i32(TCGv_i32 d, TCGv_i32 a)
+{
+    tcg_gen_clzi_i32(d, a, 32);
+}
+
+static void gen_clz_i64(TCGv_i64 d, TCGv_i64 a)
+{
+    tcg_gen_clzi_i64(d, a, 64);
+}
+
+static DisasJumpType op_vclz(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m3);
+    static const GVecGen2 g[4] = {
+        { .fno = gen_helper_gvec_vclz8, },
+        { .fno = gen_helper_gvec_vclz16, },
+        { .fni4 = gen_clz_i32, },
+        { .fni8 = gen_clz_i64, },
+    };
+
+    if (es > ES_64) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+    gen_gvec_2(get_field(s, v1), get_field(s, v2), &g[es]);
+    return DISAS_NEXT;
+}
+
+static void gen_ctz_i32(TCGv_i32 d, TCGv_i32 a)
+{
+    tcg_gen_ctzi_i32(d, a, 32);
+}
+
+static void gen_ctz_i64(TCGv_i64 d, TCGv_i64 a)
+{
+    tcg_gen_ctzi_i64(d, a, 64);
+}
+
+static DisasJumpType op_vctz(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m3);
+    static const GVecGen2 g[4] = {
+        { .fno = gen_helper_gvec_vctz8, },
+        { .fno = gen_helper_gvec_vctz16, },
+        { .fni4 = gen_ctz_i32, },
+        { .fni8 = gen_ctz_i64, },
+    };
+
+    if (es > ES_64) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+    gen_gvec_2(get_field(s, v1), get_field(s, v2), &g[es]);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vx(DisasContext *s, DisasOps *o)
+{
+    gen_gvec_fn_3(xor, ES_8, get_field(s, v1), get_field(s, v2),
+                 get_field(s, v3));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vgfm(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m4);
+    static const GVecGen3 g[4] = {
+        { .fno = gen_helper_gvec_vgfm8, },
+        { .fno = gen_helper_gvec_vgfm16, },
+        { .fno = gen_helper_gvec_vgfm32, },
+        { .fno = gen_helper_gvec_vgfm64, },
+    };
+
+    if (es > ES_64) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+    gen_gvec_3(get_field(s, v1), get_field(s, v2),
+               get_field(s, v3), &g[es]);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vgfma(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m5);
+    static const GVecGen4 g[4] = {
+        { .fno = gen_helper_gvec_vgfma8, },
+        { .fno = gen_helper_gvec_vgfma16, },
+        { .fno = gen_helper_gvec_vgfma32, },
+        { .fno = gen_helper_gvec_vgfma64, },
+    };
+
+    if (es > ES_64) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+    gen_gvec_4(get_field(s, v1), get_field(s, v2),
+               get_field(s, v3), get_field(s, v4), &g[es]);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vlc(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m3);
+
+    if (es > ES_64) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    gen_gvec_fn_2(neg, es, get_field(s, v1), get_field(s, v2));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vlp(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m3);
+
+    if (es > ES_64) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    gen_gvec_fn_2(abs, es, get_field(s, v1), get_field(s, v2));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vmx(DisasContext *s, DisasOps *o)
+{
+    const uint8_t v1 = get_field(s, v1);
+    const uint8_t v2 = get_field(s, v2);
+    const uint8_t v3 = get_field(s, v3);
+    const uint8_t es = get_field(s, m4);
+
+    if (es > ES_64) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    switch (s->fields.op2) {
+    case 0xff:
+        gen_gvec_fn_3(smax, es, v1, v2, v3);
+        break;
+    case 0xfd:
+        gen_gvec_fn_3(umax, es, v1, v2, v3);
+        break;
+    case 0xfe:
+        gen_gvec_fn_3(smin, es, v1, v2, v3);
+        break;
+    case 0xfc:
+        gen_gvec_fn_3(umin, es, v1, v2, v3);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+    return DISAS_NEXT;
+}
+
+static void gen_mal_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, TCGv_i32 c)
+{
+    TCGv_i32 t0 = tcg_temp_new_i32();
+
+    tcg_gen_mul_i32(t0, a, b);
+    tcg_gen_add_i32(d, t0, c);
+
+    tcg_temp_free_i32(t0);
+}
+
+static void gen_mah_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, TCGv_i32 c)
+{
+    TCGv_i64 t0 = tcg_temp_new_i64();
+    TCGv_i64 t1 = tcg_temp_new_i64();
+    TCGv_i64 t2 = tcg_temp_new_i64();
+
+    tcg_gen_ext_i32_i64(t0, a);
+    tcg_gen_ext_i32_i64(t1, b);
+    tcg_gen_ext_i32_i64(t2, c);
+    tcg_gen_mul_i64(t0, t0, t1);
+    tcg_gen_add_i64(t0, t0, t2);
+    tcg_gen_extrh_i64_i32(d, t0);
+
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    tcg_temp_free(t2);
+}
+
+static void gen_malh_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, TCGv_i32 c)
+{
+    TCGv_i64 t0 = tcg_temp_new_i64();
+    TCGv_i64 t1 = tcg_temp_new_i64();
+    TCGv_i64 t2 = tcg_temp_new_i64();
+
+    tcg_gen_extu_i32_i64(t0, a);
+    tcg_gen_extu_i32_i64(t1, b);
+    tcg_gen_extu_i32_i64(t2, c);
+    tcg_gen_mul_i64(t0, t0, t1);
+    tcg_gen_add_i64(t0, t0, t2);
+    tcg_gen_extrh_i64_i32(d, t0);
+
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    tcg_temp_free(t2);
+}
+
+static DisasJumpType op_vma(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m5);
+    static const GVecGen4 g_vmal[3] = {
+        { .fno = gen_helper_gvec_vmal8, },
+        { .fno = gen_helper_gvec_vmal16, },
+        { .fni4 = gen_mal_i32, },
+    };
+    static const GVecGen4 g_vmah[3] = {
+        { .fno = gen_helper_gvec_vmah8, },
+        { .fno = gen_helper_gvec_vmah16, },
+        { .fni4 = gen_mah_i32, },
+    };
+    static const GVecGen4 g_vmalh[3] = {
+        { .fno = gen_helper_gvec_vmalh8, },
+        { .fno = gen_helper_gvec_vmalh16, },
+        { .fni4 = gen_malh_i32, },
+    };
+    static const GVecGen4 g_vmae[3] = {
+        { .fno = gen_helper_gvec_vmae8, },
+        { .fno = gen_helper_gvec_vmae16, },
+        { .fno = gen_helper_gvec_vmae32, },
+    };
+    static const GVecGen4 g_vmale[3] = {
+        { .fno = gen_helper_gvec_vmale8, },
+        { .fno = gen_helper_gvec_vmale16, },
+        { .fno = gen_helper_gvec_vmale32, },
+    };
+    static const GVecGen4 g_vmao[3] = {
+        { .fno = gen_helper_gvec_vmao8, },
+        { .fno = gen_helper_gvec_vmao16, },
+        { .fno = gen_helper_gvec_vmao32, },
+    };
+    static const GVecGen4 g_vmalo[3] = {
+        { .fno = gen_helper_gvec_vmalo8, },
+        { .fno = gen_helper_gvec_vmalo16, },
+        { .fno = gen_helper_gvec_vmalo32, },
+    };
+    const GVecGen4 *fn;
+
+    if (es > ES_32) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    switch (s->fields.op2) {
+    case 0xaa:
+        fn = &g_vmal[es];
+        break;
+    case 0xab:
+        fn = &g_vmah[es];
+        break;
+    case 0xa9:
+        fn = &g_vmalh[es];
+        break;
+    case 0xae:
+        fn = &g_vmae[es];
+        break;
+    case 0xac:
+        fn = &g_vmale[es];
+        break;
+    case 0xaf:
+        fn = &g_vmao[es];
+        break;
+    case 0xad:
+        fn = &g_vmalo[es];
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    gen_gvec_4(get_field(s, v1), get_field(s, v2),
+               get_field(s, v3), get_field(s, v4), fn);
+    return DISAS_NEXT;
+}
+
+static void gen_mh_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
+{
+    TCGv_i32 t = tcg_temp_new_i32();
+
+    tcg_gen_muls2_i32(t, d, a, b);
+    tcg_temp_free_i32(t);
+}
+
+static void gen_mlh_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
+{
+    TCGv_i32 t = tcg_temp_new_i32();
+
+    tcg_gen_mulu2_i32(t, d, a, b);
+    tcg_temp_free_i32(t);
+}
+
+static DisasJumpType op_vm(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m4);
+    static const GVecGen3 g_vmh[3] = {
+        { .fno = gen_helper_gvec_vmh8, },
+        { .fno = gen_helper_gvec_vmh16, },
+        { .fni4 = gen_mh_i32, },
+    };
+    static const GVecGen3 g_vmlh[3] = {
+        { .fno = gen_helper_gvec_vmlh8, },
+        { .fno = gen_helper_gvec_vmlh16, },
+        { .fni4 = gen_mlh_i32, },
+    };
+    static const GVecGen3 g_vme[3] = {
+        { .fno = gen_helper_gvec_vme8, },
+        { .fno = gen_helper_gvec_vme16, },
+        { .fno = gen_helper_gvec_vme32, },
+    };
+    static const GVecGen3 g_vmle[3] = {
+        { .fno = gen_helper_gvec_vmle8, },
+        { .fno = gen_helper_gvec_vmle16, },
+        { .fno = gen_helper_gvec_vmle32, },
+    };
+    static const GVecGen3 g_vmo[3] = {
+        { .fno = gen_helper_gvec_vmo8, },
+        { .fno = gen_helper_gvec_vmo16, },
+        { .fno = gen_helper_gvec_vmo32, },
+    };
+    static const GVecGen3 g_vmlo[3] = {
+        { .fno = gen_helper_gvec_vmlo8, },
+        { .fno = gen_helper_gvec_vmlo16, },
+        { .fno = gen_helper_gvec_vmlo32, },
+    };
+    const GVecGen3 *fn;
+
+    if (es > ES_32) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    switch (s->fields.op2) {
+    case 0xa2:
+        gen_gvec_fn_3(mul, es, get_field(s, v1),
+                      get_field(s, v2), get_field(s, v3));
+        return DISAS_NEXT;
+    case 0xa3:
+        fn = &g_vmh[es];
+        break;
+    case 0xa1:
+        fn = &g_vmlh[es];
+        break;
+    case 0xa6:
+        fn = &g_vme[es];
+        break;
+    case 0xa4:
+        fn = &g_vmle[es];
+        break;
+    case 0xa7:
+        fn = &g_vmo[es];
+        break;
+    case 0xa5:
+        fn = &g_vmlo[es];
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    gen_gvec_3(get_field(s, v1), get_field(s, v2),
+               get_field(s, v3), fn);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vmsl(DisasContext *s, DisasOps *o)
+{
+    TCGv_i64 l1, h1, l2, h2;
+
+    if (get_field(s, m5) != ES_64) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    l1 = tcg_temp_new_i64();
+    h1 = tcg_temp_new_i64();
+    l2 = tcg_temp_new_i64();
+    h2 = tcg_temp_new_i64();
+
+    /* Multipy both even elements from v2 and v3 */
+    read_vec_element_i64(l1, get_field(s, v2), 0, ES_64);
+    read_vec_element_i64(h1, get_field(s, v3), 0, ES_64);
+    tcg_gen_mulu2_i64(l1, h1, l1, h1);
+    /* Shift result left by one (x2) if requested */
+    if (extract32(get_field(s, m6), 3, 1)) {
+        tcg_gen_add2_i64(l1, h1, l1, h1, l1, h1);
+    }
+
+    /* Multipy both odd elements from v2 and v3 */
+    read_vec_element_i64(l2, get_field(s, v2), 1, ES_64);
+    read_vec_element_i64(h2, get_field(s, v3), 1, ES_64);
+    tcg_gen_mulu2_i64(l2, h2, l2, h2);
+    /* Shift result left by one (x2) if requested */
+    if (extract32(get_field(s, m6), 2, 1)) {
+        tcg_gen_add2_i64(l2, h2, l2, h2, l2, h2);
+    }
+
+    /* Add both intermediate results */
+    tcg_gen_add2_i64(l1, h1, l1, h1, l2, h2);
+    /* Add whole v4 */
+    read_vec_element_i64(h2, get_field(s, v4), 0, ES_64);
+    read_vec_element_i64(l2, get_field(s, v4), 1, ES_64);
+    tcg_gen_add2_i64(l1, h1, l1, h1, l2, h2);
+
+    /* Store final result into v1. */
+    write_vec_element_i64(h1, get_field(s, v1), 0, ES_64);
+    write_vec_element_i64(l1, get_field(s, v1), 1, ES_64);
+
+    tcg_temp_free_i64(l1);
+    tcg_temp_free_i64(h1);
+    tcg_temp_free_i64(l2);
+    tcg_temp_free_i64(h2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vnn(DisasContext *s, DisasOps *o)
+{
+    gen_gvec_fn_3(nand, ES_8, get_field(s, v1),
+                  get_field(s, v2), get_field(s, v3));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vno(DisasContext *s, DisasOps *o)
+{
+    gen_gvec_fn_3(nor, ES_8, get_field(s, v1), get_field(s, v2),
+                  get_field(s, v3));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vnx(DisasContext *s, DisasOps *o)
+{
+    gen_gvec_fn_3(eqv, ES_8, get_field(s, v1), get_field(s, v2),
+                  get_field(s, v3));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vo(DisasContext *s, DisasOps *o)
+{
+    gen_gvec_fn_3(or, ES_8, get_field(s, v1), get_field(s, v2),
+                  get_field(s, v3));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_voc(DisasContext *s, DisasOps *o)
+{
+    gen_gvec_fn_3(orc, ES_8, get_field(s, v1), get_field(s, v2),
+                  get_field(s, v3));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vpopct(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m3);
+    static const GVecGen2 g[4] = {
+        { .fno = gen_helper_gvec_vpopct8, },
+        { .fno = gen_helper_gvec_vpopct16, },
+        { .fni4 = tcg_gen_ctpop_i32, },
+        { .fni8 = tcg_gen_ctpop_i64, },
+    };
+
+    if (es > ES_64 || (es != ES_8 && !s390_has_feat(S390_FEAT_VECTOR_ENH))) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    gen_gvec_2(get_field(s, v1), get_field(s, v2), &g[es]);
+    return DISAS_NEXT;
+}
+
+static void gen_rim_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, int32_t c)
+{
+    TCGv_i32 t = tcg_temp_new_i32();
+
+    tcg_gen_rotli_i32(t, a, c & 31);
+    tcg_gen_and_i32(t, t, b);
+    tcg_gen_andc_i32(d, d, b);
+    tcg_gen_or_i32(d, d, t);
+
+    tcg_temp_free_i32(t);
+}
+
+static void gen_rim_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b, int64_t c)
+{
+    TCGv_i64 t = tcg_temp_new_i64();
+
+    tcg_gen_rotli_i64(t, a, c & 63);
+    tcg_gen_and_i64(t, t, b);
+    tcg_gen_andc_i64(d, d, b);
+    tcg_gen_or_i64(d, d, t);
+
+    tcg_temp_free_i64(t);
+}
+
+static DisasJumpType op_verim(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m5);
+    const uint8_t i4 = get_field(s, i4) &
+                       (NUM_VEC_ELEMENT_BITS(es) - 1);
+    static const GVecGen3i g[4] = {
+        { .fno = gen_helper_gvec_verim8, },
+        { .fno = gen_helper_gvec_verim16, },
+        { .fni4 = gen_rim_i32,
+          .load_dest = true, },
+        { .fni8 = gen_rim_i64,
+          .load_dest = true, },
+    };
+
+    if (es > ES_64) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    gen_gvec_3i(get_field(s, v1), get_field(s, v2),
+                get_field(s, v3), i4, &g[es]);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vesv(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m4);
+    const uint8_t v1 = get_field(s, v1);
+    const uint8_t v2 = get_field(s, v2);
+    const uint8_t v3 = get_field(s, v3);
+
+    if (es > ES_64) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    switch (s->fields.op2) {
+    case 0x70:
+        gen_gvec_fn_3(shlv, es, v1, v2, v3);
+        break;
+    case 0x73:
+        gen_gvec_fn_3(rotlv, es, v1, v2, v3);
+        break;
+    case 0x7a:
+        gen_gvec_fn_3(sarv, es, v1, v2, v3);
+        break;
+    case 0x78:
+        gen_gvec_fn_3(shrv, es, v1, v2, v3);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_ves(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m4);
+    const uint8_t d2 = get_field(s, d2) &
+                       (NUM_VEC_ELEMENT_BITS(es) - 1);
+    const uint8_t v1 = get_field(s, v1);
+    const uint8_t v3 = get_field(s, v3);
+    TCGv_i32 shift;
+
+    if (es > ES_64) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    if (likely(!get_field(s, b2))) {
+        switch (s->fields.op2) {
+        case 0x30:
+            gen_gvec_fn_2i(shli, es, v1, v3, d2);
+            break;
+        case 0x33:
+            gen_gvec_fn_2i(rotli, es, v1, v3, d2);
+            break;
+        case 0x3a:
+            gen_gvec_fn_2i(sari, es, v1, v3, d2);
+            break;
+        case 0x38:
+            gen_gvec_fn_2i(shri, es, v1, v3, d2);
+            break;
+        default:
+            g_assert_not_reached();
+        }
+    } else {
+        shift = tcg_temp_new_i32();
+        tcg_gen_extrl_i64_i32(shift, o->addr1);
+        tcg_gen_andi_i32(shift, shift, NUM_VEC_ELEMENT_BITS(es) - 1);
+        switch (s->fields.op2) {
+        case 0x30:
+            gen_gvec_fn_2s(shls, es, v1, v3, shift);
+            break;
+        case 0x33:
+            gen_gvec_fn_2s(rotls, es, v1, v3, shift);
+            break;
+        case 0x3a:
+            gen_gvec_fn_2s(sars, es, v1, v3, shift);
+            break;
+        case 0x38:
+            gen_gvec_fn_2s(shrs, es, v1, v3, shift);
+            break;
+        default:
+            g_assert_not_reached();
+        }
+        tcg_temp_free_i32(shift);
+    }
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vsl(DisasContext *s, DisasOps *o)
+{
+    TCGv_i64 shift = tcg_temp_new_i64();
+
+    read_vec_element_i64(shift, get_field(s, v3), 7, ES_8);
+    if (s->fields.op2 == 0x74) {
+        tcg_gen_andi_i64(shift, shift, 0x7);
+    } else {
+        tcg_gen_andi_i64(shift, shift, 0x78);
+    }
+
+    gen_gvec_2i_ool(get_field(s, v1), get_field(s, v2),
+                    shift, 0, gen_helper_gvec_vsl);
+    tcg_temp_free_i64(shift);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vsldb(DisasContext *s, DisasOps *o)
+{
+    const uint8_t i4 = get_field(s, i4) & 0xf;
+    const int left_shift = (i4 & 7) * 8;
+    const int right_shift = 64 - left_shift;
+    TCGv_i64 t0 = tcg_temp_new_i64();
+    TCGv_i64 t1 = tcg_temp_new_i64();
+    TCGv_i64 t2 = tcg_temp_new_i64();
+
+    if ((i4 & 8) == 0) {
+        read_vec_element_i64(t0, get_field(s, v2), 0, ES_64);
+        read_vec_element_i64(t1, get_field(s, v2), 1, ES_64);
+        read_vec_element_i64(t2, get_field(s, v3), 0, ES_64);
+    } else {
+        read_vec_element_i64(t0, get_field(s, v2), 1, ES_64);
+        read_vec_element_i64(t1, get_field(s, v3), 0, ES_64);
+        read_vec_element_i64(t2, get_field(s, v3), 1, ES_64);
+    }
+    tcg_gen_extract2_i64(t0, t1, t0, right_shift);
+    tcg_gen_extract2_i64(t1, t2, t1, right_shift);
+    write_vec_element_i64(t0, get_field(s, v1), 0, ES_64);
+    write_vec_element_i64(t1, get_field(s, v1), 1, ES_64);
+
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+    tcg_temp_free(t2);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vsra(DisasContext *s, DisasOps *o)
+{
+    TCGv_i64 shift = tcg_temp_new_i64();
+
+    read_vec_element_i64(shift, get_field(s, v3), 7, ES_8);
+    if (s->fields.op2 == 0x7e) {
+        tcg_gen_andi_i64(shift, shift, 0x7);
+    } else {
+        tcg_gen_andi_i64(shift, shift, 0x78);
+    }
+
+    gen_gvec_2i_ool(get_field(s, v1), get_field(s, v2),
+                    shift, 0, gen_helper_gvec_vsra);
+    tcg_temp_free_i64(shift);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vsrl(DisasContext *s, DisasOps *o)
+{
+    TCGv_i64 shift = tcg_temp_new_i64();
+
+    read_vec_element_i64(shift, get_field(s, v3), 7, ES_8);
+    if (s->fields.op2 == 0x7c) {
+        tcg_gen_andi_i64(shift, shift, 0x7);
+    } else {
+        tcg_gen_andi_i64(shift, shift, 0x78);
+    }
+
+    gen_gvec_2i_ool(get_field(s, v1), get_field(s, v2),
+                    shift, 0, gen_helper_gvec_vsrl);
+    tcg_temp_free_i64(shift);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vs(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m4);
+
+    if (es > ES_128) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    } else if (es == ES_128) {
+        gen_gvec128_3_i64(tcg_gen_sub2_i64, get_field(s, v1),
+                          get_field(s, v2), get_field(s, v3));
+        return DISAS_NEXT;
+    }
+    gen_gvec_fn_3(sub, es, get_field(s, v1), get_field(s, v2),
+                  get_field(s, v3));
+    return DISAS_NEXT;
+}
+
+static void gen_scbi_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
+{
+    tcg_gen_setcond_i32(TCG_COND_GEU, d, a, b);
+}
+
+static void gen_scbi_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
+{
+    tcg_gen_setcond_i64(TCG_COND_GEU, d, a, b);
+}
+
+static void gen_scbi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
+                          TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh)
+{
+    TCGv_i64 th = tcg_temp_new_i64();
+    TCGv_i64 tl = tcg_temp_new_i64();
+    TCGv_i64 zero = tcg_const_i64(0);
+
+    tcg_gen_sub2_i64(tl, th, al, zero, bl, zero);
+    tcg_gen_andi_i64(th, th, 1);
+    tcg_gen_sub2_i64(tl, th, ah, zero, th, zero);
+    tcg_gen_sub2_i64(tl, th, tl, th, bh, zero);
+    /* "invert" the result: -1 -> 0; 0 -> 1 */
+    tcg_gen_addi_i64(dl, th, 1);
+    tcg_gen_mov_i64(dh, zero);
+
+    tcg_temp_free_i64(th);
+    tcg_temp_free_i64(tl);
+    tcg_temp_free_i64(zero);
+}
+
+static DisasJumpType op_vscbi(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m4);
+    static const GVecGen3 g[4] = {
+        { .fno = gen_helper_gvec_vscbi8, },
+        { .fno = gen_helper_gvec_vscbi16, },
+        { .fni4 = gen_scbi_i32, },
+        { .fni8 = gen_scbi_i64, },
+    };
+
+    if (es > ES_128) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    } else if (es == ES_128) {
+        gen_gvec128_3_i64(gen_scbi2_i64, get_field(s, v1),
+                          get_field(s, v2), get_field(s, v3));
+        return DISAS_NEXT;
+    }
+    gen_gvec_3(get_field(s, v1), get_field(s, v2),
+               get_field(s, v3), &g[es]);
+    return DISAS_NEXT;
+}
+
+static void gen_sbi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
+                         TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
+{
+    TCGv_i64 tl = tcg_temp_new_i64();
+    TCGv_i64 th = tcg_temp_new_i64();
+
+    tcg_gen_not_i64(tl, bl);
+    tcg_gen_not_i64(th, bh);
+    gen_ac2_i64(dl, dh, al, ah, tl, th, cl, ch);
+    tcg_temp_free_i64(tl);
+    tcg_temp_free_i64(th);
+}
+
+static DisasJumpType op_vsbi(DisasContext *s, DisasOps *o)
+{
+    if (get_field(s, m5) != ES_128) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    gen_gvec128_4_i64(gen_sbi2_i64, get_field(s, v1),
+                      get_field(s, v2), get_field(s, v3),
+                      get_field(s, v4));
+    return DISAS_NEXT;
+}
+
+static void gen_sbcbi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
+                           TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
+{
+    TCGv_i64 th = tcg_temp_new_i64();
+    TCGv_i64 tl = tcg_temp_new_i64();
+
+    tcg_gen_not_i64(tl, bl);
+    tcg_gen_not_i64(th, bh);
+    gen_accc2_i64(dl, dh, al, ah, tl, th, cl, ch);
+
+    tcg_temp_free_i64(tl);
+    tcg_temp_free_i64(th);
+}
+
+static DisasJumpType op_vsbcbi(DisasContext *s, DisasOps *o)
+{
+    if (get_field(s, m5) != ES_128) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    gen_gvec128_4_i64(gen_sbcbi2_i64, get_field(s, v1),
+                      get_field(s, v2), get_field(s, v3),
+                      get_field(s, v4));
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vsumg(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m4);
+    TCGv_i64 sum, tmp;
+    uint8_t dst_idx;
+
+    if (es == ES_8 || es > ES_32) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    sum = tcg_temp_new_i64();
+    tmp = tcg_temp_new_i64();
+    for (dst_idx = 0; dst_idx < 2; dst_idx++) {
+        uint8_t idx = dst_idx * NUM_VEC_ELEMENTS(es) / 2;
+        const uint8_t max_idx = idx + NUM_VEC_ELEMENTS(es) / 2 - 1;
+
+        read_vec_element_i64(sum, get_field(s, v3), max_idx, es);
+        for (; idx <= max_idx; idx++) {
+            read_vec_element_i64(tmp, get_field(s, v2), idx, es);
+            tcg_gen_add_i64(sum, sum, tmp);
+        }
+        write_vec_element_i64(sum, get_field(s, v1), dst_idx, ES_64);
+    }
+    tcg_temp_free_i64(sum);
+    tcg_temp_free_i64(tmp);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vsumq(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m4);
+    const uint8_t max_idx = NUM_VEC_ELEMENTS(es) - 1;
+    TCGv_i64 sumh, suml, zero, tmpl;
+    uint8_t idx;
+
+    if (es < ES_32 || es > ES_64) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    sumh = tcg_const_i64(0);
+    suml = tcg_temp_new_i64();
+    zero = tcg_const_i64(0);
+    tmpl = tcg_temp_new_i64();
+
+    read_vec_element_i64(suml, get_field(s, v3), max_idx, es);
+    for (idx = 0; idx <= max_idx; idx++) {
+        read_vec_element_i64(tmpl, get_field(s, v2), idx, es);
+        tcg_gen_add2_i64(suml, sumh, suml, sumh, tmpl, zero);
+    }
+    write_vec_element_i64(sumh, get_field(s, v1), 0, ES_64);
+    write_vec_element_i64(suml, get_field(s, v1), 1, ES_64);
+
+    tcg_temp_free_i64(sumh);
+    tcg_temp_free_i64(suml);
+    tcg_temp_free_i64(zero);
+    tcg_temp_free_i64(tmpl);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vsum(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m4);
+    TCGv_i32 sum, tmp;
+    uint8_t dst_idx;
+
+    if (es > ES_16) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    sum = tcg_temp_new_i32();
+    tmp = tcg_temp_new_i32();
+    for (dst_idx = 0; dst_idx < 4; dst_idx++) {
+        uint8_t idx = dst_idx * NUM_VEC_ELEMENTS(es) / 4;
+        const uint8_t max_idx = idx + NUM_VEC_ELEMENTS(es) / 4 - 1;
+
+        read_vec_element_i32(sum, get_field(s, v3), max_idx, es);
+        for (; idx <= max_idx; idx++) {
+            read_vec_element_i32(tmp, get_field(s, v2), idx, es);
+            tcg_gen_add_i32(sum, sum, tmp);
+        }
+        write_vec_element_i32(sum, get_field(s, v1), dst_idx, ES_32);
+    }
+    tcg_temp_free_i32(sum);
+    tcg_temp_free_i32(tmp);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vtm(DisasContext *s, DisasOps *o)
+{
+    gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2),
+                   cpu_env, 0, gen_helper_gvec_vtm);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vfae(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m4);
+    const uint8_t m5 = get_field(s, m5);
+    static gen_helper_gvec_3 * const g[3] = {
+        gen_helper_gvec_vfae8,
+        gen_helper_gvec_vfae16,
+        gen_helper_gvec_vfae32,
+    };
+    static gen_helper_gvec_3_ptr * const g_cc[3] = {
+        gen_helper_gvec_vfae_cc8,
+        gen_helper_gvec_vfae_cc16,
+        gen_helper_gvec_vfae_cc32,
+    };
+    if (es > ES_32) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    if (extract32(m5, 0, 1)) {
+        gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2),
+                       get_field(s, v3), cpu_env, m5, g_cc[es]);
+        set_cc_static(s);
+    } else {
+        gen_gvec_3_ool(get_field(s, v1), get_field(s, v2),
+                       get_field(s, v3), m5, g[es]);
+    }
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vfee(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m4);
+    const uint8_t m5 = get_field(s, m5);
+    static gen_helper_gvec_3 * const g[3] = {
+        gen_helper_gvec_vfee8,
+        gen_helper_gvec_vfee16,
+        gen_helper_gvec_vfee32,
+    };
+    static gen_helper_gvec_3_ptr * const g_cc[3] = {
+        gen_helper_gvec_vfee_cc8,
+        gen_helper_gvec_vfee_cc16,
+        gen_helper_gvec_vfee_cc32,
+    };
+
+    if (es > ES_32 || m5 & ~0x3) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    if (extract32(m5, 0, 1)) {
+        gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2),
+                       get_field(s, v3), cpu_env, m5, g_cc[es]);
+        set_cc_static(s);
+    } else {
+        gen_gvec_3_ool(get_field(s, v1), get_field(s, v2),
+                       get_field(s, v3), m5, g[es]);
+    }
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vfene(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m4);
+    const uint8_t m5 = get_field(s, m5);
+    static gen_helper_gvec_3 * const g[3] = {
+        gen_helper_gvec_vfene8,
+        gen_helper_gvec_vfene16,
+        gen_helper_gvec_vfene32,
+    };
+    static gen_helper_gvec_3_ptr * const g_cc[3] = {
+        gen_helper_gvec_vfene_cc8,
+        gen_helper_gvec_vfene_cc16,
+        gen_helper_gvec_vfene_cc32,
+    };
+
+    if (es > ES_32 || m5 & ~0x3) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    if (extract32(m5, 0, 1)) {
+        gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2),
+                       get_field(s, v3), cpu_env, m5, g_cc[es]);
+        set_cc_static(s);
+    } else {
+        gen_gvec_3_ool(get_field(s, v1), get_field(s, v2),
+                       get_field(s, v3), m5, g[es]);
+    }
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vistr(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m4);
+    const uint8_t m5 = get_field(s, m5);
+    static gen_helper_gvec_2 * const g[3] = {
+        gen_helper_gvec_vistr8,
+        gen_helper_gvec_vistr16,
+        gen_helper_gvec_vistr32,
+    };
+    static gen_helper_gvec_2_ptr * const g_cc[3] = {
+        gen_helper_gvec_vistr_cc8,
+        gen_helper_gvec_vistr_cc16,
+        gen_helper_gvec_vistr_cc32,
+    };
+
+    if (es > ES_32 || m5 & ~0x1) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    if (extract32(m5, 0, 1)) {
+        gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2),
+                       cpu_env, 0, g_cc[es]);
+        set_cc_static(s);
+    } else {
+        gen_gvec_2_ool(get_field(s, v1), get_field(s, v2), 0,
+                       g[es]);
+    }
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vstrc(DisasContext *s, DisasOps *o)
+{
+    const uint8_t es = get_field(s, m5);
+    const uint8_t m6 = get_field(s, m6);
+    static gen_helper_gvec_4 * const g[3] = {
+        gen_helper_gvec_vstrc8,
+        gen_helper_gvec_vstrc16,
+        gen_helper_gvec_vstrc32,
+    };
+    static gen_helper_gvec_4 * const g_rt[3] = {
+        gen_helper_gvec_vstrc_rt8,
+        gen_helper_gvec_vstrc_rt16,
+        gen_helper_gvec_vstrc_rt32,
+    };
+    static gen_helper_gvec_4_ptr * const g_cc[3] = {
+        gen_helper_gvec_vstrc_cc8,
+        gen_helper_gvec_vstrc_cc16,
+        gen_helper_gvec_vstrc_cc32,
+    };
+    static gen_helper_gvec_4_ptr * const g_cc_rt[3] = {
+        gen_helper_gvec_vstrc_cc_rt8,
+        gen_helper_gvec_vstrc_cc_rt16,
+        gen_helper_gvec_vstrc_cc_rt32,
+    };
+
+    if (es > ES_32) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    if (extract32(m6, 0, 1)) {
+        if (extract32(m6, 2, 1)) {
+            gen_gvec_4_ptr(get_field(s, v1), get_field(s, v2),
+                           get_field(s, v3), get_field(s, v4),
+                           cpu_env, m6, g_cc_rt[es]);
+        } else {
+            gen_gvec_4_ptr(get_field(s, v1), get_field(s, v2),
+                           get_field(s, v3), get_field(s, v4),
+                           cpu_env, m6, g_cc[es]);
+        }
+        set_cc_static(s);
+    } else {
+        if (extract32(m6, 2, 1)) {
+            gen_gvec_4_ool(get_field(s, v1), get_field(s, v2),
+                           get_field(s, v3), get_field(s, v4),
+                           m6, g_rt[es]);
+        } else {
+            gen_gvec_4_ool(get_field(s, v1), get_field(s, v2),
+                           get_field(s, v3), get_field(s, v4),
+                           m6, g[es]);
+        }
+    }
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vfa(DisasContext *s, DisasOps *o)
+{
+    const uint8_t fpf = get_field(s, m4);
+    const uint8_t m5 = get_field(s, m5);
+    gen_helper_gvec_3_ptr *fn = NULL;
+
+    switch (s->fields.op2) {
+    case 0xe3:
+        switch (fpf) {
+        case FPF_SHORT:
+            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
+                fn = gen_helper_gvec_vfa32;
+            }
+            break;
+        case FPF_LONG:
+            fn = gen_helper_gvec_vfa64;
+            break;
+        case FPF_EXT:
+            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
+                fn = gen_helper_gvec_vfa128;
+            }
+            break;
+        default:
+            break;
+        }
+        break;
+    case 0xe5:
+        switch (fpf) {
+        case FPF_SHORT:
+            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
+                fn = gen_helper_gvec_vfd32;
+            }
+            break;
+        case FPF_LONG:
+            fn = gen_helper_gvec_vfd64;
+            break;
+        case FPF_EXT:
+            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
+                fn = gen_helper_gvec_vfd128;
+            }
+            break;
+        default:
+            break;
+        }
+        break;
+    case 0xe7:
+        switch (fpf) {
+        case FPF_SHORT:
+            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
+                fn = gen_helper_gvec_vfm32;
+            }
+            break;
+        case FPF_LONG:
+            fn = gen_helper_gvec_vfm64;
+            break;
+        case FPF_EXT:
+            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
+                fn = gen_helper_gvec_vfm128;
+            }
+            break;
+        default:
+            break;
+        }
+        break;
+    case 0xe2:
+        switch (fpf) {
+        case FPF_SHORT:
+            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
+                fn = gen_helper_gvec_vfs32;
+            }
+            break;
+        case FPF_LONG:
+            fn = gen_helper_gvec_vfs64;
+            break;
+        case FPF_EXT:
+            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
+                fn = gen_helper_gvec_vfs128;
+            }
+            break;
+        default:
+            break;
+        }
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    if (!fn || extract32(m5, 0, 3)) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2),
+                   get_field(s, v3), cpu_env, m5, fn);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_wfc(DisasContext *s, DisasOps *o)
+{
+    const uint8_t fpf = get_field(s, m3);
+    const uint8_t m4 = get_field(s, m4);
+    gen_helper_gvec_2_ptr *fn = NULL;
+
+    switch (fpf) {
+    case FPF_SHORT:
+        if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
+            fn = gen_helper_gvec_wfk32;
+            if (s->fields.op2 == 0xcb) {
+                fn = gen_helper_gvec_wfc32;
+            }
+        }
+        break;
+    case FPF_LONG:
+        fn = gen_helper_gvec_wfk64;
+        if (s->fields.op2 == 0xcb) {
+            fn = gen_helper_gvec_wfc64;
+        }
+        break;
+    case FPF_EXT:
+        if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
+            fn = gen_helper_gvec_wfk128;
+            if (s->fields.op2 == 0xcb) {
+                fn = gen_helper_gvec_wfc128;
+            }
+        }
+        break;
+    default:
+        break;
+    };
+
+    if (!fn || m4) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, 0, fn);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vfc(DisasContext *s, DisasOps *o)
+{
+    const uint8_t fpf = get_field(s, m4);
+    const uint8_t m5 = get_field(s, m5);
+    const uint8_t m6 = get_field(s, m6);
+    const bool cs = extract32(m6, 0, 1);
+    const bool sq = extract32(m5, 2, 1);
+    gen_helper_gvec_3_ptr *fn = NULL;
+
+    switch (s->fields.op2) {
+    case 0xe8:
+        switch (fpf) {
+        case FPF_SHORT:
+            fn = cs ? gen_helper_gvec_vfce32_cc : gen_helper_gvec_vfce32;
+            break;
+        case FPF_LONG:
+            fn = cs ? gen_helper_gvec_vfce64_cc : gen_helper_gvec_vfce64;
+            break;
+        case FPF_EXT:
+            fn = cs ? gen_helper_gvec_vfce128_cc : gen_helper_gvec_vfce128;
+            break;
+        default:
+            break;
+        }
+        break;
+    case 0xeb:
+        switch (fpf) {
+        case FPF_SHORT:
+            fn = cs ? gen_helper_gvec_vfch32_cc : gen_helper_gvec_vfch32;
+            break;
+        case FPF_LONG:
+            fn = cs ? gen_helper_gvec_vfch64_cc : gen_helper_gvec_vfch64;
+            break;
+        case FPF_EXT:
+            fn = cs ? gen_helper_gvec_vfch128_cc : gen_helper_gvec_vfch128;
+            break;
+        default:
+            break;
+        }
+        break;
+    case 0xea:
+        switch (fpf) {
+        case FPF_SHORT:
+            fn = cs ? gen_helper_gvec_vfche32_cc : gen_helper_gvec_vfche32;
+            break;
+        case FPF_LONG:
+            fn = cs ? gen_helper_gvec_vfche64_cc : gen_helper_gvec_vfche64;
+            break;
+        case FPF_EXT:
+            fn = cs ? gen_helper_gvec_vfche128_cc : gen_helper_gvec_vfche128;
+            break;
+        default:
+            break;
+        }
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    if (!fn || extract32(m5, 0, 2) || extract32(m6, 1, 3) ||
+        (!s390_has_feat(S390_FEAT_VECTOR_ENH) && (fpf != FPF_LONG || sq))) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2), get_field(s, v3),
+                   cpu_env, m5, fn);
+    if (cs) {
+        set_cc_static(s);
+    }
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vcdg(DisasContext *s, DisasOps *o)
+{
+    const uint8_t fpf = get_field(s, m3);
+    const uint8_t m4 = get_field(s, m4);
+    const uint8_t erm = get_field(s, m5);
+    gen_helper_gvec_2_ptr *fn = NULL;
+
+
+    switch (s->fields.op2) {
+    case 0xc3:
+        if (fpf == FPF_LONG) {
+            fn = gen_helper_gvec_vcdg64;
+        }
+        break;
+    case 0xc1:
+        if (fpf == FPF_LONG) {
+            fn = gen_helper_gvec_vcdlg64;
+        }
+        break;
+    case 0xc2:
+        if (fpf == FPF_LONG) {
+            fn = gen_helper_gvec_vcgd64;
+        }
+        break;
+    case 0xc0:
+        if (fpf == FPF_LONG) {
+            fn = gen_helper_gvec_vclgd64;
+        }
+        break;
+    case 0xc7:
+        switch (fpf) {
+        case FPF_SHORT:
+            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
+                fn = gen_helper_gvec_vfi32;
+            }
+            break;
+        case FPF_LONG:
+            fn = gen_helper_gvec_vfi64;
+            break;
+        case FPF_EXT:
+            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
+                fn = gen_helper_gvec_vfi128;
+            }
+            break;
+        default:
+            break;
+        }
+        break;
+    case 0xc5:
+        switch (fpf) {
+        case FPF_LONG:
+            fn = gen_helper_gvec_vflr64;
+            break;
+        case FPF_EXT:
+            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
+                fn = gen_helper_gvec_vflr128;
+            }
+            break;
+        default:
+            break;
+        }
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    if (!fn || extract32(m4, 0, 2) || erm > 7 || erm == 2) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env,
+                   deposit32(m4, 4, 4, erm), fn);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vfll(DisasContext *s, DisasOps *o)
+{
+    const uint8_t fpf = get_field(s, m3);
+    const uint8_t m4 = get_field(s, m4);
+    gen_helper_gvec_2_ptr *fn = NULL;
+
+    switch (fpf) {
+    case FPF_SHORT:
+        fn = gen_helper_gvec_vfll32;
+        break;
+    case FPF_LONG:
+        if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
+            fn = gen_helper_gvec_vfll64;
+        }
+        break;
+    default:
+        break;
+    }
+
+    if (!fn || extract32(m4, 0, 3)) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, m4, fn);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vfmax(DisasContext *s, DisasOps *o)
+{
+    const uint8_t fpf = get_field(s, m4);
+    const uint8_t m6 = get_field(s, m6);
+    const uint8_t m5 = get_field(s, m5);
+    gen_helper_gvec_3_ptr *fn;
+
+    if (m6 == 5 || m6 == 6 || m6 == 7 || m6 > 13) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    switch (fpf) {
+    case FPF_SHORT:
+        if (s->fields.op2 == 0xef) {
+            fn = gen_helper_gvec_vfmax32;
+        } else {
+            fn = gen_helper_gvec_vfmin32;
+        }
+        break;
+    case FPF_LONG:
+        if (s->fields.op2 == 0xef) {
+            fn = gen_helper_gvec_vfmax64;
+        } else {
+            fn = gen_helper_gvec_vfmin64;
+        }
+        break;
+    case FPF_EXT:
+        if (s->fields.op2 == 0xef) {
+            fn = gen_helper_gvec_vfmax128;
+        } else {
+            fn = gen_helper_gvec_vfmin128;
+        }
+        break;
+    default:
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2), get_field(s, v3),
+                   cpu_env, deposit32(m5, 4, 4, m6), fn);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vfma(DisasContext *s, DisasOps *o)
+{
+    const uint8_t m5 = get_field(s, m5);
+    const uint8_t fpf = get_field(s, m6);
+    gen_helper_gvec_4_ptr *fn = NULL;
+
+    switch (s->fields.op2) {
+    case 0x8f:
+        switch (fpf) {
+        case FPF_SHORT:
+            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
+                fn = gen_helper_gvec_vfma32;
+            }
+            break;
+        case FPF_LONG:
+            fn = gen_helper_gvec_vfma64;
+            break;
+        case FPF_EXT:
+            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
+                fn = gen_helper_gvec_vfma128;
+            }
+            break;
+        default:
+            break;
+        }
+        break;
+    case 0x8e:
+        switch (fpf) {
+        case FPF_SHORT:
+            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
+                fn = gen_helper_gvec_vfms32;
+            }
+            break;
+        case FPF_LONG:
+            fn = gen_helper_gvec_vfms64;
+            break;
+        case FPF_EXT:
+            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
+                fn = gen_helper_gvec_vfms128;
+            }
+            break;
+        default:
+            break;
+        }
+        break;
+    case 0x9f:
+        switch (fpf) {
+        case FPF_SHORT:
+            fn = gen_helper_gvec_vfnma32;
+            break;
+        case FPF_LONG:
+            fn = gen_helper_gvec_vfnma64;
+            break;
+        case FPF_EXT:
+            fn = gen_helper_gvec_vfnma128;
+            break;
+        default:
+            break;
+        }
+        break;
+    case 0x9e:
+        switch (fpf) {
+        case FPF_SHORT:
+            fn = gen_helper_gvec_vfnms32;
+            break;
+        case FPF_LONG:
+            fn = gen_helper_gvec_vfnms64;
+            break;
+        case FPF_EXT:
+            fn = gen_helper_gvec_vfnms128;
+            break;
+        default:
+            break;
+        }
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    if (!fn || extract32(m5, 0, 3)) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    gen_gvec_4_ptr(get_field(s, v1), get_field(s, v2),
+                   get_field(s, v3), get_field(s, v4), cpu_env, m5, fn);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vfpso(DisasContext *s, DisasOps *o)
+{
+    const uint8_t v1 = get_field(s, v1);
+    const uint8_t v2 = get_field(s, v2);
+    const uint8_t fpf = get_field(s, m3);
+    const uint8_t m4 = get_field(s, m4);
+    const uint8_t m5 = get_field(s, m5);
+    const bool se = extract32(m4, 3, 1);
+    TCGv_i64 tmp;
+
+    if ((fpf != FPF_LONG && !s390_has_feat(S390_FEAT_VECTOR_ENH)) ||
+        extract32(m4, 0, 3) || m5 > 2) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    switch (fpf) {
+    case FPF_SHORT:
+        if (!se) {
+            switch (m5) {
+            case 0:
+                /* sign bit is inverted (complement) */
+                gen_gvec_fn_2i(xori, ES_32, v1, v2, 1ull << 31);
+                break;
+            case 1:
+                /* sign bit is set to one (negative) */
+                gen_gvec_fn_2i(ori, ES_32, v1, v2, 1ull << 31);
+                break;
+            case 2:
+                /* sign bit is set to zero (positive) */
+                gen_gvec_fn_2i(andi, ES_32, v1, v2, (1ull << 31) - 1);
+                break;
+            }
+            return DISAS_NEXT;
+        }
+        break;
+    case FPF_LONG:
+        if (!se) {
+            switch (m5) {
+            case 0:
+                /* sign bit is inverted (complement) */
+                gen_gvec_fn_2i(xori, ES_64, v1, v2, 1ull << 63);
+                break;
+            case 1:
+                /* sign bit is set to one (negative) */
+                gen_gvec_fn_2i(ori, ES_64, v1, v2, 1ull << 63);
+                break;
+            case 2:
+                /* sign bit is set to zero (positive) */
+                gen_gvec_fn_2i(andi, ES_64, v1, v2, (1ull << 63) - 1);
+                break;
+            }
+            return DISAS_NEXT;
+        }
+        break;
+    case FPF_EXT:
+        /* Only a single element. */
+        break;
+    default:
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    /* With a single element, we are only interested in bit 0. */
+    tmp = tcg_temp_new_i64();
+    read_vec_element_i64(tmp, v2, 0, ES_64);
+    switch (m5) {
+    case 0:
+        /* sign bit is inverted (complement) */
+        tcg_gen_xori_i64(tmp, tmp, 1ull << 63);
+        break;
+    case 1:
+        /* sign bit is set to one (negative) */
+        tcg_gen_ori_i64(tmp, tmp, 1ull << 63);
+        break;
+    case 2:
+        /* sign bit is set to zero (positive) */
+        tcg_gen_andi_i64(tmp, tmp, (1ull << 63) - 1);
+        break;
+    }
+    write_vec_element_i64(tmp, v1, 0, ES_64);
+
+    if (fpf == FPF_EXT) {
+        read_vec_element_i64(tmp, v2, 1, ES_64);
+        write_vec_element_i64(tmp, v1, 1, ES_64);
+    }
+
+    tcg_temp_free_i64(tmp);
+
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vfsq(DisasContext *s, DisasOps *o)
+{
+    const uint8_t fpf = get_field(s, m3);
+    const uint8_t m4 = get_field(s, m4);
+    gen_helper_gvec_2_ptr *fn = NULL;
+
+    switch (fpf) {
+    case FPF_SHORT:
+        if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
+            fn = gen_helper_gvec_vfsq32;
+        }
+        break;
+    case FPF_LONG:
+        fn = gen_helper_gvec_vfsq64;
+        break;
+    case FPF_EXT:
+        if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
+            fn = gen_helper_gvec_vfsq128;
+        }
+        break;
+    default:
+        break;
+    }
+
+    if (!fn || extract32(m4, 0, 3)) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, m4, fn);
+    return DISAS_NEXT;
+}
+
+static DisasJumpType op_vftci(DisasContext *s, DisasOps *o)
+{
+    const uint16_t i3 = get_field(s, i3);
+    const uint8_t fpf = get_field(s, m4);
+    const uint8_t m5 = get_field(s, m5);
+    gen_helper_gvec_2_ptr *fn = NULL;
+
+    switch (fpf) {
+    case FPF_SHORT:
+        if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
+            fn = gen_helper_gvec_vftci32;
+        }
+        break;
+    case FPF_LONG:
+        fn = gen_helper_gvec_vftci64;
+        break;
+    case FPF_EXT:
+        if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
+            fn = gen_helper_gvec_vftci128;
+        }
+        break;
+    default:
+        break;
+    }
+
+    if (!fn || extract32(m5, 0, 3)) {
+        gen_program_exception(s, PGM_SPECIFICATION);
+        return DISAS_NORETURN;
+    }
+
+    gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env,
+                   deposit32(m5, 4, 12, i3), fn);
+    set_cc_static(s);
+    return DISAS_NEXT;
+}
diff --git a/target/s390x/tcg/vec.h b/target/s390x/tcg/vec.h
new file mode 100644 (file)
index 0000000..a6e3618
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * QEMU TCG support -- s390x vector utilitites
+ *
+ * Copyright (C) 2019 Red Hat Inc
+ *
+ * Authors:
+ *   David Hildenbrand <david@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#ifndef S390X_VEC_H
+#define S390X_VEC_H
+
+#include "tcg/tcg.h"
+
+typedef union S390Vector {
+    uint64_t doubleword[2];
+    uint32_t word[4];
+    uint16_t halfword[8];
+    uint8_t byte[16];
+} S390Vector;
+
+/*
+ * Each vector is stored as two 64bit host values. So when talking about
+ * byte/halfword/word numbers, we have to take care of proper translation
+ * between element numbers.
+ *
+ * Big Endian (target/possible host)
+ * B:  [ 0][ 1][ 2][ 3][ 4][ 5][ 6][ 7] - [ 8][ 9][10][11][12][13][14][15]
+ * HW: [     0][     1][     2][     3] - [     4][     5][     6][     7]
+ * W:  [             0][             1] - [             2][             3]
+ * DW: [                             0] - [                             1]
+ *
+ * Little Endian (possible host)
+ * B:  [ 7][ 6][ 5][ 4][ 3][ 2][ 1][ 0] - [15][14][13][12][11][10][ 9][ 8]
+ * HW: [     3][     2][     1][     0] - [     7][     6][     5][     4]
+ * W:  [             1][             0] - [             3][             2]
+ * DW: [                             0] - [                             1]
+ */
+#ifndef HOST_WORDS_BIGENDIAN
+#define H1(x)  ((x) ^ 7)
+#define H2(x)  ((x) ^ 3)
+#define H4(x)  ((x) ^ 1)
+#else
+#define H1(x)  (x)
+#define H2(x)  (x)
+#define H4(x)  (x)
+#endif
+
+static inline uint8_t s390_vec_read_element8(const S390Vector *v, uint8_t enr)
+{
+    g_assert(enr < 16);
+    return v->byte[H1(enr)];
+}
+
+static inline uint16_t s390_vec_read_element16(const S390Vector *v, uint8_t enr)
+{
+    g_assert(enr < 8);
+    return v->halfword[H2(enr)];
+}
+
+static inline uint32_t s390_vec_read_element32(const S390Vector *v, uint8_t enr)
+{
+    g_assert(enr < 4);
+    return v->word[H4(enr)];
+}
+
+static inline uint64_t s390_vec_read_element64(const S390Vector *v, uint8_t enr)
+{
+    g_assert(enr < 2);
+    return v->doubleword[enr];
+}
+
+static inline uint64_t s390_vec_read_element(const S390Vector *v, uint8_t enr,
+                                             uint8_t es)
+{
+    switch (es) {
+    case MO_8:
+        return s390_vec_read_element8(v, enr);
+    case MO_16:
+        return s390_vec_read_element16(v, enr);
+    case MO_32:
+        return s390_vec_read_element32(v, enr);
+    case MO_64:
+        return s390_vec_read_element64(v, enr);
+    default:
+        g_assert_not_reached();
+    }
+}
+
+static inline void s390_vec_write_element8(S390Vector *v, uint8_t enr,
+                                           uint8_t data)
+{
+    g_assert(enr < 16);
+    v->byte[H1(enr)] = data;
+}
+
+static inline void s390_vec_write_element16(S390Vector *v, uint8_t enr,
+                                            uint16_t data)
+{
+    g_assert(enr < 8);
+    v->halfword[H2(enr)] = data;
+}
+
+static inline void s390_vec_write_element32(S390Vector *v, uint8_t enr,
+                                            uint32_t data)
+{
+    g_assert(enr < 4);
+    v->word[H4(enr)] = data;
+}
+
+static inline void s390_vec_write_element64(S390Vector *v, uint8_t enr,
+                                            uint64_t data)
+{
+    g_assert(enr < 2);
+    v->doubleword[enr] = data;
+}
+
+static inline void s390_vec_write_element(S390Vector *v, uint8_t enr,
+                                          uint8_t es, uint64_t data)
+{
+    switch (es) {
+    case MO_8:
+        s390_vec_write_element8(v, enr, data);
+        break;
+    case MO_16:
+        s390_vec_write_element16(v, enr, data);
+        break;
+    case MO_32:
+        s390_vec_write_element32(v, enr, data);
+        break;
+    case MO_64:
+        s390_vec_write_element64(v, enr, data);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+
+#endif /* S390X_VEC_H */
diff --git a/target/s390x/tcg/vec_fpu_helper.c b/target/s390x/tcg/vec_fpu_helper.c
new file mode 100644 (file)
index 0000000..1a77993
--- /dev/null
@@ -0,0 +1,1072 @@
+/*
+ * QEMU TCG support -- s390x vector floating point instruction support
+ *
+ * Copyright (C) 2019 Red Hat Inc
+ *
+ * Authors:
+ *   David Hildenbrand <david@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "cpu.h"
+#include "s390x-internal.h"
+#include "vec.h"
+#include "tcg_s390x.h"
+#include "tcg/tcg-gvec-desc.h"
+#include "exec/exec-all.h"
+#include "exec/helper-proto.h"
+#include "fpu/softfloat.h"
+
+#define VIC_INVALID         0x1
+#define VIC_DIVBYZERO       0x2
+#define VIC_OVERFLOW        0x3
+#define VIC_UNDERFLOW       0x4
+#define VIC_INEXACT         0x5
+
+/* returns the VEX. If the VEX is 0, there is no trap */
+static uint8_t check_ieee_exc(CPUS390XState *env, uint8_t enr, bool XxC,
+                              uint8_t *vec_exc)
+{
+    uint8_t vece_exc = 0, trap_exc;
+    unsigned qemu_exc;
+
+    /* Retrieve and clear the softfloat exceptions */
+    qemu_exc = env->fpu_status.float_exception_flags;
+    if (qemu_exc == 0) {
+        return 0;
+    }
+    env->fpu_status.float_exception_flags = 0;
+
+    vece_exc = s390_softfloat_exc_to_ieee(qemu_exc);
+
+    /* Add them to the vector-wide s390x exception bits */
+    *vec_exc |= vece_exc;
+
+    /* Check for traps and construct the VXC */
+    trap_exc = vece_exc & env->fpc >> 24;
+    if (trap_exc) {
+        if (trap_exc & S390_IEEE_MASK_INVALID) {
+            return enr << 4 | VIC_INVALID;
+        } else if (trap_exc & S390_IEEE_MASK_DIVBYZERO) {
+            return enr << 4 | VIC_DIVBYZERO;
+        } else if (trap_exc & S390_IEEE_MASK_OVERFLOW) {
+            return enr << 4 | VIC_OVERFLOW;
+        } else if (trap_exc & S390_IEEE_MASK_UNDERFLOW) {
+            return enr << 4 | VIC_UNDERFLOW;
+        } else if (!XxC) {
+            g_assert(trap_exc & S390_IEEE_MASK_INEXACT);
+            /* inexact has lowest priority on traps */
+            return enr << 4 | VIC_INEXACT;
+        }
+    }
+    return 0;
+}
+
+static void handle_ieee_exc(CPUS390XState *env, uint8_t vxc, uint8_t vec_exc,
+                            uintptr_t retaddr)
+{
+    if (vxc) {
+        /* on traps, the fpc flags are not updated, instruction is suppressed */
+        tcg_s390_vector_exception(env, vxc, retaddr);
+    }
+    if (vec_exc) {
+        /* indicate exceptions for all elements combined */
+        env->fpc |= vec_exc << 16;
+    }
+}
+
+static float32 s390_vec_read_float32(const S390Vector *v, uint8_t enr)
+{
+    return make_float32(s390_vec_read_element32(v, enr));
+}
+
+static float64 s390_vec_read_float64(const S390Vector *v, uint8_t enr)
+{
+    return make_float64(s390_vec_read_element64(v, enr));
+}
+
+static float128 s390_vec_read_float128(const S390Vector *v)
+{
+    return make_float128(s390_vec_read_element64(v, 0),
+                         s390_vec_read_element64(v, 1));
+}
+
+static void s390_vec_write_float32(S390Vector *v, uint8_t enr, float32 data)
+{
+    return s390_vec_write_element32(v, enr, data);
+}
+
+static void s390_vec_write_float64(S390Vector *v, uint8_t enr, float64 data)
+{
+    return s390_vec_write_element64(v, enr, data);
+}
+
+static void s390_vec_write_float128(S390Vector *v, float128 data)
+{
+    s390_vec_write_element64(v, 0, data.high);
+    s390_vec_write_element64(v, 1, data.low);
+}
+
+typedef float32 (*vop32_2_fn)(float32 a, float_status *s);
+static void vop32_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env,
+                    bool s, bool XxC, uint8_t erm, vop32_2_fn fn,
+                    uintptr_t retaddr)
+{
+    uint8_t vxc, vec_exc = 0;
+    S390Vector tmp = {};
+    int i, old_mode;
+
+    old_mode = s390_swap_bfp_rounding_mode(env, erm);
+    for (i = 0; i < 4; i++) {
+        const float32 a = s390_vec_read_float32(v2, i);
+
+        s390_vec_write_float32(&tmp, i, fn(a, &env->fpu_status));
+        vxc = check_ieee_exc(env, i, XxC, &vec_exc);
+        if (s || vxc) {
+            break;
+        }
+    }
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_ieee_exc(env, vxc, vec_exc, retaddr);
+    *v1 = tmp;
+}
+
+typedef float64 (*vop64_2_fn)(float64 a, float_status *s);
+static void vop64_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env,
+                    bool s, bool XxC, uint8_t erm, vop64_2_fn fn,
+                    uintptr_t retaddr)
+{
+    uint8_t vxc, vec_exc = 0;
+    S390Vector tmp = {};
+    int i, old_mode;
+
+    old_mode = s390_swap_bfp_rounding_mode(env, erm);
+    for (i = 0; i < 2; i++) {
+        const float64 a = s390_vec_read_float64(v2, i);
+
+        s390_vec_write_float64(&tmp, i, fn(a, &env->fpu_status));
+        vxc = check_ieee_exc(env, i, XxC, &vec_exc);
+        if (s || vxc) {
+            break;
+        }
+    }
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_ieee_exc(env, vxc, vec_exc, retaddr);
+    *v1 = tmp;
+}
+
+typedef float128 (*vop128_2_fn)(float128 a, float_status *s);
+static void vop128_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env,
+                    bool s, bool XxC, uint8_t erm, vop128_2_fn fn,
+                    uintptr_t retaddr)
+{
+    const float128 a = s390_vec_read_float128(v2);
+    uint8_t vxc, vec_exc = 0;
+    S390Vector tmp = {};
+    int old_mode;
+
+    old_mode = s390_swap_bfp_rounding_mode(env, erm);
+    s390_vec_write_float128(&tmp, fn(a, &env->fpu_status));
+    vxc = check_ieee_exc(env, 0, XxC, &vec_exc);
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_ieee_exc(env, vxc, vec_exc, retaddr);
+    *v1 = tmp;
+}
+
+static float64 vcdg64(float64 a, float_status *s)
+{
+    return int64_to_float64(a, s);
+}
+
+static float64 vcdlg64(float64 a, float_status *s)
+{
+    return uint64_to_float64(a, s);
+}
+
+static float64 vcgd64(float64 a, float_status *s)
+{
+    const float64 tmp = float64_to_int64(a, s);
+
+    return float64_is_any_nan(a) ? INT64_MIN : tmp;
+}
+
+static float64 vclgd64(float64 a, float_status *s)
+{
+    const float64 tmp = float64_to_uint64(a, s);
+
+    return float64_is_any_nan(a) ? 0 : tmp;
+}
+
+#define DEF_GVEC_VOP2_FN(NAME, FN, BITS)                                       \
+void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, CPUS390XState *env,   \
+                               uint32_t desc)                                  \
+{                                                                              \
+    const uint8_t erm = extract32(simd_data(desc), 4, 4);                      \
+    const bool se = extract32(simd_data(desc), 3, 1);                          \
+    const bool XxC = extract32(simd_data(desc), 2, 1);                         \
+                                                                               \
+    vop##BITS##_2(v1, v2, env, se, XxC, erm, FN, GETPC());                     \
+}
+
+#define DEF_GVEC_VOP2_64(NAME)                                                 \
+DEF_GVEC_VOP2_FN(NAME, NAME##64, 64)
+
+#define DEF_GVEC_VOP2(NAME, OP)                                                \
+DEF_GVEC_VOP2_FN(NAME, float32_##OP, 32)                                       \
+DEF_GVEC_VOP2_FN(NAME, float64_##OP, 64)                                       \
+DEF_GVEC_VOP2_FN(NAME, float128_##OP, 128)
+
+DEF_GVEC_VOP2_64(vcdg)
+DEF_GVEC_VOP2_64(vcdlg)
+DEF_GVEC_VOP2_64(vcgd)
+DEF_GVEC_VOP2_64(vclgd)
+DEF_GVEC_VOP2(vfi, round_to_int)
+DEF_GVEC_VOP2(vfsq, sqrt)
+
+typedef float32 (*vop32_3_fn)(float32 a, float32 b, float_status *s);
+static void vop32_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
+                    CPUS390XState *env, bool s, vop32_3_fn fn,
+                    uintptr_t retaddr)
+{
+    uint8_t vxc, vec_exc = 0;
+    S390Vector tmp = {};
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        const float32 a = s390_vec_read_float32(v2, i);
+        const float32 b = s390_vec_read_float32(v3, i);
+
+        s390_vec_write_float32(&tmp, i, fn(a, b, &env->fpu_status));
+        vxc = check_ieee_exc(env, i, false, &vec_exc);
+        if (s || vxc) {
+            break;
+        }
+    }
+    handle_ieee_exc(env, vxc, vec_exc, retaddr);
+    *v1 = tmp;
+}
+
+typedef float64 (*vop64_3_fn)(float64 a, float64 b, float_status *s);
+static void vop64_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
+                    CPUS390XState *env, bool s, vop64_3_fn fn,
+                    uintptr_t retaddr)
+{
+    uint8_t vxc, vec_exc = 0;
+    S390Vector tmp = {};
+    int i;
+
+    for (i = 0; i < 2; i++) {
+        const float64 a = s390_vec_read_float64(v2, i);
+        const float64 b = s390_vec_read_float64(v3, i);
+
+        s390_vec_write_float64(&tmp, i, fn(a, b, &env->fpu_status));
+        vxc = check_ieee_exc(env, i, false, &vec_exc);
+        if (s || vxc) {
+            break;
+        }
+    }
+    handle_ieee_exc(env, vxc, vec_exc, retaddr);
+    *v1 = tmp;
+}
+
+typedef float128 (*vop128_3_fn)(float128 a, float128 b, float_status *s);
+static void vop128_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
+                     CPUS390XState *env, bool s, vop128_3_fn fn,
+                     uintptr_t retaddr)
+{
+    const float128 a = s390_vec_read_float128(v2);
+    const float128 b = s390_vec_read_float128(v3);
+    uint8_t vxc, vec_exc = 0;
+    S390Vector tmp = {};
+
+    s390_vec_write_float128(&tmp, fn(a, b, &env->fpu_status));
+    vxc = check_ieee_exc(env, 0, false, &vec_exc);
+    handle_ieee_exc(env, vxc, vec_exc, retaddr);
+    *v1 = tmp;
+}
+
+#define DEF_GVEC_VOP3_B(NAME, OP, BITS)                                        \
+void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3,       \
+                              CPUS390XState *env, uint32_t desc)               \
+{                                                                              \
+    const bool se = extract32(simd_data(desc), 3, 1);                          \
+                                                                               \
+    vop##BITS##_3(v1, v2, v3, env, se, float##BITS##_##OP, GETPC());           \
+}
+
+#define DEF_GVEC_VOP3(NAME, OP)                                                \
+DEF_GVEC_VOP3_B(NAME, OP, 32)                                                  \
+DEF_GVEC_VOP3_B(NAME, OP, 64)                                                  \
+DEF_GVEC_VOP3_B(NAME, OP, 128)
+
+DEF_GVEC_VOP3(vfa, add)
+DEF_GVEC_VOP3(vfs, sub)
+DEF_GVEC_VOP3(vfd, div)
+DEF_GVEC_VOP3(vfm, mul)
+
+static int wfc32(const S390Vector *v1, const S390Vector *v2,
+                 CPUS390XState *env, bool signal, uintptr_t retaddr)
+{
+    /* only the zero-indexed elements are compared */
+    const float32 a = s390_vec_read_float32(v1, 0);
+    const float32 b = s390_vec_read_float32(v2, 0);
+    uint8_t vxc, vec_exc = 0;
+    int cmp;
+
+    if (signal) {
+        cmp = float32_compare(a, b, &env->fpu_status);
+    } else {
+        cmp = float32_compare_quiet(a, b, &env->fpu_status);
+    }
+    vxc = check_ieee_exc(env, 0, false, &vec_exc);
+    handle_ieee_exc(env, vxc, vec_exc, retaddr);
+
+    return float_comp_to_cc(env, cmp);
+}
+
+static int wfc64(const S390Vector *v1, const S390Vector *v2,
+                 CPUS390XState *env, bool signal, uintptr_t retaddr)
+{
+    /* only the zero-indexed elements are compared */
+    const float64 a = s390_vec_read_float64(v1, 0);
+    const float64 b = s390_vec_read_float64(v2, 0);
+    uint8_t vxc, vec_exc = 0;
+    int cmp;
+
+    if (signal) {
+        cmp = float64_compare(a, b, &env->fpu_status);
+    } else {
+        cmp = float64_compare_quiet(a, b, &env->fpu_status);
+    }
+    vxc = check_ieee_exc(env, 0, false, &vec_exc);
+    handle_ieee_exc(env, vxc, vec_exc, retaddr);
+
+    return float_comp_to_cc(env, cmp);
+}
+
+static int wfc128(const S390Vector *v1, const S390Vector *v2,
+                  CPUS390XState *env, bool signal, uintptr_t retaddr)
+{
+    /* only the zero-indexed elements are compared */
+    const float128 a = s390_vec_read_float128(v1);
+    const float128 b = s390_vec_read_float128(v2);
+    uint8_t vxc, vec_exc = 0;
+    int cmp;
+
+    if (signal) {
+        cmp = float128_compare(a, b, &env->fpu_status);
+    } else {
+        cmp = float128_compare_quiet(a, b, &env->fpu_status);
+    }
+    vxc = check_ieee_exc(env, 0, false, &vec_exc);
+    handle_ieee_exc(env, vxc, vec_exc, retaddr);
+
+    return float_comp_to_cc(env, cmp);
+}
+
+#define DEF_GVEC_WFC_B(NAME, SIGNAL, BITS)                                     \
+void HELPER(gvec_##NAME##BITS)(const void *v1, const void *v2,                 \
+                               CPUS390XState *env, uint32_t desc)              \
+{                                                                              \
+    env->cc_op = wfc##BITS(v1, v2, env, SIGNAL, GETPC());                      \
+}
+
+#define DEF_GVEC_WFC(NAME, SIGNAL)                                             \
+     DEF_GVEC_WFC_B(NAME, SIGNAL, 32)                                          \
+     DEF_GVEC_WFC_B(NAME, SIGNAL, 64)                                          \
+     DEF_GVEC_WFC_B(NAME, SIGNAL, 128)
+
+DEF_GVEC_WFC(wfc, false)
+DEF_GVEC_WFC(wfk, true)
+
+typedef bool (*vfc32_fn)(float32 a, float32 b, float_status *status);
+static int vfc32(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
+                 CPUS390XState *env, bool s, vfc32_fn fn, uintptr_t retaddr)
+{
+    uint8_t vxc, vec_exc = 0;
+    S390Vector tmp = {};
+    int match = 0;
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        const float32 a = s390_vec_read_float32(v2, i);
+        const float32 b = s390_vec_read_float32(v3, i);
+
+        /* swap the order of the parameters, so we can use existing functions */
+        if (fn(b, a, &env->fpu_status)) {
+            match++;
+            s390_vec_write_element32(&tmp, i, -1u);
+        }
+        vxc = check_ieee_exc(env, i, false, &vec_exc);
+        if (s || vxc) {
+            break;
+        }
+    }
+
+    handle_ieee_exc(env, vxc, vec_exc, retaddr);
+    *v1 = tmp;
+    if (match) {
+        return s || match == 4 ? 0 : 1;
+    }
+    return 3;
+}
+
+typedef bool (*vfc64_fn)(float64 a, float64 b, float_status *status);
+static int vfc64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
+                 CPUS390XState *env, bool s, vfc64_fn fn, uintptr_t retaddr)
+{
+    uint8_t vxc, vec_exc = 0;
+    S390Vector tmp = {};
+    int match = 0;
+    int i;
+
+    for (i = 0; i < 2; i++) {
+        const float64 a = s390_vec_read_float64(v2, i);
+        const float64 b = s390_vec_read_float64(v3, i);
+
+        /* swap the order of the parameters, so we can use existing functions */
+        if (fn(b, a, &env->fpu_status)) {
+            match++;
+            s390_vec_write_element64(&tmp, i, -1ull);
+        }
+        vxc = check_ieee_exc(env, i, false, &vec_exc);
+        if (s || vxc) {
+            break;
+        }
+    }
+
+    handle_ieee_exc(env, vxc, vec_exc, retaddr);
+    *v1 = tmp;
+    if (match) {
+        return s || match == 2 ? 0 : 1;
+    }
+    return 3;
+}
+
+typedef bool (*vfc128_fn)(float128 a, float128 b, float_status *status);
+static int vfc128(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
+                 CPUS390XState *env, bool s, vfc128_fn fn, uintptr_t retaddr)
+{
+    const float128 a = s390_vec_read_float128(v2);
+    const float128 b = s390_vec_read_float128(v3);
+    uint8_t vxc, vec_exc = 0;
+    S390Vector tmp = {};
+    bool match = false;
+
+    /* swap the order of the parameters, so we can use existing functions */
+    if (fn(b, a, &env->fpu_status)) {
+        match = true;
+        s390_vec_write_element64(&tmp, 0, -1ull);
+        s390_vec_write_element64(&tmp, 1, -1ull);
+    }
+    vxc = check_ieee_exc(env, 0, false, &vec_exc);
+    handle_ieee_exc(env, vxc, vec_exc, retaddr);
+    *v1 = tmp;
+    return match ? 0 : 3;
+}
+
+#define DEF_GVEC_VFC_B(NAME, OP, BITS)                                         \
+void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3,       \
+                               CPUS390XState *env, uint32_t desc)              \
+{                                                                              \
+    const bool se = extract32(simd_data(desc), 3, 1);                          \
+    const bool sq = extract32(simd_data(desc), 2, 1);                          \
+    vfc##BITS##_fn fn = sq ? float##BITS##_##OP : float##BITS##_##OP##_quiet;  \
+                                                                               \
+    vfc##BITS(v1, v2, v3, env, se, fn, GETPC());                               \
+}                                                                              \
+                                                                               \
+void HELPER(gvec_##NAME##BITS##_cc)(void *v1, const void *v2, const void *v3,  \
+                                    CPUS390XState *env, uint32_t desc)         \
+{                                                                              \
+    const bool se = extract32(simd_data(desc), 3, 1);                          \
+    const bool sq = extract32(simd_data(desc), 2, 1);                          \
+    vfc##BITS##_fn fn = sq ? float##BITS##_##OP : float##BITS##_##OP##_quiet;  \
+                                                                               \
+    env->cc_op = vfc##BITS(v1, v2, v3, env, se, fn, GETPC());                  \
+}
+
+#define DEF_GVEC_VFC(NAME, OP)                                                 \
+DEF_GVEC_VFC_B(NAME, OP, 32)                                                   \
+DEF_GVEC_VFC_B(NAME, OP, 64)                                                   \
+DEF_GVEC_VFC_B(NAME, OP, 128)                                                  \
+
+DEF_GVEC_VFC(vfce, eq)
+DEF_GVEC_VFC(vfch, lt)
+DEF_GVEC_VFC(vfche, le)
+
+void HELPER(gvec_vfll32)(void *v1, const void *v2, CPUS390XState *env,
+                         uint32_t desc)
+{
+    const bool s = extract32(simd_data(desc), 3, 1);
+    uint8_t vxc, vec_exc = 0;
+    S390Vector tmp = {};
+    int i;
+
+    for (i = 0; i < 2; i++) {
+        /* load from even element */
+        const float32 a = s390_vec_read_element32(v2, i * 2);
+        const uint64_t ret = float32_to_float64(a, &env->fpu_status);
+
+        s390_vec_write_element64(&tmp, i, ret);
+        /* indicate the source element */
+        vxc = check_ieee_exc(env, i * 2, false, &vec_exc);
+        if (s || vxc) {
+            break;
+        }
+    }
+    handle_ieee_exc(env, vxc, vec_exc, GETPC());
+    *(S390Vector *)v1 = tmp;
+}
+
+void HELPER(gvec_vfll64)(void *v1, const void *v2, CPUS390XState *env,
+                         uint32_t desc)
+{
+    /* load from even element */
+    const float128 ret = float64_to_float128(s390_vec_read_float64(v2, 0),
+                                             &env->fpu_status);
+    uint8_t vxc, vec_exc = 0;
+
+    vxc = check_ieee_exc(env, 0, false, &vec_exc);
+    handle_ieee_exc(env, vxc, vec_exc, GETPC());
+    s390_vec_write_float128(v1, ret);
+}
+
+void HELPER(gvec_vflr64)(void *v1, const void *v2, CPUS390XState *env,
+                         uint32_t desc)
+{
+    const uint8_t erm = extract32(simd_data(desc), 4, 4);
+    const bool s = extract32(simd_data(desc), 3, 1);
+    const bool XxC = extract32(simd_data(desc), 2, 1);
+    uint8_t vxc, vec_exc = 0;
+    S390Vector tmp = {};
+    int i, old_mode;
+
+    old_mode = s390_swap_bfp_rounding_mode(env, erm);
+    for (i = 0; i < 2; i++) {
+        float64 a = s390_vec_read_element64(v2, i);
+        uint32_t ret = float64_to_float32(a, &env->fpu_status);
+
+        /* place at even element */
+        s390_vec_write_element32(&tmp, i * 2, ret);
+        /* indicate the source element */
+        vxc = check_ieee_exc(env, i, XxC, &vec_exc);
+        if (s || vxc) {
+            break;
+        }
+    }
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_ieee_exc(env, vxc, vec_exc, GETPC());
+    *(S390Vector *)v1 = tmp;
+}
+
+void HELPER(gvec_vflr128)(void *v1, const void *v2, CPUS390XState *env,
+                          uint32_t desc)
+{
+    const uint8_t erm = extract32(simd_data(desc), 4, 4);
+    const bool XxC = extract32(simd_data(desc), 2, 1);
+    uint8_t vxc, vec_exc = 0;
+    int old_mode;
+    float64 ret;
+
+    old_mode = s390_swap_bfp_rounding_mode(env, erm);
+    ret = float128_to_float64(s390_vec_read_float128(v2), &env->fpu_status);
+    vxc = check_ieee_exc(env, 0, XxC, &vec_exc);
+    s390_restore_bfp_rounding_mode(env, old_mode);
+    handle_ieee_exc(env, vxc, vec_exc, GETPC());
+
+    /* place at even element, odd element is unpredictable */
+    s390_vec_write_float64(v1, 0, ret);
+}
+
+static void vfma32(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
+                   const S390Vector *v4, CPUS390XState *env, bool s, int flags,
+                   uintptr_t retaddr)
+{
+    uint8_t vxc, vec_exc = 0;
+    S390Vector tmp = {};
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        const float32 a = s390_vec_read_float32(v2, i);
+        const float32 b = s390_vec_read_float32(v3, i);
+        const float32 c = s390_vec_read_float32(v4, i);
+        float32 ret = float32_muladd(a, b, c, flags, &env->fpu_status);
+
+        s390_vec_write_float32(&tmp, i, ret);
+        vxc = check_ieee_exc(env, i, false, &vec_exc);
+        if (s || vxc) {
+            break;
+        }
+    }
+    handle_ieee_exc(env, vxc, vec_exc, retaddr);
+    *v1 = tmp;
+}
+
+static void vfma64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
+                   const S390Vector *v4, CPUS390XState *env, bool s, int flags,
+                   uintptr_t retaddr)
+{
+    uint8_t vxc, vec_exc = 0;
+    S390Vector tmp = {};
+    int i;
+
+    for (i = 0; i < 2; i++) {
+        const float64 a = s390_vec_read_float64(v2, i);
+        const float64 b = s390_vec_read_float64(v3, i);
+        const float64 c = s390_vec_read_float64(v4, i);
+        const float64 ret = float64_muladd(a, b, c, flags, &env->fpu_status);
+
+        s390_vec_write_float64(&tmp, i, ret);
+        vxc = check_ieee_exc(env, i, false, &vec_exc);
+        if (s || vxc) {
+            break;
+        }
+    }
+    handle_ieee_exc(env, vxc, vec_exc, retaddr);
+    *v1 = tmp;
+}
+
+static void vfma128(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
+                    const S390Vector *v4, CPUS390XState *env, bool s, int flags,
+                    uintptr_t retaddr)
+{
+    const float128 a = s390_vec_read_float128(v2);
+    const float128 b = s390_vec_read_float128(v3);
+    const float128 c = s390_vec_read_float128(v4);
+    uint8_t vxc, vec_exc = 0;
+    float128 ret;
+
+    ret = float128_muladd(a, b, c, flags, &env->fpu_status);
+    vxc = check_ieee_exc(env, 0, false, &vec_exc);
+    handle_ieee_exc(env, vxc, vec_exc, retaddr);
+    s390_vec_write_float128(v1, ret);
+}
+
+#define DEF_GVEC_VFMA_B(NAME, FLAGS, BITS)                                     \
+void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3,       \
+                               const void *v4, CPUS390XState *env,             \
+                               uint32_t desc)                                  \
+{                                                                              \
+    const bool se = extract32(simd_data(desc), 3, 1);                          \
+                                                                               \
+    vfma##BITS(v1, v2, v3, v4, env, se, FLAGS, GETPC());                       \
+}
+
+#define DEF_GVEC_VFMA(NAME, FLAGS)                                             \
+    DEF_GVEC_VFMA_B(NAME, FLAGS, 32)                                           \
+    DEF_GVEC_VFMA_B(NAME, FLAGS, 64)                                           \
+    DEF_GVEC_VFMA_B(NAME, FLAGS, 128)
+
+DEF_GVEC_VFMA(vfma, 0)
+DEF_GVEC_VFMA(vfms, float_muladd_negate_c)
+DEF_GVEC_VFMA(vfnma, float_muladd_negate_result)
+DEF_GVEC_VFMA(vfnms, float_muladd_negate_c | float_muladd_negate_result)
+
+void HELPER(gvec_vftci32)(void *v1, const void *v2, CPUS390XState *env,
+                          uint32_t desc)
+{
+    uint16_t i3 = extract32(simd_data(desc), 4, 12);
+    bool s = extract32(simd_data(desc), 3, 1);
+    int i, match = 0;
+
+    for (i = 0; i < 4; i++) {
+        float32 a = s390_vec_read_float32(v2, i);
+
+        if (float32_dcmask(env, a) & i3) {
+            match++;
+            s390_vec_write_element32(v1, i, -1u);
+        } else {
+            s390_vec_write_element32(v1, i, 0);
+        }
+        if (s) {
+            break;
+        }
+    }
+
+    if (match == 4 || (s && match)) {
+        env->cc_op = 0;
+    } else if (match) {
+        env->cc_op = 1;
+    } else {
+        env->cc_op = 3;
+    }
+}
+
+void HELPER(gvec_vftci64)(void *v1, const void *v2, CPUS390XState *env,
+                          uint32_t desc)
+{
+    const uint16_t i3 = extract32(simd_data(desc), 4, 12);
+    const bool s = extract32(simd_data(desc), 3, 1);
+    int i, match = 0;
+
+    for (i = 0; i < 2; i++) {
+        const float64 a = s390_vec_read_float64(v2, i);
+
+        if (float64_dcmask(env, a) & i3) {
+            match++;
+            s390_vec_write_element64(v1, i, -1ull);
+        } else {
+            s390_vec_write_element64(v1, i, 0);
+        }
+        if (s) {
+            break;
+        }
+    }
+
+    if (match == 2 || (s && match)) {
+        env->cc_op = 0;
+    } else if (match) {
+        env->cc_op = 1;
+    } else {
+        env->cc_op = 3;
+    }
+}
+
+void HELPER(gvec_vftci128)(void *v1, const void *v2, CPUS390XState *env,
+                           uint32_t desc)
+{
+    const float128 a = s390_vec_read_float128(v2);
+    uint16_t i3 = extract32(simd_data(desc), 4, 12);
+
+    if (float128_dcmask(env, a) & i3) {
+        env->cc_op = 0;
+        s390_vec_write_element64(v1, 0, -1ull);
+        s390_vec_write_element64(v1, 1, -1ull);
+    } else {
+        env->cc_op = 3;
+        s390_vec_write_element64(v1, 0, 0);
+        s390_vec_write_element64(v1, 1, 0);
+    }
+}
+
+typedef enum S390MinMaxType {
+    S390_MINMAX_TYPE_IEEE = 0,
+    S390_MINMAX_TYPE_JAVA,
+    S390_MINMAX_TYPE_C_MACRO,
+    S390_MINMAX_TYPE_CPP,
+    S390_MINMAX_TYPE_F,
+} S390MinMaxType;
+
+typedef enum S390MinMaxRes {
+    S390_MINMAX_RES_MINMAX = 0,
+    S390_MINMAX_RES_A,
+    S390_MINMAX_RES_B,
+    S390_MINMAX_RES_SILENCE_A,
+    S390_MINMAX_RES_SILENCE_B,
+} S390MinMaxRes;
+
+static S390MinMaxRes vfmin_res(uint16_t dcmask_a, uint16_t dcmask_b,
+                               S390MinMaxType type, float_status *s)
+{
+    const bool neg_a = dcmask_a & DCMASK_NEGATIVE;
+    const bool nan_a = dcmask_a & DCMASK_NAN;
+    const bool nan_b = dcmask_b & DCMASK_NAN;
+
+    g_assert(type > S390_MINMAX_TYPE_IEEE && type <= S390_MINMAX_TYPE_F);
+
+    if (unlikely((dcmask_a | dcmask_b) & DCMASK_NAN)) {
+        const bool sig_a = dcmask_a & DCMASK_SIGNALING_NAN;
+        const bool sig_b = dcmask_b & DCMASK_SIGNALING_NAN;
+
+        if ((dcmask_a | dcmask_b) & DCMASK_SIGNALING_NAN) {
+            s->float_exception_flags |= float_flag_invalid;
+        }
+        switch (type) {
+        case S390_MINMAX_TYPE_JAVA:
+            if (sig_a) {
+                return S390_MINMAX_RES_SILENCE_A;
+            } else if (sig_b) {
+                return S390_MINMAX_RES_SILENCE_B;
+            }
+            return nan_a ? S390_MINMAX_RES_A : S390_MINMAX_RES_B;
+        case S390_MINMAX_TYPE_F:
+            return nan_b ? S390_MINMAX_RES_A : S390_MINMAX_RES_B;
+        case S390_MINMAX_TYPE_C_MACRO:
+            s->float_exception_flags |= float_flag_invalid;
+            return S390_MINMAX_RES_B;
+        case S390_MINMAX_TYPE_CPP:
+            s->float_exception_flags |= float_flag_invalid;
+            return S390_MINMAX_RES_A;
+        default:
+            g_assert_not_reached();
+        }
+    } else if (unlikely(dcmask_a & dcmask_b & DCMASK_ZERO)) {
+        switch (type) {
+        case S390_MINMAX_TYPE_JAVA:
+            return neg_a ? S390_MINMAX_RES_A : S390_MINMAX_RES_B;
+        case S390_MINMAX_TYPE_C_MACRO:
+            return S390_MINMAX_RES_B;
+        case S390_MINMAX_TYPE_F:
+            return !neg_a ? S390_MINMAX_RES_B : S390_MINMAX_RES_A;
+        case S390_MINMAX_TYPE_CPP:
+            return S390_MINMAX_RES_A;
+        default:
+            g_assert_not_reached();
+        }
+    }
+    return S390_MINMAX_RES_MINMAX;
+}
+
+static S390MinMaxRes vfmax_res(uint16_t dcmask_a, uint16_t dcmask_b,
+                               S390MinMaxType type, float_status *s)
+{
+    g_assert(type > S390_MINMAX_TYPE_IEEE && type <= S390_MINMAX_TYPE_F);
+
+    if (unlikely((dcmask_a | dcmask_b) & DCMASK_NAN)) {
+        const bool sig_a = dcmask_a & DCMASK_SIGNALING_NAN;
+        const bool sig_b = dcmask_b & DCMASK_SIGNALING_NAN;
+        const bool nan_a = dcmask_a & DCMASK_NAN;
+        const bool nan_b = dcmask_b & DCMASK_NAN;
+
+        if ((dcmask_a | dcmask_b) & DCMASK_SIGNALING_NAN) {
+            s->float_exception_flags |= float_flag_invalid;
+        }
+        switch (type) {
+        case S390_MINMAX_TYPE_JAVA:
+            if (sig_a) {
+                return S390_MINMAX_RES_SILENCE_A;
+            } else if (sig_b) {
+                return S390_MINMAX_RES_SILENCE_B;
+            }
+            return nan_a ? S390_MINMAX_RES_A : S390_MINMAX_RES_B;
+        case S390_MINMAX_TYPE_F:
+            return nan_b ? S390_MINMAX_RES_A : S390_MINMAX_RES_B;
+        case S390_MINMAX_TYPE_C_MACRO:
+            s->float_exception_flags |= float_flag_invalid;
+            return S390_MINMAX_RES_B;
+        case S390_MINMAX_TYPE_CPP:
+            s->float_exception_flags |= float_flag_invalid;
+            return S390_MINMAX_RES_A;
+        default:
+            g_assert_not_reached();
+        }
+    } else if (unlikely(dcmask_a & dcmask_b & DCMASK_ZERO)) {
+        const bool neg_a = dcmask_a & DCMASK_NEGATIVE;
+
+        switch (type) {
+        case S390_MINMAX_TYPE_JAVA:
+        case S390_MINMAX_TYPE_F:
+            return neg_a ? S390_MINMAX_RES_B : S390_MINMAX_RES_A;
+        case S390_MINMAX_TYPE_C_MACRO:
+            return S390_MINMAX_RES_B;
+        case S390_MINMAX_TYPE_CPP:
+            return S390_MINMAX_RES_A;
+        default:
+            g_assert_not_reached();
+        }
+    }
+    return S390_MINMAX_RES_MINMAX;
+}
+
+static S390MinMaxRes vfminmax_res(uint16_t dcmask_a, uint16_t dcmask_b,
+                                  S390MinMaxType type, bool is_min,
+                                  float_status *s)
+{
+    return is_min ? vfmin_res(dcmask_a, dcmask_b, type, s) :
+                    vfmax_res(dcmask_a, dcmask_b, type, s);
+}
+
+static void vfminmax32(S390Vector *v1, const S390Vector *v2,
+                       const S390Vector *v3, CPUS390XState *env,
+                       S390MinMaxType type, bool is_min, bool is_abs, bool se,
+                       uintptr_t retaddr)
+{
+    float_status *s = &env->fpu_status;
+    uint8_t vxc, vec_exc = 0;
+    S390Vector tmp = {};
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        float32 a = s390_vec_read_float32(v2, i);
+        float32 b = s390_vec_read_float32(v3, i);
+        float32 result;
+
+        if (type != S390_MINMAX_TYPE_IEEE) {
+            S390MinMaxRes res;
+
+            if (is_abs) {
+                a = float32_abs(a);
+                b = float32_abs(b);
+            }
+
+            res = vfminmax_res(float32_dcmask(env, a), float32_dcmask(env, b),
+                               type, is_min, s);
+            switch (res) {
+            case S390_MINMAX_RES_MINMAX:
+                result = is_min ? float32_min(a, b, s) : float32_max(a, b, s);
+                break;
+            case S390_MINMAX_RES_A:
+                result = a;
+                break;
+            case S390_MINMAX_RES_B:
+                result = b;
+                break;
+            case S390_MINMAX_RES_SILENCE_A:
+                result = float32_silence_nan(a, s);
+                break;
+            case S390_MINMAX_RES_SILENCE_B:
+                result = float32_silence_nan(b, s);
+                break;
+            default:
+                g_assert_not_reached();
+            }
+        } else if (!is_abs) {
+            result = is_min ? float32_minnum(a, b, &env->fpu_status) :
+                              float32_maxnum(a, b, &env->fpu_status);
+        } else {
+            result = is_min ? float32_minnummag(a, b, &env->fpu_status) :
+                              float32_maxnummag(a, b, &env->fpu_status);
+        }
+
+        s390_vec_write_float32(&tmp, i, result);
+        vxc = check_ieee_exc(env, i, false, &vec_exc);
+        if (se || vxc) {
+            break;
+        }
+    }
+    handle_ieee_exc(env, vxc, vec_exc, retaddr);
+    *v1 = tmp;
+}
+
+static void vfminmax64(S390Vector *v1, const S390Vector *v2,
+                       const S390Vector *v3, CPUS390XState *env,
+                       S390MinMaxType type, bool is_min, bool is_abs, bool se,
+                       uintptr_t retaddr)
+{
+    float_status *s = &env->fpu_status;
+    uint8_t vxc, vec_exc = 0;
+    S390Vector tmp = {};
+    int i;
+
+    for (i = 0; i < 2; i++) {
+        float64 a = s390_vec_read_float64(v2, i);
+        float64 b = s390_vec_read_float64(v3, i);
+        float64 result;
+
+        if (type != S390_MINMAX_TYPE_IEEE) {
+            S390MinMaxRes res;
+
+            if (is_abs) {
+                a = float64_abs(a);
+                b = float64_abs(b);
+            }
+
+            res = vfminmax_res(float64_dcmask(env, a), float64_dcmask(env, b),
+                               type, is_min, s);
+            switch (res) {
+            case S390_MINMAX_RES_MINMAX:
+                result = is_min ? float64_min(a, b, s) : float64_max(a, b, s);
+                break;
+            case S390_MINMAX_RES_A:
+                result = a;
+                break;
+            case S390_MINMAX_RES_B:
+                result = b;
+                break;
+            case S390_MINMAX_RES_SILENCE_A:
+                result = float64_silence_nan(a, s);
+                break;
+            case S390_MINMAX_RES_SILENCE_B:
+                result = float64_silence_nan(b, s);
+                break;
+            default:
+                g_assert_not_reached();
+            }
+        } else if (!is_abs) {
+            result = is_min ? float64_minnum(a, b, &env->fpu_status) :
+                              float64_maxnum(a, b, &env->fpu_status);
+        } else {
+            result = is_min ? float64_minnummag(a, b, &env->fpu_status) :
+                              float64_maxnummag(a, b, &env->fpu_status);
+        }
+
+        s390_vec_write_float64(&tmp, i, result);
+        vxc = check_ieee_exc(env, i, false, &vec_exc);
+        if (se || vxc) {
+            break;
+        }
+    }
+    handle_ieee_exc(env, vxc, vec_exc, retaddr);
+    *v1 = tmp;
+}
+
+static void vfminmax128(S390Vector *v1, const S390Vector *v2,
+                        const S390Vector *v3, CPUS390XState *env,
+                        S390MinMaxType type, bool is_min, bool is_abs, bool se,
+                        uintptr_t retaddr)
+{
+    float128 a = s390_vec_read_float128(v2);
+    float128 b = s390_vec_read_float128(v3);
+    float_status *s = &env->fpu_status;
+    uint8_t vxc, vec_exc = 0;
+    float128 result;
+
+    if (type != S390_MINMAX_TYPE_IEEE) {
+        S390MinMaxRes res;
+
+        if (is_abs) {
+            a = float128_abs(a);
+            b = float128_abs(b);
+        }
+
+        res = vfminmax_res(float128_dcmask(env, a), float128_dcmask(env, b),
+                           type, is_min, s);
+        switch (res) {
+        case S390_MINMAX_RES_MINMAX:
+            result = is_min ? float128_min(a, b, s) : float128_max(a, b, s);
+            break;
+        case S390_MINMAX_RES_A:
+            result = a;
+            break;
+        case S390_MINMAX_RES_B:
+            result = b;
+            break;
+        case S390_MINMAX_RES_SILENCE_A:
+            result = float128_silence_nan(a, s);
+            break;
+        case S390_MINMAX_RES_SILENCE_B:
+            result = float128_silence_nan(b, s);
+            break;
+        default:
+            g_assert_not_reached();
+        }
+    } else if (!is_abs) {
+        result = is_min ? float128_minnum(a, b, &env->fpu_status) :
+                          float128_maxnum(a, b, &env->fpu_status);
+    } else {
+        result = is_min ? float128_minnummag(a, b, &env->fpu_status) :
+                          float128_maxnummag(a, b, &env->fpu_status);
+    }
+
+    vxc = check_ieee_exc(env, 0, false, &vec_exc);
+    handle_ieee_exc(env, vxc, vec_exc, retaddr);
+    s390_vec_write_float128(v1, result);
+}
+
+#define DEF_GVEC_VFMINMAX_B(NAME, IS_MIN, BITS)                                \
+void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3,       \
+                               CPUS390XState *env, uint32_t desc)              \
+{                                                                              \
+    const bool se = extract32(simd_data(desc), 3, 1);                          \
+    uint8_t type = extract32(simd_data(desc), 4, 4);                           \
+    bool is_abs = false;                                                       \
+                                                                               \
+    if (type >= 8) {                                                           \
+        is_abs = true;                                                         \
+        type -= 8;                                                             \
+    }                                                                          \
+                                                                               \
+    vfminmax##BITS(v1, v2, v3, env, type, IS_MIN, is_abs, se, GETPC());        \
+}
+
+#define DEF_GVEC_VFMINMAX(NAME, IS_MIN)                                        \
+    DEF_GVEC_VFMINMAX_B(NAME, IS_MIN, 32)                                      \
+    DEF_GVEC_VFMINMAX_B(NAME, IS_MIN, 64)                                      \
+    DEF_GVEC_VFMINMAX_B(NAME, IS_MIN, 128)
+
+DEF_GVEC_VFMINMAX(vfmax, false)
+DEF_GVEC_VFMINMAX(vfmin, true)
diff --git a/target/s390x/tcg/vec_helper.c b/target/s390x/tcg/vec_helper.c
new file mode 100644 (file)
index 0000000..ededf13
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * QEMU TCG support -- s390x vector support instructions
+ *
+ * Copyright (C) 2019 Red Hat Inc
+ *
+ * Authors:
+ *   David Hildenbrand <david@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "s390x-internal.h"
+#include "vec.h"
+#include "tcg/tcg.h"
+#include "tcg/tcg-gvec-desc.h"
+#include "exec/helper-proto.h"
+#include "exec/cpu_ldst.h"
+#include "exec/exec-all.h"
+
+void HELPER(gvec_vbperm)(void *v1, const void *v2, const void *v3,
+                         uint32_t desc)
+{
+    S390Vector tmp = {};
+    uint16_t result = 0;
+    int i;
+
+    for (i = 0; i < 16; i++) {
+        const uint8_t bit_nr = s390_vec_read_element8(v3, i);
+        uint16_t bit;
+
+        if (bit_nr >= 128) {
+            continue;
+        }
+        bit = (s390_vec_read_element8(v2, bit_nr / 8)
+               >> (7 - (bit_nr % 8))) & 1;
+        result |= (bit << (15 - i));
+    }
+    s390_vec_write_element16(&tmp, 3, result);
+    *(S390Vector *)v1 = tmp;
+}
+
+void HELPER(vll)(CPUS390XState *env, void *v1, uint64_t addr, uint64_t bytes)
+{
+    if (likely(bytes >= 16)) {
+        uint64_t t0, t1;
+
+        t0 = cpu_ldq_data_ra(env, addr, GETPC());
+        addr = wrap_address(env, addr + 8);
+        t1 = cpu_ldq_data_ra(env, addr, GETPC());
+        s390_vec_write_element64(v1, 0, t0);
+        s390_vec_write_element64(v1, 1, t1);
+    } else {
+        S390Vector tmp = {};
+        int i;
+
+        for (i = 0; i < bytes; i++) {
+            uint8_t byte = cpu_ldub_data_ra(env, addr, GETPC());
+
+            s390_vec_write_element8(&tmp, i, byte);
+            addr = wrap_address(env, addr + 1);
+        }
+        *(S390Vector *)v1 = tmp;
+    }
+}
+
+#define DEF_VPK_HFN(BITS, TBITS)                                               \
+typedef uint##TBITS##_t (*vpk##BITS##_fn)(uint##BITS##_t, int *);              \
+static int vpk##BITS##_hfn(S390Vector *v1, const S390Vector *v2,               \
+                           const S390Vector *v3, vpk##BITS##_fn fn)            \
+{                                                                              \
+    int i, saturated = 0;                                                      \
+    S390Vector tmp;                                                            \
+                                                                               \
+    for (i = 0; i < (128 / TBITS); i++) {                                      \
+        uint##BITS##_t src;                                                    \
+                                                                               \
+        if (i < (128 / BITS)) {                                                \
+            src = s390_vec_read_element##BITS(v2, i);                          \
+        } else {                                                               \
+            src = s390_vec_read_element##BITS(v3, i - (128 / BITS));           \
+        }                                                                      \
+        s390_vec_write_element##TBITS(&tmp, i, fn(src, &saturated));           \
+    }                                                                          \
+    *v1 = tmp;                                                                 \
+    return saturated;                                                          \
+}
+DEF_VPK_HFN(64, 32)
+DEF_VPK_HFN(32, 16)
+DEF_VPK_HFN(16, 8)
+
+#define DEF_VPK(BITS, TBITS)                                                   \
+static uint##TBITS##_t vpk##BITS##e(uint##BITS##_t src, int *saturated)        \
+{                                                                              \
+    return src;                                                                \
+}                                                                              \
+void HELPER(gvec_vpk##BITS)(void *v1, const void *v2, const void *v3,          \
+                            uint32_t desc)                                     \
+{                                                                              \
+    vpk##BITS##_hfn(v1, v2, v3, vpk##BITS##e);                                 \
+}
+DEF_VPK(64, 32)
+DEF_VPK(32, 16)
+DEF_VPK(16, 8)
+
+#define DEF_VPKS(BITS, TBITS)                                                  \
+static uint##TBITS##_t vpks##BITS##e(uint##BITS##_t src, int *saturated)       \
+{                                                                              \
+    if ((int##BITS##_t)src > INT##TBITS##_MAX) {                               \
+        (*saturated)++;                                                        \
+        return INT##TBITS##_MAX;                                               \
+    } else if ((int##BITS##_t)src < INT##TBITS##_MIN) {                        \
+        (*saturated)++;                                                        \
+        return INT##TBITS##_MIN;                                               \
+    }                                                                          \
+    return src;                                                                \
+}                                                                              \
+void HELPER(gvec_vpks##BITS)(void *v1, const void *v2, const void *v3,         \
+                             uint32_t desc)                                    \
+{                                                                              \
+    vpk##BITS##_hfn(v1, v2, v3, vpks##BITS##e);                                \
+}                                                                              \
+void HELPER(gvec_vpks_cc##BITS)(void *v1, const void *v2, const void *v3,      \
+                                CPUS390XState *env, uint32_t desc)             \
+{                                                                              \
+    int saturated = vpk##BITS##_hfn(v1, v2, v3, vpks##BITS##e);                \
+                                                                               \
+    if (saturated == (128 / TBITS)) {                                          \
+        env->cc_op = 3;                                                        \
+    } else if (saturated) {                                                    \
+        env->cc_op = 1;                                                        \
+    } else {                                                                   \
+        env->cc_op = 0;                                                        \
+    }                                                                          \
+}
+DEF_VPKS(64, 32)
+DEF_VPKS(32, 16)
+DEF_VPKS(16, 8)
+
+#define DEF_VPKLS(BITS, TBITS)                                                 \
+static uint##TBITS##_t vpkls##BITS##e(uint##BITS##_t src, int *saturated)      \
+{                                                                              \
+    if (src > UINT##TBITS##_MAX) {                                             \
+        (*saturated)++;                                                        \
+        return UINT##TBITS##_MAX;                                              \
+    }                                                                          \
+    return src;                                                                \
+}                                                                              \
+void HELPER(gvec_vpkls##BITS)(void *v1, const void *v2, const void *v3,        \
+                              uint32_t desc)                                   \
+{                                                                              \
+    vpk##BITS##_hfn(v1, v2, v3, vpkls##BITS##e);                               \
+}                                                                              \
+void HELPER(gvec_vpkls_cc##BITS)(void *v1, const void *v2, const void *v3,     \
+                                 CPUS390XState *env, uint32_t desc)            \
+{                                                                              \
+    int saturated = vpk##BITS##_hfn(v1, v2, v3, vpkls##BITS##e);               \
+                                                                               \
+    if (saturated == (128 / TBITS)) {                                          \
+        env->cc_op = 3;                                                        \
+    } else if (saturated) {                                                    \
+        env->cc_op = 1;                                                        \
+    } else {                                                                   \
+        env->cc_op = 0;                                                        \
+    }                                                                          \
+}
+DEF_VPKLS(64, 32)
+DEF_VPKLS(32, 16)
+DEF_VPKLS(16, 8)
+
+void HELPER(gvec_vperm)(void *v1, const void *v2, const void *v3,
+                        const void *v4, uint32_t desc)
+{
+    S390Vector tmp;
+    int i;
+
+    for (i = 0; i < 16; i++) {
+        const uint8_t selector = s390_vec_read_element8(v4, i) & 0x1f;
+        uint8_t byte;
+
+        if (selector < 16) {
+            byte = s390_vec_read_element8(v2, selector);
+        } else {
+            byte = s390_vec_read_element8(v3, selector - 16);
+        }
+        s390_vec_write_element8(&tmp, i, byte);
+    }
+    *(S390Vector *)v1 = tmp;
+}
+
+void HELPER(vstl)(CPUS390XState *env, const void *v1, uint64_t addr,
+                  uint64_t bytes)
+{
+    /* Probe write access before actually modifying memory */
+    probe_write_access(env, addr, bytes, GETPC());
+
+    if (likely(bytes >= 16)) {
+        cpu_stq_data_ra(env, addr, s390_vec_read_element64(v1, 0), GETPC());
+        addr = wrap_address(env, addr + 8);
+        cpu_stq_data_ra(env, addr, s390_vec_read_element64(v1, 1), GETPC());
+    } else {
+        S390Vector tmp = {};
+        int i;
+
+        for (i = 0; i < bytes; i++) {
+            uint8_t byte = s390_vec_read_element8(v1, i);
+
+            cpu_stb_data_ra(env, addr, byte, GETPC());
+            addr = wrap_address(env, addr + 1);
+        }
+        *(S390Vector *)v1 = tmp;
+    }
+}
diff --git a/target/s390x/tcg/vec_int_helper.c b/target/s390x/tcg/vec_int_helper.c
new file mode 100644 (file)
index 0000000..5561b3e
--- /dev/null
@@ -0,0 +1,587 @@
+/*
+ * QEMU TCG support -- s390x vector integer instruction support
+ *
+ * Copyright (C) 2019 Red Hat Inc
+ *
+ * Authors:
+ *   David Hildenbrand <david@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "cpu.h"
+#include "vec.h"
+#include "exec/helper-proto.h"
+#include "tcg/tcg-gvec-desc.h"
+
+static bool s390_vec_is_zero(const S390Vector *v)
+{
+    return !v->doubleword[0] && !v->doubleword[1];
+}
+
+static void s390_vec_xor(S390Vector *res, const S390Vector *a,
+                         const S390Vector *b)
+{
+    res->doubleword[0] = a->doubleword[0] ^ b->doubleword[0];
+    res->doubleword[1] = a->doubleword[1] ^ b->doubleword[1];
+}
+
+static void s390_vec_and(S390Vector *res, const S390Vector *a,
+                         const S390Vector *b)
+{
+    res->doubleword[0] = a->doubleword[0] & b->doubleword[0];
+    res->doubleword[1] = a->doubleword[1] & b->doubleword[1];
+}
+
+static bool s390_vec_equal(const S390Vector *a, const S390Vector *b)
+{
+    return a->doubleword[0] == b->doubleword[0] &&
+           a->doubleword[1] == b->doubleword[1];
+}
+
+static void s390_vec_shl(S390Vector *d, const S390Vector *a, uint64_t count)
+{
+    uint64_t tmp;
+
+    g_assert(count < 128);
+    if (count == 0) {
+        d->doubleword[0] = a->doubleword[0];
+        d->doubleword[1] = a->doubleword[1];
+    } else if (count == 64) {
+        d->doubleword[0] = a->doubleword[1];
+        d->doubleword[1] = 0;
+    } else if (count < 64) {
+        tmp = extract64(a->doubleword[1], 64 - count, count);
+        d->doubleword[1] = a->doubleword[1] << count;
+        d->doubleword[0] = (a->doubleword[0] << count) | tmp;
+    } else {
+        d->doubleword[0] = a->doubleword[1] << (count - 64);
+        d->doubleword[1] = 0;
+    }
+}
+
+static void s390_vec_sar(S390Vector *d, const S390Vector *a, uint64_t count)
+{
+    uint64_t tmp;
+
+    if (count == 0) {
+        d->doubleword[0] = a->doubleword[0];
+        d->doubleword[1] = a->doubleword[1];
+    } else if (count == 64) {
+        tmp = (int64_t)a->doubleword[0] >> 63;
+        d->doubleword[1] = a->doubleword[0];
+        d->doubleword[0] = tmp;
+    } else if (count < 64) {
+        tmp = a->doubleword[1] >> count;
+        d->doubleword[1] = deposit64(tmp, 64 - count, count, a->doubleword[0]);
+        d->doubleword[0] = (int64_t)a->doubleword[0] >> count;
+    } else {
+        tmp = (int64_t)a->doubleword[0] >> 63;
+        d->doubleword[1] = (int64_t)a->doubleword[0] >> (count - 64);
+        d->doubleword[0] = tmp;
+    }
+}
+
+static void s390_vec_shr(S390Vector *d, const S390Vector *a, uint64_t count)
+{
+    uint64_t tmp;
+
+    g_assert(count < 128);
+    if (count == 0) {
+        d->doubleword[0] = a->doubleword[0];
+        d->doubleword[1] = a->doubleword[1];
+    } else if (count == 64) {
+        d->doubleword[1] = a->doubleword[0];
+        d->doubleword[0] = 0;
+    } else if (count < 64) {
+        tmp = a->doubleword[1] >> count;
+        d->doubleword[1] = deposit64(tmp, 64 - count, count, a->doubleword[0]);
+        d->doubleword[0] = a->doubleword[0] >> count;
+    } else {
+        d->doubleword[1] = a->doubleword[0] >> (count - 64);
+        d->doubleword[0] = 0;
+    }
+}
+#define DEF_VAVG(BITS)                                                         \
+void HELPER(gvec_vavg##BITS)(void *v1, const void *v2, const void *v3,         \
+                             uint32_t desc)                                    \
+{                                                                              \
+    int i;                                                                     \
+                                                                               \
+    for (i = 0; i < (128 / BITS); i++) {                                       \
+        const int32_t a = (int##BITS##_t)s390_vec_read_element##BITS(v2, i);   \
+        const int32_t b = (int##BITS##_t)s390_vec_read_element##BITS(v3, i);   \
+                                                                               \
+        s390_vec_write_element##BITS(v1, i, (a + b + 1) >> 1);                 \
+    }                                                                          \
+}
+DEF_VAVG(8)
+DEF_VAVG(16)
+
+#define DEF_VAVGL(BITS)                                                        \
+void HELPER(gvec_vavgl##BITS)(void *v1, const void *v2, const void *v3,        \
+                              uint32_t desc)                                   \
+{                                                                              \
+    int i;                                                                     \
+                                                                               \
+    for (i = 0; i < (128 / BITS); i++) {                                       \
+        const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i);           \
+        const uint##BITS##_t b = s390_vec_read_element##BITS(v3, i);           \
+                                                                               \
+        s390_vec_write_element##BITS(v1, i, (a + b + 1) >> 1);                 \
+    }                                                                          \
+}
+DEF_VAVGL(8)
+DEF_VAVGL(16)
+
+#define DEF_VCLZ(BITS)                                                         \
+void HELPER(gvec_vclz##BITS)(void *v1, const void *v2, uint32_t desc)          \
+{                                                                              \
+    int i;                                                                     \
+                                                                               \
+    for (i = 0; i < (128 / BITS); i++) {                                       \
+        const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i);           \
+                                                                               \
+        s390_vec_write_element##BITS(v1, i, clz32(a) - 32 + BITS);             \
+    }                                                                          \
+}
+DEF_VCLZ(8)
+DEF_VCLZ(16)
+
+#define DEF_VCTZ(BITS)                                                         \
+void HELPER(gvec_vctz##BITS)(void *v1, const void *v2, uint32_t desc)          \
+{                                                                              \
+    int i;                                                                     \
+                                                                               \
+    for (i = 0; i < (128 / BITS); i++) {                                       \
+        const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i);           \
+                                                                               \
+        s390_vec_write_element##BITS(v1, i, a ? ctz32(a) : BITS);              \
+    }                                                                          \
+}
+DEF_VCTZ(8)
+DEF_VCTZ(16)
+
+/* like binary multiplication, but XOR instead of addition */
+#define DEF_GALOIS_MULTIPLY(BITS, TBITS)                                       \
+static uint##TBITS##_t galois_multiply##BITS(uint##TBITS##_t a,                \
+                                             uint##TBITS##_t b)                \
+{                                                                              \
+    uint##TBITS##_t res = 0;                                                   \
+                                                                               \
+    while (b) {                                                                \
+        if (b & 0x1) {                                                         \
+            res = res ^ a;                                                     \
+        }                                                                      \
+        a = a << 1;                                                            \
+        b = b >> 1;                                                            \
+    }                                                                          \
+    return res;                                                                \
+}
+DEF_GALOIS_MULTIPLY(8, 16)
+DEF_GALOIS_MULTIPLY(16, 32)
+DEF_GALOIS_MULTIPLY(32, 64)
+
+static S390Vector galois_multiply64(uint64_t a, uint64_t b)
+{
+    S390Vector res = {};
+    S390Vector va = {
+        .doubleword[1] = a,
+    };
+    S390Vector vb = {
+        .doubleword[1] = b,
+    };
+
+    while (!s390_vec_is_zero(&vb)) {
+        if (vb.doubleword[1] & 0x1) {
+            s390_vec_xor(&res, &res, &va);
+        }
+        s390_vec_shl(&va, &va, 1);
+        s390_vec_shr(&vb, &vb, 1);
+    }
+    return res;
+}
+
+#define DEF_VGFM(BITS, TBITS)                                                  \
+void HELPER(gvec_vgfm##BITS)(void *v1, const void *v2, const void *v3,         \
+                             uint32_t desc)                                    \
+{                                                                              \
+    int i;                                                                     \
+                                                                               \
+    for (i = 0; i < (128 / TBITS); i++) {                                      \
+        uint##BITS##_t a = s390_vec_read_element##BITS(v2, i * 2);             \
+        uint##BITS##_t b = s390_vec_read_element##BITS(v3, i * 2);             \
+        uint##TBITS##_t d = galois_multiply##BITS(a, b);                       \
+                                                                               \
+        a = s390_vec_read_element##BITS(v2, i * 2 + 1);                        \
+        b = s390_vec_read_element##BITS(v3, i * 2 + 1);                        \
+        d = d ^ galois_multiply32(a, b);                                       \
+        s390_vec_write_element##TBITS(v1, i, d);                               \
+    }                                                                          \
+}
+DEF_VGFM(8, 16)
+DEF_VGFM(16, 32)
+DEF_VGFM(32, 64)
+
+void HELPER(gvec_vgfm64)(void *v1, const void *v2, const void *v3,
+                         uint32_t desc)
+{
+    S390Vector tmp1, tmp2;
+    uint64_t a, b;
+
+    a = s390_vec_read_element64(v2, 0);
+    b = s390_vec_read_element64(v3, 0);
+    tmp1 = galois_multiply64(a, b);
+    a = s390_vec_read_element64(v2, 1);
+    b = s390_vec_read_element64(v3, 1);
+    tmp2 = galois_multiply64(a, b);
+    s390_vec_xor(v1, &tmp1, &tmp2);
+}
+
+#define DEF_VGFMA(BITS, TBITS)                                                 \
+void HELPER(gvec_vgfma##BITS)(void *v1, const void *v2, const void *v3,        \
+                              const void *v4, uint32_t desc)                   \
+{                                                                              \
+    int i;                                                                     \
+                                                                               \
+    for (i = 0; i < (128 / TBITS); i++) {                                      \
+        uint##BITS##_t a = s390_vec_read_element##BITS(v2, i * 2);             \
+        uint##BITS##_t b = s390_vec_read_element##BITS(v3, i * 2);             \
+        uint##TBITS##_t d = galois_multiply##BITS(a, b);                       \
+                                                                               \
+        a = s390_vec_read_element##BITS(v2, i * 2 + 1);                        \
+        b = s390_vec_read_element##BITS(v3, i * 2 + 1);                        \
+        d = d ^ galois_multiply32(a, b);                                       \
+        d = d ^ s390_vec_read_element##TBITS(v4, i);                           \
+        s390_vec_write_element##TBITS(v1, i, d);                               \
+    }                                                                          \
+}
+DEF_VGFMA(8, 16)
+DEF_VGFMA(16, 32)
+DEF_VGFMA(32, 64)
+
+void HELPER(gvec_vgfma64)(void *v1, const void *v2, const void *v3,
+                          const void *v4, uint32_t desc)
+{
+    S390Vector tmp1, tmp2;
+    uint64_t a, b;
+
+    a = s390_vec_read_element64(v2, 0);
+    b = s390_vec_read_element64(v3, 0);
+    tmp1 = galois_multiply64(a, b);
+    a = s390_vec_read_element64(v2, 1);
+    b = s390_vec_read_element64(v3, 1);
+    tmp2 = galois_multiply64(a, b);
+    s390_vec_xor(&tmp1, &tmp1, &tmp2);
+    s390_vec_xor(v1, &tmp1, v4);
+}
+
+#define DEF_VMAL(BITS)                                                         \
+void HELPER(gvec_vmal##BITS)(void *v1, const void *v2, const void *v3,         \
+                             const void *v4, uint32_t desc)                    \
+{                                                                              \
+    int i;                                                                     \
+                                                                               \
+    for (i = 0; i < (128 / BITS); i++) {                                       \
+        const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i);           \
+        const uint##BITS##_t b = s390_vec_read_element##BITS(v3, i);           \
+        const uint##BITS##_t c = s390_vec_read_element##BITS(v4, i);           \
+                                                                               \
+        s390_vec_write_element##BITS(v1, i, a * b + c);                        \
+    }                                                                          \
+}
+DEF_VMAL(8)
+DEF_VMAL(16)
+
+#define DEF_VMAH(BITS)                                                         \
+void HELPER(gvec_vmah##BITS)(void *v1, const void *v2, const void *v3,         \
+                             const void *v4, uint32_t desc)                    \
+{                                                                              \
+    int i;                                                                     \
+                                                                               \
+    for (i = 0; i < (128 / BITS); i++) {                                       \
+        const int32_t a = (int##BITS##_t)s390_vec_read_element##BITS(v2, i);   \
+        const int32_t b = (int##BITS##_t)s390_vec_read_element##BITS(v3, i);   \
+        const int32_t c = (int##BITS##_t)s390_vec_read_element##BITS(v4, i);   \
+                                                                               \
+        s390_vec_write_element##BITS(v1, i, (a * b + c) >> BITS);              \
+    }                                                                          \
+}
+DEF_VMAH(8)
+DEF_VMAH(16)
+
+#define DEF_VMALH(BITS)                                                        \
+void HELPER(gvec_vmalh##BITS)(void *v1, const void *v2, const void *v3,        \
+                              const void *v4, uint32_t desc)                   \
+{                                                                              \
+    int i;                                                                     \
+                                                                               \
+    for (i = 0; i < (128 / BITS); i++) {                                       \
+        const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i);           \
+        const uint##BITS##_t b = s390_vec_read_element##BITS(v3, i);           \
+        const uint##BITS##_t c = s390_vec_read_element##BITS(v4, i);           \
+                                                                               \
+        s390_vec_write_element##BITS(v1, i, (a * b + c) >> BITS);              \
+    }                                                                          \
+}
+DEF_VMALH(8)
+DEF_VMALH(16)
+
+#define DEF_VMAE(BITS, TBITS)                                                  \
+void HELPER(gvec_vmae##BITS)(void *v1, const void *v2, const void *v3,         \
+                             const void *v4, uint32_t desc)                    \
+{                                                                              \
+    int i, j;                                                                  \
+                                                                               \
+    for (i = 0, j = 0; i < (128 / TBITS); i++, j += 2) {                       \
+        int##TBITS##_t a = (int##BITS##_t)s390_vec_read_element##BITS(v2, j);  \
+        int##TBITS##_t b = (int##BITS##_t)s390_vec_read_element##BITS(v3, j);  \
+        int##TBITS##_t c = s390_vec_read_element##TBITS(v4, i);                \
+                                                                               \
+        s390_vec_write_element##TBITS(v1, i, a * b + c);                       \
+    }                                                                          \
+}
+DEF_VMAE(8, 16)
+DEF_VMAE(16, 32)
+DEF_VMAE(32, 64)
+
+#define DEF_VMALE(BITS, TBITS)                                                 \
+void HELPER(gvec_vmale##BITS)(void *v1, const void *v2, const void *v3,        \
+                              const void *v4, uint32_t desc)                   \
+{                                                                              \
+    int i, j;                                                                  \
+                                                                               \
+    for (i = 0, j = 0; i < (128 / TBITS); i++, j += 2) {                       \
+        uint##TBITS##_t a = s390_vec_read_element##BITS(v2, j);                \
+        uint##TBITS##_t b = s390_vec_read_element##BITS(v3, j);                \
+        uint##TBITS##_t c = s390_vec_read_element##TBITS(v4, i);               \
+                                                                               \
+        s390_vec_write_element##TBITS(v1, i, a * b + c);                       \
+    }                                                                          \
+}
+DEF_VMALE(8, 16)
+DEF_VMALE(16, 32)
+DEF_VMALE(32, 64)
+
+#define DEF_VMAO(BITS, TBITS)                                                  \
+void HELPER(gvec_vmao##BITS)(void *v1, const void *v2, const void *v3,         \
+                             const void *v4, uint32_t desc)                    \
+{                                                                              \
+    int i, j;                                                                  \
+                                                                               \
+    for (i = 0, j = 1; i < (128 / TBITS); i++, j += 2) {                       \
+        int##TBITS##_t a = (int##BITS##_t)s390_vec_read_element##BITS(v2, j);  \
+        int##TBITS##_t b = (int##BITS##_t)s390_vec_read_element##BITS(v3, j);  \
+        int##TBITS##_t c = s390_vec_read_element##TBITS(v4, i);                \
+                                                                               \
+        s390_vec_write_element##TBITS(v1, i, a * b + c);                       \
+    }                                                                          \
+}
+DEF_VMAO(8, 16)
+DEF_VMAO(16, 32)
+DEF_VMAO(32, 64)
+
+#define DEF_VMALO(BITS, TBITS)                                                 \
+void HELPER(gvec_vmalo##BITS)(void *v1, const void *v2, const void *v3,        \
+                              const void *v4, uint32_t desc)                   \
+{                                                                              \
+    int i, j;                                                                  \
+                                                                               \
+    for (i = 0, j = 1; i < (128 / TBITS); i++, j += 2) {                       \
+        uint##TBITS##_t a = s390_vec_read_element##BITS(v2, j);                \
+        uint##TBITS##_t b = s390_vec_read_element##BITS(v3, j);                \
+        uint##TBITS##_t c = s390_vec_read_element##TBITS(v4, i);               \
+                                                                               \
+        s390_vec_write_element##TBITS(v1, i, a * b + c);                       \
+    }                                                                          \
+}
+DEF_VMALO(8, 16)
+DEF_VMALO(16, 32)
+DEF_VMALO(32, 64)
+
+#define DEF_VMH(BITS)                                                          \
+void HELPER(gvec_vmh##BITS)(void *v1, const void *v2, const void *v3,          \
+                            uint32_t desc)                                     \
+{                                                                              \
+    int i;                                                                     \
+                                                                               \
+    for (i = 0; i < (128 / BITS); i++) {                                       \
+        const int32_t a = (int##BITS##_t)s390_vec_read_element##BITS(v2, i);   \
+        const int32_t b = (int##BITS##_t)s390_vec_read_element##BITS(v3, i);   \
+                                                                               \
+        s390_vec_write_element##BITS(v1, i, (a * b) >> BITS);                  \
+    }                                                                          \
+}
+DEF_VMH(8)
+DEF_VMH(16)
+
+#define DEF_VMLH(BITS)                                                         \
+void HELPER(gvec_vmlh##BITS)(void *v1, const void *v2, const void *v3,         \
+                             uint32_t desc)                                    \
+{                                                                              \
+    int i;                                                                     \
+                                                                               \
+    for (i = 0; i < (128 / BITS); i++) {                                       \
+        const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i);           \
+        const uint##BITS##_t b = s390_vec_read_element##BITS(v3, i);           \
+                                                                               \
+        s390_vec_write_element##BITS(v1, i, (a * b) >> BITS);                  \
+    }                                                                          \
+}
+DEF_VMLH(8)
+DEF_VMLH(16)
+
+#define DEF_VME(BITS, TBITS)                                                   \
+void HELPER(gvec_vme##BITS)(void *v1, const void *v2, const void *v3,          \
+                            uint32_t desc)                                     \
+{                                                                              \
+    int i, j;                                                                  \
+                                                                               \
+    for (i = 0, j = 0; i < (128 / TBITS); i++, j += 2) {                       \
+        int##TBITS##_t a = (int##BITS##_t)s390_vec_read_element##BITS(v2, j);  \
+        int##TBITS##_t b = (int##BITS##_t)s390_vec_read_element##BITS(v3, j);  \
+                                                                               \
+        s390_vec_write_element##TBITS(v1, i, a * b);                           \
+    }                                                                          \
+}
+DEF_VME(8, 16)
+DEF_VME(16, 32)
+DEF_VME(32, 64)
+
+#define DEF_VMLE(BITS, TBITS)                                                  \
+void HELPER(gvec_vmle##BITS)(void *v1, const void *v2, const void *v3,         \
+                             uint32_t desc)                                    \
+{                                                                              \
+    int i, j;                                                                  \
+                                                                               \
+    for (i = 0, j = 0; i < (128 / TBITS); i++, j += 2) {                       \
+        const uint##TBITS##_t a = s390_vec_read_element##BITS(v2, j);          \
+        const uint##TBITS##_t b = s390_vec_read_element##BITS(v3, j);          \
+                                                                               \
+        s390_vec_write_element##TBITS(v1, i, a * b);                           \
+    }                                                                          \
+}
+DEF_VMLE(8, 16)
+DEF_VMLE(16, 32)
+DEF_VMLE(32, 64)
+
+#define DEF_VMO(BITS, TBITS)                                                   \
+void HELPER(gvec_vmo##BITS)(void *v1, const void *v2, const void *v3,          \
+                            uint32_t desc)                                     \
+{                                                                              \
+    int i, j;                                                                  \
+                                                                               \
+    for (i = 0, j = 1; i < (128 / TBITS); i++, j += 2) {                       \
+        int##TBITS##_t a = (int##BITS##_t)s390_vec_read_element##BITS(v2, j);  \
+        int##TBITS##_t b = (int##BITS##_t)s390_vec_read_element##BITS(v3, j);  \
+                                                                               \
+        s390_vec_write_element##TBITS(v1, i, a * b);                           \
+    }                                                                          \
+}
+DEF_VMO(8, 16)
+DEF_VMO(16, 32)
+DEF_VMO(32, 64)
+
+#define DEF_VMLO(BITS, TBITS)                                                  \
+void HELPER(gvec_vmlo##BITS)(void *v1, const void *v2, const void *v3,         \
+                             uint32_t desc)                                    \
+{                                                                              \
+    int i, j;                                                                  \
+                                                                               \
+    for (i = 0, j = 1; i < (128 / TBITS); i++, j += 2) {                       \
+        const uint##TBITS##_t a = s390_vec_read_element##BITS(v2, j);          \
+        const uint##TBITS##_t b = s390_vec_read_element##BITS(v3, j);          \
+                                                                               \
+        s390_vec_write_element##TBITS(v1, i, a * b);                           \
+    }                                                                          \
+}
+DEF_VMLO(8, 16)
+DEF_VMLO(16, 32)
+DEF_VMLO(32, 64)
+
+#define DEF_VPOPCT(BITS)                                                       \
+void HELPER(gvec_vpopct##BITS)(void *v1, const void *v2, uint32_t desc)        \
+{                                                                              \
+    int i;                                                                     \
+                                                                               \
+    for (i = 0; i < (128 / BITS); i++) {                                       \
+        const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i);           \
+                                                                               \
+        s390_vec_write_element##BITS(v1, i, ctpop32(a));                       \
+    }                                                                          \
+}
+DEF_VPOPCT(8)
+DEF_VPOPCT(16)
+
+#define DEF_VERIM(BITS)                                                        \
+void HELPER(gvec_verim##BITS)(void *v1, const void *v2, const void *v3,        \
+                              uint32_t desc)                                   \
+{                                                                              \
+    const uint8_t count = simd_data(desc);                                     \
+    int i;                                                                     \
+                                                                               \
+    for (i = 0; i < (128 / BITS); i++) {                                       \
+        const uint##BITS##_t a = s390_vec_read_element##BITS(v1, i);           \
+        const uint##BITS##_t b = s390_vec_read_element##BITS(v2, i);           \
+        const uint##BITS##_t mask = s390_vec_read_element##BITS(v3, i);        \
+        const uint##BITS##_t d = (a & ~mask) | (rol##BITS(b, count) & mask);   \
+                                                                               \
+        s390_vec_write_element##BITS(v1, i, d);                                \
+    }                                                                          \
+}
+DEF_VERIM(8)
+DEF_VERIM(16)
+
+void HELPER(gvec_vsl)(void *v1, const void *v2, uint64_t count,
+                      uint32_t desc)
+{
+    s390_vec_shl(v1, v2, count);
+}
+
+void HELPER(gvec_vsra)(void *v1, const void *v2, uint64_t count,
+                       uint32_t desc)
+{
+    s390_vec_sar(v1, v2, count);
+}
+
+void HELPER(gvec_vsrl)(void *v1, const void *v2, uint64_t count,
+                       uint32_t desc)
+{
+    s390_vec_shr(v1, v2, count);
+}
+
+#define DEF_VSCBI(BITS)                                                        \
+void HELPER(gvec_vscbi##BITS)(void *v1, const void *v2, const void *v3,        \
+                              uint32_t desc)                                   \
+{                                                                              \
+    int i;                                                                     \
+                                                                               \
+    for (i = 0; i < (128 / BITS); i++) {                                       \
+        const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i);           \
+        const uint##BITS##_t b = s390_vec_read_element##BITS(v3, i);           \
+                                                                               \
+        s390_vec_write_element##BITS(v1, i, a >= b);                           \
+    }                                                                          \
+}
+DEF_VSCBI(8)
+DEF_VSCBI(16)
+
+void HELPER(gvec_vtm)(void *v1, const void *v2, CPUS390XState *env,
+                      uint32_t desc)
+{
+    S390Vector tmp;
+
+    s390_vec_and(&tmp, v1, v2);
+    if (s390_vec_is_zero(&tmp)) {
+        /* Selected bits all zeros; or all mask bits zero */
+        env->cc_op = 0;
+    } else if (s390_vec_equal(&tmp, v2)) {
+        /* Selected bits all ones */
+        env->cc_op = 3;
+    } else {
+        /* Selected bits a mix of zeros and ones */
+        env->cc_op = 1;
+    }
+}
diff --git a/target/s390x/tcg/vec_string_helper.c b/target/s390x/tcg/vec_string_helper.c
new file mode 100644 (file)
index 0000000..ac315eb
--- /dev/null
@@ -0,0 +1,473 @@
+/*
+ * QEMU TCG support -- s390x vector string instruction support
+ *
+ * Copyright (C) 2019 Red Hat Inc
+ *
+ * Authors:
+ *   David Hildenbrand <david@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "cpu.h"
+#include "s390x-internal.h"
+#include "vec.h"
+#include "tcg/tcg.h"
+#include "tcg/tcg-gvec-desc.h"
+#include "exec/helper-proto.h"
+
+/*
+ * Returns a bit set in the MSB of each element that is zero,
+ * as defined by the mask.
+ */
+static inline uint64_t zero_search(uint64_t a, uint64_t mask)
+{
+    return ~(((a & mask) + mask) | a | mask);
+}
+
+/*
+ * Returns a bit set in the MSB of each element that is not zero,
+ * as defined by the mask.
+ */
+static inline uint64_t nonzero_search(uint64_t a, uint64_t mask)
+{
+    return (((a & mask) + mask) | a) & ~mask;
+}
+
+/*
+ * Returns the byte offset for the first match, or 16 for no match.
+ */
+static inline int match_index(uint64_t c0, uint64_t c1)
+{
+    return (c0 ? clz64(c0) : clz64(c1) + 64) >> 3;
+}
+
+/*
+ * Returns the number of bits composing one element.
+ */
+static uint8_t get_element_bits(uint8_t es)
+{
+    return (1 << es) * BITS_PER_BYTE;
+}
+
+/*
+ * Returns the bitmask for a single element.
+ */
+static uint64_t get_single_element_mask(uint8_t es)
+{
+    return -1ull >> (64 - get_element_bits(es));
+}
+
+/*
+ * Returns the bitmask for a single element (excluding the MSB).
+ */
+static uint64_t get_single_element_lsbs_mask(uint8_t es)
+{
+    return -1ull >> (65 - get_element_bits(es));
+}
+
+/*
+ * Returns the bitmasks for multiple elements (excluding the MSBs).
+ */
+static uint64_t get_element_lsbs_mask(uint8_t es)
+{
+    return dup_const(es, get_single_element_lsbs_mask(es));
+}
+
+static int vfae(void *v1, const void *v2, const void *v3, bool in,
+                bool rt, bool zs, uint8_t es)
+{
+    const uint64_t mask = get_element_lsbs_mask(es);
+    const int bits = get_element_bits(es);
+    uint64_t a0, a1, b0, b1, e0, e1, t0, t1, z0, z1;
+    uint64_t first_zero = 16;
+    uint64_t first_equal;
+    int i;
+
+    a0 = s390_vec_read_element64(v2, 0);
+    a1 = s390_vec_read_element64(v2, 1);
+    b0 = s390_vec_read_element64(v3, 0);
+    b1 = s390_vec_read_element64(v3, 1);
+    e0 = 0;
+    e1 = 0;
+    /* compare against equality with every other element */
+    for (i = 0; i < 64; i += bits) {
+        t0 = rol64(b0, i);
+        t1 = rol64(b1, i);
+        e0 |= zero_search(a0 ^ t0, mask);
+        e0 |= zero_search(a0 ^ t1, mask);
+        e1 |= zero_search(a1 ^ t0, mask);
+        e1 |= zero_search(a1 ^ t1, mask);
+    }
+    /* invert the result if requested - invert only the MSBs */
+    if (in) {
+        e0 = ~e0 & ~mask;
+        e1 = ~e1 & ~mask;
+    }
+    first_equal = match_index(e0, e1);
+
+    if (zs) {
+        z0 = zero_search(a0, mask);
+        z1 = zero_search(a1, mask);
+        first_zero = match_index(z0, z1);
+    }
+
+    if (rt) {
+        e0 = (e0 >> (bits - 1)) * get_single_element_mask(es);
+        e1 = (e1 >> (bits - 1)) * get_single_element_mask(es);
+        s390_vec_write_element64(v1, 0, e0);
+        s390_vec_write_element64(v1, 1, e1);
+    } else {
+        s390_vec_write_element64(v1, 0, MIN(first_equal, first_zero));
+        s390_vec_write_element64(v1, 1, 0);
+    }
+
+    if (first_zero == 16 && first_equal == 16) {
+        return 3; /* no match */
+    } else if (first_zero == 16) {
+        return 1; /* matching elements, no match for zero */
+    } else if (first_equal < first_zero) {
+        return 2; /* matching elements before match for zero */
+    }
+    return 0; /* match for zero */
+}
+
+#define DEF_VFAE_HELPER(BITS)                                                  \
+void HELPER(gvec_vfae##BITS)(void *v1, const void *v2, const void *v3,         \
+                             uint32_t desc)                                    \
+{                                                                              \
+    const bool in = extract32(simd_data(desc), 3, 1);                          \
+    const bool rt = extract32(simd_data(desc), 2, 1);                          \
+    const bool zs = extract32(simd_data(desc), 1, 1);                          \
+                                                                               \
+    vfae(v1, v2, v3, in, rt, zs, MO_##BITS);                                   \
+}
+DEF_VFAE_HELPER(8)
+DEF_VFAE_HELPER(16)
+DEF_VFAE_HELPER(32)
+
+#define DEF_VFAE_CC_HELPER(BITS)                                               \
+void HELPER(gvec_vfae_cc##BITS)(void *v1, const void *v2, const void *v3,      \
+                                CPUS390XState *env, uint32_t desc)             \
+{                                                                              \
+    const bool in = extract32(simd_data(desc), 3, 1);                          \
+    const bool rt = extract32(simd_data(desc), 2, 1);                          \
+    const bool zs = extract32(simd_data(desc), 1, 1);                          \
+                                                                               \
+    env->cc_op = vfae(v1, v2, v3, in, rt, zs, MO_##BITS);                      \
+}
+DEF_VFAE_CC_HELPER(8)
+DEF_VFAE_CC_HELPER(16)
+DEF_VFAE_CC_HELPER(32)
+
+static int vfee(void *v1, const void *v2, const void *v3, bool zs, uint8_t es)
+{
+    const uint64_t mask = get_element_lsbs_mask(es);
+    uint64_t a0, a1, b0, b1, e0, e1, z0, z1;
+    uint64_t first_zero = 16;
+    uint64_t first_equal;
+
+    a0 = s390_vec_read_element64(v2, 0);
+    a1 = s390_vec_read_element64(v2, 1);
+    b0 = s390_vec_read_element64(v3, 0);
+    b1 = s390_vec_read_element64(v3, 1);
+    e0 = zero_search(a0 ^ b0, mask);
+    e1 = zero_search(a1 ^ b1, mask);
+    first_equal = match_index(e0, e1);
+
+    if (zs) {
+        z0 = zero_search(a0, mask);
+        z1 = zero_search(a1, mask);
+        first_zero = match_index(z0, z1);
+    }
+
+    s390_vec_write_element64(v1, 0, MIN(first_equal, first_zero));
+    s390_vec_write_element64(v1, 1, 0);
+    if (first_zero == 16 && first_equal == 16) {
+        return 3; /* no match */
+    } else if (first_zero == 16) {
+        return 1; /* matching elements, no match for zero */
+    } else if (first_equal < first_zero) {
+        return 2; /* matching elements before match for zero */
+    }
+    return 0; /* match for zero */
+}
+
+#define DEF_VFEE_HELPER(BITS)                                                  \
+void HELPER(gvec_vfee##BITS)(void *v1, const void *v2, const void *v3,         \
+                             uint32_t desc)                                    \
+{                                                                              \
+    const bool zs = extract32(simd_data(desc), 1, 1);                          \
+                                                                               \
+    vfee(v1, v2, v3, zs, MO_##BITS);                                           \
+}
+DEF_VFEE_HELPER(8)
+DEF_VFEE_HELPER(16)
+DEF_VFEE_HELPER(32)
+
+#define DEF_VFEE_CC_HELPER(BITS)                                               \
+void HELPER(gvec_vfee_cc##BITS)(void *v1, const void *v2, const void *v3,      \
+                                CPUS390XState *env, uint32_t desc)             \
+{                                                                              \
+    const bool zs = extract32(simd_data(desc), 1, 1);                          \
+                                                                               \
+    env->cc_op = vfee(v1, v2, v3, zs, MO_##BITS);                              \
+}
+DEF_VFEE_CC_HELPER(8)
+DEF_VFEE_CC_HELPER(16)
+DEF_VFEE_CC_HELPER(32)
+
+static int vfene(void *v1, const void *v2, const void *v3, bool zs, uint8_t es)
+{
+    const uint64_t mask = get_element_lsbs_mask(es);
+    uint64_t a0, a1, b0, b1, e0, e1, z0, z1;
+    uint64_t first_zero = 16;
+    uint64_t first_inequal;
+    bool smaller = false;
+
+    a0 = s390_vec_read_element64(v2, 0);
+    a1 = s390_vec_read_element64(v2, 1);
+    b0 = s390_vec_read_element64(v3, 0);
+    b1 = s390_vec_read_element64(v3, 1);
+    e0 = nonzero_search(a0 ^ b0, mask);
+    e1 = nonzero_search(a1 ^ b1, mask);
+    first_inequal = match_index(e0, e1);
+
+    /* identify the smaller element */
+    if (first_inequal < 16) {
+        uint8_t enr = first_inequal / (1 << es);
+        uint32_t a = s390_vec_read_element(v2, enr, es);
+        uint32_t b = s390_vec_read_element(v3, enr, es);
+
+        smaller = a < b;
+    }
+
+    if (zs) {
+        z0 = zero_search(a0, mask);
+        z1 = zero_search(a1, mask);
+        first_zero = match_index(z0, z1);
+    }
+
+    s390_vec_write_element64(v1, 0, MIN(first_inequal, first_zero));
+    s390_vec_write_element64(v1, 1, 0);
+    if (first_zero == 16 && first_inequal == 16) {
+        return 3;
+    } else if (first_zero < first_inequal) {
+        return 0;
+    }
+    return smaller ? 1 : 2;
+}
+
+#define DEF_VFENE_HELPER(BITS)                                                 \
+void HELPER(gvec_vfene##BITS)(void *v1, const void *v2, const void *v3,        \
+                              uint32_t desc)                                   \
+{                                                                              \
+    const bool zs = extract32(simd_data(desc), 1, 1);                          \
+                                                                               \
+    vfene(v1, v2, v3, zs, MO_##BITS);                                          \
+}
+DEF_VFENE_HELPER(8)
+DEF_VFENE_HELPER(16)
+DEF_VFENE_HELPER(32)
+
+#define DEF_VFENE_CC_HELPER(BITS)                                              \
+void HELPER(gvec_vfene_cc##BITS)(void *v1, const void *v2, const void *v3,     \
+                                 CPUS390XState *env, uint32_t desc)            \
+{                                                                              \
+    const bool zs = extract32(simd_data(desc), 1, 1);                          \
+                                                                               \
+    env->cc_op = vfene(v1, v2, v3, zs, MO_##BITS);                             \
+}
+DEF_VFENE_CC_HELPER(8)
+DEF_VFENE_CC_HELPER(16)
+DEF_VFENE_CC_HELPER(32)
+
+static int vistr(void *v1, const void *v2, uint8_t es)
+{
+    const uint64_t mask = get_element_lsbs_mask(es);
+    uint64_t a0 = s390_vec_read_element64(v2, 0);
+    uint64_t a1 = s390_vec_read_element64(v2, 1);
+    uint64_t z;
+    int cc = 3;
+
+    z = zero_search(a0, mask);
+    if (z) {
+        a0 &= ~(-1ull >> clz64(z));
+        a1 = 0;
+        cc = 0;
+    } else {
+        z = zero_search(a1, mask);
+        if (z) {
+            a1 &= ~(-1ull >> clz64(z));
+            cc = 0;
+        }
+    }
+
+    s390_vec_write_element64(v1, 0, a0);
+    s390_vec_write_element64(v1, 1, a1);
+    return cc;
+}
+
+#define DEF_VISTR_HELPER(BITS)                                                 \
+void HELPER(gvec_vistr##BITS)(void *v1, const void *v2, uint32_t desc)         \
+{                                                                              \
+    vistr(v1, v2, MO_##BITS);                                                  \
+}
+DEF_VISTR_HELPER(8)
+DEF_VISTR_HELPER(16)
+DEF_VISTR_HELPER(32)
+
+#define DEF_VISTR_CC_HELPER(BITS)                                              \
+void HELPER(gvec_vistr_cc##BITS)(void *v1, const void *v2, CPUS390XState *env, \
+                                uint32_t desc)                                 \
+{                                                                              \
+    env->cc_op = vistr(v1, v2, MO_##BITS);                                     \
+}
+DEF_VISTR_CC_HELPER(8)
+DEF_VISTR_CC_HELPER(16)
+DEF_VISTR_CC_HELPER(32)
+
+static bool element_compare(uint32_t data, uint32_t l, uint8_t c)
+{
+    const bool equal = extract32(c, 7, 1);
+    const bool lower = extract32(c, 6, 1);
+    const bool higher = extract32(c, 5, 1);
+
+    if (data < l) {
+        return lower;
+    } else if (data > l) {
+        return higher;
+    }
+    return equal;
+}
+
+static int vstrc(void *v1, const void *v2, const void *v3, const void *v4,
+                 bool in, bool rt, bool zs, uint8_t es)
+{
+    const uint64_t mask = get_element_lsbs_mask(es);
+    uint64_t a0 = s390_vec_read_element64(v2, 0);
+    uint64_t a1 = s390_vec_read_element64(v2, 1);
+    int first_zero = 16, first_match = 16;
+    S390Vector rt_result = {};
+    uint64_t z0, z1;
+    int i, j;
+
+    if (zs) {
+        z0 = zero_search(a0, mask);
+        z1 = zero_search(a1, mask);
+        first_zero = match_index(z0, z1);
+    }
+
+    for (i = 0; i < 16 / (1 << es); i++) {
+        const uint32_t data = s390_vec_read_element(v2, i, es);
+        const int cur_byte = i * (1 << es);
+        bool any_match = false;
+
+        /* if we don't need a bit vector, we can stop early */
+        if (cur_byte == first_zero && !rt) {
+            break;
+        }
+
+        for (j = 0; j < 16 / (1 << es); j += 2) {
+            const uint32_t l1 = s390_vec_read_element(v3, j, es);
+            const uint32_t l2 = s390_vec_read_element(v3, j + 1, es);
+            /* we are only interested in the highest byte of each element */
+            const uint8_t c1 = s390_vec_read_element8(v4, j * (1 << es));
+            const uint8_t c2 = s390_vec_read_element8(v4, (j + 1) * (1 << es));
+
+            if (element_compare(data, l1, c1) &&
+                element_compare(data, l2, c2)) {
+                any_match = true;
+                break;
+            }
+        }
+        /* invert the result if requested */
+        any_match = in ^ any_match;
+
+        if (any_match) {
+            /* indicate bit vector if requested */
+            if (rt) {
+                const uint64_t val = -1ull;
+
+                first_match = MIN(cur_byte, first_match);
+                s390_vec_write_element(&rt_result, i, es, val);
+            } else {
+                /* stop on the first match */
+                first_match = cur_byte;
+                break;
+            }
+        }
+    }
+
+    if (rt) {
+        *(S390Vector *)v1 = rt_result;
+    } else {
+        s390_vec_write_element64(v1, 0, MIN(first_match, first_zero));
+        s390_vec_write_element64(v1, 1, 0);
+    }
+
+    if (first_zero == 16 && first_match == 16) {
+        return 3; /* no match */
+    } else if (first_zero == 16) {
+        return 1; /* matching elements, no match for zero */
+    } else if (first_match < first_zero) {
+        return 2; /* matching elements before match for zero */
+    }
+    return 0; /* match for zero */
+}
+
+#define DEF_VSTRC_HELPER(BITS)                                                 \
+void HELPER(gvec_vstrc##BITS)(void *v1, const void *v2, const void *v3,        \
+                              const void *v4, uint32_t desc)                   \
+{                                                                              \
+    const bool in = extract32(simd_data(desc), 3, 1);                          \
+    const bool zs = extract32(simd_data(desc), 1, 1);                          \
+                                                                               \
+    vstrc(v1, v2, v3, v4, in, 0, zs, MO_##BITS);                               \
+}
+DEF_VSTRC_HELPER(8)
+DEF_VSTRC_HELPER(16)
+DEF_VSTRC_HELPER(32)
+
+#define DEF_VSTRC_RT_HELPER(BITS)                                              \
+void HELPER(gvec_vstrc_rt##BITS)(void *v1, const void *v2, const void *v3,     \
+                                 const void *v4, uint32_t desc)                \
+{                                                                              \
+    const bool in = extract32(simd_data(desc), 3, 1);                          \
+    const bool zs = extract32(simd_data(desc), 1, 1);                          \
+                                                                               \
+    vstrc(v1, v2, v3, v4, in, 1, zs, MO_##BITS);                               \
+}
+DEF_VSTRC_RT_HELPER(8)
+DEF_VSTRC_RT_HELPER(16)
+DEF_VSTRC_RT_HELPER(32)
+
+#define DEF_VSTRC_CC_HELPER(BITS)                                              \
+void HELPER(gvec_vstrc_cc##BITS)(void *v1, const void *v2, const void *v3,     \
+                                 const void *v4, CPUS390XState *env,           \
+                                 uint32_t desc)                                \
+{                                                                              \
+    const bool in = extract32(simd_data(desc), 3, 1);                          \
+    const bool zs = extract32(simd_data(desc), 1, 1);                          \
+                                                                               \
+    env->cc_op = vstrc(v1, v2, v3, v4, in, 0, zs, MO_##BITS);                  \
+}
+DEF_VSTRC_CC_HELPER(8)
+DEF_VSTRC_CC_HELPER(16)
+DEF_VSTRC_CC_HELPER(32)
+
+#define DEF_VSTRC_CC_RT_HELPER(BITS)                                           \
+void HELPER(gvec_vstrc_cc_rt##BITS)(void *v1, const void *v2, const void *v3,  \
+                                    const void *v4, CPUS390XState *env,        \
+                                    uint32_t desc)                             \
+{                                                                              \
+    const bool in = extract32(simd_data(desc), 3, 1);                          \
+    const bool zs = extract32(simd_data(desc), 1, 1);                          \
+                                                                               \
+    env->cc_op = vstrc(v1, v2, v3, v4, in, 1, zs, MO_##BITS);                  \
+}
+DEF_VSTRC_CC_RT_HELPER(8)
+DEF_VSTRC_CC_RT_HELPER(16)
+DEF_VSTRC_CC_RT_HELPER(32)
diff --git a/target/s390x/tcg_s390x.h b/target/s390x/tcg_s390x.h
deleted file mode 100644 (file)
index 2f54ccb..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * QEMU TCG support -- s390x specific functions.
- *
- * Copyright 2018 Red Hat, Inc.
- *
- * Authors:
- *   David Hildenbrand <david@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#ifndef TCG_S390X_H
-#define TCG_S390X_H
-
-void tcg_s390_tod_updated(CPUState *cs, run_on_cpu_data opaque);
-void QEMU_NORETURN tcg_s390_program_interrupt(CPUS390XState *env,
-                                              uint32_t code, uintptr_t ra);
-void QEMU_NORETURN tcg_s390_data_exception(CPUS390XState *env, uint32_t dxc,
-                                           uintptr_t ra);
-void QEMU_NORETURN tcg_s390_vector_exception(CPUS390XState *env, uint32_t vxc,
-                                             uintptr_t ra);
-
-#endif /* TCG_S390X_H */
index e661a81e3a9e966066136dcca42ccf92552215ee..729cb012b414d4c6ecedaf05d83484b0d896aa8d 100644 (file)
@@ -10,13 +10,7 @@ ioinst_sch_id(const char *insn, int cssid, int ssid, int schid) "IOINST: %s (%x.
 ioinst_chp_id(const char *insn, int cssid, int chpid) "IOINST: %s (%x.%02x)"
 ioinst_chsc_cmd(uint16_t cmd, uint16_t len) "IOINST: chsc command 0x%04x, len 0x%04x"
 
-# kvm.c
-kvm_enable_cmma(int rc) "CMMA: enabling with result code %d"
-kvm_clear_cmma(int rc) "CMMA: clearing with result code %d"
-kvm_failed_cpu_state_set(int cpu_index, uint8_t state, const char *msg) "Warning: Unable to set cpu %d state %" PRIu8 " to KVM: %s"
-kvm_assign_subch_ioeventfd(int fd, uint32_t addr, bool assign, int datamatch) "fd: %d sch: @0x%x assign: %d vq: %d"
-
-# cpu.c
+# cpu-sysemu.c
 cpu_set_state(int cpu_index, uint8_t state) "setting cpu %d state to %" PRIu8
 cpu_halt(int cpu_index) "halting cpu %d"
 cpu_unhalt(int cpu_index) "unhalting cpu %d"
diff --git a/target/s390x/translate.c b/target/s390x/translate.c
deleted file mode 100644 (file)
index c8d55d1..0000000
+++ /dev/null
@@ -1,6687 +0,0 @@
-/*
- *  S/390 translation
- *
- *  Copyright (c) 2009 Ulrich Hecht
- *  Copyright (c) 2010 Alexander Graf
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/* #define DEBUG_INLINE_BRANCHES */
-#define S390X_DEBUG_DISAS
-/* #define S390X_DEBUG_DISAS_VERBOSE */
-
-#ifdef S390X_DEBUG_DISAS_VERBOSE
-#  define LOG_DISAS(...) qemu_log(__VA_ARGS__)
-#else
-#  define LOG_DISAS(...) do { } while (0)
-#endif
-
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "internal.h"
-#include "disas/disas.h"
-#include "exec/exec-all.h"
-#include "tcg/tcg-op.h"
-#include "tcg/tcg-op-gvec.h"
-#include "qemu/log.h"
-#include "qemu/host-utils.h"
-#include "exec/cpu_ldst.h"
-#include "exec/gen-icount.h"
-#include "exec/helper-proto.h"
-#include "exec/helper-gen.h"
-
-#include "exec/translator.h"
-#include "exec/log.h"
-#include "qemu/atomic128.h"
-
-
-/* Information that (most) every instruction needs to manipulate.  */
-typedef struct DisasContext DisasContext;
-typedef struct DisasInsn DisasInsn;
-typedef struct DisasFields DisasFields;
-
-/*
- * Define a structure to hold the decoded fields.  We'll store each inside
- * an array indexed by an enum.  In order to conserve memory, we'll arrange
- * for fields that do not exist at the same time to overlap, thus the "C"
- * for compact.  For checking purposes there is an "O" for original index
- * as well that will be applied to availability bitmaps.
- */
-
-enum DisasFieldIndexO {
-    FLD_O_r1,
-    FLD_O_r2,
-    FLD_O_r3,
-    FLD_O_m1,
-    FLD_O_m3,
-    FLD_O_m4,
-    FLD_O_m5,
-    FLD_O_m6,
-    FLD_O_b1,
-    FLD_O_b2,
-    FLD_O_b4,
-    FLD_O_d1,
-    FLD_O_d2,
-    FLD_O_d4,
-    FLD_O_x2,
-    FLD_O_l1,
-    FLD_O_l2,
-    FLD_O_i1,
-    FLD_O_i2,
-    FLD_O_i3,
-    FLD_O_i4,
-    FLD_O_i5,
-    FLD_O_v1,
-    FLD_O_v2,
-    FLD_O_v3,
-    FLD_O_v4,
-};
-
-enum DisasFieldIndexC {
-    FLD_C_r1 = 0,
-    FLD_C_m1 = 0,
-    FLD_C_b1 = 0,
-    FLD_C_i1 = 0,
-    FLD_C_v1 = 0,
-
-    FLD_C_r2 = 1,
-    FLD_C_b2 = 1,
-    FLD_C_i2 = 1,
-
-    FLD_C_r3 = 2,
-    FLD_C_m3 = 2,
-    FLD_C_i3 = 2,
-    FLD_C_v3 = 2,
-
-    FLD_C_m4 = 3,
-    FLD_C_b4 = 3,
-    FLD_C_i4 = 3,
-    FLD_C_l1 = 3,
-    FLD_C_v4 = 3,
-
-    FLD_C_i5 = 4,
-    FLD_C_d1 = 4,
-    FLD_C_m5 = 4,
-
-    FLD_C_d2 = 5,
-    FLD_C_m6 = 5,
-
-    FLD_C_d4 = 6,
-    FLD_C_x2 = 6,
-    FLD_C_l2 = 6,
-    FLD_C_v2 = 6,
-
-    NUM_C_FIELD = 7
-};
-
-struct DisasFields {
-    uint64_t raw_insn;
-    unsigned op:8;
-    unsigned op2:8;
-    unsigned presentC:16;
-    unsigned int presentO;
-    int c[NUM_C_FIELD];
-};
-
-struct DisasContext {
-    DisasContextBase base;
-    const DisasInsn *insn;
-    DisasFields fields;
-    uint64_t ex_value;
-    /*
-     * During translate_one(), pc_tmp is used to determine the instruction
-     * to be executed after base.pc_next - e.g. next sequential instruction
-     * or a branch target.
-     */
-    uint64_t pc_tmp;
-    uint32_t ilen;
-    enum cc_op cc_op;
-    bool do_debug;
-};
-
-/* Information carried about a condition to be evaluated.  */
-typedef struct {
-    TCGCond cond:8;
-    bool is_64;
-    bool g1;
-    bool g2;
-    union {
-        struct { TCGv_i64 a, b; } s64;
-        struct { TCGv_i32 a, b; } s32;
-    } u;
-} DisasCompare;
-
-#ifdef DEBUG_INLINE_BRANCHES
-static uint64_t inline_branch_hit[CC_OP_MAX];
-static uint64_t inline_branch_miss[CC_OP_MAX];
-#endif
-
-static void pc_to_link_info(TCGv_i64 out, DisasContext *s, uint64_t pc)
-{
-    TCGv_i64 tmp;
-
-    if (s->base.tb->flags & FLAG_MASK_32) {
-        if (s->base.tb->flags & FLAG_MASK_64) {
-            tcg_gen_movi_i64(out, pc);
-            return;
-        }
-        pc |= 0x80000000;
-    }
-    assert(!(s->base.tb->flags & FLAG_MASK_64));
-    tmp = tcg_const_i64(pc);
-    tcg_gen_deposit_i64(out, out, tmp, 0, 32);
-    tcg_temp_free_i64(tmp);
-}
-
-static TCGv_i64 psw_addr;
-static TCGv_i64 psw_mask;
-static TCGv_i64 gbea;
-
-static TCGv_i32 cc_op;
-static TCGv_i64 cc_src;
-static TCGv_i64 cc_dst;
-static TCGv_i64 cc_vr;
-
-static char cpu_reg_names[16][4];
-static TCGv_i64 regs[16];
-
-void s390x_translate_init(void)
-{
-    int i;
-
-    psw_addr = tcg_global_mem_new_i64(cpu_env,
-                                      offsetof(CPUS390XState, psw.addr),
-                                      "psw_addr");
-    psw_mask = tcg_global_mem_new_i64(cpu_env,
-                                      offsetof(CPUS390XState, psw.mask),
-                                      "psw_mask");
-    gbea = tcg_global_mem_new_i64(cpu_env,
-                                  offsetof(CPUS390XState, gbea),
-                                  "gbea");
-
-    cc_op = tcg_global_mem_new_i32(cpu_env, offsetof(CPUS390XState, cc_op),
-                                   "cc_op");
-    cc_src = tcg_global_mem_new_i64(cpu_env, offsetof(CPUS390XState, cc_src),
-                                    "cc_src");
-    cc_dst = tcg_global_mem_new_i64(cpu_env, offsetof(CPUS390XState, cc_dst),
-                                    "cc_dst");
-    cc_vr = tcg_global_mem_new_i64(cpu_env, offsetof(CPUS390XState, cc_vr),
-                                   "cc_vr");
-
-    for (i = 0; i < 16; i++) {
-        snprintf(cpu_reg_names[i], sizeof(cpu_reg_names[0]), "r%d", i);
-        regs[i] = tcg_global_mem_new(cpu_env,
-                                     offsetof(CPUS390XState, regs[i]),
-                                     cpu_reg_names[i]);
-    }
-}
-
-static inline int vec_full_reg_offset(uint8_t reg)
-{
-    g_assert(reg < 32);
-    return offsetof(CPUS390XState, vregs[reg][0]);
-}
-
-static inline int vec_reg_offset(uint8_t reg, uint8_t enr, MemOp es)
-{
-    /* Convert element size (es) - e.g. MO_8 - to bytes */
-    const uint8_t bytes = 1 << es;
-    int offs = enr * bytes;
-
-    /*
-     * vregs[n][0] is the lowest 8 byte and vregs[n][1] the highest 8 byte
-     * of the 16 byte vector, on both, little and big endian systems.
-     *
-     * Big Endian (target/possible host)
-     * B:  [ 0][ 1][ 2][ 3][ 4][ 5][ 6][ 7] - [ 8][ 9][10][11][12][13][14][15]
-     * HW: [     0][     1][     2][     3] - [     4][     5][     6][     7]
-     * W:  [             0][             1] - [             2][             3]
-     * DW: [                             0] - [                             1]
-     *
-     * Little Endian (possible host)
-     * B:  [ 7][ 6][ 5][ 4][ 3][ 2][ 1][ 0] - [15][14][13][12][11][10][ 9][ 8]
-     * HW: [     3][     2][     1][     0] - [     7][     6][     5][     4]
-     * W:  [             1][             0] - [             3][             2]
-     * DW: [                             0] - [                             1]
-     *
-     * For 16 byte elements, the two 8 byte halves will not form a host
-     * int128 if the host is little endian, since they're in the wrong order.
-     * Some operations (e.g. xor) do not care. For operations like addition,
-     * the two 8 byte elements have to be loaded separately. Let's force all
-     * 16 byte operations to handle it in a special way.
-     */
-    g_assert(es <= MO_64);
-#ifndef HOST_WORDS_BIGENDIAN
-    offs ^= (8 - bytes);
-#endif
-    return offs + vec_full_reg_offset(reg);
-}
-
-static inline int freg64_offset(uint8_t reg)
-{
-    g_assert(reg < 16);
-    return vec_reg_offset(reg, 0, MO_64);
-}
-
-static inline int freg32_offset(uint8_t reg)
-{
-    g_assert(reg < 16);
-    return vec_reg_offset(reg, 0, MO_32);
-}
-
-static TCGv_i64 load_reg(int reg)
-{
-    TCGv_i64 r = tcg_temp_new_i64();
-    tcg_gen_mov_i64(r, regs[reg]);
-    return r;
-}
-
-static TCGv_i64 load_freg(int reg)
-{
-    TCGv_i64 r = tcg_temp_new_i64();
-
-    tcg_gen_ld_i64(r, cpu_env, freg64_offset(reg));
-    return r;
-}
-
-static TCGv_i64 load_freg32_i64(int reg)
-{
-    TCGv_i64 r = tcg_temp_new_i64();
-
-    tcg_gen_ld32u_i64(r, cpu_env, freg32_offset(reg));
-    return r;
-}
-
-static void store_reg(int reg, TCGv_i64 v)
-{
-    tcg_gen_mov_i64(regs[reg], v);
-}
-
-static void store_freg(int reg, TCGv_i64 v)
-{
-    tcg_gen_st_i64(v, cpu_env, freg64_offset(reg));
-}
-
-static void store_reg32_i64(int reg, TCGv_i64 v)
-{
-    /* 32 bit register writes keep the upper half */
-    tcg_gen_deposit_i64(regs[reg], regs[reg], v, 0, 32);
-}
-
-static void store_reg32h_i64(int reg, TCGv_i64 v)
-{
-    tcg_gen_deposit_i64(regs[reg], regs[reg], v, 32, 32);
-}
-
-static void store_freg32_i64(int reg, TCGv_i64 v)
-{
-    tcg_gen_st32_i64(v, cpu_env, freg32_offset(reg));
-}
-
-static void return_low128(TCGv_i64 dest)
-{
-    tcg_gen_ld_i64(dest, cpu_env, offsetof(CPUS390XState, retxl));
-}
-
-static void update_psw_addr(DisasContext *s)
-{
-    /* psw.addr */
-    tcg_gen_movi_i64(psw_addr, s->base.pc_next);
-}
-
-static void per_branch(DisasContext *s, bool to_next)
-{
-#ifndef CONFIG_USER_ONLY
-    tcg_gen_movi_i64(gbea, s->base.pc_next);
-
-    if (s->base.tb->flags & FLAG_MASK_PER) {
-        TCGv_i64 next_pc = to_next ? tcg_const_i64(s->pc_tmp) : psw_addr;
-        gen_helper_per_branch(cpu_env, gbea, next_pc);
-        if (to_next) {
-            tcg_temp_free_i64(next_pc);
-        }
-    }
-#endif
-}
-
-static void per_branch_cond(DisasContext *s, TCGCond cond,
-                            TCGv_i64 arg1, TCGv_i64 arg2)
-{
-#ifndef CONFIG_USER_ONLY
-    if (s->base.tb->flags & FLAG_MASK_PER) {
-        TCGLabel *lab = gen_new_label();
-        tcg_gen_brcond_i64(tcg_invert_cond(cond), arg1, arg2, lab);
-
-        tcg_gen_movi_i64(gbea, s->base.pc_next);
-        gen_helper_per_branch(cpu_env, gbea, psw_addr);
-
-        gen_set_label(lab);
-    } else {
-        TCGv_i64 pc = tcg_const_i64(s->base.pc_next);
-        tcg_gen_movcond_i64(cond, gbea, arg1, arg2, gbea, pc);
-        tcg_temp_free_i64(pc);
-    }
-#endif
-}
-
-static void per_breaking_event(DisasContext *s)
-{
-    tcg_gen_movi_i64(gbea, s->base.pc_next);
-}
-
-static void update_cc_op(DisasContext *s)
-{
-    if (s->cc_op != CC_OP_DYNAMIC && s->cc_op != CC_OP_STATIC) {
-        tcg_gen_movi_i32(cc_op, s->cc_op);
-    }
-}
-
-static inline uint64_t ld_code2(CPUS390XState *env, uint64_t pc)
-{
-    return (uint64_t)cpu_lduw_code(env, pc);
-}
-
-static inline uint64_t ld_code4(CPUS390XState *env, uint64_t pc)
-{
-    return (uint64_t)(uint32_t)cpu_ldl_code(env, pc);
-}
-
-static int get_mem_index(DisasContext *s)
-{
-#ifdef CONFIG_USER_ONLY
-    return MMU_USER_IDX;
-#else
-    if (!(s->base.tb->flags & FLAG_MASK_DAT)) {
-        return MMU_REAL_IDX;
-    }
-
-    switch (s->base.tb->flags & FLAG_MASK_ASC) {
-    case PSW_ASC_PRIMARY >> FLAG_MASK_PSW_SHIFT:
-        return MMU_PRIMARY_IDX;
-    case PSW_ASC_SECONDARY >> FLAG_MASK_PSW_SHIFT:
-        return MMU_SECONDARY_IDX;
-    case PSW_ASC_HOME >> FLAG_MASK_PSW_SHIFT:
-        return MMU_HOME_IDX;
-    default:
-        tcg_abort();
-        break;
-    }
-#endif
-}
-
-static void gen_exception(int excp)
-{
-    TCGv_i32 tmp = tcg_const_i32(excp);
-    gen_helper_exception(cpu_env, tmp);
-    tcg_temp_free_i32(tmp);
-}
-
-static void gen_program_exception(DisasContext *s, int code)
-{
-    TCGv_i32 tmp;
-
-    /* Remember what pgm exeption this was.  */
-    tmp = tcg_const_i32(code);
-    tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_code));
-    tcg_temp_free_i32(tmp);
-
-    tmp = tcg_const_i32(s->ilen);
-    tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_ilen));
-    tcg_temp_free_i32(tmp);
-
-    /* update the psw */
-    update_psw_addr(s);
-
-    /* Save off cc.  */
-    update_cc_op(s);
-
-    /* Trigger exception.  */
-    gen_exception(EXCP_PGM);
-}
-
-static inline void gen_illegal_opcode(DisasContext *s)
-{
-    gen_program_exception(s, PGM_OPERATION);
-}
-
-static inline void gen_data_exception(uint8_t dxc)
-{
-    TCGv_i32 tmp = tcg_const_i32(dxc);
-    gen_helper_data_exception(cpu_env, tmp);
-    tcg_temp_free_i32(tmp);
-}
-
-static inline void gen_trap(DisasContext *s)
-{
-    /* Set DXC to 0xff */
-    gen_data_exception(0xff);
-}
-
-static void gen_addi_and_wrap_i64(DisasContext *s, TCGv_i64 dst, TCGv_i64 src,
-                                  int64_t imm)
-{
-    tcg_gen_addi_i64(dst, src, imm);
-    if (!(s->base.tb->flags & FLAG_MASK_64)) {
-        if (s->base.tb->flags & FLAG_MASK_32) {
-            tcg_gen_andi_i64(dst, dst, 0x7fffffff);
-        } else {
-            tcg_gen_andi_i64(dst, dst, 0x00ffffff);
-        }
-    }
-}
-
-static TCGv_i64 get_address(DisasContext *s, int x2, int b2, int d2)
-{
-    TCGv_i64 tmp = tcg_temp_new_i64();
-
-    /*
-     * Note that d2 is limited to 20 bits, signed.  If we crop negative
-     * displacements early we create larger immedate addends.
-     */
-    if (b2 && x2) {
-        tcg_gen_add_i64(tmp, regs[b2], regs[x2]);
-        gen_addi_and_wrap_i64(s, tmp, tmp, d2);
-    } else if (b2) {
-        gen_addi_and_wrap_i64(s, tmp, regs[b2], d2);
-    } else if (x2) {
-        gen_addi_and_wrap_i64(s, tmp, regs[x2], d2);
-    } else if (!(s->base.tb->flags & FLAG_MASK_64)) {
-        if (s->base.tb->flags & FLAG_MASK_32) {
-            tcg_gen_movi_i64(tmp, d2 & 0x7fffffff);
-        } else {
-            tcg_gen_movi_i64(tmp, d2 & 0x00ffffff);
-        }
-    } else {
-        tcg_gen_movi_i64(tmp, d2);
-    }
-
-    return tmp;
-}
-
-static inline bool live_cc_data(DisasContext *s)
-{
-    return (s->cc_op != CC_OP_DYNAMIC
-            && s->cc_op != CC_OP_STATIC
-            && s->cc_op > 3);
-}
-
-static inline void gen_op_movi_cc(DisasContext *s, uint32_t val)
-{
-    if (live_cc_data(s)) {
-        tcg_gen_discard_i64(cc_src);
-        tcg_gen_discard_i64(cc_dst);
-        tcg_gen_discard_i64(cc_vr);
-    }
-    s->cc_op = CC_OP_CONST0 + val;
-}
-
-static void gen_op_update1_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 dst)
-{
-    if (live_cc_data(s)) {
-        tcg_gen_discard_i64(cc_src);
-        tcg_gen_discard_i64(cc_vr);
-    }
-    tcg_gen_mov_i64(cc_dst, dst);
-    s->cc_op = op;
-}
-
-static void gen_op_update2_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src,
-                                  TCGv_i64 dst)
-{
-    if (live_cc_data(s)) {
-        tcg_gen_discard_i64(cc_vr);
-    }
-    tcg_gen_mov_i64(cc_src, src);
-    tcg_gen_mov_i64(cc_dst, dst);
-    s->cc_op = op;
-}
-
-static void gen_op_update3_cc_i64(DisasContext *s, enum cc_op op, TCGv_i64 src,
-                                  TCGv_i64 dst, TCGv_i64 vr)
-{
-    tcg_gen_mov_i64(cc_src, src);
-    tcg_gen_mov_i64(cc_dst, dst);
-    tcg_gen_mov_i64(cc_vr, vr);
-    s->cc_op = op;
-}
-
-static void set_cc_nz_u64(DisasContext *s, TCGv_i64 val)
-{
-    gen_op_update1_cc_i64(s, CC_OP_NZ, val);
-}
-
-static void gen_set_cc_nz_f32(DisasContext *s, TCGv_i64 val)
-{
-    gen_op_update1_cc_i64(s, CC_OP_NZ_F32, val);
-}
-
-static void gen_set_cc_nz_f64(DisasContext *s, TCGv_i64 val)
-{
-    gen_op_update1_cc_i64(s, CC_OP_NZ_F64, val);
-}
-
-static void gen_set_cc_nz_f128(DisasContext *s, TCGv_i64 vh, TCGv_i64 vl)
-{
-    gen_op_update2_cc_i64(s, CC_OP_NZ_F128, vh, vl);
-}
-
-/* CC value is in env->cc_op */
-static void set_cc_static(DisasContext *s)
-{
-    if (live_cc_data(s)) {
-        tcg_gen_discard_i64(cc_src);
-        tcg_gen_discard_i64(cc_dst);
-        tcg_gen_discard_i64(cc_vr);
-    }
-    s->cc_op = CC_OP_STATIC;
-}
-
-/* calculates cc into cc_op */
-static void gen_op_calc_cc(DisasContext *s)
-{
-    TCGv_i32 local_cc_op = NULL;
-    TCGv_i64 dummy = NULL;
-
-    switch (s->cc_op) {
-    default:
-        dummy = tcg_const_i64(0);
-        /* FALLTHRU */
-    case CC_OP_ADD_64:
-    case CC_OP_SUB_64:
-    case CC_OP_ADD_32:
-    case CC_OP_SUB_32:
-        local_cc_op = tcg_const_i32(s->cc_op);
-        break;
-    case CC_OP_CONST0:
-    case CC_OP_CONST1:
-    case CC_OP_CONST2:
-    case CC_OP_CONST3:
-    case CC_OP_STATIC:
-    case CC_OP_DYNAMIC:
-        break;
-    }
-
-    switch (s->cc_op) {
-    case CC_OP_CONST0:
-    case CC_OP_CONST1:
-    case CC_OP_CONST2:
-    case CC_OP_CONST3:
-        /* s->cc_op is the cc value */
-        tcg_gen_movi_i32(cc_op, s->cc_op - CC_OP_CONST0);
-        break;
-    case CC_OP_STATIC:
-        /* env->cc_op already is the cc value */
-        break;
-    case CC_OP_NZ:
-    case CC_OP_ABS_64:
-    case CC_OP_NABS_64:
-    case CC_OP_ABS_32:
-    case CC_OP_NABS_32:
-    case CC_OP_LTGT0_32:
-    case CC_OP_LTGT0_64:
-    case CC_OP_COMP_32:
-    case CC_OP_COMP_64:
-    case CC_OP_NZ_F32:
-    case CC_OP_NZ_F64:
-    case CC_OP_FLOGR:
-    case CC_OP_LCBB:
-    case CC_OP_MULS_32:
-        /* 1 argument */
-        gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, dummy, cc_dst, dummy);
-        break;
-    case CC_OP_ADDU:
-    case CC_OP_ICM:
-    case CC_OP_LTGT_32:
-    case CC_OP_LTGT_64:
-    case CC_OP_LTUGTU_32:
-    case CC_OP_LTUGTU_64:
-    case CC_OP_TM_32:
-    case CC_OP_TM_64:
-    case CC_OP_SLA_32:
-    case CC_OP_SLA_64:
-    case CC_OP_SUBU:
-    case CC_OP_NZ_F128:
-    case CC_OP_VC:
-    case CC_OP_MULS_64:
-        /* 2 arguments */
-        gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, dummy);
-        break;
-    case CC_OP_ADD_64:
-    case CC_OP_SUB_64:
-    case CC_OP_ADD_32:
-    case CC_OP_SUB_32:
-        /* 3 arguments */
-        gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, cc_vr);
-        break;
-    case CC_OP_DYNAMIC:
-        /* unknown operation - assume 3 arguments and cc_op in env */
-        gen_helper_calc_cc(cc_op, cpu_env, cc_op, cc_src, cc_dst, cc_vr);
-        break;
-    default:
-        tcg_abort();
-    }
-
-    if (local_cc_op) {
-        tcg_temp_free_i32(local_cc_op);
-    }
-    if (dummy) {
-        tcg_temp_free_i64(dummy);
-    }
-
-    /* We now have cc in cc_op as constant */
-    set_cc_static(s);
-}
-
-static bool use_goto_tb(DisasContext *s, uint64_t dest)
-{
-    if (unlikely(s->base.tb->flags & FLAG_MASK_PER)) {
-        return false;
-    }
-    return translator_use_goto_tb(&s->base, dest);
-}
-
-static void account_noninline_branch(DisasContext *s, int cc_op)
-{
-#ifdef DEBUG_INLINE_BRANCHES
-    inline_branch_miss[cc_op]++;
-#endif
-}
-
-static void account_inline_branch(DisasContext *s, int cc_op)
-{
-#ifdef DEBUG_INLINE_BRANCHES
-    inline_branch_hit[cc_op]++;
-#endif
-}
-
-/* Table of mask values to comparison codes, given a comparison as input.
-   For such, CC=3 should not be possible.  */
-static const TCGCond ltgt_cond[16] = {
-    TCG_COND_NEVER,  TCG_COND_NEVER,     /*    |    |    | x */
-    TCG_COND_GT,     TCG_COND_GT,        /*    |    | GT | x */
-    TCG_COND_LT,     TCG_COND_LT,        /*    | LT |    | x */
-    TCG_COND_NE,     TCG_COND_NE,        /*    | LT | GT | x */
-    TCG_COND_EQ,     TCG_COND_EQ,        /* EQ |    |    | x */
-    TCG_COND_GE,     TCG_COND_GE,        /* EQ |    | GT | x */
-    TCG_COND_LE,     TCG_COND_LE,        /* EQ | LT |    | x */
-    TCG_COND_ALWAYS, TCG_COND_ALWAYS,    /* EQ | LT | GT | x */
-};
-
-/* Table of mask values to comparison codes, given a logic op as input.
-   For such, only CC=0 and CC=1 should be possible.  */
-static const TCGCond nz_cond[16] = {
-    TCG_COND_NEVER, TCG_COND_NEVER,      /*    |    | x | x */
-    TCG_COND_NEVER, TCG_COND_NEVER,
-    TCG_COND_NE, TCG_COND_NE,            /*    | NE | x | x */
-    TCG_COND_NE, TCG_COND_NE,
-    TCG_COND_EQ, TCG_COND_EQ,            /* EQ |    | x | x */
-    TCG_COND_EQ, TCG_COND_EQ,
-    TCG_COND_ALWAYS, TCG_COND_ALWAYS,    /* EQ | NE | x | x */
-    TCG_COND_ALWAYS, TCG_COND_ALWAYS,
-};
-
-/* Interpret MASK in terms of S->CC_OP, and fill in C with all the
-   details required to generate a TCG comparison.  */
-static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask)
-{
-    TCGCond cond;
-    enum cc_op old_cc_op = s->cc_op;
-
-    if (mask == 15 || mask == 0) {
-        c->cond = (mask ? TCG_COND_ALWAYS : TCG_COND_NEVER);
-        c->u.s32.a = cc_op;
-        c->u.s32.b = cc_op;
-        c->g1 = c->g2 = true;
-        c->is_64 = false;
-        return;
-    }
-
-    /* Find the TCG condition for the mask + cc op.  */
-    switch (old_cc_op) {
-    case CC_OP_LTGT0_32:
-    case CC_OP_LTGT0_64:
-    case CC_OP_LTGT_32:
-    case CC_OP_LTGT_64:
-        cond = ltgt_cond[mask];
-        if (cond == TCG_COND_NEVER) {
-            goto do_dynamic;
-        }
-        account_inline_branch(s, old_cc_op);
-        break;
-
-    case CC_OP_LTUGTU_32:
-    case CC_OP_LTUGTU_64:
-        cond = tcg_unsigned_cond(ltgt_cond[mask]);
-        if (cond == TCG_COND_NEVER) {
-            goto do_dynamic;
-        }
-        account_inline_branch(s, old_cc_op);
-        break;
-
-    case CC_OP_NZ:
-        cond = nz_cond[mask];
-        if (cond == TCG_COND_NEVER) {
-            goto do_dynamic;
-        }
-        account_inline_branch(s, old_cc_op);
-        break;
-
-    case CC_OP_TM_32:
-    case CC_OP_TM_64:
-        switch (mask) {
-        case 8:
-            cond = TCG_COND_EQ;
-            break;
-        case 4 | 2 | 1:
-            cond = TCG_COND_NE;
-            break;
-        default:
-            goto do_dynamic;
-        }
-        account_inline_branch(s, old_cc_op);
-        break;
-
-    case CC_OP_ICM:
-        switch (mask) {
-        case 8:
-            cond = TCG_COND_EQ;
-            break;
-        case 4 | 2 | 1:
-        case 4 | 2:
-            cond = TCG_COND_NE;
-            break;
-        default:
-            goto do_dynamic;
-        }
-        account_inline_branch(s, old_cc_op);
-        break;
-
-    case CC_OP_FLOGR:
-        switch (mask & 0xa) {
-        case 8: /* src == 0 -> no one bit found */
-            cond = TCG_COND_EQ;
-            break;
-        case 2: /* src != 0 -> one bit found */
-            cond = TCG_COND_NE;
-            break;
-        default:
-            goto do_dynamic;
-        }
-        account_inline_branch(s, old_cc_op);
-        break;
-
-    case CC_OP_ADDU:
-    case CC_OP_SUBU:
-        switch (mask) {
-        case 8 | 2: /* result == 0 */
-            cond = TCG_COND_EQ;
-            break;
-        case 4 | 1: /* result != 0 */
-            cond = TCG_COND_NE;
-            break;
-        case 8 | 4: /* !carry (borrow) */
-            cond = old_cc_op == CC_OP_ADDU ? TCG_COND_EQ : TCG_COND_NE;
-            break;
-        case 2 | 1: /* carry (!borrow) */
-            cond = old_cc_op == CC_OP_ADDU ? TCG_COND_NE : TCG_COND_EQ;
-            break;
-        default:
-            goto do_dynamic;
-        }
-        account_inline_branch(s, old_cc_op);
-        break;
-
-    default:
-    do_dynamic:
-        /* Calculate cc value.  */
-        gen_op_calc_cc(s);
-        /* FALLTHRU */
-
-    case CC_OP_STATIC:
-        /* Jump based on CC.  We'll load up the real cond below;
-           the assignment here merely avoids a compiler warning.  */
-        account_noninline_branch(s, old_cc_op);
-        old_cc_op = CC_OP_STATIC;
-        cond = TCG_COND_NEVER;
-        break;
-    }
-
-    /* Load up the arguments of the comparison.  */
-    c->is_64 = true;
-    c->g1 = c->g2 = false;
-    switch (old_cc_op) {
-    case CC_OP_LTGT0_32:
-        c->is_64 = false;
-        c->u.s32.a = tcg_temp_new_i32();
-        tcg_gen_extrl_i64_i32(c->u.s32.a, cc_dst);
-        c->u.s32.b = tcg_const_i32(0);
-        break;
-    case CC_OP_LTGT_32:
-    case CC_OP_LTUGTU_32:
-        c->is_64 = false;
-        c->u.s32.a = tcg_temp_new_i32();
-        tcg_gen_extrl_i64_i32(c->u.s32.a, cc_src);
-        c->u.s32.b = tcg_temp_new_i32();
-        tcg_gen_extrl_i64_i32(c->u.s32.b, cc_dst);
-        break;
-
-    case CC_OP_LTGT0_64:
-    case CC_OP_NZ:
-    case CC_OP_FLOGR:
-        c->u.s64.a = cc_dst;
-        c->u.s64.b = tcg_const_i64(0);
-        c->g1 = true;
-        break;
-    case CC_OP_LTGT_64:
-    case CC_OP_LTUGTU_64:
-        c->u.s64.a = cc_src;
-        c->u.s64.b = cc_dst;
-        c->g1 = c->g2 = true;
-        break;
-
-    case CC_OP_TM_32:
-    case CC_OP_TM_64:
-    case CC_OP_ICM:
-        c->u.s64.a = tcg_temp_new_i64();
-        c->u.s64.b = tcg_const_i64(0);
-        tcg_gen_and_i64(c->u.s64.a, cc_src, cc_dst);
-        break;
-
-    case CC_OP_ADDU:
-    case CC_OP_SUBU:
-        c->is_64 = true;
-        c->u.s64.b = tcg_const_i64(0);
-        c->g1 = true;
-        switch (mask) {
-        case 8 | 2:
-        case 4 | 1: /* result */
-            c->u.s64.a = cc_dst;
-            break;
-        case 8 | 4:
-        case 2 | 1: /* carry */
-            c->u.s64.a = cc_src;
-            break;
-        default:
-            g_assert_not_reached();
-        }
-        break;
-
-    case CC_OP_STATIC:
-        c->is_64 = false;
-        c->u.s32.a = cc_op;
-        c->g1 = true;
-        switch (mask) {
-        case 0x8 | 0x4 | 0x2: /* cc != 3 */
-            cond = TCG_COND_NE;
-            c->u.s32.b = tcg_const_i32(3);
-            break;
-        case 0x8 | 0x4 | 0x1: /* cc != 2 */
-            cond = TCG_COND_NE;
-            c->u.s32.b = tcg_const_i32(2);
-            break;
-        case 0x8 | 0x2 | 0x1: /* cc != 1 */
-            cond = TCG_COND_NE;
-            c->u.s32.b = tcg_const_i32(1);
-            break;
-        case 0x8 | 0x2: /* cc == 0 || cc == 2 => (cc & 1) == 0 */
-            cond = TCG_COND_EQ;
-            c->g1 = false;
-            c->u.s32.a = tcg_temp_new_i32();
-            c->u.s32.b = tcg_const_i32(0);
-            tcg_gen_andi_i32(c->u.s32.a, cc_op, 1);
-            break;
-        case 0x8 | 0x4: /* cc < 2 */
-            cond = TCG_COND_LTU;
-            c->u.s32.b = tcg_const_i32(2);
-            break;
-        case 0x8: /* cc == 0 */
-            cond = TCG_COND_EQ;
-            c->u.s32.b = tcg_const_i32(0);
-            break;
-        case 0x4 | 0x2 | 0x1: /* cc != 0 */
-            cond = TCG_COND_NE;
-            c->u.s32.b = tcg_const_i32(0);
-            break;
-        case 0x4 | 0x1: /* cc == 1 || cc == 3 => (cc & 1) != 0 */
-            cond = TCG_COND_NE;
-            c->g1 = false;
-            c->u.s32.a = tcg_temp_new_i32();
-            c->u.s32.b = tcg_const_i32(0);
-            tcg_gen_andi_i32(c->u.s32.a, cc_op, 1);
-            break;
-        case 0x4: /* cc == 1 */
-            cond = TCG_COND_EQ;
-            c->u.s32.b = tcg_const_i32(1);
-            break;
-        case 0x2 | 0x1: /* cc > 1 */
-            cond = TCG_COND_GTU;
-            c->u.s32.b = tcg_const_i32(1);
-            break;
-        case 0x2: /* cc == 2 */
-            cond = TCG_COND_EQ;
-            c->u.s32.b = tcg_const_i32(2);
-            break;
-        case 0x1: /* cc == 3 */
-            cond = TCG_COND_EQ;
-            c->u.s32.b = tcg_const_i32(3);
-            break;
-        default:
-            /* CC is masked by something else: (8 >> cc) & mask.  */
-            cond = TCG_COND_NE;
-            c->g1 = false;
-            c->u.s32.a = tcg_const_i32(8);
-            c->u.s32.b = tcg_const_i32(0);
-            tcg_gen_shr_i32(c->u.s32.a, c->u.s32.a, cc_op);
-            tcg_gen_andi_i32(c->u.s32.a, c->u.s32.a, mask);
-            break;
-        }
-        break;
-
-    default:
-        abort();
-    }
-    c->cond = cond;
-}
-
-static void free_compare(DisasCompare *c)
-{
-    if (!c->g1) {
-        if (c->is_64) {
-            tcg_temp_free_i64(c->u.s64.a);
-        } else {
-            tcg_temp_free_i32(c->u.s32.a);
-        }
-    }
-    if (!c->g2) {
-        if (c->is_64) {
-            tcg_temp_free_i64(c->u.s64.b);
-        } else {
-            tcg_temp_free_i32(c->u.s32.b);
-        }
-    }
-}
-
-/* ====================================================================== */
-/* Define the insn format enumeration.  */
-#define F0(N)                         FMT_##N,
-#define F1(N, X1)                     F0(N)
-#define F2(N, X1, X2)                 F0(N)
-#define F3(N, X1, X2, X3)             F0(N)
-#define F4(N, X1, X2, X3, X4)         F0(N)
-#define F5(N, X1, X2, X3, X4, X5)     F0(N)
-#define F6(N, X1, X2, X3, X4, X5, X6) F0(N)
-
-typedef enum {
-#include "insn-format.def"
-} DisasFormat;
-
-#undef F0
-#undef F1
-#undef F2
-#undef F3
-#undef F4
-#undef F5
-#undef F6
-
-/* This is the way fields are to be accessed out of DisasFields.  */
-#define have_field(S, F)  have_field1((S), FLD_O_##F)
-#define get_field(S, F)   get_field1((S), FLD_O_##F, FLD_C_##F)
-
-static bool have_field1(const DisasContext *s, enum DisasFieldIndexO c)
-{
-    return (s->fields.presentO >> c) & 1;
-}
-
-static int get_field1(const DisasContext *s, enum DisasFieldIndexO o,
-                      enum DisasFieldIndexC c)
-{
-    assert(have_field1(s, o));
-    return s->fields.c[c];
-}
-
-/* Describe the layout of each field in each format.  */
-typedef struct DisasField {
-    unsigned int beg:8;
-    unsigned int size:8;
-    unsigned int type:2;
-    unsigned int indexC:6;
-    enum DisasFieldIndexO indexO:8;
-} DisasField;
-
-typedef struct DisasFormatInfo {
-    DisasField op[NUM_C_FIELD];
-} DisasFormatInfo;
-
-#define R(N, B)       {  B,  4, 0, FLD_C_r##N, FLD_O_r##N }
-#define M(N, B)       {  B,  4, 0, FLD_C_m##N, FLD_O_m##N }
-#define V(N, B)       {  B,  4, 3, FLD_C_v##N, FLD_O_v##N }
-#define BD(N, BB, BD) { BB,  4, 0, FLD_C_b##N, FLD_O_b##N }, \
-                      { BD, 12, 0, FLD_C_d##N, FLD_O_d##N }
-#define BXD(N)        { 16,  4, 0, FLD_C_b##N, FLD_O_b##N }, \
-                      { 12,  4, 0, FLD_C_x##N, FLD_O_x##N }, \
-                      { 20, 12, 0, FLD_C_d##N, FLD_O_d##N }
-#define BDL(N)        { 16,  4, 0, FLD_C_b##N, FLD_O_b##N }, \
-                      { 20, 20, 2, FLD_C_d##N, FLD_O_d##N }
-#define BXDL(N)       { 16,  4, 0, FLD_C_b##N, FLD_O_b##N }, \
-                      { 12,  4, 0, FLD_C_x##N, FLD_O_x##N }, \
-                      { 20, 20, 2, FLD_C_d##N, FLD_O_d##N }
-#define I(N, B, S)    {  B,  S, 1, FLD_C_i##N, FLD_O_i##N }
-#define L(N, B, S)    {  B,  S, 0, FLD_C_l##N, FLD_O_l##N }
-
-#define F0(N)                     { { } },
-#define F1(N, X1)                 { { X1 } },
-#define F2(N, X1, X2)             { { X1, X2 } },
-#define F3(N, X1, X2, X3)         { { X1, X2, X3 } },
-#define F4(N, X1, X2, X3, X4)     { { X1, X2, X3, X4 } },
-#define F5(N, X1, X2, X3, X4, X5) { { X1, X2, X3, X4, X5 } },
-#define F6(N, X1, X2, X3, X4, X5, X6)       { { X1, X2, X3, X4, X5, X6 } },
-
-static const DisasFormatInfo format_info[] = {
-#include "insn-format.def"
-};
-
-#undef F0
-#undef F1
-#undef F2
-#undef F3
-#undef F4
-#undef F5
-#undef F6
-#undef R
-#undef M
-#undef V
-#undef BD
-#undef BXD
-#undef BDL
-#undef BXDL
-#undef I
-#undef L
-
-/* Generally, we'll extract operands into this structures, operate upon
-   them, and store them back.  See the "in1", "in2", "prep", "wout" sets
-   of routines below for more details.  */
-typedef struct {
-    bool g_out, g_out2, g_in1, g_in2;
-    TCGv_i64 out, out2, in1, in2;
-    TCGv_i64 addr1;
-} DisasOps;
-
-/* Instructions can place constraints on their operands, raising specification
-   exceptions if they are violated.  To make this easy to automate, each "in1",
-   "in2", "prep", "wout" helper will have a SPEC_<name> define that equals one
-   of the following, or 0.  To make this easy to document, we'll put the
-   SPEC_<name> defines next to <name>.  */
-
-#define SPEC_r1_even    1
-#define SPEC_r2_even    2
-#define SPEC_r3_even    4
-#define SPEC_r1_f128    8
-#define SPEC_r2_f128    16
-
-/* Return values from translate_one, indicating the state of the TB.  */
-
-/* We are not using a goto_tb (for whatever reason), but have updated
-   the PC (for whatever reason), so there's no need to do it again on
-   exiting the TB.  */
-#define DISAS_PC_UPDATED        DISAS_TARGET_0
-
-/* We have emitted one or more goto_tb.  No fixup required.  */
-#define DISAS_GOTO_TB           DISAS_TARGET_1
-
-/* We have updated the PC and CC values.  */
-#define DISAS_PC_CC_UPDATED     DISAS_TARGET_2
-
-/* We are exiting the TB, but have neither emitted a goto_tb, nor
-   updated the PC for the next instruction to be executed.  */
-#define DISAS_PC_STALE          DISAS_TARGET_3
-
-/* We are exiting the TB to the main loop.  */
-#define DISAS_PC_STALE_NOCHAIN  DISAS_TARGET_4
-
-
-/* Instruction flags */
-#define IF_AFP1     0x0001      /* r1 is a fp reg for HFP/FPS instructions */
-#define IF_AFP2     0x0002      /* r2 is a fp reg for HFP/FPS instructions */
-#define IF_AFP3     0x0004      /* r3 is a fp reg for HFP/FPS instructions */
-#define IF_BFP      0x0008      /* binary floating point instruction */
-#define IF_DFP      0x0010      /* decimal floating point instruction */
-#define IF_PRIV     0x0020      /* privileged instruction */
-#define IF_VEC      0x0040      /* vector instruction */
-#define IF_IO       0x0080      /* input/output instruction */
-
-struct DisasInsn {
-    unsigned opc:16;
-    unsigned flags:16;
-    DisasFormat fmt:8;
-    unsigned fac:8;
-    unsigned spec:8;
-
-    const char *name;
-
-    /* Pre-process arguments before HELP_OP.  */
-    void (*help_in1)(DisasContext *, DisasOps *);
-    void (*help_in2)(DisasContext *, DisasOps *);
-    void (*help_prep)(DisasContext *, DisasOps *);
-
-    /*
-     * Post-process output after HELP_OP.
-     * Note that these are not called if HELP_OP returns DISAS_NORETURN.
-     */
-    void (*help_wout)(DisasContext *, DisasOps *);
-    void (*help_cout)(DisasContext *, DisasOps *);
-
-    /* Implement the operation itself.  */
-    DisasJumpType (*help_op)(DisasContext *, DisasOps *);
-
-    uint64_t data;
-};
-
-/* ====================================================================== */
-/* Miscellaneous helpers, used by several operations.  */
-
-static void help_l2_shift(DisasContext *s, DisasOps *o, int mask)
-{
-    int b2 = get_field(s, b2);
-    int d2 = get_field(s, d2);
-
-    if (b2 == 0) {
-        o->in2 = tcg_const_i64(d2 & mask);
-    } else {
-        o->in2 = get_address(s, 0, b2, d2);
-        tcg_gen_andi_i64(o->in2, o->in2, mask);
-    }
-}
-
-static DisasJumpType help_goto_direct(DisasContext *s, uint64_t dest)
-{
-    if (dest == s->pc_tmp) {
-        per_branch(s, true);
-        return DISAS_NEXT;
-    }
-    if (use_goto_tb(s, dest)) {
-        update_cc_op(s);
-        per_breaking_event(s);
-        tcg_gen_goto_tb(0);
-        tcg_gen_movi_i64(psw_addr, dest);
-        tcg_gen_exit_tb(s->base.tb, 0);
-        return DISAS_GOTO_TB;
-    } else {
-        tcg_gen_movi_i64(psw_addr, dest);
-        per_branch(s, false);
-        return DISAS_PC_UPDATED;
-    }
-}
-
-static DisasJumpType help_branch(DisasContext *s, DisasCompare *c,
-                                 bool is_imm, int imm, TCGv_i64 cdest)
-{
-    DisasJumpType ret;
-    uint64_t dest = s->base.pc_next + 2 * imm;
-    TCGLabel *lab;
-
-    /* Take care of the special cases first.  */
-    if (c->cond == TCG_COND_NEVER) {
-        ret = DISAS_NEXT;
-        goto egress;
-    }
-    if (is_imm) {
-        if (dest == s->pc_tmp) {
-            /* Branch to next.  */
-            per_branch(s, true);
-            ret = DISAS_NEXT;
-            goto egress;
-        }
-        if (c->cond == TCG_COND_ALWAYS) {
-            ret = help_goto_direct(s, dest);
-            goto egress;
-        }
-    } else {
-        if (!cdest) {
-            /* E.g. bcr %r0 -> no branch.  */
-            ret = DISAS_NEXT;
-            goto egress;
-        }
-        if (c->cond == TCG_COND_ALWAYS) {
-            tcg_gen_mov_i64(psw_addr, cdest);
-            per_branch(s, false);
-            ret = DISAS_PC_UPDATED;
-            goto egress;
-        }
-    }
-
-    if (use_goto_tb(s, s->pc_tmp)) {
-        if (is_imm && use_goto_tb(s, dest)) {
-            /* Both exits can use goto_tb.  */
-            update_cc_op(s);
-
-            lab = gen_new_label();
-            if (c->is_64) {
-                tcg_gen_brcond_i64(c->cond, c->u.s64.a, c->u.s64.b, lab);
-            } else {
-                tcg_gen_brcond_i32(c->cond, c->u.s32.a, c->u.s32.b, lab);
-            }
-
-            /* Branch not taken.  */
-            tcg_gen_goto_tb(0);
-            tcg_gen_movi_i64(psw_addr, s->pc_tmp);
-            tcg_gen_exit_tb(s->base.tb, 0);
-
-            /* Branch taken.  */
-            gen_set_label(lab);
-            per_breaking_event(s);
-            tcg_gen_goto_tb(1);
-            tcg_gen_movi_i64(psw_addr, dest);
-            tcg_gen_exit_tb(s->base.tb, 1);
-
-            ret = DISAS_GOTO_TB;
-        } else {
-            /* Fallthru can use goto_tb, but taken branch cannot.  */
-            /* Store taken branch destination before the brcond.  This
-               avoids having to allocate a new local temp to hold it.
-               We'll overwrite this in the not taken case anyway.  */
-            if (!is_imm) {
-                tcg_gen_mov_i64(psw_addr, cdest);
-            }
-
-            lab = gen_new_label();
-            if (c->is_64) {
-                tcg_gen_brcond_i64(c->cond, c->u.s64.a, c->u.s64.b, lab);
-            } else {
-                tcg_gen_brcond_i32(c->cond, c->u.s32.a, c->u.s32.b, lab);
-            }
-
-            /* Branch not taken.  */
-            update_cc_op(s);
-            tcg_gen_goto_tb(0);
-            tcg_gen_movi_i64(psw_addr, s->pc_tmp);
-            tcg_gen_exit_tb(s->base.tb, 0);
-
-            gen_set_label(lab);
-            if (is_imm) {
-                tcg_gen_movi_i64(psw_addr, dest);
-            }
-            per_breaking_event(s);
-            ret = DISAS_PC_UPDATED;
-        }
-    } else {
-        /* Fallthru cannot use goto_tb.  This by itself is vanishingly rare.
-           Most commonly we're single-stepping or some other condition that
-           disables all use of goto_tb.  Just update the PC and exit.  */
-
-        TCGv_i64 next = tcg_const_i64(s->pc_tmp);
-        if (is_imm) {
-            cdest = tcg_const_i64(dest);
-        }
-
-        if (c->is_64) {
-            tcg_gen_movcond_i64(c->cond, psw_addr, c->u.s64.a, c->u.s64.b,
-                                cdest, next);
-            per_branch_cond(s, c->cond, c->u.s64.a, c->u.s64.b);
-        } else {
-            TCGv_i32 t0 = tcg_temp_new_i32();
-            TCGv_i64 t1 = tcg_temp_new_i64();
-            TCGv_i64 z = tcg_const_i64(0);
-            tcg_gen_setcond_i32(c->cond, t0, c->u.s32.a, c->u.s32.b);
-            tcg_gen_extu_i32_i64(t1, t0);
-            tcg_temp_free_i32(t0);
-            tcg_gen_movcond_i64(TCG_COND_NE, psw_addr, t1, z, cdest, next);
-            per_branch_cond(s, TCG_COND_NE, t1, z);
-            tcg_temp_free_i64(t1);
-            tcg_temp_free_i64(z);
-        }
-
-        if (is_imm) {
-            tcg_temp_free_i64(cdest);
-        }
-        tcg_temp_free_i64(next);
-
-        ret = DISAS_PC_UPDATED;
-    }
-
- egress:
-    free_compare(c);
-    return ret;
-}
-
-/* ====================================================================== */
-/* The operations.  These perform the bulk of the work for any insn,
-   usually after the operands have been loaded and output initialized.  */
-
-static DisasJumpType op_abs(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_abs_i64(o->out, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_absf32(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_andi_i64(o->out, o->in2, 0x7fffffffull);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_absf64(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_andi_i64(o->out, o->in2, 0x7fffffffffffffffull);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_absf128(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_andi_i64(o->out, o->in1, 0x7fffffffffffffffull);
-    tcg_gen_mov_i64(o->out2, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_add(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_add_i64(o->out, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_addu64(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_movi_i64(cc_src, 0);
-    tcg_gen_add2_i64(o->out, cc_src, o->in1, cc_src, o->in2, cc_src);
-    return DISAS_NEXT;
-}
-
-/* Compute carry into cc_src. */
-static void compute_carry(DisasContext *s)
-{
-    switch (s->cc_op) {
-    case CC_OP_ADDU:
-        /* The carry value is already in cc_src (1,0). */
-        break;
-    case CC_OP_SUBU:
-        tcg_gen_addi_i64(cc_src, cc_src, 1);
-        break;
-    default:
-        gen_op_calc_cc(s);
-        /* fall through */
-    case CC_OP_STATIC:
-        /* The carry flag is the msb of CC; compute into cc_src. */
-        tcg_gen_extu_i32_i64(cc_src, cc_op);
-        tcg_gen_shri_i64(cc_src, cc_src, 1);
-        break;
-    }
-}
-
-static DisasJumpType op_addc32(DisasContext *s, DisasOps *o)
-{
-    compute_carry(s);
-    tcg_gen_add_i64(o->out, o->in1, o->in2);
-    tcg_gen_add_i64(o->out, o->out, cc_src);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_addc64(DisasContext *s, DisasOps *o)
-{
-    compute_carry(s);
-
-    TCGv_i64 zero = tcg_const_i64(0);
-    tcg_gen_add2_i64(o->out, cc_src, o->in1, zero, cc_src, zero);
-    tcg_gen_add2_i64(o->out, cc_src, o->out, cc_src, o->in2, zero);
-    tcg_temp_free_i64(zero);
-
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_asi(DisasContext *s, DisasOps *o)
-{
-    bool non_atomic = !s390_has_feat(S390_FEAT_STFLE_45);
-
-    o->in1 = tcg_temp_new_i64();
-    if (non_atomic) {
-        tcg_gen_qemu_ld_tl(o->in1, o->addr1, get_mem_index(s), s->insn->data);
-    } else {
-        /* Perform the atomic addition in memory. */
-        tcg_gen_atomic_fetch_add_i64(o->in1, o->addr1, o->in2, get_mem_index(s),
-                                     s->insn->data);
-    }
-
-    /* Recompute also for atomic case: needed for setting CC. */
-    tcg_gen_add_i64(o->out, o->in1, o->in2);
-
-    if (non_atomic) {
-        tcg_gen_qemu_st_tl(o->out, o->addr1, get_mem_index(s), s->insn->data);
-    }
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_asiu64(DisasContext *s, DisasOps *o)
-{
-    bool non_atomic = !s390_has_feat(S390_FEAT_STFLE_45);
-
-    o->in1 = tcg_temp_new_i64();
-    if (non_atomic) {
-        tcg_gen_qemu_ld_tl(o->in1, o->addr1, get_mem_index(s), s->insn->data);
-    } else {
-        /* Perform the atomic addition in memory. */
-        tcg_gen_atomic_fetch_add_i64(o->in1, o->addr1, o->in2, get_mem_index(s),
-                                     s->insn->data);
-    }
-
-    /* Recompute also for atomic case: needed for setting CC. */
-    tcg_gen_movi_i64(cc_src, 0);
-    tcg_gen_add2_i64(o->out, cc_src, o->in1, cc_src, o->in2, cc_src);
-
-    if (non_atomic) {
-        tcg_gen_qemu_st_tl(o->out, o->addr1, get_mem_index(s), s->insn->data);
-    }
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_aeb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_aeb(o->out, cpu_env, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_adb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_adb(o->out, cpu_env, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_axb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_axb(o->out, cpu_env, o->out, o->out2, o->in1, o->in2);
-    return_low128(o->out2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_and(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_and_i64(o->out, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_andi(DisasContext *s, DisasOps *o)
-{
-    int shift = s->insn->data & 0xff;
-    int size = s->insn->data >> 8;
-    uint64_t mask = ((1ull << size) - 1) << shift;
-
-    assert(!o->g_in2);
-    tcg_gen_shli_i64(o->in2, o->in2, shift);
-    tcg_gen_ori_i64(o->in2, o->in2, ~mask);
-    tcg_gen_and_i64(o->out, o->in1, o->in2);
-
-    /* Produce the CC from only the bits manipulated.  */
-    tcg_gen_andi_i64(cc_dst, o->out, mask);
-    set_cc_nz_u64(s, cc_dst);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_ni(DisasContext *s, DisasOps *o)
-{
-    o->in1 = tcg_temp_new_i64();
-
-    if (!s390_has_feat(S390_FEAT_INTERLOCKED_ACCESS_2)) {
-        tcg_gen_qemu_ld_tl(o->in1, o->addr1, get_mem_index(s), s->insn->data);
-    } else {
-        /* Perform the atomic operation in memory. */
-        tcg_gen_atomic_fetch_and_i64(o->in1, o->addr1, o->in2, get_mem_index(s),
-                                     s->insn->data);
-    }
-
-    /* Recompute also for atomic case: needed for setting CC. */
-    tcg_gen_and_i64(o->out, o->in1, o->in2);
-
-    if (!s390_has_feat(S390_FEAT_INTERLOCKED_ACCESS_2)) {
-        tcg_gen_qemu_st_tl(o->out, o->addr1, get_mem_index(s), s->insn->data);
-    }
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_bas(DisasContext *s, DisasOps *o)
-{
-    pc_to_link_info(o->out, s, s->pc_tmp);
-    if (o->in2) {
-        tcg_gen_mov_i64(psw_addr, o->in2);
-        per_branch(s, false);
-        return DISAS_PC_UPDATED;
-    } else {
-        return DISAS_NEXT;
-    }
-}
-
-static void save_link_info(DisasContext *s, DisasOps *o)
-{
-    TCGv_i64 t;
-
-    if (s->base.tb->flags & (FLAG_MASK_32 | FLAG_MASK_64)) {
-        pc_to_link_info(o->out, s, s->pc_tmp);
-        return;
-    }
-    gen_op_calc_cc(s);
-    tcg_gen_andi_i64(o->out, o->out, 0xffffffff00000000ull);
-    tcg_gen_ori_i64(o->out, o->out, ((s->ilen / 2) << 30) | s->pc_tmp);
-    t = tcg_temp_new_i64();
-    tcg_gen_shri_i64(t, psw_mask, 16);
-    tcg_gen_andi_i64(t, t, 0x0f000000);
-    tcg_gen_or_i64(o->out, o->out, t);
-    tcg_gen_extu_i32_i64(t, cc_op);
-    tcg_gen_shli_i64(t, t, 28);
-    tcg_gen_or_i64(o->out, o->out, t);
-    tcg_temp_free_i64(t);
-}
-
-static DisasJumpType op_bal(DisasContext *s, DisasOps *o)
-{
-    save_link_info(s, o);
-    if (o->in2) {
-        tcg_gen_mov_i64(psw_addr, o->in2);
-        per_branch(s, false);
-        return DISAS_PC_UPDATED;
-    } else {
-        return DISAS_NEXT;
-    }
-}
-
-static DisasJumpType op_basi(DisasContext *s, DisasOps *o)
-{
-    pc_to_link_info(o->out, s, s->pc_tmp);
-    return help_goto_direct(s, s->base.pc_next + 2 * get_field(s, i2));
-}
-
-static DisasJumpType op_bc(DisasContext *s, DisasOps *o)
-{
-    int m1 = get_field(s, m1);
-    bool is_imm = have_field(s, i2);
-    int imm = is_imm ? get_field(s, i2) : 0;
-    DisasCompare c;
-
-    /* BCR with R2 = 0 causes no branching */
-    if (have_field(s, r2) && get_field(s, r2) == 0) {
-        if (m1 == 14) {
-            /* Perform serialization */
-            /* FIXME: check for fast-BCR-serialization facility */
-            tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
-        }
-        if (m1 == 15) {
-            /* Perform serialization */
-            /* FIXME: perform checkpoint-synchronisation */
-            tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
-        }
-        return DISAS_NEXT;
-    }
-
-    disas_jcc(s, &c, m1);
-    return help_branch(s, &c, is_imm, imm, o->in2);
-}
-
-static DisasJumpType op_bct32(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    bool is_imm = have_field(s, i2);
-    int imm = is_imm ? get_field(s, i2) : 0;
-    DisasCompare c;
-    TCGv_i64 t;
-
-    c.cond = TCG_COND_NE;
-    c.is_64 = false;
-    c.g1 = false;
-    c.g2 = false;
-
-    t = tcg_temp_new_i64();
-    tcg_gen_subi_i64(t, regs[r1], 1);
-    store_reg32_i64(r1, t);
-    c.u.s32.a = tcg_temp_new_i32();
-    c.u.s32.b = tcg_const_i32(0);
-    tcg_gen_extrl_i64_i32(c.u.s32.a, t);
-    tcg_temp_free_i64(t);
-
-    return help_branch(s, &c, is_imm, imm, o->in2);
-}
-
-static DisasJumpType op_bcth(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    int imm = get_field(s, i2);
-    DisasCompare c;
-    TCGv_i64 t;
-
-    c.cond = TCG_COND_NE;
-    c.is_64 = false;
-    c.g1 = false;
-    c.g2 = false;
-
-    t = tcg_temp_new_i64();
-    tcg_gen_shri_i64(t, regs[r1], 32);
-    tcg_gen_subi_i64(t, t, 1);
-    store_reg32h_i64(r1, t);
-    c.u.s32.a = tcg_temp_new_i32();
-    c.u.s32.b = tcg_const_i32(0);
-    tcg_gen_extrl_i64_i32(c.u.s32.a, t);
-    tcg_temp_free_i64(t);
-
-    return help_branch(s, &c, 1, imm, o->in2);
-}
-
-static DisasJumpType op_bct64(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    bool is_imm = have_field(s, i2);
-    int imm = is_imm ? get_field(s, i2) : 0;
-    DisasCompare c;
-
-    c.cond = TCG_COND_NE;
-    c.is_64 = true;
-    c.g1 = true;
-    c.g2 = false;
-
-    tcg_gen_subi_i64(regs[r1], regs[r1], 1);
-    c.u.s64.a = regs[r1];
-    c.u.s64.b = tcg_const_i64(0);
-
-    return help_branch(s, &c, is_imm, imm, o->in2);
-}
-
-static DisasJumpType op_bx32(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    int r3 = get_field(s, r3);
-    bool is_imm = have_field(s, i2);
-    int imm = is_imm ? get_field(s, i2) : 0;
-    DisasCompare c;
-    TCGv_i64 t;
-
-    c.cond = (s->insn->data ? TCG_COND_LE : TCG_COND_GT);
-    c.is_64 = false;
-    c.g1 = false;
-    c.g2 = false;
-
-    t = tcg_temp_new_i64();
-    tcg_gen_add_i64(t, regs[r1], regs[r3]);
-    c.u.s32.a = tcg_temp_new_i32();
-    c.u.s32.b = tcg_temp_new_i32();
-    tcg_gen_extrl_i64_i32(c.u.s32.a, t);
-    tcg_gen_extrl_i64_i32(c.u.s32.b, regs[r3 | 1]);
-    store_reg32_i64(r1, t);
-    tcg_temp_free_i64(t);
-
-    return help_branch(s, &c, is_imm, imm, o->in2);
-}
-
-static DisasJumpType op_bx64(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    int r3 = get_field(s, r3);
-    bool is_imm = have_field(s, i2);
-    int imm = is_imm ? get_field(s, i2) : 0;
-    DisasCompare c;
-
-    c.cond = (s->insn->data ? TCG_COND_LE : TCG_COND_GT);
-    c.is_64 = true;
-
-    if (r1 == (r3 | 1)) {
-        c.u.s64.b = load_reg(r3 | 1);
-        c.g2 = false;
-    } else {
-        c.u.s64.b = regs[r3 | 1];
-        c.g2 = true;
-    }
-
-    tcg_gen_add_i64(regs[r1], regs[r1], regs[r3]);
-    c.u.s64.a = regs[r1];
-    c.g1 = true;
-
-    return help_branch(s, &c, is_imm, imm, o->in2);
-}
-
-static DisasJumpType op_cj(DisasContext *s, DisasOps *o)
-{
-    int imm, m3 = get_field(s, m3);
-    bool is_imm;
-    DisasCompare c;
-
-    c.cond = ltgt_cond[m3];
-    if (s->insn->data) {
-        c.cond = tcg_unsigned_cond(c.cond);
-    }
-    c.is_64 = c.g1 = c.g2 = true;
-    c.u.s64.a = o->in1;
-    c.u.s64.b = o->in2;
-
-    is_imm = have_field(s, i4);
-    if (is_imm) {
-        imm = get_field(s, i4);
-    } else {
-        imm = 0;
-        o->out = get_address(s, 0, get_field(s, b4),
-                             get_field(s, d4));
-    }
-
-    return help_branch(s, &c, is_imm, imm, o->out);
-}
-
-static DisasJumpType op_ceb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_ceb(cc_op, cpu_env, o->in1, o->in2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_cdb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_cdb(cc_op, cpu_env, o->in1, o->in2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_cxb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_cxb(cc_op, cpu_env, o->out, o->out2, o->in1, o->in2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static TCGv_i32 fpinst_extract_m34(DisasContext *s, bool m3_with_fpe,
-                                   bool m4_with_fpe)
-{
-    const bool fpe = s390_has_feat(S390_FEAT_FLOATING_POINT_EXT);
-    uint8_t m3 = get_field(s, m3);
-    uint8_t m4 = get_field(s, m4);
-
-    /* m3 field was introduced with FPE */
-    if (!fpe && m3_with_fpe) {
-        m3 = 0;
-    }
-    /* m4 field was introduced with FPE */
-    if (!fpe && m4_with_fpe) {
-        m4 = 0;
-    }
-
-    /* Check for valid rounding modes. Mode 3 was introduced later. */
-    if (m3 == 2 || m3 > 7 || (!fpe && m3 == 3)) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return NULL;
-    }
-
-    return tcg_const_i32(deposit32(m3, 4, 4, m4));
-}
-
-static DisasJumpType op_cfeb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m34 = fpinst_extract_m34(s, false, true);
-
-    if (!m34) {
-        return DISAS_NORETURN;
-    }
-    gen_helper_cfeb(o->out, cpu_env, o->in2, m34);
-    tcg_temp_free_i32(m34);
-    gen_set_cc_nz_f32(s, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_cfdb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m34 = fpinst_extract_m34(s, false, true);
-
-    if (!m34) {
-        return DISAS_NORETURN;
-    }
-    gen_helper_cfdb(o->out, cpu_env, o->in2, m34);
-    tcg_temp_free_i32(m34);
-    gen_set_cc_nz_f64(s, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_cfxb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m34 = fpinst_extract_m34(s, false, true);
-
-    if (!m34) {
-        return DISAS_NORETURN;
-    }
-    gen_helper_cfxb(o->out, cpu_env, o->in1, o->in2, m34);
-    tcg_temp_free_i32(m34);
-    gen_set_cc_nz_f128(s, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_cgeb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m34 = fpinst_extract_m34(s, false, true);
-
-    if (!m34) {
-        return DISAS_NORETURN;
-    }
-    gen_helper_cgeb(o->out, cpu_env, o->in2, m34);
-    tcg_temp_free_i32(m34);
-    gen_set_cc_nz_f32(s, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_cgdb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m34 = fpinst_extract_m34(s, false, true);
-
-    if (!m34) {
-        return DISAS_NORETURN;
-    }
-    gen_helper_cgdb(o->out, cpu_env, o->in2, m34);
-    tcg_temp_free_i32(m34);
-    gen_set_cc_nz_f64(s, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_cgxb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m34 = fpinst_extract_m34(s, false, true);
-
-    if (!m34) {
-        return DISAS_NORETURN;
-    }
-    gen_helper_cgxb(o->out, cpu_env, o->in1, o->in2, m34);
-    tcg_temp_free_i32(m34);
-    gen_set_cc_nz_f128(s, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_clfeb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m34 = fpinst_extract_m34(s, false, false);
-
-    if (!m34) {
-        return DISAS_NORETURN;
-    }
-    gen_helper_clfeb(o->out, cpu_env, o->in2, m34);
-    tcg_temp_free_i32(m34);
-    gen_set_cc_nz_f32(s, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_clfdb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m34 = fpinst_extract_m34(s, false, false);
-
-    if (!m34) {
-        return DISAS_NORETURN;
-    }
-    gen_helper_clfdb(o->out, cpu_env, o->in2, m34);
-    tcg_temp_free_i32(m34);
-    gen_set_cc_nz_f64(s, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_clfxb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m34 = fpinst_extract_m34(s, false, false);
-
-    if (!m34) {
-        return DISAS_NORETURN;
-    }
-    gen_helper_clfxb(o->out, cpu_env, o->in1, o->in2, m34);
-    tcg_temp_free_i32(m34);
-    gen_set_cc_nz_f128(s, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_clgeb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m34 = fpinst_extract_m34(s, false, false);
-
-    if (!m34) {
-        return DISAS_NORETURN;
-    }
-    gen_helper_clgeb(o->out, cpu_env, o->in2, m34);
-    tcg_temp_free_i32(m34);
-    gen_set_cc_nz_f32(s, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_clgdb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m34 = fpinst_extract_m34(s, false, false);
-
-    if (!m34) {
-        return DISAS_NORETURN;
-    }
-    gen_helper_clgdb(o->out, cpu_env, o->in2, m34);
-    tcg_temp_free_i32(m34);
-    gen_set_cc_nz_f64(s, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_clgxb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m34 = fpinst_extract_m34(s, false, false);
-
-    if (!m34) {
-        return DISAS_NORETURN;
-    }
-    gen_helper_clgxb(o->out, cpu_env, o->in1, o->in2, m34);
-    tcg_temp_free_i32(m34);
-    gen_set_cc_nz_f128(s, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_cegb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m34 = fpinst_extract_m34(s, true, true);
-
-    if (!m34) {
-        return DISAS_NORETURN;
-    }
-    gen_helper_cegb(o->out, cpu_env, o->in2, m34);
-    tcg_temp_free_i32(m34);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_cdgb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m34 = fpinst_extract_m34(s, true, true);
-
-    if (!m34) {
-        return DISAS_NORETURN;
-    }
-    gen_helper_cdgb(o->out, cpu_env, o->in2, m34);
-    tcg_temp_free_i32(m34);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_cxgb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m34 = fpinst_extract_m34(s, true, true);
-
-    if (!m34) {
-        return DISAS_NORETURN;
-    }
-    gen_helper_cxgb(o->out, cpu_env, o->in2, m34);
-    tcg_temp_free_i32(m34);
-    return_low128(o->out2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_celgb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m34 = fpinst_extract_m34(s, false, false);
-
-    if (!m34) {
-        return DISAS_NORETURN;
-    }
-    gen_helper_celgb(o->out, cpu_env, o->in2, m34);
-    tcg_temp_free_i32(m34);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_cdlgb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m34 = fpinst_extract_m34(s, false, false);
-
-    if (!m34) {
-        return DISAS_NORETURN;
-    }
-    gen_helper_cdlgb(o->out, cpu_env, o->in2, m34);
-    tcg_temp_free_i32(m34);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_cxlgb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m34 = fpinst_extract_m34(s, false, false);
-
-    if (!m34) {
-        return DISAS_NORETURN;
-    }
-    gen_helper_cxlgb(o->out, cpu_env, o->in2, m34);
-    tcg_temp_free_i32(m34);
-    return_low128(o->out2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_cksm(DisasContext *s, DisasOps *o)
-{
-    int r2 = get_field(s, r2);
-    TCGv_i64 len = tcg_temp_new_i64();
-
-    gen_helper_cksm(len, cpu_env, o->in1, o->in2, regs[r2 + 1]);
-    set_cc_static(s);
-    return_low128(o->out);
-
-    tcg_gen_add_i64(regs[r2], regs[r2], len);
-    tcg_gen_sub_i64(regs[r2 + 1], regs[r2 + 1], len);
-    tcg_temp_free_i64(len);
-
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_clc(DisasContext *s, DisasOps *o)
-{
-    int l = get_field(s, l1);
-    TCGv_i32 vl;
-
-    switch (l + 1) {
-    case 1:
-        tcg_gen_qemu_ld8u(cc_src, o->addr1, get_mem_index(s));
-        tcg_gen_qemu_ld8u(cc_dst, o->in2, get_mem_index(s));
-        break;
-    case 2:
-        tcg_gen_qemu_ld16u(cc_src, o->addr1, get_mem_index(s));
-        tcg_gen_qemu_ld16u(cc_dst, o->in2, get_mem_index(s));
-        break;
-    case 4:
-        tcg_gen_qemu_ld32u(cc_src, o->addr1, get_mem_index(s));
-        tcg_gen_qemu_ld32u(cc_dst, o->in2, get_mem_index(s));
-        break;
-    case 8:
-        tcg_gen_qemu_ld64(cc_src, o->addr1, get_mem_index(s));
-        tcg_gen_qemu_ld64(cc_dst, o->in2, get_mem_index(s));
-        break;
-    default:
-        vl = tcg_const_i32(l);
-        gen_helper_clc(cc_op, cpu_env, vl, o->addr1, o->in2);
-        tcg_temp_free_i32(vl);
-        set_cc_static(s);
-        return DISAS_NEXT;
-    }
-    gen_op_update2_cc_i64(s, CC_OP_LTUGTU_64, cc_src, cc_dst);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_clcl(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    int r2 = get_field(s, r2);
-    TCGv_i32 t1, t2;
-
-    /* r1 and r2 must be even.  */
-    if (r1 & 1 || r2 & 1) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    t1 = tcg_const_i32(r1);
-    t2 = tcg_const_i32(r2);
-    gen_helper_clcl(cc_op, cpu_env, t1, t2);
-    tcg_temp_free_i32(t1);
-    tcg_temp_free_i32(t2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_clcle(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    int r3 = get_field(s, r3);
-    TCGv_i32 t1, t3;
-
-    /* r1 and r3 must be even.  */
-    if (r1 & 1 || r3 & 1) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    t1 = tcg_const_i32(r1);
-    t3 = tcg_const_i32(r3);
-    gen_helper_clcle(cc_op, cpu_env, t1, o->in2, t3);
-    tcg_temp_free_i32(t1);
-    tcg_temp_free_i32(t3);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_clclu(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    int r3 = get_field(s, r3);
-    TCGv_i32 t1, t3;
-
-    /* r1 and r3 must be even.  */
-    if (r1 & 1 || r3 & 1) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    t1 = tcg_const_i32(r1);
-    t3 = tcg_const_i32(r3);
-    gen_helper_clclu(cc_op, cpu_env, t1, o->in2, t3);
-    tcg_temp_free_i32(t1);
-    tcg_temp_free_i32(t3);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_clm(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m3 = tcg_const_i32(get_field(s, m3));
-    TCGv_i32 t1 = tcg_temp_new_i32();
-    tcg_gen_extrl_i64_i32(t1, o->in1);
-    gen_helper_clm(cc_op, cpu_env, t1, m3, o->in2);
-    set_cc_static(s);
-    tcg_temp_free_i32(t1);
-    tcg_temp_free_i32(m3);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_clst(DisasContext *s, DisasOps *o)
-{
-    gen_helper_clst(o->in1, cpu_env, regs[0], o->in1, o->in2);
-    set_cc_static(s);
-    return_low128(o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_cps(DisasContext *s, DisasOps *o)
-{
-    TCGv_i64 t = tcg_temp_new_i64();
-    tcg_gen_andi_i64(t, o->in1, 0x8000000000000000ull);
-    tcg_gen_andi_i64(o->out, o->in2, 0x7fffffffffffffffull);
-    tcg_gen_or_i64(o->out, o->out, t);
-    tcg_temp_free_i64(t);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_cs(DisasContext *s, DisasOps *o)
-{
-    int d2 = get_field(s, d2);
-    int b2 = get_field(s, b2);
-    TCGv_i64 addr, cc;
-
-    /* Note that in1 = R3 (new value) and
-       in2 = (zero-extended) R1 (expected value).  */
-
-    addr = get_address(s, 0, b2, d2);
-    tcg_gen_atomic_cmpxchg_i64(o->out, addr, o->in2, o->in1,
-                               get_mem_index(s), s->insn->data | MO_ALIGN);
-    tcg_temp_free_i64(addr);
-
-    /* Are the memory and expected values (un)equal?  Note that this setcond
-       produces the output CC value, thus the NE sense of the test.  */
-    cc = tcg_temp_new_i64();
-    tcg_gen_setcond_i64(TCG_COND_NE, cc, o->in2, o->out);
-    tcg_gen_extrl_i64_i32(cc_op, cc);
-    tcg_temp_free_i64(cc);
-    set_cc_static(s);
-
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_cdsg(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    int r3 = get_field(s, r3);
-    int d2 = get_field(s, d2);
-    int b2 = get_field(s, b2);
-    DisasJumpType ret = DISAS_NEXT;
-    TCGv_i64 addr;
-    TCGv_i32 t_r1, t_r3;
-
-    /* Note that R1:R1+1 = expected value and R3:R3+1 = new value.  */
-    addr = get_address(s, 0, b2, d2);
-    t_r1 = tcg_const_i32(r1);
-    t_r3 = tcg_const_i32(r3);
-    if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
-        gen_helper_cdsg(cpu_env, addr, t_r1, t_r3);
-    } else if (HAVE_CMPXCHG128) {
-        gen_helper_cdsg_parallel(cpu_env, addr, t_r1, t_r3);
-    } else {
-        gen_helper_exit_atomic(cpu_env);
-        ret = DISAS_NORETURN;
-    }
-    tcg_temp_free_i64(addr);
-    tcg_temp_free_i32(t_r1);
-    tcg_temp_free_i32(t_r3);
-
-    set_cc_static(s);
-    return ret;
-}
-
-static DisasJumpType op_csst(DisasContext *s, DisasOps *o)
-{
-    int r3 = get_field(s, r3);
-    TCGv_i32 t_r3 = tcg_const_i32(r3);
-
-    if (tb_cflags(s->base.tb) & CF_PARALLEL) {
-        gen_helper_csst_parallel(cc_op, cpu_env, t_r3, o->addr1, o->in2);
-    } else {
-        gen_helper_csst(cc_op, cpu_env, t_r3, o->addr1, o->in2);
-    }
-    tcg_temp_free_i32(t_r3);
-
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-#ifndef CONFIG_USER_ONLY
-static DisasJumpType op_csp(DisasContext *s, DisasOps *o)
-{
-    MemOp mop = s->insn->data;
-    TCGv_i64 addr, old, cc;
-    TCGLabel *lab = gen_new_label();
-
-    /* Note that in1 = R1 (zero-extended expected value),
-       out = R1 (original reg), out2 = R1+1 (new value).  */
-
-    addr = tcg_temp_new_i64();
-    old = tcg_temp_new_i64();
-    tcg_gen_andi_i64(addr, o->in2, -1ULL << (mop & MO_SIZE));
-    tcg_gen_atomic_cmpxchg_i64(old, addr, o->in1, o->out2,
-                               get_mem_index(s), mop | MO_ALIGN);
-    tcg_temp_free_i64(addr);
-
-    /* Are the memory and expected values (un)equal?  */
-    cc = tcg_temp_new_i64();
-    tcg_gen_setcond_i64(TCG_COND_NE, cc, o->in1, old);
-    tcg_gen_extrl_i64_i32(cc_op, cc);
-
-    /* Write back the output now, so that it happens before the
-       following branch, so that we don't need local temps.  */
-    if ((mop & MO_SIZE) == MO_32) {
-        tcg_gen_deposit_i64(o->out, o->out, old, 0, 32);
-    } else {
-        tcg_gen_mov_i64(o->out, old);
-    }
-    tcg_temp_free_i64(old);
-
-    /* If the comparison was equal, and the LSB of R2 was set,
-       then we need to flush the TLB (for all cpus).  */
-    tcg_gen_xori_i64(cc, cc, 1);
-    tcg_gen_and_i64(cc, cc, o->in2);
-    tcg_gen_brcondi_i64(TCG_COND_EQ, cc, 0, lab);
-    tcg_temp_free_i64(cc);
-
-    gen_helper_purge(cpu_env);
-    gen_set_label(lab);
-
-    return DISAS_NEXT;
-}
-#endif
-
-static DisasJumpType op_cvd(DisasContext *s, DisasOps *o)
-{
-    TCGv_i64 t1 = tcg_temp_new_i64();
-    TCGv_i32 t2 = tcg_temp_new_i32();
-    tcg_gen_extrl_i64_i32(t2, o->in1);
-    gen_helper_cvd(t1, t2);
-    tcg_temp_free_i32(t2);
-    tcg_gen_qemu_st64(t1, o->in2, get_mem_index(s));
-    tcg_temp_free_i64(t1);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_ct(DisasContext *s, DisasOps *o)
-{
-    int m3 = get_field(s, m3);
-    TCGLabel *lab = gen_new_label();
-    TCGCond c;
-
-    c = tcg_invert_cond(ltgt_cond[m3]);
-    if (s->insn->data) {
-        c = tcg_unsigned_cond(c);
-    }
-    tcg_gen_brcond_i64(c, o->in1, o->in2, lab);
-
-    /* Trap.  */
-    gen_trap(s);
-
-    gen_set_label(lab);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_cuXX(DisasContext *s, DisasOps *o)
-{
-    int m3 = get_field(s, m3);
-    int r1 = get_field(s, r1);
-    int r2 = get_field(s, r2);
-    TCGv_i32 tr1, tr2, chk;
-
-    /* R1 and R2 must both be even.  */
-    if ((r1 | r2) & 1) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-    if (!s390_has_feat(S390_FEAT_ETF3_ENH)) {
-        m3 = 0;
-    }
-
-    tr1 = tcg_const_i32(r1);
-    tr2 = tcg_const_i32(r2);
-    chk = tcg_const_i32(m3);
-
-    switch (s->insn->data) {
-    case 12:
-        gen_helper_cu12(cc_op, cpu_env, tr1, tr2, chk);
-        break;
-    case 14:
-        gen_helper_cu14(cc_op, cpu_env, tr1, tr2, chk);
-        break;
-    case 21:
-        gen_helper_cu21(cc_op, cpu_env, tr1, tr2, chk);
-        break;
-    case 24:
-        gen_helper_cu24(cc_op, cpu_env, tr1, tr2, chk);
-        break;
-    case 41:
-        gen_helper_cu41(cc_op, cpu_env, tr1, tr2, chk);
-        break;
-    case 42:
-        gen_helper_cu42(cc_op, cpu_env, tr1, tr2, chk);
-        break;
-    default:
-        g_assert_not_reached();
-    }
-
-    tcg_temp_free_i32(tr1);
-    tcg_temp_free_i32(tr2);
-    tcg_temp_free_i32(chk);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-#ifndef CONFIG_USER_ONLY
-static DisasJumpType op_diag(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
-    TCGv_i32 r3 = tcg_const_i32(get_field(s, r3));
-    TCGv_i32 func_code = tcg_const_i32(get_field(s, i2));
-
-    gen_helper_diag(cpu_env, r1, r3, func_code);
-
-    tcg_temp_free_i32(func_code);
-    tcg_temp_free_i32(r3);
-    tcg_temp_free_i32(r1);
-    return DISAS_NEXT;
-}
-#endif
-
-static DisasJumpType op_divs32(DisasContext *s, DisasOps *o)
-{
-    gen_helper_divs32(o->out2, cpu_env, o->in1, o->in2);
-    return_low128(o->out);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_divu32(DisasContext *s, DisasOps *o)
-{
-    gen_helper_divu32(o->out2, cpu_env, o->in1, o->in2);
-    return_low128(o->out);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_divs64(DisasContext *s, DisasOps *o)
-{
-    gen_helper_divs64(o->out2, cpu_env, o->in1, o->in2);
-    return_low128(o->out);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_divu64(DisasContext *s, DisasOps *o)
-{
-    gen_helper_divu64(o->out2, cpu_env, o->out, o->out2, o->in2);
-    return_low128(o->out);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_deb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_deb(o->out, cpu_env, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_ddb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_ddb(o->out, cpu_env, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_dxb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_dxb(o->out, cpu_env, o->out, o->out2, o->in1, o->in2);
-    return_low128(o->out2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_ear(DisasContext *s, DisasOps *o)
-{
-    int r2 = get_field(s, r2);
-    tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, aregs[r2]));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_ecag(DisasContext *s, DisasOps *o)
-{
-    /* No cache information provided.  */
-    tcg_gen_movi_i64(o->out, -1);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_efpc(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, fpc));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_epsw(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    int r2 = get_field(s, r2);
-    TCGv_i64 t = tcg_temp_new_i64();
-
-    /* Note the "subsequently" in the PoO, which implies a defined result
-       if r1 == r2.  Thus we cannot defer these writes to an output hook.  */
-    tcg_gen_shri_i64(t, psw_mask, 32);
-    store_reg32_i64(r1, t);
-    if (r2 != 0) {
-        store_reg32_i64(r2, psw_mask);
-    }
-
-    tcg_temp_free_i64(t);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_ex(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    TCGv_i32 ilen;
-    TCGv_i64 v1;
-
-    /* Nested EXECUTE is not allowed.  */
-    if (unlikely(s->ex_value)) {
-        gen_program_exception(s, PGM_EXECUTE);
-        return DISAS_NORETURN;
-    }
-
-    update_psw_addr(s);
-    update_cc_op(s);
-
-    if (r1 == 0) {
-        v1 = tcg_const_i64(0);
-    } else {
-        v1 = regs[r1];
-    }
-
-    ilen = tcg_const_i32(s->ilen);
-    gen_helper_ex(cpu_env, ilen, v1, o->in2);
-    tcg_temp_free_i32(ilen);
-
-    if (r1 == 0) {
-        tcg_temp_free_i64(v1);
-    }
-
-    return DISAS_PC_CC_UPDATED;
-}
-
-static DisasJumpType op_fieb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m34 = fpinst_extract_m34(s, false, true);
-
-    if (!m34) {
-        return DISAS_NORETURN;
-    }
-    gen_helper_fieb(o->out, cpu_env, o->in2, m34);
-    tcg_temp_free_i32(m34);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_fidb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m34 = fpinst_extract_m34(s, false, true);
-
-    if (!m34) {
-        return DISAS_NORETURN;
-    }
-    gen_helper_fidb(o->out, cpu_env, o->in2, m34);
-    tcg_temp_free_i32(m34);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_fixb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m34 = fpinst_extract_m34(s, false, true);
-
-    if (!m34) {
-        return DISAS_NORETURN;
-    }
-    gen_helper_fixb(o->out, cpu_env, o->in1, o->in2, m34);
-    return_low128(o->out2);
-    tcg_temp_free_i32(m34);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_flogr(DisasContext *s, DisasOps *o)
-{
-    /* We'll use the original input for cc computation, since we get to
-       compare that against 0, which ought to be better than comparing
-       the real output against 64.  It also lets cc_dst be a convenient
-       temporary during our computation.  */
-    gen_op_update1_cc_i64(s, CC_OP_FLOGR, o->in2);
-
-    /* R1 = IN ? CLZ(IN) : 64.  */
-    tcg_gen_clzi_i64(o->out, o->in2, 64);
-
-    /* R1+1 = IN & ~(found bit).  Note that we may attempt to shift this
-       value by 64, which is undefined.  But since the shift is 64 iff the
-       input is zero, we still get the correct result after and'ing.  */
-    tcg_gen_movi_i64(o->out2, 0x8000000000000000ull);
-    tcg_gen_shr_i64(o->out2, o->out2, o->out);
-    tcg_gen_andc_i64(o->out2, cc_dst, o->out2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_icm(DisasContext *s, DisasOps *o)
-{
-    int m3 = get_field(s, m3);
-    int pos, len, base = s->insn->data;
-    TCGv_i64 tmp = tcg_temp_new_i64();
-    uint64_t ccm;
-
-    switch (m3) {
-    case 0xf:
-        /* Effectively a 32-bit load.  */
-        tcg_gen_qemu_ld32u(tmp, o->in2, get_mem_index(s));
-        len = 32;
-        goto one_insert;
-
-    case 0xc:
-    case 0x6:
-    case 0x3:
-        /* Effectively a 16-bit load.  */
-        tcg_gen_qemu_ld16u(tmp, o->in2, get_mem_index(s));
-        len = 16;
-        goto one_insert;
-
-    case 0x8:
-    case 0x4:
-    case 0x2:
-    case 0x1:
-        /* Effectively an 8-bit load.  */
-        tcg_gen_qemu_ld8u(tmp, o->in2, get_mem_index(s));
-        len = 8;
-        goto one_insert;
-
-    one_insert:
-        pos = base + ctz32(m3) * 8;
-        tcg_gen_deposit_i64(o->out, o->out, tmp, pos, len);
-        ccm = ((1ull << len) - 1) << pos;
-        break;
-
-    default:
-        /* This is going to be a sequence of loads and inserts.  */
-        pos = base + 32 - 8;
-        ccm = 0;
-        while (m3) {
-            if (m3 & 0x8) {
-                tcg_gen_qemu_ld8u(tmp, o->in2, get_mem_index(s));
-                tcg_gen_addi_i64(o->in2, o->in2, 1);
-                tcg_gen_deposit_i64(o->out, o->out, tmp, pos, 8);
-                ccm |= 0xff << pos;
-            }
-            m3 = (m3 << 1) & 0xf;
-            pos -= 8;
-        }
-        break;
-    }
-
-    tcg_gen_movi_i64(tmp, ccm);
-    gen_op_update2_cc_i64(s, CC_OP_ICM, tmp, o->out);
-    tcg_temp_free_i64(tmp);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_insi(DisasContext *s, DisasOps *o)
-{
-    int shift = s->insn->data & 0xff;
-    int size = s->insn->data >> 8;
-    tcg_gen_deposit_i64(o->out, o->in1, o->in2, shift, size);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_ipm(DisasContext *s, DisasOps *o)
-{
-    TCGv_i64 t1, t2;
-
-    gen_op_calc_cc(s);
-    t1 = tcg_temp_new_i64();
-    tcg_gen_extract_i64(t1, psw_mask, 40, 4);
-    t2 = tcg_temp_new_i64();
-    tcg_gen_extu_i32_i64(t2, cc_op);
-    tcg_gen_deposit_i64(t1, t1, t2, 4, 60);
-    tcg_gen_deposit_i64(o->out, o->out, t1, 24, 8);
-    tcg_temp_free_i64(t1);
-    tcg_temp_free_i64(t2);
-    return DISAS_NEXT;
-}
-
-#ifndef CONFIG_USER_ONLY
-static DisasJumpType op_idte(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m4;
-
-    if (s390_has_feat(S390_FEAT_LOCAL_TLB_CLEARING)) {
-        m4 = tcg_const_i32(get_field(s, m4));
-    } else {
-        m4 = tcg_const_i32(0);
-    }
-    gen_helper_idte(cpu_env, o->in1, o->in2, m4);
-    tcg_temp_free_i32(m4);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_ipte(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m4;
-
-    if (s390_has_feat(S390_FEAT_LOCAL_TLB_CLEARING)) {
-        m4 = tcg_const_i32(get_field(s, m4));
-    } else {
-        m4 = tcg_const_i32(0);
-    }
-    gen_helper_ipte(cpu_env, o->in1, o->in2, m4);
-    tcg_temp_free_i32(m4);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_iske(DisasContext *s, DisasOps *o)
-{
-    gen_helper_iske(o->out, cpu_env, o->in2);
-    return DISAS_NEXT;
-}
-#endif
-
-static DisasJumpType op_msa(DisasContext *s, DisasOps *o)
-{
-    int r1 = have_field(s, r1) ? get_field(s, r1) : 0;
-    int r2 = have_field(s, r2) ? get_field(s, r2) : 0;
-    int r3 = have_field(s, r3) ? get_field(s, r3) : 0;
-    TCGv_i32 t_r1, t_r2, t_r3, type;
-
-    switch (s->insn->data) {
-    case S390_FEAT_TYPE_KMA:
-        if (r3 == r1 || r3 == r2) {
-            gen_program_exception(s, PGM_SPECIFICATION);
-            return DISAS_NORETURN;
-        }
-        /* FALL THROUGH */
-    case S390_FEAT_TYPE_KMCTR:
-        if (r3 & 1 || !r3) {
-            gen_program_exception(s, PGM_SPECIFICATION);
-            return DISAS_NORETURN;
-        }
-        /* FALL THROUGH */
-    case S390_FEAT_TYPE_PPNO:
-    case S390_FEAT_TYPE_KMF:
-    case S390_FEAT_TYPE_KMC:
-    case S390_FEAT_TYPE_KMO:
-    case S390_FEAT_TYPE_KM:
-        if (r1 & 1 || !r1) {
-            gen_program_exception(s, PGM_SPECIFICATION);
-            return DISAS_NORETURN;
-        }
-        /* FALL THROUGH */
-    case S390_FEAT_TYPE_KMAC:
-    case S390_FEAT_TYPE_KIMD:
-    case S390_FEAT_TYPE_KLMD:
-        if (r2 & 1 || !r2) {
-            gen_program_exception(s, PGM_SPECIFICATION);
-            return DISAS_NORETURN;
-        }
-        /* FALL THROUGH */
-    case S390_FEAT_TYPE_PCKMO:
-    case S390_FEAT_TYPE_PCC:
-        break;
-    default:
-        g_assert_not_reached();
-    };
-
-    t_r1 = tcg_const_i32(r1);
-    t_r2 = tcg_const_i32(r2);
-    t_r3 = tcg_const_i32(r3);
-    type = tcg_const_i32(s->insn->data);
-    gen_helper_msa(cc_op, cpu_env, t_r1, t_r2, t_r3, type);
-    set_cc_static(s);
-    tcg_temp_free_i32(t_r1);
-    tcg_temp_free_i32(t_r2);
-    tcg_temp_free_i32(t_r3);
-    tcg_temp_free_i32(type);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_keb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_keb(cc_op, cpu_env, o->in1, o->in2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_kdb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_kdb(cc_op, cpu_env, o->in1, o->in2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_kxb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_kxb(cc_op, cpu_env, o->out, o->out2, o->in1, o->in2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_laa(DisasContext *s, DisasOps *o)
-{
-    /* The real output is indeed the original value in memory;
-       recompute the addition for the computation of CC.  */
-    tcg_gen_atomic_fetch_add_i64(o->in2, o->in2, o->in1, get_mem_index(s),
-                                 s->insn->data | MO_ALIGN);
-    /* However, we need to recompute the addition for setting CC.  */
-    tcg_gen_add_i64(o->out, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_lan(DisasContext *s, DisasOps *o)
-{
-    /* The real output is indeed the original value in memory;
-       recompute the addition for the computation of CC.  */
-    tcg_gen_atomic_fetch_and_i64(o->in2, o->in2, o->in1, get_mem_index(s),
-                                 s->insn->data | MO_ALIGN);
-    /* However, we need to recompute the operation for setting CC.  */
-    tcg_gen_and_i64(o->out, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_lao(DisasContext *s, DisasOps *o)
-{
-    /* The real output is indeed the original value in memory;
-       recompute the addition for the computation of CC.  */
-    tcg_gen_atomic_fetch_or_i64(o->in2, o->in2, o->in1, get_mem_index(s),
-                                s->insn->data | MO_ALIGN);
-    /* However, we need to recompute the operation for setting CC.  */
-    tcg_gen_or_i64(o->out, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_lax(DisasContext *s, DisasOps *o)
-{
-    /* The real output is indeed the original value in memory;
-       recompute the addition for the computation of CC.  */
-    tcg_gen_atomic_fetch_xor_i64(o->in2, o->in2, o->in1, get_mem_index(s),
-                                 s->insn->data | MO_ALIGN);
-    /* However, we need to recompute the operation for setting CC.  */
-    tcg_gen_xor_i64(o->out, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_ldeb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_ldeb(o->out, cpu_env, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_ledb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m34 = fpinst_extract_m34(s, true, true);
-
-    if (!m34) {
-        return DISAS_NORETURN;
-    }
-    gen_helper_ledb(o->out, cpu_env, o->in2, m34);
-    tcg_temp_free_i32(m34);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_ldxb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m34 = fpinst_extract_m34(s, true, true);
-
-    if (!m34) {
-        return DISAS_NORETURN;
-    }
-    gen_helper_ldxb(o->out, cpu_env, o->in1, o->in2, m34);
-    tcg_temp_free_i32(m34);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_lexb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 m34 = fpinst_extract_m34(s, true, true);
-
-    if (!m34) {
-        return DISAS_NORETURN;
-    }
-    gen_helper_lexb(o->out, cpu_env, o->in1, o->in2, m34);
-    tcg_temp_free_i32(m34);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_lxdb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_lxdb(o->out, cpu_env, o->in2);
-    return_low128(o->out2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_lxeb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_lxeb(o->out, cpu_env, o->in2);
-    return_low128(o->out2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_lde(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_shli_i64(o->out, o->in2, 32);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_llgt(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_andi_i64(o->out, o->in2, 0x7fffffff);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_ld8s(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_qemu_ld8s(o->out, o->in2, get_mem_index(s));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_ld8u(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_qemu_ld8u(o->out, o->in2, get_mem_index(s));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_ld16s(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_qemu_ld16s(o->out, o->in2, get_mem_index(s));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_ld16u(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_qemu_ld16u(o->out, o->in2, get_mem_index(s));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_ld32s(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_qemu_ld32s(o->out, o->in2, get_mem_index(s));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_ld32u(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_qemu_ld32u(o->out, o->in2, get_mem_index(s));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_ld64(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_qemu_ld64(o->out, o->in2, get_mem_index(s));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_lat(DisasContext *s, DisasOps *o)
-{
-    TCGLabel *lab = gen_new_label();
-    store_reg32_i64(get_field(s, r1), o->in2);
-    /* The value is stored even in case of trap. */
-    tcg_gen_brcondi_i64(TCG_COND_NE, o->in2, 0, lab);
-    gen_trap(s);
-    gen_set_label(lab);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_lgat(DisasContext *s, DisasOps *o)
-{
-    TCGLabel *lab = gen_new_label();
-    tcg_gen_qemu_ld64(o->out, o->in2, get_mem_index(s));
-    /* The value is stored even in case of trap. */
-    tcg_gen_brcondi_i64(TCG_COND_NE, o->out, 0, lab);
-    gen_trap(s);
-    gen_set_label(lab);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_lfhat(DisasContext *s, DisasOps *o)
-{
-    TCGLabel *lab = gen_new_label();
-    store_reg32h_i64(get_field(s, r1), o->in2);
-    /* The value is stored even in case of trap. */
-    tcg_gen_brcondi_i64(TCG_COND_NE, o->in2, 0, lab);
-    gen_trap(s);
-    gen_set_label(lab);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_llgfat(DisasContext *s, DisasOps *o)
-{
-    TCGLabel *lab = gen_new_label();
-    tcg_gen_qemu_ld32u(o->out, o->in2, get_mem_index(s));
-    /* The value is stored even in case of trap. */
-    tcg_gen_brcondi_i64(TCG_COND_NE, o->out, 0, lab);
-    gen_trap(s);
-    gen_set_label(lab);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_llgtat(DisasContext *s, DisasOps *o)
-{
-    TCGLabel *lab = gen_new_label();
-    tcg_gen_andi_i64(o->out, o->in2, 0x7fffffff);
-    /* The value is stored even in case of trap. */
-    tcg_gen_brcondi_i64(TCG_COND_NE, o->out, 0, lab);
-    gen_trap(s);
-    gen_set_label(lab);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_loc(DisasContext *s, DisasOps *o)
-{
-    DisasCompare c;
-
-    disas_jcc(s, &c, get_field(s, m3));
-
-    if (c.is_64) {
-        tcg_gen_movcond_i64(c.cond, o->out, c.u.s64.a, c.u.s64.b,
-                            o->in2, o->in1);
-        free_compare(&c);
-    } else {
-        TCGv_i32 t32 = tcg_temp_new_i32();
-        TCGv_i64 t, z;
-
-        tcg_gen_setcond_i32(c.cond, t32, c.u.s32.a, c.u.s32.b);
-        free_compare(&c);
-
-        t = tcg_temp_new_i64();
-        tcg_gen_extu_i32_i64(t, t32);
-        tcg_temp_free_i32(t32);
-
-        z = tcg_const_i64(0);
-        tcg_gen_movcond_i64(TCG_COND_NE, o->out, t, z, o->in2, o->in1);
-        tcg_temp_free_i64(t);
-        tcg_temp_free_i64(z);
-    }
-
-    return DISAS_NEXT;
-}
-
-#ifndef CONFIG_USER_ONLY
-static DisasJumpType op_lctl(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
-    TCGv_i32 r3 = tcg_const_i32(get_field(s, r3));
-    gen_helper_lctl(cpu_env, r1, o->in2, r3);
-    tcg_temp_free_i32(r1);
-    tcg_temp_free_i32(r3);
-    /* Exit to main loop to reevaluate s390_cpu_exec_interrupt.  */
-    return DISAS_PC_STALE_NOCHAIN;
-}
-
-static DisasJumpType op_lctlg(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
-    TCGv_i32 r3 = tcg_const_i32(get_field(s, r3));
-    gen_helper_lctlg(cpu_env, r1, o->in2, r3);
-    tcg_temp_free_i32(r1);
-    tcg_temp_free_i32(r3);
-    /* Exit to main loop to reevaluate s390_cpu_exec_interrupt.  */
-    return DISAS_PC_STALE_NOCHAIN;
-}
-
-static DisasJumpType op_lra(DisasContext *s, DisasOps *o)
-{
-    gen_helper_lra(o->out, cpu_env, o->in2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_lpp(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_st_i64(o->in2, cpu_env, offsetof(CPUS390XState, pp));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_lpsw(DisasContext *s, DisasOps *o)
-{
-    TCGv_i64 t1, t2;
-
-    per_breaking_event(s);
-
-    t1 = tcg_temp_new_i64();
-    t2 = tcg_temp_new_i64();
-    tcg_gen_qemu_ld_i64(t1, o->in2, get_mem_index(s),
-                        MO_TEUL | MO_ALIGN_8);
-    tcg_gen_addi_i64(o->in2, o->in2, 4);
-    tcg_gen_qemu_ld32u(t2, o->in2, get_mem_index(s));
-    /* Convert the 32-bit PSW_MASK into the 64-bit PSW_MASK.  */
-    tcg_gen_shli_i64(t1, t1, 32);
-    gen_helper_load_psw(cpu_env, t1, t2);
-    tcg_temp_free_i64(t1);
-    tcg_temp_free_i64(t2);
-    return DISAS_NORETURN;
-}
-
-static DisasJumpType op_lpswe(DisasContext *s, DisasOps *o)
-{
-    TCGv_i64 t1, t2;
-
-    per_breaking_event(s);
-
-    t1 = tcg_temp_new_i64();
-    t2 = tcg_temp_new_i64();
-    tcg_gen_qemu_ld_i64(t1, o->in2, get_mem_index(s),
-                        MO_TEQ | MO_ALIGN_8);
-    tcg_gen_addi_i64(o->in2, o->in2, 8);
-    tcg_gen_qemu_ld64(t2, o->in2, get_mem_index(s));
-    gen_helper_load_psw(cpu_env, t1, t2);
-    tcg_temp_free_i64(t1);
-    tcg_temp_free_i64(t2);
-    return DISAS_NORETURN;
-}
-#endif
-
-static DisasJumpType op_lam(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
-    TCGv_i32 r3 = tcg_const_i32(get_field(s, r3));
-    gen_helper_lam(cpu_env, r1, o->in2, r3);
-    tcg_temp_free_i32(r1);
-    tcg_temp_free_i32(r3);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_lm32(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    int r3 = get_field(s, r3);
-    TCGv_i64 t1, t2;
-
-    /* Only one register to read. */
-    t1 = tcg_temp_new_i64();
-    if (unlikely(r1 == r3)) {
-        tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s));
-        store_reg32_i64(r1, t1);
-        tcg_temp_free(t1);
-        return DISAS_NEXT;
-    }
-
-    /* First load the values of the first and last registers to trigger
-       possible page faults. */
-    t2 = tcg_temp_new_i64();
-    tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s));
-    tcg_gen_addi_i64(t2, o->in2, 4 * ((r3 - r1) & 15));
-    tcg_gen_qemu_ld32u(t2, t2, get_mem_index(s));
-    store_reg32_i64(r1, t1);
-    store_reg32_i64(r3, t2);
-
-    /* Only two registers to read. */
-    if (((r1 + 1) & 15) == r3) {
-        tcg_temp_free(t2);
-        tcg_temp_free(t1);
-        return DISAS_NEXT;
-    }
-
-    /* Then load the remaining registers. Page fault can't occur. */
-    r3 = (r3 - 1) & 15;
-    tcg_gen_movi_i64(t2, 4);
-    while (r1 != r3) {
-        r1 = (r1 + 1) & 15;
-        tcg_gen_add_i64(o->in2, o->in2, t2);
-        tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s));
-        store_reg32_i64(r1, t1);
-    }
-    tcg_temp_free(t2);
-    tcg_temp_free(t1);
-
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_lmh(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    int r3 = get_field(s, r3);
-    TCGv_i64 t1, t2;
-
-    /* Only one register to read. */
-    t1 = tcg_temp_new_i64();
-    if (unlikely(r1 == r3)) {
-        tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s));
-        store_reg32h_i64(r1, t1);
-        tcg_temp_free(t1);
-        return DISAS_NEXT;
-    }
-
-    /* First load the values of the first and last registers to trigger
-       possible page faults. */
-    t2 = tcg_temp_new_i64();
-    tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s));
-    tcg_gen_addi_i64(t2, o->in2, 4 * ((r3 - r1) & 15));
-    tcg_gen_qemu_ld32u(t2, t2, get_mem_index(s));
-    store_reg32h_i64(r1, t1);
-    store_reg32h_i64(r3, t2);
-
-    /* Only two registers to read. */
-    if (((r1 + 1) & 15) == r3) {
-        tcg_temp_free(t2);
-        tcg_temp_free(t1);
-        return DISAS_NEXT;
-    }
-
-    /* Then load the remaining registers. Page fault can't occur. */
-    r3 = (r3 - 1) & 15;
-    tcg_gen_movi_i64(t2, 4);
-    while (r1 != r3) {
-        r1 = (r1 + 1) & 15;
-        tcg_gen_add_i64(o->in2, o->in2, t2);
-        tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s));
-        store_reg32h_i64(r1, t1);
-    }
-    tcg_temp_free(t2);
-    tcg_temp_free(t1);
-
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_lm64(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    int r3 = get_field(s, r3);
-    TCGv_i64 t1, t2;
-
-    /* Only one register to read. */
-    if (unlikely(r1 == r3)) {
-        tcg_gen_qemu_ld64(regs[r1], o->in2, get_mem_index(s));
-        return DISAS_NEXT;
-    }
-
-    /* First load the values of the first and last registers to trigger
-       possible page faults. */
-    t1 = tcg_temp_new_i64();
-    t2 = tcg_temp_new_i64();
-    tcg_gen_qemu_ld64(t1, o->in2, get_mem_index(s));
-    tcg_gen_addi_i64(t2, o->in2, 8 * ((r3 - r1) & 15));
-    tcg_gen_qemu_ld64(regs[r3], t2, get_mem_index(s));
-    tcg_gen_mov_i64(regs[r1], t1);
-    tcg_temp_free(t2);
-
-    /* Only two registers to read. */
-    if (((r1 + 1) & 15) == r3) {
-        tcg_temp_free(t1);
-        return DISAS_NEXT;
-    }
-
-    /* Then load the remaining registers. Page fault can't occur. */
-    r3 = (r3 - 1) & 15;
-    tcg_gen_movi_i64(t1, 8);
-    while (r1 != r3) {
-        r1 = (r1 + 1) & 15;
-        tcg_gen_add_i64(o->in2, o->in2, t1);
-        tcg_gen_qemu_ld64(regs[r1], o->in2, get_mem_index(s));
-    }
-    tcg_temp_free(t1);
-
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_lpd(DisasContext *s, DisasOps *o)
-{
-    TCGv_i64 a1, a2;
-    MemOp mop = s->insn->data;
-
-    /* In a parallel context, stop the world and single step.  */
-    if (tb_cflags(s->base.tb) & CF_PARALLEL) {
-        update_psw_addr(s);
-        update_cc_op(s);
-        gen_exception(EXCP_ATOMIC);
-        return DISAS_NORETURN;
-    }
-
-    /* In a serial context, perform the two loads ... */
-    a1 = get_address(s, 0, get_field(s, b1), get_field(s, d1));
-    a2 = get_address(s, 0, get_field(s, b2), get_field(s, d2));
-    tcg_gen_qemu_ld_i64(o->out, a1, get_mem_index(s), mop | MO_ALIGN);
-    tcg_gen_qemu_ld_i64(o->out2, a2, get_mem_index(s), mop | MO_ALIGN);
-    tcg_temp_free_i64(a1);
-    tcg_temp_free_i64(a2);
-
-    /* ... and indicate that we performed them while interlocked.  */
-    gen_op_movi_cc(s, 0);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_lpq(DisasContext *s, DisasOps *o)
-{
-    if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
-        gen_helper_lpq(o->out, cpu_env, o->in2);
-    } else if (HAVE_ATOMIC128) {
-        gen_helper_lpq_parallel(o->out, cpu_env, o->in2);
-    } else {
-        gen_helper_exit_atomic(cpu_env);
-        return DISAS_NORETURN;
-    }
-    return_low128(o->out2);
-    return DISAS_NEXT;
-}
-
-#ifndef CONFIG_USER_ONLY
-static DisasJumpType op_lura(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_qemu_ld_tl(o->out, o->in2, MMU_REAL_IDX, s->insn->data);
-    return DISAS_NEXT;
-}
-#endif
-
-static DisasJumpType op_lzrb(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_andi_i64(o->out, o->in2, -256);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_lcbb(DisasContext *s, DisasOps *o)
-{
-    const int64_t block_size = (1ull << (get_field(s, m3) + 6));
-
-    if (get_field(s, m3) > 6) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    tcg_gen_ori_i64(o->addr1, o->addr1, -block_size);
-    tcg_gen_neg_i64(o->addr1, o->addr1);
-    tcg_gen_movi_i64(o->out, 16);
-    tcg_gen_umin_i64(o->out, o->out, o->addr1);
-    gen_op_update1_cc_i64(s, CC_OP_LCBB, o->out);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_mc(DisasContext *s, DisasOps *o)
-{
-#if !defined(CONFIG_USER_ONLY)
-    TCGv_i32 i2;
-#endif
-    const uint16_t monitor_class = get_field(s, i2);
-
-    if (monitor_class & 0xff00) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-#if !defined(CONFIG_USER_ONLY)
-    i2 = tcg_const_i32(monitor_class);
-    gen_helper_monitor_call(cpu_env, o->addr1, i2);
-    tcg_temp_free_i32(i2);
-#endif
-    /* Defaults to a NOP. */
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_mov2(DisasContext *s, DisasOps *o)
-{
-    o->out = o->in2;
-    o->g_out = o->g_in2;
-    o->in2 = NULL;
-    o->g_in2 = false;
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_mov2e(DisasContext *s, DisasOps *o)
-{
-    int b2 = get_field(s, b2);
-    TCGv ar1 = tcg_temp_new_i64();
-
-    o->out = o->in2;
-    o->g_out = o->g_in2;
-    o->in2 = NULL;
-    o->g_in2 = false;
-
-    switch (s->base.tb->flags & FLAG_MASK_ASC) {
-    case PSW_ASC_PRIMARY >> FLAG_MASK_PSW_SHIFT:
-        tcg_gen_movi_i64(ar1, 0);
-        break;
-    case PSW_ASC_ACCREG >> FLAG_MASK_PSW_SHIFT:
-        tcg_gen_movi_i64(ar1, 1);
-        break;
-    case PSW_ASC_SECONDARY >> FLAG_MASK_PSW_SHIFT:
-        if (b2) {
-            tcg_gen_ld32u_i64(ar1, cpu_env, offsetof(CPUS390XState, aregs[b2]));
-        } else {
-            tcg_gen_movi_i64(ar1, 0);
-        }
-        break;
-    case PSW_ASC_HOME >> FLAG_MASK_PSW_SHIFT:
-        tcg_gen_movi_i64(ar1, 2);
-        break;
-    }
-
-    tcg_gen_st32_i64(ar1, cpu_env, offsetof(CPUS390XState, aregs[1]));
-    tcg_temp_free_i64(ar1);
-
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_movx(DisasContext *s, DisasOps *o)
-{
-    o->out = o->in1;
-    o->out2 = o->in2;
-    o->g_out = o->g_in1;
-    o->g_out2 = o->g_in2;
-    o->in1 = NULL;
-    o->in2 = NULL;
-    o->g_in1 = o->g_in2 = false;
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_mvc(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 l = tcg_const_i32(get_field(s, l1));
-    gen_helper_mvc(cpu_env, l, o->addr1, o->in2);
-    tcg_temp_free_i32(l);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_mvcin(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 l = tcg_const_i32(get_field(s, l1));
-    gen_helper_mvcin(cpu_env, l, o->addr1, o->in2);
-    tcg_temp_free_i32(l);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_mvcl(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    int r2 = get_field(s, r2);
-    TCGv_i32 t1, t2;
-
-    /* r1 and r2 must be even.  */
-    if (r1 & 1 || r2 & 1) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    t1 = tcg_const_i32(r1);
-    t2 = tcg_const_i32(r2);
-    gen_helper_mvcl(cc_op, cpu_env, t1, t2);
-    tcg_temp_free_i32(t1);
-    tcg_temp_free_i32(t2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_mvcle(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    int r3 = get_field(s, r3);
-    TCGv_i32 t1, t3;
-
-    /* r1 and r3 must be even.  */
-    if (r1 & 1 || r3 & 1) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    t1 = tcg_const_i32(r1);
-    t3 = tcg_const_i32(r3);
-    gen_helper_mvcle(cc_op, cpu_env, t1, o->in2, t3);
-    tcg_temp_free_i32(t1);
-    tcg_temp_free_i32(t3);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_mvclu(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    int r3 = get_field(s, r3);
-    TCGv_i32 t1, t3;
-
-    /* r1 and r3 must be even.  */
-    if (r1 & 1 || r3 & 1) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    t1 = tcg_const_i32(r1);
-    t3 = tcg_const_i32(r3);
-    gen_helper_mvclu(cc_op, cpu_env, t1, o->in2, t3);
-    tcg_temp_free_i32(t1);
-    tcg_temp_free_i32(t3);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_mvcos(DisasContext *s, DisasOps *o)
-{
-    int r3 = get_field(s, r3);
-    gen_helper_mvcos(cc_op, cpu_env, o->addr1, o->in2, regs[r3]);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-#ifndef CONFIG_USER_ONLY
-static DisasJumpType op_mvcp(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, l1);
-    gen_helper_mvcp(cc_op, cpu_env, regs[r1], o->addr1, o->in2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_mvcs(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, l1);
-    gen_helper_mvcs(cc_op, cpu_env, regs[r1], o->addr1, o->in2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-#endif
-
-static DisasJumpType op_mvn(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 l = tcg_const_i32(get_field(s, l1));
-    gen_helper_mvn(cpu_env, l, o->addr1, o->in2);
-    tcg_temp_free_i32(l);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_mvo(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 l = tcg_const_i32(get_field(s, l1));
-    gen_helper_mvo(cpu_env, l, o->addr1, o->in2);
-    tcg_temp_free_i32(l);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_mvpg(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 t1 = tcg_const_i32(get_field(s, r1));
-    TCGv_i32 t2 = tcg_const_i32(get_field(s, r2));
-
-    gen_helper_mvpg(cc_op, cpu_env, regs[0], t1, t2);
-    tcg_temp_free_i32(t1);
-    tcg_temp_free_i32(t2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_mvst(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 t1 = tcg_const_i32(get_field(s, r1));
-    TCGv_i32 t2 = tcg_const_i32(get_field(s, r2));
-
-    gen_helper_mvst(cc_op, cpu_env, t1, t2);
-    tcg_temp_free_i32(t1);
-    tcg_temp_free_i32(t2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_mvz(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 l = tcg_const_i32(get_field(s, l1));
-    gen_helper_mvz(cpu_env, l, o->addr1, o->in2);
-    tcg_temp_free_i32(l);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_mul(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_mul_i64(o->out, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_mul128(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_mulu2_i64(o->out2, o->out, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_muls128(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_muls2_i64(o->out2, o->out, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_meeb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_meeb(o->out, cpu_env, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_mdeb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_mdeb(o->out, cpu_env, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_mdb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_mdb(o->out, cpu_env, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_mxb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_mxb(o->out, cpu_env, o->out, o->out2, o->in1, o->in2);
-    return_low128(o->out2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_mxdb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_mxdb(o->out, cpu_env, o->out, o->out2, o->in2);
-    return_low128(o->out2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_maeb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i64 r3 = load_freg32_i64(get_field(s, r3));
-    gen_helper_maeb(o->out, cpu_env, o->in1, o->in2, r3);
-    tcg_temp_free_i64(r3);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_madb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i64 r3 = load_freg(get_field(s, r3));
-    gen_helper_madb(o->out, cpu_env, o->in1, o->in2, r3);
-    tcg_temp_free_i64(r3);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_mseb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i64 r3 = load_freg32_i64(get_field(s, r3));
-    gen_helper_mseb(o->out, cpu_env, o->in1, o->in2, r3);
-    tcg_temp_free_i64(r3);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_msdb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i64 r3 = load_freg(get_field(s, r3));
-    gen_helper_msdb(o->out, cpu_env, o->in1, o->in2, r3);
-    tcg_temp_free_i64(r3);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_nabs(DisasContext *s, DisasOps *o)
-{
-    TCGv_i64 z, n;
-    z = tcg_const_i64(0);
-    n = tcg_temp_new_i64();
-    tcg_gen_neg_i64(n, o->in2);
-    tcg_gen_movcond_i64(TCG_COND_GE, o->out, o->in2, z, n, o->in2);
-    tcg_temp_free_i64(n);
-    tcg_temp_free_i64(z);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_nabsf32(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_ori_i64(o->out, o->in2, 0x80000000ull);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_nabsf64(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_ori_i64(o->out, o->in2, 0x8000000000000000ull);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_nabsf128(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_ori_i64(o->out, o->in1, 0x8000000000000000ull);
-    tcg_gen_mov_i64(o->out2, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_nc(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 l = tcg_const_i32(get_field(s, l1));
-    gen_helper_nc(cc_op, cpu_env, l, o->addr1, o->in2);
-    tcg_temp_free_i32(l);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_neg(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_neg_i64(o->out, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_negf32(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_xori_i64(o->out, o->in2, 0x80000000ull);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_negf64(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_xori_i64(o->out, o->in2, 0x8000000000000000ull);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_negf128(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_xori_i64(o->out, o->in1, 0x8000000000000000ull);
-    tcg_gen_mov_i64(o->out2, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_oc(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 l = tcg_const_i32(get_field(s, l1));
-    gen_helper_oc(cc_op, cpu_env, l, o->addr1, o->in2);
-    tcg_temp_free_i32(l);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_or(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_or_i64(o->out, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_ori(DisasContext *s, DisasOps *o)
-{
-    int shift = s->insn->data & 0xff;
-    int size = s->insn->data >> 8;
-    uint64_t mask = ((1ull << size) - 1) << shift;
-
-    assert(!o->g_in2);
-    tcg_gen_shli_i64(o->in2, o->in2, shift);
-    tcg_gen_or_i64(o->out, o->in1, o->in2);
-
-    /* Produce the CC from only the bits manipulated.  */
-    tcg_gen_andi_i64(cc_dst, o->out, mask);
-    set_cc_nz_u64(s, cc_dst);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_oi(DisasContext *s, DisasOps *o)
-{
-    o->in1 = tcg_temp_new_i64();
-
-    if (!s390_has_feat(S390_FEAT_INTERLOCKED_ACCESS_2)) {
-        tcg_gen_qemu_ld_tl(o->in1, o->addr1, get_mem_index(s), s->insn->data);
-    } else {
-        /* Perform the atomic operation in memory. */
-        tcg_gen_atomic_fetch_or_i64(o->in1, o->addr1, o->in2, get_mem_index(s),
-                                    s->insn->data);
-    }
-
-    /* Recompute also for atomic case: needed for setting CC. */
-    tcg_gen_or_i64(o->out, o->in1, o->in2);
-
-    if (!s390_has_feat(S390_FEAT_INTERLOCKED_ACCESS_2)) {
-        tcg_gen_qemu_st_tl(o->out, o->addr1, get_mem_index(s), s->insn->data);
-    }
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_pack(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 l = tcg_const_i32(get_field(s, l1));
-    gen_helper_pack(cpu_env, l, o->addr1, o->in2);
-    tcg_temp_free_i32(l);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_pka(DisasContext *s, DisasOps *o)
-{
-    int l2 = get_field(s, l2) + 1;
-    TCGv_i32 l;
-
-    /* The length must not exceed 32 bytes.  */
-    if (l2 > 32) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-    l = tcg_const_i32(l2);
-    gen_helper_pka(cpu_env, o->addr1, o->in2, l);
-    tcg_temp_free_i32(l);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_pku(DisasContext *s, DisasOps *o)
-{
-    int l2 = get_field(s, l2) + 1;
-    TCGv_i32 l;
-
-    /* The length must be even and should not exceed 64 bytes.  */
-    if ((l2 & 1) || (l2 > 64)) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-    l = tcg_const_i32(l2);
-    gen_helper_pku(cpu_env, o->addr1, o->in2, l);
-    tcg_temp_free_i32(l);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_popcnt(DisasContext *s, DisasOps *o)
-{
-    gen_helper_popcnt(o->out, o->in2);
-    return DISAS_NEXT;
-}
-
-#ifndef CONFIG_USER_ONLY
-static DisasJumpType op_ptlb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_ptlb(cpu_env);
-    return DISAS_NEXT;
-}
-#endif
-
-static DisasJumpType op_risbg(DisasContext *s, DisasOps *o)
-{
-    int i3 = get_field(s, i3);
-    int i4 = get_field(s, i4);
-    int i5 = get_field(s, i5);
-    int do_zero = i4 & 0x80;
-    uint64_t mask, imask, pmask;
-    int pos, len, rot;
-
-    /* Adjust the arguments for the specific insn.  */
-    switch (s->fields.op2) {
-    case 0x55: /* risbg */
-    case 0x59: /* risbgn */
-        i3 &= 63;
-        i4 &= 63;
-        pmask = ~0;
-        break;
-    case 0x5d: /* risbhg */
-        i3 &= 31;
-        i4 &= 31;
-        pmask = 0xffffffff00000000ull;
-        break;
-    case 0x51: /* risblg */
-        i3 = (i3 & 31) + 32;
-        i4 = (i4 & 31) + 32;
-        pmask = 0x00000000ffffffffull;
-        break;
-    default:
-        g_assert_not_reached();
-    }
-
-    /* MASK is the set of bits to be inserted from R2. */
-    if (i3 <= i4) {
-        /* [0...i3---i4...63] */
-        mask = (-1ull >> i3) & (-1ull << (63 - i4));
-    } else {
-        /* [0---i4...i3---63] */
-        mask = (-1ull >> i3) | (-1ull << (63 - i4));
-    }
-    /* For RISBLG/RISBHG, the wrapping is limited to the high/low doubleword. */
-    mask &= pmask;
-
-    /* IMASK is the set of bits to be kept from R1.  In the case of the high/low
-       insns, we need to keep the other half of the register.  */
-    imask = ~mask | ~pmask;
-    if (do_zero) {
-        imask = ~pmask;
-    }
-
-    len = i4 - i3 + 1;
-    pos = 63 - i4;
-    rot = i5 & 63;
-
-    /* In some cases we can implement this with extract.  */
-    if (imask == 0 && pos == 0 && len > 0 && len <= rot) {
-        tcg_gen_extract_i64(o->out, o->in2, 64 - rot, len);
-        return DISAS_NEXT;
-    }
-
-    /* In some cases we can implement this with deposit.  */
-    if (len > 0 && (imask == 0 || ~mask == imask)) {
-        /* Note that we rotate the bits to be inserted to the lsb, not to
-           the position as described in the PoO.  */
-        rot = (rot - pos) & 63;
-    } else {
-        pos = -1;
-    }
-
-    /* Rotate the input as necessary.  */
-    tcg_gen_rotli_i64(o->in2, o->in2, rot);
-
-    /* Insert the selected bits into the output.  */
-    if (pos >= 0) {
-        if (imask == 0) {
-            tcg_gen_deposit_z_i64(o->out, o->in2, pos, len);
-        } else {
-            tcg_gen_deposit_i64(o->out, o->out, o->in2, pos, len);
-        }
-    } else if (imask == 0) {
-        tcg_gen_andi_i64(o->out, o->in2, mask);
-    } else {
-        tcg_gen_andi_i64(o->in2, o->in2, mask);
-        tcg_gen_andi_i64(o->out, o->out, imask);
-        tcg_gen_or_i64(o->out, o->out, o->in2);
-    }
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_rosbg(DisasContext *s, DisasOps *o)
-{
-    int i3 = get_field(s, i3);
-    int i4 = get_field(s, i4);
-    int i5 = get_field(s, i5);
-    uint64_t mask;
-
-    /* If this is a test-only form, arrange to discard the result.  */
-    if (i3 & 0x80) {
-        o->out = tcg_temp_new_i64();
-        o->g_out = false;
-    }
-
-    i3 &= 63;
-    i4 &= 63;
-    i5 &= 63;
-
-    /* MASK is the set of bits to be operated on from R2.
-       Take care for I3/I4 wraparound.  */
-    mask = ~0ull >> i3;
-    if (i3 <= i4) {
-        mask ^= ~0ull >> i4 >> 1;
-    } else {
-        mask |= ~(~0ull >> i4 >> 1);
-    }
-
-    /* Rotate the input as necessary.  */
-    tcg_gen_rotli_i64(o->in2, o->in2, i5);
-
-    /* Operate.  */
-    switch (s->fields.op2) {
-    case 0x54: /* AND */
-        tcg_gen_ori_i64(o->in2, o->in2, ~mask);
-        tcg_gen_and_i64(o->out, o->out, o->in2);
-        break;
-    case 0x56: /* OR */
-        tcg_gen_andi_i64(o->in2, o->in2, mask);
-        tcg_gen_or_i64(o->out, o->out, o->in2);
-        break;
-    case 0x57: /* XOR */
-        tcg_gen_andi_i64(o->in2, o->in2, mask);
-        tcg_gen_xor_i64(o->out, o->out, o->in2);
-        break;
-    default:
-        abort();
-    }
-
-    /* Set the CC.  */
-    tcg_gen_andi_i64(cc_dst, o->out, mask);
-    set_cc_nz_u64(s, cc_dst);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_rev16(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_bswap16_i64(o->out, o->in2, TCG_BSWAP_IZ | TCG_BSWAP_OZ);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_rev32(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_bswap32_i64(o->out, o->in2, TCG_BSWAP_IZ | TCG_BSWAP_OZ);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_rev64(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_bswap64_i64(o->out, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_rll32(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 t1 = tcg_temp_new_i32();
-    TCGv_i32 t2 = tcg_temp_new_i32();
-    TCGv_i32 to = tcg_temp_new_i32();
-    tcg_gen_extrl_i64_i32(t1, o->in1);
-    tcg_gen_extrl_i64_i32(t2, o->in2);
-    tcg_gen_rotl_i32(to, t1, t2);
-    tcg_gen_extu_i32_i64(o->out, to);
-    tcg_temp_free_i32(t1);
-    tcg_temp_free_i32(t2);
-    tcg_temp_free_i32(to);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_rll64(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_rotl_i64(o->out, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-#ifndef CONFIG_USER_ONLY
-static DisasJumpType op_rrbe(DisasContext *s, DisasOps *o)
-{
-    gen_helper_rrbe(cc_op, cpu_env, o->in2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_sacf(DisasContext *s, DisasOps *o)
-{
-    gen_helper_sacf(cpu_env, o->in2);
-    /* Addressing mode has changed, so end the block.  */
-    return DISAS_PC_STALE;
-}
-#endif
-
-static DisasJumpType op_sam(DisasContext *s, DisasOps *o)
-{
-    int sam = s->insn->data;
-    TCGv_i64 tsam;
-    uint64_t mask;
-
-    switch (sam) {
-    case 0:
-        mask = 0xffffff;
-        break;
-    case 1:
-        mask = 0x7fffffff;
-        break;
-    default:
-        mask = -1;
-        break;
-    }
-
-    /* Bizarre but true, we check the address of the current insn for the
-       specification exception, not the next to be executed.  Thus the PoO
-       documents that Bad Things Happen two bytes before the end.  */
-    if (s->base.pc_next & ~mask) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-    s->pc_tmp &= mask;
-
-    tsam = tcg_const_i64(sam);
-    tcg_gen_deposit_i64(psw_mask, psw_mask, tsam, 31, 2);
-    tcg_temp_free_i64(tsam);
-
-    /* Always exit the TB, since we (may have) changed execution mode.  */
-    return DISAS_PC_STALE;
-}
-
-static DisasJumpType op_sar(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    tcg_gen_st32_i64(o->in2, cpu_env, offsetof(CPUS390XState, aregs[r1]));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_seb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_seb(o->out, cpu_env, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_sdb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_sdb(o->out, cpu_env, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_sxb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_sxb(o->out, cpu_env, o->out, o->out2, o->in1, o->in2);
-    return_low128(o->out2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_sqeb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_sqeb(o->out, cpu_env, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_sqdb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_sqdb(o->out, cpu_env, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_sqxb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_sqxb(o->out, cpu_env, o->in1, o->in2);
-    return_low128(o->out2);
-    return DISAS_NEXT;
-}
-
-#ifndef CONFIG_USER_ONLY
-static DisasJumpType op_servc(DisasContext *s, DisasOps *o)
-{
-    gen_helper_servc(cc_op, cpu_env, o->in2, o->in1);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_sigp(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
-    TCGv_i32 r3 = tcg_const_i32(get_field(s, r3));
-    gen_helper_sigp(cc_op, cpu_env, o->in2, r1, r3);
-    set_cc_static(s);
-    tcg_temp_free_i32(r1);
-    tcg_temp_free_i32(r3);
-    return DISAS_NEXT;
-}
-#endif
-
-static DisasJumpType op_soc(DisasContext *s, DisasOps *o)
-{
-    DisasCompare c;
-    TCGv_i64 a, h;
-    TCGLabel *lab;
-    int r1;
-
-    disas_jcc(s, &c, get_field(s, m3));
-
-    /* We want to store when the condition is fulfilled, so branch
-       out when it's not */
-    c.cond = tcg_invert_cond(c.cond);
-
-    lab = gen_new_label();
-    if (c.is_64) {
-        tcg_gen_brcond_i64(c.cond, c.u.s64.a, c.u.s64.b, lab);
-    } else {
-        tcg_gen_brcond_i32(c.cond, c.u.s32.a, c.u.s32.b, lab);
-    }
-    free_compare(&c);
-
-    r1 = get_field(s, r1);
-    a = get_address(s, 0, get_field(s, b2), get_field(s, d2));
-    switch (s->insn->data) {
-    case 1: /* STOCG */
-        tcg_gen_qemu_st64(regs[r1], a, get_mem_index(s));
-        break;
-    case 0: /* STOC */
-        tcg_gen_qemu_st32(regs[r1], a, get_mem_index(s));
-        break;
-    case 2: /* STOCFH */
-        h = tcg_temp_new_i64();
-        tcg_gen_shri_i64(h, regs[r1], 32);
-        tcg_gen_qemu_st32(h, a, get_mem_index(s));
-        tcg_temp_free_i64(h);
-        break;
-    default:
-        g_assert_not_reached();
-    }
-    tcg_temp_free_i64(a);
-
-    gen_set_label(lab);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_sla(DisasContext *s, DisasOps *o)
-{
-    uint64_t sign = 1ull << s->insn->data;
-    enum cc_op cco = s->insn->data == 31 ? CC_OP_SLA_32 : CC_OP_SLA_64;
-    gen_op_update2_cc_i64(s, cco, o->in1, o->in2);
-    tcg_gen_shl_i64(o->out, o->in1, o->in2);
-    /* The arithmetic left shift is curious in that it does not affect
-       the sign bit.  Copy that over from the source unchanged.  */
-    tcg_gen_andi_i64(o->out, o->out, ~sign);
-    tcg_gen_andi_i64(o->in1, o->in1, sign);
-    tcg_gen_or_i64(o->out, o->out, o->in1);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_sll(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_shl_i64(o->out, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_sra(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_sar_i64(o->out, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_srl(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_shr_i64(o->out, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_sfpc(DisasContext *s, DisasOps *o)
-{
-    gen_helper_sfpc(cpu_env, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_sfas(DisasContext *s, DisasOps *o)
-{
-    gen_helper_sfas(cpu_env, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_srnm(DisasContext *s, DisasOps *o)
-{
-    /* Bits other than 62 and 63 are ignored. Bit 29 is set to zero. */
-    tcg_gen_andi_i64(o->addr1, o->addr1, 0x3ull);
-    gen_helper_srnm(cpu_env, o->addr1);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_srnmb(DisasContext *s, DisasOps *o)
-{
-    /* Bits 0-55 are are ignored. */
-    tcg_gen_andi_i64(o->addr1, o->addr1, 0xffull);
-    gen_helper_srnm(cpu_env, o->addr1);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_srnmt(DisasContext *s, DisasOps *o)
-{
-    TCGv_i64 tmp = tcg_temp_new_i64();
-
-    /* Bits other than 61-63 are ignored. */
-    tcg_gen_andi_i64(o->addr1, o->addr1, 0x7ull);
-
-    /* No need to call a helper, we don't implement dfp */
-    tcg_gen_ld32u_i64(tmp, cpu_env, offsetof(CPUS390XState, fpc));
-    tcg_gen_deposit_i64(tmp, tmp, o->addr1, 4, 3);
-    tcg_gen_st32_i64(tmp, cpu_env, offsetof(CPUS390XState, fpc));
-
-    tcg_temp_free_i64(tmp);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_spm(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_extrl_i64_i32(cc_op, o->in1);
-    tcg_gen_extract_i32(cc_op, cc_op, 28, 2);
-    set_cc_static(s);
-
-    tcg_gen_shri_i64(o->in1, o->in1, 24);
-    tcg_gen_deposit_i64(psw_mask, psw_mask, o->in1, PSW_SHIFT_MASK_PM, 4);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_ectg(DisasContext *s, DisasOps *o)
-{
-    int b1 = get_field(s, b1);
-    int d1 = get_field(s, d1);
-    int b2 = get_field(s, b2);
-    int d2 = get_field(s, d2);
-    int r3 = get_field(s, r3);
-    TCGv_i64 tmp = tcg_temp_new_i64();
-
-    /* fetch all operands first */
-    o->in1 = tcg_temp_new_i64();
-    tcg_gen_addi_i64(o->in1, regs[b1], d1);
-    o->in2 = tcg_temp_new_i64();
-    tcg_gen_addi_i64(o->in2, regs[b2], d2);
-    o->addr1 = tcg_temp_new_i64();
-    gen_addi_and_wrap_i64(s, o->addr1, regs[r3], 0);
-
-    /* load the third operand into r3 before modifying anything */
-    tcg_gen_qemu_ld64(regs[r3], o->addr1, get_mem_index(s));
-
-    /* subtract CPU timer from first operand and store in GR0 */
-    gen_helper_stpt(tmp, cpu_env);
-    tcg_gen_sub_i64(regs[0], o->in1, tmp);
-
-    /* store second operand in GR1 */
-    tcg_gen_mov_i64(regs[1], o->in2);
-
-    tcg_temp_free_i64(tmp);
-    return DISAS_NEXT;
-}
-
-#ifndef CONFIG_USER_ONLY
-static DisasJumpType op_spka(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_shri_i64(o->in2, o->in2, 4);
-    tcg_gen_deposit_i64(psw_mask, psw_mask, o->in2, PSW_SHIFT_KEY, 4);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_sske(DisasContext *s, DisasOps *o)
-{
-    gen_helper_sske(cpu_env, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_ssm(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_deposit_i64(psw_mask, psw_mask, o->in2, 56, 8);
-    /* Exit to main loop to reevaluate s390_cpu_exec_interrupt.  */
-    return DISAS_PC_STALE_NOCHAIN;
-}
-
-static DisasJumpType op_stap(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, core_id));
-    return DISAS_NEXT;
-}
-#endif
-
-static DisasJumpType op_stck(DisasContext *s, DisasOps *o)
-{
-    gen_helper_stck(o->out, cpu_env);
-    /* ??? We don't implement clock states.  */
-    gen_op_movi_cc(s, 0);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_stcke(DisasContext *s, DisasOps *o)
-{
-    TCGv_i64 c1 = tcg_temp_new_i64();
-    TCGv_i64 c2 = tcg_temp_new_i64();
-    TCGv_i64 todpr = tcg_temp_new_i64();
-    gen_helper_stck(c1, cpu_env);
-    /* 16 bit value store in an uint32_t (only valid bits set) */
-    tcg_gen_ld32u_i64(todpr, cpu_env, offsetof(CPUS390XState, todpr));
-    /* Shift the 64-bit value into its place as a zero-extended
-       104-bit value.  Note that "bit positions 64-103 are always
-       non-zero so that they compare differently to STCK"; we set
-       the least significant bit to 1.  */
-    tcg_gen_shli_i64(c2, c1, 56);
-    tcg_gen_shri_i64(c1, c1, 8);
-    tcg_gen_ori_i64(c2, c2, 0x10000);
-    tcg_gen_or_i64(c2, c2, todpr);
-    tcg_gen_qemu_st64(c1, o->in2, get_mem_index(s));
-    tcg_gen_addi_i64(o->in2, o->in2, 8);
-    tcg_gen_qemu_st64(c2, o->in2, get_mem_index(s));
-    tcg_temp_free_i64(c1);
-    tcg_temp_free_i64(c2);
-    tcg_temp_free_i64(todpr);
-    /* ??? We don't implement clock states.  */
-    gen_op_movi_cc(s, 0);
-    return DISAS_NEXT;
-}
-
-#ifndef CONFIG_USER_ONLY
-static DisasJumpType op_sck(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_qemu_ld_i64(o->in1, o->addr1, get_mem_index(s), MO_TEQ | MO_ALIGN);
-    gen_helper_sck(cc_op, cpu_env, o->in1);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_sckc(DisasContext *s, DisasOps *o)
-{
-    gen_helper_sckc(cpu_env, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_sckpf(DisasContext *s, DisasOps *o)
-{
-    gen_helper_sckpf(cpu_env, regs[0]);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_stckc(DisasContext *s, DisasOps *o)
-{
-    gen_helper_stckc(o->out, cpu_env);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_stctg(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
-    TCGv_i32 r3 = tcg_const_i32(get_field(s, r3));
-    gen_helper_stctg(cpu_env, r1, o->in2, r3);
-    tcg_temp_free_i32(r1);
-    tcg_temp_free_i32(r3);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_stctl(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
-    TCGv_i32 r3 = tcg_const_i32(get_field(s, r3));
-    gen_helper_stctl(cpu_env, r1, o->in2, r3);
-    tcg_temp_free_i32(r1);
-    tcg_temp_free_i32(r3);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_stidp(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_ld_i64(o->out, cpu_env, offsetof(CPUS390XState, cpuid));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_spt(DisasContext *s, DisasOps *o)
-{
-    gen_helper_spt(cpu_env, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_stfl(DisasContext *s, DisasOps *o)
-{
-    gen_helper_stfl(cpu_env);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_stpt(DisasContext *s, DisasOps *o)
-{
-    gen_helper_stpt(o->out, cpu_env);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_stsi(DisasContext *s, DisasOps *o)
-{
-    gen_helper_stsi(cc_op, cpu_env, o->in2, regs[0], regs[1]);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_spx(DisasContext *s, DisasOps *o)
-{
-    gen_helper_spx(cpu_env, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_xsch(DisasContext *s, DisasOps *o)
-{
-    gen_helper_xsch(cpu_env, regs[1]);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_csch(DisasContext *s, DisasOps *o)
-{
-    gen_helper_csch(cpu_env, regs[1]);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_hsch(DisasContext *s, DisasOps *o)
-{
-    gen_helper_hsch(cpu_env, regs[1]);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_msch(DisasContext *s, DisasOps *o)
-{
-    gen_helper_msch(cpu_env, regs[1], o->in2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_rchp(DisasContext *s, DisasOps *o)
-{
-    gen_helper_rchp(cpu_env, regs[1]);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_rsch(DisasContext *s, DisasOps *o)
-{
-    gen_helper_rsch(cpu_env, regs[1]);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_sal(DisasContext *s, DisasOps *o)
-{
-    gen_helper_sal(cpu_env, regs[1]);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_schm(DisasContext *s, DisasOps *o)
-{
-    gen_helper_schm(cpu_env, regs[1], regs[2], o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_siga(DisasContext *s, DisasOps *o)
-{
-    /* From KVM code: Not provided, set CC = 3 for subchannel not operational */
-    gen_op_movi_cc(s, 3);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_stcps(DisasContext *s, DisasOps *o)
-{
-    /* The instruction is suppressed if not provided. */
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_ssch(DisasContext *s, DisasOps *o)
-{
-    gen_helper_ssch(cpu_env, regs[1], o->in2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_stsch(DisasContext *s, DisasOps *o)
-{
-    gen_helper_stsch(cpu_env, regs[1], o->in2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_stcrw(DisasContext *s, DisasOps *o)
-{
-    gen_helper_stcrw(cpu_env, o->in2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_tpi(DisasContext *s, DisasOps *o)
-{
-    gen_helper_tpi(cc_op, cpu_env, o->addr1);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_tsch(DisasContext *s, DisasOps *o)
-{
-    gen_helper_tsch(cpu_env, regs[1], o->in2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_chsc(DisasContext *s, DisasOps *o)
-{
-    gen_helper_chsc(cpu_env, o->in2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_stpx(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_ld_i64(o->out, cpu_env, offsetof(CPUS390XState, psa));
-    tcg_gen_andi_i64(o->out, o->out, 0x7fffe000);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_stnosm(DisasContext *s, DisasOps *o)
-{
-    uint64_t i2 = get_field(s, i2);
-    TCGv_i64 t;
-
-    /* It is important to do what the instruction name says: STORE THEN.
-       If we let the output hook perform the store then if we fault and
-       restart, we'll have the wrong SYSTEM MASK in place.  */
-    t = tcg_temp_new_i64();
-    tcg_gen_shri_i64(t, psw_mask, 56);
-    tcg_gen_qemu_st8(t, o->addr1, get_mem_index(s));
-    tcg_temp_free_i64(t);
-
-    if (s->fields.op == 0xac) {
-        tcg_gen_andi_i64(psw_mask, psw_mask,
-                         (i2 << 56) | 0x00ffffffffffffffull);
-    } else {
-        tcg_gen_ori_i64(psw_mask, psw_mask, i2 << 56);
-    }
-
-    /* Exit to main loop to reevaluate s390_cpu_exec_interrupt.  */
-    return DISAS_PC_STALE_NOCHAIN;
-}
-
-static DisasJumpType op_stura(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_qemu_st_tl(o->in1, o->in2, MMU_REAL_IDX, s->insn->data);
-
-    if (s->base.tb->flags & FLAG_MASK_PER) {
-        update_psw_addr(s);
-        gen_helper_per_store_real(cpu_env);
-    }
-    return DISAS_NEXT;
-}
-#endif
-
-static DisasJumpType op_stfle(DisasContext *s, DisasOps *o)
-{
-    gen_helper_stfle(cc_op, cpu_env, o->in2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_st8(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_qemu_st8(o->in1, o->in2, get_mem_index(s));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_st16(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_qemu_st16(o->in1, o->in2, get_mem_index(s));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_st32(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_qemu_st32(o->in1, o->in2, get_mem_index(s));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_st64(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_qemu_st64(o->in1, o->in2, get_mem_index(s));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_stam(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
-    TCGv_i32 r3 = tcg_const_i32(get_field(s, r3));
-    gen_helper_stam(cpu_env, r1, o->in2, r3);
-    tcg_temp_free_i32(r1);
-    tcg_temp_free_i32(r3);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_stcm(DisasContext *s, DisasOps *o)
-{
-    int m3 = get_field(s, m3);
-    int pos, base = s->insn->data;
-    TCGv_i64 tmp = tcg_temp_new_i64();
-
-    pos = base + ctz32(m3) * 8;
-    switch (m3) {
-    case 0xf:
-        /* Effectively a 32-bit store.  */
-        tcg_gen_shri_i64(tmp, o->in1, pos);
-        tcg_gen_qemu_st32(tmp, o->in2, get_mem_index(s));
-        break;
-
-    case 0xc:
-    case 0x6:
-    case 0x3:
-        /* Effectively a 16-bit store.  */
-        tcg_gen_shri_i64(tmp, o->in1, pos);
-        tcg_gen_qemu_st16(tmp, o->in2, get_mem_index(s));
-        break;
-
-    case 0x8:
-    case 0x4:
-    case 0x2:
-    case 0x1:
-        /* Effectively an 8-bit store.  */
-        tcg_gen_shri_i64(tmp, o->in1, pos);
-        tcg_gen_qemu_st8(tmp, o->in2, get_mem_index(s));
-        break;
-
-    default:
-        /* This is going to be a sequence of shifts and stores.  */
-        pos = base + 32 - 8;
-        while (m3) {
-            if (m3 & 0x8) {
-                tcg_gen_shri_i64(tmp, o->in1, pos);
-                tcg_gen_qemu_st8(tmp, o->in2, get_mem_index(s));
-                tcg_gen_addi_i64(o->in2, o->in2, 1);
-            }
-            m3 = (m3 << 1) & 0xf;
-            pos -= 8;
-        }
-        break;
-    }
-    tcg_temp_free_i64(tmp);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_stm(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    int r3 = get_field(s, r3);
-    int size = s->insn->data;
-    TCGv_i64 tsize = tcg_const_i64(size);
-
-    while (1) {
-        if (size == 8) {
-            tcg_gen_qemu_st64(regs[r1], o->in2, get_mem_index(s));
-        } else {
-            tcg_gen_qemu_st32(regs[r1], o->in2, get_mem_index(s));
-        }
-        if (r1 == r3) {
-            break;
-        }
-        tcg_gen_add_i64(o->in2, o->in2, tsize);
-        r1 = (r1 + 1) & 15;
-    }
-
-    tcg_temp_free_i64(tsize);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_stmh(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    int r3 = get_field(s, r3);
-    TCGv_i64 t = tcg_temp_new_i64();
-    TCGv_i64 t4 = tcg_const_i64(4);
-    TCGv_i64 t32 = tcg_const_i64(32);
-
-    while (1) {
-        tcg_gen_shl_i64(t, regs[r1], t32);
-        tcg_gen_qemu_st32(t, o->in2, get_mem_index(s));
-        if (r1 == r3) {
-            break;
-        }
-        tcg_gen_add_i64(o->in2, o->in2, t4);
-        r1 = (r1 + 1) & 15;
-    }
-
-    tcg_temp_free_i64(t);
-    tcg_temp_free_i64(t4);
-    tcg_temp_free_i64(t32);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_stpq(DisasContext *s, DisasOps *o)
-{
-    if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
-        gen_helper_stpq(cpu_env, o->in2, o->out2, o->out);
-    } else if (HAVE_ATOMIC128) {
-        gen_helper_stpq_parallel(cpu_env, o->in2, o->out2, o->out);
-    } else {
-        gen_helper_exit_atomic(cpu_env);
-        return DISAS_NORETURN;
-    }
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_srst(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
-    TCGv_i32 r2 = tcg_const_i32(get_field(s, r2));
-
-    gen_helper_srst(cpu_env, r1, r2);
-
-    tcg_temp_free_i32(r1);
-    tcg_temp_free_i32(r2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_srstu(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
-    TCGv_i32 r2 = tcg_const_i32(get_field(s, r2));
-
-    gen_helper_srstu(cpu_env, r1, r2);
-
-    tcg_temp_free_i32(r1);
-    tcg_temp_free_i32(r2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_sub(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_sub_i64(o->out, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_subu64(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_movi_i64(cc_src, 0);
-    tcg_gen_sub2_i64(o->out, cc_src, o->in1, cc_src, o->in2, cc_src);
-    return DISAS_NEXT;
-}
-
-/* Compute borrow (0, -1) into cc_src. */
-static void compute_borrow(DisasContext *s)
-{
-    switch (s->cc_op) {
-    case CC_OP_SUBU:
-        /* The borrow value is already in cc_src (0,-1). */
-        break;
-    default:
-        gen_op_calc_cc(s);
-        /* fall through */
-    case CC_OP_STATIC:
-        /* The carry flag is the msb of CC; compute into cc_src. */
-        tcg_gen_extu_i32_i64(cc_src, cc_op);
-        tcg_gen_shri_i64(cc_src, cc_src, 1);
-        /* fall through */
-    case CC_OP_ADDU:
-        /* Convert carry (1,0) to borrow (0,-1). */
-        tcg_gen_subi_i64(cc_src, cc_src, 1);
-        break;
-    }
-}
-
-static DisasJumpType op_subb32(DisasContext *s, DisasOps *o)
-{
-    compute_borrow(s);
-
-    /* Borrow is {0, -1}, so add to subtract. */
-    tcg_gen_add_i64(o->out, o->in1, cc_src);
-    tcg_gen_sub_i64(o->out, o->out, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_subb64(DisasContext *s, DisasOps *o)
-{
-    compute_borrow(s);
-
-    /*
-     * Borrow is {0, -1}, so add to subtract; replicate the
-     * borrow input to produce 128-bit -1 for the addition.
-     */
-    TCGv_i64 zero = tcg_const_i64(0);
-    tcg_gen_add2_i64(o->out, cc_src, o->in1, zero, cc_src, cc_src);
-    tcg_gen_sub2_i64(o->out, cc_src, o->out, cc_src, o->in2, zero);
-    tcg_temp_free_i64(zero);
-
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_svc(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 t;
-
-    update_psw_addr(s);
-    update_cc_op(s);
-
-    t = tcg_const_i32(get_field(s, i1) & 0xff);
-    tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, int_svc_code));
-    tcg_temp_free_i32(t);
-
-    t = tcg_const_i32(s->ilen);
-    tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, int_svc_ilen));
-    tcg_temp_free_i32(t);
-
-    gen_exception(EXCP_SVC);
-    return DISAS_NORETURN;
-}
-
-static DisasJumpType op_tam(DisasContext *s, DisasOps *o)
-{
-    int cc = 0;
-
-    cc |= (s->base.tb->flags & FLAG_MASK_64) ? 2 : 0;
-    cc |= (s->base.tb->flags & FLAG_MASK_32) ? 1 : 0;
-    gen_op_movi_cc(s, cc);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_tceb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_tceb(cc_op, cpu_env, o->in1, o->in2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_tcdb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_tcdb(cc_op, cpu_env, o->in1, o->in2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_tcxb(DisasContext *s, DisasOps *o)
-{
-    gen_helper_tcxb(cc_op, cpu_env, o->out, o->out2, o->in2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-#ifndef CONFIG_USER_ONLY
-
-static DisasJumpType op_testblock(DisasContext *s, DisasOps *o)
-{
-    gen_helper_testblock(cc_op, cpu_env, o->in2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_tprot(DisasContext *s, DisasOps *o)
-{
-    gen_helper_tprot(cc_op, cpu_env, o->addr1, o->in2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-#endif
-
-static DisasJumpType op_tp(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 l1 = tcg_const_i32(get_field(s, l1) + 1);
-    gen_helper_tp(cc_op, cpu_env, o->addr1, l1);
-    tcg_temp_free_i32(l1);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_tr(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 l = tcg_const_i32(get_field(s, l1));
-    gen_helper_tr(cpu_env, l, o->addr1, o->in2);
-    tcg_temp_free_i32(l);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_tre(DisasContext *s, DisasOps *o)
-{
-    gen_helper_tre(o->out, cpu_env, o->out, o->out2, o->in2);
-    return_low128(o->out2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_trt(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 l = tcg_const_i32(get_field(s, l1));
-    gen_helper_trt(cc_op, cpu_env, l, o->addr1, o->in2);
-    tcg_temp_free_i32(l);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_trtr(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 l = tcg_const_i32(get_field(s, l1));
-    gen_helper_trtr(cc_op, cpu_env, l, o->addr1, o->in2);
-    tcg_temp_free_i32(l);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_trXX(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
-    TCGv_i32 r2 = tcg_const_i32(get_field(s, r2));
-    TCGv_i32 sizes = tcg_const_i32(s->insn->opc & 3);
-    TCGv_i32 tst = tcg_temp_new_i32();
-    int m3 = get_field(s, m3);
-
-    if (!s390_has_feat(S390_FEAT_ETF2_ENH)) {
-        m3 = 0;
-    }
-    if (m3 & 1) {
-        tcg_gen_movi_i32(tst, -1);
-    } else {
-        tcg_gen_extrl_i64_i32(tst, regs[0]);
-        if (s->insn->opc & 3) {
-            tcg_gen_ext8u_i32(tst, tst);
-        } else {
-            tcg_gen_ext16u_i32(tst, tst);
-        }
-    }
-    gen_helper_trXX(cc_op, cpu_env, r1, r2, tst, sizes);
-
-    tcg_temp_free_i32(r1);
-    tcg_temp_free_i32(r2);
-    tcg_temp_free_i32(sizes);
-    tcg_temp_free_i32(tst);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_ts(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 t1 = tcg_const_i32(0xff);
-    tcg_gen_atomic_xchg_i32(t1, o->in2, t1, get_mem_index(s), MO_UB);
-    tcg_gen_extract_i32(cc_op, t1, 7, 1);
-    tcg_temp_free_i32(t1);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_unpk(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 l = tcg_const_i32(get_field(s, l1));
-    gen_helper_unpk(cpu_env, l, o->addr1, o->in2);
-    tcg_temp_free_i32(l);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_unpka(DisasContext *s, DisasOps *o)
-{
-    int l1 = get_field(s, l1) + 1;
-    TCGv_i32 l;
-
-    /* The length must not exceed 32 bytes.  */
-    if (l1 > 32) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-    l = tcg_const_i32(l1);
-    gen_helper_unpka(cc_op, cpu_env, o->addr1, l, o->in2);
-    tcg_temp_free_i32(l);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_unpku(DisasContext *s, DisasOps *o)
-{
-    int l1 = get_field(s, l1) + 1;
-    TCGv_i32 l;
-
-    /* The length must be even and should not exceed 64 bytes.  */
-    if ((l1 & 1) || (l1 > 64)) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-    l = tcg_const_i32(l1);
-    gen_helper_unpku(cc_op, cpu_env, o->addr1, l, o->in2);
-    tcg_temp_free_i32(l);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-
-static DisasJumpType op_xc(DisasContext *s, DisasOps *o)
-{
-    int d1 = get_field(s, d1);
-    int d2 = get_field(s, d2);
-    int b1 = get_field(s, b1);
-    int b2 = get_field(s, b2);
-    int l = get_field(s, l1);
-    TCGv_i32 t32;
-
-    o->addr1 = get_address(s, 0, b1, d1);
-
-    /* If the addresses are identical, this is a store/memset of zero.  */
-    if (b1 == b2 && d1 == d2 && (l + 1) <= 32) {
-        o->in2 = tcg_const_i64(0);
-
-        l++;
-        while (l >= 8) {
-            tcg_gen_qemu_st64(o->in2, o->addr1, get_mem_index(s));
-            l -= 8;
-            if (l > 0) {
-                tcg_gen_addi_i64(o->addr1, o->addr1, 8);
-            }
-        }
-        if (l >= 4) {
-            tcg_gen_qemu_st32(o->in2, o->addr1, get_mem_index(s));
-            l -= 4;
-            if (l > 0) {
-                tcg_gen_addi_i64(o->addr1, o->addr1, 4);
-            }
-        }
-        if (l >= 2) {
-            tcg_gen_qemu_st16(o->in2, o->addr1, get_mem_index(s));
-            l -= 2;
-            if (l > 0) {
-                tcg_gen_addi_i64(o->addr1, o->addr1, 2);
-            }
-        }
-        if (l) {
-            tcg_gen_qemu_st8(o->in2, o->addr1, get_mem_index(s));
-        }
-        gen_op_movi_cc(s, 0);
-        return DISAS_NEXT;
-    }
-
-    /* But in general we'll defer to a helper.  */
-    o->in2 = get_address(s, 0, b2, d2);
-    t32 = tcg_const_i32(l);
-    gen_helper_xc(cc_op, cpu_env, t32, o->addr1, o->in2);
-    tcg_temp_free_i32(t32);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_xor(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_xor_i64(o->out, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_xori(DisasContext *s, DisasOps *o)
-{
-    int shift = s->insn->data & 0xff;
-    int size = s->insn->data >> 8;
-    uint64_t mask = ((1ull << size) - 1) << shift;
-
-    assert(!o->g_in2);
-    tcg_gen_shli_i64(o->in2, o->in2, shift);
-    tcg_gen_xor_i64(o->out, o->in1, o->in2);
-
-    /* Produce the CC from only the bits manipulated.  */
-    tcg_gen_andi_i64(cc_dst, o->out, mask);
-    set_cc_nz_u64(s, cc_dst);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_xi(DisasContext *s, DisasOps *o)
-{
-    o->in1 = tcg_temp_new_i64();
-
-    if (!s390_has_feat(S390_FEAT_INTERLOCKED_ACCESS_2)) {
-        tcg_gen_qemu_ld_tl(o->in1, o->addr1, get_mem_index(s), s->insn->data);
-    } else {
-        /* Perform the atomic operation in memory. */
-        tcg_gen_atomic_fetch_xor_i64(o->in1, o->addr1, o->in2, get_mem_index(s),
-                                     s->insn->data);
-    }
-
-    /* Recompute also for atomic case: needed for setting CC. */
-    tcg_gen_xor_i64(o->out, o->in1, o->in2);
-
-    if (!s390_has_feat(S390_FEAT_INTERLOCKED_ACCESS_2)) {
-        tcg_gen_qemu_st_tl(o->out, o->addr1, get_mem_index(s), s->insn->data);
-    }
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_zero(DisasContext *s, DisasOps *o)
-{
-    o->out = tcg_const_i64(0);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_zero2(DisasContext *s, DisasOps *o)
-{
-    o->out = tcg_const_i64(0);
-    o->out2 = o->out;
-    o->g_out2 = true;
-    return DISAS_NEXT;
-}
-
-#ifndef CONFIG_USER_ONLY
-static DisasJumpType op_clp(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 r2 = tcg_const_i32(get_field(s, r2));
-
-    gen_helper_clp(cpu_env, r2);
-    tcg_temp_free_i32(r2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_pcilg(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
-    TCGv_i32 r2 = tcg_const_i32(get_field(s, r2));
-
-    gen_helper_pcilg(cpu_env, r1, r2);
-    tcg_temp_free_i32(r1);
-    tcg_temp_free_i32(r2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_pcistg(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
-    TCGv_i32 r2 = tcg_const_i32(get_field(s, r2));
-
-    gen_helper_pcistg(cpu_env, r1, r2);
-    tcg_temp_free_i32(r1);
-    tcg_temp_free_i32(r2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_stpcifc(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
-    TCGv_i32 ar = tcg_const_i32(get_field(s, b2));
-
-    gen_helper_stpcifc(cpu_env, r1, o->addr1, ar);
-    tcg_temp_free_i32(ar);
-    tcg_temp_free_i32(r1);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_sic(DisasContext *s, DisasOps *o)
-{
-    gen_helper_sic(cpu_env, o->in1, o->in2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_rpcit(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
-    TCGv_i32 r2 = tcg_const_i32(get_field(s, r2));
-
-    gen_helper_rpcit(cpu_env, r1, r2);
-    tcg_temp_free_i32(r1);
-    tcg_temp_free_i32(r2);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_pcistb(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
-    TCGv_i32 r3 = tcg_const_i32(get_field(s, r3));
-    TCGv_i32 ar = tcg_const_i32(get_field(s, b2));
-
-    gen_helper_pcistb(cpu_env, r1, r3, o->addr1, ar);
-    tcg_temp_free_i32(ar);
-    tcg_temp_free_i32(r1);
-    tcg_temp_free_i32(r3);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_mpcifc(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 r1 = tcg_const_i32(get_field(s, r1));
-    TCGv_i32 ar = tcg_const_i32(get_field(s, b2));
-
-    gen_helper_mpcifc(cpu_env, r1, o->addr1, ar);
-    tcg_temp_free_i32(ar);
-    tcg_temp_free_i32(r1);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-#endif
-
-#include "translate_vx.c.inc"
-
-/* ====================================================================== */
-/* The "Cc OUTput" generators.  Given the generated output (and in some cases
-   the original inputs), update the various cc data structures in order to
-   be able to compute the new condition code.  */
-
-static void cout_abs32(DisasContext *s, DisasOps *o)
-{
-    gen_op_update1_cc_i64(s, CC_OP_ABS_32, o->out);
-}
-
-static void cout_abs64(DisasContext *s, DisasOps *o)
-{
-    gen_op_update1_cc_i64(s, CC_OP_ABS_64, o->out);
-}
-
-static void cout_adds32(DisasContext *s, DisasOps *o)
-{
-    gen_op_update3_cc_i64(s, CC_OP_ADD_32, o->in1, o->in2, o->out);
-}
-
-static void cout_adds64(DisasContext *s, DisasOps *o)
-{
-    gen_op_update3_cc_i64(s, CC_OP_ADD_64, o->in1, o->in2, o->out);
-}
-
-static void cout_addu32(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_shri_i64(cc_src, o->out, 32);
-    tcg_gen_ext32u_i64(cc_dst, o->out);
-    gen_op_update2_cc_i64(s, CC_OP_ADDU, cc_src, cc_dst);
-}
-
-static void cout_addu64(DisasContext *s, DisasOps *o)
-{
-    gen_op_update2_cc_i64(s, CC_OP_ADDU, cc_src, o->out);
-}
-
-static void cout_cmps32(DisasContext *s, DisasOps *o)
-{
-    gen_op_update2_cc_i64(s, CC_OP_LTGT_32, o->in1, o->in2);
-}
-
-static void cout_cmps64(DisasContext *s, DisasOps *o)
-{
-    gen_op_update2_cc_i64(s, CC_OP_LTGT_64, o->in1, o->in2);
-}
-
-static void cout_cmpu32(DisasContext *s, DisasOps *o)
-{
-    gen_op_update2_cc_i64(s, CC_OP_LTUGTU_32, o->in1, o->in2);
-}
-
-static void cout_cmpu64(DisasContext *s, DisasOps *o)
-{
-    gen_op_update2_cc_i64(s, CC_OP_LTUGTU_64, o->in1, o->in2);
-}
-
-static void cout_f32(DisasContext *s, DisasOps *o)
-{
-    gen_op_update1_cc_i64(s, CC_OP_NZ_F32, o->out);
-}
-
-static void cout_f64(DisasContext *s, DisasOps *o)
-{
-    gen_op_update1_cc_i64(s, CC_OP_NZ_F64, o->out);
-}
-
-static void cout_f128(DisasContext *s, DisasOps *o)
-{
-    gen_op_update2_cc_i64(s, CC_OP_NZ_F128, o->out, o->out2);
-}
-
-static void cout_nabs32(DisasContext *s, DisasOps *o)
-{
-    gen_op_update1_cc_i64(s, CC_OP_NABS_32, o->out);
-}
-
-static void cout_nabs64(DisasContext *s, DisasOps *o)
-{
-    gen_op_update1_cc_i64(s, CC_OP_NABS_64, o->out);
-}
-
-static void cout_neg32(DisasContext *s, DisasOps *o)
-{
-    gen_op_update1_cc_i64(s, CC_OP_COMP_32, o->out);
-}
-
-static void cout_neg64(DisasContext *s, DisasOps *o)
-{
-    gen_op_update1_cc_i64(s, CC_OP_COMP_64, o->out);
-}
-
-static void cout_nz32(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_ext32u_i64(cc_dst, o->out);
-    gen_op_update1_cc_i64(s, CC_OP_NZ, cc_dst);
-}
-
-static void cout_nz64(DisasContext *s, DisasOps *o)
-{
-    gen_op_update1_cc_i64(s, CC_OP_NZ, o->out);
-}
-
-static void cout_s32(DisasContext *s, DisasOps *o)
-{
-    gen_op_update1_cc_i64(s, CC_OP_LTGT0_32, o->out);
-}
-
-static void cout_s64(DisasContext *s, DisasOps *o)
-{
-    gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, o->out);
-}
-
-static void cout_subs32(DisasContext *s, DisasOps *o)
-{
-    gen_op_update3_cc_i64(s, CC_OP_SUB_32, o->in1, o->in2, o->out);
-}
-
-static void cout_subs64(DisasContext *s, DisasOps *o)
-{
-    gen_op_update3_cc_i64(s, CC_OP_SUB_64, o->in1, o->in2, o->out);
-}
-
-static void cout_subu32(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_sari_i64(cc_src, o->out, 32);
-    tcg_gen_ext32u_i64(cc_dst, o->out);
-    gen_op_update2_cc_i64(s, CC_OP_SUBU, cc_src, cc_dst);
-}
-
-static void cout_subu64(DisasContext *s, DisasOps *o)
-{
-    gen_op_update2_cc_i64(s, CC_OP_SUBU, cc_src, o->out);
-}
-
-static void cout_tm32(DisasContext *s, DisasOps *o)
-{
-    gen_op_update2_cc_i64(s, CC_OP_TM_32, o->in1, o->in2);
-}
-
-static void cout_tm64(DisasContext *s, DisasOps *o)
-{
-    gen_op_update2_cc_i64(s, CC_OP_TM_64, o->in1, o->in2);
-}
-
-static void cout_muls32(DisasContext *s, DisasOps *o)
-{
-    gen_op_update1_cc_i64(s, CC_OP_MULS_32, o->out);
-}
-
-static void cout_muls64(DisasContext *s, DisasOps *o)
-{
-    /* out contains "high" part, out2 contains "low" part of 128 bit result */
-    gen_op_update2_cc_i64(s, CC_OP_MULS_64, o->out, o->out2);
-}
-
-/* ====================================================================== */
-/* The "PREParation" generators.  These initialize the DisasOps.OUT fields
-   with the TCG register to which we will write.  Used in combination with
-   the "wout" generators, in some cases we need a new temporary, and in
-   some cases we can write to a TCG global.  */
-
-static void prep_new(DisasContext *s, DisasOps *o)
-{
-    o->out = tcg_temp_new_i64();
-}
-#define SPEC_prep_new 0
-
-static void prep_new_P(DisasContext *s, DisasOps *o)
-{
-    o->out = tcg_temp_new_i64();
-    o->out2 = tcg_temp_new_i64();
-}
-#define SPEC_prep_new_P 0
-
-static void prep_r1(DisasContext *s, DisasOps *o)
-{
-    o->out = regs[get_field(s, r1)];
-    o->g_out = true;
-}
-#define SPEC_prep_r1 0
-
-static void prep_r1_P(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    o->out = regs[r1];
-    o->out2 = regs[r1 + 1];
-    o->g_out = o->g_out2 = true;
-}
-#define SPEC_prep_r1_P SPEC_r1_even
-
-/* Whenever we need x1 in addition to other inputs, we'll load it to out/out2 */
-static void prep_x1(DisasContext *s, DisasOps *o)
-{
-    o->out = load_freg(get_field(s, r1));
-    o->out2 = load_freg(get_field(s, r1) + 2);
-}
-#define SPEC_prep_x1 SPEC_r1_f128
-
-/* ====================================================================== */
-/* The "Write OUTput" generators.  These generally perform some non-trivial
-   copy of data to TCG globals, or to main memory.  The trivial cases are
-   generally handled by having a "prep" generator install the TCG global
-   as the destination of the operation.  */
-
-static void wout_r1(DisasContext *s, DisasOps *o)
-{
-    store_reg(get_field(s, r1), o->out);
-}
-#define SPEC_wout_r1 0
-
-static void wout_out2_r1(DisasContext *s, DisasOps *o)
-{
-    store_reg(get_field(s, r1), o->out2);
-}
-#define SPEC_wout_out2_r1 0
-
-static void wout_r1_8(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    tcg_gen_deposit_i64(regs[r1], regs[r1], o->out, 0, 8);
-}
-#define SPEC_wout_r1_8 0
-
-static void wout_r1_16(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    tcg_gen_deposit_i64(regs[r1], regs[r1], o->out, 0, 16);
-}
-#define SPEC_wout_r1_16 0
-
-static void wout_r1_32(DisasContext *s, DisasOps *o)
-{
-    store_reg32_i64(get_field(s, r1), o->out);
-}
-#define SPEC_wout_r1_32 0
-
-static void wout_r1_32h(DisasContext *s, DisasOps *o)
-{
-    store_reg32h_i64(get_field(s, r1), o->out);
-}
-#define SPEC_wout_r1_32h 0
-
-static void wout_r1_P32(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    store_reg32_i64(r1, o->out);
-    store_reg32_i64(r1 + 1, o->out2);
-}
-#define SPEC_wout_r1_P32 SPEC_r1_even
-
-static void wout_r1_D32(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    store_reg32_i64(r1 + 1, o->out);
-    tcg_gen_shri_i64(o->out, o->out, 32);
-    store_reg32_i64(r1, o->out);
-}
-#define SPEC_wout_r1_D32 SPEC_r1_even
-
-static void wout_r3_P32(DisasContext *s, DisasOps *o)
-{
-    int r3 = get_field(s, r3);
-    store_reg32_i64(r3, o->out);
-    store_reg32_i64(r3 + 1, o->out2);
-}
-#define SPEC_wout_r3_P32 SPEC_r3_even
-
-static void wout_r3_P64(DisasContext *s, DisasOps *o)
-{
-    int r3 = get_field(s, r3);
-    store_reg(r3, o->out);
-    store_reg(r3 + 1, o->out2);
-}
-#define SPEC_wout_r3_P64 SPEC_r3_even
-
-static void wout_e1(DisasContext *s, DisasOps *o)
-{
-    store_freg32_i64(get_field(s, r1), o->out);
-}
-#define SPEC_wout_e1 0
-
-static void wout_f1(DisasContext *s, DisasOps *o)
-{
-    store_freg(get_field(s, r1), o->out);
-}
-#define SPEC_wout_f1 0
-
-static void wout_x1(DisasContext *s, DisasOps *o)
-{
-    int f1 = get_field(s, r1);
-    store_freg(f1, o->out);
-    store_freg(f1 + 2, o->out2);
-}
-#define SPEC_wout_x1 SPEC_r1_f128
-
-static void wout_cond_r1r2_32(DisasContext *s, DisasOps *o)
-{
-    if (get_field(s, r1) != get_field(s, r2)) {
-        store_reg32_i64(get_field(s, r1), o->out);
-    }
-}
-#define SPEC_wout_cond_r1r2_32 0
-
-static void wout_cond_e1e2(DisasContext *s, DisasOps *o)
-{
-    if (get_field(s, r1) != get_field(s, r2)) {
-        store_freg32_i64(get_field(s, r1), o->out);
-    }
-}
-#define SPEC_wout_cond_e1e2 0
-
-static void wout_m1_8(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_qemu_st8(o->out, o->addr1, get_mem_index(s));
-}
-#define SPEC_wout_m1_8 0
-
-static void wout_m1_16(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_qemu_st16(o->out, o->addr1, get_mem_index(s));
-}
-#define SPEC_wout_m1_16 0
-
-#ifndef CONFIG_USER_ONLY
-static void wout_m1_16a(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_qemu_st_tl(o->out, o->addr1, get_mem_index(s), MO_TEUW | MO_ALIGN);
-}
-#define SPEC_wout_m1_16a 0
-#endif
-
-static void wout_m1_32(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_qemu_st32(o->out, o->addr1, get_mem_index(s));
-}
-#define SPEC_wout_m1_32 0
-
-#ifndef CONFIG_USER_ONLY
-static void wout_m1_32a(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_qemu_st_tl(o->out, o->addr1, get_mem_index(s), MO_TEUL | MO_ALIGN);
-}
-#define SPEC_wout_m1_32a 0
-#endif
-
-static void wout_m1_64(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_qemu_st64(o->out, o->addr1, get_mem_index(s));
-}
-#define SPEC_wout_m1_64 0
-
-#ifndef CONFIG_USER_ONLY
-static void wout_m1_64a(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_qemu_st_i64(o->out, o->addr1, get_mem_index(s), MO_TEQ | MO_ALIGN);
-}
-#define SPEC_wout_m1_64a 0
-#endif
-
-static void wout_m2_32(DisasContext *s, DisasOps *o)
-{
-    tcg_gen_qemu_st32(o->out, o->in2, get_mem_index(s));
-}
-#define SPEC_wout_m2_32 0
-
-static void wout_in2_r1(DisasContext *s, DisasOps *o)
-{
-    store_reg(get_field(s, r1), o->in2);
-}
-#define SPEC_wout_in2_r1 0
-
-static void wout_in2_r1_32(DisasContext *s, DisasOps *o)
-{
-    store_reg32_i64(get_field(s, r1), o->in2);
-}
-#define SPEC_wout_in2_r1_32 0
-
-/* ====================================================================== */
-/* The "INput 1" generators.  These load the first operand to an insn.  */
-
-static void in1_r1(DisasContext *s, DisasOps *o)
-{
-    o->in1 = load_reg(get_field(s, r1));
-}
-#define SPEC_in1_r1 0
-
-static void in1_r1_o(DisasContext *s, DisasOps *o)
-{
-    o->in1 = regs[get_field(s, r1)];
-    o->g_in1 = true;
-}
-#define SPEC_in1_r1_o 0
-
-static void in1_r1_32s(DisasContext *s, DisasOps *o)
-{
-    o->in1 = tcg_temp_new_i64();
-    tcg_gen_ext32s_i64(o->in1, regs[get_field(s, r1)]);
-}
-#define SPEC_in1_r1_32s 0
-
-static void in1_r1_32u(DisasContext *s, DisasOps *o)
-{
-    o->in1 = tcg_temp_new_i64();
-    tcg_gen_ext32u_i64(o->in1, regs[get_field(s, r1)]);
-}
-#define SPEC_in1_r1_32u 0
-
-static void in1_r1_sr32(DisasContext *s, DisasOps *o)
-{
-    o->in1 = tcg_temp_new_i64();
-    tcg_gen_shri_i64(o->in1, regs[get_field(s, r1)], 32);
-}
-#define SPEC_in1_r1_sr32 0
-
-static void in1_r1p1(DisasContext *s, DisasOps *o)
-{
-    o->in1 = load_reg(get_field(s, r1) + 1);
-}
-#define SPEC_in1_r1p1 SPEC_r1_even
-
-static void in1_r1p1_o(DisasContext *s, DisasOps *o)
-{
-    o->in1 = regs[get_field(s, r1) + 1];
-    o->g_in1 = true;
-}
-#define SPEC_in1_r1p1_o SPEC_r1_even
-
-static void in1_r1p1_32s(DisasContext *s, DisasOps *o)
-{
-    o->in1 = tcg_temp_new_i64();
-    tcg_gen_ext32s_i64(o->in1, regs[get_field(s, r1) + 1]);
-}
-#define SPEC_in1_r1p1_32s SPEC_r1_even
-
-static void in1_r1p1_32u(DisasContext *s, DisasOps *o)
-{
-    o->in1 = tcg_temp_new_i64();
-    tcg_gen_ext32u_i64(o->in1, regs[get_field(s, r1) + 1]);
-}
-#define SPEC_in1_r1p1_32u SPEC_r1_even
-
-static void in1_r1_D32(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    o->in1 = tcg_temp_new_i64();
-    tcg_gen_concat32_i64(o->in1, regs[r1 + 1], regs[r1]);
-}
-#define SPEC_in1_r1_D32 SPEC_r1_even
-
-static void in1_r2(DisasContext *s, DisasOps *o)
-{
-    o->in1 = load_reg(get_field(s, r2));
-}
-#define SPEC_in1_r2 0
-
-static void in1_r2_sr32(DisasContext *s, DisasOps *o)
-{
-    o->in1 = tcg_temp_new_i64();
-    tcg_gen_shri_i64(o->in1, regs[get_field(s, r2)], 32);
-}
-#define SPEC_in1_r2_sr32 0
-
-static void in1_r2_32u(DisasContext *s, DisasOps *o)
-{
-    o->in1 = tcg_temp_new_i64();
-    tcg_gen_ext32u_i64(o->in1, regs[get_field(s, r2)]);
-}
-#define SPEC_in1_r2_32u 0
-
-static void in1_r3(DisasContext *s, DisasOps *o)
-{
-    o->in1 = load_reg(get_field(s, r3));
-}
-#define SPEC_in1_r3 0
-
-static void in1_r3_o(DisasContext *s, DisasOps *o)
-{
-    o->in1 = regs[get_field(s, r3)];
-    o->g_in1 = true;
-}
-#define SPEC_in1_r3_o 0
-
-static void in1_r3_32s(DisasContext *s, DisasOps *o)
-{
-    o->in1 = tcg_temp_new_i64();
-    tcg_gen_ext32s_i64(o->in1, regs[get_field(s, r3)]);
-}
-#define SPEC_in1_r3_32s 0
-
-static void in1_r3_32u(DisasContext *s, DisasOps *o)
-{
-    o->in1 = tcg_temp_new_i64();
-    tcg_gen_ext32u_i64(o->in1, regs[get_field(s, r3)]);
-}
-#define SPEC_in1_r3_32u 0
-
-static void in1_r3_D32(DisasContext *s, DisasOps *o)
-{
-    int r3 = get_field(s, r3);
-    o->in1 = tcg_temp_new_i64();
-    tcg_gen_concat32_i64(o->in1, regs[r3 + 1], regs[r3]);
-}
-#define SPEC_in1_r3_D32 SPEC_r3_even
-
-static void in1_e1(DisasContext *s, DisasOps *o)
-{
-    o->in1 = load_freg32_i64(get_field(s, r1));
-}
-#define SPEC_in1_e1 0
-
-static void in1_f1(DisasContext *s, DisasOps *o)
-{
-    o->in1 = load_freg(get_field(s, r1));
-}
-#define SPEC_in1_f1 0
-
-/* Load the high double word of an extended (128-bit) format FP number */
-static void in1_x2h(DisasContext *s, DisasOps *o)
-{
-    o->in1 = load_freg(get_field(s, r2));
-}
-#define SPEC_in1_x2h SPEC_r2_f128
-
-static void in1_f3(DisasContext *s, DisasOps *o)
-{
-    o->in1 = load_freg(get_field(s, r3));
-}
-#define SPEC_in1_f3 0
-
-static void in1_la1(DisasContext *s, DisasOps *o)
-{
-    o->addr1 = get_address(s, 0, get_field(s, b1), get_field(s, d1));
-}
-#define SPEC_in1_la1 0
-
-static void in1_la2(DisasContext *s, DisasOps *o)
-{
-    int x2 = have_field(s, x2) ? get_field(s, x2) : 0;
-    o->addr1 = get_address(s, x2, get_field(s, b2), get_field(s, d2));
-}
-#define SPEC_in1_la2 0
-
-static void in1_m1_8u(DisasContext *s, DisasOps *o)
-{
-    in1_la1(s, o);
-    o->in1 = tcg_temp_new_i64();
-    tcg_gen_qemu_ld8u(o->in1, o->addr1, get_mem_index(s));
-}
-#define SPEC_in1_m1_8u 0
-
-static void in1_m1_16s(DisasContext *s, DisasOps *o)
-{
-    in1_la1(s, o);
-    o->in1 = tcg_temp_new_i64();
-    tcg_gen_qemu_ld16s(o->in1, o->addr1, get_mem_index(s));
-}
-#define SPEC_in1_m1_16s 0
-
-static void in1_m1_16u(DisasContext *s, DisasOps *o)
-{
-    in1_la1(s, o);
-    o->in1 = tcg_temp_new_i64();
-    tcg_gen_qemu_ld16u(o->in1, o->addr1, get_mem_index(s));
-}
-#define SPEC_in1_m1_16u 0
-
-static void in1_m1_32s(DisasContext *s, DisasOps *o)
-{
-    in1_la1(s, o);
-    o->in1 = tcg_temp_new_i64();
-    tcg_gen_qemu_ld32s(o->in1, o->addr1, get_mem_index(s));
-}
-#define SPEC_in1_m1_32s 0
-
-static void in1_m1_32u(DisasContext *s, DisasOps *o)
-{
-    in1_la1(s, o);
-    o->in1 = tcg_temp_new_i64();
-    tcg_gen_qemu_ld32u(o->in1, o->addr1, get_mem_index(s));
-}
-#define SPEC_in1_m1_32u 0
-
-static void in1_m1_64(DisasContext *s, DisasOps *o)
-{
-    in1_la1(s, o);
-    o->in1 = tcg_temp_new_i64();
-    tcg_gen_qemu_ld64(o->in1, o->addr1, get_mem_index(s));
-}
-#define SPEC_in1_m1_64 0
-
-/* ====================================================================== */
-/* The "INput 2" generators.  These load the second operand to an insn.  */
-
-static void in2_r1_o(DisasContext *s, DisasOps *o)
-{
-    o->in2 = regs[get_field(s, r1)];
-    o->g_in2 = true;
-}
-#define SPEC_in2_r1_o 0
-
-static void in2_r1_16u(DisasContext *s, DisasOps *o)
-{
-    o->in2 = tcg_temp_new_i64();
-    tcg_gen_ext16u_i64(o->in2, regs[get_field(s, r1)]);
-}
-#define SPEC_in2_r1_16u 0
-
-static void in2_r1_32u(DisasContext *s, DisasOps *o)
-{
-    o->in2 = tcg_temp_new_i64();
-    tcg_gen_ext32u_i64(o->in2, regs[get_field(s, r1)]);
-}
-#define SPEC_in2_r1_32u 0
-
-static void in2_r1_D32(DisasContext *s, DisasOps *o)
-{
-    int r1 = get_field(s, r1);
-    o->in2 = tcg_temp_new_i64();
-    tcg_gen_concat32_i64(o->in2, regs[r1 + 1], regs[r1]);
-}
-#define SPEC_in2_r1_D32 SPEC_r1_even
-
-static void in2_r2(DisasContext *s, DisasOps *o)
-{
-    o->in2 = load_reg(get_field(s, r2));
-}
-#define SPEC_in2_r2 0
-
-static void in2_r2_o(DisasContext *s, DisasOps *o)
-{
-    o->in2 = regs[get_field(s, r2)];
-    o->g_in2 = true;
-}
-#define SPEC_in2_r2_o 0
-
-static void in2_r2_nz(DisasContext *s, DisasOps *o)
-{
-    int r2 = get_field(s, r2);
-    if (r2 != 0) {
-        o->in2 = load_reg(r2);
-    }
-}
-#define SPEC_in2_r2_nz 0
-
-static void in2_r2_8s(DisasContext *s, DisasOps *o)
-{
-    o->in2 = tcg_temp_new_i64();
-    tcg_gen_ext8s_i64(o->in2, regs[get_field(s, r2)]);
-}
-#define SPEC_in2_r2_8s 0
-
-static void in2_r2_8u(DisasContext *s, DisasOps *o)
-{
-    o->in2 = tcg_temp_new_i64();
-    tcg_gen_ext8u_i64(o->in2, regs[get_field(s, r2)]);
-}
-#define SPEC_in2_r2_8u 0
-
-static void in2_r2_16s(DisasContext *s, DisasOps *o)
-{
-    o->in2 = tcg_temp_new_i64();
-    tcg_gen_ext16s_i64(o->in2, regs[get_field(s, r2)]);
-}
-#define SPEC_in2_r2_16s 0
-
-static void in2_r2_16u(DisasContext *s, DisasOps *o)
-{
-    o->in2 = tcg_temp_new_i64();
-    tcg_gen_ext16u_i64(o->in2, regs[get_field(s, r2)]);
-}
-#define SPEC_in2_r2_16u 0
-
-static void in2_r3(DisasContext *s, DisasOps *o)
-{
-    o->in2 = load_reg(get_field(s, r3));
-}
-#define SPEC_in2_r3 0
-
-static void in2_r3_sr32(DisasContext *s, DisasOps *o)
-{
-    o->in2 = tcg_temp_new_i64();
-    tcg_gen_shri_i64(o->in2, regs[get_field(s, r3)], 32);
-}
-#define SPEC_in2_r3_sr32 0
-
-static void in2_r3_32u(DisasContext *s, DisasOps *o)
-{
-    o->in2 = tcg_temp_new_i64();
-    tcg_gen_ext32u_i64(o->in2, regs[get_field(s, r3)]);
-}
-#define SPEC_in2_r3_32u 0
-
-static void in2_r2_32s(DisasContext *s, DisasOps *o)
-{
-    o->in2 = tcg_temp_new_i64();
-    tcg_gen_ext32s_i64(o->in2, regs[get_field(s, r2)]);
-}
-#define SPEC_in2_r2_32s 0
-
-static void in2_r2_32u(DisasContext *s, DisasOps *o)
-{
-    o->in2 = tcg_temp_new_i64();
-    tcg_gen_ext32u_i64(o->in2, regs[get_field(s, r2)]);
-}
-#define SPEC_in2_r2_32u 0
-
-static void in2_r2_sr32(DisasContext *s, DisasOps *o)
-{
-    o->in2 = tcg_temp_new_i64();
-    tcg_gen_shri_i64(o->in2, regs[get_field(s, r2)], 32);
-}
-#define SPEC_in2_r2_sr32 0
-
-static void in2_e2(DisasContext *s, DisasOps *o)
-{
-    o->in2 = load_freg32_i64(get_field(s, r2));
-}
-#define SPEC_in2_e2 0
-
-static void in2_f2(DisasContext *s, DisasOps *o)
-{
-    o->in2 = load_freg(get_field(s, r2));
-}
-#define SPEC_in2_f2 0
-
-/* Load the low double word of an extended (128-bit) format FP number */
-static void in2_x2l(DisasContext *s, DisasOps *o)
-{
-    o->in2 = load_freg(get_field(s, r2) + 2);
-}
-#define SPEC_in2_x2l SPEC_r2_f128
-
-static void in2_ra2(DisasContext *s, DisasOps *o)
-{
-    int r2 = get_field(s, r2);
-
-    /* Note: *don't* treat !r2 as 0, use the reg value. */
-    o->in2 = tcg_temp_new_i64();
-    gen_addi_and_wrap_i64(s, o->in2, regs[r2], 0);
-}
-#define SPEC_in2_ra2 0
-
-static void in2_a2(DisasContext *s, DisasOps *o)
-{
-    int x2 = have_field(s, x2) ? get_field(s, x2) : 0;
-    o->in2 = get_address(s, x2, get_field(s, b2), get_field(s, d2));
-}
-#define SPEC_in2_a2 0
-
-static void in2_ri2(DisasContext *s, DisasOps *o)
-{
-    o->in2 = tcg_const_i64(s->base.pc_next + (int64_t)get_field(s, i2) * 2);
-}
-#define SPEC_in2_ri2 0
-
-static void in2_sh32(DisasContext *s, DisasOps *o)
-{
-    help_l2_shift(s, o, 31);
-}
-#define SPEC_in2_sh32 0
-
-static void in2_sh64(DisasContext *s, DisasOps *o)
-{
-    help_l2_shift(s, o, 63);
-}
-#define SPEC_in2_sh64 0
-
-static void in2_m2_8u(DisasContext *s, DisasOps *o)
-{
-    in2_a2(s, o);
-    tcg_gen_qemu_ld8u(o->in2, o->in2, get_mem_index(s));
-}
-#define SPEC_in2_m2_8u 0
-
-static void in2_m2_16s(DisasContext *s, DisasOps *o)
-{
-    in2_a2(s, o);
-    tcg_gen_qemu_ld16s(o->in2, o->in2, get_mem_index(s));
-}
-#define SPEC_in2_m2_16s 0
-
-static void in2_m2_16u(DisasContext *s, DisasOps *o)
-{
-    in2_a2(s, o);
-    tcg_gen_qemu_ld16u(o->in2, o->in2, get_mem_index(s));
-}
-#define SPEC_in2_m2_16u 0
-
-static void in2_m2_32s(DisasContext *s, DisasOps *o)
-{
-    in2_a2(s, o);
-    tcg_gen_qemu_ld32s(o->in2, o->in2, get_mem_index(s));
-}
-#define SPEC_in2_m2_32s 0
-
-static void in2_m2_32u(DisasContext *s, DisasOps *o)
-{
-    in2_a2(s, o);
-    tcg_gen_qemu_ld32u(o->in2, o->in2, get_mem_index(s));
-}
-#define SPEC_in2_m2_32u 0
-
-#ifndef CONFIG_USER_ONLY
-static void in2_m2_32ua(DisasContext *s, DisasOps *o)
-{
-    in2_a2(s, o);
-    tcg_gen_qemu_ld_tl(o->in2, o->in2, get_mem_index(s), MO_TEUL | MO_ALIGN);
-}
-#define SPEC_in2_m2_32ua 0
-#endif
-
-static void in2_m2_64(DisasContext *s, DisasOps *o)
-{
-    in2_a2(s, o);
-    tcg_gen_qemu_ld64(o->in2, o->in2, get_mem_index(s));
-}
-#define SPEC_in2_m2_64 0
-
-static void in2_m2_64w(DisasContext *s, DisasOps *o)
-{
-    in2_a2(s, o);
-    tcg_gen_qemu_ld64(o->in2, o->in2, get_mem_index(s));
-    gen_addi_and_wrap_i64(s, o->in2, o->in2, 0);
-}
-#define SPEC_in2_m2_64w 0
-
-#ifndef CONFIG_USER_ONLY
-static void in2_m2_64a(DisasContext *s, DisasOps *o)
-{
-    in2_a2(s, o);
-    tcg_gen_qemu_ld_i64(o->in2, o->in2, get_mem_index(s), MO_TEQ | MO_ALIGN);
-}
-#define SPEC_in2_m2_64a 0
-#endif
-
-static void in2_mri2_16u(DisasContext *s, DisasOps *o)
-{
-    in2_ri2(s, o);
-    tcg_gen_qemu_ld16u(o->in2, o->in2, get_mem_index(s));
-}
-#define SPEC_in2_mri2_16u 0
-
-static void in2_mri2_32s(DisasContext *s, DisasOps *o)
-{
-    in2_ri2(s, o);
-    tcg_gen_qemu_ld32s(o->in2, o->in2, get_mem_index(s));
-}
-#define SPEC_in2_mri2_32s 0
-
-static void in2_mri2_32u(DisasContext *s, DisasOps *o)
-{
-    in2_ri2(s, o);
-    tcg_gen_qemu_ld32u(o->in2, o->in2, get_mem_index(s));
-}
-#define SPEC_in2_mri2_32u 0
-
-static void in2_mri2_64(DisasContext *s, DisasOps *o)
-{
-    in2_ri2(s, o);
-    tcg_gen_qemu_ld64(o->in2, o->in2, get_mem_index(s));
-}
-#define SPEC_in2_mri2_64 0
-
-static void in2_i2(DisasContext *s, DisasOps *o)
-{
-    o->in2 = tcg_const_i64(get_field(s, i2));
-}
-#define SPEC_in2_i2 0
-
-static void in2_i2_8u(DisasContext *s, DisasOps *o)
-{
-    o->in2 = tcg_const_i64((uint8_t)get_field(s, i2));
-}
-#define SPEC_in2_i2_8u 0
-
-static void in2_i2_16u(DisasContext *s, DisasOps *o)
-{
-    o->in2 = tcg_const_i64((uint16_t)get_field(s, i2));
-}
-#define SPEC_in2_i2_16u 0
-
-static void in2_i2_32u(DisasContext *s, DisasOps *o)
-{
-    o->in2 = tcg_const_i64((uint32_t)get_field(s, i2));
-}
-#define SPEC_in2_i2_32u 0
-
-static void in2_i2_16u_shl(DisasContext *s, DisasOps *o)
-{
-    uint64_t i2 = (uint16_t)get_field(s, i2);
-    o->in2 = tcg_const_i64(i2 << s->insn->data);
-}
-#define SPEC_in2_i2_16u_shl 0
-
-static void in2_i2_32u_shl(DisasContext *s, DisasOps *o)
-{
-    uint64_t i2 = (uint32_t)get_field(s, i2);
-    o->in2 = tcg_const_i64(i2 << s->insn->data);
-}
-#define SPEC_in2_i2_32u_shl 0
-
-#ifndef CONFIG_USER_ONLY
-static void in2_insn(DisasContext *s, DisasOps *o)
-{
-    o->in2 = tcg_const_i64(s->fields.raw_insn);
-}
-#define SPEC_in2_insn 0
-#endif
-
-/* ====================================================================== */
-
-/* Find opc within the table of insns.  This is formulated as a switch
-   statement so that (1) we get compile-time notice of cut-paste errors
-   for duplicated opcodes, and (2) the compiler generates the binary
-   search tree, rather than us having to post-process the table.  */
-
-#define C(OPC, NM, FT, FC, I1, I2, P, W, OP, CC) \
-    E(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, 0, 0)
-
-#define D(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D) \
-    E(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D, 0)
-
-#define F(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, FL) \
-    E(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, 0, FL)
-
-#define E(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D, FL) insn_ ## NM,
-
-enum DisasInsnEnum {
-#include "insn-data.def"
-};
-
-#undef E
-#define E(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D, FL) {                   \
-    .opc = OPC,                                                             \
-    .flags = FL,                                                            \
-    .fmt = FMT_##FT,                                                        \
-    .fac = FAC_##FC,                                                        \
-    .spec = SPEC_in1_##I1 | SPEC_in2_##I2 | SPEC_prep_##P | SPEC_wout_##W,  \
-    .name = #NM,                                                            \
-    .help_in1 = in1_##I1,                                                   \
-    .help_in2 = in2_##I2,                                                   \
-    .help_prep = prep_##P,                                                  \
-    .help_wout = wout_##W,                                                  \
-    .help_cout = cout_##CC,                                                 \
-    .help_op = op_##OP,                                                     \
-    .data = D                                                               \
- },
-
-/* Allow 0 to be used for NULL in the table below.  */
-#define in1_0  NULL
-#define in2_0  NULL
-#define prep_0  NULL
-#define wout_0  NULL
-#define cout_0  NULL
-#define op_0  NULL
-
-#define SPEC_in1_0 0
-#define SPEC_in2_0 0
-#define SPEC_prep_0 0
-#define SPEC_wout_0 0
-
-/* Give smaller names to the various facilities.  */
-#define FAC_Z           S390_FEAT_ZARCH
-#define FAC_CASS        S390_FEAT_COMPARE_AND_SWAP_AND_STORE
-#define FAC_DFP         S390_FEAT_DFP
-#define FAC_DFPR        S390_FEAT_FLOATING_POINT_SUPPPORT_ENH /* DFP-rounding */
-#define FAC_DO          S390_FEAT_STFLE_45 /* distinct-operands */
-#define FAC_EE          S390_FEAT_EXECUTE_EXT
-#define FAC_EI          S390_FEAT_EXTENDED_IMMEDIATE
-#define FAC_FPE         S390_FEAT_FLOATING_POINT_EXT
-#define FAC_FPSSH       S390_FEAT_FLOATING_POINT_SUPPPORT_ENH /* FPS-sign-handling */
-#define FAC_FPRGR       S390_FEAT_FLOATING_POINT_SUPPPORT_ENH /* FPR-GR-transfer */
-#define FAC_GIE         S390_FEAT_GENERAL_INSTRUCTIONS_EXT
-#define FAC_HFP_MA      S390_FEAT_HFP_MADDSUB
-#define FAC_HW          S390_FEAT_STFLE_45 /* high-word */
-#define FAC_IEEEE_SIM   S390_FEAT_FLOATING_POINT_SUPPPORT_ENH /* IEEE-exception-simulation */
-#define FAC_MIE         S390_FEAT_STFLE_49 /* misc-instruction-extensions */
-#define FAC_LAT         S390_FEAT_STFLE_49 /* load-and-trap */
-#define FAC_LOC         S390_FEAT_STFLE_45 /* load/store on condition 1 */
-#define FAC_LOC2        S390_FEAT_STFLE_53 /* load/store on condition 2 */
-#define FAC_LD          S390_FEAT_LONG_DISPLACEMENT
-#define FAC_PC          S390_FEAT_STFLE_45 /* population count */
-#define FAC_SCF         S390_FEAT_STORE_CLOCK_FAST
-#define FAC_SFLE        S390_FEAT_STFLE
-#define FAC_ILA         S390_FEAT_STFLE_45 /* interlocked-access-facility 1 */
-#define FAC_MVCOS       S390_FEAT_MOVE_WITH_OPTIONAL_SPEC
-#define FAC_LPP         S390_FEAT_SET_PROGRAM_PARAMETERS /* load-program-parameter */
-#define FAC_DAT_ENH     S390_FEAT_DAT_ENH
-#define FAC_E2          S390_FEAT_EXTENDED_TRANSLATION_2
-#define FAC_EH          S390_FEAT_STFLE_49 /* execution-hint */
-#define FAC_PPA         S390_FEAT_STFLE_49 /* processor-assist */
-#define FAC_LZRB        S390_FEAT_STFLE_53 /* load-and-zero-rightmost-byte */
-#define FAC_ETF3        S390_FEAT_EXTENDED_TRANSLATION_3
-#define FAC_MSA         S390_FEAT_MSA /* message-security-assist facility */
-#define FAC_MSA3        S390_FEAT_MSA_EXT_3 /* msa-extension-3 facility */
-#define FAC_MSA4        S390_FEAT_MSA_EXT_4 /* msa-extension-4 facility */
-#define FAC_MSA5        S390_FEAT_MSA_EXT_5 /* msa-extension-5 facility */
-#define FAC_MSA8        S390_FEAT_MSA_EXT_8 /* msa-extension-8 facility */
-#define FAC_ECT         S390_FEAT_EXTRACT_CPU_TIME
-#define FAC_PCI         S390_FEAT_ZPCI /* z/PCI facility */
-#define FAC_AIS         S390_FEAT_ADAPTER_INT_SUPPRESSION
-#define FAC_V           S390_FEAT_VECTOR /* vector facility */
-#define FAC_VE          S390_FEAT_VECTOR_ENH /* vector enhancements facility 1 */
-#define FAC_MIE2        S390_FEAT_MISC_INSTRUCTION_EXT2 /* miscellaneous-instruction-extensions facility 2 */
-
-static const DisasInsn insn_info[] = {
-#include "insn-data.def"
-};
-
-#undef E
-#define E(OPC, NM, FT, FC, I1, I2, P, W, OP, CC, D, FL) \
-    case OPC: return &insn_info[insn_ ## NM];
-
-static const DisasInsn *lookup_opc(uint16_t opc)
-{
-    switch (opc) {
-#include "insn-data.def"
-    default:
-        return NULL;
-    }
-}
-
-#undef F
-#undef E
-#undef D
-#undef C
-
-/* Extract a field from the insn.  The INSN should be left-aligned in
-   the uint64_t so that we can more easily utilize the big-bit-endian
-   definitions we extract from the Principals of Operation.  */
-
-static void extract_field(DisasFields *o, const DisasField *f, uint64_t insn)
-{
-    uint32_t r, m;
-
-    if (f->size == 0) {
-        return;
-    }
-
-    /* Zero extract the field from the insn.  */
-    r = (insn << f->beg) >> (64 - f->size);
-
-    /* Sign-extend, or un-swap the field as necessary.  */
-    switch (f->type) {
-    case 0: /* unsigned */
-        break;
-    case 1: /* signed */
-        assert(f->size <= 32);
-        m = 1u << (f->size - 1);
-        r = (r ^ m) - m;
-        break;
-    case 2: /* dl+dh split, signed 20 bit. */
-        r = ((int8_t)r << 12) | (r >> 8);
-        break;
-    case 3: /* MSB stored in RXB */
-        g_assert(f->size == 4);
-        switch (f->beg) {
-        case 8:
-            r |= extract64(insn, 63 - 36, 1) << 4;
-            break;
-        case 12:
-            r |= extract64(insn, 63 - 37, 1) << 4;
-            break;
-        case 16:
-            r |= extract64(insn, 63 - 38, 1) << 4;
-            break;
-        case 32:
-            r |= extract64(insn, 63 - 39, 1) << 4;
-            break;
-        default:
-            g_assert_not_reached();
-        }
-        break;
-    default:
-        abort();
-    }
-
-    /*
-     * Validate that the "compressed" encoding we selected above is valid.
-     * I.e. we haven't made two different original fields overlap.
-     */
-    assert(((o->presentC >> f->indexC) & 1) == 0);
-    o->presentC |= 1 << f->indexC;
-    o->presentO |= 1 << f->indexO;
-
-    o->c[f->indexC] = r;
-}
-
-/* Lookup the insn at the current PC, extracting the operands into O and
-   returning the info struct for the insn.  Returns NULL for invalid insn.  */
-
-static const DisasInsn *extract_insn(CPUS390XState *env, DisasContext *s)
-{
-    uint64_t insn, pc = s->base.pc_next;
-    int op, op2, ilen;
-    const DisasInsn *info;
-
-    if (unlikely(s->ex_value)) {
-        /* Drop the EX data now, so that it's clear on exception paths.  */
-        TCGv_i64 zero = tcg_const_i64(0);
-        tcg_gen_st_i64(zero, cpu_env, offsetof(CPUS390XState, ex_value));
-        tcg_temp_free_i64(zero);
-
-        /* Extract the values saved by EXECUTE.  */
-        insn = s->ex_value & 0xffffffffffff0000ull;
-        ilen = s->ex_value & 0xf;
-        op = insn >> 56;
-    } else {
-        insn = ld_code2(env, pc);
-        op = (insn >> 8) & 0xff;
-        ilen = get_ilen(op);
-        switch (ilen) {
-        case 2:
-            insn = insn << 48;
-            break;
-        case 4:
-            insn = ld_code4(env, pc) << 32;
-            break;
-        case 6:
-            insn = (insn << 48) | (ld_code4(env, pc + 2) << 16);
-            break;
-        default:
-            g_assert_not_reached();
-        }
-    }
-    s->pc_tmp = s->base.pc_next + ilen;
-    s->ilen = ilen;
-
-    /* We can't actually determine the insn format until we've looked up
-       the full insn opcode.  Which we can't do without locating the
-       secondary opcode.  Assume by default that OP2 is at bit 40; for
-       those smaller insns that don't actually have a secondary opcode
-       this will correctly result in OP2 = 0. */
-    switch (op) {
-    case 0x01: /* E */
-    case 0x80: /* S */
-    case 0x82: /* S */
-    case 0x93: /* S */
-    case 0xb2: /* S, RRF, RRE, IE */
-    case 0xb3: /* RRE, RRD, RRF */
-    case 0xb9: /* RRE, RRF */
-    case 0xe5: /* SSE, SIL */
-        op2 = (insn << 8) >> 56;
-        break;
-    case 0xa5: /* RI */
-    case 0xa7: /* RI */
-    case 0xc0: /* RIL */
-    case 0xc2: /* RIL */
-    case 0xc4: /* RIL */
-    case 0xc6: /* RIL */
-    case 0xc8: /* SSF */
-    case 0xcc: /* RIL */
-        op2 = (insn << 12) >> 60;
-        break;
-    case 0xc5: /* MII */
-    case 0xc7: /* SMI */
-    case 0xd0 ... 0xdf: /* SS */
-    case 0xe1: /* SS */
-    case 0xe2: /* SS */
-    case 0xe8: /* SS */
-    case 0xe9: /* SS */
-    case 0xea: /* SS */
-    case 0xee ... 0xf3: /* SS */
-    case 0xf8 ... 0xfd: /* SS */
-        op2 = 0;
-        break;
-    default:
-        op2 = (insn << 40) >> 56;
-        break;
-    }
-
-    memset(&s->fields, 0, sizeof(s->fields));
-    s->fields.raw_insn = insn;
-    s->fields.op = op;
-    s->fields.op2 = op2;
-
-    /* Lookup the instruction.  */
-    info = lookup_opc(op << 8 | op2);
-    s->insn = info;
-
-    /* If we found it, extract the operands.  */
-    if (info != NULL) {
-        DisasFormat fmt = info->fmt;
-        int i;
-
-        for (i = 0; i < NUM_C_FIELD; ++i) {
-            extract_field(&s->fields, &format_info[fmt].op[i], insn);
-        }
-    }
-    return info;
-}
-
-static bool is_afp_reg(int reg)
-{
-    return reg % 2 || reg > 6;
-}
-
-static bool is_fp_pair(int reg)
-{
-    /* 0,1,4,5,8,9,12,13: to exclude the others, check for single bit */
-    return !(reg & 0x2);
-}
-
-static DisasJumpType translate_one(CPUS390XState *env, DisasContext *s)
-{
-    const DisasInsn *insn;
-    DisasJumpType ret = DISAS_NEXT;
-    DisasOps o = {};
-    bool icount = false;
-
-    /* Search for the insn in the table.  */
-    insn = extract_insn(env, s);
-
-    /* Emit insn_start now that we know the ILEN.  */
-    tcg_gen_insn_start(s->base.pc_next, s->cc_op, s->ilen);
-
-    /* Not found means unimplemented/illegal opcode.  */
-    if (insn == NULL) {
-        qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%02x%02x\n",
-                      s->fields.op, s->fields.op2);
-        gen_illegal_opcode(s);
-        ret = DISAS_NORETURN;
-        goto out;
-    }
-
-#ifndef CONFIG_USER_ONLY
-    if (s->base.tb->flags & FLAG_MASK_PER) {
-        TCGv_i64 addr = tcg_const_i64(s->base.pc_next);
-        gen_helper_per_ifetch(cpu_env, addr);
-        tcg_temp_free_i64(addr);
-    }
-#endif
-
-    /* process flags */
-    if (insn->flags) {
-        /* privileged instruction */
-        if ((s->base.tb->flags & FLAG_MASK_PSTATE) && (insn->flags & IF_PRIV)) {
-            gen_program_exception(s, PGM_PRIVILEGED);
-            ret = DISAS_NORETURN;
-            goto out;
-        }
-
-        /* if AFP is not enabled, instructions and registers are forbidden */
-        if (!(s->base.tb->flags & FLAG_MASK_AFP)) {
-            uint8_t dxc = 0;
-
-            if ((insn->flags & IF_AFP1) && is_afp_reg(get_field(s, r1))) {
-                dxc = 1;
-            }
-            if ((insn->flags & IF_AFP2) && is_afp_reg(get_field(s, r2))) {
-                dxc = 1;
-            }
-            if ((insn->flags & IF_AFP3) && is_afp_reg(get_field(s, r3))) {
-                dxc = 1;
-            }
-            if (insn->flags & IF_BFP) {
-                dxc = 2;
-            }
-            if (insn->flags & IF_DFP) {
-                dxc = 3;
-            }
-            if (insn->flags & IF_VEC) {
-                dxc = 0xfe;
-            }
-            if (dxc) {
-                gen_data_exception(dxc);
-                ret = DISAS_NORETURN;
-                goto out;
-            }
-        }
-
-        /* if vector instructions not enabled, executing them is forbidden */
-        if (insn->flags & IF_VEC) {
-            if (!((s->base.tb->flags & FLAG_MASK_VECTOR))) {
-                gen_data_exception(0xfe);
-                ret = DISAS_NORETURN;
-                goto out;
-            }
-        }
-
-        /* input/output is the special case for icount mode */
-        if (unlikely(insn->flags & IF_IO)) {
-            icount = tb_cflags(s->base.tb) & CF_USE_ICOUNT;
-            if (icount) {
-                gen_io_start();
-            }
-        }
-    }
-
-    /* Check for insn specification exceptions.  */
-    if (insn->spec) {
-        if ((insn->spec & SPEC_r1_even && get_field(s, r1) & 1) ||
-            (insn->spec & SPEC_r2_even && get_field(s, r2) & 1) ||
-            (insn->spec & SPEC_r3_even && get_field(s, r3) & 1) ||
-            (insn->spec & SPEC_r1_f128 && !is_fp_pair(get_field(s, r1))) ||
-            (insn->spec & SPEC_r2_f128 && !is_fp_pair(get_field(s, r2)))) {
-            gen_program_exception(s, PGM_SPECIFICATION);
-            ret = DISAS_NORETURN;
-            goto out;
-        }
-    }
-
-    /* Implement the instruction.  */
-    if (insn->help_in1) {
-        insn->help_in1(s, &o);
-    }
-    if (insn->help_in2) {
-        insn->help_in2(s, &o);
-    }
-    if (insn->help_prep) {
-        insn->help_prep(s, &o);
-    }
-    if (insn->help_op) {
-        ret = insn->help_op(s, &o);
-    }
-    if (ret != DISAS_NORETURN) {
-        if (insn->help_wout) {
-            insn->help_wout(s, &o);
-        }
-        if (insn->help_cout) {
-            insn->help_cout(s, &o);
-        }
-    }
-
-    /* Free any temporaries created by the helpers.  */
-    if (o.out && !o.g_out) {
-        tcg_temp_free_i64(o.out);
-    }
-    if (o.out2 && !o.g_out2) {
-        tcg_temp_free_i64(o.out2);
-    }
-    if (o.in1 && !o.g_in1) {
-        tcg_temp_free_i64(o.in1);
-    }
-    if (o.in2 && !o.g_in2) {
-        tcg_temp_free_i64(o.in2);
-    }
-    if (o.addr1) {
-        tcg_temp_free_i64(o.addr1);
-    }
-
-    /* io should be the last instruction in tb when icount is enabled */
-    if (unlikely(icount && ret == DISAS_NEXT)) {
-        ret = DISAS_PC_STALE;
-    }
-
-#ifndef CONFIG_USER_ONLY
-    if (s->base.tb->flags & FLAG_MASK_PER) {
-        /* An exception might be triggered, save PSW if not already done.  */
-        if (ret == DISAS_NEXT || ret == DISAS_PC_STALE) {
-            tcg_gen_movi_i64(psw_addr, s->pc_tmp);
-        }
-
-        /* Call the helper to check for a possible PER exception.  */
-        gen_helper_per_check_exception(cpu_env);
-    }
-#endif
-
-out:
-    /* Advance to the next instruction.  */
-    s->base.pc_next = s->pc_tmp;
-    return ret;
-}
-
-static void s390x_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
-{
-    DisasContext *dc = container_of(dcbase, DisasContext, base);
-
-    /* 31-bit mode */
-    if (!(dc->base.tb->flags & FLAG_MASK_64)) {
-        dc->base.pc_first &= 0x7fffffff;
-        dc->base.pc_next = dc->base.pc_first;
-    }
-
-    dc->cc_op = CC_OP_DYNAMIC;
-    dc->ex_value = dc->base.tb->cs_base;
-    dc->do_debug = dc->base.singlestep_enabled;
-}
-
-static void s390x_tr_tb_start(DisasContextBase *db, CPUState *cs)
-{
-}
-
-static void s390x_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
-{
-}
-
-static bool s390x_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs,
-                                      const CPUBreakpoint *bp)
-{
-    DisasContext *dc = container_of(dcbase, DisasContext, base);
-
-    /*
-     * Emit an insn_start to accompany the breakpoint exception.
-     * The ILEN value is a dummy, since this does not result in
-     * an s390x exception, but an internal qemu exception which
-     * brings us back to interact with the gdbstub.
-     */
-    tcg_gen_insn_start(dc->base.pc_next, dc->cc_op, 2);
-
-    dc->base.is_jmp = DISAS_PC_STALE;
-    dc->do_debug = true;
-    /* The address covered by the breakpoint must be included in
-       [tb->pc, tb->pc + tb->size) in order to for it to be
-       properly cleared -- thus we increment the PC here so that
-       the logic setting tb->size does the right thing.  */
-    dc->base.pc_next += 2;
-    return true;
-}
-
-static void s390x_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
-{
-    CPUS390XState *env = cs->env_ptr;
-    DisasContext *dc = container_of(dcbase, DisasContext, base);
-
-    dc->base.is_jmp = translate_one(env, dc);
-    if (dc->base.is_jmp == DISAS_NEXT) {
-        uint64_t page_start;
-
-        page_start = dc->base.pc_first & TARGET_PAGE_MASK;
-        if (dc->base.pc_next - page_start >= TARGET_PAGE_SIZE || dc->ex_value) {
-            dc->base.is_jmp = DISAS_TOO_MANY;
-        }
-    }
-}
-
-static void s390x_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
-{
-    DisasContext *dc = container_of(dcbase, DisasContext, base);
-
-    switch (dc->base.is_jmp) {
-    case DISAS_GOTO_TB:
-    case DISAS_NORETURN:
-        break;
-    case DISAS_TOO_MANY:
-    case DISAS_PC_STALE:
-    case DISAS_PC_STALE_NOCHAIN:
-        update_psw_addr(dc);
-        /* FALLTHRU */
-    case DISAS_PC_UPDATED:
-        /* Next TB starts off with CC_OP_DYNAMIC, so make sure the
-           cc op type is in env */
-        update_cc_op(dc);
-        /* FALLTHRU */
-    case DISAS_PC_CC_UPDATED:
-        /* Exit the TB, either by raising a debug exception or by return.  */
-        if (dc->do_debug) {
-            gen_exception(EXCP_DEBUG);
-        } else if ((dc->base.tb->flags & FLAG_MASK_PER) ||
-                   dc->base.is_jmp == DISAS_PC_STALE_NOCHAIN) {
-            tcg_gen_exit_tb(NULL, 0);
-        } else {
-            tcg_gen_lookup_and_goto_ptr();
-        }
-        break;
-    default:
-        g_assert_not_reached();
-    }
-}
-
-static void s390x_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs)
-{
-    DisasContext *dc = container_of(dcbase, DisasContext, base);
-
-    if (unlikely(dc->ex_value)) {
-        /* ??? Unfortunately log_target_disas can't use host memory.  */
-        qemu_log("IN: EXECUTE %016" PRIx64, dc->ex_value);
-    } else {
-        qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
-        log_target_disas(cs, dc->base.pc_first, dc->base.tb->size);
-    }
-}
-
-static const TranslatorOps s390x_tr_ops = {
-    .init_disas_context = s390x_tr_init_disas_context,
-    .tb_start           = s390x_tr_tb_start,
-    .insn_start         = s390x_tr_insn_start,
-    .breakpoint_check   = s390x_tr_breakpoint_check,
-    .translate_insn     = s390x_tr_translate_insn,
-    .tb_stop            = s390x_tr_tb_stop,
-    .disas_log          = s390x_tr_disas_log,
-};
-
-void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
-{
-    DisasContext dc;
-
-    translator_loop(&s390x_tr_ops, &dc.base, cs, tb, max_insns);
-}
-
-void restore_state_to_opc(CPUS390XState *env, TranslationBlock *tb,
-                          target_ulong *data)
-{
-    int cc_op = data[1];
-
-    env->psw.addr = data[0];
-
-    /* Update the CC opcode if it is not already up-to-date.  */
-    if ((cc_op != CC_OP_DYNAMIC) && (cc_op != CC_OP_STATIC)) {
-        env->cc_op = cc_op;
-    }
-
-    /* Record ILEN.  */
-    env->int_pgm_ilen = data[2];
-}
diff --git a/target/s390x/translate_vx.c.inc b/target/s390x/translate_vx.c.inc
deleted file mode 100644 (file)
index a9d51b1..0000000
+++ /dev/null
@@ -1,3109 +0,0 @@
-/*
- * QEMU TCG support -- s390x vector instruction translation functions
- *
- * Copyright (C) 2019 Red Hat Inc
- *
- * Authors:
- *   David Hildenbrand <david@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-/*
- * For most instructions that use the same element size for reads and
- * writes, we can use real gvec vector expansion, which potantially uses
- * real host vector instructions. As they only work up to 64 bit elements,
- * 128 bit elements (vector is a single element) have to be handled
- * differently. Operations that are too complicated to encode via TCG ops
- * are handled via gvec ool (out-of-line) handlers.
- *
- * As soon as instructions use different element sizes for reads and writes
- * or access elements "out of their element scope" we expand them manually
- * in fancy loops, as gvec expansion does not deal with actual element
- * numbers and does also not support access to other elements.
- *
- * 128 bit elements:
- *  As we only have i32/i64, such elements have to be loaded into two
- *  i64 values and can then be processed e.g. by tcg_gen_add2_i64.
- *
- * Sizes:
- *  On s390x, the operand size (oprsz) and the maximum size (maxsz) are
- *  always 16 (128 bit). What gvec code calls "vece", s390x calls "es",
- *  a.k.a. "element size". These values nicely map to MO_8 ... MO_64. Only
- *  128 bit element size has to be treated in a special way (MO_64 + 1).
- *  We will use ES_* instead of MO_* for this reason in this file.
- *
- * CC handling:
- *  As gvec ool-helpers can currently not return values (besides via
- *  pointers like vectors or cpu_env), whenever we have to set the CC and
- *  can't conclude the value from the result vector, we will directly
- *  set it in "env->cc_op" and mark it as static via set_cc_static()".
- *  Whenever this is done, the helper writes globals (cc_op).
- */
-
-#define NUM_VEC_ELEMENT_BYTES(es) (1 << (es))
-#define NUM_VEC_ELEMENTS(es) (16 / NUM_VEC_ELEMENT_BYTES(es))
-#define NUM_VEC_ELEMENT_BITS(es) (NUM_VEC_ELEMENT_BYTES(es) * BITS_PER_BYTE)
-
-#define ES_8    MO_8
-#define ES_16   MO_16
-#define ES_32   MO_32
-#define ES_64   MO_64
-#define ES_128  4
-
-/* Floating-Point Format */
-#define FPF_SHORT       2
-#define FPF_LONG        3
-#define FPF_EXT         4
-
-static inline bool valid_vec_element(uint8_t enr, MemOp es)
-{
-    return !(enr & ~(NUM_VEC_ELEMENTS(es) - 1));
-}
-
-static void read_vec_element_i64(TCGv_i64 dst, uint8_t reg, uint8_t enr,
-                                 MemOp memop)
-{
-    const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
-
-    switch (memop) {
-    case ES_8:
-        tcg_gen_ld8u_i64(dst, cpu_env, offs);
-        break;
-    case ES_16:
-        tcg_gen_ld16u_i64(dst, cpu_env, offs);
-        break;
-    case ES_32:
-        tcg_gen_ld32u_i64(dst, cpu_env, offs);
-        break;
-    case ES_8 | MO_SIGN:
-        tcg_gen_ld8s_i64(dst, cpu_env, offs);
-        break;
-    case ES_16 | MO_SIGN:
-        tcg_gen_ld16s_i64(dst, cpu_env, offs);
-        break;
-    case ES_32 | MO_SIGN:
-        tcg_gen_ld32s_i64(dst, cpu_env, offs);
-        break;
-    case ES_64:
-    case ES_64 | MO_SIGN:
-        tcg_gen_ld_i64(dst, cpu_env, offs);
-        break;
-    default:
-        g_assert_not_reached();
-    }
-}
-
-static void read_vec_element_i32(TCGv_i32 dst, uint8_t reg, uint8_t enr,
-                                 MemOp memop)
-{
-    const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
-
-    switch (memop) {
-    case ES_8:
-        tcg_gen_ld8u_i32(dst, cpu_env, offs);
-        break;
-    case ES_16:
-        tcg_gen_ld16u_i32(dst, cpu_env, offs);
-        break;
-    case ES_8 | MO_SIGN:
-        tcg_gen_ld8s_i32(dst, cpu_env, offs);
-        break;
-    case ES_16 | MO_SIGN:
-        tcg_gen_ld16s_i32(dst, cpu_env, offs);
-        break;
-    case ES_32:
-    case ES_32 | MO_SIGN:
-        tcg_gen_ld_i32(dst, cpu_env, offs);
-        break;
-    default:
-        g_assert_not_reached();
-    }
-}
-
-static void write_vec_element_i64(TCGv_i64 src, int reg, uint8_t enr,
-                                  MemOp memop)
-{
-    const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
-
-    switch (memop) {
-    case ES_8:
-        tcg_gen_st8_i64(src, cpu_env, offs);
-        break;
-    case ES_16:
-        tcg_gen_st16_i64(src, cpu_env, offs);
-        break;
-    case ES_32:
-        tcg_gen_st32_i64(src, cpu_env, offs);
-        break;
-    case ES_64:
-        tcg_gen_st_i64(src, cpu_env, offs);
-        break;
-    default:
-        g_assert_not_reached();
-    }
-}
-
-static void write_vec_element_i32(TCGv_i32 src, int reg, uint8_t enr,
-                                  MemOp memop)
-{
-    const int offs = vec_reg_offset(reg, enr, memop & MO_SIZE);
-
-    switch (memop) {
-    case ES_8:
-        tcg_gen_st8_i32(src, cpu_env, offs);
-        break;
-    case ES_16:
-        tcg_gen_st16_i32(src, cpu_env, offs);
-        break;
-    case ES_32:
-        tcg_gen_st_i32(src, cpu_env, offs);
-        break;
-    default:
-        g_assert_not_reached();
-    }
-}
-
-static void get_vec_element_ptr_i64(TCGv_ptr ptr, uint8_t reg, TCGv_i64 enr,
-                                    uint8_t es)
-{
-    TCGv_i64 tmp = tcg_temp_new_i64();
-
-    /* mask off invalid parts from the element nr */
-    tcg_gen_andi_i64(tmp, enr, NUM_VEC_ELEMENTS(es) - 1);
-
-    /* convert it to an element offset relative to cpu_env (vec_reg_offset() */
-    tcg_gen_shli_i64(tmp, tmp, es);
-#ifndef HOST_WORDS_BIGENDIAN
-    tcg_gen_xori_i64(tmp, tmp, 8 - NUM_VEC_ELEMENT_BYTES(es));
-#endif
-    tcg_gen_addi_i64(tmp, tmp, vec_full_reg_offset(reg));
-
-    /* generate the final ptr by adding cpu_env */
-    tcg_gen_trunc_i64_ptr(ptr, tmp);
-    tcg_gen_add_ptr(ptr, ptr, cpu_env);
-
-    tcg_temp_free_i64(tmp);
-}
-
-#define gen_gvec_2(v1, v2, gen) \
-    tcg_gen_gvec_2(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
-                   16, 16, gen)
-#define gen_gvec_2s(v1, v2, c, gen) \
-    tcg_gen_gvec_2s(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
-                    16, 16, c, gen)
-#define gen_gvec_2_ool(v1, v2, data, fn) \
-    tcg_gen_gvec_2_ool(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
-                       16, 16, data, fn)
-#define gen_gvec_2i_ool(v1, v2, c, data, fn) \
-    tcg_gen_gvec_2i_ool(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
-                        c, 16, 16, data, fn)
-#define gen_gvec_2_ptr(v1, v2, ptr, data, fn) \
-    tcg_gen_gvec_2_ptr(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
-                       ptr, 16, 16, data, fn)
-#define gen_gvec_3(v1, v2, v3, gen) \
-    tcg_gen_gvec_3(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
-                   vec_full_reg_offset(v3), 16, 16, gen)
-#define gen_gvec_3_ool(v1, v2, v3, data, fn) \
-    tcg_gen_gvec_3_ool(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
-                       vec_full_reg_offset(v3), 16, 16, data, fn)
-#define gen_gvec_3_ptr(v1, v2, v3, ptr, data, fn) \
-    tcg_gen_gvec_3_ptr(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
-                       vec_full_reg_offset(v3), ptr, 16, 16, data, fn)
-#define gen_gvec_3i(v1, v2, v3, c, gen) \
-    tcg_gen_gvec_3i(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
-                    vec_full_reg_offset(v3), 16, 16, c, gen)
-#define gen_gvec_4(v1, v2, v3, v4, gen) \
-    tcg_gen_gvec_4(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
-                   vec_full_reg_offset(v3), vec_full_reg_offset(v4), \
-                   16, 16, gen)
-#define gen_gvec_4_ool(v1, v2, v3, v4, data, fn) \
-    tcg_gen_gvec_4_ool(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
-                       vec_full_reg_offset(v3), vec_full_reg_offset(v4), \
-                       16, 16, data, fn)
-#define gen_gvec_4_ptr(v1, v2, v3, v4, ptr, data, fn) \
-    tcg_gen_gvec_4_ptr(vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
-                       vec_full_reg_offset(v3), vec_full_reg_offset(v4), \
-                       ptr, 16, 16, data, fn)
-#define gen_gvec_dup_i64(es, v1, c) \
-    tcg_gen_gvec_dup_i64(es, vec_full_reg_offset(v1), 16, 16, c)
-#define gen_gvec_mov(v1, v2) \
-    tcg_gen_gvec_mov(0, vec_full_reg_offset(v1), vec_full_reg_offset(v2), 16, \
-                     16)
-#define gen_gvec_dup_imm(es, v1, c) \
-    tcg_gen_gvec_dup_imm(es, vec_full_reg_offset(v1), 16, 16, c);
-#define gen_gvec_fn_2(fn, es, v1, v2) \
-    tcg_gen_gvec_##fn(es, vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
-                      16, 16)
-#define gen_gvec_fn_2i(fn, es, v1, v2, c) \
-    tcg_gen_gvec_##fn(es, vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
-                      c, 16, 16)
-#define gen_gvec_fn_2s(fn, es, v1, v2, s) \
-    tcg_gen_gvec_##fn(es, vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
-                      s, 16, 16)
-#define gen_gvec_fn_3(fn, es, v1, v2, v3) \
-    tcg_gen_gvec_##fn(es, vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
-                      vec_full_reg_offset(v3), 16, 16)
-#define gen_gvec_fn_4(fn, es, v1, v2, v3, v4) \
-    tcg_gen_gvec_##fn(es, vec_full_reg_offset(v1), vec_full_reg_offset(v2), \
-                      vec_full_reg_offset(v3), vec_full_reg_offset(v4), 16, 16)
-
-/*
- * Helper to carry out a 128 bit vector computation using 2 i64 values per
- * vector.
- */
-typedef void (*gen_gvec128_3_i64_fn)(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
-                                     TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh);
-static void gen_gvec128_3_i64(gen_gvec128_3_i64_fn fn, uint8_t d, uint8_t a,
-                              uint8_t b)
-{
-        TCGv_i64 dh = tcg_temp_new_i64();
-        TCGv_i64 dl = tcg_temp_new_i64();
-        TCGv_i64 ah = tcg_temp_new_i64();
-        TCGv_i64 al = tcg_temp_new_i64();
-        TCGv_i64 bh = tcg_temp_new_i64();
-        TCGv_i64 bl = tcg_temp_new_i64();
-
-        read_vec_element_i64(ah, a, 0, ES_64);
-        read_vec_element_i64(al, a, 1, ES_64);
-        read_vec_element_i64(bh, b, 0, ES_64);
-        read_vec_element_i64(bl, b, 1, ES_64);
-        fn(dl, dh, al, ah, bl, bh);
-        write_vec_element_i64(dh, d, 0, ES_64);
-        write_vec_element_i64(dl, d, 1, ES_64);
-
-        tcg_temp_free_i64(dh);
-        tcg_temp_free_i64(dl);
-        tcg_temp_free_i64(ah);
-        tcg_temp_free_i64(al);
-        tcg_temp_free_i64(bh);
-        tcg_temp_free_i64(bl);
-}
-
-typedef void (*gen_gvec128_4_i64_fn)(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
-                                     TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh,
-                                     TCGv_i64 cl, TCGv_i64 ch);
-static void gen_gvec128_4_i64(gen_gvec128_4_i64_fn fn, uint8_t d, uint8_t a,
-                              uint8_t b, uint8_t c)
-{
-        TCGv_i64 dh = tcg_temp_new_i64();
-        TCGv_i64 dl = tcg_temp_new_i64();
-        TCGv_i64 ah = tcg_temp_new_i64();
-        TCGv_i64 al = tcg_temp_new_i64();
-        TCGv_i64 bh = tcg_temp_new_i64();
-        TCGv_i64 bl = tcg_temp_new_i64();
-        TCGv_i64 ch = tcg_temp_new_i64();
-        TCGv_i64 cl = tcg_temp_new_i64();
-
-        read_vec_element_i64(ah, a, 0, ES_64);
-        read_vec_element_i64(al, a, 1, ES_64);
-        read_vec_element_i64(bh, b, 0, ES_64);
-        read_vec_element_i64(bl, b, 1, ES_64);
-        read_vec_element_i64(ch, c, 0, ES_64);
-        read_vec_element_i64(cl, c, 1, ES_64);
-        fn(dl, dh, al, ah, bl, bh, cl, ch);
-        write_vec_element_i64(dh, d, 0, ES_64);
-        write_vec_element_i64(dl, d, 1, ES_64);
-
-        tcg_temp_free_i64(dh);
-        tcg_temp_free_i64(dl);
-        tcg_temp_free_i64(ah);
-        tcg_temp_free_i64(al);
-        tcg_temp_free_i64(bh);
-        tcg_temp_free_i64(bl);
-        tcg_temp_free_i64(ch);
-        tcg_temp_free_i64(cl);
-}
-
-static void gen_addi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
-                          uint64_t b)
-{
-    TCGv_i64 bl = tcg_const_i64(b);
-    TCGv_i64 bh = tcg_const_i64(0);
-
-    tcg_gen_add2_i64(dl, dh, al, ah, bl, bh);
-    tcg_temp_free_i64(bl);
-    tcg_temp_free_i64(bh);
-}
-
-static DisasJumpType op_vbperm(DisasContext *s, DisasOps *o)
-{
-    gen_gvec_3_ool(get_field(s, v1), get_field(s, v2), get_field(s, v3), 0,
-                   gen_helper_gvec_vbperm);
-
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vge(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = s->insn->data;
-    const uint8_t enr = get_field(s, m3);
-    TCGv_i64 tmp;
-
-    if (!valid_vec_element(enr, es)) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    tmp = tcg_temp_new_i64();
-    read_vec_element_i64(tmp, get_field(s, v2), enr, es);
-    tcg_gen_add_i64(o->addr1, o->addr1, tmp);
-    gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 0);
-
-    tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
-    write_vec_element_i64(tmp, get_field(s, v1), enr, es);
-    tcg_temp_free_i64(tmp);
-    return DISAS_NEXT;
-}
-
-static uint64_t generate_byte_mask(uint8_t mask)
-{
-    uint64_t r = 0;
-    int i;
-
-    for (i = 0; i < 8; i++) {
-        if ((mask >> i) & 1) {
-            r |= 0xffull << (i * 8);
-        }
-    }
-    return r;
-}
-
-static DisasJumpType op_vgbm(DisasContext *s, DisasOps *o)
-{
-    const uint16_t i2 = get_field(s, i2);
-
-    if (i2 == (i2 & 0xff) * 0x0101) {
-        /*
-         * Masks for both 64 bit elements of the vector are the same.
-         * Trust tcg to produce a good constant loading.
-         */
-        gen_gvec_dup_imm(ES_64, get_field(s, v1),
-                         generate_byte_mask(i2 & 0xff));
-    } else {
-        TCGv_i64 t = tcg_temp_new_i64();
-
-        tcg_gen_movi_i64(t, generate_byte_mask(i2 >> 8));
-        write_vec_element_i64(t, get_field(s, v1), 0, ES_64);
-        tcg_gen_movi_i64(t, generate_byte_mask(i2));
-        write_vec_element_i64(t, get_field(s, v1), 1, ES_64);
-        tcg_temp_free_i64(t);
-    }
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vgm(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m4);
-    const uint8_t bits = NUM_VEC_ELEMENT_BITS(es);
-    const uint8_t i2 = get_field(s, i2) & (bits - 1);
-    const uint8_t i3 = get_field(s, i3) & (bits - 1);
-    uint64_t mask = 0;
-    int i;
-
-    if (es > ES_64) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    /* generate the mask - take care of wrapping */
-    for (i = i2; ; i = (i + 1) % bits) {
-        mask |= 1ull << (bits - i - 1);
-        if (i == i3) {
-            break;
-        }
-    }
-
-    gen_gvec_dup_imm(es, get_field(s, v1), mask);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vl(DisasContext *s, DisasOps *o)
-{
-    TCGv_i64 t0 = tcg_temp_new_i64();
-    TCGv_i64 t1 = tcg_temp_new_i64();
-
-    tcg_gen_qemu_ld_i64(t0, o->addr1, get_mem_index(s), MO_TEQ);
-    gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
-    tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEQ);
-    write_vec_element_i64(t0, get_field(s, v1), 0, ES_64);
-    write_vec_element_i64(t1, get_field(s, v1), 1, ES_64);
-    tcg_temp_free(t0);
-    tcg_temp_free(t1);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vlr(DisasContext *s, DisasOps *o)
-{
-    gen_gvec_mov(get_field(s, v1), get_field(s, v2));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vlrep(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m3);
-    TCGv_i64 tmp;
-
-    if (es > ES_64) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    tmp = tcg_temp_new_i64();
-    tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
-    gen_gvec_dup_i64(es, get_field(s, v1), tmp);
-    tcg_temp_free_i64(tmp);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vle(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = s->insn->data;
-    const uint8_t enr = get_field(s, m3);
-    TCGv_i64 tmp;
-
-    if (!valid_vec_element(enr, es)) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    tmp = tcg_temp_new_i64();
-    tcg_gen_qemu_ld_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
-    write_vec_element_i64(tmp, get_field(s, v1), enr, es);
-    tcg_temp_free_i64(tmp);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vlei(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = s->insn->data;
-    const uint8_t enr = get_field(s, m3);
-    TCGv_i64 tmp;
-
-    if (!valid_vec_element(enr, es)) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    tmp = tcg_const_i64((int16_t)get_field(s, i2));
-    write_vec_element_i64(tmp, get_field(s, v1), enr, es);
-    tcg_temp_free_i64(tmp);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vlgv(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m4);
-    TCGv_ptr ptr;
-
-    if (es > ES_64) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    /* fast path if we don't need the register content */
-    if (!get_field(s, b2)) {
-        uint8_t enr = get_field(s, d2) & (NUM_VEC_ELEMENTS(es) - 1);
-
-        read_vec_element_i64(o->out, get_field(s, v3), enr, es);
-        return DISAS_NEXT;
-    }
-
-    ptr = tcg_temp_new_ptr();
-    get_vec_element_ptr_i64(ptr, get_field(s, v3), o->addr1, es);
-    switch (es) {
-    case ES_8:
-        tcg_gen_ld8u_i64(o->out, ptr, 0);
-        break;
-    case ES_16:
-        tcg_gen_ld16u_i64(o->out, ptr, 0);
-        break;
-    case ES_32:
-        tcg_gen_ld32u_i64(o->out, ptr, 0);
-        break;
-    case ES_64:
-        tcg_gen_ld_i64(o->out, ptr, 0);
-        break;
-    default:
-        g_assert_not_reached();
-    }
-    tcg_temp_free_ptr(ptr);
-
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vllez(DisasContext *s, DisasOps *o)
-{
-    uint8_t es = get_field(s, m3);
-    uint8_t enr;
-    TCGv_i64 t;
-
-    switch (es) {
-    /* rightmost sub-element of leftmost doubleword */
-    case ES_8:
-        enr = 7;
-        break;
-    case ES_16:
-        enr = 3;
-        break;
-    case ES_32:
-        enr = 1;
-        break;
-    case ES_64:
-        enr = 0;
-        break;
-    /* leftmost sub-element of leftmost doubleword */
-    case 6:
-        if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
-            es = ES_32;
-            enr = 0;
-            break;
-        }
-        /* fallthrough */
-    default:
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    t = tcg_temp_new_i64();
-    tcg_gen_qemu_ld_i64(t, o->addr1, get_mem_index(s), MO_TE | es);
-    gen_gvec_dup_imm(es, get_field(s, v1), 0);
-    write_vec_element_i64(t, get_field(s, v1), enr, es);
-    tcg_temp_free_i64(t);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vlm(DisasContext *s, DisasOps *o)
-{
-    const uint8_t v3 = get_field(s, v3);
-    uint8_t v1 = get_field(s, v1);
-    TCGv_i64 t0, t1;
-
-    if (v3 < v1 || (v3 - v1 + 1) > 16) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    /*
-     * Check for possible access exceptions by trying to load the last
-     * element. The first element will be checked first next.
-     */
-    t0 = tcg_temp_new_i64();
-    t1 = tcg_temp_new_i64();
-    gen_addi_and_wrap_i64(s, t0, o->addr1, (v3 - v1) * 16 + 8);
-    tcg_gen_qemu_ld_i64(t0, t0, get_mem_index(s), MO_TEQ);
-
-    for (;; v1++) {
-        tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEQ);
-        write_vec_element_i64(t1, v1, 0, ES_64);
-        if (v1 == v3) {
-            break;
-        }
-        gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
-        tcg_gen_qemu_ld_i64(t1, o->addr1, get_mem_index(s), MO_TEQ);
-        write_vec_element_i64(t1, v1, 1, ES_64);
-        gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
-    }
-
-    /* Store the last element, loaded first */
-    write_vec_element_i64(t0, v1, 1, ES_64);
-
-    tcg_temp_free_i64(t0);
-    tcg_temp_free_i64(t1);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vlbb(DisasContext *s, DisasOps *o)
-{
-    const int64_t block_size = (1ull << (get_field(s, m3) + 6));
-    const int v1_offs = vec_full_reg_offset(get_field(s, v1));
-    TCGv_ptr a0;
-    TCGv_i64 bytes;
-
-    if (get_field(s, m3) > 6) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    bytes = tcg_temp_new_i64();
-    a0 = tcg_temp_new_ptr();
-    /* calculate the number of bytes until the next block boundary */
-    tcg_gen_ori_i64(bytes, o->addr1, -block_size);
-    tcg_gen_neg_i64(bytes, bytes);
-
-    tcg_gen_addi_ptr(a0, cpu_env, v1_offs);
-    gen_helper_vll(cpu_env, a0, o->addr1, bytes);
-    tcg_temp_free_i64(bytes);
-    tcg_temp_free_ptr(a0);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vlvg(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m4);
-    TCGv_ptr ptr;
-
-    if (es > ES_64) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    /* fast path if we don't need the register content */
-    if (!get_field(s, b2)) {
-        uint8_t enr = get_field(s, d2) & (NUM_VEC_ELEMENTS(es) - 1);
-
-        write_vec_element_i64(o->in2, get_field(s, v1), enr, es);
-        return DISAS_NEXT;
-    }
-
-    ptr = tcg_temp_new_ptr();
-    get_vec_element_ptr_i64(ptr, get_field(s, v1), o->addr1, es);
-    switch (es) {
-    case ES_8:
-        tcg_gen_st8_i64(o->in2, ptr, 0);
-        break;
-    case ES_16:
-        tcg_gen_st16_i64(o->in2, ptr, 0);
-        break;
-    case ES_32:
-        tcg_gen_st32_i64(o->in2, ptr, 0);
-        break;
-    case ES_64:
-        tcg_gen_st_i64(o->in2, ptr, 0);
-        break;
-    default:
-        g_assert_not_reached();
-    }
-    tcg_temp_free_ptr(ptr);
-
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vlvgp(DisasContext *s, DisasOps *o)
-{
-    write_vec_element_i64(o->in1, get_field(s, v1), 0, ES_64);
-    write_vec_element_i64(o->in2, get_field(s, v1), 1, ES_64);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vll(DisasContext *s, DisasOps *o)
-{
-    const int v1_offs = vec_full_reg_offset(get_field(s, v1));
-    TCGv_ptr a0 = tcg_temp_new_ptr();
-
-    /* convert highest index into an actual length */
-    tcg_gen_addi_i64(o->in2, o->in2, 1);
-    tcg_gen_addi_ptr(a0, cpu_env, v1_offs);
-    gen_helper_vll(cpu_env, a0, o->addr1, o->in2);
-    tcg_temp_free_ptr(a0);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vmr(DisasContext *s, DisasOps *o)
-{
-    const uint8_t v1 = get_field(s, v1);
-    const uint8_t v2 = get_field(s, v2);
-    const uint8_t v3 = get_field(s, v3);
-    const uint8_t es = get_field(s, m4);
-    int dst_idx, src_idx;
-    TCGv_i64 tmp;
-
-    if (es > ES_64) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    tmp = tcg_temp_new_i64();
-    if (s->fields.op2 == 0x61) {
-        /* iterate backwards to avoid overwriting data we might need later */
-        for (dst_idx = NUM_VEC_ELEMENTS(es) - 1; dst_idx >= 0; dst_idx--) {
-            src_idx = dst_idx / 2;
-            if (dst_idx % 2 == 0) {
-                read_vec_element_i64(tmp, v2, src_idx, es);
-            } else {
-                read_vec_element_i64(tmp, v3, src_idx, es);
-            }
-            write_vec_element_i64(tmp, v1, dst_idx, es);
-        }
-    } else {
-        /* iterate forward to avoid overwriting data we might need later */
-        for (dst_idx = 0; dst_idx < NUM_VEC_ELEMENTS(es); dst_idx++) {
-            src_idx = (dst_idx + NUM_VEC_ELEMENTS(es)) / 2;
-            if (dst_idx % 2 == 0) {
-                read_vec_element_i64(tmp, v2, src_idx, es);
-            } else {
-                read_vec_element_i64(tmp, v3, src_idx, es);
-            }
-            write_vec_element_i64(tmp, v1, dst_idx, es);
-        }
-    }
-    tcg_temp_free_i64(tmp);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vpk(DisasContext *s, DisasOps *o)
-{
-    const uint8_t v1 = get_field(s, v1);
-    const uint8_t v2 = get_field(s, v2);
-    const uint8_t v3 = get_field(s, v3);
-    const uint8_t es = get_field(s, m4);
-    static gen_helper_gvec_3 * const vpk[3] = {
-        gen_helper_gvec_vpk16,
-        gen_helper_gvec_vpk32,
-        gen_helper_gvec_vpk64,
-    };
-     static gen_helper_gvec_3 * const vpks[3] = {
-        gen_helper_gvec_vpks16,
-        gen_helper_gvec_vpks32,
-        gen_helper_gvec_vpks64,
-    };
-    static gen_helper_gvec_3_ptr * const vpks_cc[3] = {
-        gen_helper_gvec_vpks_cc16,
-        gen_helper_gvec_vpks_cc32,
-        gen_helper_gvec_vpks_cc64,
-    };
-    static gen_helper_gvec_3 * const vpkls[3] = {
-        gen_helper_gvec_vpkls16,
-        gen_helper_gvec_vpkls32,
-        gen_helper_gvec_vpkls64,
-    };
-    static gen_helper_gvec_3_ptr * const vpkls_cc[3] = {
-        gen_helper_gvec_vpkls_cc16,
-        gen_helper_gvec_vpkls_cc32,
-        gen_helper_gvec_vpkls_cc64,
-    };
-
-    if (es == ES_8 || es > ES_64) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    switch (s->fields.op2) {
-    case 0x97:
-        if (get_field(s, m5) & 0x1) {
-            gen_gvec_3_ptr(v1, v2, v3, cpu_env, 0, vpks_cc[es - 1]);
-            set_cc_static(s);
-        } else {
-            gen_gvec_3_ool(v1, v2, v3, 0, vpks[es - 1]);
-        }
-        break;
-    case 0x95:
-        if (get_field(s, m5) & 0x1) {
-            gen_gvec_3_ptr(v1, v2, v3, cpu_env, 0, vpkls_cc[es - 1]);
-            set_cc_static(s);
-        } else {
-            gen_gvec_3_ool(v1, v2, v3, 0, vpkls[es - 1]);
-        }
-        break;
-    case 0x94:
-        /* If sources and destination dont't overlap -> fast path */
-        if (v1 != v2 && v1 != v3) {
-            const uint8_t src_es = get_field(s, m4);
-            const uint8_t dst_es = src_es - 1;
-            TCGv_i64 tmp = tcg_temp_new_i64();
-            int dst_idx, src_idx;
-
-            for (dst_idx = 0; dst_idx < NUM_VEC_ELEMENTS(dst_es); dst_idx++) {
-                src_idx = dst_idx;
-                if (src_idx < NUM_VEC_ELEMENTS(src_es)) {
-                    read_vec_element_i64(tmp, v2, src_idx, src_es);
-                } else {
-                    src_idx -= NUM_VEC_ELEMENTS(src_es);
-                    read_vec_element_i64(tmp, v3, src_idx, src_es);
-                }
-                write_vec_element_i64(tmp, v1, dst_idx, dst_es);
-            }
-            tcg_temp_free_i64(tmp);
-        } else {
-            gen_gvec_3_ool(v1, v2, v3, 0, vpk[es - 1]);
-        }
-        break;
-    default:
-        g_assert_not_reached();
-    }
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vperm(DisasContext *s, DisasOps *o)
-{
-    gen_gvec_4_ool(get_field(s, v1), get_field(s, v2),
-                   get_field(s, v3), get_field(s, v4),
-                   0, gen_helper_gvec_vperm);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vpdi(DisasContext *s, DisasOps *o)
-{
-    const uint8_t i2 = extract32(get_field(s, m4), 2, 1);
-    const uint8_t i3 = extract32(get_field(s, m4), 0, 1);
-    TCGv_i64 t0 = tcg_temp_new_i64();
-    TCGv_i64 t1 = tcg_temp_new_i64();
-
-    read_vec_element_i64(t0, get_field(s, v2), i2, ES_64);
-    read_vec_element_i64(t1, get_field(s, v3), i3, ES_64);
-    write_vec_element_i64(t0, get_field(s, v1), 0, ES_64);
-    write_vec_element_i64(t1, get_field(s, v1), 1, ES_64);
-    tcg_temp_free_i64(t0);
-    tcg_temp_free_i64(t1);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vrep(DisasContext *s, DisasOps *o)
-{
-    const uint8_t enr = get_field(s, i2);
-    const uint8_t es = get_field(s, m4);
-
-    if (es > ES_64 || !valid_vec_element(enr, es)) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    tcg_gen_gvec_dup_mem(es, vec_full_reg_offset(get_field(s, v1)),
-                         vec_reg_offset(get_field(s, v3), enr, es),
-                         16, 16);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vrepi(DisasContext *s, DisasOps *o)
-{
-    const int64_t data = (int16_t)get_field(s, i2);
-    const uint8_t es = get_field(s, m3);
-
-    if (es > ES_64) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    gen_gvec_dup_imm(es, get_field(s, v1), data);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vsce(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = s->insn->data;
-    const uint8_t enr = get_field(s, m3);
-    TCGv_i64 tmp;
-
-    if (!valid_vec_element(enr, es)) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    tmp = tcg_temp_new_i64();
-    read_vec_element_i64(tmp, get_field(s, v2), enr, es);
-    tcg_gen_add_i64(o->addr1, o->addr1, tmp);
-    gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 0);
-
-    read_vec_element_i64(tmp, get_field(s, v1), enr, es);
-    tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
-    tcg_temp_free_i64(tmp);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vsel(DisasContext *s, DisasOps *o)
-{
-    gen_gvec_fn_4(bitsel, ES_8, get_field(s, v1),
-                  get_field(s, v4), get_field(s, v2),
-                  get_field(s, v3));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vseg(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m3);
-    int idx1, idx2;
-    TCGv_i64 tmp;
-
-    switch (es) {
-    case ES_8:
-        idx1 = 7;
-        idx2 = 15;
-        break;
-    case ES_16:
-        idx1 = 3;
-        idx2 = 7;
-        break;
-    case ES_32:
-        idx1 = 1;
-        idx2 = 3;
-        break;
-    default:
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    tmp = tcg_temp_new_i64();
-    read_vec_element_i64(tmp, get_field(s, v2), idx1, es | MO_SIGN);
-    write_vec_element_i64(tmp, get_field(s, v1), 0, ES_64);
-    read_vec_element_i64(tmp, get_field(s, v2), idx2, es | MO_SIGN);
-    write_vec_element_i64(tmp, get_field(s, v1), 1, ES_64);
-    tcg_temp_free_i64(tmp);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vst(DisasContext *s, DisasOps *o)
-{
-    TCGv_i64 tmp = tcg_const_i64(16);
-
-    /* Probe write access before actually modifying memory */
-    gen_helper_probe_write_access(cpu_env, o->addr1, tmp);
-
-    read_vec_element_i64(tmp,  get_field(s, v1), 0, ES_64);
-    tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
-    gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
-    read_vec_element_i64(tmp,  get_field(s, v1), 1, ES_64);
-    tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
-    tcg_temp_free_i64(tmp);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vste(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = s->insn->data;
-    const uint8_t enr = get_field(s, m3);
-    TCGv_i64 tmp;
-
-    if (!valid_vec_element(enr, es)) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    tmp = tcg_temp_new_i64();
-    read_vec_element_i64(tmp, get_field(s, v1), enr, es);
-    tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TE | es);
-    tcg_temp_free_i64(tmp);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vstm(DisasContext *s, DisasOps *o)
-{
-    const uint8_t v3 = get_field(s, v3);
-    uint8_t v1 = get_field(s, v1);
-    TCGv_i64 tmp;
-
-    while (v3 < v1 || (v3 - v1 + 1) > 16) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    /* Probe write access before actually modifying memory */
-    tmp = tcg_const_i64((v3 - v1 + 1) * 16);
-    gen_helper_probe_write_access(cpu_env, o->addr1, tmp);
-
-    for (;; v1++) {
-        read_vec_element_i64(tmp, v1, 0, ES_64);
-        tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
-        gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
-        read_vec_element_i64(tmp, v1, 1, ES_64);
-        tcg_gen_qemu_st_i64(tmp, o->addr1, get_mem_index(s), MO_TEQ);
-        if (v1 == v3) {
-            break;
-        }
-        gen_addi_and_wrap_i64(s, o->addr1, o->addr1, 8);
-    }
-    tcg_temp_free_i64(tmp);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vstl(DisasContext *s, DisasOps *o)
-{
-    const int v1_offs = vec_full_reg_offset(get_field(s, v1));
-    TCGv_ptr a0 = tcg_temp_new_ptr();
-
-    /* convert highest index into an actual length */
-    tcg_gen_addi_i64(o->in2, o->in2, 1);
-    tcg_gen_addi_ptr(a0, cpu_env, v1_offs);
-    gen_helper_vstl(cpu_env, a0, o->addr1, o->in2);
-    tcg_temp_free_ptr(a0);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vup(DisasContext *s, DisasOps *o)
-{
-    const bool logical = s->fields.op2 == 0xd4 || s->fields.op2 == 0xd5;
-    const uint8_t v1 = get_field(s, v1);
-    const uint8_t v2 = get_field(s, v2);
-    const uint8_t src_es = get_field(s, m3);
-    const uint8_t dst_es = src_es + 1;
-    int dst_idx, src_idx;
-    TCGv_i64 tmp;
-
-    if (src_es > ES_32) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    tmp = tcg_temp_new_i64();
-    if (s->fields.op2 == 0xd7 || s->fields.op2 == 0xd5) {
-        /* iterate backwards to avoid overwriting data we might need later */
-        for (dst_idx = NUM_VEC_ELEMENTS(dst_es) - 1; dst_idx >= 0; dst_idx--) {
-            src_idx = dst_idx;
-            read_vec_element_i64(tmp, v2, src_idx,
-                                 src_es | (logical ? 0 : MO_SIGN));
-            write_vec_element_i64(tmp, v1, dst_idx, dst_es);
-        }
-
-    } else {
-        /* iterate forward to avoid overwriting data we might need later */
-        for (dst_idx = 0; dst_idx < NUM_VEC_ELEMENTS(dst_es); dst_idx++) {
-            src_idx = dst_idx + NUM_VEC_ELEMENTS(src_es) / 2;
-            read_vec_element_i64(tmp, v2, src_idx,
-                                 src_es | (logical ? 0 : MO_SIGN));
-            write_vec_element_i64(tmp, v1, dst_idx, dst_es);
-        }
-    }
-    tcg_temp_free_i64(tmp);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_va(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m4);
-
-    if (es > ES_128) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    } else if (es == ES_128) {
-        gen_gvec128_3_i64(tcg_gen_add2_i64, get_field(s, v1),
-                          get_field(s, v2), get_field(s, v3));
-        return DISAS_NEXT;
-    }
-    gen_gvec_fn_3(add, es, get_field(s, v1), get_field(s, v2),
-                  get_field(s, v3));
-    return DISAS_NEXT;
-}
-
-static void gen_acc(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b, uint8_t es)
-{
-    const uint8_t msb_bit_nr = NUM_VEC_ELEMENT_BITS(es) - 1;
-    TCGv_i64 msb_mask = tcg_const_i64(dup_const(es, 1ull << msb_bit_nr));
-    TCGv_i64 t1 = tcg_temp_new_i64();
-    TCGv_i64 t2 = tcg_temp_new_i64();
-    TCGv_i64 t3 = tcg_temp_new_i64();
-
-    /* Calculate the carry into the MSB, ignoring the old MSBs */
-    tcg_gen_andc_i64(t1, a, msb_mask);
-    tcg_gen_andc_i64(t2, b, msb_mask);
-    tcg_gen_add_i64(t1, t1, t2);
-    /* Calculate the MSB without any carry into it */
-    tcg_gen_xor_i64(t3, a, b);
-    /* Calculate the carry out of the MSB in the MSB bit position */
-    tcg_gen_and_i64(d, a, b);
-    tcg_gen_and_i64(t1, t1, t3);
-    tcg_gen_or_i64(d, d, t1);
-    /* Isolate and shift the carry into position */
-    tcg_gen_and_i64(d, d, msb_mask);
-    tcg_gen_shri_i64(d, d, msb_bit_nr);
-
-    tcg_temp_free_i64(t1);
-    tcg_temp_free_i64(t2);
-    tcg_temp_free_i64(t3);
-}
-
-static void gen_acc8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
-{
-    gen_acc(d, a, b, ES_8);
-}
-
-static void gen_acc16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
-{
-    gen_acc(d, a, b, ES_16);
-}
-
-static void gen_acc_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
-{
-    TCGv_i32 t = tcg_temp_new_i32();
-
-    tcg_gen_add_i32(t, a, b);
-    tcg_gen_setcond_i32(TCG_COND_LTU, d, t, b);
-    tcg_temp_free_i32(t);
-}
-
-static void gen_acc_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
-{
-    TCGv_i64 t = tcg_temp_new_i64();
-
-    tcg_gen_add_i64(t, a, b);
-    tcg_gen_setcond_i64(TCG_COND_LTU, d, t, b);
-    tcg_temp_free_i64(t);
-}
-
-static void gen_acc2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
-                         TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh)
-{
-    TCGv_i64 th = tcg_temp_new_i64();
-    TCGv_i64 tl = tcg_temp_new_i64();
-    TCGv_i64 zero = tcg_const_i64(0);
-
-    tcg_gen_add2_i64(tl, th, al, zero, bl, zero);
-    tcg_gen_add2_i64(tl, th, th, zero, ah, zero);
-    tcg_gen_add2_i64(tl, dl, tl, th, bh, zero);
-    tcg_gen_mov_i64(dh, zero);
-
-    tcg_temp_free_i64(th);
-    tcg_temp_free_i64(tl);
-    tcg_temp_free_i64(zero);
-}
-
-static DisasJumpType op_vacc(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m4);
-    static const GVecGen3 g[4] = {
-        { .fni8 = gen_acc8_i64, },
-        { .fni8 = gen_acc16_i64, },
-        { .fni4 = gen_acc_i32, },
-        { .fni8 = gen_acc_i64, },
-    };
-
-    if (es > ES_128) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    } else if (es == ES_128) {
-        gen_gvec128_3_i64(gen_acc2_i64, get_field(s, v1),
-                          get_field(s, v2), get_field(s, v3));
-        return DISAS_NEXT;
-    }
-    gen_gvec_3(get_field(s, v1), get_field(s, v2),
-               get_field(s, v3), &g[es]);
-    return DISAS_NEXT;
-}
-
-static void gen_ac2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
-                        TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
-{
-    TCGv_i64 tl = tcg_temp_new_i64();
-    TCGv_i64 th = tcg_const_i64(0);
-
-    /* extract the carry only */
-    tcg_gen_extract_i64(tl, cl, 0, 1);
-    tcg_gen_add2_i64(dl, dh, al, ah, bl, bh);
-    tcg_gen_add2_i64(dl, dh, dl, dh, tl, th);
-
-    tcg_temp_free_i64(tl);
-    tcg_temp_free_i64(th);
-}
-
-static DisasJumpType op_vac(DisasContext *s, DisasOps *o)
-{
-    if (get_field(s, m5) != ES_128) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    gen_gvec128_4_i64(gen_ac2_i64, get_field(s, v1),
-                      get_field(s, v2), get_field(s, v3),
-                      get_field(s, v4));
-    return DISAS_NEXT;
-}
-
-static void gen_accc2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
-                          TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
-{
-    TCGv_i64 tl = tcg_temp_new_i64();
-    TCGv_i64 th = tcg_temp_new_i64();
-    TCGv_i64 zero = tcg_const_i64(0);
-
-    tcg_gen_andi_i64(tl, cl, 1);
-    tcg_gen_add2_i64(tl, th, tl, zero, al, zero);
-    tcg_gen_add2_i64(tl, th, tl, th, bl, zero);
-    tcg_gen_add2_i64(tl, th, th, zero, ah, zero);
-    tcg_gen_add2_i64(tl, dl, tl, th, bh, zero);
-    tcg_gen_mov_i64(dh, zero);
-
-    tcg_temp_free_i64(tl);
-    tcg_temp_free_i64(th);
-    tcg_temp_free_i64(zero);
-}
-
-static DisasJumpType op_vaccc(DisasContext *s, DisasOps *o)
-{
-    if (get_field(s, m5) != ES_128) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    gen_gvec128_4_i64(gen_accc2_i64, get_field(s, v1),
-                      get_field(s, v2), get_field(s, v3),
-                      get_field(s, v4));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vn(DisasContext *s, DisasOps *o)
-{
-    gen_gvec_fn_3(and, ES_8, get_field(s, v1), get_field(s, v2),
-                  get_field(s, v3));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vnc(DisasContext *s, DisasOps *o)
-{
-    gen_gvec_fn_3(andc, ES_8, get_field(s, v1),
-                  get_field(s, v2), get_field(s, v3));
-    return DISAS_NEXT;
-}
-
-static void gen_avg_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
-{
-    TCGv_i64 t0 = tcg_temp_new_i64();
-    TCGv_i64 t1 = tcg_temp_new_i64();
-
-    tcg_gen_ext_i32_i64(t0, a);
-    tcg_gen_ext_i32_i64(t1, b);
-    tcg_gen_add_i64(t0, t0, t1);
-    tcg_gen_addi_i64(t0, t0, 1);
-    tcg_gen_shri_i64(t0, t0, 1);
-    tcg_gen_extrl_i64_i32(d, t0);
-
-    tcg_temp_free(t0);
-    tcg_temp_free(t1);
-}
-
-static void gen_avg_i64(TCGv_i64 dl, TCGv_i64 al, TCGv_i64 bl)
-{
-    TCGv_i64 dh = tcg_temp_new_i64();
-    TCGv_i64 ah = tcg_temp_new_i64();
-    TCGv_i64 bh = tcg_temp_new_i64();
-
-    /* extending the sign by one bit is sufficient */
-    tcg_gen_extract_i64(ah, al, 63, 1);
-    tcg_gen_extract_i64(bh, bl, 63, 1);
-    tcg_gen_add2_i64(dl, dh, al, ah, bl, bh);
-    gen_addi2_i64(dl, dh, dl, dh, 1);
-    tcg_gen_extract2_i64(dl, dl, dh, 1);
-
-    tcg_temp_free_i64(dh);
-    tcg_temp_free_i64(ah);
-    tcg_temp_free_i64(bh);
-}
-
-static DisasJumpType op_vavg(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m4);
-    static const GVecGen3 g[4] = {
-        { .fno = gen_helper_gvec_vavg8, },
-        { .fno = gen_helper_gvec_vavg16, },
-        { .fni4 = gen_avg_i32, },
-        { .fni8 = gen_avg_i64, },
-    };
-
-    if (es > ES_64) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-    gen_gvec_3(get_field(s, v1), get_field(s, v2),
-               get_field(s, v3), &g[es]);
-    return DISAS_NEXT;
-}
-
-static void gen_avgl_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
-{
-    TCGv_i64 t0 = tcg_temp_new_i64();
-    TCGv_i64 t1 = tcg_temp_new_i64();
-
-    tcg_gen_extu_i32_i64(t0, a);
-    tcg_gen_extu_i32_i64(t1, b);
-    tcg_gen_add_i64(t0, t0, t1);
-    tcg_gen_addi_i64(t0, t0, 1);
-    tcg_gen_shri_i64(t0, t0, 1);
-    tcg_gen_extrl_i64_i32(d, t0);
-
-    tcg_temp_free(t0);
-    tcg_temp_free(t1);
-}
-
-static void gen_avgl_i64(TCGv_i64 dl, TCGv_i64 al, TCGv_i64 bl)
-{
-    TCGv_i64 dh = tcg_temp_new_i64();
-    TCGv_i64 zero = tcg_const_i64(0);
-
-    tcg_gen_add2_i64(dl, dh, al, zero, bl, zero);
-    gen_addi2_i64(dl, dh, dl, dh, 1);
-    tcg_gen_extract2_i64(dl, dl, dh, 1);
-
-    tcg_temp_free_i64(dh);
-    tcg_temp_free_i64(zero);
-}
-
-static DisasJumpType op_vavgl(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m4);
-    static const GVecGen3 g[4] = {
-        { .fno = gen_helper_gvec_vavgl8, },
-        { .fno = gen_helper_gvec_vavgl16, },
-        { .fni4 = gen_avgl_i32, },
-        { .fni8 = gen_avgl_i64, },
-    };
-
-    if (es > ES_64) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-    gen_gvec_3(get_field(s, v1), get_field(s, v2),
-               get_field(s, v3), &g[es]);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vcksm(DisasContext *s, DisasOps *o)
-{
-    TCGv_i32 tmp = tcg_temp_new_i32();
-    TCGv_i32 sum = tcg_temp_new_i32();
-    int i;
-
-    read_vec_element_i32(sum, get_field(s, v3), 1, ES_32);
-    for (i = 0; i < 4; i++) {
-        read_vec_element_i32(tmp, get_field(s, v2), i, ES_32);
-        tcg_gen_add2_i32(tmp, sum, sum, sum, tmp, tmp);
-    }
-    gen_gvec_dup_imm(ES_32, get_field(s, v1), 0);
-    write_vec_element_i32(sum, get_field(s, v1), 1, ES_32);
-
-    tcg_temp_free_i32(tmp);
-    tcg_temp_free_i32(sum);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vec(DisasContext *s, DisasOps *o)
-{
-    uint8_t es = get_field(s, m3);
-    const uint8_t enr = NUM_VEC_ELEMENTS(es) / 2 - 1;
-
-    if (es > ES_64) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-    if (s->fields.op2 == 0xdb) {
-        es |= MO_SIGN;
-    }
-
-    o->in1 = tcg_temp_new_i64();
-    o->in2 = tcg_temp_new_i64();
-    read_vec_element_i64(o->in1, get_field(s, v1), enr, es);
-    read_vec_element_i64(o->in2, get_field(s, v2), enr, es);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vc(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m4);
-    TCGCond cond = s->insn->data;
-
-    if (es > ES_64) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    tcg_gen_gvec_cmp(cond, es,
-                     vec_full_reg_offset(get_field(s, v1)),
-                     vec_full_reg_offset(get_field(s, v2)),
-                     vec_full_reg_offset(get_field(s, v3)), 16, 16);
-    if (get_field(s, m5) & 0x1) {
-        TCGv_i64 low = tcg_temp_new_i64();
-        TCGv_i64 high = tcg_temp_new_i64();
-
-        read_vec_element_i64(high, get_field(s, v1), 0, ES_64);
-        read_vec_element_i64(low, get_field(s, v1), 1, ES_64);
-        gen_op_update2_cc_i64(s, CC_OP_VC, low, high);
-
-        tcg_temp_free_i64(low);
-        tcg_temp_free_i64(high);
-    }
-    return DISAS_NEXT;
-}
-
-static void gen_clz_i32(TCGv_i32 d, TCGv_i32 a)
-{
-    tcg_gen_clzi_i32(d, a, 32);
-}
-
-static void gen_clz_i64(TCGv_i64 d, TCGv_i64 a)
-{
-    tcg_gen_clzi_i64(d, a, 64);
-}
-
-static DisasJumpType op_vclz(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m3);
-    static const GVecGen2 g[4] = {
-        { .fno = gen_helper_gvec_vclz8, },
-        { .fno = gen_helper_gvec_vclz16, },
-        { .fni4 = gen_clz_i32, },
-        { .fni8 = gen_clz_i64, },
-    };
-
-    if (es > ES_64) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-    gen_gvec_2(get_field(s, v1), get_field(s, v2), &g[es]);
-    return DISAS_NEXT;
-}
-
-static void gen_ctz_i32(TCGv_i32 d, TCGv_i32 a)
-{
-    tcg_gen_ctzi_i32(d, a, 32);
-}
-
-static void gen_ctz_i64(TCGv_i64 d, TCGv_i64 a)
-{
-    tcg_gen_ctzi_i64(d, a, 64);
-}
-
-static DisasJumpType op_vctz(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m3);
-    static const GVecGen2 g[4] = {
-        { .fno = gen_helper_gvec_vctz8, },
-        { .fno = gen_helper_gvec_vctz16, },
-        { .fni4 = gen_ctz_i32, },
-        { .fni8 = gen_ctz_i64, },
-    };
-
-    if (es > ES_64) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-    gen_gvec_2(get_field(s, v1), get_field(s, v2), &g[es]);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vx(DisasContext *s, DisasOps *o)
-{
-    gen_gvec_fn_3(xor, ES_8, get_field(s, v1), get_field(s, v2),
-                 get_field(s, v3));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vgfm(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m4);
-    static const GVecGen3 g[4] = {
-        { .fno = gen_helper_gvec_vgfm8, },
-        { .fno = gen_helper_gvec_vgfm16, },
-        { .fno = gen_helper_gvec_vgfm32, },
-        { .fno = gen_helper_gvec_vgfm64, },
-    };
-
-    if (es > ES_64) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-    gen_gvec_3(get_field(s, v1), get_field(s, v2),
-               get_field(s, v3), &g[es]);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vgfma(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m5);
-    static const GVecGen4 g[4] = {
-        { .fno = gen_helper_gvec_vgfma8, },
-        { .fno = gen_helper_gvec_vgfma16, },
-        { .fno = gen_helper_gvec_vgfma32, },
-        { .fno = gen_helper_gvec_vgfma64, },
-    };
-
-    if (es > ES_64) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-    gen_gvec_4(get_field(s, v1), get_field(s, v2),
-               get_field(s, v3), get_field(s, v4), &g[es]);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vlc(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m3);
-
-    if (es > ES_64) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    gen_gvec_fn_2(neg, es, get_field(s, v1), get_field(s, v2));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vlp(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m3);
-
-    if (es > ES_64) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    gen_gvec_fn_2(abs, es, get_field(s, v1), get_field(s, v2));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vmx(DisasContext *s, DisasOps *o)
-{
-    const uint8_t v1 = get_field(s, v1);
-    const uint8_t v2 = get_field(s, v2);
-    const uint8_t v3 = get_field(s, v3);
-    const uint8_t es = get_field(s, m4);
-
-    if (es > ES_64) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    switch (s->fields.op2) {
-    case 0xff:
-        gen_gvec_fn_3(smax, es, v1, v2, v3);
-        break;
-    case 0xfd:
-        gen_gvec_fn_3(umax, es, v1, v2, v3);
-        break;
-    case 0xfe:
-        gen_gvec_fn_3(smin, es, v1, v2, v3);
-        break;
-    case 0xfc:
-        gen_gvec_fn_3(umin, es, v1, v2, v3);
-        break;
-    default:
-        g_assert_not_reached();
-    }
-    return DISAS_NEXT;
-}
-
-static void gen_mal_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, TCGv_i32 c)
-{
-    TCGv_i32 t0 = tcg_temp_new_i32();
-
-    tcg_gen_mul_i32(t0, a, b);
-    tcg_gen_add_i32(d, t0, c);
-
-    tcg_temp_free_i32(t0);
-}
-
-static void gen_mah_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, TCGv_i32 c)
-{
-    TCGv_i64 t0 = tcg_temp_new_i64();
-    TCGv_i64 t1 = tcg_temp_new_i64();
-    TCGv_i64 t2 = tcg_temp_new_i64();
-
-    tcg_gen_ext_i32_i64(t0, a);
-    tcg_gen_ext_i32_i64(t1, b);
-    tcg_gen_ext_i32_i64(t2, c);
-    tcg_gen_mul_i64(t0, t0, t1);
-    tcg_gen_add_i64(t0, t0, t2);
-    tcg_gen_extrh_i64_i32(d, t0);
-
-    tcg_temp_free(t0);
-    tcg_temp_free(t1);
-    tcg_temp_free(t2);
-}
-
-static void gen_malh_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, TCGv_i32 c)
-{
-    TCGv_i64 t0 = tcg_temp_new_i64();
-    TCGv_i64 t1 = tcg_temp_new_i64();
-    TCGv_i64 t2 = tcg_temp_new_i64();
-
-    tcg_gen_extu_i32_i64(t0, a);
-    tcg_gen_extu_i32_i64(t1, b);
-    tcg_gen_extu_i32_i64(t2, c);
-    tcg_gen_mul_i64(t0, t0, t1);
-    tcg_gen_add_i64(t0, t0, t2);
-    tcg_gen_extrh_i64_i32(d, t0);
-
-    tcg_temp_free(t0);
-    tcg_temp_free(t1);
-    tcg_temp_free(t2);
-}
-
-static DisasJumpType op_vma(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m5);
-    static const GVecGen4 g_vmal[3] = {
-        { .fno = gen_helper_gvec_vmal8, },
-        { .fno = gen_helper_gvec_vmal16, },
-        { .fni4 = gen_mal_i32, },
-    };
-    static const GVecGen4 g_vmah[3] = {
-        { .fno = gen_helper_gvec_vmah8, },
-        { .fno = gen_helper_gvec_vmah16, },
-        { .fni4 = gen_mah_i32, },
-    };
-    static const GVecGen4 g_vmalh[3] = {
-        { .fno = gen_helper_gvec_vmalh8, },
-        { .fno = gen_helper_gvec_vmalh16, },
-        { .fni4 = gen_malh_i32, },
-    };
-    static const GVecGen4 g_vmae[3] = {
-        { .fno = gen_helper_gvec_vmae8, },
-        { .fno = gen_helper_gvec_vmae16, },
-        { .fno = gen_helper_gvec_vmae32, },
-    };
-    static const GVecGen4 g_vmale[3] = {
-        { .fno = gen_helper_gvec_vmale8, },
-        { .fno = gen_helper_gvec_vmale16, },
-        { .fno = gen_helper_gvec_vmale32, },
-    };
-    static const GVecGen4 g_vmao[3] = {
-        { .fno = gen_helper_gvec_vmao8, },
-        { .fno = gen_helper_gvec_vmao16, },
-        { .fno = gen_helper_gvec_vmao32, },
-    };
-    static const GVecGen4 g_vmalo[3] = {
-        { .fno = gen_helper_gvec_vmalo8, },
-        { .fno = gen_helper_gvec_vmalo16, },
-        { .fno = gen_helper_gvec_vmalo32, },
-    };
-    const GVecGen4 *fn;
-
-    if (es > ES_32) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    switch (s->fields.op2) {
-    case 0xaa:
-        fn = &g_vmal[es];
-        break;
-    case 0xab:
-        fn = &g_vmah[es];
-        break;
-    case 0xa9:
-        fn = &g_vmalh[es];
-        break;
-    case 0xae:
-        fn = &g_vmae[es];
-        break;
-    case 0xac:
-        fn = &g_vmale[es];
-        break;
-    case 0xaf:
-        fn = &g_vmao[es];
-        break;
-    case 0xad:
-        fn = &g_vmalo[es];
-        break;
-    default:
-        g_assert_not_reached();
-    }
-
-    gen_gvec_4(get_field(s, v1), get_field(s, v2),
-               get_field(s, v3), get_field(s, v4), fn);
-    return DISAS_NEXT;
-}
-
-static void gen_mh_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
-{
-    TCGv_i32 t = tcg_temp_new_i32();
-
-    tcg_gen_muls2_i32(t, d, a, b);
-    tcg_temp_free_i32(t);
-}
-
-static void gen_mlh_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
-{
-    TCGv_i32 t = tcg_temp_new_i32();
-
-    tcg_gen_mulu2_i32(t, d, a, b);
-    tcg_temp_free_i32(t);
-}
-
-static DisasJumpType op_vm(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m4);
-    static const GVecGen3 g_vmh[3] = {
-        { .fno = gen_helper_gvec_vmh8, },
-        { .fno = gen_helper_gvec_vmh16, },
-        { .fni4 = gen_mh_i32, },
-    };
-    static const GVecGen3 g_vmlh[3] = {
-        { .fno = gen_helper_gvec_vmlh8, },
-        { .fno = gen_helper_gvec_vmlh16, },
-        { .fni4 = gen_mlh_i32, },
-    };
-    static const GVecGen3 g_vme[3] = {
-        { .fno = gen_helper_gvec_vme8, },
-        { .fno = gen_helper_gvec_vme16, },
-        { .fno = gen_helper_gvec_vme32, },
-    };
-    static const GVecGen3 g_vmle[3] = {
-        { .fno = gen_helper_gvec_vmle8, },
-        { .fno = gen_helper_gvec_vmle16, },
-        { .fno = gen_helper_gvec_vmle32, },
-    };
-    static const GVecGen3 g_vmo[3] = {
-        { .fno = gen_helper_gvec_vmo8, },
-        { .fno = gen_helper_gvec_vmo16, },
-        { .fno = gen_helper_gvec_vmo32, },
-    };
-    static const GVecGen3 g_vmlo[3] = {
-        { .fno = gen_helper_gvec_vmlo8, },
-        { .fno = gen_helper_gvec_vmlo16, },
-        { .fno = gen_helper_gvec_vmlo32, },
-    };
-    const GVecGen3 *fn;
-
-    if (es > ES_32) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    switch (s->fields.op2) {
-    case 0xa2:
-        gen_gvec_fn_3(mul, es, get_field(s, v1),
-                      get_field(s, v2), get_field(s, v3));
-        return DISAS_NEXT;
-    case 0xa3:
-        fn = &g_vmh[es];
-        break;
-    case 0xa1:
-        fn = &g_vmlh[es];
-        break;
-    case 0xa6:
-        fn = &g_vme[es];
-        break;
-    case 0xa4:
-        fn = &g_vmle[es];
-        break;
-    case 0xa7:
-        fn = &g_vmo[es];
-        break;
-    case 0xa5:
-        fn = &g_vmlo[es];
-        break;
-    default:
-        g_assert_not_reached();
-    }
-
-    gen_gvec_3(get_field(s, v1), get_field(s, v2),
-               get_field(s, v3), fn);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vmsl(DisasContext *s, DisasOps *o)
-{
-    TCGv_i64 l1, h1, l2, h2;
-
-    if (get_field(s, m4) != ES_64) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    l1 = tcg_temp_new_i64();
-    h1 = tcg_temp_new_i64();
-    l2 = tcg_temp_new_i64();
-    h2 = tcg_temp_new_i64();
-
-    /* Multipy both even elements from v2 and v3 */
-    read_vec_element_i64(l1, get_field(s, v2), 0, ES_64);
-    read_vec_element_i64(h1, get_field(s, v3), 0, ES_64);
-    tcg_gen_mulu2_i64(l1, h1, l1, h1);
-    /* Shift result left by one (x2) if requested */
-    if (extract32(get_field(s, m6), 3, 1)) {
-        tcg_gen_add2_i64(l1, h1, l1, h1, l1, h1);
-    }
-
-    /* Multipy both odd elements from v2 and v3 */
-    read_vec_element_i64(l2, get_field(s, v2), 1, ES_64);
-    read_vec_element_i64(h2, get_field(s, v3), 1, ES_64);
-    tcg_gen_mulu2_i64(l2, h2, l2, h2);
-    /* Shift result left by one (x2) if requested */
-    if (extract32(get_field(s, m6), 2, 1)) {
-        tcg_gen_add2_i64(l2, h2, l2, h2, l2, h2);
-    }
-
-    /* Add both intermediate results */
-    tcg_gen_add2_i64(l1, h1, l1, h1, l2, h2);
-    /* Add whole v4 */
-    read_vec_element_i64(h2, get_field(s, v4), 0, ES_64);
-    read_vec_element_i64(l2, get_field(s, v4), 1, ES_64);
-    tcg_gen_add2_i64(l1, h1, l1, h1, l2, h2);
-
-    /* Store final result into v1. */
-    write_vec_element_i64(h1, get_field(s, v1), 0, ES_64);
-    write_vec_element_i64(l1, get_field(s, v1), 1, ES_64);
-
-    tcg_temp_free_i64(l1);
-    tcg_temp_free_i64(h1);
-    tcg_temp_free_i64(l2);
-    tcg_temp_free_i64(h2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vnn(DisasContext *s, DisasOps *o)
-{
-    gen_gvec_fn_3(nand, ES_8, get_field(s, v1),
-                  get_field(s, v2), get_field(s, v3));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vno(DisasContext *s, DisasOps *o)
-{
-    gen_gvec_fn_3(nor, ES_8, get_field(s, v1), get_field(s, v2),
-                  get_field(s, v3));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vnx(DisasContext *s, DisasOps *o)
-{
-    gen_gvec_fn_3(eqv, ES_8, get_field(s, v1), get_field(s, v2),
-                  get_field(s, v3));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vo(DisasContext *s, DisasOps *o)
-{
-    gen_gvec_fn_3(or, ES_8, get_field(s, v1), get_field(s, v2),
-                  get_field(s, v3));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_voc(DisasContext *s, DisasOps *o)
-{
-    gen_gvec_fn_3(orc, ES_8, get_field(s, v1), get_field(s, v2),
-                  get_field(s, v3));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vpopct(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m3);
-    static const GVecGen2 g[4] = {
-        { .fno = gen_helper_gvec_vpopct8, },
-        { .fno = gen_helper_gvec_vpopct16, },
-        { .fni4 = tcg_gen_ctpop_i32, },
-        { .fni8 = tcg_gen_ctpop_i64, },
-    };
-
-    if (es > ES_64 || (es != ES_8 && !s390_has_feat(S390_FEAT_VECTOR_ENH))) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    gen_gvec_2(get_field(s, v1), get_field(s, v2), &g[es]);
-    return DISAS_NEXT;
-}
-
-static void gen_rim_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b, int32_t c)
-{
-    TCGv_i32 t = tcg_temp_new_i32();
-
-    tcg_gen_rotli_i32(t, a, c & 31);
-    tcg_gen_and_i32(t, t, b);
-    tcg_gen_andc_i32(d, d, b);
-    tcg_gen_or_i32(d, d, t);
-
-    tcg_temp_free_i32(t);
-}
-
-static void gen_rim_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b, int64_t c)
-{
-    TCGv_i64 t = tcg_temp_new_i64();
-
-    tcg_gen_rotli_i64(t, a, c & 63);
-    tcg_gen_and_i64(t, t, b);
-    tcg_gen_andc_i64(d, d, b);
-    tcg_gen_or_i64(d, d, t);
-
-    tcg_temp_free_i64(t);
-}
-
-static DisasJumpType op_verim(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m5);
-    const uint8_t i4 = get_field(s, i4) &
-                       (NUM_VEC_ELEMENT_BITS(es) - 1);
-    static const GVecGen3i g[4] = {
-        { .fno = gen_helper_gvec_verim8, },
-        { .fno = gen_helper_gvec_verim16, },
-        { .fni4 = gen_rim_i32,
-          .load_dest = true, },
-        { .fni8 = gen_rim_i64,
-          .load_dest = true, },
-    };
-
-    if (es > ES_64) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    gen_gvec_3i(get_field(s, v1), get_field(s, v2),
-                get_field(s, v3), i4, &g[es]);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vesv(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m4);
-    const uint8_t v1 = get_field(s, v1);
-    const uint8_t v2 = get_field(s, v2);
-    const uint8_t v3 = get_field(s, v3);
-
-    if (es > ES_64) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    switch (s->fields.op2) {
-    case 0x70:
-        gen_gvec_fn_3(shlv, es, v1, v2, v3);
-        break;
-    case 0x73:
-        gen_gvec_fn_3(rotlv, es, v1, v2, v3);
-        break;
-    case 0x7a:
-        gen_gvec_fn_3(sarv, es, v1, v2, v3);
-        break;
-    case 0x78:
-        gen_gvec_fn_3(shrv, es, v1, v2, v3);
-        break;
-    default:
-        g_assert_not_reached();
-    }
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_ves(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m4);
-    const uint8_t d2 = get_field(s, d2) &
-                       (NUM_VEC_ELEMENT_BITS(es) - 1);
-    const uint8_t v1 = get_field(s, v1);
-    const uint8_t v3 = get_field(s, v3);
-    TCGv_i32 shift;
-
-    if (es > ES_64) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    if (likely(!get_field(s, b2))) {
-        switch (s->fields.op2) {
-        case 0x30:
-            gen_gvec_fn_2i(shli, es, v1, v3, d2);
-            break;
-        case 0x33:
-            gen_gvec_fn_2i(rotli, es, v1, v3, d2);
-            break;
-        case 0x3a:
-            gen_gvec_fn_2i(sari, es, v1, v3, d2);
-            break;
-        case 0x38:
-            gen_gvec_fn_2i(shri, es, v1, v3, d2);
-            break;
-        default:
-            g_assert_not_reached();
-        }
-    } else {
-        shift = tcg_temp_new_i32();
-        tcg_gen_extrl_i64_i32(shift, o->addr1);
-        tcg_gen_andi_i32(shift, shift, NUM_VEC_ELEMENT_BITS(es) - 1);
-        switch (s->fields.op2) {
-        case 0x30:
-            gen_gvec_fn_2s(shls, es, v1, v3, shift);
-            break;
-        case 0x33:
-            gen_gvec_fn_2s(rotls, es, v1, v3, shift);
-            break;
-        case 0x3a:
-            gen_gvec_fn_2s(sars, es, v1, v3, shift);
-            break;
-        case 0x38:
-            gen_gvec_fn_2s(shrs, es, v1, v3, shift);
-            break;
-        default:
-            g_assert_not_reached();
-        }
-        tcg_temp_free_i32(shift);
-    }
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vsl(DisasContext *s, DisasOps *o)
-{
-    TCGv_i64 shift = tcg_temp_new_i64();
-
-    read_vec_element_i64(shift, get_field(s, v3), 7, ES_8);
-    if (s->fields.op2 == 0x74) {
-        tcg_gen_andi_i64(shift, shift, 0x7);
-    } else {
-        tcg_gen_andi_i64(shift, shift, 0x78);
-    }
-
-    gen_gvec_2i_ool(get_field(s, v1), get_field(s, v2),
-                    shift, 0, gen_helper_gvec_vsl);
-    tcg_temp_free_i64(shift);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vsldb(DisasContext *s, DisasOps *o)
-{
-    const uint8_t i4 = get_field(s, i4) & 0xf;
-    const int left_shift = (i4 & 7) * 8;
-    const int right_shift = 64 - left_shift;
-    TCGv_i64 t0 = tcg_temp_new_i64();
-    TCGv_i64 t1 = tcg_temp_new_i64();
-    TCGv_i64 t2 = tcg_temp_new_i64();
-
-    if ((i4 & 8) == 0) {
-        read_vec_element_i64(t0, get_field(s, v2), 0, ES_64);
-        read_vec_element_i64(t1, get_field(s, v2), 1, ES_64);
-        read_vec_element_i64(t2, get_field(s, v3), 0, ES_64);
-    } else {
-        read_vec_element_i64(t0, get_field(s, v2), 1, ES_64);
-        read_vec_element_i64(t1, get_field(s, v3), 0, ES_64);
-        read_vec_element_i64(t2, get_field(s, v3), 1, ES_64);
-    }
-    tcg_gen_extract2_i64(t0, t1, t0, right_shift);
-    tcg_gen_extract2_i64(t1, t2, t1, right_shift);
-    write_vec_element_i64(t0, get_field(s, v1), 0, ES_64);
-    write_vec_element_i64(t1, get_field(s, v1), 1, ES_64);
-
-    tcg_temp_free(t0);
-    tcg_temp_free(t1);
-    tcg_temp_free(t2);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vsra(DisasContext *s, DisasOps *o)
-{
-    TCGv_i64 shift = tcg_temp_new_i64();
-
-    read_vec_element_i64(shift, get_field(s, v3), 7, ES_8);
-    if (s->fields.op2 == 0x7e) {
-        tcg_gen_andi_i64(shift, shift, 0x7);
-    } else {
-        tcg_gen_andi_i64(shift, shift, 0x78);
-    }
-
-    gen_gvec_2i_ool(get_field(s, v1), get_field(s, v2),
-                    shift, 0, gen_helper_gvec_vsra);
-    tcg_temp_free_i64(shift);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vsrl(DisasContext *s, DisasOps *o)
-{
-    TCGv_i64 shift = tcg_temp_new_i64();
-
-    read_vec_element_i64(shift, get_field(s, v3), 7, ES_8);
-    if (s->fields.op2 == 0x7c) {
-        tcg_gen_andi_i64(shift, shift, 0x7);
-    } else {
-        tcg_gen_andi_i64(shift, shift, 0x78);
-    }
-
-    gen_gvec_2i_ool(get_field(s, v1), get_field(s, v2),
-                    shift, 0, gen_helper_gvec_vsrl);
-    tcg_temp_free_i64(shift);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vs(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m4);
-
-    if (es > ES_128) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    } else if (es == ES_128) {
-        gen_gvec128_3_i64(tcg_gen_sub2_i64, get_field(s, v1),
-                          get_field(s, v2), get_field(s, v3));
-        return DISAS_NEXT;
-    }
-    gen_gvec_fn_3(sub, es, get_field(s, v1), get_field(s, v2),
-                  get_field(s, v3));
-    return DISAS_NEXT;
-}
-
-static void gen_scbi_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
-{
-    tcg_gen_setcond_i32(TCG_COND_GEU, d, a, b);
-}
-
-static void gen_scbi_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
-{
-    tcg_gen_setcond_i64(TCG_COND_GEU, d, a, b);
-}
-
-static void gen_scbi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
-                          TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh)
-{
-    TCGv_i64 th = tcg_temp_new_i64();
-    TCGv_i64 tl = tcg_temp_new_i64();
-    TCGv_i64 zero = tcg_const_i64(0);
-
-    tcg_gen_sub2_i64(tl, th, al, zero, bl, zero);
-    tcg_gen_andi_i64(th, th, 1);
-    tcg_gen_sub2_i64(tl, th, ah, zero, th, zero);
-    tcg_gen_sub2_i64(tl, th, tl, th, bh, zero);
-    /* "invert" the result: -1 -> 0; 0 -> 1 */
-    tcg_gen_addi_i64(dl, th, 1);
-    tcg_gen_mov_i64(dh, zero);
-
-    tcg_temp_free_i64(th);
-    tcg_temp_free_i64(tl);
-    tcg_temp_free_i64(zero);
-}
-
-static DisasJumpType op_vscbi(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m4);
-    static const GVecGen3 g[4] = {
-        { .fno = gen_helper_gvec_vscbi8, },
-        { .fno = gen_helper_gvec_vscbi16, },
-        { .fni4 = gen_scbi_i32, },
-        { .fni8 = gen_scbi_i64, },
-    };
-
-    if (es > ES_128) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    } else if (es == ES_128) {
-        gen_gvec128_3_i64(gen_scbi2_i64, get_field(s, v1),
-                          get_field(s, v2), get_field(s, v3));
-        return DISAS_NEXT;
-    }
-    gen_gvec_3(get_field(s, v1), get_field(s, v2),
-               get_field(s, v3), &g[es]);
-    return DISAS_NEXT;
-}
-
-static void gen_sbi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
-                         TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
-{
-    TCGv_i64 tl = tcg_temp_new_i64();
-    TCGv_i64 th = tcg_temp_new_i64();
-
-    tcg_gen_not_i64(tl, bl);
-    tcg_gen_not_i64(th, bh);
-    gen_ac2_i64(dl, dh, al, ah, tl, th, cl, ch);
-    tcg_temp_free_i64(tl);
-    tcg_temp_free_i64(th);
-}
-
-static DisasJumpType op_vsbi(DisasContext *s, DisasOps *o)
-{
-    if (get_field(s, m5) != ES_128) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    gen_gvec128_4_i64(gen_sbi2_i64, get_field(s, v1),
-                      get_field(s, v2), get_field(s, v3),
-                      get_field(s, v4));
-    return DISAS_NEXT;
-}
-
-static void gen_sbcbi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
-                           TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
-{
-    TCGv_i64 th = tcg_temp_new_i64();
-    TCGv_i64 tl = tcg_temp_new_i64();
-
-    tcg_gen_not_i64(tl, bl);
-    tcg_gen_not_i64(th, bh);
-    gen_accc2_i64(dl, dh, al, ah, tl, th, cl, ch);
-
-    tcg_temp_free_i64(tl);
-    tcg_temp_free_i64(th);
-}
-
-static DisasJumpType op_vsbcbi(DisasContext *s, DisasOps *o)
-{
-    if (get_field(s, m5) != ES_128) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    gen_gvec128_4_i64(gen_sbcbi2_i64, get_field(s, v1),
-                      get_field(s, v2), get_field(s, v3),
-                      get_field(s, v4));
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vsumg(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m4);
-    TCGv_i64 sum, tmp;
-    uint8_t dst_idx;
-
-    if (es == ES_8 || es > ES_32) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    sum = tcg_temp_new_i64();
-    tmp = tcg_temp_new_i64();
-    for (dst_idx = 0; dst_idx < 2; dst_idx++) {
-        uint8_t idx = dst_idx * NUM_VEC_ELEMENTS(es) / 2;
-        const uint8_t max_idx = idx + NUM_VEC_ELEMENTS(es) / 2 - 1;
-
-        read_vec_element_i64(sum, get_field(s, v3), max_idx, es);
-        for (; idx <= max_idx; idx++) {
-            read_vec_element_i64(tmp, get_field(s, v2), idx, es);
-            tcg_gen_add_i64(sum, sum, tmp);
-        }
-        write_vec_element_i64(sum, get_field(s, v1), dst_idx, ES_64);
-    }
-    tcg_temp_free_i64(sum);
-    tcg_temp_free_i64(tmp);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vsumq(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m4);
-    const uint8_t max_idx = NUM_VEC_ELEMENTS(es) - 1;
-    TCGv_i64 sumh, suml, zero, tmpl;
-    uint8_t idx;
-
-    if (es < ES_32 || es > ES_64) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    sumh = tcg_const_i64(0);
-    suml = tcg_temp_new_i64();
-    zero = tcg_const_i64(0);
-    tmpl = tcg_temp_new_i64();
-
-    read_vec_element_i64(suml, get_field(s, v3), max_idx, es);
-    for (idx = 0; idx <= max_idx; idx++) {
-        read_vec_element_i64(tmpl, get_field(s, v2), idx, es);
-        tcg_gen_add2_i64(suml, sumh, suml, sumh, tmpl, zero);
-    }
-    write_vec_element_i64(sumh, get_field(s, v1), 0, ES_64);
-    write_vec_element_i64(suml, get_field(s, v1), 1, ES_64);
-
-    tcg_temp_free_i64(sumh);
-    tcg_temp_free_i64(suml);
-    tcg_temp_free_i64(zero);
-    tcg_temp_free_i64(tmpl);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vsum(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m4);
-    TCGv_i32 sum, tmp;
-    uint8_t dst_idx;
-
-    if (es > ES_16) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    sum = tcg_temp_new_i32();
-    tmp = tcg_temp_new_i32();
-    for (dst_idx = 0; dst_idx < 4; dst_idx++) {
-        uint8_t idx = dst_idx * NUM_VEC_ELEMENTS(es) / 4;
-        const uint8_t max_idx = idx + NUM_VEC_ELEMENTS(es) / 4 - 1;
-
-        read_vec_element_i32(sum, get_field(s, v3), max_idx, es);
-        for (; idx <= max_idx; idx++) {
-            read_vec_element_i32(tmp, get_field(s, v2), idx, es);
-            tcg_gen_add_i32(sum, sum, tmp);
-        }
-        write_vec_element_i32(sum, get_field(s, v1), dst_idx, ES_32);
-    }
-    tcg_temp_free_i32(sum);
-    tcg_temp_free_i32(tmp);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vtm(DisasContext *s, DisasOps *o)
-{
-    gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2),
-                   cpu_env, 0, gen_helper_gvec_vtm);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vfae(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m4);
-    const uint8_t m5 = get_field(s, m5);
-    static gen_helper_gvec_3 * const g[3] = {
-        gen_helper_gvec_vfae8,
-        gen_helper_gvec_vfae16,
-        gen_helper_gvec_vfae32,
-    };
-    static gen_helper_gvec_3_ptr * const g_cc[3] = {
-        gen_helper_gvec_vfae_cc8,
-        gen_helper_gvec_vfae_cc16,
-        gen_helper_gvec_vfae_cc32,
-    };
-    if (es > ES_32) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    if (extract32(m5, 0, 1)) {
-        gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2),
-                       get_field(s, v3), cpu_env, m5, g_cc[es]);
-        set_cc_static(s);
-    } else {
-        gen_gvec_3_ool(get_field(s, v1), get_field(s, v2),
-                       get_field(s, v3), m5, g[es]);
-    }
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vfee(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m4);
-    const uint8_t m5 = get_field(s, m5);
-    static gen_helper_gvec_3 * const g[3] = {
-        gen_helper_gvec_vfee8,
-        gen_helper_gvec_vfee16,
-        gen_helper_gvec_vfee32,
-    };
-    static gen_helper_gvec_3_ptr * const g_cc[3] = {
-        gen_helper_gvec_vfee_cc8,
-        gen_helper_gvec_vfee_cc16,
-        gen_helper_gvec_vfee_cc32,
-    };
-
-    if (es > ES_32 || m5 & ~0x3) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    if (extract32(m5, 0, 1)) {
-        gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2),
-                       get_field(s, v3), cpu_env, m5, g_cc[es]);
-        set_cc_static(s);
-    } else {
-        gen_gvec_3_ool(get_field(s, v1), get_field(s, v2),
-                       get_field(s, v3), m5, g[es]);
-    }
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vfene(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m4);
-    const uint8_t m5 = get_field(s, m5);
-    static gen_helper_gvec_3 * const g[3] = {
-        gen_helper_gvec_vfene8,
-        gen_helper_gvec_vfene16,
-        gen_helper_gvec_vfene32,
-    };
-    static gen_helper_gvec_3_ptr * const g_cc[3] = {
-        gen_helper_gvec_vfene_cc8,
-        gen_helper_gvec_vfene_cc16,
-        gen_helper_gvec_vfene_cc32,
-    };
-
-    if (es > ES_32 || m5 & ~0x3) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    if (extract32(m5, 0, 1)) {
-        gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2),
-                       get_field(s, v3), cpu_env, m5, g_cc[es]);
-        set_cc_static(s);
-    } else {
-        gen_gvec_3_ool(get_field(s, v1), get_field(s, v2),
-                       get_field(s, v3), m5, g[es]);
-    }
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vistr(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m4);
-    const uint8_t m5 = get_field(s, m5);
-    static gen_helper_gvec_2 * const g[3] = {
-        gen_helper_gvec_vistr8,
-        gen_helper_gvec_vistr16,
-        gen_helper_gvec_vistr32,
-    };
-    static gen_helper_gvec_2_ptr * const g_cc[3] = {
-        gen_helper_gvec_vistr_cc8,
-        gen_helper_gvec_vistr_cc16,
-        gen_helper_gvec_vistr_cc32,
-    };
-
-    if (es > ES_32 || m5 & ~0x1) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    if (extract32(m5, 0, 1)) {
-        gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2),
-                       cpu_env, 0, g_cc[es]);
-        set_cc_static(s);
-    } else {
-        gen_gvec_2_ool(get_field(s, v1), get_field(s, v2), 0,
-                       g[es]);
-    }
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vstrc(DisasContext *s, DisasOps *o)
-{
-    const uint8_t es = get_field(s, m5);
-    const uint8_t m6 = get_field(s, m6);
-    static gen_helper_gvec_4 * const g[3] = {
-        gen_helper_gvec_vstrc8,
-        gen_helper_gvec_vstrc16,
-        gen_helper_gvec_vstrc32,
-    };
-    static gen_helper_gvec_4 * const g_rt[3] = {
-        gen_helper_gvec_vstrc_rt8,
-        gen_helper_gvec_vstrc_rt16,
-        gen_helper_gvec_vstrc_rt32,
-    };
-    static gen_helper_gvec_4_ptr * const g_cc[3] = {
-        gen_helper_gvec_vstrc_cc8,
-        gen_helper_gvec_vstrc_cc16,
-        gen_helper_gvec_vstrc_cc32,
-    };
-    static gen_helper_gvec_4_ptr * const g_cc_rt[3] = {
-        gen_helper_gvec_vstrc_cc_rt8,
-        gen_helper_gvec_vstrc_cc_rt16,
-        gen_helper_gvec_vstrc_cc_rt32,
-    };
-
-    if (es > ES_32) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    if (extract32(m6, 0, 1)) {
-        if (extract32(m6, 2, 1)) {
-            gen_gvec_4_ptr(get_field(s, v1), get_field(s, v2),
-                           get_field(s, v3), get_field(s, v4),
-                           cpu_env, m6, g_cc_rt[es]);
-        } else {
-            gen_gvec_4_ptr(get_field(s, v1), get_field(s, v2),
-                           get_field(s, v3), get_field(s, v4),
-                           cpu_env, m6, g_cc[es]);
-        }
-        set_cc_static(s);
-    } else {
-        if (extract32(m6, 2, 1)) {
-            gen_gvec_4_ool(get_field(s, v1), get_field(s, v2),
-                           get_field(s, v3), get_field(s, v4),
-                           m6, g_rt[es]);
-        } else {
-            gen_gvec_4_ool(get_field(s, v1), get_field(s, v2),
-                           get_field(s, v3), get_field(s, v4),
-                           m6, g[es]);
-        }
-    }
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vfa(DisasContext *s, DisasOps *o)
-{
-    const uint8_t fpf = get_field(s, m4);
-    const uint8_t m5 = get_field(s, m5);
-    gen_helper_gvec_3_ptr *fn = NULL;
-
-    switch (s->fields.op2) {
-    case 0xe3:
-        switch (fpf) {
-        case FPF_SHORT:
-            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
-                fn = gen_helper_gvec_vfa32;
-            }
-            break;
-        case FPF_LONG:
-            fn = gen_helper_gvec_vfa64;
-            break;
-        case FPF_EXT:
-            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
-                fn = gen_helper_gvec_vfa128;
-            }
-            break;
-        default:
-            break;
-        }
-        break;
-    case 0xe5:
-        switch (fpf) {
-        case FPF_SHORT:
-            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
-                fn = gen_helper_gvec_vfd32;
-            }
-            break;
-        case FPF_LONG:
-            fn = gen_helper_gvec_vfd64;
-            break;
-        case FPF_EXT:
-            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
-                fn = gen_helper_gvec_vfd128;
-            }
-            break;
-        default:
-            break;
-        }
-        break;
-    case 0xe7:
-        switch (fpf) {
-        case FPF_SHORT:
-            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
-                fn = gen_helper_gvec_vfm32;
-            }
-            break;
-        case FPF_LONG:
-            fn = gen_helper_gvec_vfm64;
-            break;
-        case FPF_EXT:
-            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
-                fn = gen_helper_gvec_vfm128;
-            }
-            break;
-        default:
-            break;
-        }
-        break;
-    case 0xe2:
-        switch (fpf) {
-        case FPF_SHORT:
-            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
-                fn = gen_helper_gvec_vfs32;
-            }
-            break;
-        case FPF_LONG:
-            fn = gen_helper_gvec_vfs64;
-            break;
-        case FPF_EXT:
-            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
-                fn = gen_helper_gvec_vfs128;
-            }
-            break;
-        default:
-            break;
-        }
-        break;
-    default:
-        g_assert_not_reached();
-    }
-
-    if (!fn || extract32(m5, 0, 3)) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2),
-                   get_field(s, v3), cpu_env, m5, fn);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_wfc(DisasContext *s, DisasOps *o)
-{
-    const uint8_t fpf = get_field(s, m3);
-    const uint8_t m4 = get_field(s, m4);
-    gen_helper_gvec_2_ptr *fn = NULL;
-
-    switch (fpf) {
-    case FPF_SHORT:
-        if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
-            fn = gen_helper_gvec_wfk32;
-            if (s->fields.op2 == 0xcb) {
-                fn = gen_helper_gvec_wfc32;
-            }
-        }
-        break;
-    case FPF_LONG:
-        fn = gen_helper_gvec_wfk64;
-        if (s->fields.op2 == 0xcb) {
-            fn = gen_helper_gvec_wfc64;
-        }
-        break;
-    case FPF_EXT:
-        if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
-            fn = gen_helper_gvec_wfk128;
-            if (s->fields.op2 == 0xcb) {
-                fn = gen_helper_gvec_wfc128;
-            }
-        }
-        break;
-    default:
-        break;
-    };
-
-    if (!fn || m4) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, 0, fn);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vfc(DisasContext *s, DisasOps *o)
-{
-    const uint8_t fpf = get_field(s, m4);
-    const uint8_t m5 = get_field(s, m5);
-    const uint8_t m6 = get_field(s, m6);
-    const bool cs = extract32(m6, 0, 1);
-    const bool sq = extract32(m5, 2, 1);
-    gen_helper_gvec_3_ptr *fn = NULL;
-
-    switch (s->fields.op2) {
-    case 0xe8:
-        switch (fpf) {
-        case FPF_SHORT:
-            fn = cs ? gen_helper_gvec_vfce32_cc : gen_helper_gvec_vfce32;
-            break;
-        case FPF_LONG:
-            fn = cs ? gen_helper_gvec_vfce64_cc : gen_helper_gvec_vfce64;
-            break;
-        case FPF_EXT:
-            fn = cs ? gen_helper_gvec_vfce128_cc : gen_helper_gvec_vfce128;
-            break;
-        default:
-            break;
-        }
-        break;
-    case 0xeb:
-        switch (fpf) {
-        case FPF_SHORT:
-            fn = cs ? gen_helper_gvec_vfch32_cc : gen_helper_gvec_vfch32;
-            break;
-        case FPF_LONG:
-            fn = cs ? gen_helper_gvec_vfch64_cc : gen_helper_gvec_vfch64;
-            break;
-        case FPF_EXT:
-            fn = cs ? gen_helper_gvec_vfch128_cc : gen_helper_gvec_vfch128;
-            break;
-        default:
-            break;
-        }
-        break;
-    case 0xea:
-        switch (fpf) {
-        case FPF_SHORT:
-            fn = cs ? gen_helper_gvec_vfche32_cc : gen_helper_gvec_vfche32;
-            break;
-        case FPF_LONG:
-            fn = cs ? gen_helper_gvec_vfche64_cc : gen_helper_gvec_vfche64;
-            break;
-        case FPF_EXT:
-            fn = cs ? gen_helper_gvec_vfche128_cc : gen_helper_gvec_vfche128;
-            break;
-        default:
-            break;
-        }
-        break;
-    default:
-        g_assert_not_reached();
-    }
-
-    if (!fn || extract32(m5, 0, 2) || extract32(m6, 1, 3) ||
-        (!s390_has_feat(S390_FEAT_VECTOR_ENH) && (fpf != FPF_LONG || sq))) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2), get_field(s, v3),
-                   cpu_env, m5, fn);
-    if (cs) {
-        set_cc_static(s);
-    }
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vcdg(DisasContext *s, DisasOps *o)
-{
-    const uint8_t fpf = get_field(s, m3);
-    const uint8_t m4 = get_field(s, m4);
-    const uint8_t erm = get_field(s, m5);
-    gen_helper_gvec_2_ptr *fn = NULL;
-
-
-    switch (s->fields.op2) {
-    case 0xc3:
-        if (fpf == FPF_LONG) {
-            fn = gen_helper_gvec_vcdg64;
-        }
-        break;
-    case 0xc1:
-        if (fpf == FPF_LONG) {
-            fn = gen_helper_gvec_vcdlg64;
-        }
-        break;
-    case 0xc2:
-        if (fpf == FPF_LONG) {
-            fn = gen_helper_gvec_vcgd64;
-        }
-        break;
-    case 0xc0:
-        if (fpf == FPF_LONG) {
-            fn = gen_helper_gvec_vclgd64;
-        }
-        break;
-    case 0xc7:
-        switch (fpf) {
-        case FPF_SHORT:
-            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
-                fn = gen_helper_gvec_vfi32;
-            }
-            break;
-        case FPF_LONG:
-            fn = gen_helper_gvec_vfi64;
-            break;
-        case FPF_EXT:
-            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
-                fn = gen_helper_gvec_vfi128;
-            }
-            break;
-        default:
-            break;
-        }
-        break;
-    case 0xc5:
-        switch (fpf) {
-        case FPF_LONG:
-            fn = gen_helper_gvec_vflr64;
-            break;
-        case FPF_EXT:
-            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
-                fn = gen_helper_gvec_vflr128;
-            }
-            break;
-        default:
-            break;
-        }
-        break;
-    default:
-        g_assert_not_reached();
-    }
-
-    if (!fn || extract32(m4, 0, 2) || erm > 7 || erm == 2) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env,
-                   deposit32(m4, 4, 4, erm), fn);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vfll(DisasContext *s, DisasOps *o)
-{
-    const uint8_t fpf = get_field(s, m3);
-    const uint8_t m4 = get_field(s, m4);
-    gen_helper_gvec_2_ptr *fn = NULL;
-
-    switch (fpf) {
-    case FPF_SHORT:
-        fn = gen_helper_gvec_vfll32;
-        break;
-    case FPF_LONG:
-        if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
-            fn = gen_helper_gvec_vfll64;
-        }
-        break;
-    default:
-        break;
-    }
-
-    if (!fn || extract32(m4, 0, 3)) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, m4, fn);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vfmax(DisasContext *s, DisasOps *o)
-{
-    const uint8_t fpf = get_field(s, m4);
-    const uint8_t m6 = get_field(s, m6);
-    const uint8_t m5 = get_field(s, m5);
-    gen_helper_gvec_3_ptr *fn;
-
-    if (m6 == 5 || m6 == 6 || m6 == 7 || m6 > 13) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    switch (fpf) {
-    case FPF_SHORT:
-        if (s->fields.op2 == 0xef) {
-            fn = gen_helper_gvec_vfmax32;
-        } else {
-            fn = gen_helper_gvec_vfmin32;
-        }
-        break;
-    case FPF_LONG:
-        if (s->fields.op2 == 0xef) {
-            fn = gen_helper_gvec_vfmax64;
-        } else {
-            fn = gen_helper_gvec_vfmin64;
-        }
-        break;
-    case FPF_EXT:
-        if (s->fields.op2 == 0xef) {
-            fn = gen_helper_gvec_vfmax128;
-        } else {
-            fn = gen_helper_gvec_vfmin128;
-        }
-        break;
-    default:
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2), get_field(s, v3),
-                   cpu_env, deposit32(m5, 4, 4, m6), fn);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vfma(DisasContext *s, DisasOps *o)
-{
-    const uint8_t m5 = get_field(s, m5);
-    const uint8_t fpf = get_field(s, m6);
-    gen_helper_gvec_4_ptr *fn = NULL;
-
-    switch (s->fields.op2) {
-    case 0x8f:
-        switch (fpf) {
-        case FPF_SHORT:
-            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
-                fn = gen_helper_gvec_vfma32;
-            }
-            break;
-        case FPF_LONG:
-            fn = gen_helper_gvec_vfma64;
-            break;
-        case FPF_EXT:
-            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
-                fn = gen_helper_gvec_vfma128;
-            }
-            break;
-        default:
-            break;
-        }
-        break;
-    case 0x8e:
-        switch (fpf) {
-        case FPF_SHORT:
-            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
-                fn = gen_helper_gvec_vfms32;
-            }
-            break;
-        case FPF_LONG:
-            fn = gen_helper_gvec_vfms64;
-            break;
-        case FPF_EXT:
-            if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
-                fn = gen_helper_gvec_vfms128;
-            }
-            break;
-        default:
-            break;
-        }
-        break;
-    case 0x9f:
-        switch (fpf) {
-        case FPF_SHORT:
-            fn = gen_helper_gvec_vfnma32;
-            break;
-        case FPF_LONG:
-            fn = gen_helper_gvec_vfnma64;
-            break;
-        case FPF_EXT:
-            fn = gen_helper_gvec_vfnma128;
-            break;
-        default:
-            break;
-        }
-        break;
-    case 0x9e:
-        switch (fpf) {
-        case FPF_SHORT:
-            fn = gen_helper_gvec_vfnms32;
-            break;
-        case FPF_LONG:
-            fn = gen_helper_gvec_vfnms64;
-            break;
-        case FPF_EXT:
-            fn = gen_helper_gvec_vfnms128;
-            break;
-        default:
-            break;
-        }
-        break;
-    default:
-        g_assert_not_reached();
-    }
-
-    if (!fn || extract32(m5, 0, 3)) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    gen_gvec_4_ptr(get_field(s, v1), get_field(s, v2),
-                   get_field(s, v3), get_field(s, v4), cpu_env, m5, fn);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vfpso(DisasContext *s, DisasOps *o)
-{
-    const uint8_t v1 = get_field(s, v1);
-    const uint8_t v2 = get_field(s, v2);
-    const uint8_t fpf = get_field(s, m3);
-    const uint8_t m4 = get_field(s, m4);
-    const uint8_t m5 = get_field(s, m5);
-    const bool se = extract32(m4, 3, 1);
-    TCGv_i64 tmp;
-
-    if ((fpf != FPF_LONG && !s390_has_feat(S390_FEAT_VECTOR_ENH)) ||
-        extract32(m4, 0, 3) || m5 > 2) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    switch (fpf) {
-    case FPF_SHORT:
-        if (!se) {
-            switch (m5) {
-            case 0:
-                /* sign bit is inverted (complement) */
-                gen_gvec_fn_2i(xori, ES_32, v1, v2, 1ull << 31);
-                break;
-            case 1:
-                /* sign bit is set to one (negative) */
-                gen_gvec_fn_2i(ori, ES_32, v1, v2, 1ull << 31);
-                break;
-            case 2:
-                /* sign bit is set to zero (positive) */
-                gen_gvec_fn_2i(andi, ES_32, v1, v2, (1ull << 31) - 1);
-                break;
-            }
-            return DISAS_NEXT;
-        }
-        break;
-    case FPF_LONG:
-        if (!se) {
-            switch (m5) {
-            case 0:
-                /* sign bit is inverted (complement) */
-                gen_gvec_fn_2i(xori, ES_64, v1, v2, 1ull << 63);
-                break;
-            case 1:
-                /* sign bit is set to one (negative) */
-                gen_gvec_fn_2i(ori, ES_64, v1, v2, 1ull << 63);
-                break;
-            case 2:
-                /* sign bit is set to zero (positive) */
-                gen_gvec_fn_2i(andi, ES_64, v1, v2, (1ull << 63) - 1);
-                break;
-            }
-            return DISAS_NEXT;
-        }
-        break;
-    case FPF_EXT:
-        /* Only a single element. */
-        break;
-    default:
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    /* With a single element, we are only interested in bit 0. */
-    tmp = tcg_temp_new_i64();
-    read_vec_element_i64(tmp, v2, 0, ES_64);
-    switch (m5) {
-    case 0:
-        /* sign bit is inverted (complement) */
-        tcg_gen_xori_i64(tmp, tmp, 1ull << 63);
-        break;
-    case 1:
-        /* sign bit is set to one (negative) */
-        tcg_gen_ori_i64(tmp, tmp, 1ull << 63);
-        break;
-    case 2:
-        /* sign bit is set to zero (positive) */
-        tcg_gen_andi_i64(tmp, tmp, (1ull << 63) - 1);
-        break;
-    }
-    write_vec_element_i64(tmp, v1, 0, ES_64);
-
-    if (fpf == FPF_EXT) {
-        read_vec_element_i64(tmp, v2, 1, ES_64);
-        write_vec_element_i64(tmp, v1, 1, ES_64);
-    }
-
-    tcg_temp_free_i64(tmp);
-
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vfsq(DisasContext *s, DisasOps *o)
-{
-    const uint8_t fpf = get_field(s, m3);
-    const uint8_t m4 = get_field(s, m4);
-    gen_helper_gvec_2_ptr *fn = NULL;
-
-    switch (fpf) {
-    case FPF_SHORT:
-        if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
-            fn = gen_helper_gvec_vfsq32;
-        }
-        break;
-    case FPF_LONG:
-        fn = gen_helper_gvec_vfsq64;
-        break;
-    case FPF_EXT:
-        if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
-            fn = gen_helper_gvec_vfsq128;
-        }
-        break;
-    default:
-        break;
-    }
-
-    if (!fn || extract32(m4, 0, 3)) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, m4, fn);
-    return DISAS_NEXT;
-}
-
-static DisasJumpType op_vftci(DisasContext *s, DisasOps *o)
-{
-    const uint16_t i3 = get_field(s, i3);
-    const uint8_t fpf = get_field(s, m4);
-    const uint8_t m5 = get_field(s, m5);
-    gen_helper_gvec_2_ptr *fn = NULL;
-
-    switch (fpf) {
-    case FPF_SHORT:
-        if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
-            fn = gen_helper_gvec_vftci32;
-        }
-        break;
-    case FPF_LONG:
-        fn = gen_helper_gvec_vftci64;
-        break;
-    case FPF_EXT:
-        if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
-            fn = gen_helper_gvec_vftci128;
-        }
-        break;
-    default:
-        break;
-    }
-
-    if (!fn || extract32(m5, 0, 3)) {
-        gen_program_exception(s, PGM_SPECIFICATION);
-        return DISAS_NORETURN;
-    }
-
-    gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env,
-                   deposit32(m5, 4, 12, i3), fn);
-    set_cc_static(s);
-    return DISAS_NEXT;
-}
diff --git a/target/s390x/vec.h b/target/s390x/vec.h
deleted file mode 100644 (file)
index a6e3618..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * QEMU TCG support -- s390x vector utilitites
- *
- * Copyright (C) 2019 Red Hat Inc
- *
- * Authors:
- *   David Hildenbrand <david@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-#ifndef S390X_VEC_H
-#define S390X_VEC_H
-
-#include "tcg/tcg.h"
-
-typedef union S390Vector {
-    uint64_t doubleword[2];
-    uint32_t word[4];
-    uint16_t halfword[8];
-    uint8_t byte[16];
-} S390Vector;
-
-/*
- * Each vector is stored as two 64bit host values. So when talking about
- * byte/halfword/word numbers, we have to take care of proper translation
- * between element numbers.
- *
- * Big Endian (target/possible host)
- * B:  [ 0][ 1][ 2][ 3][ 4][ 5][ 6][ 7] - [ 8][ 9][10][11][12][13][14][15]
- * HW: [     0][     1][     2][     3] - [     4][     5][     6][     7]
- * W:  [             0][             1] - [             2][             3]
- * DW: [                             0] - [                             1]
- *
- * Little Endian (possible host)
- * B:  [ 7][ 6][ 5][ 4][ 3][ 2][ 1][ 0] - [15][14][13][12][11][10][ 9][ 8]
- * HW: [     3][     2][     1][     0] - [     7][     6][     5][     4]
- * W:  [             1][             0] - [             3][             2]
- * DW: [                             0] - [                             1]
- */
-#ifndef HOST_WORDS_BIGENDIAN
-#define H1(x)  ((x) ^ 7)
-#define H2(x)  ((x) ^ 3)
-#define H4(x)  ((x) ^ 1)
-#else
-#define H1(x)  (x)
-#define H2(x)  (x)
-#define H4(x)  (x)
-#endif
-
-static inline uint8_t s390_vec_read_element8(const S390Vector *v, uint8_t enr)
-{
-    g_assert(enr < 16);
-    return v->byte[H1(enr)];
-}
-
-static inline uint16_t s390_vec_read_element16(const S390Vector *v, uint8_t enr)
-{
-    g_assert(enr < 8);
-    return v->halfword[H2(enr)];
-}
-
-static inline uint32_t s390_vec_read_element32(const S390Vector *v, uint8_t enr)
-{
-    g_assert(enr < 4);
-    return v->word[H4(enr)];
-}
-
-static inline uint64_t s390_vec_read_element64(const S390Vector *v, uint8_t enr)
-{
-    g_assert(enr < 2);
-    return v->doubleword[enr];
-}
-
-static inline uint64_t s390_vec_read_element(const S390Vector *v, uint8_t enr,
-                                             uint8_t es)
-{
-    switch (es) {
-    case MO_8:
-        return s390_vec_read_element8(v, enr);
-    case MO_16:
-        return s390_vec_read_element16(v, enr);
-    case MO_32:
-        return s390_vec_read_element32(v, enr);
-    case MO_64:
-        return s390_vec_read_element64(v, enr);
-    default:
-        g_assert_not_reached();
-    }
-}
-
-static inline void s390_vec_write_element8(S390Vector *v, uint8_t enr,
-                                           uint8_t data)
-{
-    g_assert(enr < 16);
-    v->byte[H1(enr)] = data;
-}
-
-static inline void s390_vec_write_element16(S390Vector *v, uint8_t enr,
-                                            uint16_t data)
-{
-    g_assert(enr < 8);
-    v->halfword[H2(enr)] = data;
-}
-
-static inline void s390_vec_write_element32(S390Vector *v, uint8_t enr,
-                                            uint32_t data)
-{
-    g_assert(enr < 4);
-    v->word[H4(enr)] = data;
-}
-
-static inline void s390_vec_write_element64(S390Vector *v, uint8_t enr,
-                                            uint64_t data)
-{
-    g_assert(enr < 2);
-    v->doubleword[enr] = data;
-}
-
-static inline void s390_vec_write_element(S390Vector *v, uint8_t enr,
-                                          uint8_t es, uint64_t data)
-{
-    switch (es) {
-    case MO_8:
-        s390_vec_write_element8(v, enr, data);
-        break;
-    case MO_16:
-        s390_vec_write_element16(v, enr, data);
-        break;
-    case MO_32:
-        s390_vec_write_element32(v, enr, data);
-        break;
-    case MO_64:
-        s390_vec_write_element64(v, enr, data);
-        break;
-    default:
-        g_assert_not_reached();
-    }
-}
-
-#endif /* S390X_VEC_H */
diff --git a/target/s390x/vec_fpu_helper.c b/target/s390x/vec_fpu_helper.c
deleted file mode 100644 (file)
index 8e2b274..0000000
+++ /dev/null
@@ -1,1072 +0,0 @@
-/*
- * QEMU TCG support -- s390x vector floating point instruction support
- *
- * Copyright (C) 2019 Red Hat Inc
- *
- * Authors:
- *   David Hildenbrand <david@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "internal.h"
-#include "vec.h"
-#include "tcg_s390x.h"
-#include "tcg/tcg-gvec-desc.h"
-#include "exec/exec-all.h"
-#include "exec/helper-proto.h"
-#include "fpu/softfloat.h"
-
-#define VIC_INVALID         0x1
-#define VIC_DIVBYZERO       0x2
-#define VIC_OVERFLOW        0x3
-#define VIC_UNDERFLOW       0x4
-#define VIC_INEXACT         0x5
-
-/* returns the VEX. If the VEX is 0, there is no trap */
-static uint8_t check_ieee_exc(CPUS390XState *env, uint8_t enr, bool XxC,
-                              uint8_t *vec_exc)
-{
-    uint8_t vece_exc = 0, trap_exc;
-    unsigned qemu_exc;
-
-    /* Retrieve and clear the softfloat exceptions */
-    qemu_exc = env->fpu_status.float_exception_flags;
-    if (qemu_exc == 0) {
-        return 0;
-    }
-    env->fpu_status.float_exception_flags = 0;
-
-    vece_exc = s390_softfloat_exc_to_ieee(qemu_exc);
-
-    /* Add them to the vector-wide s390x exception bits */
-    *vec_exc |= vece_exc;
-
-    /* Check for traps and construct the VXC */
-    trap_exc = vece_exc & env->fpc >> 24;
-    if (trap_exc) {
-        if (trap_exc & S390_IEEE_MASK_INVALID) {
-            return enr << 4 | VIC_INVALID;
-        } else if (trap_exc & S390_IEEE_MASK_DIVBYZERO) {
-            return enr << 4 | VIC_DIVBYZERO;
-        } else if (trap_exc & S390_IEEE_MASK_OVERFLOW) {
-            return enr << 4 | VIC_OVERFLOW;
-        } else if (trap_exc & S390_IEEE_MASK_UNDERFLOW) {
-            return enr << 4 | VIC_UNDERFLOW;
-        } else if (!XxC) {
-            g_assert(trap_exc & S390_IEEE_MASK_INEXACT);
-            /* inexact has lowest priority on traps */
-            return enr << 4 | VIC_INEXACT;
-        }
-    }
-    return 0;
-}
-
-static void handle_ieee_exc(CPUS390XState *env, uint8_t vxc, uint8_t vec_exc,
-                            uintptr_t retaddr)
-{
-    if (vxc) {
-        /* on traps, the fpc flags are not updated, instruction is suppressed */
-        tcg_s390_vector_exception(env, vxc, retaddr);
-    }
-    if (vec_exc) {
-        /* indicate exceptions for all elements combined */
-        env->fpc |= vec_exc << 16;
-    }
-}
-
-static float32 s390_vec_read_float32(const S390Vector *v, uint8_t enr)
-{
-    return make_float32(s390_vec_read_element32(v, enr));
-}
-
-static float64 s390_vec_read_float64(const S390Vector *v, uint8_t enr)
-{
-    return make_float64(s390_vec_read_element64(v, enr));
-}
-
-static float128 s390_vec_read_float128(const S390Vector *v)
-{
-    return make_float128(s390_vec_read_element64(v, 0),
-                         s390_vec_read_element64(v, 1));
-}
-
-static void s390_vec_write_float32(S390Vector *v, uint8_t enr, float32 data)
-{
-    return s390_vec_write_element32(v, enr, data);
-}
-
-static void s390_vec_write_float64(S390Vector *v, uint8_t enr, float64 data)
-{
-    return s390_vec_write_element64(v, enr, data);
-}
-
-static void s390_vec_write_float128(S390Vector *v, float128 data)
-{
-    s390_vec_write_element64(v, 0, data.high);
-    s390_vec_write_element64(v, 1, data.low);
-}
-
-typedef float32 (*vop32_2_fn)(float32 a, float_status *s);
-static void vop32_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env,
-                    bool s, bool XxC, uint8_t erm, vop32_2_fn fn,
-                    uintptr_t retaddr)
-{
-    uint8_t vxc, vec_exc = 0;
-    S390Vector tmp = {};
-    int i, old_mode;
-
-    old_mode = s390_swap_bfp_rounding_mode(env, erm);
-    for (i = 0; i < 4; i++) {
-        const float32 a = s390_vec_read_float32(v2, i);
-
-        s390_vec_write_float32(&tmp, i, fn(a, &env->fpu_status));
-        vxc = check_ieee_exc(env, i, XxC, &vec_exc);
-        if (s || vxc) {
-            break;
-        }
-    }
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_ieee_exc(env, vxc, vec_exc, retaddr);
-    *v1 = tmp;
-}
-
-typedef float64 (*vop64_2_fn)(float64 a, float_status *s);
-static void vop64_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env,
-                    bool s, bool XxC, uint8_t erm, vop64_2_fn fn,
-                    uintptr_t retaddr)
-{
-    uint8_t vxc, vec_exc = 0;
-    S390Vector tmp = {};
-    int i, old_mode;
-
-    old_mode = s390_swap_bfp_rounding_mode(env, erm);
-    for (i = 0; i < 2; i++) {
-        const float64 a = s390_vec_read_float64(v2, i);
-
-        s390_vec_write_float64(&tmp, i, fn(a, &env->fpu_status));
-        vxc = check_ieee_exc(env, i, XxC, &vec_exc);
-        if (s || vxc) {
-            break;
-        }
-    }
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_ieee_exc(env, vxc, vec_exc, retaddr);
-    *v1 = tmp;
-}
-
-typedef float128 (*vop128_2_fn)(float128 a, float_status *s);
-static void vop128_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env,
-                    bool s, bool XxC, uint8_t erm, vop128_2_fn fn,
-                    uintptr_t retaddr)
-{
-    const float128 a = s390_vec_read_float128(v2);
-    uint8_t vxc, vec_exc = 0;
-    S390Vector tmp = {};
-    int old_mode;
-
-    old_mode = s390_swap_bfp_rounding_mode(env, erm);
-    s390_vec_write_float128(&tmp, fn(a, &env->fpu_status));
-    vxc = check_ieee_exc(env, 0, XxC, &vec_exc);
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_ieee_exc(env, vxc, vec_exc, retaddr);
-    *v1 = tmp;
-}
-
-static float64 vcdg64(float64 a, float_status *s)
-{
-    return int64_to_float64(a, s);
-}
-
-static float64 vcdlg64(float64 a, float_status *s)
-{
-    return uint64_to_float64(a, s);
-}
-
-static float64 vcgd64(float64 a, float_status *s)
-{
-    const float64 tmp = float64_to_int64(a, s);
-
-    return float64_is_any_nan(a) ? INT64_MIN : tmp;
-}
-
-static float64 vclgd64(float64 a, float_status *s)
-{
-    const float64 tmp = float64_to_uint64(a, s);
-
-    return float64_is_any_nan(a) ? 0 : tmp;
-}
-
-#define DEF_GVEC_VOP2_FN(NAME, FN, BITS)                                       \
-void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, CPUS390XState *env,   \
-                               uint32_t desc)                                  \
-{                                                                              \
-    const uint8_t erm = extract32(simd_data(desc), 4, 4);                      \
-    const bool se = extract32(simd_data(desc), 3, 1);                          \
-    const bool XxC = extract32(simd_data(desc), 2, 1);                         \
-                                                                               \
-    vop##BITS##_2(v1, v2, env, se, XxC, erm, FN, GETPC());                     \
-}
-
-#define DEF_GVEC_VOP2_64(NAME)                                                 \
-DEF_GVEC_VOP2_FN(NAME, NAME##64, 64)
-
-#define DEF_GVEC_VOP2(NAME, OP)                                                \
-DEF_GVEC_VOP2_FN(NAME, float32_##OP, 32)                                       \
-DEF_GVEC_VOP2_FN(NAME, float64_##OP, 64)                                       \
-DEF_GVEC_VOP2_FN(NAME, float128_##OP, 128)
-
-DEF_GVEC_VOP2_64(vcdg)
-DEF_GVEC_VOP2_64(vcdlg)
-DEF_GVEC_VOP2_64(vcgd)
-DEF_GVEC_VOP2_64(vclgd)
-DEF_GVEC_VOP2(vfi, round_to_int)
-DEF_GVEC_VOP2(vfsq, sqrt)
-
-typedef float32 (*vop32_3_fn)(float32 a, float32 b, float_status *s);
-static void vop32_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
-                    CPUS390XState *env, bool s, vop32_3_fn fn,
-                    uintptr_t retaddr)
-{
-    uint8_t vxc, vec_exc = 0;
-    S390Vector tmp = {};
-    int i;
-
-    for (i = 0; i < 4; i++) {
-        const float32 a = s390_vec_read_float32(v2, i);
-        const float32 b = s390_vec_read_float32(v3, i);
-
-        s390_vec_write_float32(&tmp, i, fn(a, b, &env->fpu_status));
-        vxc = check_ieee_exc(env, i, false, &vec_exc);
-        if (s || vxc) {
-            break;
-        }
-    }
-    handle_ieee_exc(env, vxc, vec_exc, retaddr);
-    *v1 = tmp;
-}
-
-typedef float64 (*vop64_3_fn)(float64 a, float64 b, float_status *s);
-static void vop64_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
-                    CPUS390XState *env, bool s, vop64_3_fn fn,
-                    uintptr_t retaddr)
-{
-    uint8_t vxc, vec_exc = 0;
-    S390Vector tmp = {};
-    int i;
-
-    for (i = 0; i < 2; i++) {
-        const float64 a = s390_vec_read_float64(v2, i);
-        const float64 b = s390_vec_read_float64(v3, i);
-
-        s390_vec_write_float64(&tmp, i, fn(a, b, &env->fpu_status));
-        vxc = check_ieee_exc(env, i, false, &vec_exc);
-        if (s || vxc) {
-            break;
-        }
-    }
-    handle_ieee_exc(env, vxc, vec_exc, retaddr);
-    *v1 = tmp;
-}
-
-typedef float128 (*vop128_3_fn)(float128 a, float128 b, float_status *s);
-static void vop128_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
-                     CPUS390XState *env, bool s, vop128_3_fn fn,
-                     uintptr_t retaddr)
-{
-    const float128 a = s390_vec_read_float128(v2);
-    const float128 b = s390_vec_read_float128(v3);
-    uint8_t vxc, vec_exc = 0;
-    S390Vector tmp = {};
-
-    s390_vec_write_float128(&tmp, fn(a, b, &env->fpu_status));
-    vxc = check_ieee_exc(env, 0, false, &vec_exc);
-    handle_ieee_exc(env, vxc, vec_exc, retaddr);
-    *v1 = tmp;
-}
-
-#define DEF_GVEC_VOP3_B(NAME, OP, BITS)                                        \
-void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3,       \
-                              CPUS390XState *env, uint32_t desc)               \
-{                                                                              \
-    const bool se = extract32(simd_data(desc), 3, 1);                          \
-                                                                               \
-    vop##BITS##_3(v1, v2, v3, env, se, float##BITS##_##OP, GETPC());           \
-}
-
-#define DEF_GVEC_VOP3(NAME, OP)                                                \
-DEF_GVEC_VOP3_B(NAME, OP, 32)                                                  \
-DEF_GVEC_VOP3_B(NAME, OP, 64)                                                  \
-DEF_GVEC_VOP3_B(NAME, OP, 128)
-
-DEF_GVEC_VOP3(vfa, add)
-DEF_GVEC_VOP3(vfs, sub)
-DEF_GVEC_VOP3(vfd, div)
-DEF_GVEC_VOP3(vfm, mul)
-
-static int wfc32(const S390Vector *v1, const S390Vector *v2,
-                 CPUS390XState *env, bool signal, uintptr_t retaddr)
-{
-    /* only the zero-indexed elements are compared */
-    const float32 a = s390_vec_read_float32(v1, 0);
-    const float32 b = s390_vec_read_float32(v2, 0);
-    uint8_t vxc, vec_exc = 0;
-    int cmp;
-
-    if (signal) {
-        cmp = float32_compare(a, b, &env->fpu_status);
-    } else {
-        cmp = float32_compare_quiet(a, b, &env->fpu_status);
-    }
-    vxc = check_ieee_exc(env, 0, false, &vec_exc);
-    handle_ieee_exc(env, vxc, vec_exc, retaddr);
-
-    return float_comp_to_cc(env, cmp);
-}
-
-static int wfc64(const S390Vector *v1, const S390Vector *v2,
-                 CPUS390XState *env, bool signal, uintptr_t retaddr)
-{
-    /* only the zero-indexed elements are compared */
-    const float64 a = s390_vec_read_float64(v1, 0);
-    const float64 b = s390_vec_read_float64(v2, 0);
-    uint8_t vxc, vec_exc = 0;
-    int cmp;
-
-    if (signal) {
-        cmp = float64_compare(a, b, &env->fpu_status);
-    } else {
-        cmp = float64_compare_quiet(a, b, &env->fpu_status);
-    }
-    vxc = check_ieee_exc(env, 0, false, &vec_exc);
-    handle_ieee_exc(env, vxc, vec_exc, retaddr);
-
-    return float_comp_to_cc(env, cmp);
-}
-
-static int wfc128(const S390Vector *v1, const S390Vector *v2,
-                  CPUS390XState *env, bool signal, uintptr_t retaddr)
-{
-    /* only the zero-indexed elements are compared */
-    const float128 a = s390_vec_read_float128(v1);
-    const float128 b = s390_vec_read_float128(v2);
-    uint8_t vxc, vec_exc = 0;
-    int cmp;
-
-    if (signal) {
-        cmp = float128_compare(a, b, &env->fpu_status);
-    } else {
-        cmp = float128_compare_quiet(a, b, &env->fpu_status);
-    }
-    vxc = check_ieee_exc(env, 0, false, &vec_exc);
-    handle_ieee_exc(env, vxc, vec_exc, retaddr);
-
-    return float_comp_to_cc(env, cmp);
-}
-
-#define DEF_GVEC_WFC_B(NAME, SIGNAL, BITS)                                     \
-void HELPER(gvec_##NAME##BITS)(const void *v1, const void *v2,                 \
-                               CPUS390XState *env, uint32_t desc)              \
-{                                                                              \
-    env->cc_op = wfc##BITS(v1, v2, env, SIGNAL, GETPC());                      \
-}
-
-#define DEF_GVEC_WFC(NAME, SIGNAL)                                             \
-     DEF_GVEC_WFC_B(NAME, SIGNAL, 32)                                          \
-     DEF_GVEC_WFC_B(NAME, SIGNAL, 64)                                          \
-     DEF_GVEC_WFC_B(NAME, SIGNAL, 128)
-
-DEF_GVEC_WFC(wfc, false)
-DEF_GVEC_WFC(wfk, true)
-
-typedef bool (*vfc32_fn)(float32 a, float32 b, float_status *status);
-static int vfc32(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
-                 CPUS390XState *env, bool s, vfc32_fn fn, uintptr_t retaddr)
-{
-    uint8_t vxc, vec_exc = 0;
-    S390Vector tmp = {};
-    int match = 0;
-    int i;
-
-    for (i = 0; i < 4; i++) {
-        const float32 a = s390_vec_read_float32(v2, i);
-        const float32 b = s390_vec_read_float32(v3, i);
-
-        /* swap the order of the parameters, so we can use existing functions */
-        if (fn(b, a, &env->fpu_status)) {
-            match++;
-            s390_vec_write_element32(&tmp, i, -1u);
-        }
-        vxc = check_ieee_exc(env, i, false, &vec_exc);
-        if (s || vxc) {
-            break;
-        }
-    }
-
-    handle_ieee_exc(env, vxc, vec_exc, retaddr);
-    *v1 = tmp;
-    if (match) {
-        return s || match == 4 ? 0 : 1;
-    }
-    return 3;
-}
-
-typedef bool (*vfc64_fn)(float64 a, float64 b, float_status *status);
-static int vfc64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
-                 CPUS390XState *env, bool s, vfc64_fn fn, uintptr_t retaddr)
-{
-    uint8_t vxc, vec_exc = 0;
-    S390Vector tmp = {};
-    int match = 0;
-    int i;
-
-    for (i = 0; i < 2; i++) {
-        const float64 a = s390_vec_read_float64(v2, i);
-        const float64 b = s390_vec_read_float64(v3, i);
-
-        /* swap the order of the parameters, so we can use existing functions */
-        if (fn(b, a, &env->fpu_status)) {
-            match++;
-            s390_vec_write_element64(&tmp, i, -1ull);
-        }
-        vxc = check_ieee_exc(env, i, false, &vec_exc);
-        if (s || vxc) {
-            break;
-        }
-    }
-
-    handle_ieee_exc(env, vxc, vec_exc, retaddr);
-    *v1 = tmp;
-    if (match) {
-        return s || match == 2 ? 0 : 1;
-    }
-    return 3;
-}
-
-typedef bool (*vfc128_fn)(float128 a, float128 b, float_status *status);
-static int vfc128(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
-                 CPUS390XState *env, bool s, vfc128_fn fn, uintptr_t retaddr)
-{
-    const float128 a = s390_vec_read_float128(v2);
-    const float128 b = s390_vec_read_float128(v3);
-    uint8_t vxc, vec_exc = 0;
-    S390Vector tmp = {};
-    bool match = false;
-
-    /* swap the order of the parameters, so we can use existing functions */
-    if (fn(b, a, &env->fpu_status)) {
-        match = true;
-        s390_vec_write_element64(&tmp, 0, -1ull);
-        s390_vec_write_element64(&tmp, 1, -1ull);
-    }
-    vxc = check_ieee_exc(env, 0, false, &vec_exc);
-    handle_ieee_exc(env, vxc, vec_exc, retaddr);
-    *v1 = tmp;
-    return match ? 0 : 3;
-}
-
-#define DEF_GVEC_VFC_B(NAME, OP, BITS)                                         \
-void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3,       \
-                               CPUS390XState *env, uint32_t desc)              \
-{                                                                              \
-    const bool se = extract32(simd_data(desc), 3, 1);                          \
-    const bool sq = extract32(simd_data(desc), 2, 1);                          \
-    vfc##BITS##_fn fn = sq ? float##BITS##_##OP : float##BITS##_##OP##_quiet;  \
-                                                                               \
-    vfc##BITS(v1, v2, v3, env, se, fn, GETPC());                               \
-}                                                                              \
-                                                                               \
-void HELPER(gvec_##NAME##BITS##_cc)(void *v1, const void *v2, const void *v3,  \
-                                    CPUS390XState *env, uint32_t desc)         \
-{                                                                              \
-    const bool se = extract32(simd_data(desc), 3, 1);                          \
-    const bool sq = extract32(simd_data(desc), 2, 1);                          \
-    vfc##BITS##_fn fn = sq ? float##BITS##_##OP : float##BITS##_##OP##_quiet;  \
-                                                                               \
-    env->cc_op = vfc##BITS(v1, v2, v3, env, se, fn, GETPC());                  \
-}
-
-#define DEF_GVEC_VFC(NAME, OP)                                                 \
-DEF_GVEC_VFC_B(NAME, OP, 32)                                                   \
-DEF_GVEC_VFC_B(NAME, OP, 64)                                                   \
-DEF_GVEC_VFC_B(NAME, OP, 128)                                                  \
-
-DEF_GVEC_VFC(vfce, eq)
-DEF_GVEC_VFC(vfch, lt)
-DEF_GVEC_VFC(vfche, le)
-
-void HELPER(gvec_vfll32)(void *v1, const void *v2, CPUS390XState *env,
-                         uint32_t desc)
-{
-    const bool s = extract32(simd_data(desc), 3, 1);
-    uint8_t vxc, vec_exc = 0;
-    S390Vector tmp = {};
-    int i;
-
-    for (i = 0; i < 2; i++) {
-        /* load from even element */
-        const float32 a = s390_vec_read_element32(v2, i * 2);
-        const uint64_t ret = float32_to_float64(a, &env->fpu_status);
-
-        s390_vec_write_element64(&tmp, i, ret);
-        /* indicate the source element */
-        vxc = check_ieee_exc(env, i * 2, false, &vec_exc);
-        if (s || vxc) {
-            break;
-        }
-    }
-    handle_ieee_exc(env, vxc, vec_exc, GETPC());
-    *(S390Vector *)v1 = tmp;
-}
-
-void HELPER(gvec_vfll64)(void *v1, const void *v2, CPUS390XState *env,
-                         uint32_t desc)
-{
-    /* load from even element */
-    const float128 ret = float64_to_float128(s390_vec_read_float64(v2, 0),
-                                             &env->fpu_status);
-    uint8_t vxc, vec_exc = 0;
-
-    vxc = check_ieee_exc(env, 0, false, &vec_exc);
-    handle_ieee_exc(env, vxc, vec_exc, GETPC());
-    s390_vec_write_float128(v1, ret);
-}
-
-void HELPER(gvec_vflr64)(void *v1, const void *v2, CPUS390XState *env,
-                         uint32_t desc)
-{
-    const uint8_t erm = extract32(simd_data(desc), 4, 4);
-    const bool s = extract32(simd_data(desc), 3, 1);
-    const bool XxC = extract32(simd_data(desc), 2, 1);
-    uint8_t vxc, vec_exc = 0;
-    S390Vector tmp = {};
-    int i, old_mode;
-
-    old_mode = s390_swap_bfp_rounding_mode(env, erm);
-    for (i = 0; i < 2; i++) {
-        float64 a = s390_vec_read_element64(v2, i);
-        uint32_t ret = float64_to_float32(a, &env->fpu_status);
-
-        /* place at even element */
-        s390_vec_write_element32(&tmp, i * 2, ret);
-        /* indicate the source element */
-        vxc = check_ieee_exc(env, i, XxC, &vec_exc);
-        if (s || vxc) {
-            break;
-        }
-    }
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_ieee_exc(env, vxc, vec_exc, GETPC());
-    *(S390Vector *)v1 = tmp;
-}
-
-void HELPER(gvec_vflr128)(void *v1, const void *v2, CPUS390XState *env,
-                          uint32_t desc)
-{
-    const uint8_t erm = extract32(simd_data(desc), 4, 4);
-    const bool XxC = extract32(simd_data(desc), 2, 1);
-    uint8_t vxc, vec_exc = 0;
-    int old_mode;
-    float64 ret;
-
-    old_mode = s390_swap_bfp_rounding_mode(env, erm);
-    ret = float128_to_float64(s390_vec_read_float128(v2), &env->fpu_status);
-    vxc = check_ieee_exc(env, 0, XxC, &vec_exc);
-    s390_restore_bfp_rounding_mode(env, old_mode);
-    handle_ieee_exc(env, vxc, vec_exc, GETPC());
-
-    /* place at even element, odd element is unpredictable */
-    s390_vec_write_float64(v1, 0, ret);
-}
-
-static void vfma32(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
-                   const S390Vector *v4, CPUS390XState *env, bool s, int flags,
-                   uintptr_t retaddr)
-{
-    uint8_t vxc, vec_exc = 0;
-    S390Vector tmp = {};
-    int i;
-
-    for (i = 0; i < 4; i++) {
-        const float32 a = s390_vec_read_float32(v2, i);
-        const float32 b = s390_vec_read_float32(v3, i);
-        const float32 c = s390_vec_read_float32(v4, i);
-        float32 ret = float32_muladd(a, b, c, flags, &env->fpu_status);
-
-        s390_vec_write_float32(&tmp, i, ret);
-        vxc = check_ieee_exc(env, i, false, &vec_exc);
-        if (s || vxc) {
-            break;
-        }
-    }
-    handle_ieee_exc(env, vxc, vec_exc, retaddr);
-    *v1 = tmp;
-}
-
-static void vfma64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
-                   const S390Vector *v4, CPUS390XState *env, bool s, int flags,
-                   uintptr_t retaddr)
-{
-    uint8_t vxc, vec_exc = 0;
-    S390Vector tmp = {};
-    int i;
-
-    for (i = 0; i < 2; i++) {
-        const float64 a = s390_vec_read_float64(v2, i);
-        const float64 b = s390_vec_read_float64(v3, i);
-        const float64 c = s390_vec_read_float64(v4, i);
-        const float64 ret = float64_muladd(a, b, c, flags, &env->fpu_status);
-
-        s390_vec_write_float64(&tmp, i, ret);
-        vxc = check_ieee_exc(env, i, false, &vec_exc);
-        if (s || vxc) {
-            break;
-        }
-    }
-    handle_ieee_exc(env, vxc, vec_exc, retaddr);
-    *v1 = tmp;
-}
-
-static void vfma128(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
-                    const S390Vector *v4, CPUS390XState *env, bool s, int flags,
-                    uintptr_t retaddr)
-{
-    const float128 a = s390_vec_read_float128(v2);
-    const float128 b = s390_vec_read_float128(v3);
-    const float128 c = s390_vec_read_float128(v4);
-    uint8_t vxc, vec_exc = 0;
-    float128 ret;
-
-    ret = float128_muladd(a, b, c, flags, &env->fpu_status);
-    vxc = check_ieee_exc(env, 0, false, &vec_exc);
-    handle_ieee_exc(env, vxc, vec_exc, retaddr);
-    s390_vec_write_float128(v1, ret);
-}
-
-#define DEF_GVEC_VFMA_B(NAME, FLAGS, BITS)                                     \
-void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3,       \
-                               const void *v4, CPUS390XState *env,             \
-                               uint32_t desc)                                  \
-{                                                                              \
-    const bool se = extract32(simd_data(desc), 3, 1);                          \
-                                                                               \
-    vfma##BITS(v1, v2, v3, v4, env, se, FLAGS, GETPC());                       \
-}
-
-#define DEF_GVEC_VFMA(NAME, FLAGS)                                             \
-    DEF_GVEC_VFMA_B(NAME, FLAGS, 32)                                           \
-    DEF_GVEC_VFMA_B(NAME, FLAGS, 64)                                           \
-    DEF_GVEC_VFMA_B(NAME, FLAGS, 128)
-
-DEF_GVEC_VFMA(vfma, 0)
-DEF_GVEC_VFMA(vfms, float_muladd_negate_c)
-DEF_GVEC_VFMA(vfnma, float_muladd_negate_result)
-DEF_GVEC_VFMA(vfnms, float_muladd_negate_c | float_muladd_negate_result)
-
-void HELPER(gvec_vftci32)(void *v1, const void *v2, CPUS390XState *env,
-                          uint32_t desc)
-{
-    uint16_t i3 = extract32(simd_data(desc), 4, 12);
-    bool s = extract32(simd_data(desc), 3, 1);
-    int i, match = 0;
-
-    for (i = 0; i < 4; i++) {
-        float32 a = s390_vec_read_float32(v2, i);
-
-        if (float32_dcmask(env, a) & i3) {
-            match++;
-            s390_vec_write_element32(v1, i, -1u);
-        } else {
-            s390_vec_write_element32(v1, i, 0);
-        }
-        if (s) {
-            break;
-        }
-    }
-
-    if (match == 4 || (s && match)) {
-        env->cc_op = 0;
-    } else if (match) {
-        env->cc_op = 1;
-    } else {
-        env->cc_op = 3;
-    }
-}
-
-void HELPER(gvec_vftci64)(void *v1, const void *v2, CPUS390XState *env,
-                          uint32_t desc)
-{
-    const uint16_t i3 = extract32(simd_data(desc), 4, 12);
-    const bool s = extract32(simd_data(desc), 3, 1);
-    int i, match = 0;
-
-    for (i = 0; i < 2; i++) {
-        const float64 a = s390_vec_read_float64(v2, i);
-
-        if (float64_dcmask(env, a) & i3) {
-            match++;
-            s390_vec_write_element64(v1, i, -1ull);
-        } else {
-            s390_vec_write_element64(v1, i, 0);
-        }
-        if (s) {
-            break;
-        }
-    }
-
-    if (match == 2 || (s && match)) {
-        env->cc_op = 0;
-    } else if (match) {
-        env->cc_op = 1;
-    } else {
-        env->cc_op = 3;
-    }
-}
-
-void HELPER(gvec_vftci128)(void *v1, const void *v2, CPUS390XState *env,
-                           uint32_t desc)
-{
-    const float128 a = s390_vec_read_float128(v2);
-    uint16_t i3 = extract32(simd_data(desc), 4, 12);
-
-    if (float128_dcmask(env, a) & i3) {
-        env->cc_op = 0;
-        s390_vec_write_element64(v1, 0, -1ull);
-        s390_vec_write_element64(v1, 1, -1ull);
-    } else {
-        env->cc_op = 3;
-        s390_vec_write_element64(v1, 0, 0);
-        s390_vec_write_element64(v1, 1, 0);
-    }
-}
-
-typedef enum S390MinMaxType {
-    S390_MINMAX_TYPE_IEEE = 0,
-    S390_MINMAX_TYPE_JAVA,
-    S390_MINMAX_TYPE_C_MACRO,
-    S390_MINMAX_TYPE_CPP,
-    S390_MINMAX_TYPE_F,
-} S390MinMaxType;
-
-typedef enum S390MinMaxRes {
-    S390_MINMAX_RES_MINMAX = 0,
-    S390_MINMAX_RES_A,
-    S390_MINMAX_RES_B,
-    S390_MINMAX_RES_SILENCE_A,
-    S390_MINMAX_RES_SILENCE_B,
-} S390MinMaxRes;
-
-static S390MinMaxRes vfmin_res(uint16_t dcmask_a, uint16_t dcmask_b,
-                               S390MinMaxType type, float_status *s)
-{
-    const bool neg_a = dcmask_a & DCMASK_NEGATIVE;
-    const bool nan_a = dcmask_a & DCMASK_NAN;
-    const bool nan_b = dcmask_b & DCMASK_NAN;
-
-    g_assert(type > S390_MINMAX_TYPE_IEEE && type <= S390_MINMAX_TYPE_F);
-
-    if (unlikely((dcmask_a | dcmask_b) & DCMASK_NAN)) {
-        const bool sig_a = dcmask_a & DCMASK_SIGNALING_NAN;
-        const bool sig_b = dcmask_b & DCMASK_SIGNALING_NAN;
-
-        if ((dcmask_a | dcmask_b) & DCMASK_SIGNALING_NAN) {
-            s->float_exception_flags |= float_flag_invalid;
-        }
-        switch (type) {
-        case S390_MINMAX_TYPE_JAVA:
-            if (sig_a) {
-                return S390_MINMAX_RES_SILENCE_A;
-            } else if (sig_b) {
-                return S390_MINMAX_RES_SILENCE_B;
-            }
-            return nan_a ? S390_MINMAX_RES_A : S390_MINMAX_RES_B;
-        case S390_MINMAX_TYPE_F:
-            return nan_b ? S390_MINMAX_RES_A : S390_MINMAX_RES_B;
-        case S390_MINMAX_TYPE_C_MACRO:
-            s->float_exception_flags |= float_flag_invalid;
-            return S390_MINMAX_RES_B;
-        case S390_MINMAX_TYPE_CPP:
-            s->float_exception_flags |= float_flag_invalid;
-            return S390_MINMAX_RES_A;
-        default:
-            g_assert_not_reached();
-        }
-    } else if (unlikely(dcmask_a & dcmask_b & DCMASK_ZERO)) {
-        switch (type) {
-        case S390_MINMAX_TYPE_JAVA:
-            return neg_a ? S390_MINMAX_RES_A : S390_MINMAX_RES_B;
-        case S390_MINMAX_TYPE_C_MACRO:
-            return S390_MINMAX_RES_B;
-        case S390_MINMAX_TYPE_F:
-            return !neg_a ? S390_MINMAX_RES_B : S390_MINMAX_RES_A;
-        case S390_MINMAX_TYPE_CPP:
-            return S390_MINMAX_RES_A;
-        default:
-            g_assert_not_reached();
-        }
-    }
-    return S390_MINMAX_RES_MINMAX;
-}
-
-static S390MinMaxRes vfmax_res(uint16_t dcmask_a, uint16_t dcmask_b,
-                               S390MinMaxType type, float_status *s)
-{
-    g_assert(type > S390_MINMAX_TYPE_IEEE && type <= S390_MINMAX_TYPE_F);
-
-    if (unlikely((dcmask_a | dcmask_b) & DCMASK_NAN)) {
-        const bool sig_a = dcmask_a & DCMASK_SIGNALING_NAN;
-        const bool sig_b = dcmask_b & DCMASK_SIGNALING_NAN;
-        const bool nan_a = dcmask_a & DCMASK_NAN;
-        const bool nan_b = dcmask_b & DCMASK_NAN;
-
-        if ((dcmask_a | dcmask_b) & DCMASK_SIGNALING_NAN) {
-            s->float_exception_flags |= float_flag_invalid;
-        }
-        switch (type) {
-        case S390_MINMAX_TYPE_JAVA:
-            if (sig_a) {
-                return S390_MINMAX_RES_SILENCE_A;
-            } else if (sig_b) {
-                return S390_MINMAX_RES_SILENCE_B;
-            }
-            return nan_a ? S390_MINMAX_RES_A : S390_MINMAX_RES_B;
-        case S390_MINMAX_TYPE_F:
-            return nan_b ? S390_MINMAX_RES_A : S390_MINMAX_RES_B;
-        case S390_MINMAX_TYPE_C_MACRO:
-            s->float_exception_flags |= float_flag_invalid;
-            return S390_MINMAX_RES_B;
-        case S390_MINMAX_TYPE_CPP:
-            s->float_exception_flags |= float_flag_invalid;
-            return S390_MINMAX_RES_A;
-        default:
-            g_assert_not_reached();
-        }
-    } else if (unlikely(dcmask_a & dcmask_b & DCMASK_ZERO)) {
-        const bool neg_a = dcmask_a & DCMASK_NEGATIVE;
-
-        switch (type) {
-        case S390_MINMAX_TYPE_JAVA:
-        case S390_MINMAX_TYPE_F:
-            return neg_a ? S390_MINMAX_RES_B : S390_MINMAX_RES_A;
-        case S390_MINMAX_TYPE_C_MACRO:
-            return S390_MINMAX_RES_B;
-        case S390_MINMAX_TYPE_CPP:
-            return S390_MINMAX_RES_A;
-        default:
-            g_assert_not_reached();
-        }
-    }
-    return S390_MINMAX_RES_MINMAX;
-}
-
-static S390MinMaxRes vfminmax_res(uint16_t dcmask_a, uint16_t dcmask_b,
-                                  S390MinMaxType type, bool is_min,
-                                  float_status *s)
-{
-    return is_min ? vfmin_res(dcmask_a, dcmask_b, type, s) :
-                    vfmax_res(dcmask_a, dcmask_b, type, s);
-}
-
-static void vfminmax32(S390Vector *v1, const S390Vector *v2,
-                       const S390Vector *v3, CPUS390XState *env,
-                       S390MinMaxType type, bool is_min, bool is_abs, bool se,
-                       uintptr_t retaddr)
-{
-    float_status *s = &env->fpu_status;
-    uint8_t vxc, vec_exc = 0;
-    S390Vector tmp = {};
-    int i;
-
-    for (i = 0; i < 4; i++) {
-        float32 a = s390_vec_read_float32(v2, i);
-        float32 b = s390_vec_read_float32(v3, i);
-        float32 result;
-
-        if (type != S390_MINMAX_TYPE_IEEE) {
-            S390MinMaxRes res;
-
-            if (is_abs) {
-                a = float32_abs(a);
-                b = float32_abs(b);
-            }
-
-            res = vfminmax_res(float32_dcmask(env, a), float32_dcmask(env, b),
-                               type, is_min, s);
-            switch (res) {
-            case S390_MINMAX_RES_MINMAX:
-                result = is_min ? float32_min(a, b, s) : float32_max(a, b, s);
-                break;
-            case S390_MINMAX_RES_A:
-                result = a;
-                break;
-            case S390_MINMAX_RES_B:
-                result = b;
-                break;
-            case S390_MINMAX_RES_SILENCE_A:
-                result = float32_silence_nan(a, s);
-                break;
-            case S390_MINMAX_RES_SILENCE_B:
-                result = float32_silence_nan(b, s);
-                break;
-            default:
-                g_assert_not_reached();
-            }
-        } else if (!is_abs) {
-            result = is_min ? float32_minnum(a, b, &env->fpu_status) :
-                              float32_maxnum(a, b, &env->fpu_status);
-        } else {
-            result = is_min ? float32_minnummag(a, b, &env->fpu_status) :
-                              float32_maxnummag(a, b, &env->fpu_status);
-        }
-
-        s390_vec_write_float32(&tmp, i, result);
-        vxc = check_ieee_exc(env, i, false, &vec_exc);
-        if (se || vxc) {
-            break;
-        }
-    }
-    handle_ieee_exc(env, vxc, vec_exc, retaddr);
-    *v1 = tmp;
-}
-
-static void vfminmax64(S390Vector *v1, const S390Vector *v2,
-                       const S390Vector *v3, CPUS390XState *env,
-                       S390MinMaxType type, bool is_min, bool is_abs, bool se,
-                       uintptr_t retaddr)
-{
-    float_status *s = &env->fpu_status;
-    uint8_t vxc, vec_exc = 0;
-    S390Vector tmp = {};
-    int i;
-
-    for (i = 0; i < 2; i++) {
-        float64 a = s390_vec_read_float64(v2, i);
-        float64 b = s390_vec_read_float64(v3, i);
-        float64 result;
-
-        if (type != S390_MINMAX_TYPE_IEEE) {
-            S390MinMaxRes res;
-
-            if (is_abs) {
-                a = float64_abs(a);
-                b = float64_abs(b);
-            }
-
-            res = vfminmax_res(float64_dcmask(env, a), float64_dcmask(env, b),
-                               type, is_min, s);
-            switch (res) {
-            case S390_MINMAX_RES_MINMAX:
-                result = is_min ? float64_min(a, b, s) : float64_max(a, b, s);
-                break;
-            case S390_MINMAX_RES_A:
-                result = a;
-                break;
-            case S390_MINMAX_RES_B:
-                result = b;
-                break;
-            case S390_MINMAX_RES_SILENCE_A:
-                result = float64_silence_nan(a, s);
-                break;
-            case S390_MINMAX_RES_SILENCE_B:
-                result = float64_silence_nan(b, s);
-                break;
-            default:
-                g_assert_not_reached();
-            }
-        } else if (!is_abs) {
-            result = is_min ? float64_minnum(a, b, &env->fpu_status) :
-                              float64_maxnum(a, b, &env->fpu_status);
-        } else {
-            result = is_min ? float64_minnummag(a, b, &env->fpu_status) :
-                              float64_maxnummag(a, b, &env->fpu_status);
-        }
-
-        s390_vec_write_float64(&tmp, i, result);
-        vxc = check_ieee_exc(env, i, false, &vec_exc);
-        if (se || vxc) {
-            break;
-        }
-    }
-    handle_ieee_exc(env, vxc, vec_exc, retaddr);
-    *v1 = tmp;
-}
-
-static void vfminmax128(S390Vector *v1, const S390Vector *v2,
-                        const S390Vector *v3, CPUS390XState *env,
-                        S390MinMaxType type, bool is_min, bool is_abs, bool se,
-                        uintptr_t retaddr)
-{
-    float128 a = s390_vec_read_float128(v2);
-    float128 b = s390_vec_read_float128(v3);
-    float_status *s = &env->fpu_status;
-    uint8_t vxc, vec_exc = 0;
-    float128 result;
-
-    if (type != S390_MINMAX_TYPE_IEEE) {
-        S390MinMaxRes res;
-
-        if (is_abs) {
-            a = float128_abs(a);
-            b = float128_abs(b);
-        }
-
-        res = vfminmax_res(float128_dcmask(env, a), float128_dcmask(env, b),
-                           type, is_min, s);
-        switch (res) {
-        case S390_MINMAX_RES_MINMAX:
-            result = is_min ? float128_min(a, b, s) : float128_max(a, b, s);
-            break;
-        case S390_MINMAX_RES_A:
-            result = a;
-            break;
-        case S390_MINMAX_RES_B:
-            result = b;
-            break;
-        case S390_MINMAX_RES_SILENCE_A:
-            result = float128_silence_nan(a, s);
-            break;
-        case S390_MINMAX_RES_SILENCE_B:
-            result = float128_silence_nan(b, s);
-            break;
-        default:
-            g_assert_not_reached();
-        }
-    } else if (!is_abs) {
-        result = is_min ? float128_minnum(a, b, &env->fpu_status) :
-                          float128_maxnum(a, b, &env->fpu_status);
-    } else {
-        result = is_min ? float128_minnummag(a, b, &env->fpu_status) :
-                          float128_maxnummag(a, b, &env->fpu_status);
-    }
-
-    vxc = check_ieee_exc(env, 0, false, &vec_exc);
-    handle_ieee_exc(env, vxc, vec_exc, retaddr);
-    s390_vec_write_float128(v1, result);
-}
-
-#define DEF_GVEC_VFMINMAX_B(NAME, IS_MIN, BITS)                                \
-void HELPER(gvec_##NAME##BITS)(void *v1, const void *v2, const void *v3,       \
-                               CPUS390XState *env, uint32_t desc)              \
-{                                                                              \
-    const bool se = extract32(simd_data(desc), 3, 1);                          \
-    uint8_t type = extract32(simd_data(desc), 4, 4);                           \
-    bool is_abs = false;                                                       \
-                                                                               \
-    if (type >= 8) {                                                           \
-        is_abs = true;                                                         \
-        type -= 8;                                                             \
-    }                                                                          \
-                                                                               \
-    vfminmax##BITS(v1, v2, v3, env, type, IS_MIN, is_abs, se, GETPC());        \
-}
-
-#define DEF_GVEC_VFMINMAX(NAME, IS_MIN)                                        \
-    DEF_GVEC_VFMINMAX_B(NAME, IS_MIN, 32)                                      \
-    DEF_GVEC_VFMINMAX_B(NAME, IS_MIN, 64)                                      \
-    DEF_GVEC_VFMINMAX_B(NAME, IS_MIN, 128)
-
-DEF_GVEC_VFMINMAX(vfmax, false)
-DEF_GVEC_VFMINMAX(vfmin, true)
diff --git a/target/s390x/vec_helper.c b/target/s390x/vec_helper.c
deleted file mode 100644 (file)
index 599bab0..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * QEMU TCG support -- s390x vector support instructions
- *
- * Copyright (C) 2019 Red Hat Inc
- *
- * Authors:
- *   David Hildenbrand <david@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "internal.h"
-#include "vec.h"
-#include "tcg/tcg.h"
-#include "tcg/tcg-gvec-desc.h"
-#include "exec/helper-proto.h"
-#include "exec/cpu_ldst.h"
-#include "exec/exec-all.h"
-
-void HELPER(gvec_vbperm)(void *v1, const void *v2, const void *v3,
-                         uint32_t desc)
-{
-    S390Vector tmp = {};
-    uint16_t result = 0;
-    int i;
-
-    for (i = 0; i < 16; i++) {
-        const uint8_t bit_nr = s390_vec_read_element8(v3, i);
-        uint16_t bit;
-
-        if (bit_nr >= 128) {
-            continue;
-        }
-        bit = (s390_vec_read_element8(v2, bit_nr / 8)
-               >> (7 - (bit_nr % 8))) & 1;
-        result |= (bit << (15 - i));
-    }
-    s390_vec_write_element16(&tmp, 3, result);
-    *(S390Vector *)v1 = tmp;
-}
-
-void HELPER(vll)(CPUS390XState *env, void *v1, uint64_t addr, uint64_t bytes)
-{
-    if (likely(bytes >= 16)) {
-        uint64_t t0, t1;
-
-        t0 = cpu_ldq_data_ra(env, addr, GETPC());
-        addr = wrap_address(env, addr + 8);
-        t1 = cpu_ldq_data_ra(env, addr, GETPC());
-        s390_vec_write_element64(v1, 0, t0);
-        s390_vec_write_element64(v1, 1, t1);
-    } else {
-        S390Vector tmp = {};
-        int i;
-
-        for (i = 0; i < bytes; i++) {
-            uint8_t byte = cpu_ldub_data_ra(env, addr, GETPC());
-
-            s390_vec_write_element8(&tmp, i, byte);
-            addr = wrap_address(env, addr + 1);
-        }
-        *(S390Vector *)v1 = tmp;
-    }
-}
-
-#define DEF_VPK_HFN(BITS, TBITS)                                               \
-typedef uint##TBITS##_t (*vpk##BITS##_fn)(uint##BITS##_t, int *);              \
-static int vpk##BITS##_hfn(S390Vector *v1, const S390Vector *v2,               \
-                           const S390Vector *v3, vpk##BITS##_fn fn)            \
-{                                                                              \
-    int i, saturated = 0;                                                      \
-    S390Vector tmp;                                                            \
-                                                                               \
-    for (i = 0; i < (128 / TBITS); i++) {                                      \
-        uint##BITS##_t src;                                                    \
-                                                                               \
-        if (i < (128 / BITS)) {                                                \
-            src = s390_vec_read_element##BITS(v2, i);                          \
-        } else {                                                               \
-            src = s390_vec_read_element##BITS(v3, i - (128 / BITS));           \
-        }                                                                      \
-        s390_vec_write_element##TBITS(&tmp, i, fn(src, &saturated));           \
-    }                                                                          \
-    *v1 = tmp;                                                                 \
-    return saturated;                                                          \
-}
-DEF_VPK_HFN(64, 32)
-DEF_VPK_HFN(32, 16)
-DEF_VPK_HFN(16, 8)
-
-#define DEF_VPK(BITS, TBITS)                                                   \
-static uint##TBITS##_t vpk##BITS##e(uint##BITS##_t src, int *saturated)        \
-{                                                                              \
-    return src;                                                                \
-}                                                                              \
-void HELPER(gvec_vpk##BITS)(void *v1, const void *v2, const void *v3,          \
-                            uint32_t desc)                                     \
-{                                                                              \
-    vpk##BITS##_hfn(v1, v2, v3, vpk##BITS##e);                                 \
-}
-DEF_VPK(64, 32)
-DEF_VPK(32, 16)
-DEF_VPK(16, 8)
-
-#define DEF_VPKS(BITS, TBITS)                                                  \
-static uint##TBITS##_t vpks##BITS##e(uint##BITS##_t src, int *saturated)       \
-{                                                                              \
-    if ((int##BITS##_t)src > INT##TBITS##_MAX) {                               \
-        (*saturated)++;                                                        \
-        return INT##TBITS##_MAX;                                               \
-    } else if ((int##BITS##_t)src < INT##TBITS##_MIN) {                        \
-        (*saturated)++;                                                        \
-        return INT##TBITS##_MIN;                                               \
-    }                                                                          \
-    return src;                                                                \
-}                                                                              \
-void HELPER(gvec_vpks##BITS)(void *v1, const void *v2, const void *v3,         \
-                             uint32_t desc)                                    \
-{                                                                              \
-    vpk##BITS##_hfn(v1, v2, v3, vpks##BITS##e);                                \
-}                                                                              \
-void HELPER(gvec_vpks_cc##BITS)(void *v1, const void *v2, const void *v3,      \
-                                CPUS390XState *env, uint32_t desc)             \
-{                                                                              \
-    int saturated = vpk##BITS##_hfn(v1, v2, v3, vpks##BITS##e);                \
-                                                                               \
-    if (saturated == (128 / TBITS)) {                                          \
-        env->cc_op = 3;                                                        \
-    } else if (saturated) {                                                    \
-        env->cc_op = 1;                                                        \
-    } else {                                                                   \
-        env->cc_op = 0;                                                        \
-    }                                                                          \
-}
-DEF_VPKS(64, 32)
-DEF_VPKS(32, 16)
-DEF_VPKS(16, 8)
-
-#define DEF_VPKLS(BITS, TBITS)                                                 \
-static uint##TBITS##_t vpkls##BITS##e(uint##BITS##_t src, int *saturated)      \
-{                                                                              \
-    if (src > UINT##TBITS##_MAX) {                                             \
-        (*saturated)++;                                                        \
-        return UINT##TBITS##_MAX;                                              \
-    }                                                                          \
-    return src;                                                                \
-}                                                                              \
-void HELPER(gvec_vpkls##BITS)(void *v1, const void *v2, const void *v3,        \
-                              uint32_t desc)                                   \
-{                                                                              \
-    vpk##BITS##_hfn(v1, v2, v3, vpkls##BITS##e);                               \
-}                                                                              \
-void HELPER(gvec_vpkls_cc##BITS)(void *v1, const void *v2, const void *v3,     \
-                                 CPUS390XState *env, uint32_t desc)            \
-{                                                                              \
-    int saturated = vpk##BITS##_hfn(v1, v2, v3, vpkls##BITS##e);               \
-                                                                               \
-    if (saturated == (128 / TBITS)) {                                          \
-        env->cc_op = 3;                                                        \
-    } else if (saturated) {                                                    \
-        env->cc_op = 1;                                                        \
-    } else {                                                                   \
-        env->cc_op = 0;                                                        \
-    }                                                                          \
-}
-DEF_VPKLS(64, 32)
-DEF_VPKLS(32, 16)
-DEF_VPKLS(16, 8)
-
-void HELPER(gvec_vperm)(void *v1, const void *v2, const void *v3,
-                        const void *v4, uint32_t desc)
-{
-    S390Vector tmp;
-    int i;
-
-    for (i = 0; i < 16; i++) {
-        const uint8_t selector = s390_vec_read_element8(v4, i) & 0x1f;
-        uint8_t byte;
-
-        if (selector < 16) {
-            byte = s390_vec_read_element8(v2, selector);
-        } else {
-            byte = s390_vec_read_element8(v3, selector - 16);
-        }
-        s390_vec_write_element8(&tmp, i, byte);
-    }
-    *(S390Vector *)v1 = tmp;
-}
-
-void HELPER(vstl)(CPUS390XState *env, const void *v1, uint64_t addr,
-                  uint64_t bytes)
-{
-    /* Probe write access before actually modifying memory */
-    probe_write_access(env, addr, bytes, GETPC());
-
-    if (likely(bytes >= 16)) {
-        cpu_stq_data_ra(env, addr, s390_vec_read_element64(v1, 0), GETPC());
-        addr = wrap_address(env, addr + 8);
-        cpu_stq_data_ra(env, addr, s390_vec_read_element64(v1, 1), GETPC());
-    } else {
-        S390Vector tmp = {};
-        int i;
-
-        for (i = 0; i < bytes; i++) {
-            uint8_t byte = s390_vec_read_element8(v1, i);
-
-            cpu_stb_data_ra(env, addr, byte, GETPC());
-            addr = wrap_address(env, addr + 1);
-        }
-        *(S390Vector *)v1 = tmp;
-    }
-}
diff --git a/target/s390x/vec_int_helper.c b/target/s390x/vec_int_helper.c
deleted file mode 100644 (file)
index 5561b3e..0000000
+++ /dev/null
@@ -1,587 +0,0 @@
-/*
- * QEMU TCG support -- s390x vector integer instruction support
- *
- * Copyright (C) 2019 Red Hat Inc
- *
- * Authors:
- *   David Hildenbrand <david@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "vec.h"
-#include "exec/helper-proto.h"
-#include "tcg/tcg-gvec-desc.h"
-
-static bool s390_vec_is_zero(const S390Vector *v)
-{
-    return !v->doubleword[0] && !v->doubleword[1];
-}
-
-static void s390_vec_xor(S390Vector *res, const S390Vector *a,
-                         const S390Vector *b)
-{
-    res->doubleword[0] = a->doubleword[0] ^ b->doubleword[0];
-    res->doubleword[1] = a->doubleword[1] ^ b->doubleword[1];
-}
-
-static void s390_vec_and(S390Vector *res, const S390Vector *a,
-                         const S390Vector *b)
-{
-    res->doubleword[0] = a->doubleword[0] & b->doubleword[0];
-    res->doubleword[1] = a->doubleword[1] & b->doubleword[1];
-}
-
-static bool s390_vec_equal(const S390Vector *a, const S390Vector *b)
-{
-    return a->doubleword[0] == b->doubleword[0] &&
-           a->doubleword[1] == b->doubleword[1];
-}
-
-static void s390_vec_shl(S390Vector *d, const S390Vector *a, uint64_t count)
-{
-    uint64_t tmp;
-
-    g_assert(count < 128);
-    if (count == 0) {
-        d->doubleword[0] = a->doubleword[0];
-        d->doubleword[1] = a->doubleword[1];
-    } else if (count == 64) {
-        d->doubleword[0] = a->doubleword[1];
-        d->doubleword[1] = 0;
-    } else if (count < 64) {
-        tmp = extract64(a->doubleword[1], 64 - count, count);
-        d->doubleword[1] = a->doubleword[1] << count;
-        d->doubleword[0] = (a->doubleword[0] << count) | tmp;
-    } else {
-        d->doubleword[0] = a->doubleword[1] << (count - 64);
-        d->doubleword[1] = 0;
-    }
-}
-
-static void s390_vec_sar(S390Vector *d, const S390Vector *a, uint64_t count)
-{
-    uint64_t tmp;
-
-    if (count == 0) {
-        d->doubleword[0] = a->doubleword[0];
-        d->doubleword[1] = a->doubleword[1];
-    } else if (count == 64) {
-        tmp = (int64_t)a->doubleword[0] >> 63;
-        d->doubleword[1] = a->doubleword[0];
-        d->doubleword[0] = tmp;
-    } else if (count < 64) {
-        tmp = a->doubleword[1] >> count;
-        d->doubleword[1] = deposit64(tmp, 64 - count, count, a->doubleword[0]);
-        d->doubleword[0] = (int64_t)a->doubleword[0] >> count;
-    } else {
-        tmp = (int64_t)a->doubleword[0] >> 63;
-        d->doubleword[1] = (int64_t)a->doubleword[0] >> (count - 64);
-        d->doubleword[0] = tmp;
-    }
-}
-
-static void s390_vec_shr(S390Vector *d, const S390Vector *a, uint64_t count)
-{
-    uint64_t tmp;
-
-    g_assert(count < 128);
-    if (count == 0) {
-        d->doubleword[0] = a->doubleword[0];
-        d->doubleword[1] = a->doubleword[1];
-    } else if (count == 64) {
-        d->doubleword[1] = a->doubleword[0];
-        d->doubleword[0] = 0;
-    } else if (count < 64) {
-        tmp = a->doubleword[1] >> count;
-        d->doubleword[1] = deposit64(tmp, 64 - count, count, a->doubleword[0]);
-        d->doubleword[0] = a->doubleword[0] >> count;
-    } else {
-        d->doubleword[1] = a->doubleword[0] >> (count - 64);
-        d->doubleword[0] = 0;
-    }
-}
-#define DEF_VAVG(BITS)                                                         \
-void HELPER(gvec_vavg##BITS)(void *v1, const void *v2, const void *v3,         \
-                             uint32_t desc)                                    \
-{                                                                              \
-    int i;                                                                     \
-                                                                               \
-    for (i = 0; i < (128 / BITS); i++) {                                       \
-        const int32_t a = (int##BITS##_t)s390_vec_read_element##BITS(v2, i);   \
-        const int32_t b = (int##BITS##_t)s390_vec_read_element##BITS(v3, i);   \
-                                                                               \
-        s390_vec_write_element##BITS(v1, i, (a + b + 1) >> 1);                 \
-    }                                                                          \
-}
-DEF_VAVG(8)
-DEF_VAVG(16)
-
-#define DEF_VAVGL(BITS)                                                        \
-void HELPER(gvec_vavgl##BITS)(void *v1, const void *v2, const void *v3,        \
-                              uint32_t desc)                                   \
-{                                                                              \
-    int i;                                                                     \
-                                                                               \
-    for (i = 0; i < (128 / BITS); i++) {                                       \
-        const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i);           \
-        const uint##BITS##_t b = s390_vec_read_element##BITS(v3, i);           \
-                                                                               \
-        s390_vec_write_element##BITS(v1, i, (a + b + 1) >> 1);                 \
-    }                                                                          \
-}
-DEF_VAVGL(8)
-DEF_VAVGL(16)
-
-#define DEF_VCLZ(BITS)                                                         \
-void HELPER(gvec_vclz##BITS)(void *v1, const void *v2, uint32_t desc)          \
-{                                                                              \
-    int i;                                                                     \
-                                                                               \
-    for (i = 0; i < (128 / BITS); i++) {                                       \
-        const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i);           \
-                                                                               \
-        s390_vec_write_element##BITS(v1, i, clz32(a) - 32 + BITS);             \
-    }                                                                          \
-}
-DEF_VCLZ(8)
-DEF_VCLZ(16)
-
-#define DEF_VCTZ(BITS)                                                         \
-void HELPER(gvec_vctz##BITS)(void *v1, const void *v2, uint32_t desc)          \
-{                                                                              \
-    int i;                                                                     \
-                                                                               \
-    for (i = 0; i < (128 / BITS); i++) {                                       \
-        const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i);           \
-                                                                               \
-        s390_vec_write_element##BITS(v1, i, a ? ctz32(a) : BITS);              \
-    }                                                                          \
-}
-DEF_VCTZ(8)
-DEF_VCTZ(16)
-
-/* like binary multiplication, but XOR instead of addition */
-#define DEF_GALOIS_MULTIPLY(BITS, TBITS)                                       \
-static uint##TBITS##_t galois_multiply##BITS(uint##TBITS##_t a,                \
-                                             uint##TBITS##_t b)                \
-{                                                                              \
-    uint##TBITS##_t res = 0;                                                   \
-                                                                               \
-    while (b) {                                                                \
-        if (b & 0x1) {                                                         \
-            res = res ^ a;                                                     \
-        }                                                                      \
-        a = a << 1;                                                            \
-        b = b >> 1;                                                            \
-    }                                                                          \
-    return res;                                                                \
-}
-DEF_GALOIS_MULTIPLY(8, 16)
-DEF_GALOIS_MULTIPLY(16, 32)
-DEF_GALOIS_MULTIPLY(32, 64)
-
-static S390Vector galois_multiply64(uint64_t a, uint64_t b)
-{
-    S390Vector res = {};
-    S390Vector va = {
-        .doubleword[1] = a,
-    };
-    S390Vector vb = {
-        .doubleword[1] = b,
-    };
-
-    while (!s390_vec_is_zero(&vb)) {
-        if (vb.doubleword[1] & 0x1) {
-            s390_vec_xor(&res, &res, &va);
-        }
-        s390_vec_shl(&va, &va, 1);
-        s390_vec_shr(&vb, &vb, 1);
-    }
-    return res;
-}
-
-#define DEF_VGFM(BITS, TBITS)                                                  \
-void HELPER(gvec_vgfm##BITS)(void *v1, const void *v2, const void *v3,         \
-                             uint32_t desc)                                    \
-{                                                                              \
-    int i;                                                                     \
-                                                                               \
-    for (i = 0; i < (128 / TBITS); i++) {                                      \
-        uint##BITS##_t a = s390_vec_read_element##BITS(v2, i * 2);             \
-        uint##BITS##_t b = s390_vec_read_element##BITS(v3, i * 2);             \
-        uint##TBITS##_t d = galois_multiply##BITS(a, b);                       \
-                                                                               \
-        a = s390_vec_read_element##BITS(v2, i * 2 + 1);                        \
-        b = s390_vec_read_element##BITS(v3, i * 2 + 1);                        \
-        d = d ^ galois_multiply32(a, b);                                       \
-        s390_vec_write_element##TBITS(v1, i, d);                               \
-    }                                                                          \
-}
-DEF_VGFM(8, 16)
-DEF_VGFM(16, 32)
-DEF_VGFM(32, 64)
-
-void HELPER(gvec_vgfm64)(void *v1, const void *v2, const void *v3,
-                         uint32_t desc)
-{
-    S390Vector tmp1, tmp2;
-    uint64_t a, b;
-
-    a = s390_vec_read_element64(v2, 0);
-    b = s390_vec_read_element64(v3, 0);
-    tmp1 = galois_multiply64(a, b);
-    a = s390_vec_read_element64(v2, 1);
-    b = s390_vec_read_element64(v3, 1);
-    tmp2 = galois_multiply64(a, b);
-    s390_vec_xor(v1, &tmp1, &tmp2);
-}
-
-#define DEF_VGFMA(BITS, TBITS)                                                 \
-void HELPER(gvec_vgfma##BITS)(void *v1, const void *v2, const void *v3,        \
-                              const void *v4, uint32_t desc)                   \
-{                                                                              \
-    int i;                                                                     \
-                                                                               \
-    for (i = 0; i < (128 / TBITS); i++) {                                      \
-        uint##BITS##_t a = s390_vec_read_element##BITS(v2, i * 2);             \
-        uint##BITS##_t b = s390_vec_read_element##BITS(v3, i * 2);             \
-        uint##TBITS##_t d = galois_multiply##BITS(a, b);                       \
-                                                                               \
-        a = s390_vec_read_element##BITS(v2, i * 2 + 1);                        \
-        b = s390_vec_read_element##BITS(v3, i * 2 + 1);                        \
-        d = d ^ galois_multiply32(a, b);                                       \
-        d = d ^ s390_vec_read_element##TBITS(v4, i);                           \
-        s390_vec_write_element##TBITS(v1, i, d);                               \
-    }                                                                          \
-}
-DEF_VGFMA(8, 16)
-DEF_VGFMA(16, 32)
-DEF_VGFMA(32, 64)
-
-void HELPER(gvec_vgfma64)(void *v1, const void *v2, const void *v3,
-                          const void *v4, uint32_t desc)
-{
-    S390Vector tmp1, tmp2;
-    uint64_t a, b;
-
-    a = s390_vec_read_element64(v2, 0);
-    b = s390_vec_read_element64(v3, 0);
-    tmp1 = galois_multiply64(a, b);
-    a = s390_vec_read_element64(v2, 1);
-    b = s390_vec_read_element64(v3, 1);
-    tmp2 = galois_multiply64(a, b);
-    s390_vec_xor(&tmp1, &tmp1, &tmp2);
-    s390_vec_xor(v1, &tmp1, v4);
-}
-
-#define DEF_VMAL(BITS)                                                         \
-void HELPER(gvec_vmal##BITS)(void *v1, const void *v2, const void *v3,         \
-                             const void *v4, uint32_t desc)                    \
-{                                                                              \
-    int i;                                                                     \
-                                                                               \
-    for (i = 0; i < (128 / BITS); i++) {                                       \
-        const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i);           \
-        const uint##BITS##_t b = s390_vec_read_element##BITS(v3, i);           \
-        const uint##BITS##_t c = s390_vec_read_element##BITS(v4, i);           \
-                                                                               \
-        s390_vec_write_element##BITS(v1, i, a * b + c);                        \
-    }                                                                          \
-}
-DEF_VMAL(8)
-DEF_VMAL(16)
-
-#define DEF_VMAH(BITS)                                                         \
-void HELPER(gvec_vmah##BITS)(void *v1, const void *v2, const void *v3,         \
-                             const void *v4, uint32_t desc)                    \
-{                                                                              \
-    int i;                                                                     \
-                                                                               \
-    for (i = 0; i < (128 / BITS); i++) {                                       \
-        const int32_t a = (int##BITS##_t)s390_vec_read_element##BITS(v2, i);   \
-        const int32_t b = (int##BITS##_t)s390_vec_read_element##BITS(v3, i);   \
-        const int32_t c = (int##BITS##_t)s390_vec_read_element##BITS(v4, i);   \
-                                                                               \
-        s390_vec_write_element##BITS(v1, i, (a * b + c) >> BITS);              \
-    }                                                                          \
-}
-DEF_VMAH(8)
-DEF_VMAH(16)
-
-#define DEF_VMALH(BITS)                                                        \
-void HELPER(gvec_vmalh##BITS)(void *v1, const void *v2, const void *v3,        \
-                              const void *v4, uint32_t desc)                   \
-{                                                                              \
-    int i;                                                                     \
-                                                                               \
-    for (i = 0; i < (128 / BITS); i++) {                                       \
-        const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i);           \
-        const uint##BITS##_t b = s390_vec_read_element##BITS(v3, i);           \
-        const uint##BITS##_t c = s390_vec_read_element##BITS(v4, i);           \
-                                                                               \
-        s390_vec_write_element##BITS(v1, i, (a * b + c) >> BITS);              \
-    }                                                                          \
-}
-DEF_VMALH(8)
-DEF_VMALH(16)
-
-#define DEF_VMAE(BITS, TBITS)                                                  \
-void HELPER(gvec_vmae##BITS)(void *v1, const void *v2, const void *v3,         \
-                             const void *v4, uint32_t desc)                    \
-{                                                                              \
-    int i, j;                                                                  \
-                                                                               \
-    for (i = 0, j = 0; i < (128 / TBITS); i++, j += 2) {                       \
-        int##TBITS##_t a = (int##BITS##_t)s390_vec_read_element##BITS(v2, j);  \
-        int##TBITS##_t b = (int##BITS##_t)s390_vec_read_element##BITS(v3, j);  \
-        int##TBITS##_t c = s390_vec_read_element##TBITS(v4, i);                \
-                                                                               \
-        s390_vec_write_element##TBITS(v1, i, a * b + c);                       \
-    }                                                                          \
-}
-DEF_VMAE(8, 16)
-DEF_VMAE(16, 32)
-DEF_VMAE(32, 64)
-
-#define DEF_VMALE(BITS, TBITS)                                                 \
-void HELPER(gvec_vmale##BITS)(void *v1, const void *v2, const void *v3,        \
-                              const void *v4, uint32_t desc)                   \
-{                                                                              \
-    int i, j;                                                                  \
-                                                                               \
-    for (i = 0, j = 0; i < (128 / TBITS); i++, j += 2) {                       \
-        uint##TBITS##_t a = s390_vec_read_element##BITS(v2, j);                \
-        uint##TBITS##_t b = s390_vec_read_element##BITS(v3, j);                \
-        uint##TBITS##_t c = s390_vec_read_element##TBITS(v4, i);               \
-                                                                               \
-        s390_vec_write_element##TBITS(v1, i, a * b + c);                       \
-    }                                                                          \
-}
-DEF_VMALE(8, 16)
-DEF_VMALE(16, 32)
-DEF_VMALE(32, 64)
-
-#define DEF_VMAO(BITS, TBITS)                                                  \
-void HELPER(gvec_vmao##BITS)(void *v1, const void *v2, const void *v3,         \
-                             const void *v4, uint32_t desc)                    \
-{                                                                              \
-    int i, j;                                                                  \
-                                                                               \
-    for (i = 0, j = 1; i < (128 / TBITS); i++, j += 2) {                       \
-        int##TBITS##_t a = (int##BITS##_t)s390_vec_read_element##BITS(v2, j);  \
-        int##TBITS##_t b = (int##BITS##_t)s390_vec_read_element##BITS(v3, j);  \
-        int##TBITS##_t c = s390_vec_read_element##TBITS(v4, i);                \
-                                                                               \
-        s390_vec_write_element##TBITS(v1, i, a * b + c);                       \
-    }                                                                          \
-}
-DEF_VMAO(8, 16)
-DEF_VMAO(16, 32)
-DEF_VMAO(32, 64)
-
-#define DEF_VMALO(BITS, TBITS)                                                 \
-void HELPER(gvec_vmalo##BITS)(void *v1, const void *v2, const void *v3,        \
-                              const void *v4, uint32_t desc)                   \
-{                                                                              \
-    int i, j;                                                                  \
-                                                                               \
-    for (i = 0, j = 1; i < (128 / TBITS); i++, j += 2) {                       \
-        uint##TBITS##_t a = s390_vec_read_element##BITS(v2, j);                \
-        uint##TBITS##_t b = s390_vec_read_element##BITS(v3, j);                \
-        uint##TBITS##_t c = s390_vec_read_element##TBITS(v4, i);               \
-                                                                               \
-        s390_vec_write_element##TBITS(v1, i, a * b + c);                       \
-    }                                                                          \
-}
-DEF_VMALO(8, 16)
-DEF_VMALO(16, 32)
-DEF_VMALO(32, 64)
-
-#define DEF_VMH(BITS)                                                          \
-void HELPER(gvec_vmh##BITS)(void *v1, const void *v2, const void *v3,          \
-                            uint32_t desc)                                     \
-{                                                                              \
-    int i;                                                                     \
-                                                                               \
-    for (i = 0; i < (128 / BITS); i++) {                                       \
-        const int32_t a = (int##BITS##_t)s390_vec_read_element##BITS(v2, i);   \
-        const int32_t b = (int##BITS##_t)s390_vec_read_element##BITS(v3, i);   \
-                                                                               \
-        s390_vec_write_element##BITS(v1, i, (a * b) >> BITS);                  \
-    }                                                                          \
-}
-DEF_VMH(8)
-DEF_VMH(16)
-
-#define DEF_VMLH(BITS)                                                         \
-void HELPER(gvec_vmlh##BITS)(void *v1, const void *v2, const void *v3,         \
-                             uint32_t desc)                                    \
-{                                                                              \
-    int i;                                                                     \
-                                                                               \
-    for (i = 0; i < (128 / BITS); i++) {                                       \
-        const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i);           \
-        const uint##BITS##_t b = s390_vec_read_element##BITS(v3, i);           \
-                                                                               \
-        s390_vec_write_element##BITS(v1, i, (a * b) >> BITS);                  \
-    }                                                                          \
-}
-DEF_VMLH(8)
-DEF_VMLH(16)
-
-#define DEF_VME(BITS, TBITS)                                                   \
-void HELPER(gvec_vme##BITS)(void *v1, const void *v2, const void *v3,          \
-                            uint32_t desc)                                     \
-{                                                                              \
-    int i, j;                                                                  \
-                                                                               \
-    for (i = 0, j = 0; i < (128 / TBITS); i++, j += 2) {                       \
-        int##TBITS##_t a = (int##BITS##_t)s390_vec_read_element##BITS(v2, j);  \
-        int##TBITS##_t b = (int##BITS##_t)s390_vec_read_element##BITS(v3, j);  \
-                                                                               \
-        s390_vec_write_element##TBITS(v1, i, a * b);                           \
-    }                                                                          \
-}
-DEF_VME(8, 16)
-DEF_VME(16, 32)
-DEF_VME(32, 64)
-
-#define DEF_VMLE(BITS, TBITS)                                                  \
-void HELPER(gvec_vmle##BITS)(void *v1, const void *v2, const void *v3,         \
-                             uint32_t desc)                                    \
-{                                                                              \
-    int i, j;                                                                  \
-                                                                               \
-    for (i = 0, j = 0; i < (128 / TBITS); i++, j += 2) {                       \
-        const uint##TBITS##_t a = s390_vec_read_element##BITS(v2, j);          \
-        const uint##TBITS##_t b = s390_vec_read_element##BITS(v3, j);          \
-                                                                               \
-        s390_vec_write_element##TBITS(v1, i, a * b);                           \
-    }                                                                          \
-}
-DEF_VMLE(8, 16)
-DEF_VMLE(16, 32)
-DEF_VMLE(32, 64)
-
-#define DEF_VMO(BITS, TBITS)                                                   \
-void HELPER(gvec_vmo##BITS)(void *v1, const void *v2, const void *v3,          \
-                            uint32_t desc)                                     \
-{                                                                              \
-    int i, j;                                                                  \
-                                                                               \
-    for (i = 0, j = 1; i < (128 / TBITS); i++, j += 2) {                       \
-        int##TBITS##_t a = (int##BITS##_t)s390_vec_read_element##BITS(v2, j);  \
-        int##TBITS##_t b = (int##BITS##_t)s390_vec_read_element##BITS(v3, j);  \
-                                                                               \
-        s390_vec_write_element##TBITS(v1, i, a * b);                           \
-    }                                                                          \
-}
-DEF_VMO(8, 16)
-DEF_VMO(16, 32)
-DEF_VMO(32, 64)
-
-#define DEF_VMLO(BITS, TBITS)                                                  \
-void HELPER(gvec_vmlo##BITS)(void *v1, const void *v2, const void *v3,         \
-                             uint32_t desc)                                    \
-{                                                                              \
-    int i, j;                                                                  \
-                                                                               \
-    for (i = 0, j = 1; i < (128 / TBITS); i++, j += 2) {                       \
-        const uint##TBITS##_t a = s390_vec_read_element##BITS(v2, j);          \
-        const uint##TBITS##_t b = s390_vec_read_element##BITS(v3, j);          \
-                                                                               \
-        s390_vec_write_element##TBITS(v1, i, a * b);                           \
-    }                                                                          \
-}
-DEF_VMLO(8, 16)
-DEF_VMLO(16, 32)
-DEF_VMLO(32, 64)
-
-#define DEF_VPOPCT(BITS)                                                       \
-void HELPER(gvec_vpopct##BITS)(void *v1, const void *v2, uint32_t desc)        \
-{                                                                              \
-    int i;                                                                     \
-                                                                               \
-    for (i = 0; i < (128 / BITS); i++) {                                       \
-        const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i);           \
-                                                                               \
-        s390_vec_write_element##BITS(v1, i, ctpop32(a));                       \
-    }                                                                          \
-}
-DEF_VPOPCT(8)
-DEF_VPOPCT(16)
-
-#define DEF_VERIM(BITS)                                                        \
-void HELPER(gvec_verim##BITS)(void *v1, const void *v2, const void *v3,        \
-                              uint32_t desc)                                   \
-{                                                                              \
-    const uint8_t count = simd_data(desc);                                     \
-    int i;                                                                     \
-                                                                               \
-    for (i = 0; i < (128 / BITS); i++) {                                       \
-        const uint##BITS##_t a = s390_vec_read_element##BITS(v1, i);           \
-        const uint##BITS##_t b = s390_vec_read_element##BITS(v2, i);           \
-        const uint##BITS##_t mask = s390_vec_read_element##BITS(v3, i);        \
-        const uint##BITS##_t d = (a & ~mask) | (rol##BITS(b, count) & mask);   \
-                                                                               \
-        s390_vec_write_element##BITS(v1, i, d);                                \
-    }                                                                          \
-}
-DEF_VERIM(8)
-DEF_VERIM(16)
-
-void HELPER(gvec_vsl)(void *v1, const void *v2, uint64_t count,
-                      uint32_t desc)
-{
-    s390_vec_shl(v1, v2, count);
-}
-
-void HELPER(gvec_vsra)(void *v1, const void *v2, uint64_t count,
-                       uint32_t desc)
-{
-    s390_vec_sar(v1, v2, count);
-}
-
-void HELPER(gvec_vsrl)(void *v1, const void *v2, uint64_t count,
-                       uint32_t desc)
-{
-    s390_vec_shr(v1, v2, count);
-}
-
-#define DEF_VSCBI(BITS)                                                        \
-void HELPER(gvec_vscbi##BITS)(void *v1, const void *v2, const void *v3,        \
-                              uint32_t desc)                                   \
-{                                                                              \
-    int i;                                                                     \
-                                                                               \
-    for (i = 0; i < (128 / BITS); i++) {                                       \
-        const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i);           \
-        const uint##BITS##_t b = s390_vec_read_element##BITS(v3, i);           \
-                                                                               \
-        s390_vec_write_element##BITS(v1, i, a >= b);                           \
-    }                                                                          \
-}
-DEF_VSCBI(8)
-DEF_VSCBI(16)
-
-void HELPER(gvec_vtm)(void *v1, const void *v2, CPUS390XState *env,
-                      uint32_t desc)
-{
-    S390Vector tmp;
-
-    s390_vec_and(&tmp, v1, v2);
-    if (s390_vec_is_zero(&tmp)) {
-        /* Selected bits all zeros; or all mask bits zero */
-        env->cc_op = 0;
-    } else if (s390_vec_equal(&tmp, v2)) {
-        /* Selected bits all ones */
-        env->cc_op = 3;
-    } else {
-        /* Selected bits a mix of zeros and ones */
-        env->cc_op = 1;
-    }
-}
diff --git a/target/s390x/vec_string_helper.c b/target/s390x/vec_string_helper.c
deleted file mode 100644 (file)
index c516c0c..0000000
+++ /dev/null
@@ -1,473 +0,0 @@
-/*
- * QEMU TCG support -- s390x vector string instruction support
- *
- * Copyright (C) 2019 Red Hat Inc
- *
- * Authors:
- *   David Hildenbrand <david@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "cpu.h"
-#include "internal.h"
-#include "vec.h"
-#include "tcg/tcg.h"
-#include "tcg/tcg-gvec-desc.h"
-#include "exec/helper-proto.h"
-
-/*
- * Returns a bit set in the MSB of each element that is zero,
- * as defined by the mask.
- */
-static inline uint64_t zero_search(uint64_t a, uint64_t mask)
-{
-    return ~(((a & mask) + mask) | a | mask);
-}
-
-/*
- * Returns a bit set in the MSB of each element that is not zero,
- * as defined by the mask.
- */
-static inline uint64_t nonzero_search(uint64_t a, uint64_t mask)
-{
-    return (((a & mask) + mask) | a) & ~mask;
-}
-
-/*
- * Returns the byte offset for the first match, or 16 for no match.
- */
-static inline int match_index(uint64_t c0, uint64_t c1)
-{
-    return (c0 ? clz64(c0) : clz64(c1) + 64) >> 3;
-}
-
-/*
- * Returns the number of bits composing one element.
- */
-static uint8_t get_element_bits(uint8_t es)
-{
-    return (1 << es) * BITS_PER_BYTE;
-}
-
-/*
- * Returns the bitmask for a single element.
- */
-static uint64_t get_single_element_mask(uint8_t es)
-{
-    return -1ull >> (64 - get_element_bits(es));
-}
-
-/*
- * Returns the bitmask for a single element (excluding the MSB).
- */
-static uint64_t get_single_element_lsbs_mask(uint8_t es)
-{
-    return -1ull >> (65 - get_element_bits(es));
-}
-
-/*
- * Returns the bitmasks for multiple elements (excluding the MSBs).
- */
-static uint64_t get_element_lsbs_mask(uint8_t es)
-{
-    return dup_const(es, get_single_element_lsbs_mask(es));
-}
-
-static int vfae(void *v1, const void *v2, const void *v3, bool in,
-                bool rt, bool zs, uint8_t es)
-{
-    const uint64_t mask = get_element_lsbs_mask(es);
-    const int bits = get_element_bits(es);
-    uint64_t a0, a1, b0, b1, e0, e1, t0, t1, z0, z1;
-    uint64_t first_zero = 16;
-    uint64_t first_equal;
-    int i;
-
-    a0 = s390_vec_read_element64(v2, 0);
-    a1 = s390_vec_read_element64(v2, 1);
-    b0 = s390_vec_read_element64(v3, 0);
-    b1 = s390_vec_read_element64(v3, 1);
-    e0 = 0;
-    e1 = 0;
-    /* compare against equality with every other element */
-    for (i = 0; i < 64; i += bits) {
-        t0 = rol64(b0, i);
-        t1 = rol64(b1, i);
-        e0 |= zero_search(a0 ^ t0, mask);
-        e0 |= zero_search(a0 ^ t1, mask);
-        e1 |= zero_search(a1 ^ t0, mask);
-        e1 |= zero_search(a1 ^ t1, mask);
-    }
-    /* invert the result if requested - invert only the MSBs */
-    if (in) {
-        e0 = ~e0 & ~mask;
-        e1 = ~e1 & ~mask;
-    }
-    first_equal = match_index(e0, e1);
-
-    if (zs) {
-        z0 = zero_search(a0, mask);
-        z1 = zero_search(a1, mask);
-        first_zero = match_index(z0, z1);
-    }
-
-    if (rt) {
-        e0 = (e0 >> (bits - 1)) * get_single_element_mask(es);
-        e1 = (e1 >> (bits - 1)) * get_single_element_mask(es);
-        s390_vec_write_element64(v1, 0, e0);
-        s390_vec_write_element64(v1, 1, e1);
-    } else {
-        s390_vec_write_element64(v1, 0, MIN(first_equal, first_zero));
-        s390_vec_write_element64(v1, 1, 0);
-    }
-
-    if (first_zero == 16 && first_equal == 16) {
-        return 3; /* no match */
-    } else if (first_zero == 16) {
-        return 1; /* matching elements, no match for zero */
-    } else if (first_equal < first_zero) {
-        return 2; /* matching elements before match for zero */
-    }
-    return 0; /* match for zero */
-}
-
-#define DEF_VFAE_HELPER(BITS)                                                  \
-void HELPER(gvec_vfae##BITS)(void *v1, const void *v2, const void *v3,         \
-                             uint32_t desc)                                    \
-{                                                                              \
-    const bool in = extract32(simd_data(desc), 3, 1);                          \
-    const bool rt = extract32(simd_data(desc), 2, 1);                          \
-    const bool zs = extract32(simd_data(desc), 1, 1);                          \
-                                                                               \
-    vfae(v1, v2, v3, in, rt, zs, MO_##BITS);                                   \
-}
-DEF_VFAE_HELPER(8)
-DEF_VFAE_HELPER(16)
-DEF_VFAE_HELPER(32)
-
-#define DEF_VFAE_CC_HELPER(BITS)                                               \
-void HELPER(gvec_vfae_cc##BITS)(void *v1, const void *v2, const void *v3,      \
-                                CPUS390XState *env, uint32_t desc)             \
-{                                                                              \
-    const bool in = extract32(simd_data(desc), 3, 1);                          \
-    const bool rt = extract32(simd_data(desc), 2, 1);                          \
-    const bool zs = extract32(simd_data(desc), 1, 1);                          \
-                                                                               \
-    env->cc_op = vfae(v1, v2, v3, in, rt, zs, MO_##BITS);                      \
-}
-DEF_VFAE_CC_HELPER(8)
-DEF_VFAE_CC_HELPER(16)
-DEF_VFAE_CC_HELPER(32)
-
-static int vfee(void *v1, const void *v2, const void *v3, bool zs, uint8_t es)
-{
-    const uint64_t mask = get_element_lsbs_mask(es);
-    uint64_t a0, a1, b0, b1, e0, e1, z0, z1;
-    uint64_t first_zero = 16;
-    uint64_t first_equal;
-
-    a0 = s390_vec_read_element64(v2, 0);
-    a1 = s390_vec_read_element64(v2, 1);
-    b0 = s390_vec_read_element64(v3, 0);
-    b1 = s390_vec_read_element64(v3, 1);
-    e0 = zero_search(a0 ^ b0, mask);
-    e1 = zero_search(a1 ^ b1, mask);
-    first_equal = match_index(e0, e1);
-
-    if (zs) {
-        z0 = zero_search(a0, mask);
-        z1 = zero_search(a1, mask);
-        first_zero = match_index(z0, z1);
-    }
-
-    s390_vec_write_element64(v1, 0, MIN(first_equal, first_zero));
-    s390_vec_write_element64(v1, 1, 0);
-    if (first_zero == 16 && first_equal == 16) {
-        return 3; /* no match */
-    } else if (first_zero == 16) {
-        return 1; /* matching elements, no match for zero */
-    } else if (first_equal < first_zero) {
-        return 2; /* matching elements before match for zero */
-    }
-    return 0; /* match for zero */
-}
-
-#define DEF_VFEE_HELPER(BITS)                                                  \
-void HELPER(gvec_vfee##BITS)(void *v1, const void *v2, const void *v3,         \
-                             uint32_t desc)                                    \
-{                                                                              \
-    const bool zs = extract32(simd_data(desc), 1, 1);                          \
-                                                                               \
-    vfee(v1, v2, v3, zs, MO_##BITS);                                           \
-}
-DEF_VFEE_HELPER(8)
-DEF_VFEE_HELPER(16)
-DEF_VFEE_HELPER(32)
-
-#define DEF_VFEE_CC_HELPER(BITS)                                               \
-void HELPER(gvec_vfee_cc##BITS)(void *v1, const void *v2, const void *v3,      \
-                                CPUS390XState *env, uint32_t desc)             \
-{                                                                              \
-    const bool zs = extract32(simd_data(desc), 1, 1);                          \
-                                                                               \
-    env->cc_op = vfee(v1, v2, v3, zs, MO_##BITS);                              \
-}
-DEF_VFEE_CC_HELPER(8)
-DEF_VFEE_CC_HELPER(16)
-DEF_VFEE_CC_HELPER(32)
-
-static int vfene(void *v1, const void *v2, const void *v3, bool zs, uint8_t es)
-{
-    const uint64_t mask = get_element_lsbs_mask(es);
-    uint64_t a0, a1, b0, b1, e0, e1, z0, z1;
-    uint64_t first_zero = 16;
-    uint64_t first_inequal;
-    bool smaller = false;
-
-    a0 = s390_vec_read_element64(v2, 0);
-    a1 = s390_vec_read_element64(v2, 1);
-    b0 = s390_vec_read_element64(v3, 0);
-    b1 = s390_vec_read_element64(v3, 1);
-    e0 = nonzero_search(a0 ^ b0, mask);
-    e1 = nonzero_search(a1 ^ b1, mask);
-    first_inequal = match_index(e0, e1);
-
-    /* identify the smaller element */
-    if (first_inequal < 16) {
-        uint8_t enr = first_inequal / (1 << es);
-        uint32_t a = s390_vec_read_element(v2, enr, es);
-        uint32_t b = s390_vec_read_element(v3, enr, es);
-
-        smaller = a < b;
-    }
-
-    if (zs) {
-        z0 = zero_search(a0, mask);
-        z1 = zero_search(a1, mask);
-        first_zero = match_index(z0, z1);
-    }
-
-    s390_vec_write_element64(v1, 0, MIN(first_inequal, first_zero));
-    s390_vec_write_element64(v1, 1, 0);
-    if (first_zero == 16 && first_inequal == 16) {
-        return 3;
-    } else if (first_zero < first_inequal) {
-        return 0;
-    }
-    return smaller ? 1 : 2;
-}
-
-#define DEF_VFENE_HELPER(BITS)                                                 \
-void HELPER(gvec_vfene##BITS)(void *v1, const void *v2, const void *v3,        \
-                              uint32_t desc)                                   \
-{                                                                              \
-    const bool zs = extract32(simd_data(desc), 1, 1);                          \
-                                                                               \
-    vfene(v1, v2, v3, zs, MO_##BITS);                                          \
-}
-DEF_VFENE_HELPER(8)
-DEF_VFENE_HELPER(16)
-DEF_VFENE_HELPER(32)
-
-#define DEF_VFENE_CC_HELPER(BITS)                                              \
-void HELPER(gvec_vfene_cc##BITS)(void *v1, const void *v2, const void *v3,     \
-                                 CPUS390XState *env, uint32_t desc)            \
-{                                                                              \
-    const bool zs = extract32(simd_data(desc), 1, 1);                          \
-                                                                               \
-    env->cc_op = vfene(v1, v2, v3, zs, MO_##BITS);                             \
-}
-DEF_VFENE_CC_HELPER(8)
-DEF_VFENE_CC_HELPER(16)
-DEF_VFENE_CC_HELPER(32)
-
-static int vistr(void *v1, const void *v2, uint8_t es)
-{
-    const uint64_t mask = get_element_lsbs_mask(es);
-    uint64_t a0 = s390_vec_read_element64(v2, 0);
-    uint64_t a1 = s390_vec_read_element64(v2, 1);
-    uint64_t z;
-    int cc = 3;
-
-    z = zero_search(a0, mask);
-    if (z) {
-        a0 &= ~(-1ull >> clz64(z));
-        a1 = 0;
-        cc = 0;
-    } else {
-        z = zero_search(a1, mask);
-        if (z) {
-            a1 &= ~(-1ull >> clz64(z));
-            cc = 0;
-        }
-    }
-
-    s390_vec_write_element64(v1, 0, a0);
-    s390_vec_write_element64(v1, 1, a1);
-    return cc;
-}
-
-#define DEF_VISTR_HELPER(BITS)                                                 \
-void HELPER(gvec_vistr##BITS)(void *v1, const void *v2, uint32_t desc)         \
-{                                                                              \
-    vistr(v1, v2, MO_##BITS);                                                  \
-}
-DEF_VISTR_HELPER(8)
-DEF_VISTR_HELPER(16)
-DEF_VISTR_HELPER(32)
-
-#define DEF_VISTR_CC_HELPER(BITS)                                              \
-void HELPER(gvec_vistr_cc##BITS)(void *v1, const void *v2, CPUS390XState *env, \
-                                uint32_t desc)                                 \
-{                                                                              \
-    env->cc_op = vistr(v1, v2, MO_##BITS);                                     \
-}
-DEF_VISTR_CC_HELPER(8)
-DEF_VISTR_CC_HELPER(16)
-DEF_VISTR_CC_HELPER(32)
-
-static bool element_compare(uint32_t data, uint32_t l, uint8_t c)
-{
-    const bool equal = extract32(c, 7, 1);
-    const bool lower = extract32(c, 6, 1);
-    const bool higher = extract32(c, 5, 1);
-
-    if (data < l) {
-        return lower;
-    } else if (data > l) {
-        return higher;
-    }
-    return equal;
-}
-
-static int vstrc(void *v1, const void *v2, const void *v3, const void *v4,
-                 bool in, bool rt, bool zs, uint8_t es)
-{
-    const uint64_t mask = get_element_lsbs_mask(es);
-    uint64_t a0 = s390_vec_read_element64(v2, 0);
-    uint64_t a1 = s390_vec_read_element64(v2, 1);
-    int first_zero = 16, first_match = 16;
-    S390Vector rt_result = {};
-    uint64_t z0, z1;
-    int i, j;
-
-    if (zs) {
-        z0 = zero_search(a0, mask);
-        z1 = zero_search(a1, mask);
-        first_zero = match_index(z0, z1);
-    }
-
-    for (i = 0; i < 16 / (1 << es); i++) {
-        const uint32_t data = s390_vec_read_element(v2, i, es);
-        const int cur_byte = i * (1 << es);
-        bool any_match = false;
-
-        /* if we don't need a bit vector, we can stop early */
-        if (cur_byte == first_zero && !rt) {
-            break;
-        }
-
-        for (j = 0; j < 16 / (1 << es); j += 2) {
-            const uint32_t l1 = s390_vec_read_element(v3, j, es);
-            const uint32_t l2 = s390_vec_read_element(v3, j + 1, es);
-            /* we are only interested in the highest byte of each element */
-            const uint8_t c1 = s390_vec_read_element8(v4, j * (1 << es));
-            const uint8_t c2 = s390_vec_read_element8(v4, (j + 1) * (1 << es));
-
-            if (element_compare(data, l1, c1) &&
-                element_compare(data, l2, c2)) {
-                any_match = true;
-                break;
-            }
-        }
-        /* invert the result if requested */
-        any_match = in ^ any_match;
-
-        if (any_match) {
-            /* indicate bit vector if requested */
-            if (rt) {
-                const uint64_t val = -1ull;
-
-                first_match = MIN(cur_byte, first_match);
-                s390_vec_write_element(&rt_result, i, es, val);
-            } else {
-                /* stop on the first match */
-                first_match = cur_byte;
-                break;
-            }
-        }
-    }
-
-    if (rt) {
-        *(S390Vector *)v1 = rt_result;
-    } else {
-        s390_vec_write_element64(v1, 0, MIN(first_match, first_zero));
-        s390_vec_write_element64(v1, 1, 0);
-    }
-
-    if (first_zero == 16 && first_match == 16) {
-        return 3; /* no match */
-    } else if (first_zero == 16) {
-        return 1; /* matching elements, no match for zero */
-    } else if (first_match < first_zero) {
-        return 2; /* matching elements before match for zero */
-    }
-    return 0; /* match for zero */
-}
-
-#define DEF_VSTRC_HELPER(BITS)                                                 \
-void HELPER(gvec_vstrc##BITS)(void *v1, const void *v2, const void *v3,        \
-                              const void *v4, uint32_t desc)                   \
-{                                                                              \
-    const bool in = extract32(simd_data(desc), 3, 1);                          \
-    const bool zs = extract32(simd_data(desc), 1, 1);                          \
-                                                                               \
-    vstrc(v1, v2, v3, v4, in, 0, zs, MO_##BITS);                               \
-}
-DEF_VSTRC_HELPER(8)
-DEF_VSTRC_HELPER(16)
-DEF_VSTRC_HELPER(32)
-
-#define DEF_VSTRC_RT_HELPER(BITS)                                              \
-void HELPER(gvec_vstrc_rt##BITS)(void *v1, const void *v2, const void *v3,     \
-                                 const void *v4, uint32_t desc)                \
-{                                                                              \
-    const bool in = extract32(simd_data(desc), 3, 1);                          \
-    const bool zs = extract32(simd_data(desc), 1, 1);                          \
-                                                                               \
-    vstrc(v1, v2, v3, v4, in, 1, zs, MO_##BITS);                               \
-}
-DEF_VSTRC_RT_HELPER(8)
-DEF_VSTRC_RT_HELPER(16)
-DEF_VSTRC_RT_HELPER(32)
-
-#define DEF_VSTRC_CC_HELPER(BITS)                                              \
-void HELPER(gvec_vstrc_cc##BITS)(void *v1, const void *v2, const void *v3,     \
-                                 const void *v4, CPUS390XState *env,           \
-                                 uint32_t desc)                                \
-{                                                                              \
-    const bool in = extract32(simd_data(desc), 3, 1);                          \
-    const bool zs = extract32(simd_data(desc), 1, 1);                          \
-                                                                               \
-    env->cc_op = vstrc(v1, v2, v3, v4, in, 0, zs, MO_##BITS);                  \
-}
-DEF_VSTRC_CC_HELPER(8)
-DEF_VSTRC_CC_HELPER(16)
-DEF_VSTRC_CC_HELPER(32)
-
-#define DEF_VSTRC_CC_RT_HELPER(BITS)                                           \
-void HELPER(gvec_vstrc_cc_rt##BITS)(void *v1, const void *v2, const void *v3,  \
-                                    const void *v4, CPUS390XState *env,        \
-                                    uint32_t desc)                             \
-{                                                                              \
-    const bool in = extract32(simd_data(desc), 3, 1);                          \
-    const bool zs = extract32(simd_data(desc), 1, 1);                          \
-                                                                               \
-    env->cc_op = vstrc(v1, v2, v3, v4, in, 1, zs, MO_##BITS);                  \
-}
-DEF_VSTRC_CC_RT_HELPER(8)
-DEF_VSTRC_CC_RT_HELPER(16)
-DEF_VSTRC_CC_RT_HELPER(32)
diff --git a/tests/qtest/fuzz-sdcard-test.c b/tests/qtest/fuzz-sdcard-test.c
new file mode 100644 (file)
index 0000000..96602ea
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * QTest fuzzer-generated testcase for sdcard device
+ *
+ * Copyright (c) 2021 Philippe Mathieu-Daudé <f4bug@amsat.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "libqos/libqtest.h"
+
+/*
+ * https://gitlab.com/qemu-project/qemu/-/issues/450
+ * Used to trigger:
+ *  Assertion `wpnum < sd->wpgrps_size' failed.
+ */
+static void oss_fuzz_29225(void)
+{
+    QTestState *s;
+
+    s = qtest_init(" -display none -m 512m -nodefaults -nographic"
+                   " -device sdhci-pci,sd-spec-version=3"
+                   " -device sd-card,drive=d0"
+                   " -drive if=none,index=0,file=null-co://,format=raw,id=d0");
+
+    qtest_outl(s, 0xcf8, 0x80001010);
+    qtest_outl(s, 0xcfc, 0xd0690);
+    qtest_outl(s, 0xcf8, 0x80001003);
+    qtest_outl(s, 0xcf8, 0x80001013);
+    qtest_outl(s, 0xcfc, 0xffffffff);
+    qtest_outl(s, 0xcf8, 0x80001003);
+    qtest_outl(s, 0xcfc, 0x3effe00);
+
+    qtest_bufwrite(s, 0xff0d062c, "\xff", 0x1);
+    qtest_bufwrite(s, 0xff0d060f, "\xb7", 0x1);
+    qtest_bufwrite(s, 0xff0d060a, "\xc9", 0x1);
+    qtest_bufwrite(s, 0xff0d060f, "\x29", 0x1);
+    qtest_bufwrite(s, 0xff0d060f, "\xc2", 0x1);
+    qtest_bufwrite(s, 0xff0d0628, "\xf7", 0x1);
+    qtest_bufwrite(s, 0x0, "\xe3", 0x1);
+    qtest_bufwrite(s, 0x7, "\x13", 0x1);
+    qtest_bufwrite(s, 0x8, "\xe3", 0x1);
+    qtest_bufwrite(s, 0xf, "\xe3", 0x1);
+    qtest_bufwrite(s, 0xff0d060f, "\x03", 0x1);
+    qtest_bufwrite(s, 0xff0d0605, "\x01", 0x1);
+    qtest_bufwrite(s, 0xff0d060b, "\xff", 0x1);
+    qtest_bufwrite(s, 0xff0d060c, "\xff", 0x1);
+    qtest_bufwrite(s, 0xff0d060e, "\xff", 0x1);
+    qtest_bufwrite(s, 0xff0d060f, "\x06", 0x1);
+    qtest_bufwrite(s, 0xff0d060f, "\x9e", 0x1);
+
+    qtest_quit(s);
+}
+
+int main(int argc, char **argv)
+{
+    const char *arch = qtest_get_arch();
+
+    g_test_init(&argc, &argv, NULL);
+
+   if (strcmp(arch, "i386") == 0) {
+        qtest_add_func("fuzz/sdcard/oss_fuzz_29225", oss_fuzz_29225);
+   }
+
+   return g_test_run();
+}
index ee7347b72756324851b098fd2fe26634f6d87241..e22a0792c587d7c324fa8c5c7fb781c0fdb852e3 100644 (file)
@@ -21,6 +21,7 @@ qtests_generic = \
   (config_all_devices.has_key('CONFIG_MEGASAS_SCSI_PCI') ? ['fuzz-megasas-test'] : []) + \
   (config_all_devices.has_key('CONFIG_VIRTIO_SCSI') ? ['fuzz-virtio-scsi-test'] : []) + \
   (config_all_devices.has_key('CONFIG_SB16') ? ['fuzz-sb16-test'] : []) + \
+  (config_all_devices.has_key('CONFIG_SDHCI_PCI') ? ['fuzz-sdcard-test'] : []) + \
   [
   'cdrom-test',
   'device-introspect-test',
index e293eeed7c00120bf6983ca6c54275308920480f..8418673c18cf0f654c356d7ae242b4c082077ae8 100644 (file)
@@ -127,7 +127,7 @@ void trace_init_vcpu(CPUState *vcpu)
 {
     TraceEventIter iter;
     TraceEvent *ev;
-    trace_event_iter_init(&iter, NULL);
+    trace_event_iter_init_all(&iter);
     while ((ev = trace_event_iter_next(&iter)) != NULL) {
         if (trace_event_is_vcpu(ev) &&
             trace_event_get_state_static(ev) &&
index 4be38e1af28dbf2c715532dde5c60cb9fd4ef834..d5b68e846eeb834c62ce587551c441b1f0a8cd28 100644 (file)
@@ -82,6 +82,10 @@ void trace_event_register_group(TraceEvent **events)
     event_groups = g_renew(TraceEventGroup, event_groups, nevent_groups + 1);
     event_groups[nevent_groups].events = events;
     nevent_groups++;
+
+#ifdef CONFIG_TRACE_SIMPLE
+    st_init_group(nevent_groups - 1);
+#endif
 }
 
 
@@ -91,7 +95,7 @@ TraceEvent *trace_event_name(const char *name)
 
     TraceEventIter iter;
     TraceEvent *ev;
-    trace_event_iter_init(&iter, NULL);
+    trace_event_iter_init_all(&iter);
     while ((ev = trace_event_iter_next(&iter)) != NULL) {
         if (strcmp(trace_event_get_name(ev), name) == 0) {
             return ev;
@@ -100,27 +104,46 @@ TraceEvent *trace_event_name(const char *name)
     return NULL;
 }
 
-void trace_event_iter_init(TraceEventIter *iter, const char *pattern)
+void trace_event_iter_init_all(TraceEventIter *iter)
 {
     iter->event = 0;
     iter->group = 0;
+    iter->group_id = -1;
+    iter->pattern = NULL;
+}
+
+void trace_event_iter_init_pattern(TraceEventIter *iter, const char *pattern)
+{
+    trace_event_iter_init_all(iter);
     iter->pattern = pattern;
 }
 
+void trace_event_iter_init_group(TraceEventIter *iter, size_t group_id)
+{
+    trace_event_iter_init_all(iter);
+    iter->group_id = group_id;
+}
+
 TraceEvent *trace_event_iter_next(TraceEventIter *iter)
 {
     while (iter->group < nevent_groups &&
            event_groups[iter->group].events[iter->event] != NULL) {
         TraceEvent *ev = event_groups[iter->group].events[iter->event];
+        size_t group = iter->group;
         iter->event++;
         if (event_groups[iter->group].events[iter->event] == NULL) {
             iter->event = 0;
             iter->group++;
         }
-        if (!iter->pattern ||
-            g_pattern_match_simple(iter->pattern, trace_event_get_name(ev))) {
-            return ev;
+        if (iter->pattern &&
+            !g_pattern_match_simple(iter->pattern, trace_event_get_name(ev))) {
+            continue;
+        }
+        if (iter->group_id != -1 &&
+            iter->group_id != group) {
+            continue;
         }
+        return ev;
     }
 
     return NULL;
@@ -130,7 +153,7 @@ void trace_list_events(FILE *f)
 {
     TraceEventIter iter;
     TraceEvent *ev;
-    trace_event_iter_init(&iter, NULL);
+    trace_event_iter_init_all(&iter);
     while ((ev = trace_event_iter_next(&iter)) != NULL) {
         fprintf(f, "%s\n", trace_event_get_name(ev));
     }
@@ -150,7 +173,7 @@ static void do_trace_enable_events(const char *line_buf)
     TraceEvent *ev;
     bool is_pattern = trace_event_is_pattern(line_ptr);
 
-    trace_event_iter_init(&iter, line_ptr);
+    trace_event_iter_init_pattern(&iter, line_ptr);
     while ((ev = trace_event_iter_next(&iter)) != NULL) {
         if (!trace_event_get_state_static(ev)) {
             if (!is_pattern) {
@@ -256,7 +279,7 @@ void trace_fini_vcpu(CPUState *vcpu)
 
     trace_guest_cpu_exit(vcpu);
 
-    trace_event_iter_init(&iter, NULL);
+    trace_event_iter_init_all(&iter);
     while ((ev = trace_event_iter_next(&iter)) != NULL) {
         if (trace_event_is_vcpu(ev) &&
             trace_event_get_state_static(ev) &&
index 9522a7b318e21294fabd36864c27f7402dc9425e..23b8393b297e379bb64e504f99a4606d705be768 100644 (file)
 #include "event-internal.h"
 
 typedef struct TraceEventIter {
+    /* iter state */
     size_t event;
     size_t group;
+    /* filter conditions */
+    size_t group_id;
     const char *pattern;
 } TraceEventIter;
 
 
 /**
- * trace_event_iter_init:
+ * trace_event_iter_init_all:
  * @iter: the event iterator struct
- * @pattern: optional pattern to filter events on name
  *
  * Initialize the event iterator struct @iter,
- * optionally using @pattern to filter out events
+ * for all events.
+ */
+void trace_event_iter_init_all(TraceEventIter *iter);
+
+/**
+ * trace_event_iter_init_pattern:
+ * @iter: the event iterator struct
+ * @pattern: pattern to filter events on name
+ *
+ * Initialize the event iterator struct @iter,
+ * using @pattern to filter out events
  * with non-matching names.
  */
-void trace_event_iter_init(TraceEventIter *iter, const char *pattern);
+void trace_event_iter_init_pattern(TraceEventIter *iter, const char *pattern);
+
+/**
+ * trace_event_iter_init_group:
+ * @iter: the event iterator struct
+ * @group_id: group_id to filter events by group.
+ *
+ * Initialize the event iterator struct @iter,
+ * using @group_id to filter for events in the group.
+ */
+void trace_event_iter_init_group(TraceEventIter *iter, size_t group_id);
 
 /**
  * trace_event_iter_next:
index 08f83a15c3169edb6b38adcca9fdc0e885e68f83..ef18f11d6468191fc6e3572e2da4f52def55f981 100644 (file)
@@ -26,7 +26,7 @@ foreach dir : [ '.' ] + trace_events_subdirs
                                 input: trace_events_file,
                                 command: [ tracetool, group, '--format=ust-events-h', '@INPUT@', '@OUTPUT@' ],
                                 depend_files: tracetool_depends)
-    trace_ss.add(trace_ust_h, lttng, urcubp)
+    trace_ss.add(trace_ust_h, lttng)
     genh += trace_ust_h
   endif
   trace_ss.add(trace_h, trace_c)
index 85f81e47cc6d998068bad07c2fe0851cd96cbed2..3b4f4702b4f02b8d5b6357b4e17877634508c1c4 100644 (file)
@@ -55,7 +55,7 @@ static bool check_events(bool has_vcpu, bool ignore_unavailable, bool is_pattern
         /* error for unavailable events */
         TraceEventIter iter;
         TraceEvent *ev;
-        trace_event_iter_init(&iter, name);
+        trace_event_iter_init_pattern(&iter, name);
         while ((ev = trace_event_iter_next(&iter)) != NULL) {
             if (!ignore_unavailable && !trace_event_get_state_static(ev)) {
                 error_setg(errp, "event \"%s\" is disabled", trace_event_get_name(ev));
@@ -90,7 +90,7 @@ TraceEventInfoList *qmp_trace_event_get_state(const char *name,
     }
 
     /* Get states (all errors checked above) */
-    trace_event_iter_init(&iter, name);
+    trace_event_iter_init_pattern(&iter, name);
     while ((ev = trace_event_iter_next(&iter)) != NULL) {
         TraceEventInfo *value;
         bool is_vcpu = trace_event_is_vcpu(ev);
@@ -153,7 +153,7 @@ void qmp_trace_event_set_state(const char *name, bool enable,
     }
 
     /* Apply changes (all errors checked above) */
-    trace_event_iter_init(&iter, name);
+    trace_event_iter_init_pattern(&iter, name);
     while ((ev = trace_event_iter_next(&iter)) != NULL) {
         if (!trace_event_get_state_static(ev) ||
             (has_vcpu && !trace_event_is_vcpu(ev))) {
index 9cd2ed1fb3f4c90c2af4885c2a98c1bd31e8492c..ac499edee0d5fb7b19c700525b9b524ca275f3bc 100644 (file)
@@ -280,14 +280,12 @@ void trace_record_finish(TraceBufferRecord *rec)
     }
 }
 
-static int st_write_event_mapping(void)
+static int st_write_event_mapping(TraceEventIter *iter)
 {
     uint64_t type = TRACE_RECORD_TYPE_MAPPING;
-    TraceEventIter iter;
     TraceEvent *ev;
 
-    trace_event_iter_init(&iter, NULL);
-    while ((ev = trace_event_iter_next(&iter)) != NULL) {
+    while ((ev = trace_event_iter_next(iter)) != NULL) {
         uint64_t id = trace_event_get_id(ev);
         const char *name = trace_event_get_name(ev);
         uint32_t len = strlen(name);
@@ -309,6 +307,7 @@ static int st_write_event_mapping(void)
  */
 bool st_set_trace_file_enabled(bool enable)
 {
+    TraceEventIter iter;
     bool was_enabled = trace_fp;
 
     if (enable == !!trace_fp) {
@@ -333,8 +332,9 @@ bool st_set_trace_file_enabled(bool enable)
             return was_enabled;
         }
 
+        trace_event_iter_init_all(&iter);
         if (fwrite(&header, sizeof header, 1, trace_fp) != 1 ||
-            st_write_event_mapping() < 0) {
+            st_write_event_mapping(&iter) < 0) {
             fclose(trace_fp);
             trace_fp = NULL;
             return was_enabled;
@@ -422,3 +422,15 @@ bool st_init(void)
     atexit(st_flush_trace_buffer);
     return true;
 }
+
+void st_init_group(size_t group)
+{
+    TraceEventIter iter;
+
+    if (!trace_writeout_enabled) {
+        return;
+    }
+
+    trace_event_iter_init_group(&iter, group);
+    st_write_event_mapping(&iter);
+}
index 26ccbc8b8ae353244eb1fe5351cd6d8002b36a28..ee1983ce5617a9c8b09f66d8ca7d83ed3a155a57 100644 (file)
@@ -15,6 +15,7 @@ void st_print_trace_file_status(void);
 bool st_set_trace_file_enabled(bool enable);
 void st_set_trace_file(const char *file);
 bool st_init(void);
+void st_init_group(size_t group);
 void st_flush_trace_buffer(void);
 
 typedef struct {