aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2014-12-17 16:25:21 +0000
committerPeter Maydell <peter.maydell@linaro.org>2014-12-17 16:25:21 +0000
commit84afc4dd56648ac302c7b5a917e95ca7b1239695 (patch)
tree7f1905105f79a12f7f83e5bb033f80192ae9070c
parent339aaf5b7f26d1e638641c59a44883b7654bd8ea (diff)
parentd4fa5354a246a1c6cb538a5d8ebcc21206d502fb (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.c10
-rw-r--r--linux-user/main.c2
-rw-r--r--target-mips/cpu.h124
-rw-r--r--target-mips/gdbstub.c56
-rw-r--r--target-mips/helper.c17
-rw-r--r--target-mips/helper.h1
-rw-r--r--target-mips/msa_helper.c69
-rw-r--r--target-mips/op_helper.c433
-rw-r--r--target-mips/translate.c170
-rw-r--r--target-mips/translate_init.c128
-rw-r--r--translate-all.c2
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;
}