diff options
author | ths <ths@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-05-18 11:55:54 +0000 |
---|---|---|
committer | ths <ths@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-05-18 11:55:54 +0000 |
commit | fd4a04ebb220b1ada72275297fc12cb85e89bbfb (patch) | |
tree | dd328471d4edb0b260bd2c0f8d85142465fcd365 /target-mips/translate.c | |
parent | 34ae7b51f54a5d58d30e31a92f8ece02973de50b (diff) |
- Move FPU exception handling into helper functions, since they are big.
- Fix FP-conditional branches.
- Check FPU register mode at runtime, not translation time, as the F64
status bit can change.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2828 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-mips/translate.c')
-rw-r--r-- | target-mips/translate.c | 176 |
1 files changed, 75 insertions, 101 deletions
diff --git a/target-mips/translate.c b/target-mips/translate.c index 66e9def854..57e5777ccb 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -491,7 +491,7 @@ FGEN32(gen_op_load_fpr_WTH2, gen_op_load_fpr_WTH2_fpr); FGEN32(gen_op_store_fpr_WTH2, gen_op_store_fpr_WTH2_fpr); #define FOP_CONDS(type, fmt) \ -static GenOpFunc1 * cond ## type ## _ ## fmt ## _table[16] = { \ +static GenOpFunc1 * gen_op_cmp ## type ## _ ## fmt ## _table[16] = { \ gen_op_cmp ## type ## _ ## fmt ## _f, \ gen_op_cmp ## type ## _ ## fmt ## _un, \ gen_op_cmp ## type ## _ ## fmt ## _eq, \ @@ -511,7 +511,7 @@ static GenOpFunc1 * cond ## type ## _ ## fmt ## _table[16] = { \ }; \ static inline void gen_cmp ## type ## _ ## fmt(int n, long cc) \ { \ - cond ## type ## _ ## fmt ## _table[n](cc); \ + gen_op_cmp ## type ## _ ## fmt ## _table[n](cc); \ } FOP_CONDS(, d) @@ -525,11 +525,10 @@ typedef struct DisasContext { struct TranslationBlock *tb; target_ulong pc, saved_pc; uint32_t opcode; - uint32_t fp_status, saved_fp_status; + uint32_t fp_status; /* Routine used to access memory */ int mem_idx; uint32_t hflags, saved_hflags; - uint32_t CP0_Status; int bstate; target_ulong btarget; } DisasContext; @@ -628,11 +627,21 @@ static inline void save_cpu_state (DisasContext *ctx, int do_save_pc) } } -static inline void save_fpu_state (DisasContext *ctx) +static inline void restore_cpu_state (CPUState *env, DisasContext *ctx) { - if (ctx->fp_status != ctx->saved_fp_status) { - gen_op_save_fp_status(ctx->fp_status); - ctx->saved_fp_status = ctx->fp_status; + ctx->saved_hflags = ctx->hflags; + switch (ctx->hflags & MIPS_HFLAG_BMASK) { + case MIPS_HFLAG_BR: + gen_op_restore_breg_target(); + break; + case MIPS_HFLAG_B: + ctx->btarget = env->btarget; + break; + case MIPS_HFLAG_BC: + case MIPS_HFLAG_BL: + ctx->btarget = env->btarget; + gen_op_restore_bcond(); + break; } } @@ -4293,20 +4302,20 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, gen_op_save_bcond(); break; case OPC_BC1FANY2: - gen_op_bc1fany2(cc); - opn = "bc1fany2"; + gen_op_bc1any2f(cc); + opn = "bc1any2f"; goto not_likely; case OPC_BC1TANY2: - gen_op_bc1tany2(cc); - opn = "bc1tany2"; + gen_op_bc1any2t(cc); + opn = "bc1any2t"; goto not_likely; case OPC_BC1FANY4: - gen_op_bc1fany4(cc); - opn = "bc1fany4"; + gen_op_bc1any4f(cc); + opn = "bc1any4f"; goto not_likely; case OPC_BC1TANY4: - gen_op_bc1tany4(cc); - opn = "bc1tany4"; + gen_op_bc1any4t(cc); + opn = "bc1any4t"; not_likely: ctx->hflags |= MIPS_HFLAG_BC; gen_op_set_bcond(); @@ -4323,27 +4332,6 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, /* Coprocessor 1 (FPU) */ -/* verify if floating point register is valid; an operation is not defined - * if bit 0 of any register specification is set and the FR bit in the - * Status register equals zero, since the register numbers specify an - * even-odd pair of adjacent coprocessor general registers. When the FR bit - * in the Status register equals one, both even and odd register numbers - * are valid. This limitation exists only for 64 bit wide (d,l,ps) registers. - * - * Multiple 64 bit wide registers can be checked by calling - * CHECK_FR(ctx, freg1 | freg2 | ... | fregN); - * - * FIXME: This is broken for R2, it needs to be checked at runtime, not - * at translation time. - */ -#define CHECK_FR(ctx, freg) do { \ - if (!((ctx)->CP0_Status & (1 << CP0St_FR)) && ((freg) & 1)) { \ - MIPS_INVAL("FPU mode"); \ - generate_exception (ctx, EXCP_RI); \ - return; \ - } \ - } while(0) - #define FOP(func, fmt) (((fmt) << 21) | (func)) static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) @@ -4388,14 +4376,14 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) opn = "dmtc1"; break; case OPC_MFHC1: - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_mfhc1(); GEN_STORE_TN_REG(rt, T0); opn = "mfhc1"; break; case OPC_MTHC1: - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_REG_TN(T0, rt); gen_op_mthc1(); GEN_STORE_FTN_FREG(fs, WTH0); @@ -4546,28 +4534,28 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "neg.s"; break; case FOP(8, 16): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_roundl_s(); GEN_STORE_FTN_FREG(fd, DT2); opn = "round.l.s"; break; case FOP(9, 16): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_truncl_s(); GEN_STORE_FTN_FREG(fd, DT2); opn = "trunc.l.s"; break; case FOP(10, 16): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_ceill_s(); GEN_STORE_FTN_FREG(fd, DT2); opn = "ceil.l.s"; break; case FOP(11, 16): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_floorl_s(); GEN_STORE_FTN_FREG(fd, DT2); @@ -4622,7 +4610,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "movn.s"; break; case FOP(33, 16): - CHECK_FR(ctx, fd); + gen_op_cp1_registers(fd); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_cvtd_s(); GEN_STORE_FTN_FREG(fd, DT2); @@ -4635,14 +4623,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "cvt.w.s"; break; case FOP(37, 16): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_cvtl_s(); GEN_STORE_FTN_FREG(fd, DT2); opn = "cvt.l.s"; break; case FOP(38, 16): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(WT1, fs); GEN_LOAD_FREG_FTN(WT0, ft); gen_op_float_cvtps_s(); @@ -4676,7 +4664,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, } break; case FOP(0, 17): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); gen_op_float_add_d(); @@ -4685,7 +4673,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, optype = BINOP; break; case FOP(1, 17): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); gen_op_float_sub_d(); @@ -4694,7 +4682,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, optype = BINOP; break; case FOP(2, 17): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); gen_op_float_mul_d(); @@ -4703,7 +4691,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, optype = BINOP; break; case FOP(3, 17): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); gen_op_float_div_d(); @@ -4712,84 +4700,84 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, optype = BINOP; break; case FOP(4, 17): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_sqrt_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "sqrt.d"; break; case FOP(5, 17): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_abs_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "abs.d"; break; case FOP(6, 17): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_mov_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "mov.d"; break; case FOP(7, 17): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_chs_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "neg.d"; break; case FOP(8, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_roundl_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "round.l.d"; break; case FOP(9, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_truncl_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "trunc.l.d"; break; case FOP(10, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_ceill_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "ceil.l.d"; break; case FOP(11, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_floorl_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "floor.l.d"; break; case FOP(12, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_roundw_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "round.w.d"; break; case FOP(13, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_truncw_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "trunc.w.d"; break; case FOP(14, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_ceilw_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "ceil.w.d"; break; case FOP(15, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_floorw_d(); GEN_STORE_FTN_FREG(fd, WT2); @@ -4835,7 +4823,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, case FOP(61, 17): case FOP(62, 17): case FOP(63, 17): - CHECK_FR(ctx, fs | ft); + gen_op_cp1_registers(fs | ft); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); if (ctx->opcode & (1 << 6)) { @@ -4847,21 +4835,21 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, } break; case FOP(32, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvts_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.s.d"; break; case FOP(36, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvtw_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.w.d"; break; case FOP(37, 17): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvtl_d(); GEN_STORE_FTN_FREG(fd, DT2); @@ -4874,21 +4862,21 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "cvt.s.w"; break; case FOP(33, 20): - CHECK_FR(ctx, fd); + gen_op_cp1_registers(fd); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_cvtd_w(); GEN_STORE_FTN_FREG(fd, DT2); opn = "cvt.d.w"; break; case FOP(32, 21): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvts_l(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.s.l"; break; case FOP(33, 21): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvtd_l(); GEN_STORE_FTN_FREG(fd, DT2); @@ -4896,7 +4884,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, break; case FOP(38, 20): case FOP(38, 21): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_cvtps_pw(); @@ -4905,7 +4893,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "cvt.ps.pw"; break; case FOP(0, 22): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -4916,7 +4904,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "add.ps"; break; case FOP(1, 22): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -4927,7 +4915,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "sub.ps"; break; case FOP(2, 22): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -4938,7 +4926,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "mul.ps"; break; case FOP(5, 22): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_abs_ps(); @@ -4947,7 +4935,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "abs.ps"; break; case FOP(6, 22): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_mov_ps(); @@ -4956,7 +4944,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "mov.ps"; break; case FOP(7, 22): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_chs_ps(); @@ -4998,7 +4986,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "movn.ps"; break; case FOP(24, 22): - CHECK_FR(ctx, fs | fd | ft); + gen_op_cp1_registers(fs | fd | ft); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -5009,14 +4997,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "addr.ps"; break; case FOP(32, 22): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_cvts_pu(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.s.pu"; break; case FOP(36, 22): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_cvtpw_ps(); @@ -5025,14 +5013,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "cvt.pw.ps"; break; case FOP(40, 22): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_cvts_pl(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.s.pl"; break; case FOP(44, 22): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WT1, ft); gen_op_float_pll_ps(); @@ -5040,7 +5028,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "pll.ps"; break; case FOP(45, 22): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH1, ft); gen_op_float_plu_ps(); @@ -5048,7 +5036,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "plu.ps"; break; case FOP(46, 22): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); gen_op_float_pul_ps(); @@ -5056,7 +5044,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "pul.ps"; break; case FOP(47, 22): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WTH1, ft); gen_op_float_puu_ps(); @@ -5079,7 +5067,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, case FOP(61, 22): case FOP(62, 22): case FOP(63, 22): - CHECK_FR(ctx, fs | ft); + gen_op_cp1_registers(fs | ft); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -5166,7 +5154,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, int fd, const char *opn = "flt3_arith"; /* All of those work only on 64bit FPUs. */ - CHECK_FR(ctx, fd | fr | fs | ft); + gen_op_cp1_registers(fd | fr | fs | ft); switch (opc) { case OPC_ALNV_PS: GEN_LOAD_REG_TN(T0, fr); @@ -5874,26 +5862,12 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, ctx.bstate = BS_NONE; /* Restore delay slot state from the tb context. */ ctx.hflags = tb->flags; - ctx.saved_hflags = ctx.hflags; - switch (ctx.hflags & MIPS_HFLAG_BMASK) { - case MIPS_HFLAG_BR: - gen_op_restore_breg_target(); - break; - case MIPS_HFLAG_B: - ctx.btarget = env->btarget; - break; - case MIPS_HFLAG_BC: - case MIPS_HFLAG_BL: - ctx.btarget = env->btarget; - gen_op_restore_bcond(); - break; - } + restore_cpu_state(env, &ctx); #if defined(CONFIG_USER_ONLY) ctx.mem_idx = 0; #else ctx.mem_idx = !((ctx.hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM); #endif - ctx.CP0_Status = env->CP0_Status; #ifdef DEBUG_DISAS if (loglevel & CPU_LOG_TB_CPU) { fprintf(logfile, "------------------------------------------------\n"); |