diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c
index 880e3b2..99c7d57 100644
--- a/target-s390x/cc_helper.c
+++ b/target-s390x/cc_helper.c
@@ -20,6 +20,7 @@
 
 #include "cpu.h"
 #include "helper.h"
+#include "host-utils.h"
 
 /* #define DEBUG_HELPER */
 #ifdef DEBUG_HELPER
@@ -86,13 +87,11 @@ static inline uint32_t cc_calc_ltugtu_64(CPUS390XState *env, uint64_t src,
     }
 }
 
-static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val,
-                                     uint32_t mask)
+static uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, uint32_t mask)
 {
-    uint16_t r = val & mask;
+    uint32_t r = val & mask;
 
-    HELPER_LOG("%s: val 0x%x mask 0x%x\n", __func__, val, mask);
-    if (r == 0 || mask == 0) {
+    if (r == 0) {
         return 0;
     } else if (r == mask) {
         return 3;
@@ -101,23 +100,17 @@ static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val,
     }
 }
 
-/* set condition code for test under mask */
-static inline uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val,
-                                     uint32_t mask)
+static uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val, uint64_t mask)
 {
-    uint16_t r = val & mask;
+    uint64_t r = val & mask;
 
-    HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __func__, val, mask, r);
-    if (r == 0 || mask == 0) {
+    if (r == 0) {
         return 0;
     } else if (r == mask) {
         return 3;
     } else {
-        while (!(mask & 0x8000)) {
-            mask <<= 1;
-            val <<= 1;
-        }
-        if (val & 0x8000) {
+        int top = clz64(mask);
+        if ((int64_t)(val << top) < 0) {
             return 2;
         } else {
             return 1;
diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def
index 6785bc2..845d22c 100644
--- a/target-s390x/insn-data.def
+++ b/target-s390x/insn-data.def
@@ -336,3 +336,11 @@
     C(0xb989, SLBGR,   RRE,   Z,   r1, r2, r1, 0, subb, subb64)
     C(0xe399, SLB,     RXY_a, Z,   r1, m2_32u, new, r1_32, subb, subb32)
     C(0xe389, SLBG,    RXY_a, Z,   r1, m2_64, r1, 0, subb, subb64)
+
+/* 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)
diff --git a/target-s390x/translate.c b/target-s390x/translate.c
index 42f8ce8..34513d5 100644
--- a/target-s390x/translate.c
+++ b/target-s390x/translate.c
@@ -1510,16 +1510,6 @@ do_mh:
         tcg_temp_free_i32(tmp32_1);
         tcg_temp_free_i32(tmp32_2);
         break;
-    case 0x51: /* TMY D1(B1),I2 [SIY] */
-        tmp = get_address(s, 0, b2, d2); /* SIY -> this is the destination */
-        tmp2 = tcg_const_i64((r1 << 4) | r3);
-        tcg_gen_qemu_ld8u(tmp, tmp, get_mem_index(s));
-        /* yes, this is a 32 bit operation with 64 bit tcg registers, because
-           that incurs less conversions */
-        cmp_64(s, tmp, tmp2, CC_OP_TM_32);
-        tcg_temp_free_i64(tmp);
-        tcg_temp_free_i64(tmp2);
-        break;
     case 0x52: /* MVIY D1(B1),I2 [SIY] */
         tmp = get_address(s, 0, b2, d2); /* SIY -> this is the destination */
         tmp2 = tcg_const_i64((r1 << 4) | r3);
@@ -1668,43 +1658,6 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2,
     tcg_temp_free_i64(addr);
 }
 
-static void disas_a7(DisasContext *s, int op, int r1, int i2)
-{
-    TCGv_i64 tmp, tmp2;
-
-    LOG_DISAS("disas_a7: op 0x%x r1 %d i2 0x%x\n", op, r1, i2);
-    switch (op) {
-    case 0x0: /* TMLH or TMH     R1,I2     [RI] */
-    case 0x1: /* TMLL or TML     R1,I2     [RI] */
-    case 0x2: /* TMHH     R1,I2     [RI] */
-    case 0x3: /* TMHL     R1,I2     [RI] */
-        tmp = load_reg(r1);
-        tmp2 = tcg_const_i64((uint16_t)i2);
-        switch (op) {
-        case 0x0:
-            tcg_gen_shri_i64(tmp, tmp, 16);
-            break;
-        case 0x1:
-            break;
-        case 0x2:
-            tcg_gen_shri_i64(tmp, tmp, 48);
-            break;
-        case 0x3:
-            tcg_gen_shri_i64(tmp, tmp, 32);
-            break;
-        }
-        tcg_gen_andi_i64(tmp, tmp, 0xffff);
-        cmp_64(s, tmp, tmp2, CC_OP_TM_64);
-        tcg_temp_free_i64(tmp);
-        tcg_temp_free_i64(tmp2);
-        break;
-    default:
-        LOG_DISAS("illegal a7 operation 0x%x\n", op);
-        gen_illegal_opcode(s);
-        return;
-    }
-}
-
 static void disas_b2(DisasContext *s, int op, uint32_t insn)
 {
     TCGv_i64 tmp, tmp2, tmp3;
@@ -2668,15 +2621,6 @@ static void disas_s390_insn(DisasContext *s)
         tcg_temp_free_i64(tmp3);
         tcg_temp_free_i64(tmp4);
         break;
-    case 0x91: /* TM     D1(B1),I2        [SI] */
-        insn = ld_code4(s->pc);
-        tmp = decode_si(s, insn, &i2, &b1, &d1);
-        tmp2 = tcg_const_i64(i2);
-        tcg_gen_qemu_ld8u(tmp, tmp, get_mem_index(s));
-        cmp_64(s, tmp, tmp2, CC_OP_TM_32);
-        tcg_temp_free_i64(tmp);
-        tcg_temp_free_i64(tmp2);
-        break;
     case 0x92: /* MVI    D1(B1),I2        [SI] */
         insn = ld_code4(s->pc);
         tmp = decode_si(s, insn, &i2, &b1, &d1);
@@ -2734,13 +2678,6 @@ static void disas_s390_insn(DisasContext *s)
         tcg_temp_free_i32(tmp32_1);
         tcg_temp_free_i32(tmp32_2);
         break;
-    case 0xa7:
-        insn = ld_code4(s->pc);
-        r1 = (insn >> 20) & 0xf;
-        op = (insn >> 16) & 0xf;
-        i2 = (short)insn;
-        disas_a7(s, op, r1, i2);
-        break;
     case 0xa8: /* MVCLE   R1,R3,D2(B2)     [RS] */
         insn = ld_code4(s->pc);
         decode_rs(s, insn, &r1, &r3, &b2, &d2);
@@ -3891,6 +3828,16 @@ static void cout_subb64(DisasContext *s, DisasOps *o)
     gen_op_update3_cc_i64(s, CC_OP_SUBB_64, o->in1, o->in2, 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);
+}
+
 /* ====================================================================== */
 /* The "PREPeration" generators.  These initialize the DisasOps.OUT fields
    with the TCG register to which we will write.  Used in combination with
