diff options
-rw-r--r-- | target-ppc/cpu.h | 1 | ||||
-rw-r--r-- | target-ppc/op.c | 236 | ||||
-rw-r--r-- | target-ppc/op.tpl | 197 | ||||
-rw-r--r-- | target-ppc/op_template.h | 87 | ||||
-rw-r--r-- | target-ppc/translate.c | 91 |
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: */ |