aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target-ppc/cpu.h1
-rw-r--r--target-ppc/op.c236
-rw-r--r--target-ppc/op.tpl197
-rw-r--r--target-ppc/op_template.h87
-rw-r--r--target-ppc/translate.c91
5 files changed, 385 insertions, 227 deletions
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 12cfc4648c..5b8ea0ad8e 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -172,6 +172,7 @@ typedef struct CPUPPCState {
uint32_t exception;
/* qemu dedicated */
+ uint64_t ft0; /* temporary float register */
int interrupt_request;
jmp_buf jmp_env;
int exception_index;
diff --git a/target-ppc/op.c b/target-ppc/op.c
index ecb991786f..e5ba004734 100644
--- a/target-ppc/op.c
+++ b/target-ppc/op.c
@@ -22,20 +22,110 @@
#include "exec.h"
#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 PPC_OP(name) void 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 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 */
PPC_OP(set_Rc0)
@@ -1114,3 +1204,135 @@ PPC_OP(stswx)
do_stsw(PARAM(1), T0, T1 + T2);
RETURN();
}
+
+/* SPR */
+PPC_OP(load_spr)
+{
+ T0 = regs->spr[PARAM(1)];
+}
+
+PPC_OP(store_spr)
+{
+ regs->spr[PARAM(1)] = T0;
+}
+
+/* FPSCR */
+PPC_OP(load_fpscr)
+{
+ T0 = do_load_fpscr();
+}
+
+PPC_OP(store_fpscr)
+{
+ do_store_fpscr(PARAM(1), T0);
+}
+
+/*** Floating-point store ***/
+
+static inline uint32_t dtos(uint64_t f)
+{
+ unsigned int e, m, s;
+ e = (((f >> 52) & 0x7ff) - 1022) + 126;
+ s = (f >> 63);
+ m = (f >> 29);
+ return (s << 31) | (e << 23) | m;
+}
+
+static inline uint64_t stod(uint32_t f)
+{
+ unsigned int e, m, s;
+ e = ((f >> 23) & 0xff) - 126 + 1022;
+ s = f >> 31;
+ m = f & ((1 << 23) - 1);
+ return ((uint64_t)s << 63) | ((uint64_t)e << 52) | ((uint64_t)m << 29);
+}
+
+PPC_OP(stfd_z_FT0)
+{
+ st64(SPARAM(1), FT0);
+}
+
+PPC_OP(stfd_FT0)
+{
+ T0 += SPARAM(1);
+ st64(T0, FT0);
+}
+
+PPC_OP(stfdx_z_FT0)
+{
+ st64(T0, FT0);
+}
+
+PPC_OP(stfdx_FT0)
+{
+ T0 += T1;
+ st64(T0, FT0);
+}
+
+
+PPC_OP(stfs_z_FT0)
+{
+ st32(SPARAM(1), dtos(FT0));
+}
+
+PPC_OP(stfs_FT0)
+{
+ T0 += SPARAM(1);
+ st32(T0, dtos(FT0));
+}
+
+PPC_OP(stfsx_z_FT0)
+{
+ st32(T0, dtos(FT0));
+}
+
+PPC_OP(stfsx_FT0)
+{
+ T0 += T1;
+ st32(T0, dtos(FT0));
+}
+
+/*** Floating-point load ***/
+PPC_OP(lfd_z_FT0)
+{
+ FT0 = ld64(SPARAM(1));
+}
+
+PPC_OP(lfd_FT0)
+{
+ T0 += SPARAM(1);
+ FT0 = ld64(T0);
+}
+
+PPC_OP(lfdx_z_FT0)
+{
+ FT0 = ld64(T0);
+}
+
+PPC_OP(lfdx_FT0)
+{
+ T0 += T1;
+ FT0 = ld64(T0);
+}
+
+PPC_OP(lfs_z_FT0)
+{
+ FT0 = stod(ld32(SPARAM(1)));
+}
+
+PPC_OP(lfs_FT0)
+{
+ T0 += SPARAM(1);
+ FT0 = stod(ld32(T0));
+}
+
+PPC_OP(lfsx_z_FT0)
+{
+ FT0 = stod(ld32(T0));
+}
+
+PPC_OP(lfsx_FT0)
+{
+ T0 += T1;
+ FT0 = stod(ld32(T0));
+}
diff --git a/target-ppc/op.tpl b/target-ppc/op.tpl
deleted file mode 100644
index f6f6d9817d..0000000000
--- a/target-ppc/op.tpl
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * PPC emulation micro-operations for qemu.
- *
- * Copyright (c) 2003 Jocelyn Mayer
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/* Host registers definitions */
-$DEFH T 3
-/* PPC registers definitions */
-$DEF gpr 32
-$DEF fpr 32
-$DEF crf 8
-$DEF spr 1024
-
-/* PPC registers <-> host registers move */
-/* GPR */
-$OP load_gpr_T0 gpr
-{
- T0 = regs->gpra;
- RETURN();
-}
-$ENDOP
-
-$OP load_gpr_T1 gpr
-{
- T1 = regs->gpra;
- RETURN();
-}
-$ENDOP
-
-$OP load_gpr_T2 gpr
-{
- T2 = regs->gpra;
- RETURN();
-}
-$ENDOP
-
-$OP store_T0_gpr gpr
-{
- regs->gpra = T0;
- RETURN();
-}
-$ENDOP
-
-$OP store_T1_gpr gpr
-{
- regs->gpra = T1;
- RETURN();
-}
-$ENDOP
-
-$OP store_gpr_P gpr PARAM
-{
- regs->gpra = PARAM(1);
- RETURN();
-}
-$ENDOP
-
-/* crf */
-$OP load_crf_T0 crf
-{
- T0 = regs->crfa;
- RETURN();
-}
-$ENDOP
-
-$OP load_crf_T1 crf
-{
- T1 = regs->crfa;
- RETURN();
-}
-$ENDOP
-
-$OP store_T0_crf crf
-{
- regs->crfa = T0;
- RETURN();
-}
-$ENDOP
-
-$OP store_T1_crf crf
-{
- regs->crfa = T1;
- RETURN();
-}
-$ENDOP
-
-/* SPR */
-$OP load_spr spr
-{
- T0 = regs->spra;
- RETURN();
-}
-$ENDOP
-
-$OP store_spr spr
-{
- regs->spra = T0;
- RETURN();
-}
-$ENDOP
-
-/* FPSCR */
-$OP load_fpscr fpr
-{
- regs->fpra = do_load_fpscr();
- RETURN();
-}
-$ENDOP
-
-$OP store_fpscr fpr PARAM
-{
- do_store_fpscr(PARAM(1), regs->fpra);
- RETURN();
-}
-$ENDOP
-
-/*** Floating-point store ***/
-/* candidate for helper (too long on x86 host) */
-$OP stfd_z fpr PARAM
-{
- st64(SPARAM(1), regs->fpra);
- RETURN();
-}
-$ENDOP
-
-/* candidate for helper (too long on x86 host) */
-$OP stfd fpr PARAM
-{
- T0 += SPARAM(1);
- st64(T0, regs->fpra);
- RETURN();
-}
-$ENDOP
-
-/* candidate for helper (too long on x86 host) */
-$OP stfdx_z fpr
-{
- st64(T0, regs->fpra);
- RETURN();
-}
-$ENDOP
-/* candidate for helper (too long on x86 host) */
-$OP stfdx fpr
-{
- T0 += T1;
- st64(T0, regs->fpra);
- RETURN();
-}
-$ENDOP
-
-/* candidate for helper (too long on x86 host) */
-$OP lfd_z fpr PARAM
-{
- regs->fpra = ld64(SPARAM(1));
- RETURN();
-}
-$ENDOP
-
-/* candidate for helper (too long) */
-$OP lfd fpr PARAM
-{
- T0 += SPARAM(1);
- regs->fpra = ld64(T0);
- RETURN();
-}
-$ENDOP
-
-$OP lfdx_z fpr
-{
- regs->fpra = ld64(T0);
- RETURN();
-}
-$ENDOP
-
-$OP lfdx fpr
-{
- T0 += T1;
- regs->fpra = ld64(T0);
- RETURN();
-}
-$ENDOP
-/*****************************************************************************/
diff --git a/target-ppc/op_template.h b/target-ppc/op_template.h
new file mode 100644
index 0000000000..d0a3f85f19
--- /dev/null
+++ b/target-ppc/op_template.h
@@ -0,0 +1,87 @@
+/*
+ * PPC emulation micro-operations for qemu.
+ *
+ * Copyright (c) 2003 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+void OPPROTO glue(op_load_gpr_T0_gpr, REG)(void)
+{
+ T0 = regs->gpr[REG];
+}
+
+void OPPROTO glue(op_load_gpr_T1_gpr, REG)(void)
+{
+ T1 = regs->gpr[REG];
+}
+
+void OPPROTO glue(op_load_gpr_T2_gpr, REG)(void)
+{
+ T2 = regs->gpr[REG];
+}
+
+void OPPROTO glue(op_store_T0_gpr_gpr, REG)(void)
+{
+ regs->gpr[REG] = T0;
+}
+
+void OPPROTO glue(op_store_T1_gpr_gpr, REG)(void)
+{
+ regs->gpr[REG] = T1;
+}
+
+void OPPROTO glue(op_store_T2_gpr_gpr, REG)(void)
+{
+ regs->gpr[REG] = T2;
+}
+
+#if REG <= 7
+
+void OPPROTO glue(op_load_crf_T0_crf, REG)(void)
+{
+ T0 = regs->crf[REG];
+}
+
+void OPPROTO glue(op_load_crf_T1_crf, REG)(void)
+{
+ T1 = regs->crf[REG];
+}
+
+void OPPROTO glue(op_store_T0_crf_crf, REG)(void)
+{
+ regs->crf[REG] = T0;
+}
+
+void OPPROTO glue(op_store_T1_crf_crf, REG)(void)
+{
+ regs->crf[REG] = T1;
+}
+
+#endif /* REG <= 7 */
+
+/* float moves */
+
+void OPPROTO glue(op_load_FT0_fpr, REG)(void)
+{
+ FT0 = env->fpr[REG];
+}
+
+void OPPROTO glue(op_store_FT0_fpr, REG)(void)
+{
+ env->fpr[REG] = FT0;
+}
+
+#undef REG
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 5560e72b4f..f2e30a78e5 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -36,7 +36,50 @@ static uint16_t *gen_opc_ptr;
static uint32_t *gen_opparam_ptr;
#include "gen-op.h"
-#include "select.h"
+
+typedef void (GenOpFunc)(void);
+
+#define GEN8(func, NAME) \
+static GenOpFunc *NAME ## _table [8] = {\
+NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3,\
+NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7,\
+};\
+static inline void func(int n)\
+{\
+ NAME ## _table[n]();\
+}
+
+#define GEN32(func, NAME) \
+static GenOpFunc *NAME ## _table [32] = {\
+NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3,\
+NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7,\
+NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11,\
+NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15,\
+NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19,\
+NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23,\
+NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27,\
+NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31,\
+};\
+static inline void func(int n)\
+{\
+ NAME ## _table[n]();\
+}
+
+GEN8(gen_op_load_crf_T0, gen_op_load_crf_T0_crf)
+GEN8(gen_op_load_crf_T1, gen_op_load_crf_T1_crf)
+GEN8(gen_op_store_T0_crf, gen_op_store_T0_crf_crf)
+GEN8(gen_op_store_T1_crf, gen_op_store_T1_crf_crf)
+
+GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr)
+GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr)
+GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr)
+
+GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr)
+GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr)
+GEN32(gen_op_store_T2_gpr, gen_op_store_T2_gpr_gpr)
+
+GEN32(gen_op_load_FT0_fpr, gen_op_load_FT0_fpr)
+GEN32(gen_op_store_FT0_fpr, gen_op_store_FT0_fpr)
static uint8_t spr_access[1024 / 2];
@@ -810,7 +853,8 @@ GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
/* mffs */
GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT)
{
- gen_op_load_fpscr(rD(ctx->opcode));
+ gen_op_load_fpscr();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
if (Rc(ctx->opcode)) {
/* Update CR1 */
}
@@ -832,7 +876,8 @@ GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT)
/* mtfsf */
GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT)
{
- gen_op_store_fpscr(FM(ctx->opcode), rB(ctx->opcode));
+ gen_op_load_gpr_T0(rB(ctx->opcode));
+ gen_op_store_fpscr(FM(ctx->opcode));
if (Rc(ctx->opcode)) {
/* Update CR1 */
}
@@ -1182,11 +1227,12 @@ GEN_HANDLER(lf##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
{ \
uint32_t simm = SIMM(ctx->opcode); \
if (rA(ctx->opcode) == 0) { \
- gen_op_lf##width##_z(simm, rD(ctx->opcode)); \
+ gen_op_lf##width##_z_FT0(simm); \
} else { \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
- gen_op_lf##width(simm, rD(ctx->opcode)); \
+ gen_op_lf##width##_FT0(simm); \
} \
+ gen_op_store_FT0_fpr(rD(ctx->opcode));\
SET_RETVAL(0); \
}
@@ -1197,7 +1243,8 @@ GEN_HANDLER(lf##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
rA(ctx->opcode) == rD(ctx->opcode)) \
SET_RETVAL(EXCP_INVAL); \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
- gen_op_lf##width(SIMM(ctx->opcode), rD(ctx->opcode)); \
+ gen_op_lf##width##_FT0(SIMM(ctx->opcode)); \
+ gen_op_store_FT0_fpr(rD(ctx->opcode));\
gen_op_store_T0_gpr(rA(ctx->opcode)); \
SET_RETVAL(0); \
}
@@ -1210,7 +1257,8 @@ GEN_HANDLER(lf##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \
SET_RETVAL(EXCP_INVAL); \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
- gen_op_lf##width##x(rD(ctx->opcode)); \
+ gen_op_lf##width##x_FT0(); \
+ gen_op_store_FT0_fpr(rD(ctx->opcode));\
gen_op_store_T0_gpr(rA(ctx->opcode)); \
SET_RETVAL(0); \
}
@@ -1220,12 +1268,13 @@ GEN_HANDLER(lf##width##x, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \
{ \
if (rA(ctx->opcode) == 0) { \
gen_op_load_gpr_T0(rB(ctx->opcode)); \
- gen_op_lf##width##x_z(rD(ctx->opcode)); \
+ gen_op_lf##width##x_z_FT0(); \
} else { \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
- gen_op_lf##width##x(rD(ctx->opcode)); \
+ gen_op_lf##width##x_FT0(); \
} \
+ gen_op_store_FT0_fpr(rD(ctx->opcode));\
SET_RETVAL(0); \
}
@@ -1238,10 +1287,6 @@ GEN_LFX(width, opc | 0x00)
/* lfd lfdu lfdux lfdx */
GEN_LDF(d, 0x12);
/* lfs lfsu lfsux lfsx */
-#define gen_op_lfs_z(a, b)
-#define gen_op_lfs(a, b)
-#define gen_op_lfsx_z(a)
-#define gen_op_lfsx(a)
GEN_LDF(s, 0x10);
/*** Floating-point store ***/
@@ -1249,11 +1294,12 @@ GEN_LDF(s, 0x10);
GEN_HANDLER(stf##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
{ \
uint32_t simm = SIMM(ctx->opcode); \
+ gen_op_load_FT0_fpr(rS(ctx->opcode));\
if (rA(ctx->opcode) == 0) { \
- gen_op_stf##width##_z(simm, rS(ctx->opcode)); \
+ gen_op_stf##width##_z_FT0(simm); \
} else { \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
- gen_op_stf##width(simm, rS(ctx->opcode)); \
+ gen_op_stf##width##_FT0(simm); \
} \
SET_RETVAL(0); \
}
@@ -1264,7 +1310,8 @@ GEN_HANDLER(stf##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
if (rA(ctx->opcode) == 0) \
SET_RETVAL(EXCP_INVAL); \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
- gen_op_stf##width(SIMM(ctx->opcode), rS(ctx->opcode)); \
+ gen_op_load_FT0_fpr(rS(ctx->opcode));\
+ gen_op_stf##width##_FT0(SIMM(ctx->opcode)); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
SET_RETVAL(0); \
}
@@ -1276,7 +1323,8 @@ GEN_HANDLER(stf##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \
SET_RETVAL(EXCP_INVAL); \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
- gen_op_stf##width##x(rS(ctx->opcode)); \
+ gen_op_load_FT0_fpr(rS(ctx->opcode));\
+ gen_op_stf##width##x_FT0(); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
SET_RETVAL(0); \
}
@@ -1284,13 +1332,14 @@ GEN_HANDLER(stf##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \
#define GEN_STFX(width, opc) \
GEN_HANDLER(stf##width##x, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \
{ \
+ gen_op_load_FT0_fpr(rS(ctx->opcode));\
if (rA(ctx->opcode) == 0) { \
gen_op_load_gpr_T0(rB(ctx->opcode)); \
- gen_op_stf##width##x_z(rS(ctx->opcode)); \
+ gen_op_stf##width##x_z_FT0(); \
} else { \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
- gen_op_stf##width##x(rS(ctx->opcode)); \
+ gen_op_stf##width##x_FT0(); \
} \
SET_RETVAL(0); \
}
@@ -1304,10 +1353,6 @@ GEN_STFX(width, opc | 0x00)
/* stfd stfdu stfdux stfdx */
GEN_STOF(d, 0x16);
/* stfs stfsu stfsux stfsx */
-#define gen_op_stfs_z(a, b)
-#define gen_op_stfs(a, b)
-#define gen_op_stfsx_z(a)
-#define gen_op_stfsx(a)
GEN_STOF(s, 0x14);
/* Optional: */