]> git.proxmox.com Git - mirror_qemu.git/blobdiff - target-sparc/op.c
find -type f | xargs sed -i 's/[\t ]$//g' # on most files
[mirror_qemu.git] / target-sparc / op.c
index 86c45c7093cc5336a7d626d195c290b86b9776ff..834173097d318a1df0cff7dd5771119787527f79 100644 (file)
 #endif
 
 #ifdef TARGET_SPARC64
-#undef JUMP_TB
-#define JUMP_TB(opname, tbparam, n, eip)       \
-    do {                                       \
-       GOTO_TB(opname, tbparam, n);            \
-       T0 = (long)(tbparam) + (n);             \
-       env->pc = (eip) & 0xffffffff;           \
-       EXIT_TB();                              \
-    } while (0)
-
 #ifdef WORDS_BIGENDIAN
 typedef union UREG64 {
     struct { uint16_t v3, v2, v1, v0; } w;
@@ -296,7 +287,7 @@ typedef union UREG64 {
     __p.l.v1 = PARAM1;\
     __p.l.v0 = PARAM2;\
     __p.q;\
-}) 
+})
 
 void OPPROTO op_movq_T0_im64(void)
 {
@@ -422,11 +413,71 @@ void OPPROTO op_addx_T1_T0(void)
 }
 
 void OPPROTO op_addx_T1_T0_cc(void)
+{
+    target_ulong src1;
+    src1 = T0;
+    if (FLAG_SET(PSR_CARRY))
+    {
+      T0 += T1 + 1;
+      env->psr = 0;
+#ifdef TARGET_SPARC64
+      if ((T0 & 0xffffffff) <= (src1 & 0xffffffff))
+        env->psr |= PSR_CARRY;
+      env->xcc = 0;
+      if (T0 <= src1)
+        env->xcc |= PSR_CARRY;
+#else
+      if (T0 <= src1)
+        env->psr |= PSR_CARRY;
+#endif
+    }
+    else
+    {
+      T0 += T1;
+      env->psr = 0;
+#ifdef TARGET_SPARC64
+      if ((T0 & 0xffffffff) < (src1 & 0xffffffff))
+        env->psr |= PSR_CARRY;
+      env->xcc = 0;
+      if (T0 < src1)
+        env->xcc |= PSR_CARRY;
+#else
+      if (T0 < src1)
+        env->psr |= PSR_CARRY;
+#endif
+    }
+#ifdef TARGET_SPARC64
+    if (!(T0 & 0xffffffff))
+       env->psr |= PSR_ZERO;
+    if ((int32_t) T0 < 0)
+       env->psr |= PSR_NEG;
+    if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) &
+        ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
+       env->psr |= PSR_OVF;
+
+    if (!T0)
+       env->xcc |= PSR_ZERO;
+    if ((int64_t) T0 < 0)
+       env->xcc |= PSR_NEG;
+    if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1ULL << 63))
+       env->xcc |= PSR_OVF;
+#else
+    if (!T0)
+       env->psr |= PSR_ZERO;
+    if ((int32_t) T0 < 0)
+       env->psr |= PSR_NEG;
+    if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31))
+       env->psr |= PSR_OVF;
+#endif
+    FORCE_RET();
+}
+
+void OPPROTO op_tadd_T1_T0_cc(void)
 {
     target_ulong src1;
 
     src1 = T0;
-    T0 += T1 + FLAG_SET(PSR_CARRY);
+    T0 += T1;
     env->psr = 0;
 #ifdef TARGET_SPARC64
     if (!(T0 & 0xffffffff))
@@ -438,6 +489,8 @@ void OPPROTO op_addx_T1_T0_cc(void)
     if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) &
         ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
        env->psr |= PSR_OVF;
+    if ((src1 & 0x03) || (T1 & 0x03))
+       env->psr |= PSR_OVF;
 
     env->xcc = 0;
     if (!T0)
@@ -457,6 +510,54 @@ void OPPROTO op_addx_T1_T0_cc(void)
        env->psr |= PSR_CARRY;
     if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31))
        env->psr |= PSR_OVF;
+    if ((src1 & 0x03) || (T1 & 0x03))
+       env->psr |= PSR_OVF;
+#endif
+    FORCE_RET();
+}
+
+void OPPROTO op_tadd_T1_T0_ccTV(void)
+{
+    target_ulong src1;
+
+    if ((T0 & 0x03) || (T1 & 0x03))
+        raise_exception(TT_TOVF);
+
+    src1 = T0;
+    T0 += T1;
+
+#ifdef TARGET_SPARC64
+    if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) &
+        ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
+        raise_exception(TT_TOVF);
+#else
+    if ((src1 & 0x03) || (T1 & 0x03))
+        raise_exception(TT_TOVF);
+#endif
+
+    env->psr = 0;
+#ifdef TARGET_SPARC64
+    if (!(T0 & 0xffffffff))
+       env->psr |= PSR_ZERO;
+    if ((int32_t) T0 < 0)
+       env->psr |= PSR_NEG;
+    if ((T0 & 0xffffffff) < (src1 & 0xffffffff))
+       env->psr |= PSR_CARRY;
+
+    env->xcc = 0;
+    if (!T0)
+       env->xcc |= PSR_ZERO;
+    if ((int64_t) T0 < 0)
+       env->xcc |= PSR_NEG;
+    if (T0 < src1)
+       env->xcc |= PSR_CARRY;
+#else
+    if (!T0)
+       env->psr |= PSR_ZERO;
+    if ((int32_t) T0 < 0)
+       env->psr |= PSR_NEG;
+    if (T0 < src1)
+       env->psr |= PSR_CARRY;
 #endif
     FORCE_RET();
 }
@@ -478,7 +579,7 @@ void OPPROTO op_sub_T1_T0_cc(void)
        env->psr |= PSR_ZERO;
     if ((int32_t) T0 < 0)
        env->psr |= PSR_NEG;
-    if ((T0 & 0xffffffff) < (src1 & 0xffffffff))
+    if ((src1 & 0xffffffff) < (T1 & 0xffffffff))
        env->psr |= PSR_CARRY;
     if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) &
         ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
@@ -489,7 +590,7 @@ void OPPROTO op_sub_T1_T0_cc(void)
        env->xcc |= PSR_ZERO;
     if ((int64_t) T0 < 0)
        env->xcc |= PSR_NEG;
-    if (T0 < src1)
+    if (src1 < T1)
        env->xcc |= PSR_CARRY;
     if (((src1 ^ T1) & (src1 ^ T0)) & (1ULL << 63))
        env->xcc |= PSR_OVF;
@@ -512,29 +613,91 @@ void OPPROTO op_subx_T1_T0(void)
 }
 
 void OPPROTO op_subx_T1_T0_cc(void)
+{
+    target_ulong src1;
+    src1 = T0;
+    if (FLAG_SET(PSR_CARRY))
+    {
+      T0 -= T1 + 1;
+      env->psr = 0;
+#ifdef TARGET_SPARC64
+      if ((src1 & 0xffffffff) <= (T1 & 0xffffffff))
+        env->psr |= PSR_CARRY;
+      env->xcc = 0;
+      if (src1 <= T1)
+        env->xcc |= PSR_CARRY;
+#else
+      if (src1 <= T1)
+        env->psr |= PSR_CARRY;
+#endif
+    }
+    else
+    {
+      T0 -= T1;
+      env->psr = 0;
+#ifdef TARGET_SPARC64
+      if ((src1 & 0xffffffff) < (T1 & 0xffffffff))
+        env->psr |= PSR_CARRY;
+      env->xcc = 0;
+      if (src1 < T1)
+        env->xcc |= PSR_CARRY;
+#else
+      if (src1 < T1)
+        env->psr |= PSR_CARRY;
+#endif
+    }
+#ifdef TARGET_SPARC64
+    if (!(T0 & 0xffffffff))
+       env->psr |= PSR_ZERO;
+    if ((int32_t) T0 < 0)
+       env->psr |= PSR_NEG;
+    if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) &
+        ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
+       env->psr |= PSR_OVF;
+
+    if (!T0)
+       env->xcc |= PSR_ZERO;
+    if ((int64_t) T0 < 0)
+       env->xcc |= PSR_NEG;
+    if (((src1 ^ T1) & (src1 ^ T0)) & (1ULL << 63))
+       env->xcc |= PSR_OVF;
+#else
+    if (!T0)
+       env->psr |= PSR_ZERO;
+    if ((int32_t) T0 < 0)
+       env->psr |= PSR_NEG;
+    if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31))
+       env->psr |= PSR_OVF;
+#endif
+    FORCE_RET();
+}
+
+void OPPROTO op_tsub_T1_T0_cc(void)
 {
     target_ulong src1;
 
     src1 = T0;
-    T0 -= T1 + FLAG_SET(PSR_CARRY);
+    T0 -= T1;
     env->psr = 0;
 #ifdef TARGET_SPARC64
     if (!(T0 & 0xffffffff))
        env->psr |= PSR_ZERO;
     if ((int32_t) T0 < 0)
        env->psr |= PSR_NEG;
-    if ((T0 & 0xffffffff) < (src1 & 0xffffffff))
+    if ((src1 & 0xffffffff) < (T1 & 0xffffffff))
        env->psr |= PSR_CARRY;
     if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) &
         ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
        env->psr |= PSR_OVF;
+    if ((src1 & 0x03) || (T1 & 0x03))
+       env->psr |= PSR_OVF;
 
     env->xcc = 0;
     if (!T0)
        env->xcc |= PSR_ZERO;
     if ((int64_t) T0 < 0)
        env->xcc |= PSR_NEG;
-    if (T0 < src1)
+    if (src1 < T1)
        env->xcc |= PSR_CARRY;
     if (((src1 ^ T1) & (src1 ^ T0)) & (1ULL << 63))
        env->xcc |= PSR_OVF;
@@ -547,6 +710,54 @@ void OPPROTO op_subx_T1_T0_cc(void)
        env->psr |= PSR_CARRY;
     if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31))
        env->psr |= PSR_OVF;
+    if ((src1 & 0x03) || (T1 & 0x03))
+       env->psr |= PSR_OVF;
+#endif
+    FORCE_RET();
+}
+
+void OPPROTO op_tsub_T1_T0_ccTV(void)
+{
+    target_ulong src1;
+
+    if ((T0 & 0x03) || (T1 & 0x03))
+        raise_exception(TT_TOVF);
+
+    src1 = T0;
+    T0 -= T1;
+
+#ifdef TARGET_SPARC64
+    if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) &
+        ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
+        raise_exception(TT_TOVF);
+#else
+    if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31))
+        raise_exception(TT_TOVF);
+#endif
+
+    env->psr = 0;
+#ifdef TARGET_SPARC64
+    if (!(T0 & 0xffffffff))
+       env->psr |= PSR_ZERO;
+    if ((int32_t) T0 < 0)
+       env->psr |= PSR_NEG;
+    if ((src1 & 0xffffffff) < (T1 & 0xffffffff))
+       env->psr |= PSR_CARRY;
+
+    env->xcc = 0;
+    if (!T0)
+       env->xcc |= PSR_ZERO;
+    if ((int64_t) T0 < 0)
+       env->xcc |= PSR_NEG;
+    if (src1 < T1)
+       env->xcc |= PSR_CARRY;
+#else
+    if (!T0)
+       env->psr |= PSR_ZERO;
+    if ((int32_t) T0 < 0)
+       env->psr |= PSR_NEG;
+    if (src1 < T1)
+       env->psr |= PSR_CARRY;
 #endif
     FORCE_RET();
 }
@@ -585,7 +796,11 @@ void OPPROTO op_umul_T1_T0(void)
 {
     uint64_t res;
     res = (uint64_t) T0 * (uint64_t) T1;
+#ifdef TARGET_SPARC64
+    T0 = res;
+#else
     T0 = res & 0xffffffff;
+#endif
     env->y = res >> 32;
 }
 
@@ -593,7 +808,11 @@ void OPPROTO op_smul_T1_T0(void)
 {
     uint64_t res;
     res = (int64_t) ((int32_t) T0) * (int64_t) ((int32_t) T1);
+#ifdef TARGET_SPARC64
+    T0 = res;
+#else
     T0 = res & 0xffffffff;
+#endif
     env->y = res >> 32;
 }
 
@@ -632,6 +851,11 @@ void OPPROTO op_udiv_T1_T0(void)
 
     x0 = T0 | ((uint64_t) (env->y) << 32);
     x1 = T1;
+
+    if (x1 == 0) {
+        raise_exception(TT_DIV_ZERO);
+    }
+
     x0 = x0 / x1;
     if (x0 > 0xffffffff) {
        T0 = 0xffffffff;
@@ -650,6 +874,11 @@ void OPPROTO op_sdiv_T1_T0(void)
 
     x0 = T0 | ((int64_t) (env->y) << 32);
     x1 = T1;
+
+    if (x1 == 0) {
+        raise_exception(TT_DIV_ZERO);
+    }
+
     x0 = x0 / x1;
     if ((int32_t) x0 != x0) {
        T0 = x0 < 0? 0x80000000: 0x7fffffff;
@@ -697,12 +926,18 @@ void OPPROTO op_mulx_T1_T0(void)
 
 void OPPROTO op_udivx_T1_T0(void)
 {
+    if (T1 == 0) {
+        raise_exception(TT_DIV_ZERO);
+    }
     T0 /= T1;
     FORCE_RET();
 }
 
 void OPPROTO op_sdivx_T1_T0(void)
 {
+    if (T1 == 0) {
+        raise_exception(TT_DIV_ZERO);
+    }
     if (T0 == INT64_MIN && T1 == -1)
        T0 = INT64_MIN;
     else
@@ -736,38 +971,43 @@ void OPPROTO op_logic_T0_cc(void)
 
 void OPPROTO op_sll(void)
 {
-    T0 <<= T1;
+    T0 <<= (T1 & 0x1f);
 }
 
 #ifdef TARGET_SPARC64
+void OPPROTO op_sllx(void)
+{
+    T0 <<= (T1 & 0x3f);
+}
+
 void OPPROTO op_srl(void)
 {
-    T0 = (T0 & 0xffffffff) >> T1;
+    T0 = (T0 & 0xffffffff) >> (T1 & 0x1f);
 }
 
 void OPPROTO op_srlx(void)
 {
-    T0 >>= T1;
+    T0 >>= (T1 & 0x3f);
 }
 
 void OPPROTO op_sra(void)
 {
-    T0 = ((int32_t) (T0 & 0xffffffff)) >> T1;
+    T0 = ((int32_t) (T0 & 0xffffffff)) >> (T1 & 0x1f);
 }
 
 void OPPROTO op_srax(void)
 {
-    T0 = ((int64_t) T0) >> T1;
+    T0 = ((int64_t) T0) >> (T1 & 0x3f);
 }
 #else
 void OPPROTO op_srl(void)
 {
-    T0 >>= T1;
+    T0 >>= (T1 & 0x1f);
 }
 
 void OPPROTO op_sra(void)
 {
-    T0 = ((int32_t) T0) >> T1;
+    T0 = ((int32_t) T0) >> (T1 & 0x1f);
 }
 #endif
 
@@ -805,6 +1045,15 @@ void OPPROTO op_wrpsr(void)
     FORCE_RET();
 }
 
+void OPPROTO op_wrwim(void)
+{
+#if NWINDOWS == 32
+    env->wim = T0;
+#else
+    env->wim = T0 & ((1 << NWINDOWS) - 1);
+#endif
+}
+
 void OPPROTO op_rett(void)
 {
     helper_rett();
@@ -816,7 +1065,7 @@ void OPPROTO op_rett(void)
 void OPPROTO op_save(void)
 {
     uint32_t cwp;
-    cwp = (env->cwp - 1) & (NWINDOWS - 1); 
+    cwp = (env->cwp - 1) & (NWINDOWS - 1);
     if (env->wim & (1 << cwp)) {
         raise_exception(TT_WIN_OVF);
     }
@@ -827,7 +1076,7 @@ void OPPROTO op_save(void)
 void OPPROTO op_restore(void)
 {
     uint32_t cwp;
-    cwp = (env->cwp + 1) & (NWINDOWS - 1); 
+    cwp = (env->cwp + 1) & (NWINDOWS - 1);
     if (env->wim & (1 << cwp)) {
         raise_exception(TT_WIN_UNF);
     }
@@ -847,12 +1096,38 @@ void OPPROTO op_wrccr(void)
 
 void OPPROTO op_rdtick(void)
 {
-    T0 = 0; // XXX read cycle counter and bit 31
+    T0 = do_tick_get_count(env->tick);
 }
 
 void OPPROTO op_wrtick(void)
 {
-    // XXX write cycle counter and bit 31
+    do_tick_set_count(env->tick, T0);
+}
+
+void OPPROTO op_wrtick_cmpr(void)
+{
+    do_tick_set_limit(env->tick, T0);
+}
+
+void OPPROTO op_rdstick(void)
+{
+    T0 = do_tick_get_count(env->stick);
+}
+
+void OPPROTO op_wrstick(void)
+{
+    do_tick_set_count(env->stick, T0);
+    do_tick_set_count(env->hstick, T0);
+}
+
+void OPPROTO op_wrstick_cmpr(void)
+{
+    do_tick_set_limit(env->stick, T0);
+}
+
+void OPPROTO op_wrhstick_cmpr(void)
+{
+    do_tick_set_limit(env->hstick, T0);
 }
 
 void OPPROTO op_rdtpc(void)
@@ -902,19 +1177,19 @@ void OPPROTO op_rdpstate(void)
 
 void OPPROTO op_wrpstate(void)
 {
-    env->pstate = T0 & 0x1f;
+    do_wrpstate();
 }
 
 // CWP handling is reversed in V9, but we still use the V8 register
 // order.
 void OPPROTO op_rdcwp(void)
 {
-    T0 = NWINDOWS - 1 - env->cwp;
+    T0 = GET_CWP64(env);
 }
 
 void OPPROTO op_wrcwp(void)
 {
-    env->cwp = NWINDOWS - 1 - T0;
+    PUT_CWP64(env, T0);
 }
 
 /* XXX: use another pointer for %iN registers to avoid slow wrapping
@@ -922,9 +1197,9 @@ void OPPROTO op_wrcwp(void)
 void OPPROTO op_save(void)
 {
     uint32_t cwp;
-    cwp = (env->cwp - 1) & (NWINDOWS - 1); 
+    cwp = (env->cwp - 1) & (NWINDOWS - 1);
     if (env->cansave == 0) {
-        raise_exception(TT_SPILL | (env->otherwin != 0 ? 
+        raise_exception(TT_SPILL | (env->otherwin != 0 ?
                                    (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
                                    ((env->wstate & 0x7) << 2)));
     } else {
@@ -943,9 +1218,9 @@ void OPPROTO op_save(void)
 void OPPROTO op_restore(void)
 {
     uint32_t cwp;
-    cwp = (env->cwp + 1) & (NWINDOWS - 1); 
+    cwp = (env->cwp + 1) & (NWINDOWS - 1);
     if (env->canrestore == 0) {
-        raise_exception(TT_FILL | (env->otherwin != 0 ? 
+        raise_exception(TT_FILL | (env->otherwin != 0 ?
                                   (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
                                   ((env->wstate & 0x7) << 2)));
     } else {
@@ -978,15 +1253,6 @@ void OPPROTO op_trapcc_T0(void)
     FORCE_RET();
 }
 
-void OPPROTO op_trap_ifnofpu(void)
-{
-    if (!env->psref) {
-        env->exception_index = TT_NFPU_INSN;
-        cpu_loop_exit();
-    }
-    FORCE_RET();
-}
-
 void OPPROTO op_fpexception_im(void)
 {
     env->exception_index = TT_FP_EXCP;
@@ -1019,7 +1285,7 @@ void OPPROTO op_eval_be(void)
 void OPPROTO op_eval_ble(void)
 {
     target_ulong Z = FLAG_SET(PSR_ZERO), N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF);
-    
+   
     T2 = Z | (N ^ V);
 }
 
@@ -1107,7 +1373,7 @@ void OPPROTO op_eval_xbe(void)
 void OPPROTO op_eval_xble(void)
 {
     target_ulong Z = XFLAG_SET(PSR_ZERO), N = XFLAG_SET(PSR_NEG), V = XFLAG_SET(PSR_OVF);
-    
+   
     T2 = Z | (N ^ V);
 }
 
@@ -1201,12 +1467,12 @@ void OPPROTO op_eval_xbvc(void)
 #ifdef TARGET_SPARC64
 void OPPROTO op_eval_brz(void)
 {
-    T2 = T0;
+    T2 = (T0 == 0);
 }
 
 void OPPROTO op_eval_brnz(void)
 {
-    T2 = !T0;
+    T2 = (T0 != 0);
 }
 
 void OPPROTO op_eval_brlz(void)
@@ -1266,43 +1532,32 @@ void OPPROTO op_next_insn(void)
     env->npc = env->npc + 4;
 }
 
-void OPPROTO op_branch(void)
+void OPPROTO op_goto_tb0(void)
 {
-    env->npc = (uint32_t)PARAM3; /* XXX: optimize */
-    JUMP_TB(op_branch, PARAM1, 0, PARAM2);
+    GOTO_TB(op_goto_tb0, PARAM1, 0);
 }
 
-void OPPROTO op_branch2(void)
+void OPPROTO op_goto_tb1(void)
 {
-    if (T2) {
-        env->npc = (uint32_t)PARAM2 + 4; 
-        JUMP_TB(op_branch2, PARAM1, 0, PARAM2);
-    } else {
-        env->npc = (uint32_t)PARAM3 + 4; 
-        JUMP_TB(op_branch2, PARAM1, 1, PARAM3);
-    }
-    FORCE_RET();
+    GOTO_TB(op_goto_tb1, PARAM1, 1);
 }
 
-void OPPROTO op_branch_a(void)
+void OPPROTO op_jmp_label(void)
 {
-    if (T2) {
-       env->npc = (uint32_t)PARAM2; /* XXX: optimize */
-        JUMP_TB(op_branch_a, PARAM1, 0, PARAM3);
-    } else {
-       env->npc = (uint32_t)PARAM3 + 8; /* XXX: optimize */
-        JUMP_TB(op_branch_a, PARAM1, 1, PARAM3 + 4);
-    }
+    GOTO_LABEL_PARAM(1);
+}
+
+void OPPROTO op_jnz_T2_label(void)
+{
+    if (T2)
+        GOTO_LABEL_PARAM(1);
     FORCE_RET();
 }
 
-void OPPROTO op_generic_branch(void)
+void OPPROTO op_jz_T2_label(void)
 {
-    if (T2) {
-       env->npc = (uint32_t)PARAM1;
-    } else {
-       env->npc = (uint32_t)PARAM2;
-    }
+    if (!T2)
+        GOTO_LABEL_PARAM(1);
     FORCE_RET();
 }
 
@@ -1311,188 +1566,219 @@ void OPPROTO op_flush_T0(void)
     helper_flush(T0);
 }
 
-void OPPROTO op_fnegs(void)
+void OPPROTO op_clear_ieee_excp_and_FTT(void)
 {
-    FT0 = -FT1;
+    env->fsr &= ~(FSR_FTT_MASK | FSR_CEXC_MASK);;
 }
 
-void OPPROTO op_fabss(void)
-{
-    do_fabss();
-}
+#define F_OP(name, p) void OPPROTO op_f##name##p(void)
 
-#ifdef TARGET_SPARC64
-void OPPROTO op_fnegd(void)
-{
-    DT0 = -DT1;
-}
+#define F_BINOP(name)                                           \
+    F_OP(name, s)                                               \
+    {                                                           \
+       set_float_exception_flags(0, &env->fp_status);          \
+        FT0 = float32_ ## name (FT0, FT1, &env->fp_status);     \
+       check_ieee_exceptions();                                \
+    }                                                           \
+    F_OP(name, d)                                               \
+    {                                                           \
+       set_float_exception_flags(0, &env->fp_status);          \
+        DT0 = float64_ ## name (DT0, DT1, &env->fp_status);     \
+       check_ieee_exceptions();                                \
+    }
 
-void OPPROTO op_fabsd(void)
-{
-    do_fabsd();
-}
-#endif
+F_BINOP(add);
+F_BINOP(sub);
+F_BINOP(mul);
+F_BINOP(div);
+#undef F_BINOP
 
-void OPPROTO op_fsqrts(void)
+void OPPROTO op_fsmuld(void)
 {
-    do_fsqrts();
-}
+    set_float_exception_flags(0, &env->fp_status);
+    DT0 = float64_mul(float32_to_float64(FT0, &env->fp_status),
+                      float32_to_float64(FT1, &env->fp_status),
+                      &env->fp_status);
+    check_ieee_exceptions();
+}
+
+#define F_HELPER(name)    \
+    F_OP(name, s)         \
+    {                     \
+        do_f##name##s();  \
+    }                     \
+    F_OP(name, d)         \
+    {                     \
+        do_f##name##d();  \
+    }
 
-void OPPROTO op_fsqrtd(void)
-{
-    do_fsqrtd();
-}
+F_HELPER(sqrt);
 
-void OPPROTO op_fmuls(void)
+F_OP(neg, s)
 {
-    FT0 *= FT1;
+    FT0 = float32_chs(FT1);
 }
 
-void OPPROTO op_fmuld(void)
+F_OP(abs, s)
 {
-    DT0 *= DT1;
+    do_fabss();
 }
 
-void OPPROTO op_fsmuld(void)
-{
-    DT0 = FT0 * FT1;
-}
+F_HELPER(cmp);
+F_HELPER(cmpe);
 
-void OPPROTO op_fadds(void)
+#ifdef TARGET_SPARC64
+F_OP(neg, d)
 {
-    FT0 += FT1;
+    DT0 = float64_chs(DT1);
 }
 
-void OPPROTO op_faddd(void)
+F_OP(abs, d)
 {
-    DT0 += DT1;
+    do_fabsd();
 }
 
-void OPPROTO op_fsubs(void)
+void OPPROTO op_fcmps_fcc1(void)
 {
-    FT0 -= FT1;
+    do_fcmps_fcc1();
 }
 
-void OPPROTO op_fsubd(void)
+void OPPROTO op_fcmpd_fcc1(void)
 {
-    DT0 -= DT1;
+    do_fcmpd_fcc1();
 }
 
-void OPPROTO op_fdivs(void)
+void OPPROTO op_fcmps_fcc2(void)
 {
-    FT0 /= FT1;
+    do_fcmps_fcc2();
 }
 
-void OPPROTO op_fdivd(void)
+void OPPROTO op_fcmpd_fcc2(void)
 {
-    DT0 /= DT1;
+    do_fcmpd_fcc2();
 }
 
-void OPPROTO op_fcmps(void)
+void OPPROTO op_fcmps_fcc3(void)
 {
-    do_fcmps();
+    do_fcmps_fcc3();
 }
 
-void OPPROTO op_fcmpd(void)
+void OPPROTO op_fcmpd_fcc3(void)
 {
-    do_fcmpd();
+    do_fcmpd_fcc3();
 }
 
-#ifdef TARGET_SPARC64
-void OPPROTO op_fcmps_fcc1(void)
+void OPPROTO op_fcmpes_fcc1(void)
 {
-    do_fcmps_fcc1();
+    do_fcmpes_fcc1();
 }
 
-void OPPROTO op_fcmpd_fcc1(void)
+void OPPROTO op_fcmped_fcc1(void)
 {
-    do_fcmpd_fcc1();
+    do_fcmped_fcc1();
 }
 
-void OPPROTO op_fcmps_fcc2(void)
+void OPPROTO op_fcmpes_fcc2(void)
 {
-    do_fcmps_fcc2();
+    do_fcmpes_fcc2();
 }
 
-void OPPROTO op_fcmpd_fcc2(void)
+void OPPROTO op_fcmped_fcc2(void)
 {
-    do_fcmpd_fcc2();
+    do_fcmped_fcc2();
 }
 
-void OPPROTO op_fcmps_fcc3(void)
+void OPPROTO op_fcmpes_fcc3(void)
 {
-    do_fcmps_fcc3();
+    do_fcmpes_fcc3();
 }
 
-void OPPROTO op_fcmpd_fcc3(void)
+void OPPROTO op_fcmped_fcc3(void)
 {
-    do_fcmpd_fcc3();
+    do_fcmped_fcc3();
 }
+
 #endif
 
+/* Integer to float conversion.  */
 #ifdef USE_INT_TO_FLOAT_HELPERS
-void OPPROTO op_fitos(void)
-{
-    do_fitos();
-}
-
-void OPPROTO op_fitod(void)
-{
-    do_fitod();
-}
+F_HELPER(ito);
 #else
-void OPPROTO op_fitos(void)
+F_OP(ito, s)
 {
-    FT0 = (float) *((int32_t *)&FT1);
+    set_float_exception_flags(0, &env->fp_status);
+    FT0 = int32_to_float32(*((int32_t *)&FT1), &env->fp_status);
+    check_ieee_exceptions();
 }
 
-void OPPROTO op_fitod(void)
+F_OP(ito, d)
 {
-    DT0 = (double) *((int32_t *)&FT1);
+    set_float_exception_flags(0, &env->fp_status);
+    DT0 = int32_to_float64(*((int32_t *)&FT1), &env->fp_status);
+    check_ieee_exceptions();
 }
 
 #ifdef TARGET_SPARC64
-void OPPROTO op_fxtos(void)
+F_OP(xto, s)
 {
-    FT0 = (float) *((int64_t *)&DT1);
+    set_float_exception_flags(0, &env->fp_status);
+    FT0 = int64_to_float32(*((int64_t *)&DT1), &env->fp_status);
+    check_ieee_exceptions();
 }
 
-void OPPROTO op_fxtod(void)
+F_OP(xto, d)
 {
-    DT0 = (double) *((int64_t *)&DT1);
+    set_float_exception_flags(0, &env->fp_status);
+    DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status);
+    check_ieee_exceptions();
 }
 #endif
 #endif
+#undef F_HELPER
 
+/* floating point conversion */
 void OPPROTO op_fdtos(void)
 {
-    FT0 = (float) DT1;
+    set_float_exception_flags(0, &env->fp_status);
+    FT0 = float64_to_float32(DT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 void OPPROTO op_fstod(void)
 {
-    DT0 = (double) FT1;
+    set_float_exception_flags(0, &env->fp_status);
+    DT0 = float32_to_float64(FT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
+/* Float to integer conversion.  */
 void OPPROTO op_fstoi(void)
 {
-    *((int32_t *)&FT0) = (int32_t) FT1;
+    set_float_exception_flags(0, &env->fp_status);
+    *((int32_t *)&FT0) = float32_to_int32_round_to_zero(FT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 void OPPROTO op_fdtoi(void)
 {
-    *((int32_t *)&FT0) = (int32_t) DT1;
+    set_float_exception_flags(0, &env->fp_status);
+    *((int32_t *)&FT0) = float64_to_int32_round_to_zero(DT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 #ifdef TARGET_SPARC64
 void OPPROTO op_fstox(void)
 {
-    *((int64_t *)&DT0) = (int64_t) FT1;
+    set_float_exception_flags(0, &env->fp_status);
+    *((int64_t *)&DT0) = float32_to_int64_round_to_zero(FT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 void OPPROTO op_fdtox(void)
 {
-    *((int64_t *)&DT0) = (int64_t) DT1;
+    set_float_exception_flags(0, &env->fp_status);
+    *((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 void OPPROTO op_fmovs_cc(void)
@@ -1516,7 +1802,7 @@ void OPPROTO op_mov_cc(void)
 void OPPROTO op_flushw(void)
 {
     if (env->cansave != NWINDOWS - 2) {
-        raise_exception(TT_SPILL | (env->otherwin != 0 ? 
+        raise_exception(TT_SPILL | (env->otherwin != 0 ?
                                    (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
                                    ((env->wstate & 0x7) << 2)));
     }
@@ -1527,6 +1813,9 @@ void OPPROTO op_saved(void)
     env->cansave++;
     if (env->otherwin == 0)
        env->canrestore--;
+    else
+       env->otherwin--;
+    FORCE_RET();
 }
 
 void OPPROTO op_restored(void)
@@ -1538,6 +1827,7 @@ void OPPROTO op_restored(void)
        env->cansave--;
     else
        env->otherwin--;
+    FORCE_RET();
 }
 
 void OPPROTO op_popc(void)
@@ -1547,24 +1837,17 @@ void OPPROTO op_popc(void)
 
 void OPPROTO op_done(void)
 {
-    env->pc = env->tnpc[env->tl];
-    env->npc = env->tnpc[env->tl] + 4;
-    env->pstate = env->tstate[env->tl];
-    env->tl--;
+    do_done();
 }
 
 void OPPROTO op_retry(void)
 {
-    env->pc = env->tpc[env->tl];
-    env->npc = env->tnpc[env->tl];
-    env->pstate = env->tstate[env->tl];
-    env->tl--;
+    do_retry();
 }
 
 void OPPROTO op_sir(void)
 {
-    // XXX
-
+    T0 = 0;  // XXX
 }
 
 void OPPROTO op_ld_asi_reg()
@@ -1590,3 +1873,507 @@ void OPPROTO op_st_asi()
     helper_st_asi(PARAM1, PARAM2, PARAM3);
 }
 
+#ifdef TARGET_SPARC64
+// This function uses non-native bit order
+#define GET_FIELD(X, FROM, TO)                                  \
+    ((X) >> (63 - (TO)) & ((1ULL << ((TO) - (FROM) + 1)) - 1))
+
+// This function uses the order in the manuals, i.e. bit 0 is 2^0
+#define GET_FIELD_SP(X, FROM, TO)               \
+    GET_FIELD(X, 63 - (TO), 63 - (FROM))
+
+void OPPROTO op_array8()
+{
+    T0 = (GET_FIELD_SP(T0, 60, 63) << (17 + 2 * T1)) |
+        (GET_FIELD_SP(T0, 39, 39 + T1 - 1) << (17 + T1)) |
+        (GET_FIELD_SP(T0, 17 + T1 - 1, 17) << 17) |
+        (GET_FIELD_SP(T0, 56, 59) << 13) | (GET_FIELD_SP(T0, 35, 38) << 9) |
+        (GET_FIELD_SP(T0, 13, 16) << 5) | (((T0 >> 55) & 1) << 4) |
+        (GET_FIELD_SP(T0, 33, 34) << 2) | GET_FIELD_SP(T0, 11, 12);
+}
+
+void OPPROTO op_array16()
+{
+    T0 = ((GET_FIELD_SP(T0, 60, 63) << (17 + 2 * T1)) |
+          (GET_FIELD_SP(T0, 39, 39 + T1 - 1) << (17 + T1)) |
+          (GET_FIELD_SP(T0, 17 + T1 - 1, 17) << 17) |
+          (GET_FIELD_SP(T0, 56, 59) << 13) | (GET_FIELD_SP(T0, 35, 38) << 9) |
+          (GET_FIELD_SP(T0, 13, 16) << 5) | (((T0 >> 55) & 1) << 4) |
+          (GET_FIELD_SP(T0, 33, 34) << 2) | GET_FIELD_SP(T0, 11, 12)) << 1;
+}
+
+void OPPROTO op_array32()
+{
+    T0 = ((GET_FIELD_SP(T0, 60, 63) << (17 + 2 * T1)) |
+          (GET_FIELD_SP(T0, 39, 39 + T1 - 1) << (17 + T1)) |
+          (GET_FIELD_SP(T0, 17 + T1 - 1, 17) << 17) |
+          (GET_FIELD_SP(T0, 56, 59) << 13) | (GET_FIELD_SP(T0, 35, 38) << 9) |
+          (GET_FIELD_SP(T0, 13, 16) << 5) | (((T0 >> 55) & 1) << 4) |
+          (GET_FIELD_SP(T0, 33, 34) << 2) | GET_FIELD_SP(T0, 11, 12)) << 2;
+}
+
+void OPPROTO op_alignaddr()
+{
+    uint64_t tmp;
+
+    tmp = T0 + T1;
+    env->gsr &= ~7ULL;
+    env->gsr |= tmp & 7ULL;
+    T0 = tmp & ~7ULL;
+}
+
+void OPPROTO op_faligndata()
+{
+    uint64_t tmp;
+
+    tmp = (*((uint64_t *)&DT0)) << ((env->gsr & 7) * 8);
+    tmp |= (*((uint64_t *)&DT1)) >> (64 - (env->gsr & 7) * 8);
+    *((uint64_t *)&DT0) = tmp;
+}
+
+void OPPROTO op_movl_FT0_0(void)
+{
+    *((uint32_t *)&FT0) = 0;
+}
+
+void OPPROTO op_movl_DT0_0(void)
+{
+    *((uint64_t *)&DT0) = 0;
+}
+
+void OPPROTO op_movl_FT0_1(void)
+{
+    *((uint32_t *)&FT0) = 0xffffffff;
+}
+
+void OPPROTO op_movl_DT0_1(void)
+{
+    *((uint64_t *)&DT0) = 0xffffffffffffffffULL;
+}
+
+void OPPROTO op_fnot(void)
+{
+    *(uint64_t *)&DT0 = ~*(uint64_t *)&DT1;
+}
+
+void OPPROTO op_fnots(void)
+{
+    *(uint32_t *)&FT0 = ~*(uint32_t *)&FT1;
+}
+
+void OPPROTO op_fnor(void)
+{
+    *(uint64_t *)&DT0 = ~(*(uint64_t *)&DT0 | *(uint64_t *)&DT1);
+}
+
+void OPPROTO op_fnors(void)
+{
+    *(uint32_t *)&FT0 = ~(*(uint32_t *)&FT0 | *(uint32_t *)&FT1);
+}
+
+void OPPROTO op_for(void)
+{
+    *(uint64_t *)&DT0 |= *(uint64_t *)&DT1;
+}
+
+void OPPROTO op_fors(void)
+{
+    *(uint32_t *)&FT0 |= *(uint32_t *)&FT1;
+}
+
+void OPPROTO op_fxor(void)
+{
+    *(uint64_t *)&DT0 ^= *(uint64_t *)&DT1;
+}
+
+void OPPROTO op_fxors(void)
+{
+    *(uint32_t *)&FT0 ^= *(uint32_t *)&FT1;
+}
+
+void OPPROTO op_fand(void)
+{
+    *(uint64_t *)&DT0 &= *(uint64_t *)&DT1;
+}
+
+void OPPROTO op_fands(void)
+{
+    *(uint32_t *)&FT0 &= *(uint32_t *)&FT1;
+}
+
+void OPPROTO op_fornot(void)
+{
+    *(uint64_t *)&DT0 = *(uint64_t *)&DT0 | ~*(uint64_t *)&DT1;
+}
+
+void OPPROTO op_fornots(void)
+{
+    *(uint32_t *)&FT0 = *(uint32_t *)&FT0 | ~*(uint32_t *)&FT1;
+}
+
+void OPPROTO op_fandnot(void)
+{
+    *(uint64_t *)&DT0 = *(uint64_t *)&DT0 & ~*(uint64_t *)&DT1;
+}
+
+void OPPROTO op_fandnots(void)
+{
+    *(uint32_t *)&FT0 = *(uint32_t *)&FT0 & ~*(uint32_t *)&FT1;
+}
+
+void OPPROTO op_fnand(void)
+{
+    *(uint64_t *)&DT0 = ~(*(uint64_t *)&DT0 & *(uint64_t *)&DT1);
+}
+
+void OPPROTO op_fnands(void)
+{
+    *(uint32_t *)&FT0 = ~(*(uint32_t *)&FT0 & *(uint32_t *)&FT1);
+}
+
+void OPPROTO op_fxnor(void)
+{
+    *(uint64_t *)&DT0 ^= ~*(uint64_t *)&DT1;
+}
+
+void OPPROTO op_fxnors(void)
+{
+    *(uint32_t *)&FT0 ^= ~*(uint32_t *)&FT1;
+}
+
+#ifdef WORDS_BIGENDIAN
+#define VIS_B64(n) b[7 - (n)]
+#define VIS_W64(n) w[3 - (n)]
+#define VIS_SW64(n) sw[3 - (n)]
+#define VIS_L64(n) l[1 - (n)]
+#define VIS_B32(n) b[3 - (n)]
+#define VIS_W32(n) w[1 - (n)]
+#else
+#define VIS_B64(n) b[n]
+#define VIS_W64(n) w[n]
+#define VIS_SW64(n) sw[n]
+#define VIS_L64(n) l[n]
+#define VIS_B32(n) b[n]
+#define VIS_W32(n) w[n]
+#endif
+
+typedef union {
+    uint8_t b[8];
+    uint16_t w[4];
+    int16_t sw[4];
+    uint32_t l[2];
+    float64 d;
+} vis64;
+
+typedef union {
+    uint8_t b[4];
+    uint16_t w[2];
+    uint32_t l;
+    float32 f;
+} vis32;
+
+void OPPROTO op_fpmerge(void)
+{
+    vis64 s, d;
+
+    s.d = DT0;
+    d.d = DT1;
+
+    // Reverse calculation order to handle overlap
+    d.VIS_B64(7) = s.VIS_B64(3);
+    d.VIS_B64(6) = d.VIS_B64(3);
+    d.VIS_B64(5) = s.VIS_B64(2);
+    d.VIS_B64(4) = d.VIS_B64(2);
+    d.VIS_B64(3) = s.VIS_B64(1);
+    d.VIS_B64(2) = d.VIS_B64(1);
+    d.VIS_B64(1) = s.VIS_B64(0);
+    //d.VIS_B64(0) = d.VIS_B64(0);
+
+    DT0 = d.d;
+}
+
+void OPPROTO op_fmul8x16(void)
+{
+    vis64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                 \
+    tmp = (int32_t)d.VIS_SW64(r) * (int32_t)s.VIS_B64(r);       \
+    if ((tmp & 0xff) > 0x7f)                                    \
+        tmp += 0x100;                                           \
+    d.VIS_W64(r) = tmp >> 8;
+
+    PMUL(0);
+    PMUL(1);
+    PMUL(2);
+    PMUL(3);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void OPPROTO op_fmul8x16al(void)
+{
+    vis64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                 \
+    tmp = (int32_t)d.VIS_SW64(1) * (int32_t)s.VIS_B64(r);       \
+    if ((tmp & 0xff) > 0x7f)                                    \
+        tmp += 0x100;                                           \
+    d.VIS_W64(r) = tmp >> 8;
+
+    PMUL(0);
+    PMUL(1);
+    PMUL(2);
+    PMUL(3);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void OPPROTO op_fmul8x16au(void)
+{
+    vis64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                 \
+    tmp = (int32_t)d.VIS_SW64(0) * (int32_t)s.VIS_B64(r);       \
+    if ((tmp & 0xff) > 0x7f)                                    \
+        tmp += 0x100;                                           \
+    d.VIS_W64(r) = tmp >> 8;
+
+    PMUL(0);
+    PMUL(1);
+    PMUL(2);
+    PMUL(3);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void OPPROTO op_fmul8sux16(void)
+{
+    vis64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                         \
+    tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8);       \
+    if ((tmp & 0xff) > 0x7f)                                            \
+        tmp += 0x100;                                                   \
+    d.VIS_W64(r) = tmp >> 8;
+
+    PMUL(0);
+    PMUL(1);
+    PMUL(2);
+    PMUL(3);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void OPPROTO op_fmul8ulx16(void)
+{
+    vis64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                         \
+    tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2));        \
+    if ((tmp & 0xff) > 0x7f)                                            \
+        tmp += 0x100;                                                   \
+    d.VIS_W64(r) = tmp >> 8;
+
+    PMUL(0);
+    PMUL(1);
+    PMUL(2);
+    PMUL(3);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void OPPROTO op_fmuld8sux16(void)
+{
+    vis64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                         \
+    tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8);       \
+    if ((tmp & 0xff) > 0x7f)                                            \
+        tmp += 0x100;                                                   \
+    d.VIS_L64(r) = tmp;
+
+    // Reverse calculation order to handle overlap
+    PMUL(1);
+    PMUL(0);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void OPPROTO op_fmuld8ulx16(void)
+{
+    vis64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                         \
+    tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2));        \
+    if ((tmp & 0xff) > 0x7f)                                            \
+        tmp += 0x100;                                                   \
+    d.VIS_L64(r) = tmp;
+
+    // Reverse calculation order to handle overlap
+    PMUL(1);
+    PMUL(0);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void OPPROTO op_fexpand(void)
+{
+    vis32 s;
+    vis64 d;
+
+    s.l = (uint32_t)(*(uint64_t *)&DT0 & 0xffffffff);
+    d.d = DT1;
+    d.VIS_L64(0) = s.VIS_W32(0) << 4;
+    d.VIS_L64(1) = s.VIS_W32(1) << 4;
+    d.VIS_L64(2) = s.VIS_W32(2) << 4;
+    d.VIS_L64(3) = s.VIS_W32(3) << 4;
+
+    DT0 = d.d;
+}
+
+#define VIS_OP(name, F)                                 \
+    void OPPROTO name##16(void)                         \
+    {                                                   \
+        vis64 s, d;                                     \
+                                                        \
+        s.d = DT0;                                      \
+        d.d = DT1;                                      \
+                                                        \
+        d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0));   \
+        d.VIS_W64(1) = F(d.VIS_W64(1), s.VIS_W64(1));   \
+        d.VIS_W64(2) = F(d.VIS_W64(2), s.VIS_W64(2));   \
+        d.VIS_W64(3) = F(d.VIS_W64(3), s.VIS_W64(3));   \
+                                                        \
+        DT0 = d.d;                                      \
+    }                                                   \
+                                                        \
+    void OPPROTO name##16s(void)                        \
+    {                                                   \
+        vis32 s, d;                                     \
+                                                        \
+        s.f = FT0;                                      \
+        d.f = FT1;                                      \
+                                                        \
+        d.VIS_W32(0) = F(d.VIS_W32(0), s.VIS_W32(0));   \
+        d.VIS_W32(1) = F(d.VIS_W32(1), s.VIS_W32(1));   \
+                                                        \
+        FT0 = d.f;                                      \
+    }                                                   \
+                                                        \
+    void OPPROTO name##32(void)                         \
+    {                                                   \
+        vis64 s, d;                                     \
+                                                        \
+        s.d = DT0;                                      \
+        d.d = DT1;                                      \
+                                                        \
+        d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0));   \
+        d.VIS_L64(1) = F(d.VIS_L64(1), s.VIS_L64(1));   \
+                                                        \
+        DT0 = d.d;                                      \
+    }                                                   \
+                                                        \
+    void OPPROTO name##32s(void)                        \
+    {                                                   \
+        vis32 s, d;                                     \
+                                                        \
+        s.f = FT0;                                      \
+        d.f = FT1;                                      \
+                                                        \
+        d.l = F(d.l, s.l);                              \
+                                                        \
+        FT0 = d.f;                                      \
+    }
+
+#define FADD(a, b) ((a) + (b))
+#define FSUB(a, b) ((a) - (b))
+VIS_OP(op_fpadd, FADD)
+VIS_OP(op_fpsub, FSUB)
+
+#define VIS_CMPOP(name, F)                                        \
+    void OPPROTO name##16(void)                                   \
+    {                                                             \
+        vis64 s, d;                                               \
+                                                                  \
+        s.d = DT0;                                                \
+        d.d = DT1;                                                \
+                                                                  \
+        d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0))? 1: 0;       \
+        d.VIS_W64(0) |= F(d.VIS_W64(1), s.VIS_W64(1))? 2: 0;      \
+        d.VIS_W64(0) |= F(d.VIS_W64(2), s.VIS_W64(2))? 4: 0;      \
+        d.VIS_W64(0) |= F(d.VIS_W64(3), s.VIS_W64(3))? 8: 0;      \
+                                                                  \
+        DT0 = d.d;                                                \
+    }                                                             \
+                                                                  \
+    void OPPROTO name##32(void)                                   \
+    {                                                             \
+        vis64 s, d;                                               \
+                                                                  \
+        s.d = DT0;                                                \
+        d.d = DT1;                                                \
+                                                                  \
+        d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0))? 1: 0;       \
+        d.VIS_L64(0) |= F(d.VIS_L64(1), s.VIS_L64(1))? 2: 0;      \
+                                                                  \
+        DT0 = d.d;                                                \
+    }
+
+#define FCMPGT(a, b) ((a) > (b))
+#define FCMPEQ(a, b) ((a) == (b))
+#define FCMPLE(a, b) ((a) <= (b))
+#define FCMPNE(a, b) ((a) != (b))
+
+VIS_CMPOP(op_fcmpgt, FCMPGT)
+VIS_CMPOP(op_fcmpeq, FCMPEQ)
+VIS_CMPOP(op_fcmple, FCMPLE)
+VIS_CMPOP(op_fcmpne, FCMPNE)
+
+#endif
+
+#define CHECK_ALIGN_OP(align)                           \
+    void OPPROTO op_check_align_T0_ ## align (void)     \
+    {                                                   \
+        if (T0 & align)                                 \
+            raise_exception(TT_UNALIGNED);              \
+        FORCE_RET();                                    \
+    }
+
+CHECK_ALIGN_OP(1)
+CHECK_ALIGN_OP(3)
+CHECK_ALIGN_OP(7)