diff mbox

[076/147] target-s390: Convert FP ADD, COMPARE, LOAD TEST/ROUND/LENGTHENED

Message ID 1348790963-25949-1-git-send-email-rth@twiddle.net
State New
Headers show

Commit Message

Richard Henderson Sept. 28, 2012, 12:09 a.m. UTC
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target-s390x/cc_helper.c   |   9 +-
 target-s390x/cpu.h         |  10 +-
 target-s390x/fpu_helper.c  | 298 +++++++++++++++++----------------------------
 target-s390x/helper.h      |  31 ++---
 target-s390x/insn-data.def |  25 ++++
 target-s390x/translate.c   | 217 +++++++++++++++++++--------------
 6 files changed, 278 insertions(+), 312 deletions(-)
diff mbox

Patch

diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c
index bead820..27aac03 100644
--- a/target-s390x/cc_helper.c
+++ b/target-s390x/cc_helper.c
@@ -505,18 +505,15 @@  static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op,
         r =  cc_calc_sla_64(src, dst);
         break;
 
-    case CC_OP_LTGT_F32:
-        r = set_cc_f32(env, src, dst);
-        break;
-    case CC_OP_LTGT_F64:
-        r = set_cc_f64(env, 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, "Unknown CC operation: %s\n", cc_name(cc_op));
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index ae9b4a3..7d17bf3 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -471,11 +471,9 @@  enum cc_op {
     CC_OP_TM_32,                /* test under mask (32bit) */
     CC_OP_TM_64,                /* test under mask (64bit) */
 
-    CC_OP_LTGT_F32,             /* FP compare (32bit) */
-    CC_OP_LTGT_F64,             /* FP compare (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) */
@@ -517,10 +515,9 @@  static const char *cc_names[] = {
     [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_LTGT_F32]  = "CC_OP_LTGT_F32",
-    [CC_OP_LTGT_F64]  = "CC_OP_LTGT_F64",
     [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",
@@ -935,10 +932,9 @@  static inline void cpu_pc_from_tb(CPUS390XState *env, TranslationBlock* tb)
 }
 
 /* fpu_helper.c */
-uint32_t set_cc_f32(CPUS390XState *env, float32 v1, float32 v2);
-uint32_t set_cc_f64(CPUS390XState *env, float64 v1, float64 v2);
 uint32_t set_cc_nz_f32(float32 v);
 uint32_t set_cc_nz_f64(float64 v);
+uint32_t set_cc_nz_f128(float128 v);
 
 /* misc_helper.c */
 void program_interrupt(CPUS390XState *env, uint32_t code, int ilen);
diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c
index ee9420d..debaa7f 100644
--- a/target-s390x/fpu_helper.c
+++ b/target-s390x/fpu_helper.c
@@ -32,6 +32,52 @@ 
 #define HELPER_LOG(x...)
 #endif
 
+#define RET128(F) (env->retxl = F.low, F.high)
+
+#define convert_bit(mask, from, to) \
+    (to < from                      \
+     ? (mask / (from / to)) & to    \
+     : (mask & from) * (to / from))
+
+static void ieee_exception(CPUS390XState *env, uint32_t dxc, uintptr_t retaddr)
+{
+    /* Install the DXC code.  */
+    env->fpc = (env->fpc & ~0xff00) | (dxc << 8);
+    /* Trap.  */
+    runtime_exception(env, PGM_DATA, retaddr);
+}
+
+/* Should be called after any operation that may raise IEEE exceptions.  */
+static void handle_exceptions(CPUS390XState *env, 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;
+
+    /* Convert softfloat exception bits to s390 exception bits.  */
+    s390_exc = 0;
+    s390_exc |= convert_bit(qemu_exc, float_flag_invalid, 0x80);
+    s390_exc |= convert_bit(qemu_exc, float_flag_divbyzero, 0x40);
+    s390_exc |= convert_bit(qemu_exc, float_flag_overflow, 0x20);
+    s390_exc |= convert_bit(qemu_exc, float_flag_underflow, 0x10);
+    s390_exc |= convert_bit(qemu_exc, float_flag_inexact, 0x08);
+
+    /* Install the exceptions that we raised.  */
+    env->fpc |= s390_exc << 16;
+
+    /* Send signals for enabled exceptions.  */
+    s390_exc &= env->fpc >> 24;
+    if (s390_exc) {
+        ieee_exception(env, s390_exc, retaddr);
+    }
+}
+
 static inline int float_comp_to_cc(CPUS390XState *env, int float_compare)
 {
     switch (float_compare) {
@@ -48,19 +94,6 @@  static inline int float_comp_to_cc(CPUS390XState *env, int float_compare)
     }
 }
 
-/* condition codes for binary FP ops */
-uint32_t set_cc_f32(CPUS390XState *env, float32 v1, float32 v2)
-{
-    return float_comp_to_cc(env, float32_compare_quiet(v1, v2,
-                                                       &env->fpu_status));
-}
-
-uint32_t set_cc_f64(CPUS390XState *env, float64 v1, float64 v2)
-{
-    return float_comp_to_cc(env, float64_compare_quiet(v1, v2,
-                                                       &env->fpu_status));
-}
-
 /* condition codes for unary FP ops */
 uint32_t set_cc_nz_f32(float32 v)
 {
@@ -88,7 +121,7 @@  uint32_t set_cc_nz_f64(float64 v)
     }
 }
 
-static uint32_t set_cc_nz_f128(float128 v)
+uint32_t set_cc_nz_f128(float128 v)
 {
     if (float128_is_any_nan(v)) {
         return 3;
@@ -152,27 +185,31 @@  void HELPER(cefbr)(CPUS390XState *env, uint32_t f1, int32_t v2)
                env->fregs[f1].l.upper, f1);
 }
 
-/* 32-bit FP addition RR */
-uint32_t HELPER(aebr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+/* 32-bit FP addition */
+uint64_t HELPER(aeb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
 {
-    env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper,
-                                         env->fregs[f2].l.upper,
-                                         &env->fpu_status);
-    HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __func__,
-               env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1);
-
-    return set_cc_nz_f32(env->fregs[f1].l.upper);
+    float32 ret = float32_add(f1, f2, &env->fpu_status);
+    handle_exceptions(env, GETPC());
+    return ret;
 }
 
-/* 64-bit FP addition RR */
-uint32_t HELPER(adbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+/* 64-bit FP addition */
+uint64_t HELPER(adb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
 {
-    env->fregs[f1].d = float64_add(env->fregs[f1].d, env->fregs[f2].d,
-                                   &env->fpu_status);
-    HELPER_LOG("%s: adding 0x%ld resulting in 0x%ld in f%d\n", __func__,
-               env->fregs[f2].d, env->fregs[f1].d, f1);
+    float64 ret = float64_add(f1, f2, &env->fpu_status);
+    handle_exceptions(env, GETPC());
+    return ret;
+}
 
-    return set_cc_nz_f64(env->fregs[f1].d);
+/* 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, GETPC());
+    return RET128(ret);
 }
 
 /* 32-bit FP subtraction RR */
@@ -246,50 +283,51 @@  void HELPER(mxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
 }
 
 /* convert 32-bit float to 64-bit float */
-void HELPER(ldebr)(CPUS390XState *env, uint32_t r1, uint32_t r2)
+uint64_t HELPER(ldeb)(CPUS390XState *env, uint64_t f2)
 {
-    env->fregs[r1].d = float32_to_float64(env->fregs[r2].l.upper,
-                                          &env->fpu_status);
+    float64 ret = float32_to_float64(f2, &env->fpu_status);
+    handle_exceptions(env, GETPC());
+    return ret;
 }
 
 /* convert 128-bit float to 64-bit float */
-void HELPER(ldxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+uint64_t HELPER(ldxb)(CPUS390XState *env, uint64_t ah, uint64_t al)
 {
-    CPU_QuadU x2;
-
-    x2.ll.upper = env->fregs[f2].ll;
-    x2.ll.lower = env->fregs[f2 + 2].ll;
-    env->fregs[f1].d = float128_to_float64(x2.q, &env->fpu_status);
-    HELPER_LOG("%s: to 0x%ld\n", __func__, env->fregs[f1].d);
+    float64 ret = float128_to_float64(make_float128(ah, al), &env->fpu_status);
+    handle_exceptions(env, GETPC());
+    return ret;
 }
 
 /* convert 64-bit float to 128-bit float */
-void HELPER(lxdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+uint64_t HELPER(lxdb)(CPUS390XState *env, uint64_t f2)
 {
-    CPU_QuadU res;
+    float128 ret = float64_to_float128(f2, &env->fpu_status);
+    handle_exceptions(env, GETPC());
+    return RET128(ret);
+}
 
-    res.q = float64_to_float128(env->fregs[f2].d, &env->fpu_status);
-    env->fregs[f1].ll = res.ll.upper;
-    env->fregs[f1 + 2].ll = res.ll.lower;
+/* 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, GETPC());
+    return RET128(ret);
 }
 
 /* convert 64-bit float to 32-bit float */
-void HELPER(ledbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+uint64_t HELPER(ledb)(CPUS390XState *env, uint64_t f2)
 {
-    float64 d2 = env->fregs[f2].d;
-
-    env->fregs[f1].l.upper = float64_to_float32(d2, &env->fpu_status);
+    float32 ret = float64_to_float32(f2, &env->fpu_status);
+    handle_exceptions(env, GETPC());
+    return ret;
 }
 
 /* convert 128-bit float to 32-bit float */
-void HELPER(lexbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al)
 {
-    CPU_QuadU x2;
-
-    x2.ll.upper = env->fregs[f2].ll;
-    x2.ll.lower = env->fregs[f2 + 2].ll;
-    env->fregs[f1].l.upper = float128_to_float32(x2.q, &env->fpu_status);
-    HELPER_LOG("%s: to 0x%d\n", __func__, env->fregs[f1].l.upper);
+    float32 ret = float128_to_float32(make_float128(ah, al), &env->fpu_status);
+    handle_exceptions(env, GETPC());
+    return ret;
 }
 
 /* absolute value of 32-bit float */
@@ -328,32 +366,6 @@  uint32_t HELPER(lpxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
     return set_cc_nz_f128(v1.q);
 }
 
-/* load and test 64-bit float */
-uint32_t HELPER(ltdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
-{
-    env->fregs[f1].d = env->fregs[f2].d;
-    return set_cc_nz_f64(env->fregs[f1].d);
-}
-
-/* load and test 32-bit float */
-uint32_t HELPER(ltebr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
-{
-    env->fregs[f1].l.upper = env->fregs[f2].l.upper;
-    return set_cc_nz_f32(env->fregs[f1].l.upper);
-}
-
-/* load and test 128-bit float */
-uint32_t HELPER(ltxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
-{
-    CPU_QuadU x;
-
-    x.ll.upper = env->fregs[f2].ll;
-    x.ll.lower = env->fregs[f2 + 2].ll;
-    env->fregs[f1].ll = x.ll.upper;
-    env->fregs[f1 + 2].ll = x.ll.lower;
-    return set_cc_nz_f128(x.q);
-}
-
 /* load complement of 32-bit float */
 uint32_t HELPER(lcebr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
 {
@@ -383,18 +395,6 @@  uint32_t HELPER(lcxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
     return set_cc_nz_f128(x1.q);
 }
 
-/* 32-bit FP addition RM */
-void HELPER(aeb)(CPUS390XState *env, uint32_t f1, uint32_t val)
-{
-    float32 v1 = env->fregs[f1].l.upper;
-    CPU_FloatU v2;
-
-    v2.l = val;
-    HELPER_LOG("%s: adding 0x%d from f%d and 0x%d\n", __func__,
-               v1, f1, v2.f);
-    env->fregs[f1].l.upper = float32_add(v1, v2.f, &env->fpu_status);
-}
-
 /* 32-bit FP division RM */
 void HELPER(deb)(CPUS390XState *env, uint32_t f1, uint32_t val)
 {
@@ -419,66 +419,31 @@  void HELPER(meeb)(CPUS390XState *env, uint32_t f1, uint32_t val)
     env->fregs[f1].l.upper = float32_mul(v1, v2.f, &env->fpu_status);
 }
 
-/* 32-bit FP compare RR */
-uint32_t HELPER(cebr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
-{
-    float32 v1 = env->fregs[f1].l.upper;
-    float32 v2 = env->fregs[f2].l.upper;
-
-    HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __func__,
-               v1, f1, v2);
-    return set_cc_f32(env, v1, v2);
-}
-
-/* 64-bit FP compare RR */
-uint32_t HELPER(cdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
+/* 32-bit FP compare */
+uint32_t HELPER(ceb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
 {
-    float64 v1 = env->fregs[f1].d;
-    float64 v2 = env->fregs[f2].d;
-
-    HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __func__,
-               v1, f1, v2);
-    return set_cc_f64(env, v1, v2);
-}
-
-/* 128-bit FP compare RR */
-uint32_t HELPER(cxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
-{
-    CPU_QuadU v1;
-    CPU_QuadU v2;
-
-    v1.ll.upper = env->fregs[f1].ll;
-    v1.ll.lower = env->fregs[f1 + 2].ll;
-    v2.ll.upper = env->fregs[f2].ll;
-    v2.ll.lower = env->fregs[f2 + 2].ll;
-
-    return float_comp_to_cc(env, float128_compare_quiet(v1.q, v2.q,
-                                                   &env->fpu_status));
+    int cmp = float32_compare_quiet(f1, f2, &env->fpu_status);
+    handle_exceptions(env, GETPC());
+    return float_comp_to_cc(env, cmp);
 }
 
-/* 64-bit FP compare RM */
-uint32_t HELPER(cdb)(CPUS390XState *env, uint32_t f1, uint64_t a2)
+/* 64-bit FP compare */
+uint32_t HELPER(cdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
 {
-    float64 v1 = env->fregs[f1].d;
-    CPU_DoubleU v2;
-
-    v2.ll = cpu_ldq_data(env, a2);
-    HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __func__, v1,
-               f1, v2.d);
-    return set_cc_f64(env, v1, v2.d);
+    int cmp = float64_compare_quiet(f1, f2, &env->fpu_status);
+    handle_exceptions(env, GETPC());
+    return float_comp_to_cc(env, cmp);
 }
 
-/* 64-bit FP addition RM */
-uint32_t HELPER(adb)(CPUS390XState *env, uint32_t f1, uint64_t a2)
+/* 128-bit FP compare */
+uint32_t HELPER(cxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
+                     uint64_t bh, uint64_t bl)
 {
-    float64 v1 = env->fregs[f1].d;
-    CPU_DoubleU v2;
-
-    v2.ll = cpu_ldq_data(env, a2);
-    HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __func__,
-               v1, f1, v2.d);
-    env->fregs[f1].d = v1 = float64_add(v1, v2.d, &env->fpu_status);
-    return set_cc_nz_f64(v1);
+    int cmp = float128_compare_quiet(make_float128(ah, al),
+                                     make_float128(bh, bl),
+                                     &env->fpu_status);
+    handle_exceptions(env, GETPC());
+    return float_comp_to_cc(env, cmp);
 }
 
 /* 32-bit FP subtraction RM */
@@ -672,23 +637,6 @@  uint32_t HELPER(sxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
     return set_cc_nz_f128(res.q);
 }
 
-/* 128-bit FP addition RR */
-uint32_t HELPER(axbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
-{
-    CPU_QuadU v1;
-    CPU_QuadU v2;
-    CPU_QuadU res;
-
-    v1.ll.upper = env->fregs[f1].ll;
-    v1.ll.lower = env->fregs[f1 + 2].ll;
-    v2.ll.upper = env->fregs[f2].ll;
-    v2.ll.lower = env->fregs[f2 + 2].ll;
-    res.q = float128_add(v1.q, v2.q, &env->fpu_status);
-    env->fregs[f1].ll = res.ll.upper;
-    env->fregs[f1 + 2].ll = res.ll.lower;
-    return set_cc_nz_f128(res.q);
-}
-
 /* 32-bit FP multiplication RR */
 void HELPER(meebr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
 {
@@ -747,28 +695,6 @@  void HELPER(maebr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2)
                                          &env->fpu_status);
 }
 
-/* convert 32-bit float to 64-bit float */
-void HELPER(ldeb)(CPUS390XState *env, uint32_t f1, uint64_t a2)
-{
-    uint32_t v2;
-
-    v2 = cpu_ldl_data(env, a2);
-    env->fregs[f1].d = float32_to_float64(v2,
-                                          &env->fpu_status);
-}
-
-/* convert 64-bit float to 128-bit float */
-void HELPER(lxdb)(CPUS390XState *env, uint32_t f1, uint64_t a2)
-{
-    CPU_DoubleU v2;
-    CPU_QuadU v1;
-
-    v2.ll = cpu_ldq_data(env, a2);
-    v1.q = float64_to_float128(v2.d, &env->fpu_status);
-    env->fregs[f1].ll = v1.ll.upper;
-    env->fregs[f1 + 2].ll = v1.ll.lower;
-}
-
 /* test data class 32-bit */
 uint32_t HELPER(tceb)(CPUS390XState *env, uint32_t f1, uint64_t m2)
 {
diff --git a/target-s390x/helper.h b/target-s390x/helper.h
index c33c844..a2ef6af 100644
--- a/target-s390x/helper.h
+++ b/target-s390x/helper.h
@@ -36,40 +36,36 @@  DEF_HELPER_3(cxfbr, void, env, i32, s32)
 DEF_HELPER_3(cegbr, void, env, i32, s64)
 DEF_HELPER_3(cdgbr, void, env, i32, s64)
 DEF_HELPER_3(cxgbr, void, env, i32, s64)
-DEF_HELPER_3(adbr, i32, env, i32, i32)
-DEF_HELPER_3(aebr, i32, env, i32, i32)
+DEF_HELPER_3(aeb, i64, env, i64, i64)
+DEF_HELPER_3(adb, i64, env, i64, i64)
+DEF_HELPER_5(axb, i64, env, i64, i64, i64, i64)
 DEF_HELPER_3(sebr, i32, env, i32, i32)
 DEF_HELPER_3(sdbr, i32, env, i32, i32)
 DEF_HELPER_3(debr, void, env, i32, i32)
 DEF_HELPER_3(dxbr, void, env, i32, i32)
 DEF_HELPER_3(mdbr, void, env, i32, i32)
 DEF_HELPER_3(mxbr, void, env, i32, i32)
-DEF_HELPER_3(ldebr, void, env, i32, i32)
-DEF_HELPER_3(ldxbr, void, env, i32, i32)
-DEF_HELPER_3(lxdbr, void, env, i32, i32)
-DEF_HELPER_3(ledbr, void, env, i32, i32)
-DEF_HELPER_3(lexbr, void, env, i32, i32)
+DEF_HELPER_2(ldeb, i64, env, i64)
+DEF_HELPER_3(ldxb, i64, env, i64, i64)
+DEF_HELPER_2(lxdb, i64, env, i64)
+DEF_HELPER_2(lxeb, i64, env, i64)
+DEF_HELPER_2(ledb, i64, env, i64)
+DEF_HELPER_3(lexb, i64, env, i64, i64)
 DEF_HELPER_3(lpebr, i32, env, i32, i32)
 DEF_HELPER_3(lpdbr, i32, env, i32, i32)
 DEF_HELPER_3(lpxbr, i32, env, i32, i32)
-DEF_HELPER_3(ltebr, i32, env, i32, i32)
-DEF_HELPER_3(ltdbr, i32, env, i32, i32)
-DEF_HELPER_3(ltxbr, i32, env, i32, i32)
 DEF_HELPER_3(lcebr, i32, env, i32, i32)
 DEF_HELPER_3(lcdbr, i32, env, i32, i32)
 DEF_HELPER_3(lcxbr, i32, env, i32, i32)
-DEF_HELPER_3(aeb, void, env, i32, i32)
 DEF_HELPER_3(deb, void, env, i32, i32)
 DEF_HELPER_3(meeb, void, env, i32, i32)
-DEF_HELPER_3(cdb, i32, env, i32, i64)
-DEF_HELPER_3(adb, i32, env, i32, i64)
 DEF_HELPER_3(seb, void, env, i32, i32)
 DEF_HELPER_3(sdb, i32, env, i32, i64)
 DEF_HELPER_3(mdb, void, env, i32, i64)
 DEF_HELPER_3(ddb, void, env, i32, i64)
-DEF_HELPER_FLAGS_3(cebr, TCG_CALL_PURE, i32, env, i32, i32)
-DEF_HELPER_FLAGS_3(cdbr, TCG_CALL_PURE, i32, env, i32, i32)
-DEF_HELPER_FLAGS_3(cxbr, TCG_CALL_PURE, i32, env, i32, i32)
+DEF_HELPER_FLAGS_3(ceb, TCG_CALL_PURE, i32, env, i64, i64)
+DEF_HELPER_FLAGS_3(cdb, TCG_CALL_PURE, i32, env, i64, i64)
+DEF_HELPER_FLAGS_5(cxb, TCG_CALL_PURE, i32, env, i64, i64, i64, i64)
 DEF_HELPER_4(cgebr, i32, env, i32, i32, i32)
 DEF_HELPER_4(cgdbr, i32, env, i32, i32, i32)
 DEF_HELPER_4(cgxbr, i32, env, i32, i32, i32)
@@ -79,7 +75,6 @@  DEF_HELPER_2(lzxr, void, env, i32)
 DEF_HELPER_4(cfebr, i32, env, i32, i32, i32)
 DEF_HELPER_4(cfdbr, i32, env, i32, i32, i32)
 DEF_HELPER_4(cfxbr, i32, env, i32, i32, i32)
-DEF_HELPER_3(axbr, i32, env, i32, i32)
 DEF_HELPER_3(sxbr, i32, env, i32, i32)
 DEF_HELPER_3(meebr, void, env, i32, i32)
 DEF_HELPER_3(ddbr, void, env, i32, i32)
@@ -87,8 +82,6 @@  DEF_HELPER_4(madb, void, env, i32, i64, i32)
 DEF_HELPER_4(maebr, void, env, i32, i32, i32)
 DEF_HELPER_4(madbr, void, env, i32, i32, i32)
 DEF_HELPER_4(msdbr, void, env, i32, i32, i32)
-DEF_HELPER_3(ldeb, void, env, i32, i64)
-DEF_HELPER_3(lxdb, void, env, i32, i64)
 DEF_HELPER_FLAGS_3(tceb, TCG_CALL_PURE, i32, env, i32, i64)
 DEF_HELPER_FLAGS_3(tcdb, TCG_CALL_PURE, i32, env, i32, i64)
 DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_PURE, i32, env, i32, i64)
diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def
index 8914d34..f1c37e8 100644
--- a/target-s390x/insn-data.def
+++ b/target-s390x/insn-data.def
@@ -8,6 +8,11 @@ 
     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)
+    C(0xb30a, AEBR,    RRE,   Z,   e1, e2, new, e1, aeb, f32)
+    C(0xb31a, ADBR,    RRE,   Z,   f1_o, f2_o, f1, 0, adb, f64)
+    C(0xb34a, AXBR,    RRE,   Z,   0, x2_o, x1, 0, axb, f128)
+    C(0xed0a, AEB,     RXE,   Z,   e1, m2_32u, new, e1, aeb, f32)
+    C(0xed1a, ADB,     RXE,   Z,   f1_o, m2_64, f1, 0, adb, f64)
 /* ADD IMMEDIATE */
     C(0xc209, AFI,     RIL_a, EI,  r1, i2, new, r1_32, add, adds32)
     C(0xeb6a, ASI,     SIY,   GIE, m1_32s, i2, new, m1_32, add, adds32)
@@ -94,6 +99,11 @@ 
     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)
+    C(0xb309, CEBR,    RRE,   Z,   e1, e2, 0, 0, ceb, 0)
+    C(0xb319, CDBR,    RRE,   Z,   f1_o, f2_o, 0, 0, cdb, 0)
+    C(0xb349, CXBR,    RRE,   Z,   x1_o, x2_o, 0, 0, cxb, 0)
+    C(0xed09, CEB,     RXE,   Z,   e1, m2_32u, 0, 0, ceb, 0)
+    C(0xed19, CDB,     RXE,   Z,   f1_o, m2_64, 0, 0, cdb, 0)
 /* 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)
@@ -239,6 +249,9 @@ 
     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)
+    C(0xb302, LTEBR,   RRE,   Z,   0, e2, 0, cond_e1e2, mov2, f32)
+    C(0xb312, LTDBR,   RRE,   Z,   0, f2_o, 0, f1, mov2, f64)
+    C(0xb342, LTXBR,   RRE,   Z,   0, x2_o, 0, x1, movx, f128)
 /* 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)
@@ -303,6 +316,18 @@ 
     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 LENGTHENED */
+    C(0xb304, LDEBR,   RRE,   Z,   0, e2, f1, 0, ldeb, 0)
+    C(0xb305, LXDBR,   RRE,   Z,   0, f2_o, x1, 0, lxdb, 0)
+    C(0xb306, LXEBR,   RRE,   Z,   0, e2, x1, 0, lxeb, 0)
+    C(0xed04, LDEB,    RXE,   Z,   0, m2_32u, f1, 0, ldeb, 0)
+    C(0xed05, LXDB,    RXE,   Z,   0, m2_64, x1, 0, lxdb, 0)
+    C(0xed06, LXEB,    RXE,   Z,   0, m2_32u, x1, 0, lxeb, 0)
+/* LOAD ROUNDED */
+    C(0xb344, LEDBR,   RRE,   Z,   0, f2_o, new, e1, ledb, 0)
+    C(0xb345, LDXBR,   RRE,   Z,   0, x2_o, f1, 0, ldxb, 0)
+    C(0xb346, LEXBR,   RRE,   Z,   0, x2_o, new, e1, lexb, 0)
+
 /* 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)
diff --git a/target-s390x/translate.c b/target-s390x/translate.c
index 739d665..b37c140 100644
--- a/target-s390x/translate.c
+++ b/target-s390x/translate.c
@@ -556,14 +556,6 @@  static inline void set_cc_s64(DisasContext *s, TCGv_i64 val)
     gen_op_update1_cc_i64(s, CC_OP_LTGT0_64, val);
 }
 
-static void set_cc_cmp_f32_i64(DisasContext *s, TCGv_i32 v1, TCGv_i64 v2)
-{
-    tcg_gen_extu_i32_i64(cc_src, v1);
-    tcg_gen_mov_i64(cc_dst, v2);
-    tcg_gen_discard_i64(cc_vr);
-    s->cc_op = CC_OP_LTGT_F32;
-}
-
 static void gen_set_cc_nz_f32(DisasContext *s, TCGv_i32 v1)
 {
     gen_op_update1_cc_i32(s, CC_OP_NZ_F32, v1);
@@ -628,10 +620,9 @@  static void gen_op_calc_cc(DisasContext *s)
     case CC_OP_LTUGTU_64:
     case CC_OP_TM_32:
     case CC_OP_TM_64:
-    case CC_OP_LTGT_F32:
-    case CC_OP_LTGT_F64:
     case CC_OP_SLA_32:
     case CC_OP_SLA_64:
+    case CC_OP_NZ_F128:
         /* 2 arguments */
         gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, dummy);
         break;
@@ -1009,35 +1000,6 @@  static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1,
     addr = get_address(s, x2, b2, d2);
     tmp_r1 = tcg_const_i32(r1);
     switch (op) {
-    case 0x4: /* LDEB R1,D2(X2,B2) [RXE] */
-        potential_page_fault(s);
-        gen_helper_ldeb(cpu_env, tmp_r1, addr);
-        break;
-    case 0x5: /* LXDB R1,D2(X2,B2) [RXE] */
-        potential_page_fault(s);
-        gen_helper_lxdb(cpu_env, tmp_r1, addr);
-        break;
-    case 0x9: /* CEB    R1,D2(X2,B2)       [RXE] */
-        tmp = tcg_temp_new_i64();
-        tmp32 = load_freg32(r1);
-        tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s));
-        set_cc_cmp_f32_i64(s, tmp32, tmp);
-        tcg_temp_free_i64(tmp);
-        tcg_temp_free_i32(tmp32);
-        break;
-    case 0xa: /* AEB    R1,D2(X2,B2)       [RXE] */
-        tmp = tcg_temp_new_i64();
-        tmp32 = tcg_temp_new_i32();
-        tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s));
-        tcg_gen_trunc_i64_i32(tmp32, tmp);
-        gen_helper_aeb(cpu_env, tmp_r1, tmp32);
-        tcg_temp_free_i64(tmp);
-        tcg_temp_free_i32(tmp32);
-
-        tmp32 = load_freg32(r1);
-        gen_set_cc_nz_f32(s, tmp32);
-        tcg_temp_free_i32(tmp32);
-        break;
     case 0xb: /* SEB    R1,D2(X2,B2)       [RXE] */
         tmp = tcg_temp_new_i64();
         tmp32 = tcg_temp_new_i32();
@@ -1084,16 +1046,6 @@  static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1,
         tcg_temp_free_i64(tmp);
         tcg_temp_free_i32(tmp32);
         break;
-    case 0x19: /* CDB    R1,D2(X2,B2)       [RXE] */
-        potential_page_fault(s);
-        gen_helper_cdb(cc_op, cpu_env, tmp_r1, addr);
-        set_cc_static(s);
-        break;
-    case 0x1a: /* ADB    R1,D2(X2,B2)       [RXE] */
-        potential_page_fault(s);
-        gen_helper_adb(cc_op, cpu_env, tmp_r1, addr);
-        set_cc_static(s);
-        break;
     case 0x1b: /* SDB    R1,D2(X2,B2)       [RXE] */
         potential_page_fault(s);
         gen_helper_sdb(cc_op, cpu_env, tmp_r1, addr);
@@ -1524,24 +1476,9 @@  static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3,
     case 0x0: /* LPEBR       R1,R2             [RRE] */
         FP_HELPER_CC(lpebr);
         break;
-    case 0x2: /* LTEBR       R1,R2             [RRE] */
-        FP_HELPER_CC(ltebr);
-        break;
     case 0x3: /* LCEBR       R1,R2             [RRE] */
         FP_HELPER_CC(lcebr);
         break;
-    case 0x4: /* LDEBR       R1,R2             [RRE] */
-        FP_HELPER(ldebr);
-        break;
-    case 0x5: /* LXDBR       R1,R2             [RRE] */
-        FP_HELPER(lxdbr);
-        break;
-    case 0x9: /* CEBR        R1,R2             [RRE] */
-        FP_HELPER_CC(cebr);
-        break;
-    case 0xa: /* AEBR        R1,R2             [RRE] */
-        FP_HELPER_CC(aebr);
-        break;
     case 0xb: /* SEBR        R1,R2             [RRE] */
         FP_HELPER_CC(sebr);
         break;
@@ -1551,9 +1488,6 @@  static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3,
     case 0x10: /* LPDBR       R1,R2             [RRE] */
         FP_HELPER_CC(lpdbr);
         break;
-    case 0x12: /* LTDBR       R1,R2             [RRE] */
-        FP_HELPER_CC(ltdbr);
-        break;
     case 0x13: /* LCDBR       R1,R2             [RRE] */
         FP_HELPER_CC(lcdbr);
         break;
@@ -1563,12 +1497,6 @@  static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3,
     case 0x17: /* MEEBR       R1,R2             [RRE] */
         FP_HELPER(meebr);
         break;
-    case 0x19: /* CDBR        R1,R2             [RRE] */
-        FP_HELPER_CC(cdbr);
-        break;
-    case 0x1a: /* ADBR        R1,R2             [RRE] */
-        FP_HELPER_CC(adbr);
-        break;
     case 0x1b: /* SDBR        R1,R2             [RRE] */
         FP_HELPER_CC(sdbr);
         break;
@@ -1605,27 +1533,9 @@  static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3,
     case 0x40: /* LPXBR       R1,R2             [RRE] */
         FP_HELPER_CC(lpxbr);
         break;
-    case 0x42: /* LTXBR       R1,R2             [RRE] */
-        FP_HELPER_CC(ltxbr);
-        break;
     case 0x43: /* LCXBR       R1,R2             [RRE] */
         FP_HELPER_CC(lcxbr);
         break;
-    case 0x44: /* LEDBR       R1,R2             [RRE] */
-        FP_HELPER(ledbr);
-        break;
-    case 0x45: /* LDXBR       R1,R2             [RRE] */
-        FP_HELPER(ldxbr);
-        break;
-    case 0x46: /* LEXBR       R1,R2             [RRE] */
-        FP_HELPER(lexbr);
-        break;
-    case 0x49: /* CXBR        R1,R2             [RRE] */
-        FP_HELPER_CC(cxbr);
-        break;
-    case 0x4a: /* AXBR        R1,R2             [RRE] */
-        FP_HELPER_CC(axbr);
-        break;
     case 0x4b: /* SXBR        R1,R2             [RRE] */
         FP_HELPER_CC(sxbr);
         break;
@@ -2260,6 +2170,25 @@  static ExitStatus op_addc(DisasContext *s, DisasOps *o)
     return NO_EXIT;
 }
 
+static ExitStatus op_aeb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_aeb(o->out, cpu_env, o->in1, o->in2);
+    return NO_EXIT;
+}
+
+static ExitStatus op_adb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_adb(o->out, cpu_env, o->in1, o->in2);
+    return NO_EXIT;
+}
+
+static ExitStatus 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 NO_EXIT;
+}
+
 static ExitStatus op_and(DisasContext *s, DisasOps *o)
 {
     tcg_gen_and_i64(o->out, o->in1, o->in2);
@@ -2354,6 +2283,27 @@  static ExitStatus op_bct64(DisasContext *s, DisasOps *o)
     return help_branch(s, &c, is_imm, imm, o->in2);
 }
 
+static ExitStatus op_ceb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_ceb(cc_op, cpu_env, o->in1, o->in2);
+    set_cc_static(s);
+    return NO_EXIT;
+}
+
+static ExitStatus op_cdb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_cdb(cc_op, cpu_env, o->in1, o->in2);
+    set_cc_static(s);
+    return NO_EXIT;
+}
+
+static ExitStatus 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 NO_EXIT;
+}
+
 static ExitStatus op_clc(DisasContext *s, DisasOps *o)
 {
     int l = get_field(s->fields, l1);
@@ -2610,6 +2560,44 @@  static ExitStatus op_insi(DisasContext *s, DisasOps *o)
     return NO_EXIT;
 }
 
+static ExitStatus op_ldeb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_ldeb(o->out, cpu_env, o->in2);
+    return NO_EXIT;
+}
+
+static ExitStatus op_ledb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_ledb(o->out, cpu_env, o->in2);
+    return NO_EXIT;
+}
+
+static ExitStatus op_ldxb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_ldxb(o->out, cpu_env, o->in1, o->in2);
+    return NO_EXIT;
+}
+
+static ExitStatus op_lexb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_lexb(o->out, cpu_env, o->in1, o->in2);
+    return NO_EXIT;
+}
+
+static ExitStatus op_lxdb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_lxdb(o->out, cpu_env, o->in2);
+    return_low128(o->out2);
+    return NO_EXIT;
+}
+
+static ExitStatus op_lxeb(DisasContext *s, DisasOps *o)
+{
+    gen_helper_lxeb(o->out, cpu_env, o->in2);
+    return_low128(o->out2);
+    return NO_EXIT;
+}
+
 static ExitStatus op_llgt(DisasContext *s, DisasOps *o)
 {
     tcg_gen_andi_i64(o->out, o->in2, 0x7fffffff);
@@ -3369,6 +3357,21 @@  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);
@@ -3482,6 +3485,21 @@  static void prep_r1_P(DisasContext *s, DisasFields *f, DisasOps *o)
     o->g_out = o->g_out2 = true;
 }
 
+static void prep_f1(DisasContext *s, DisasFields *f, DisasOps *o)
+{
+    o->out = fregs[get_field(f, r1)];
+    o->g_out = true;
+}
+
+static void prep_x1(DisasContext *s, DisasFields *f, DisasOps *o)
+{
+    /* ??? Specification exception: r1 must be < 14.  */
+    int r1 = get_field(f, r1);
+    o->out = fregs[r1];
+    o->out2 = fregs[(r1 + 2) & 15];
+    o->g_out = o->g_out2 = true;
+}
+
 /* ====================================================================== */
 /* The "Write OUTput" generators.  These generally perform some non-trivial
    copy of data to TCG globals, or to main memory.  The trivial cases are
@@ -3539,6 +3557,7 @@  static void wout_f1(DisasContext *s, DisasFields *f, DisasOps *o)
 
 static void wout_x1(DisasContext *s, DisasFields *f, DisasOps *o)
 {
+    /* ??? Specification exception: r1 must be < 14.  */
     int f1 = get_field(s->fields, r1);
     store_freg(f1, o->out);
     store_freg((f1 + 2) & 15, o->out2);
@@ -3685,6 +3704,15 @@  static void in1_f1_o(DisasContext *s, DisasFields *f, DisasOps *o)
     o->g_in1 = true;
 }
 
+static void in1_x1_o(DisasContext *s, DisasFields *f, DisasOps *o)
+{
+    /* ??? Specification exception: r1 must be < 14.  */
+    int r1 = get_field(f, r1);
+    o->out = fregs[r1];
+    o->out2 = fregs[(r1 + 2) & 15];
+    o->g_out = o->g_out2 = true;
+}
+
 static void in1_la1(DisasContext *s, DisasFields *f, DisasOps *o)
 {
     o->addr1 = get_address(s, 0, get_field(f, b1), get_field(f, d1));
@@ -3832,9 +3860,10 @@  static void in2_f2_o(DisasContext *s, DisasFields *f, DisasOps *o)
 
 static void in2_x2_o(DisasContext *s, DisasFields *f, DisasOps *o)
 {
-    int f2 = get_field(f, r2);
-    o->in1 = fregs[f2];
-    o->in2 = fregs[(f2 + 2) & 15];
+    /* ??? Specification exception: r1 must be < 14.  */
+    int r2 = get_field(f, r2);
+    o->in1 = fregs[r2];
+    o->in2 = fregs[(r2 + 2) & 15];
     o->g_in1 = o->g_in2 = true;
 }