diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2014-12-17 16:25:21 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2014-12-17 16:25:21 +0000 |
commit | 84afc4dd56648ac302c7b5a917e95ca7b1239695 (patch) | |
tree | 7f1905105f79a12f7f83e5bb033f80192ae9070c | |
parent | 339aaf5b7f26d1e638641c59a44883b7654bd8ea (diff) | |
parent | d4fa5354a246a1c6cb538a5d8ebcc21206d502fb (diff) |
Merge remote-tracking branch 'remotes/lalrae/tags/mips-20141216' into staging
* remotes/lalrae/tags/mips-20141216: (30 commits)
target-mips: remove excp_names[] from linux-user as it is unused
disas/mips: disable unused mips16_to_32_reg_map[]
disas/mips: remove unused mips_msa_control_names_numeric[32]
target-mips: convert single case switch into if statement
target-mips: Fix DisasContext's ulri member initialization
target-mips: Use local float status pointer across MSA macros
target-mips: Add missing calls to synchronise SoftFloat status
linux-user: Use the 5KEf processor for 64-bit emulation
target-mips: Also apply the CP0.Status mask to MTTC0
target-mips: gdbstub: Clean up FPU register handling
target-mips: Correct 32-bit address space wrapping
target-mips: Tighten ISA level checks
target-mips: Fix CP0.Config3.ISAOnExc write accesses
target-mips: Output CP0.Config2-5 in the register dump
target-mips: Fix the 64-bit case for microMIPS MOVE16 and MOVEP
target-mips: Correct the writes to Status and Cause registers via gdbstub
target-mips: Correct the handling of writes to CP0.Status for MIPSr6
target-mips: Correct MIPS16/microMIPS branch size calculation
target-mips: Restore the order of helpers
target-mips: Remove unused `FLOAT_OP' macro
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | disas/mips.c | 10 | ||||
-rw-r--r-- | linux-user/main.c | 2 | ||||
-rw-r--r-- | target-mips/cpu.h | 124 | ||||
-rw-r--r-- | target-mips/gdbstub.c | 56 | ||||
-rw-r--r-- | target-mips/helper.c | 17 | ||||
-rw-r--r-- | target-mips/helper.h | 1 | ||||
-rw-r--r-- | target-mips/msa_helper.c | 69 | ||||
-rw-r--r-- | target-mips/op_helper.c | 433 | ||||
-rw-r--r-- | target-mips/translate.c | 170 | ||||
-rw-r--r-- | target-mips/translate_init.c | 128 | ||||
-rw-r--r-- | translate-all.c | 2 |
11 files changed, 620 insertions, 392 deletions
diff --git a/disas/mips.c b/disas/mips.c index 2614c52a4b..1afe0c5511 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -3511,6 +3511,7 @@ struct mips_cp0sel_name const char * const name; }; +#if 0 /* The mips16 registers. */ static const unsigned int mips16_to_32_reg_map[] = { @@ -3518,7 +3519,7 @@ static const unsigned int mips16_to_32_reg_map[] = }; #define mips16_reg_names(rn) mips_gpr_names[mips16_to_32_reg_map[rn]] - +#endif static const char * const mips_gpr_names_numeric[32] = { @@ -3801,13 +3802,6 @@ static const char * const mips_hwr_names_mips3264r2[32] = "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" }; -static const char * const mips_msa_control_names_numeric[32] = { - "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", - "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", - "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", - "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31" -}; - static const char * const mips_msa_control_names_mips3264r2[32] = { "MSAIR", "MSACSR", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", diff --git a/linux-user/main.c b/linux-user/main.c index 186ee4d54f..67b02316c1 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -3905,7 +3905,7 @@ int main(int argc, char **argv, char **envp) #endif #elif defined(TARGET_MIPS) #if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) - cpu_model = "20Kc"; + cpu_model = "5KEf"; #else cpu_model = "24Kf"; #endif diff --git a/target-mips/cpu.h b/target-mips/cpu.h index c01bbdac2d..8875c975e0 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -446,8 +446,8 @@ struct CPUMIPSState { #define CP0C3_MT 2 #define CP0C3_SM 1 #define CP0C3_TL 0 - uint32_t CP0_Config4; - uint32_t CP0_Config4_rw_bitmask; + int32_t CP0_Config4; + int32_t CP0_Config4_rw_bitmask; #define CP0C4_M 31 #define CP0C4_IE 29 #define CP0C4_KScrExist 16 @@ -456,8 +456,8 @@ struct CPUMIPSState { #define CP0C4_FTLBWays 4 #define CP0C4_FTLBSets 0 #define CP0C4_MMUSizeExt 0 - uint32_t CP0_Config5; - uint32_t CP0_Config5_rw_bitmask; + int32_t CP0_Config5; + int32_t CP0_Config5_rw_bitmask; #define CP0C5_M 31 #define CP0C5_K 30 #define CP0C5_CV 29 @@ -777,6 +777,18 @@ target_ulong exception_resume_pc (CPUMIPSState *env); extern unsigned int ieee_rm[]; int ieee_ex_to_mips(int xcpt); +static inline void restore_rounding_mode(CPUMIPSState *env) +{ + set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], + &env->active_fpu.fp_status); +} + +static inline void restore_flush_mode(CPUMIPSState *env) +{ + set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, + &env->active_fpu.fp_status); +} + static inline void cpu_get_tb_cpu_state(CPUMIPSState *env, target_ulong *pc, target_ulong *cs_base, int *flags) { @@ -831,16 +843,19 @@ static inline void compute_hflags(CPUMIPSState *env) env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU; } #if defined(TARGET_MIPS64) - if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) || - (env->CP0_Status & (1 << CP0St_PX)) || - (env->CP0_Status & (1 << CP0St_UX))) { + if ((env->insn_flags & ISA_MIPS3) && + (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) || + (env->CP0_Status & (1 << CP0St_PX)) || + (env->CP0_Status & (1 << CP0St_UX)))) { env->hflags |= MIPS_HFLAG_64; } - if (((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) && - !(env->CP0_Status & (1 << CP0St_UX))) { + if (!(env->insn_flags & ISA_MIPS3)) { + env->hflags |= MIPS_HFLAG_AWRAP; + } else if (((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) && + !(env->CP0_Status & (1 << CP0St_UX))) { env->hflags |= MIPS_HFLAG_AWRAP; - } else if (env->insn_flags & ISA_MIPS32R6) { + } else if (env->insn_flags & ISA_MIPS64R6) { /* Address wrapping for Supervisor and Kernel is specified in R6 */ if ((((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_SM) && !(env->CP0_Status & (1 << CP0St_SX))) || @@ -904,4 +919,93 @@ static inline void compute_hflags(CPUMIPSState *env) } } +#ifndef CONFIG_USER_ONLY +/* Called for updates to CP0_Status. */ +static inline void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc) +{ + int32_t tcstatus, *tcst; + uint32_t v = cpu->CP0_Status; + uint32_t cu, mx, asid, ksu; + uint32_t mask = ((1 << CP0TCSt_TCU3) + | (1 << CP0TCSt_TCU2) + | (1 << CP0TCSt_TCU1) + | (1 << CP0TCSt_TCU0) + | (1 << CP0TCSt_TMX) + | (3 << CP0TCSt_TKSU) + | (0xff << CP0TCSt_TASID)); + + cu = (v >> CP0St_CU0) & 0xf; + mx = (v >> CP0St_MX) & 0x1; + ksu = (v >> CP0St_KSU) & 0x3; + asid = env->CP0_EntryHi & 0xff; + + tcstatus = cu << CP0TCSt_TCU0; + tcstatus |= mx << CP0TCSt_TMX; + tcstatus |= ksu << CP0TCSt_TKSU; + tcstatus |= asid; + + if (tc == cpu->current_tc) { + tcst = &cpu->active_tc.CP0_TCStatus; + } else { + tcst = &cpu->tcs[tc].CP0_TCStatus; + } + + *tcst &= ~mask; + *tcst |= tcstatus; + compute_hflags(cpu); +} + +static inline void cpu_mips_store_status(CPUMIPSState *env, target_ulong val) +{ + uint32_t mask = env->CP0_Status_rw_bitmask; + + if (env->insn_flags & ISA_MIPS32R6) { + bool has_supervisor = extract32(mask, CP0St_KSU, 2) == 0x3; + + if (has_supervisor && extract32(val, CP0St_KSU, 2) == 0x3) { + mask &= ~(3 << CP0St_KSU); + } + mask &= ~(((1 << CP0St_SR) | (1 << CP0St_NMI)) & val); + } + + env->CP0_Status = (env->CP0_Status & ~mask) | (val & mask); + if (env->CP0_Config3 & (1 << CP0C3_MT)) { + sync_c0_status(env, env, env->current_tc); + } else { + compute_hflags(env); + } +} + +static inline void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val) +{ + uint32_t mask = 0x00C00300; + uint32_t old = env->CP0_Cause; + int i; + + if (env->insn_flags & ISA_MIPS32R2) { + mask |= 1 << CP0Ca_DC; + } + if (env->insn_flags & ISA_MIPS32R6) { + mask &= ~((1 << CP0Ca_WP) & val); + } + + env->CP0_Cause = (env->CP0_Cause & ~mask) | (val & mask); + + if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) { + if (env->CP0_Cause & (1 << CP0Ca_DC)) { + cpu_mips_stop_count(env); + } else { + cpu_mips_start_count(env); + } + } + + /* Set/reset software interrupts */ + for (i = 0 ; i < 2 ; i++) { + if ((old ^ env->CP0_Cause) & (1 << (CP0Ca_IP + i))) { + cpu_mips_soft_irq(env, i, env->CP0_Cause & (1 << (CP0Ca_IP + i))); + } + } +} +#endif + #endif /* !defined (__MIPS_CPU_H__) */ diff --git a/target-mips/gdbstub.c b/target-mips/gdbstub.c index f65fec23cc..9845d880ae 100644 --- a/target-mips/gdbstub.c +++ b/target-mips/gdbstub.c @@ -29,8 +29,13 @@ int mips_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) if (n < 32) { return gdb_get_regl(mem_buf, env->active_tc.gpr[n]); } - if (env->CP0_Config1 & (1 << CP0C1_FP)) { - if (n >= 38 && n < 70) { + if (env->CP0_Config1 & (1 << CP0C1_FP) && n >= 38 && n < 72) { + switch (n) { + case 70: + return gdb_get_regl(mem_buf, (int32_t)env->active_fpu.fcr31); + case 71: + return gdb_get_regl(mem_buf, (int32_t)env->active_fpu.fcr0); + default: if (env->CP0_Status & (1 << CP0St_FR)) { return gdb_get_regl(mem_buf, env->active_fpu.fpr[n - 38].d); @@ -39,12 +44,6 @@ int mips_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX]); } } - switch (n) { - case 70: - return gdb_get_regl(mem_buf, (int32_t)env->active_fpu.fcr31); - case 71: - return gdb_get_regl(mem_buf, (int32_t)env->active_fpu.fcr0); - } } switch (n) { case 32: @@ -64,8 +63,10 @@ int mips_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) return gdb_get_regl(mem_buf, 0); /* fp */ case 89: return gdb_get_regl(mem_buf, (int32_t)env->CP0_PRid); - } - if (n >= 73 && n <= 88) { + default: + if (n > 89) { + return 0; + } /* 16 embedded regs. */ return gdb_get_regl(mem_buf, 0); } @@ -73,10 +74,6 @@ int mips_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) return 0; } -#define RESTORE_ROUNDING_MODE \ - set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], \ - &env->active_fpu.fp_status) - int mips_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) { MIPSCPU *cpu = MIPS_CPU(cs); @@ -89,30 +86,33 @@ int mips_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) env->active_tc.gpr[n] = tmp; return sizeof(target_ulong); } - if (env->CP0_Config1 & (1 << CP0C1_FP) - && n >= 38 && n < 73) { - if (n < 70) { - if (env->CP0_Status & (1 << CP0St_FR)) { - env->active_fpu.fpr[n - 38].d = tmp; - } else { - env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX] = tmp; - } - } + if (env->CP0_Config1 & (1 << CP0C1_FP) && n >= 38 && n < 72) { switch (n) { case 70: env->active_fpu.fcr31 = tmp & 0xFF83FFFF; /* set rounding mode */ - RESTORE_ROUNDING_MODE; + restore_rounding_mode(env); + /* set flush-to-zero mode */ + restore_flush_mode(env); break; case 71: - env->active_fpu.fcr0 = tmp; + /* FIR is read-only. Ignore writes. */ + break; + default: + if (env->CP0_Status & (1 << CP0St_FR)) { + env->active_fpu.fpr[n - 38].d = tmp; + } else { + env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX] = tmp; + } break; } return sizeof(target_ulong); } switch (n) { case 32: - env->CP0_Status = tmp; +#ifndef CONFIG_USER_ONLY + cpu_mips_store_status(env, tmp); +#endif break; case 33: env->active_tc.LO[0] = tmp; @@ -124,7 +124,9 @@ int mips_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) env->CP0_BadVAddr = tmp; break; case 36: - env->CP0_Cause = tmp; +#ifndef CONFIG_USER_ONLY + cpu_mips_store_cause(env, tmp); +#endif break; case 37: env->active_tc.PC = tmp & ~(target_ulong)1; diff --git a/target-mips/helper.c b/target-mips/helper.c index 1b80aa38e0..8e3204a3a0 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -390,7 +390,6 @@ hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address, int r return physical; } } -#endif static const char * const excp_names[EXCP_LAST + 1] = { [EXCP_RESET] = "reset", @@ -431,6 +430,7 @@ static const char * const excp_names[EXCP_LAST + 1] = { [EXCP_MSADIS] = "MSA disabled", [EXCP_MSAFPE] = "MSA floating point", }; +#endif target_ulong exception_resume_pc (CPUMIPSState *env) { @@ -529,7 +529,10 @@ void mips_cpu_do_interrupt(CPUState *cs) env->CP0_DEPC = exception_resume_pc(env); env->hflags &= ~MIPS_HFLAG_BMASK; enter_debug_mode: - env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0; + if (env->insn_flags & ISA_MIPS3) { + env->hflags |= MIPS_HFLAG_64; + } + env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_CP0; env->hflags &= ~(MIPS_HFLAG_KSU); /* EJTAG probe trap enable is not implemented... */ if (!(env->CP0_Status & (1 << CP0St_EXL))) @@ -550,7 +553,10 @@ void mips_cpu_do_interrupt(CPUState *cs) env->CP0_ErrorEPC = exception_resume_pc(env); env->hflags &= ~MIPS_HFLAG_BMASK; env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); - env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0; + if (env->insn_flags & ISA_MIPS3) { + env->hflags |= MIPS_HFLAG_64; + } + env->hflags |= MIPS_HFLAG_CP0; env->hflags &= ~(MIPS_HFLAG_KSU); if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1U << CP0Ca_BD); @@ -728,7 +734,10 @@ void mips_cpu_do_interrupt(CPUState *cs) env->CP0_Cause &= ~(1U << CP0Ca_BD); } env->CP0_Status |= (1 << CP0St_EXL); - env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0; + if (env->insn_flags & ISA_MIPS3) { + env->hflags |= MIPS_HFLAG_64; + } + env->hflags |= MIPS_HFLAG_CP0; env->hflags &= ~(MIPS_HFLAG_KSU); } env->hflags &= ~MIPS_HFLAG_BMASK; diff --git a/target-mips/helper.h b/target-mips/helper.h index 9d0275891c..3bd0b029e4 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -137,6 +137,7 @@ DEF_HELPER_2(mtc0_ebase, void, env, tl) DEF_HELPER_2(mttc0_ebase, void, env, tl) DEF_HELPER_2(mtc0_config0, void, env, tl) DEF_HELPER_2(mtc0_config2, void, env, tl) +DEF_HELPER_2(mtc0_config3, void, env, tl) DEF_HELPER_2(mtc0_config4, void, env, tl) DEF_HELPER_2(mtc0_config5, void, env, tl) DEF_HELPER_2(mtc0_lladdr, void, env, tl) diff --git a/target-mips/msa_helper.c b/target-mips/msa_helper.c index b08f37f787..6e07f6ede3 100644 --- a/target-mips/msa_helper.c +++ b/target-mips/msa_helper.c @@ -1782,15 +1782,14 @@ static inline int32 float64_to_q32(float64 a STATUS_PARAM) #define MSA_FLOAT_COND(DEST, OP, ARG1, ARG2, BITS, QUIET) \ do { \ + float_status *status = &env->active_tc.msa_fp_status; \ int c; \ int64_t cond; \ - set_float_exception_flags(0, &env->active_tc.msa_fp_status); \ + set_float_exception_flags(0, status); \ if (!QUIET) { \ - cond = float ## BITS ## _ ## OP(ARG1, ARG2, \ - &env->active_tc.msa_fp_status); \ + cond = float ## BITS ## _ ## OP(ARG1, ARG2, status); \ } else { \ - cond = float ## BITS ## _ ## OP ## _quiet(ARG1, ARG2, \ - &env->active_tc.msa_fp_status); \ + cond = float ## BITS ## _ ## OP ## _quiet(ARG1, ARG2, status); \ } \ DEST = cond ? M_MAX_UINT(BITS) : 0; \ c = update_msacsr(env, CLEAR_IS_INEXACT, 0); \ @@ -2375,11 +2374,11 @@ void helper_msa_fsne_df(CPUMIPSState *env, uint32_t df, uint32_t wd, #define MSA_FLOAT_BINOP(DEST, OP, ARG1, ARG2, BITS) \ do { \ + float_status *status = &env->active_tc.msa_fp_status; \ int c; \ \ - set_float_exception_flags(0, &env->active_tc.msa_fp_status); \ - DEST = float ## BITS ## _ ## OP(ARG1, ARG2, \ - &env->active_tc.msa_fp_status); \ + set_float_exception_flags(0, status); \ + DEST = float ## BITS ## _ ## OP(ARG1, ARG2, status); \ c = update_msacsr(env, 0, IS_DENORMAL(DEST, BITS)); \ \ if (get_enabled_exceptions(env, c)) { \ @@ -2511,11 +2510,11 @@ void helper_msa_fdiv_df(CPUMIPSState *env, uint32_t df, uint32_t wd, #define MSA_FLOAT_MULADD(DEST, ARG1, ARG2, ARG3, NEGATE, BITS) \ do { \ + float_status *status = &env->active_tc.msa_fp_status; \ int c; \ \ - set_float_exception_flags(0, &env->active_tc.msa_fp_status); \ - DEST = float ## BITS ## _muladd(ARG2, ARG3, ARG1, NEGATE, \ - &env->active_tc.msa_fp_status); \ + set_float_exception_flags(0, status); \ + DEST = float ## BITS ## _muladd(ARG2, ARG3, ARG1, NEGATE, status); \ c = update_msacsr(env, 0, IS_DENORMAL(DEST, BITS)); \ \ if (get_enabled_exceptions(env, c)) { \ @@ -2630,10 +2629,11 @@ void helper_msa_fexp2_df(CPUMIPSState *env, uint32_t df, uint32_t wd, #define MSA_FLOAT_UNOP(DEST, OP, ARG, BITS) \ do { \ + float_status *status = &env->active_tc.msa_fp_status; \ int c; \ \ - set_float_exception_flags(0, &env->active_tc.msa_fp_status); \ - DEST = float ## BITS ## _ ## OP(ARG, &env->active_tc.msa_fp_status);\ + set_float_exception_flags(0, status); \ + DEST = float ## BITS ## _ ## OP(ARG, status); \ c = update_msacsr(env, 0, IS_DENORMAL(DEST, BITS)); \ \ if (get_enabled_exceptions(env, c)) { \ @@ -2678,10 +2678,11 @@ void helper_msa_fexdo_df(CPUMIPSState *env, uint32_t df, uint32_t wd, #define MSA_FLOAT_UNOP_XD(DEST, OP, ARG, BITS, XBITS) \ do { \ + float_status *status = &env->active_tc.msa_fp_status; \ int c; \ \ - set_float_exception_flags(0, &env->active_tc.msa_fp_status); \ - DEST = float ## BITS ## _ ## OP(ARG, &env->active_tc.msa_fp_status);\ + set_float_exception_flags(0, status); \ + DEST = float ## BITS ## _ ## OP(ARG, status); \ c = update_msacsr(env, CLEAR_FS_UNDERFLOW, 0); \ \ if (get_enabled_exceptions(env, c)) { \ @@ -2728,11 +2729,11 @@ void helper_msa_ftq_df(CPUMIPSState *env, uint32_t df, uint32_t wd, #define MSA_FLOAT_MAXOP(DEST, OP, ARG1, ARG2, BITS) \ do { \ + float_status *status = &env->active_tc.msa_fp_status; \ int c; \ \ - set_float_exception_flags(0, &env->active_tc.msa_fp_status); \ - DEST = float ## BITS ## _ ## OP(ARG1, ARG2, \ - &env->active_tc.msa_fp_status); \ + set_float_exception_flags(0, status); \ + DEST = float ## BITS ## _ ## OP(ARG1, ARG2, status); \ c = update_msacsr(env, 0, 0); \ \ if (get_enabled_exceptions(env, c)) { \ @@ -2924,10 +2925,11 @@ void helper_msa_fclass_df(CPUMIPSState *env, uint32_t df, #define MSA_FLOAT_UNOP0(DEST, OP, ARG, BITS) \ do { \ + float_status *status = &env->active_tc.msa_fp_status; \ int c; \ \ - set_float_exception_flags(0, &env->active_tc.msa_fp_status); \ - DEST = float ## BITS ## _ ## OP(ARG, &env->active_tc.msa_fp_status);\ + set_float_exception_flags(0, status); \ + DEST = float ## BITS ## _ ## OP(ARG, status); \ c = update_msacsr(env, CLEAR_FS_UNDERFLOW, 0); \ \ if (get_enabled_exceptions(env, c)) { \ @@ -3029,11 +3031,11 @@ void helper_msa_fsqrt_df(CPUMIPSState *env, uint32_t df, uint32_t wd, #define MSA_FLOAT_RECIPROCAL(DEST, ARG, BITS) \ do { \ + float_status *status = &env->active_tc.msa_fp_status; \ int c; \ \ - set_float_exception_flags(0, &env->active_tc.msa_fp_status); \ - DEST = float ## BITS ## _ ## div(FLOAT_ONE ## BITS, ARG, \ - &env->active_tc.msa_fp_status); \ + set_float_exception_flags(0, status); \ + DEST = float ## BITS ## _ ## div(FLOAT_ONE ## BITS, ARG, status); \ c = update_msacsr(env, float ## BITS ## _is_infinity(ARG) || \ float ## BITS ## _is_quiet_nan(DEST) ? \ 0 : RECIPROCAL_INEXACT, \ @@ -3138,23 +3140,20 @@ void helper_msa_frint_df(CPUMIPSState *env, uint32_t df, uint32_t wd, #define MSA_FLOAT_LOGB(DEST, ARG, BITS) \ do { \ + float_status *status = &env->active_tc.msa_fp_status; \ int c; \ \ - set_float_exception_flags(0, &env->active_tc.msa_fp_status); \ - set_float_rounding_mode(float_round_down, \ - &env->active_tc.msa_fp_status); \ - DEST = float ## BITS ## _ ## log2(ARG, \ - &env->active_tc.msa_fp_status); \ - DEST = float ## BITS ## _ ## round_to_int(DEST, \ - &env->active_tc.msa_fp_status); \ + set_float_exception_flags(0, status); \ + set_float_rounding_mode(float_round_down, status); \ + DEST = float ## BITS ## _ ## log2(ARG, status); \ + DEST = float ## BITS ## _ ## round_to_int(DEST, status); \ set_float_rounding_mode(ieee_rm[(env->active_tc.msacsr & \ MSACSR_RM_MASK) >> MSACSR_RM], \ - &env->active_tc.msa_fp_status); \ + status); \ \ - set_float_exception_flags( \ - get_float_exception_flags(&env->active_tc.msa_fp_status) \ - & (~float_flag_inexact), \ - &env->active_tc.msa_fp_status); \ + set_float_exception_flags(get_float_exception_flags(status) & \ + (~float_flag_inexact), \ + status); \ \ c = update_msacsr(env, 0, IS_DENORMAL(DEST, BITS)); \ \ diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 638c9f9dfb..d619ba4785 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -625,40 +625,9 @@ static CPUMIPSState *mips_cpu_map_tc(CPUMIPSState *env, int *tc) These helper call synchronizes the regs for a given cpu. */ -/* Called for updates to CP0_Status. */ -static void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc) -{ - int32_t tcstatus, *tcst; - uint32_t v = cpu->CP0_Status; - uint32_t cu, mx, asid, ksu; - uint32_t mask = ((1 << CP0TCSt_TCU3) - | (1 << CP0TCSt_TCU2) - | (1 << CP0TCSt_TCU1) - | (1 << CP0TCSt_TCU0) - | (1 << CP0TCSt_TMX) - | (3 << CP0TCSt_TKSU) - | (0xff << CP0TCSt_TASID)); - - cu = (v >> CP0St_CU0) & 0xf; - mx = (v >> CP0St_MX) & 0x1; - ksu = (v >> CP0St_KSU) & 0x3; - asid = env->CP0_EntryHi & 0xff; - - tcstatus = cu << CP0TCSt_TCU0; - tcstatus |= mx << CP0TCSt_TMX; - tcstatus |= ksu << CP0TCSt_TKSU; - tcstatus |= asid; - - if (tc == cpu->current_tc) { - tcst = &cpu->active_tc.CP0_TCStatus; - } else { - tcst = &cpu->tcs[tc].CP0_TCStatus; - } - - *tcst &= ~mask; - *tcst |= tcstatus; - compute_hflags(cpu); -} +/* Called for updates to CP0_Status. Defined in "cpu.h" for gdbstub.c. */ +/* static inline void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, + int tc); */ /* Called for updates to CP0_TCStatus. */ static void sync_c0_tcstatus(CPUMIPSState *cpu, int tc, @@ -1420,23 +1389,10 @@ void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1) { MIPSCPU *cpu = mips_env_get_cpu(env); uint32_t val, old; - uint32_t mask = env->CP0_Status_rw_bitmask; - if (env->insn_flags & ISA_MIPS32R6) { - if (extract32(env->CP0_Status, CP0St_KSU, 2) == 0x3) { - mask &= ~(3 << CP0St_KSU); - } - mask &= ~(0x00180000 & arg1); - } - - val = arg1 & mask; old = env->CP0_Status; - env->CP0_Status = (env->CP0_Status & ~mask) | val; - if (env->CP0_Config3 & (1 << CP0C3_MT)) { - sync_c0_status(env, env, env->current_tc); - } else { - compute_hflags(env); - } + cpu_mips_store_status(env, arg1); + val = env->CP0_Status; if (qemu_loglevel_mask(CPU_LOG_EXEC)) { qemu_log("Status %08x (%08x) => %08x (%08x) Cause %08x", @@ -1457,9 +1413,10 @@ void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1) void helper_mttc0_status(CPUMIPSState *env, target_ulong arg1) { int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + uint32_t mask = env->CP0_Status_rw_bitmask & ~0xf1000018; CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); - other->CP0_Status = arg1 & ~0xf1000018; + other->CP0_Status = (other->CP0_Status & ~mask) | (arg1 & mask); sync_c0_status(env, other, other_tc); } @@ -1475,40 +1432,9 @@ void helper_mtc0_srsctl(CPUMIPSState *env, target_ulong arg1) env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask); } -static void mtc0_cause(CPUMIPSState *cpu, target_ulong arg1) -{ - uint32_t mask = 0x00C00300; - uint32_t old = cpu->CP0_Cause; - int i; - - if (cpu->insn_flags & ISA_MIPS32R2) { - mask |= 1 << CP0Ca_DC; - } - if (cpu->insn_flags & ISA_MIPS32R6) { - mask &= ~((1 << CP0Ca_WP) & arg1); - } - - cpu->CP0_Cause = (cpu->CP0_Cause & ~mask) | (arg1 & mask); - - if ((old ^ cpu->CP0_Cause) & (1 << CP0Ca_DC)) { - if (cpu->CP0_Cause & (1 << CP0Ca_DC)) { - cpu_mips_stop_count(cpu); - } else { - cpu_mips_start_count(cpu); - } - } - - /* Set/reset software interrupts */ - for (i = 0 ; i < 2 ; i++) { - if ((old ^ cpu->CP0_Cause) & (1 << (CP0Ca_IP + i))) { - cpu_mips_soft_irq(cpu, i, cpu->CP0_Cause & (1 << (CP0Ca_IP + i))); - } - } -} - void helper_mtc0_cause(CPUMIPSState *env, target_ulong arg1) { - mtc0_cause(env, arg1); + cpu_mips_store_cause(env, arg1); } void helper_mttc0_cause(CPUMIPSState *env, target_ulong arg1) @@ -1516,7 +1442,7 @@ void helper_mttc0_cause(CPUMIPSState *env, target_ulong arg1) int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); - mtc0_cause(other, arg1); + cpu_mips_store_cause(other, arg1); } target_ulong helper_mftc0_epc(CPUMIPSState *env) @@ -1578,6 +1504,14 @@ void helper_mtc0_config2(CPUMIPSState *env, target_ulong arg1) env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF); } +void helper_mtc0_config3(CPUMIPSState *env, target_ulong arg1) +{ + if (env->insn_flags & ASE_MICROMIPS) { + env->CP0_Config3 = (env->CP0_Config3 & ~(1 << CP0C3_ISA_ON_EXC)) | + (arg1 & (1 << CP0C3_ISA_ON_EXC)); + } +} + void helper_mtc0_config4(CPUMIPSState *env, target_ulong arg1) { env->CP0_Config4 = (env->CP0_Config4 & (~env->CP0_Config4_rw_bitmask)) | @@ -2346,18 +2280,6 @@ unsigned int ieee_rm[] = { float_round_down }; -static inline void restore_rounding_mode(CPUMIPSState *env) -{ - set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], - &env->active_fpu.fp_status); -} - -static inline void restore_flush_mode(CPUMIPSState *env) -{ - set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, - &env->active_fpu.fp_status); -} - target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg) { target_ulong arg1 = 0; @@ -2659,11 +2581,11 @@ uint32_t helper_float_cvtw_s(CPUMIPSState *env, uint32_t fst0) uint32_t wt2; wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); - update_fcr31(env, GETPC()); if (get_float_exception_flags(&env->active_fpu.fp_status) & (float_flag_invalid | float_flag_overflow)) { wt2 = FP_TO_INT32_OVERFLOW; } + update_fcr31(env, GETPC()); return wt2; } @@ -2935,110 +2857,6 @@ FLOAT_UNOP(abs) FLOAT_UNOP(chs) #undef FLOAT_UNOP -#define FLOAT_FMADDSUB(name, bits, muladd_arg) \ -uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \ - uint ## bits ## _t fs, \ - uint ## bits ## _t ft, \ - uint ## bits ## _t fd) \ -{ \ - uint ## bits ## _t fdret; \ - \ - fdret = float ## bits ## _muladd(fs, ft, fd, muladd_arg, \ - &env->active_fpu.fp_status); \ - update_fcr31(env, GETPC()); \ - return fdret; \ -} - -FLOAT_FMADDSUB(maddf_s, 32, 0) -FLOAT_FMADDSUB(maddf_d, 64, 0) -FLOAT_FMADDSUB(msubf_s, 32, float_muladd_negate_product) -FLOAT_FMADDSUB(msubf_d, 64, float_muladd_negate_product) -#undef FLOAT_FMADDSUB - -#define FLOAT_MINMAX(name, bits, minmaxfunc) \ -uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \ - uint ## bits ## _t fs, \ - uint ## bits ## _t ft) \ -{ \ - uint ## bits ## _t fdret; \ - \ - fdret = float ## bits ## _ ## minmaxfunc(fs, ft, \ - &env->active_fpu.fp_status); \ - update_fcr31(env, GETPC()); \ - return fdret; \ -} - -FLOAT_MINMAX(max_s, 32, maxnum) -FLOAT_MINMAX(max_d, 64, maxnum) -FLOAT_MINMAX(maxa_s, 32, maxnummag) -FLOAT_MINMAX(maxa_d, 64, maxnummag) - -FLOAT_MINMAX(min_s, 32, minnum) -FLOAT_MINMAX(min_d, 64, minnum) -FLOAT_MINMAX(mina_s, 32, minnummag) -FLOAT_MINMAX(mina_d, 64, minnummag) -#undef FLOAT_MINMAX - -#define FLOAT_RINT(name, bits) \ -uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \ - uint ## bits ## _t fs) \ -{ \ - uint ## bits ## _t fdret; \ - \ - fdret = float ## bits ## _round_to_int(fs, &env->active_fpu.fp_status); \ - update_fcr31(env, GETPC()); \ - return fdret; \ -} - -FLOAT_RINT(rint_s, 32) -FLOAT_RINT(rint_d, 64) -#undef FLOAT_RINT - -#define FLOAT_CLASS_SIGNALING_NAN 0x001 -#define FLOAT_CLASS_QUIET_NAN 0x002 -#define FLOAT_CLASS_NEGATIVE_INFINITY 0x004 -#define FLOAT_CLASS_NEGATIVE_NORMAL 0x008 -#define FLOAT_CLASS_NEGATIVE_SUBNORMAL 0x010 -#define FLOAT_CLASS_NEGATIVE_ZERO 0x020 -#define FLOAT_CLASS_POSITIVE_INFINITY 0x040 -#define FLOAT_CLASS_POSITIVE_NORMAL 0x080 -#define FLOAT_CLASS_POSITIVE_SUBNORMAL 0x100 -#define FLOAT_CLASS_POSITIVE_ZERO 0x200 - -#define FLOAT_CLASS(name, bits) \ -uint ## bits ## _t helper_float_ ## name (uint ## bits ## _t arg) \ -{ \ - if (float ## bits ## _is_signaling_nan(arg)) { \ - return FLOAT_CLASS_SIGNALING_NAN; \ - } else if (float ## bits ## _is_quiet_nan(arg)) { \ - return FLOAT_CLASS_QUIET_NAN; \ - } else if (float ## bits ## _is_neg(arg)) { \ - if (float ## bits ## _is_infinity(arg)) { \ - return FLOAT_CLASS_NEGATIVE_INFINITY; \ - } else if (float ## bits ## _is_zero(arg)) { \ - return FLOAT_CLASS_NEGATIVE_ZERO; \ - } else if (float ## bits ## _is_zero_or_denormal(arg)) { \ - return FLOAT_CLASS_NEGATIVE_SUBNORMAL; \ - } else { \ - return FLOAT_CLASS_NEGATIVE_NORMAL; \ - } \ - } else { \ - if (float ## bits ## _is_infinity(arg)) { \ - return FLOAT_CLASS_POSITIVE_INFINITY; \ - } else if (float ## bits ## _is_zero(arg)) { \ - return FLOAT_CLASS_POSITIVE_ZERO; \ - } else if (float ## bits ## _is_zero_or_denormal(arg)) { \ - return FLOAT_CLASS_POSITIVE_SUBNORMAL; \ - } else { \ - return FLOAT_CLASS_POSITIVE_NORMAL; \ - } \ - } \ -} - -FLOAT_CLASS(class_s, 32) -FLOAT_CLASS(class_d, 64) -#undef FLOAT_CLASS - /* MIPS specific unary operations */ uint64_t helper_float_recip_d(CPUMIPSState *env, uint64_t fdt0) { @@ -3140,7 +2958,65 @@ uint64_t helper_float_rsqrt1_ps(CPUMIPSState *env, uint64_t fdt0) return ((uint64_t)fsth2 << 32) | fst2; } -#define FLOAT_OP(name, p) void helper_float_##name##_##p(CPUMIPSState *env) +#define FLOAT_RINT(name, bits) \ +uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \ + uint ## bits ## _t fs) \ +{ \ + uint ## bits ## _t fdret; \ + \ + fdret = float ## bits ## _round_to_int(fs, &env->active_fpu.fp_status); \ + update_fcr31(env, GETPC()); \ + return fdret; \ +} + +FLOAT_RINT(rint_s, 32) +FLOAT_RINT(rint_d, 64) +#undef FLOAT_RINT + +#define FLOAT_CLASS_SIGNALING_NAN 0x001 +#define FLOAT_CLASS_QUIET_NAN 0x002 +#define FLOAT_CLASS_NEGATIVE_INFINITY 0x004 +#define FLOAT_CLASS_NEGATIVE_NORMAL 0x008 +#define FLOAT_CLASS_NEGATIVE_SUBNORMAL 0x010 +#define FLOAT_CLASS_NEGATIVE_ZERO 0x020 +#define FLOAT_CLASS_POSITIVE_INFINITY 0x040 +#define FLOAT_CLASS_POSITIVE_NORMAL 0x080 +#define FLOAT_CLASS_POSITIVE_SUBNORMAL 0x100 +#define FLOAT_CLASS_POSITIVE_ZERO 0x200 + +#define FLOAT_CLASS(name, bits) \ +uint ## bits ## _t helper_float_ ## name (uint ## bits ## _t arg) \ +{ \ + if (float ## bits ## _is_signaling_nan(arg)) { \ + return FLOAT_CLASS_SIGNALING_NAN; \ + } else if (float ## bits ## _is_quiet_nan(arg)) { \ + return FLOAT_CLASS_QUIET_NAN; \ + } else if (float ## bits ## _is_neg(arg)) { \ + if (float ## bits ## _is_infinity(arg)) { \ + return FLOAT_CLASS_NEGATIVE_INFINITY; \ + } else if (float ## bits ## _is_zero(arg)) { \ + return FLOAT_CLASS_NEGATIVE_ZERO; \ + } else if (float ## bits ## _is_zero_or_denormal(arg)) { \ + return FLOAT_CLASS_NEGATIVE_SUBNORMAL; \ + } else { \ + return FLOAT_CLASS_NEGATIVE_NORMAL; \ + } \ + } else { \ + if (float ## bits ## _is_infinity(arg)) { \ + return FLOAT_CLASS_POSITIVE_INFINITY; \ + } else if (float ## bits ## _is_zero(arg)) { \ + return FLOAT_CLASS_POSITIVE_ZERO; \ + } else if (float ## bits ## _is_zero_or_denormal(arg)) { \ + return FLOAT_CLASS_POSITIVE_SUBNORMAL; \ + } else { \ + return FLOAT_CLASS_POSITIVE_NORMAL; \ + } \ + } \ +} + +FLOAT_CLASS(class_s, 32) +FLOAT_CLASS(class_d, 64) +#undef FLOAT_CLASS /* binary operations */ #define FLOAT_BINOP(name) \ @@ -3187,61 +3063,6 @@ FLOAT_BINOP(mul) FLOAT_BINOP(div) #undef FLOAT_BINOP -#define UNFUSED_FMA(prefix, a, b, c, flags) \ -{ \ - a = prefix##_mul(a, b, &env->active_fpu.fp_status); \ - if ((flags) & float_muladd_negate_c) { \ - a = prefix##_sub(a, c, &env->active_fpu.fp_status); \ - } else { \ - a = prefix##_add(a, c, &env->active_fpu.fp_status); \ - } \ - if ((flags) & float_muladd_negate_result) { \ - a = prefix##_chs(a); \ - } \ -} - -/* FMA based operations */ -#define FLOAT_FMA(name, type) \ -uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \ - uint64_t fdt0, uint64_t fdt1, \ - uint64_t fdt2) \ -{ \ - UNFUSED_FMA(float64, fdt0, fdt1, fdt2, type); \ - update_fcr31(env, GETPC()); \ - return fdt0; \ -} \ - \ -uint32_t helper_float_ ## name ## _s(CPUMIPSState *env, \ - uint32_t fst0, uint32_t fst1, \ - uint32_t fst2) \ -{ \ - UNFUSED_FMA(float32, fst0, fst1, fst2, type); \ - update_fcr31(env, GETPC()); \ - return fst0; \ -} \ - \ -uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \ - uint64_t fdt0, uint64_t fdt1, \ - uint64_t fdt2) \ -{ \ - uint32_t fst0 = fdt0 & 0XFFFFFFFF; \ - uint32_t fsth0 = fdt0 >> 32; \ - uint32_t fst1 = fdt1 & 0XFFFFFFFF; \ - uint32_t fsth1 = fdt1 >> 32; \ - uint32_t fst2 = fdt2 & 0XFFFFFFFF; \ - uint32_t fsth2 = fdt2 >> 32; \ - \ - UNFUSED_FMA(float32, fst0, fst1, fst2, type); \ - UNFUSED_FMA(float32, fsth0, fsth1, fsth2, type); \ - update_fcr31(env, GETPC()); \ - return ((uint64_t)fsth0 << 32) | fst0; \ -} -FLOAT_FMA(madd, 0) -FLOAT_FMA(msub, float_muladd_negate_c) -FLOAT_FMA(nmadd, float_muladd_negate_result) -FLOAT_FMA(nmsub, float_muladd_negate_result | float_muladd_negate_c) -#undef FLOAT_FMA - /* MIPS specific binary operations */ uint64_t helper_float_recip2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2) { @@ -3339,6 +3160,106 @@ uint64_t helper_float_mulr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1) return ((uint64_t)fsth2 << 32) | fst2; } +#define FLOAT_MINMAX(name, bits, minmaxfunc) \ +uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \ + uint ## bits ## _t fs, \ + uint ## bits ## _t ft) \ +{ \ + uint ## bits ## _t fdret; \ + \ + fdret = float ## bits ## _ ## minmaxfunc(fs, ft, \ + &env->active_fpu.fp_status); \ + update_fcr31(env, GETPC()); \ + return fdret; \ +} + +FLOAT_MINMAX(max_s, 32, maxnum) +FLOAT_MINMAX(max_d, 64, maxnum) +FLOAT_MINMAX(maxa_s, 32, maxnummag) +FLOAT_MINMAX(maxa_d, 64, maxnummag) + +FLOAT_MINMAX(min_s, 32, minnum) +FLOAT_MINMAX(min_d, 64, minnum) +FLOAT_MINMAX(mina_s, 32, minnummag) +FLOAT_MINMAX(mina_d, 64, minnummag) +#undef FLOAT_MINMAX + +/* ternary operations */ +#define UNFUSED_FMA(prefix, a, b, c, flags) \ +{ \ + a = prefix##_mul(a, b, &env->active_fpu.fp_status); \ + if ((flags) & float_muladd_negate_c) { \ + a = prefix##_sub(a, c, &env->active_fpu.fp_status); \ + } else { \ + a = prefix##_add(a, c, &env->active_fpu.fp_status); \ + } \ + if ((flags) & float_muladd_negate_result) { \ + a = prefix##_chs(a); \ + } \ +} + +/* FMA based operations */ +#define FLOAT_FMA(name, type) \ +uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \ + uint64_t fdt0, uint64_t fdt1, \ + uint64_t fdt2) \ +{ \ + UNFUSED_FMA(float64, fdt0, fdt1, fdt2, type); \ + update_fcr31(env, GETPC()); \ + return fdt0; \ +} \ + \ +uint32_t helper_float_ ## name ## _s(CPUMIPSState *env, \ + uint32_t fst0, uint32_t fst1, \ + uint32_t fst2) \ +{ \ + UNFUSED_FMA(float32, fst0, fst1, fst2, type); \ + update_fcr31(env, GETPC()); \ + return fst0; \ +} \ + \ +uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \ + uint64_t fdt0, uint64_t fdt1, \ + uint64_t fdt2) \ +{ \ + uint32_t fst0 = fdt0 & 0XFFFFFFFF; \ + uint32_t fsth0 = fdt0 >> 32; \ + uint32_t fst1 = fdt1 & 0XFFFFFFFF; \ + uint32_t fsth1 = fdt1 >> 32; \ + uint32_t fst2 = fdt2 & 0XFFFFFFFF; \ + uint32_t fsth2 = fdt2 >> 32; \ + \ + UNFUSED_FMA(float32, fst0, fst1, fst2, type); \ + UNFUSED_FMA(float32, fsth0, fsth1, fsth2, type); \ + update_fcr31(env, GETPC()); \ + return ((uint64_t)fsth0 << 32) | fst0; \ +} +FLOAT_FMA(madd, 0) +FLOAT_FMA(msub, float_muladd_negate_c) +FLOAT_FMA(nmadd, float_muladd_negate_result) +FLOAT_FMA(nmsub, float_muladd_negate_result | float_muladd_negate_c) +#undef FLOAT_FMA + +#define FLOAT_FMADDSUB(name, bits, muladd_arg) \ +uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \ + uint ## bits ## _t fs, \ + uint ## bits ## _t ft, \ + uint ## bits ## _t fd) \ +{ \ + uint ## bits ## _t fdret; \ + \ + fdret = float ## bits ## _muladd(fs, ft, fd, muladd_arg, \ + &env->active_fpu.fp_status); \ + update_fcr31(env, GETPC()); \ + return fdret; \ +} + +FLOAT_FMADDSUB(maddf_s, 32, 0) +FLOAT_FMADDSUB(maddf_d, 64, 0) +FLOAT_FMADDSUB(msubf_s, 32, float_muladd_negate_product) +FLOAT_FMADDSUB(msubf_d, 64, float_muladd_negate_product) +#undef FLOAT_FMADDSUB + /* compare operations */ #define FOP_COND_D(op, cond) \ void helper_cmp_d_ ## op(CPUMIPSState *env, uint64_t fdt0, \ diff --git a/target-mips/translate.c b/target-mips/translate.c index f0b8e6ffe4..1205909f78 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1882,10 +1882,8 @@ static inline void gen_r6_cmp_ ## fmt(DisasContext * ctx, int n, \ { \ TCGv_i ## bits fp0 = tcg_temp_new_i ## bits(); \ TCGv_i ## bits fp1 = tcg_temp_new_i ## bits(); \ - switch (ifmt) { \ - case FMT_D: \ + if (ifmt == FMT_D) { \ check_cp1_registers(ctx, fs | ft | fd); \ - break; \ } \ gen_ldcmp_fpr ## bits(ctx, fp0, fs); \ gen_ldcmp_fpr ## bits(ctx, fp1, ft); \ @@ -2398,7 +2396,14 @@ static void gen_cop1_ldst(DisasContext *ctx, uint32_t op, int rt, { if (ctx->CP0_Config1 & (1 << CP0C1_FP)) { check_cp1_enabled(ctx); - gen_flt_ldst(ctx, op, rt, rs, imm); + switch (op) { + case OPC_LDC1: + case OPC_SDC1: + check_insn(ctx, ISA_MIPS2); + /* Fallthrough */ + default: + gen_flt_ldst(ctx, op, rt, rs, imm); + } } else { generate_exception_err(ctx, EXCP_CpU, 1); } @@ -5846,8 +5851,10 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) ctx->bstate = BS_STOP; break; case 3: - /* ignored, read only */ + gen_helper_mtc0_config3(cpu_env, arg); rn = "Config3"; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 4: gen_helper_mtc0_config4(cpu_env, arg); @@ -7097,8 +7104,10 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) ctx->bstate = BS_STOP; break; case 3: - /* ignored */ + gen_helper_mtc0_config3(cpu_env, arg); rn = "Config3"; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; break; case 4: /* currently ignored */ @@ -10717,6 +10726,7 @@ static void gen_mips16_save (DisasContext *ctx, { TCGv t0 = tcg_temp_new(); TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); int args, astatic; switch (aregs) { @@ -10775,7 +10785,8 @@ static void gen_mips16_save (DisasContext *ctx, gen_load_gpr(t0, 29); #define DECR_AND_STORE(reg) do { \ - tcg_gen_subi_tl(t0, t0, 4); \ + tcg_gen_movi_tl(t2, -4); \ + gen_op_addr_add(ctx, t0, t0, t2); \ gen_load_gpr(t1, reg); \ tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); \ } while (0) @@ -10859,9 +10870,11 @@ static void gen_mips16_save (DisasContext *ctx, } #undef DECR_AND_STORE - tcg_gen_subi_tl(cpu_gpr[29], cpu_gpr[29], framesize); + tcg_gen_movi_tl(t2, -framesize); + gen_op_addr_add(ctx, cpu_gpr[29], cpu_gpr[29], t2); tcg_temp_free(t0); tcg_temp_free(t1); + tcg_temp_free(t2); } static void gen_mips16_restore (DisasContext *ctx, @@ -10872,11 +10885,14 @@ static void gen_mips16_restore (DisasContext *ctx, int astatic; TCGv t0 = tcg_temp_new(); TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); - tcg_gen_addi_tl(t0, cpu_gpr[29], framesize); + tcg_gen_movi_tl(t2, framesize); + gen_op_addr_add(ctx, t0, cpu_gpr[29], t2); #define DECR_AND_LOAD(reg) do { \ - tcg_gen_subi_tl(t0, t0, 4); \ + tcg_gen_movi_tl(t2, -4); \ + gen_op_addr_add(ctx, t0, t0, t2); \ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TESL); \ gen_store_gpr(t1, reg); \ } while (0) @@ -10960,9 +10976,11 @@ static void gen_mips16_restore (DisasContext *ctx, } #undef DECR_AND_LOAD - tcg_gen_addi_tl(cpu_gpr[29], cpu_gpr[29], framesize); + tcg_gen_movi_tl(t2, framesize); + gen_op_addr_add(ctx, cpu_gpr[29], cpu_gpr[29], t2); tcg_temp_free(t0); tcg_temp_free(t1); + tcg_temp_free(t2); } static void gen_addiupc (DisasContext *ctx, int rx, int imm, @@ -10993,26 +11011,32 @@ static void decode_i64_mips16 (DisasContext *ctx, { switch (funct) { case I64_LDSP: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); offset = extended ? offset : offset << 3; gen_ld(ctx, OPC_LD, ry, 29, offset); break; case I64_SDSP: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); offset = extended ? offset : offset << 3; gen_st(ctx, OPC_SD, ry, 29, offset); break; case I64_SDRASP: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); offset = extended ? offset : (ctx->opcode & 0xff) << 3; gen_st(ctx, OPC_SD, 31, 29, offset); break; case I64_DADJSP: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); offset = extended ? offset : ((int8_t)ctx->opcode) << 3; gen_arith_imm(ctx, OPC_DADDIU, 29, 29, offset); break; case I64_LDPC: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); if (extended && (ctx->hflags & MIPS_HFLAG_BMASK)) { generate_exception(ctx, EXCP_RI); } else { @@ -11021,16 +11045,19 @@ static void decode_i64_mips16 (DisasContext *ctx, } break; case I64_DADDIU5: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); offset = extended ? offset : ((int8_t)(offset << 3)) >> 3; gen_arith_imm(ctx, OPC_DADDIU, ry, ry, offset); break; case I64_DADDIUPC: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); offset = extended ? offset : offset << 2; gen_addiupc(ctx, ry, offset, 1, extended); break; case I64_DADDIUSP: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); offset = extended ? offset : offset << 2; gen_arith_imm(ctx, OPC_DADDIU, ry, 29, offset); @@ -11099,7 +11126,8 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx) break; #if defined(TARGET_MIPS64) case M16_OPC_LD: - check_mips_64(ctx); + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); gen_ld(ctx, OPC_LD, ry, rx, offset); break; #endif @@ -11143,6 +11171,7 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx) gen_arith_imm(ctx, OPC_ADDIU, 29, 29, imm); break; case I8_SVRS: + check_insn(ctx, ISA_MIPS32); { int xsregs = (ctx->opcode >> 24) & 0x7; int aregs = (ctx->opcode >> 16) & 0xf; @@ -11176,6 +11205,8 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx) break; #if defined(TARGET_MIPS64) case M16_OPC_SD: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); gen_st(ctx, OPC_SD, ry, rx, offset); break; #endif @@ -11202,6 +11233,8 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx) break; #if defined(TARGET_MIPS64) case M16_OPC_LWU: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); gen_ld(ctx, OPC_LWU, ry, rx, offset); break; #endif @@ -11291,6 +11324,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) break; case 0x1: #if defined(TARGET_MIPS64) + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_shift_imm(ctx, OPC_DSLL, rx, ry, sa); #else @@ -11307,6 +11341,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) break; #if defined(TARGET_MIPS64) case M16_OPC_LD: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_ld(ctx, OPC_LD, ry, rx, offset << 3); break; @@ -11317,6 +11352,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) if ((ctx->opcode >> 4) & 1) { #if defined(TARGET_MIPS64) + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_arith_imm(ctx, OPC_DADDIU, ry, rx, imm); #else @@ -11368,6 +11404,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) ((int8_t)ctx->opcode) << 3); break; case I8_SVRS: + check_insn(ctx, ISA_MIPS32); { int do_ra = ctx->opcode & (1 << 6); int do_s0 = ctx->opcode & (1 << 5); @@ -11423,6 +11460,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) break; #if defined(TARGET_MIPS64) case M16_OPC_SD: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_st(ctx, OPC_SD, ry, rx, offset << 3); break; @@ -11450,6 +11488,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) break; #if defined (TARGET_MIPS64) case M16_OPC_LWU: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_ld(ctx, OPC_LWU, ry, rx, offset << 2); break; @@ -11481,10 +11520,12 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) #if defined(TARGET_MIPS64) case RRR_DADDU: mips32_op = OPC_DADDU; + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); break; case RRR_DSUBU: mips32_op = OPC_DSUBU; + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); break; #endif @@ -11506,6 +11547,10 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) int link = (ctx->opcode >> 6) & 0x1; int ra = (ctx->opcode >> 5) & 0x1; + if (nd) { + check_insn(ctx, ISA_MIPS32); + } + if (link) { op = OPC_JALR; } else { @@ -11547,6 +11592,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) break; #if defined (TARGET_MIPS64) case RR_DSRL: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_shift_imm(ctx, OPC_DSRL, ry, ry, sa); break; @@ -11573,6 +11619,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) gen_HILO(ctx, OPC_MFHI, 0, rx); break; case RR_CNVT: + check_insn(ctx, ISA_MIPS32); switch (cnvt_op) { case RR_RY_CNVT_ZEB: tcg_gen_ext8u_tl(cpu_gpr[rx], cpu_gpr[rx]); @@ -11588,10 +11635,12 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) break; #if defined (TARGET_MIPS64) case RR_RY_CNVT_ZEW: + check_insn(ctx, ISA_MIPS64); check_mips_64(ctx); tcg_gen_ext32u_tl(cpu_gpr[rx], cpu_gpr[rx]); break; case RR_RY_CNVT_SEW: + check_insn(ctx, ISA_MIPS64); check_mips_64(ctx); tcg_gen_ext32s_tl(cpu_gpr[rx], cpu_gpr[rx]); break; @@ -11606,18 +11655,22 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) break; #if defined (TARGET_MIPS64) case RR_DSRA: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_shift_imm(ctx, OPC_DSRA, ry, ry, sa); break; case RR_DSLLV: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_shift(ctx, OPC_DSLLV, ry, rx, ry); break; case RR_DSRLV: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_shift(ctx, OPC_DSRLV, ry, rx, ry); break; case RR_DSRAV: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_shift(ctx, OPC_DSRAV, ry, rx, ry); break; @@ -11636,18 +11689,22 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) break; #if defined (TARGET_MIPS64) case RR_DMULT: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_muldiv(ctx, OPC_DMULT, 0, rx, ry); break; case RR_DMULTU: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_muldiv(ctx, OPC_DMULTU, 0, rx, ry); break; case RR_DDIV: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_muldiv(ctx, OPC_DDIV, 0, rx, ry); break; case RR_DDIVU: + check_insn(ctx, ISA_MIPS3); check_mips_64(ctx); gen_muldiv(ctx, OPC_DDIVU, 0, rx, ry); break; @@ -13212,20 +13269,26 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, /* COP2: Not implemented. */ generate_exception_err(ctx, EXCP_CpU, 2); break; - case LWP: - case SWP: #ifdef TARGET_MIPS64 case LDP: case SDP: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + /* Fallthrough */ #endif + case LWP: + case SWP: gen_ldst_pair(ctx, minor, rt, rs, SIMM(ctx->opcode, 0, 12)); break; - case LWM32: - case SWM32: #ifdef TARGET_MIPS64 case LDM: case SDM: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + /* Fallthrough */ #endif + case LWM32: + case SWM32: gen_ldst_multiple(ctx, minor, rt, rs, SIMM(ctx->opcode, 0, 12)); break; default: @@ -13649,21 +13712,33 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, goto do_st_lr; #if defined(TARGET_MIPS64) case LDL: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); mips32_op = OPC_LDL; goto do_ld_lr; case SDL: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); mips32_op = OPC_SDL; goto do_st_lr; case LDR: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); mips32_op = OPC_LDR; goto do_ld_lr; case SDR: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); mips32_op = OPC_SDR; goto do_st_lr; case LWU: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); mips32_op = OPC_LWU; goto do_ld_lr; case LLD: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); mips32_op = OPC_LLD; goto do_ld_lr; #endif @@ -13681,6 +13756,8 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, break; #if defined(TARGET_MIPS64) case SCD: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); gen_st_cond(ctx, OPC_SCD, rt, rs, SIMM(ctx->opcode, 0, 12)); break; #endif @@ -13790,9 +13867,13 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, goto do_ld; #ifdef TARGET_MIPS64 case LD32: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); mips32_op = OPC_LD; goto do_ld; case SD32: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); mips32_op = OPC_SD; goto do_st; #endif @@ -13936,8 +14017,8 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) rs = rs_rt_enc[enc_rs]; rt = rs_rt_enc[enc_rt]; - gen_arith_imm(ctx, OPC_ADDIU, rd, rs, 0); - gen_arith_imm(ctx, OPC_ADDIU, re, rt, 0); + gen_arith(ctx, OPC_ADDU, rd, rs, 0); + gen_arith(ctx, OPC_ADDU, re, rt, 0); } break; case LBU16: @@ -14018,7 +14099,7 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) int rd = uMIPS_RD5(ctx->opcode); int rs = uMIPS_RS5(ctx->opcode); - gen_arith_imm(ctx, OPC_ADDIU, rd, rs, 0); + gen_arith(ctx, OPC_ADDU, rd, rs, 0); } break; case ANDI16: @@ -16322,6 +16403,7 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) break; case OPC_TGE ... OPC_TEQ: /* Traps */ case OPC_TNE: + check_insn(ctx, ISA_MIPS2); gen_trap(ctx, op1, rs, rt, -1); break; case OPC_LSA: /* OPC_PMON */ @@ -16346,6 +16428,7 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) generate_exception(ctx, EXCP_BREAK); break; case OPC_SYNC: + check_insn(ctx, ISA_MIPS2); /* Treat as NOP. */ break; @@ -18340,7 +18423,7 @@ static void gen_msa(CPUMIPSState *env, DisasContext *ctx) } -static void decode_opc (CPUMIPSState *env, DisasContext *ctx) +static void decode_opc(CPUMIPSState *env, DisasContext *ctx) { int32_t offset; int rs, rt, rd, sa; @@ -18392,7 +18475,9 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) case OPC_BGEZL: case OPC_BLTZALL: case OPC_BGEZALL: + check_insn(ctx, ISA_MIPS2); check_insn_opc_removed(ctx, ISA_MIPS32R6); + /* Fallthrough */ case OPC_BLTZ: case OPC_BGEZ: gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2, 4); @@ -18412,6 +18497,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) break; case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */ case OPC_TNEI: + check_insn(ctx, ISA_MIPS2); check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_trap(ctx, op1, rs, -1, imm); break; @@ -18506,7 +18592,8 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) save_cpu_state(ctx, 1); gen_helper_di(t0, cpu_env); gen_store_gpr(t0, rt); - /* Stop translation as we may have switched the execution mode */ + /* Stop translation as we may have switched + the execution mode. */ ctx->bstate = BS_STOP; break; case OPC_EI: @@ -18514,7 +18601,8 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) save_cpu_state(ctx, 1); gen_helper_ei(t0, cpu_env); gen_store_gpr(t0, rt); - /* Stop translation as we may have switched the execution mode */ + /* Stop translation as we may have switched + the execution mode. */ ctx->bstate = BS_STOP; break; default: /* Invalid */ @@ -18616,15 +18704,20 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) break; case OPC_BEQL: case OPC_BNEL: + check_insn(ctx, ISA_MIPS2); check_insn_opc_removed(ctx, ISA_MIPS32R6); + /* Fallthrough */ case OPC_BEQ: case OPC_BNE: gen_compute_branch(ctx, op, 4, rs, rt, imm << 2, 4); break; - case OPC_LWL: /* Load and stores */ + case OPC_LL: /* Load and stores */ + check_insn(ctx, ISA_MIPS2); + /* Fallthrough */ + case OPC_LWL: case OPC_LWR: - case OPC_LL: check_insn_opc_removed(ctx, ISA_MIPS32R6); + /* Fallthrough */ case OPC_LB ... OPC_LH: case OPC_LW ... OPC_LHU: gen_ld(ctx, op, rt, rs, imm); @@ -18637,6 +18730,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) gen_st(ctx, op, rt, rs, imm); break; case OPC_SC: + check_insn(ctx, ISA_MIPS2); check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_st_cond(ctx, op, rt, rs, imm); break; @@ -18680,6 +18774,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) case OPC_DMTC1: check_cp1_enabled(ctx); check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); gen_cp1(ctx, op1, rt, rd); break; #endif @@ -18780,8 +18875,9 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) gen_r6_cmp_d(ctx, ctx->opcode & 0x1f, rt, rd, sa); break; default: - gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa, - (imm >> 8) & 0x7); + gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), + rt, rd, sa, (imm >> 8) & 0x7); + break; } } else { @@ -18852,18 +18948,24 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) check_cp1_enabled(ctx); op1 = MASK_CP3(ctx->opcode); switch (op1) { + case OPC_LUXC1: + case OPC_SUXC1: + check_insn(ctx, ISA_MIPS5 | ISA_MIPS32R2); + /* Fallthrough */ case OPC_LWXC1: case OPC_LDXC1: - case OPC_LUXC1: case OPC_SWXC1: case OPC_SDXC1: - case OPC_SUXC1: + check_insn(ctx, ISA_MIPS4 | ISA_MIPS32R2); gen_flt3_ldst(ctx, op1, sa, rd, rs, rt); break; case OPC_PREFX: + check_insn(ctx, ISA_MIPS4 | ISA_MIPS32R2); /* Treat as NOP. */ break; case OPC_ALNV_PS: + check_insn(ctx, ISA_MIPS5 | ISA_MIPS32R2); + /* Fallthrough */ case OPC_MADD_S: case OPC_MADD_D: case OPC_MADD_PS: @@ -18876,6 +18978,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) case OPC_NMSUB_S: case OPC_NMSUB_D: case OPC_NMSUB_PS: + check_insn(ctx, ISA_MIPS4 | ISA_MIPS32R2); gen_flt3_arith(ctx, op1, sa, rs, rd, rt); break; default: @@ -19011,7 +19114,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, ctx.bp = (env->CP0_Config3 >> CP0C3_BP) & 1; /* Restore delay slot state from the tb context. */ ctx.hflags = (uint32_t)tb->flags; /* FIXME: maybe use 64 bits here? */ - ctx.ulri = env->CP0_Config3 & (1 << CP0C3_ULRI); + ctx.ulri = (env->CP0_Config3 >> CP0C3_ULRI) & 1; restore_cpu_state(env, &ctx); #ifdef CONFIG_USER_ONLY ctx.mem_idx = MIPS_HFLAG_UM; @@ -19261,6 +19364,10 @@ void mips_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, env->CP0_Status, env->CP0_Cause, env->CP0_EPC); cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x" TARGET_FMT_lx "\n", env->CP0_Config0, env->CP0_Config1, env->lladdr); + cpu_fprintf(f, " Config2 0x%08x Config3 0x%08x\n", + env->CP0_Config2, env->CP0_Config3); + cpu_fprintf(f, " Config4 0x%08x Config5 0x%08x\n", + env->CP0_Config4, env->CP0_Config5); if (env->hflags & MIPS_HFLAG_FPU) fpu_dump_state(env, f, cpu_fprintf, flags); #if defined(TARGET_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS) @@ -19436,7 +19543,8 @@ void cpu_state_reset(CPUMIPSState *env) if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, come back to the jump. */ - env->CP0_ErrorEPC = env->active_tc.PC - 4; + env->CP0_ErrorEPC = (env->active_tc.PC + - (env->hflags & MIPS_HFLAG_B16 ? 2 : 4)); } else { env->CP0_ErrorEPC = env->active_tc.PC; } @@ -19507,6 +19615,8 @@ void cpu_state_reset(CPUMIPSState *env) } compute_hflags(env); + restore_rounding_mode(env); + restore_flush_mode(env); cs->exception_index = EXCP_NONE; } diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c index 148b394cf0..1543f6c388 100644 --- a/target-mips/translate_init.c +++ b/target-mips/translate_init.c @@ -334,7 +334,7 @@ static const mips_def_t mips_defs[] = (1 << CP0C1_CA), .CP0_Config2 = MIPS_CONFIG2, .CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_DSP2P) | (1 << CP0C3_DSPP) | - (0 << CP0C3_VInt), + (1 << CP0C3_VInt), .CP0_LLAddr_rw_bitmask = 0, .CP0_LLAddr_shift = 4, .SYNCI_Step = 32, @@ -348,6 +348,47 @@ static const mips_def_t mips_defs[] = .mmu_type = MMU_TYPE_R4000, }, { + .name = "M14K", + .CP0_PRid = 0x00019b00, + /* Config1 implemented, fixed mapping MMU, + no virtual icache, uncached coherency. */ + .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_KU) | (0x2 << CP0C0_K23) | + (0x1 << CP0C0_AR) | (MMU_TYPE_FMT << CP0C0_MT), + .CP0_Config1 = MIPS_CONFIG1, + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3 | (0x2 << CP0C3_ISA) | (1 << CP0C3_VInt), + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 4, + .SYNCI_Step = 32, + .CCRes = 2, + .CP0_Status_rw_bitmask = 0x1258FF17, + .SEGBITS = 32, + .PABITS = 32, + .insn_flags = CPU_MIPS32R2 | ASE_MICROMIPS, + .mmu_type = MMU_TYPE_FMT, + }, + { + .name = "M14Kc", + /* This is the TLB-based MMU core. */ + .CP0_PRid = 0x00019c00, + .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | + (MMU_TYPE_R4000 << CP0C0_MT), + .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) | + (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) | + (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA), + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3 | (0x2 << CP0C3_ISA) | (0 << CP0C3_VInt), + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 4, + .SYNCI_Step = 32, + .CCRes = 2, + .CP0_Status_rw_bitmask = 0x1278FF17, + .SEGBITS = 32, + .PABITS = 32, + .insn_flags = CPU_MIPS32R2 | ASE_MICROMIPS, + .mmu_type = MMU_TYPE_R4000, + }, + { /* A generic CPU providing MIPS32 Release 5 features. FIXME: Eventually this should be replaced by a real CPU model. */ .name = "mips32r5-generic", @@ -520,6 +561,51 @@ static const mips_def_t mips_defs[] = .mmu_type = MMU_TYPE_R4000, }, { + .name = "5KEc", + .CP0_PRid = 0x00018900, + .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) | + (MMU_TYPE_R4000 << CP0C0_MT), + .CP0_Config1 = MIPS_CONFIG1 | (31 << CP0C1_MMU) | + (1 << CP0C1_IS) | (4 << CP0C1_IL) | (1 << CP0C1_IA) | + (1 << CP0C1_DS) | (4 << CP0C1_DL) | (1 << CP0C1_DA) | + (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP), + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3, + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 4, + .SYNCI_Step = 32, + .CCRes = 2, + .CP0_Status_rw_bitmask = 0x32F8FFFF, + .SEGBITS = 42, + .PABITS = 36, + .insn_flags = CPU_MIPS64R2, + .mmu_type = MMU_TYPE_R4000, + }, + { + .name = "5KEf", + .CP0_PRid = 0x00018900, + .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) | + (MMU_TYPE_R4000 << CP0C0_MT), + .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (31 << CP0C1_MMU) | + (1 << CP0C1_IS) | (4 << CP0C1_IL) | (1 << CP0C1_IA) | + (1 << CP0C1_DS) | (4 << CP0C1_DL) | (1 << CP0C1_DA) | + (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP), + .CP0_Config2 = MIPS_CONFIG2, + .CP0_Config3 = MIPS_CONFIG3, + .CP0_LLAddr_rw_bitmask = 0, + .CP0_LLAddr_shift = 4, + .SYNCI_Step = 32, + .CCRes = 2, + .CP0_Status_rw_bitmask = 0x36F8FFFF, + .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) | + (1 << FCR0_D) | (1 << FCR0_S) | + (0x89 << FCR0_PRID) | (0x0 << FCR0_REV), + .SEGBITS = 42, + .PABITS = 36, + .insn_flags = CPU_MIPS64R2, + .mmu_type = MMU_TYPE_R4000, + }, + { /* A generic CPU supporting MIPS64 Release 6 ISA. FIXME: Support IEEE 754-2008 FP and misaligned memory accesses. Eventually this should be replaced by a real CPU model. */ @@ -559,10 +645,11 @@ static const mips_def_t mips_defs[] = { .name = "Loongson-2E", .CP0_PRid = 0x6302, - /*64KB I-cache and d-cache. 4 way with 32 bit cache line size*/ - .CP0_Config0 = (0x1<<17) | (0x1<<16) | (0x1<<11) | (0x1<<8) | (0x1<<5) | - (0x1<<4) | (0x1<<1), - /* Note: Config1 is only used internally, Loongson-2E has only Config0. */ + /* 64KB I-cache and d-cache. 4 way with 32 bit cache line size. */ + .CP0_Config0 = (0x1<<17) | (0x1<<16) | (0x1<<11) | (0x1<<8) | + (0x1<<5) | (0x1<<4) | (0x1<<1), + /* Note: Config1 is only used internally, + Loongson-2E has only Config0. */ .CP0_Config1 = (1 << CP0C1_FP) | (47 << CP0C1_MMU), .SYNCI_Step = 16, .CCRes = 2, @@ -574,21 +661,22 @@ static const mips_def_t mips_defs[] = .mmu_type = MMU_TYPE_R4000, }, { - .name = "Loongson-2F", - .CP0_PRid = 0x6303, - /*64KB I-cache and d-cache. 4 way with 32 bit cache line size*/ - .CP0_Config0 = (0x1<<17) | (0x1<<16) | (0x1<<11) | (0x1<<8) | (0x1<<5) | - (0x1<<4) | (0x1<<1), - /* Note: Config1 is only used internally, Loongson-2F has only Config0. */ - .CP0_Config1 = (1 << CP0C1_FP) | (47 << CP0C1_MMU), - .SYNCI_Step = 16, - .CCRes = 2, - .CP0_Status_rw_bitmask = 0xF5D0FF1F, /*bit5:7 not writable*/ - .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x1 << FCR0_REV), - .SEGBITS = 40, - .PABITS = 40, - .insn_flags = CPU_LOONGSON2F, - .mmu_type = MMU_TYPE_R4000, + .name = "Loongson-2F", + .CP0_PRid = 0x6303, + /* 64KB I-cache and d-cache. 4 way with 32 bit cache line size. */ + .CP0_Config0 = (0x1<<17) | (0x1<<16) | (0x1<<11) | (0x1<<8) | + (0x1<<5) | (0x1<<4) | (0x1<<1), + /* Note: Config1 is only used internally, + Loongson-2F has only Config0. */ + .CP0_Config1 = (1 << CP0C1_FP) | (47 << CP0C1_MMU), + .SYNCI_Step = 16, + .CCRes = 2, + .CP0_Status_rw_bitmask = 0xF5D0FF1F, /* Bits 7:5 not writable. */ + .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x1 << FCR0_REV), + .SEGBITS = 40, + .PABITS = 40, + .insn_flags = CPU_LOONGSON2F, + .mmu_type = MMU_TYPE_R4000, }, { /* A generic CPU providing MIPS64 ASE DSP 2 features. diff --git a/translate-all.c b/translate-all.c index cf05472008..d930a5ce67 100644 --- a/translate-all.c +++ b/translate-all.c @@ -1540,7 +1540,7 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr) branch. */ #if defined(TARGET_MIPS) if ((env->hflags & MIPS_HFLAG_BMASK) != 0 && n > 1) { - env->active_tc.PC -= 4; + env->active_tc.PC -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4); cpu->icount_decr.u16.low++; env->hflags &= ~MIPS_HFLAG_BMASK; } |