PowerPC merge (Jocelyn Mayer)
[qemu] / target-ppc / op.c
index ecb9917..98d7885 100644 (file)
 #include "config.h"
 #include "exec.h"
 
+//#define DEBUG_OP
+
 #define regs (env)
-extern uint32_t __a;
-extern uint32_t __b;
-extern uint32_t __c;
-extern uint32_t __d;
-extern uint32_t __e;
-extern uint32_t __f;
 #define Ts0 (int32_t)T0
 #define Ts1 (int32_t)T1
 #define Ts2 (int32_t)T2
 
-#include "op-multi.c"
+#define FT0 (env->ft0)
+#define FT1 (env->ft1)
+#define FT2 (env->ft2)
+
+#define FTS0 ((float)env->ft0)
+#define FTS1 ((float)env->ft1)
+#define FTS2 ((float)env->ft2)
+
+#define PPC_OP(name) void glue(op_, name)(void)
+
+#define REG 0
+#include "op_template.h"
+
+#define REG 1
+#include "op_template.h"
+
+#define REG 2
+#include "op_template.h"
+
+#define REG 3
+#include "op_template.h"
+
+#define REG 4
+#include "op_template.h"
+
+#define REG 5
+#include "op_template.h"
+
+#define REG 6
+#include "op_template.h"
+
+#define REG 7
+#include "op_template.h"
+
+#define REG 8
+#include "op_template.h"
+
+#define REG 9
+#include "op_template.h"
+
+#define REG 10
+#include "op_template.h"
+
+#define REG 11
+#include "op_template.h"
+
+#define REG 12
+#include "op_template.h"
+
+#define REG 13
+#include "op_template.h"
+
+#define REG 14
+#include "op_template.h"
+
+#define REG 15
+#include "op_template.h"
+
+#define REG 16
+#include "op_template.h"
+
+#define REG 17
+#include "op_template.h"
+
+#define REG 18
+#include "op_template.h"
+
+#define REG 19
+#include "op_template.h"
+
+#define REG 20
+#include "op_template.h"
+
+#define REG 21
+#include "op_template.h"
+
+#define REG 22
+#include "op_template.h"
+
+#define REG 23
+#include "op_template.h"
+
+#define REG 24
+#include "op_template.h"
+
+#define REG 25
+#include "op_template.h"
+
+#define REG 26
+#include "op_template.h"
+
+#define REG 27
+#include "op_template.h"
+
+#define REG 28
+#include "op_template.h"
 
-#define PPC_OP(name) void op_##name(void)
+#define REG 29
+#include "op_template.h"
+
+#define REG 30
+#include "op_template.h"
+
+#define REG 31
+#include "op_template.h"
 
 /* PPC state maintenance operations */
 /* set_Rc0 */
@@ -49,7 +147,7 @@ PPC_OP(set_Rc0)
     } else {
         tmp = 0x02;
     }
-    set_CRn(0, tmp);
+    env->crf[0] = tmp;
     RETURN();
 }
 
@@ -65,24 +163,32 @@ PPC_OP(set_Rc0_ov)
         tmp = 0x02;
     }
     tmp |= xer_ov;
-    set_CRn(0, tmp);
+    env->crf[0] = tmp;
     RETURN();
 }
 
 /* reset_Rc0 */
 PPC_OP(reset_Rc0)
 {
-    set_CRn(0, 0x02 | xer_ov);
+    env->crf[0] = 0x02 | xer_ov;
     RETURN();
 }
 
 /* set_Rc0_1 */
 PPC_OP(set_Rc0_1)
 {
-    set_CRn(0, 0x04 | xer_ov);
+    env->crf[0] = 0x04 | xer_ov;
+    RETURN();
+}
+
+/* Set Rc1 (for floating point arithmetic) */
+PPC_OP(set_Rc1)
+{
+    env->crf[1] = regs->fpscr[7];
     RETURN();
 }
 
+/* Constants load */
 PPC_OP(set_T0)
 {
     T0 = PARAM(1);
@@ -101,23 +207,50 @@ PPC_OP(set_T2)
     RETURN();
 }
 
-/* Update time base */
-PPC_OP(update_tb)
+/* Generate exceptions */
+PPC_OP(queue_exception_err)
 {
-    T0 = regs->spr[SPR_ENCODE(268)];
-    T1 = T0;
-    T0 += PARAM(1);
-    if (T0 < T1) {
-        T1 = regs->spr[SPR_ENCODE(269)] + 1;
-        regs->spr[SPR_ENCODE(269)] = T1;
+    do_queue_exception_err(PARAM(1), PARAM(2));
+}
+
+PPC_OP(queue_exception)
+{
+    do_queue_exception(PARAM(1));
+}
+
+PPC_OP(process_exceptions)
+{
+    if (env->exceptions != 0) {
+        env->nip = PARAM(1);
+        do_check_exception_state();
     }
-    regs->spr[SPR_ENCODE(268)] = T0;
+}
+
+/* Segment registers load and store with immediate index */
+PPC_OP(load_srin)
+{
+    T0 = regs->sr[T1 >> 28];
+    RETURN();
+}
+
+PPC_OP(store_srin)
+{
+#if defined (DEBUG_OP)
+    dump_store_sr(T1 >> 28);
+#endif
+    regs->sr[T1 >> 28] = T0;
     RETURN();
 }
 
-PPC_OP(raise_exception)
+PPC_OP(load_sdr1)
 {
-    raise_exception(PARAM(1));
+    T0 = regs->sdr1;
+    RETURN();
+}
+
+PPC_OP(store_sdr1)
+{
+    regs->sdr1 = T0;
     RETURN();
 }
 
@@ -126,15 +259,16 @@ PPC_OP(exit_tb)
     EXIT_TB();
 }
 
+/* Load/store special registers */
 PPC_OP(load_cr)
 {
-    T0 = do_load_cr();
+    do_load_cr();
     RETURN();
 }
 
 PPC_OP(store_cr)
 {
-    do_store_cr(PARAM(1), T0);
+    do_store_cr(PARAM(1));
     RETURN();
 }
 
@@ -154,51 +288,168 @@ PPC_OP(clear_xer_cr)
 
 PPC_OP(load_xer_bc)
 {
-    T0 = xer_bc;
+    T1 = xer_bc;
     RETURN();
 }
 
 PPC_OP(load_xer)
 {
-    T0 = do_load_xer();
+    do_load_xer();
     RETURN();
 }
 
 PPC_OP(store_xer)
 {
-    do_store_xer(T0);
+    do_store_xer();
     RETURN();
 }
 
 PPC_OP(load_msr)
 {
-    T0 = do_load_msr();
+    do_load_msr();
     RETURN();
 }
 
 PPC_OP(store_msr)
 {
-    do_store_msr(T0);
+    do_store_msr();
+    RETURN();
+}
+
+/* SPR */
+PPC_OP(load_spr)
+{
+    T0 = regs->spr[PARAM(1)];
+    RETURN();
+}
+
+PPC_OP(store_spr)
+{
+    regs->spr[PARAM(1)] = T0;
     RETURN();
 }
 
 PPC_OP(load_lr)
 {
-    regs->LR = PARAM(1);
+    T0 = regs->lr;
+    RETURN();
+}
+
+PPC_OP(store_lr)
+{
+    regs->lr = T0;
+    RETURN();
+}
+
+PPC_OP(load_ctr)
+{
+    T0 = regs->ctr;
+    RETURN();
+}
+
+PPC_OP(store_ctr)
+{
+    regs->ctr = T0;
+    RETURN();
+}
+
+/* Update time base */
+PPC_OP(update_tb)
+{
+    T0 = regs->tb[0];
+    T1 = T0;
+    T0 += PARAM(1);
+#if defined (DEBUG_OP)
+    dump_update_tb(PARAM(1));
+#endif
+    if (T0 < T1) {
+        T1 = regs->tb[1] + 1;
+        regs->tb[1] = T1;
+    }
+    regs->tb[0] = T0;
+    RETURN();
+}
+
+PPC_OP(load_tb)
+{
+    T0 = regs->tb[PARAM(1)];
+    RETURN();
+}
+
+PPC_OP(store_tb)
+{
+    regs->tb[PARAM(1)] = T0;
+#if defined (DEBUG_OP)
+    dump_store_tb(PARAM(1));
+#endif
+    RETURN();
+}
+
+/* Update decrementer */
+PPC_OP(update_decr)
+{
+    T0 = regs->decr;
+    T1 = T0;
+    T0 -= PARAM(1);
+    regs->decr = T0;
+    if (PARAM(1) > T1) {
+        do_queue_exception(EXCP_DECR);
+    }
+    RETURN();
+}
+
+PPC_OP(store_decr)
+{
+    T1 = regs->decr;
+    regs->decr = T0;
+    if (Ts0 < 0 && Ts1 > 0) {
+        do_queue_exception(EXCP_DECR);
+    }
+    RETURN();
+}
+
+PPC_OP(load_ibat)
+{
+    T0 = regs->IBAT[PARAM(1)][PARAM(2)];
+}
+
+PPC_OP(store_ibat)
+{
+#if defined (DEBUG_OP)
+    dump_store_ibat(PARAM(1), PARAM(2));
+#endif
+    regs->IBAT[PARAM(1)][PARAM(2)] = T0;
+}
+
+PPC_OP(load_dbat)
+{
+    T0 = regs->DBAT[PARAM(1)][PARAM(2)];
+}
+
+PPC_OP(store_dbat)
+{
+#if defined (DEBUG_OP)
+    dump_store_dbat(PARAM(1), PARAM(2));
+#endif
+    regs->DBAT[PARAM(1)][PARAM(2)] = T0;
+}
+
+/* FPSCR */
+PPC_OP(load_fpscr)
+{
+    do_load_fpscr();
     RETURN();
 }
 
-/* Set reservation */
-PPC_OP(set_reservation)
+PPC_OP(store_fpscr)
 {
-    regs->reserve = T1 & ~0x03;
+    do_store_fpscr(PARAM(1));
     RETURN();
 }
 
-/* Reset reservation */
-PPC_OP(reset_reservation)
+PPC_OP(reset_scrfx)
 {
-    regs->reserve = 0;
+    regs->fpscr[7] &= ~0x8;
     RETURN();
 }
 
@@ -222,47 +473,65 @@ PPC_OP(setcrfbit)
 }
 
 /* Branch */
+#if 0
+#define EIP regs->nip
+#define TB_DO_JUMP(name, tb, n, target) JUMP_TB(name, tb, n, target)
+#else
+#define TB_DO_JUMP(name, tb, n, target) regs->nip = target;
+#endif
+
 #define __PPC_OP_B(name, target)                                              \
 PPC_OP(name)                                                                  \
 {                                                                             \
-    regs->nip = (target);                                                     \
+    TB_DO_JUMP(glue(op_, name), T1, 0, (target));                             \
     RETURN();                                                                 \
 }
 
-#define __PPC_OP_BL(name, target)                                             \
+#define __PPC_OP_BL(name, target, link)                                       \
 PPC_OP(name)                                                                  \
 {                                                                             \
-    regs->LR = PARAM(1);                                                      \
-    regs->nip = (target);                                                     \
+    regs->lr = (link);                                                        \
+    TB_DO_JUMP(glue(op_, name), T1, 0, (target));                             \
     RETURN();                                                                 \
 }
 
-#define PPC_OP_B(name, target)                                                \
+#define PPC_OP_B(name, target, link)                                          \
 __PPC_OP_B(name, target);                                                     \
-__PPC_OP_BL(name##l, target)
+__PPC_OP_BL(glue(name, l), target, link)
 
 #define __PPC_OP_BC(name, cond, target)                                       \
 PPC_OP(name)                                                                  \
 {                                                                             \
     if (cond) {                                                               \
-        T0 = (target);                                                        \
+        TB_DO_JUMP(glue(op_, name), T1, 1, (target));                         \
     } else {                                                                  \
-        T0 = PARAM(1);                                                        \
+        TB_DO_JUMP(glue(op_, name), T1, 0, PARAM(1));                         \
     }                                                                         \
-    regs->nip = T0;                                                           \
     RETURN();                                                                 \
 }
 
 #define __PPC_OP_BCL(name, cond, target)                                      \
 PPC_OP(name)                                                                  \
 {                                                                             \
+    regs->lr = PARAM(1);                                                      \
+    if (cond) {                                                               \
+        TB_DO_JUMP(glue(op_, name), T1, 1, (target));                         \
+    } else {                                                                  \
+        TB_DO_JUMP(glue(op_, name), T1, 0, PARAM(1));                         \
+    }                                                                         \
+    RETURN();                                                                 \
+}
+
+#define __PPC_OP_BCLRL(name, cond, target)                                    \
+PPC_OP(name)                                                                  \
+{                                                                             \
+    T2 = (target);                                                            \
+    regs->lr = PARAM(1);                                                      \
     if (cond) {                                                               \
-        T0 = (target);                                                        \
-        regs->LR = PARAM(1);                                                  \
+        TB_DO_JUMP(glue(op_, name), T1, 1, T2);                               \
     } else {                                                                  \
-        T0 = PARAM(1);                                                        \
+        TB_DO_JUMP(glue(op_, name), T1, 0, PARAM(1));                         \
     }                                                                         \
-    regs->nip = T0;                                                           \
     RETURN();                                                                 \
 }
 
@@ -274,48 +543,56 @@ __PPC_OP_BCL(namel, cond, target)
 #define PPC_OP_BC(name, cond)                                                 \
 _PPC_OP_BC(b_##name, bl_##name, cond, PARAM(2))
 
-PPC_OP_B(b, PARAM(1));
-PPC_OP_BC(ctr,        (regs->CTR != 0));
-PPC_OP_BC(ctr_true,   (regs->CTR != 0 && (T0 & PARAM(3)) != 0));
-PPC_OP_BC(ctr_false,  (regs->CTR != 0 && (T0 & PARAM(3)) == 0));
-PPC_OP_BC(ctrz,       (regs->CTR == 0));
-PPC_OP_BC(ctrz_true,  (regs->CTR == 0 && (T0 & PARAM(3)) != 0));
-PPC_OP_BC(ctrz_false, (regs->CTR == 0 && (T0 & PARAM(3)) == 0));
+PPC_OP_B(b, PARAM(1), PARAM(2));
+PPC_OP_BC(ctr,        (regs->ctr != 0));
+PPC_OP_BC(ctr_true,   (regs->ctr != 0 && (T0 & PARAM(3)) != 0));
+PPC_OP_BC(ctr_false,  (regs->ctr != 0 && (T0 & PARAM(3)) == 0));
+PPC_OP_BC(ctrz,       (regs->ctr == 0));
+PPC_OP_BC(ctrz_true,  (regs->ctr == 0 && (T0 & PARAM(3)) != 0));
+PPC_OP_BC(ctrz_false, (regs->ctr == 0 && (T0 & PARAM(3)) == 0));
 PPC_OP_BC(true,       ((T0 & PARAM(3)) != 0));
 PPC_OP_BC(false,      ((T0 & PARAM(3)) == 0));
 
 /* Branch to CTR */
 #define PPC_OP_BCCTR(name, cond)                                              \
-_PPC_OP_BC(bctr_##name, bctrl_##name, cond, regs->CTR & ~0x03)
-
-PPC_OP_B(bctr, regs->CTR & ~0x03);
-PPC_OP_BCCTR(ctr,        (regs->CTR != 0));
-PPC_OP_BCCTR(ctr_true,   (regs->CTR != 0 && (T0 & PARAM(2)) != 0));
-PPC_OP_BCCTR(ctr_false,  (regs->CTR != 0 && (T0 & PARAM(2)) == 0));
-PPC_OP_BCCTR(ctrz,       (regs->CTR == 0));
-PPC_OP_BCCTR(ctrz_true,  (regs->CTR == 0 && (T0 & PARAM(2)) != 0));
-PPC_OP_BCCTR(ctrz_false, (regs->CTR == 0 && (T0 & PARAM(2)) == 0));
+_PPC_OP_BC(bctr_##name, bctrl_##name, cond, regs->ctr & ~0x03)
+
+PPC_OP_B(bctr, regs->ctr & ~0x03, PARAM(1));
+PPC_OP_BCCTR(ctr,        (regs->ctr != 0));
+PPC_OP_BCCTR(ctr_true,   (regs->ctr != 0 && (T0 & PARAM(2)) != 0));
+PPC_OP_BCCTR(ctr_false,  (regs->ctr != 0 && (T0 & PARAM(2)) == 0));
+PPC_OP_BCCTR(ctrz,       (regs->ctr == 0));
+PPC_OP_BCCTR(ctrz_true,  (regs->ctr == 0 && (T0 & PARAM(2)) != 0));
+PPC_OP_BCCTR(ctrz_false, (regs->ctr == 0 && (T0 & PARAM(2)) == 0));
 PPC_OP_BCCTR(true,       ((T0 & PARAM(2)) != 0));
 PPC_OP_BCCTR(false,      ((T0 & PARAM(2)) == 0));
 
 /* Branch to LR */
 #define PPC_OP_BCLR(name, cond)                                               \
-_PPC_OP_BC(blr_##name, blrl_##name, cond, regs->LR & ~0x03)
-
-PPC_OP_B(blr, regs->LR & ~0x03);
-PPC_OP_BCLR(ctr,        (regs->CTR != 0));
-PPC_OP_BCLR(ctr_true,   (regs->CTR != 0 && (T0 & PARAM(2)) != 0));
-PPC_OP_BCLR(ctr_false,  (regs->CTR != 0 && (T0 & PARAM(2)) == 0));
-PPC_OP_BCLR(ctrz,       (regs->CTR == 0));
-PPC_OP_BCLR(ctrz_true,  (regs->CTR == 0 && (T0 & PARAM(2)) != 0));
-PPC_OP_BCLR(ctrz_false, (regs->CTR == 0 && (T0 & PARAM(2)) == 0));
+__PPC_OP_BC(blr_##name, cond, regs->lr & ~0x03);                              \
+__PPC_OP_BCLRL(blrl_##name, cond, regs->lr & ~0x03)
+
+__PPC_OP_B(blr, regs->lr & ~0x03);
+PPC_OP(blrl)
+{
+    T0 = regs->lr & ~0x03;
+    regs->lr = PARAM(1);
+    TB_DO_JUMP(op_blrl, T1, 0, T0);
+    RETURN();
+}
+PPC_OP_BCLR(ctr,        (regs->ctr != 0));
+PPC_OP_BCLR(ctr_true,   (regs->ctr != 0 && (T0 & PARAM(2)) != 0));
+PPC_OP_BCLR(ctr_false,  (regs->ctr != 0 && (T0 & PARAM(2)) == 0));
+PPC_OP_BCLR(ctrz,       (regs->ctr == 0));
+PPC_OP_BCLR(ctrz_true,  (regs->ctr == 0 && (T0 & PARAM(2)) != 0));
+PPC_OP_BCLR(ctrz_false, (regs->ctr == 0 && (T0 & PARAM(2)) == 0));
 PPC_OP_BCLR(true,       ((T0 & PARAM(2)) != 0));
 PPC_OP_BCLR(false,      ((T0 & PARAM(2)) == 0));
 
 /* CTR maintenance */
 PPC_OP(dec_ctr)
 {
-    regs->CTR--;
+    regs->ctr--;
     RETURN();
 }
 
@@ -898,7 +1175,7 @@ PPC_OP(xori)
 /* rotate left word immediate then mask insert */
 PPC_OP(rlwimi)
 {
-    T0 = rotl(T0, PARAM(1) & PARAM(2)) | (T0 & PARAM(3));
+    T0 = (rotl(T0, PARAM(1)) & PARAM(2)) | (T1 & PARAM(3));
     RETURN();
 }
 
@@ -955,7 +1232,7 @@ PPC_OP(slw)
 /* shift right algebraic word */
 PPC_OP(sraw)
 {
-    Ts0 = do_sraw(Ts0, T1);
+    do_sraw();
     RETURN();
 }
 
@@ -984,133 +1261,280 @@ PPC_OP(srw)
 }
 
 /***                       Floating-Point arithmetic                       ***/
+/* fadd - fadd. */
+PPC_OP(fadd)
+{
+    FT0 += FT1;
+    RETURN();
+}
+
+/* fadds - fadds. */
+PPC_OP(fadds)
+{
+    FTS0 += FTS1;
+    RETURN();
+}
+
+/* fsub - fsub. */
+PPC_OP(fsub)
+{
+    FT0 -= FT1;
+    RETURN();
+}
+
+/* fsubs - fsubs. */
+PPC_OP(fsubs)
+{
+    FTS0 -= FTS1;
+    RETURN();
+}
+
+/* fmul - fmul. */
+PPC_OP(fmul)
+{
+    FT0 *= FT1;
+    RETURN();
+}
+
+/* fmuls - fmuls. */
+PPC_OP(fmuls)
+{
+    FTS0 *= FTS1;
+    RETURN();
+}
+
+/* fdiv - fdiv. */
+PPC_OP(fdiv)
+{
+    FT0 /= FT1;
+    RETURN();
+}
+
+/* fdivs - fdivs. */
+PPC_OP(fdivs)
+{
+    FTS0 /= FTS1;
+    RETURN();
+}
+
+/* fsqrt - fsqrt. */
+PPC_OP(fsqrt)
+{
+    do_fsqrt();
+    RETURN();
+}
+
+/* fsqrts - fsqrts. */
+PPC_OP(fsqrts)
+{
+    do_fsqrts();
+    RETURN();
+}
+
+/* fres - fres. */
+PPC_OP(fres)
+{
+    do_fres();
+    RETURN();
+}
+
+/* frsqrte  - frsqrte. */
+PPC_OP(frsqrte)
+{
+    do_fsqrte();
+    RETURN();
+}
+
+/* fsel - fsel. */
+PPC_OP(fsel)
+{
+    do_fsel();
+    RETURN();
+}
 
 /***                     Floating-Point multiply-and-add                   ***/
+/* fmadd - fmadd. */
+PPC_OP(fmadd)
+{
+    FT0 = (FT0 * FT1) + FT2;
+    RETURN();
+}
 
-/***                     Floating-Point round & convert                    ***/
+/* fmadds - fmadds. */
+PPC_OP(fmadds)
+{
+    FTS0 = (FTS0 * FTS1) + FTS2;
+    RETURN();
+}
 
-/***                         Floating-Point compare                        ***/
+/* fmsub - fmsub. */
+PPC_OP(fmsub)
+{
+    FT0 = (FT0 * FT1) - FT2;
+    RETURN();
+}
 
-/***                  Floating-Point status & ctrl register                ***/
+/* fmsubs - fmsubs. */
+PPC_OP(fmsubs)
+{
+    FTS0 = (FTS0 * FTS1) - FTS2;
+    RETURN();
+}
 
-/***                             Integer load                              ***/
-#define ld16x(x) s_ext16(ld16(x))
-#define PPC_ILD_OPX(name, op)                                                 \
-PPC_OP(l##name##x_z)                                                          \
-{                                                                             \
-    T1 = op(T0);                                                              \
-    RETURN();                                                                 \
-}                                                                             \
-PPC_OP(l##name##x)                                                            \
-{                                                                             \
-    T0 += T1;                                                                 \
-    T1 = op(T0);                                                              \
-    RETURN();                                                                 \
+/* fnmadd - fnmadd. - fnmadds - fnmadds. */
+PPC_OP(fnmadd)
+{
+    FT0 = -((FT0 * FT1) + FT2);
+    RETURN();
 }
 
-#define PPC_ILD_OP(name, op)                                                  \
-PPC_OP(l##name##_z)                                                           \
-{                                                                             \
-    T1 = op(SPARAM(1));                                                       \
-    RETURN();                                                                 \
-}                                                                             \
-PPC_OP(l##name)                                                               \
-{                                                                             \
-    T0 += SPARAM(1);                                                          \
-    T1 = op(T0);                                                              \
-    RETURN();                                                                 \
-}                                                                             \
-PPC_ILD_OPX(name, op)
+/* fnmadds - fnmadds. */
+PPC_OP(fnmadds)
+{
+    FTS0 = -((FTS0 * FTS1) + FTS2);
+    RETURN();
+}
 
-PPC_ILD_OP(bz, ld8);
-PPC_ILD_OP(ha, ld16x);
-PPC_ILD_OP(hz, ld16);
-PPC_ILD_OP(wz, ld32);
+/* fnmsub - fnmsub. */
+PPC_OP(fnmsub)
+{
+    FT0 = -((FT0 * FT1) - FT2);
+    RETURN();
+}
 
-/***                              Integer store                            ***/
-#define PPC_IST_OPX(name, op)                                                 \
-PPC_OP(st##name##x_z)                                                         \
-{                                                                             \
-    op(T0, T1);                                                               \
-    RETURN();                                                                 \
-}                                                                             \
-PPC_OP(st##name##x)                                                           \
-{                                                                             \
-    T0 += T1;                                                                 \
-    op(T0, T2);                                                               \
-    RETURN();                                                                 \
+/* fnmsubs - fnmsubs. */
+PPC_OP(fnmsubs)
+{
+    FTS0 = -((FTS0 * FTS1) - FTS2);
+    RETURN();
 }
 
-#define PPC_IST_OP(name, op)                                                  \
-PPC_OP(st##name##_z)                                                          \
-{                                                                             \
-    op(SPARAM(1), T0);                                                        \
-    RETURN();                                                                 \
-}                                                                             \
-PPC_OP(st##name)                                                              \
-{                                                                             \
-    T0 += SPARAM(1);                                                          \
-    op(T0, T1);                                                               \
-    RETURN();                                                                 \
-}                                                                             \
-PPC_IST_OPX(name, op);
+/***                     Floating-Point round & convert                    ***/
+/* frsp - frsp. */
+PPC_OP(frsp)
+{
+    FT0 = FTS0;
+    RETURN();
+}
+
+/* fctiw - fctiw. */
+PPC_OP(fctiw)
+{
+    do_fctiw();
+    RETURN();
+}
+
+/* fctiwz - fctiwz. */
+PPC_OP(fctiwz)
+{
+    do_fctiwz();
+    RETURN();
+}
+
+
+/***                         Floating-Point compare                        ***/
+/* fcmpu */
+PPC_OP(fcmpu)
+{
+    do_fcmpu();
+    RETURN();
+}
 
-PPC_IST_OP(b, st8);
-PPC_IST_OP(h, st16);
-PPC_IST_OP(w, st32);
+/* fcmpo */
+PPC_OP(fcmpo)
+{
+    do_fcmpo();
+    RETURN();
+}
 
-/***                Integer load and store with byte reverse               ***/
-PPC_ILD_OPX(hbr, ld16r);
-PPC_ILD_OPX(wbr, ld32r);
-PPC_IST_OPX(hbr, st16r);
-PPC_IST_OPX(wbr, st32r);
+/***                         Floating-point move                           ***/
+/* fabs */
+PPC_OP(fabs)
+{
+    do_fabs();
+    RETURN();
+}
 
-/***                    Integer load and store multiple                    ***/
-PPC_OP(lmw)
+/* fnabs */
+PPC_OP(fnabs)
 {
-    do_lmw(PARAM(1), SPARAM(2) + T0);
+    do_fnabs();
     RETURN();
 }
 
-PPC_OP(stmw)
+/* fneg */
+PPC_OP(fneg)
 {
-    do_stmw(PARAM(1), SPARAM(2) + T0);
+    FT0 = -FT0;
     RETURN();
 }
 
-/***                    Integer load and store strings                     ***/
-PPC_OP(lswi)
+/* Load and store */
+#if defined(CONFIG_USER_ONLY)
+#define MEMSUFFIX _raw
+#include "op_mem.h"
+#else
+#define MEMSUFFIX _user
+#include "op_mem.h"
+
+#define MEMSUFFIX _kernel
+#include "op_mem.h"
+#endif
+
+/* Return from interrupt */
+PPC_OP(rfi)
 {
-    do_lsw(PARAM(1), PARAM(2), T0);
+    T0 = regs->spr[SRR1] & ~0xFFFF0000;
+    do_store_msr();
+    do_tlbia();
+    dump_rfi();
+    regs->nip = regs->spr[SRR0] & ~0x00000003;
+    if (env->exceptions != 0) {
+        do_check_exception_state();
+    }
     RETURN();
 }
 
-PPC_OP(lswx)
+/* Trap word */
+PPC_OP(tw)
 {
-    do_lsw(PARAM(1), T0, T1 + T2);
+    if ((Ts0 < Ts1 && (PARAM(1) & 0x10)) ||
+        (Ts0 > Ts1 && (PARAM(1) & 0x08)) ||
+        (Ts0 == Ts1 && (PARAM(1) & 0x04)) ||
+        (T0 < T1 && (PARAM(1) & 0x02)) ||
+        (T0 > T1 && (PARAM(1) & 0x01)))
+        do_queue_exception_err(EXCP_PROGRAM, EXCP_TRAP);
     RETURN();
 }
 
-PPC_OP(stswi_z)
+PPC_OP(twi)
 {
-    do_stsw(PARAM(1), PARAM(2), 0);
+    if ((Ts0 < SPARAM(1) && (PARAM(2) & 0x10)) ||
+        (Ts0 > SPARAM(1) && (PARAM(2) & 0x08)) ||
+        (Ts0 == SPARAM(1) && (PARAM(2) & 0x04)) ||
+        (T0 < (uint32_t)SPARAM(1) && (PARAM(2) & 0x02)) ||
+        (T0 > (uint32_t)SPARAM(1) && (PARAM(2) & 0x01)))
+        do_queue_exception_err(EXCP_PROGRAM, EXCP_TRAP);
     RETURN();
 }
 
-PPC_OP(stswi)
+/* Instruction cache block invalidate */
+PPC_OP(icbi)
 {
-    do_stsw(PARAM(1), PARAM(2), T0);
+    do_icbi();
     RETURN();
 }
 
-PPC_OP(stswx_z)
+/* tlbia */
+PPC_OP(tlbia)
 {
-    do_stsw(PARAM(1), T0, T1);
+    do_tlbia();
     RETURN();
 }
 
-PPC_OP(stswx)
+/* tlbie */
+PPC_OP(tlbie)
 {
-    do_stsw(PARAM(1), T0, T1 + T2);
+    do_tlbie();
     RETURN();
 }