summaryrefslogtreecommitdiffstats
path: root/qemu/target-mips/op_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/target-mips/op_helper.c')
-rw-r--r--qemu/target-mips/op_helper.c458
1 files changed, 309 insertions, 149 deletions
diff --git a/qemu/target-mips/op_helper.c b/qemu/target-mips/op_helper.c
index db4f6b946..4417e6ba2 100644
--- a/qemu/target-mips/op_helper.c
+++ b/qemu/target-mips/op_helper.c
@@ -16,55 +16,33 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#include <stdlib.h>
+#include "qemu/osdep.h"
#include "cpu.h"
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
#include "exec/cpu_ldst.h"
#include "sysemu/kvm.h"
-#ifndef CONFIG_USER_ONLY
-static inline void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global);
-#endif
-
/*****************************************************************************/
/* Exceptions processing helpers */
-static inline void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env,
- uint32_t exception,
- int error_code,
- uintptr_t pc)
+void helper_raise_exception_err(CPUMIPSState *env, uint32_t exception,
+ int error_code)
{
- CPUState *cs = CPU(mips_env_get_cpu(env));
-
- if (exception < EXCP_SC) {
- qemu_log("%s: %d %d\n", __func__, exception, error_code);
- }
- cs->exception_index = exception;
- env->error_code = error_code;
-
- if (pc) {
- /* now we have a real cpu fault */
- cpu_restore_state(cs, pc);
- }
-
- cpu_loop_exit(cs);
+ do_raise_exception_err(env, exception, error_code, 0);
}
-static inline void QEMU_NORETURN do_raise_exception(CPUMIPSState *env,
- uint32_t exception,
- uintptr_t pc)
+void helper_raise_exception(CPUMIPSState *env, uint32_t exception)
{
- do_raise_exception_err(env, exception, 0, pc);
+ do_raise_exception(env, exception, GETPC());
}
-void helper_raise_exception_err(CPUMIPSState *env, uint32_t exception,
- int error_code)
+void helper_raise_exception_debug(CPUMIPSState *env)
{
- do_raise_exception_err(env, exception, error_code, 0);
+ do_raise_exception(env, EXCP_DEBUG, 0);
}
-void helper_raise_exception(CPUMIPSState *env, uint32_t exception)
+static void raise_exception(CPUMIPSState *env, uint32_t exception)
{
do_raise_exception(env, exception, 0);
}
@@ -72,21 +50,21 @@ void helper_raise_exception(CPUMIPSState *env, uint32_t exception)
#if defined(CONFIG_USER_ONLY)
#define HELPER_LD(name, insn, type) \
static inline type do_##name(CPUMIPSState *env, target_ulong addr, \
- int mem_idx) \
+ int mem_idx, uintptr_t retaddr) \
{ \
- return (type) cpu_##insn##_data(env, addr); \
+ return (type) cpu_##insn##_data_ra(env, addr, retaddr); \
}
#else
#define HELPER_LD(name, insn, type) \
static inline type do_##name(CPUMIPSState *env, target_ulong addr, \
- int mem_idx) \
+ int mem_idx, uintptr_t retaddr) \
{ \
switch (mem_idx) \
{ \
- case 0: return (type) cpu_##insn##_kernel(env, addr); break; \
- case 1: return (type) cpu_##insn##_super(env, addr); break; \
+ case 0: return (type) cpu_##insn##_kernel_ra(env, addr, retaddr); \
+ case 1: return (type) cpu_##insn##_super_ra(env, addr, retaddr); \
default: \
- case 2: return (type) cpu_##insn##_user(env, addr); break; \
+ case 2: return (type) cpu_##insn##_user_ra(env, addr, retaddr); \
} \
}
#endif
@@ -99,21 +77,21 @@ HELPER_LD(ld, ldq, int64_t)
#if defined(CONFIG_USER_ONLY)
#define HELPER_ST(name, insn, type) \
static inline void do_##name(CPUMIPSState *env, target_ulong addr, \
- type val, int mem_idx) \
+ type val, int mem_idx, uintptr_t retaddr) \
{ \
- cpu_##insn##_data(env, addr, val); \
+ cpu_##insn##_data_ra(env, addr, val, retaddr); \
}
#else
#define HELPER_ST(name, insn, type) \
static inline void do_##name(CPUMIPSState *env, target_ulong addr, \
- type val, int mem_idx) \
+ type val, int mem_idx, uintptr_t retaddr) \
{ \
switch (mem_idx) \
{ \
- case 0: cpu_##insn##_kernel(env, addr, val); break; \
- case 1: cpu_##insn##_super(env, addr, val); break; \
+ case 0: cpu_##insn##_kernel_ra(env, addr, val, retaddr); break; \
+ case 1: cpu_##insn##_super_ra(env, addr, val, retaddr); break; \
default: \
- case 2: cpu_##insn##_user(env, addr, val); break; \
+ case 2: cpu_##insn##_user_ra(env, addr, val, retaddr); break; \
} \
}
#endif
@@ -292,14 +270,15 @@ target_ulong helper_bitswap(target_ulong rt)
static inline hwaddr do_translate_address(CPUMIPSState *env,
target_ulong address,
- int rw)
+ int rw, uintptr_t retaddr)
{
hwaddr lladdr;
+ CPUState *cs = CPU(mips_env_get_cpu(env));
lladdr = cpu_mips_translate_address(env, address, rw);
if (lladdr == -1LL) {
- cpu_loop_exit(CPU(mips_env_get_cpu(env)));
+ cpu_loop_exit_restore(cs, retaddr);
} else {
return lladdr;
}
@@ -310,10 +289,10 @@ target_ulong helper_##name(CPUMIPSState *env, target_ulong arg, int mem_idx) \
{ \
if (arg & almask) { \
env->CP0_BadVAddr = arg; \
- helper_raise_exception(env, EXCP_AdEL); \
+ do_raise_exception(env, EXCP_AdEL, GETPC()); \
} \
- env->lladdr = do_translate_address(env, arg, 0); \
- env->llval = do_##insn(env, arg, mem_idx); \
+ env->lladdr = do_translate_address(env, arg, 0, GETPC()); \
+ env->llval = do_##insn(env, arg, mem_idx, GETPC()); \
return env->llval; \
}
HELPER_LD_ATOMIC(ll, lw, 0x3)
@@ -330,12 +309,12 @@ target_ulong helper_##name(CPUMIPSState *env, target_ulong arg1, \
\
if (arg2 & almask) { \
env->CP0_BadVAddr = arg2; \
- helper_raise_exception(env, EXCP_AdES); \
+ do_raise_exception(env, EXCP_AdES, GETPC()); \
} \
- if (do_translate_address(env, arg2, 1) == env->lladdr) { \
- tmp = do_##ld_insn(env, arg2, mem_idx); \
+ if (do_translate_address(env, arg2, 1, GETPC()) == env->lladdr) { \
+ tmp = do_##ld_insn(env, arg2, mem_idx, GETPC()); \
if (tmp == env->llval) { \
- do_##st_insn(env, arg2, arg1, mem_idx); \
+ do_##st_insn(env, arg2, arg1, mem_idx, GETPC()); \
return 1; \
} \
} \
@@ -359,31 +338,43 @@ HELPER_ST_ATOMIC(scd, ld, sd, 0x7)
void helper_swl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
int mem_idx)
{
- do_sb(env, arg2, (uint8_t)(arg1 >> 24), mem_idx);
+ do_sb(env, arg2, (uint8_t)(arg1 >> 24), mem_idx, GETPC());
- if (GET_LMASK(arg2) <= 2)
- do_sb(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16), mem_idx);
+ if (GET_LMASK(arg2) <= 2) {
+ do_sb(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16), mem_idx,
+ GETPC());
+ }
- if (GET_LMASK(arg2) <= 1)
- do_sb(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8), mem_idx);
+ if (GET_LMASK(arg2) <= 1) {
+ do_sb(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8), mem_idx,
+ GETPC());
+ }
- if (GET_LMASK(arg2) == 0)
- do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)arg1, mem_idx);
+ if (GET_LMASK(arg2) == 0) {
+ do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)arg1, mem_idx,
+ GETPC());
+ }
}
void helper_swr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
int mem_idx)
{
- do_sb(env, arg2, (uint8_t)arg1, mem_idx);
+ do_sb(env, arg2, (uint8_t)arg1, mem_idx, GETPC());
- if (GET_LMASK(arg2) >= 1)
- do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
+ if (GET_LMASK(arg2) >= 1) {
+ do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx,
+ GETPC());
+ }
- if (GET_LMASK(arg2) >= 2)
- do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
+ if (GET_LMASK(arg2) >= 2) {
+ do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx,
+ GETPC());
+ }
- if (GET_LMASK(arg2) == 3)
- do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
+ if (GET_LMASK(arg2) == 3) {
+ do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx,
+ GETPC());
+ }
}
#if defined(TARGET_MIPS64)
@@ -399,55 +390,83 @@ void helper_swr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
void helper_sdl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
int mem_idx)
{
- do_sb(env, arg2, (uint8_t)(arg1 >> 56), mem_idx);
+ do_sb(env, arg2, (uint8_t)(arg1 >> 56), mem_idx, GETPC());
- if (GET_LMASK64(arg2) <= 6)
- do_sb(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48), mem_idx);
+ if (GET_LMASK64(arg2) <= 6) {
+ do_sb(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48), mem_idx,
+ GETPC());
+ }
- if (GET_LMASK64(arg2) <= 5)
- do_sb(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40), mem_idx);
+ if (GET_LMASK64(arg2) <= 5) {
+ do_sb(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40), mem_idx,
+ GETPC());
+ }
- if (GET_LMASK64(arg2) <= 4)
- do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32), mem_idx);
+ if (GET_LMASK64(arg2) <= 4) {
+ do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32), mem_idx,
+ GETPC());
+ }
- if (GET_LMASK64(arg2) <= 3)
- do_sb(env, GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24), mem_idx);
+ if (GET_LMASK64(arg2) <= 3) {
+ do_sb(env, GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24), mem_idx,
+ GETPC());
+ }
- if (GET_LMASK64(arg2) <= 2)
- do_sb(env, GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16), mem_idx);
+ if (GET_LMASK64(arg2) <= 2) {
+ do_sb(env, GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16), mem_idx,
+ GETPC());
+ }
- if (GET_LMASK64(arg2) <= 1)
- do_sb(env, GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8), mem_idx);
+ if (GET_LMASK64(arg2) <= 1) {
+ do_sb(env, GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8), mem_idx,
+ GETPC());
+ }
- if (GET_LMASK64(arg2) <= 0)
- do_sb(env, GET_OFFSET(arg2, 7), (uint8_t)arg1, mem_idx);
+ if (GET_LMASK64(arg2) <= 0) {
+ do_sb(env, GET_OFFSET(arg2, 7), (uint8_t)arg1, mem_idx,
+ GETPC());
+ }
}
void helper_sdr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
int mem_idx)
{
- do_sb(env, arg2, (uint8_t)arg1, mem_idx);
+ do_sb(env, arg2, (uint8_t)arg1, mem_idx, GETPC());
- if (GET_LMASK64(arg2) >= 1)
- do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
+ if (GET_LMASK64(arg2) >= 1) {
+ do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx,
+ GETPC());
+ }
- if (GET_LMASK64(arg2) >= 2)
- do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
+ if (GET_LMASK64(arg2) >= 2) {
+ do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx,
+ GETPC());
+ }
- if (GET_LMASK64(arg2) >= 3)
- do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
+ if (GET_LMASK64(arg2) >= 3) {
+ do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx,
+ GETPC());
+ }
- if (GET_LMASK64(arg2) >= 4)
- do_sb(env, GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), mem_idx);
+ if (GET_LMASK64(arg2) >= 4) {
+ do_sb(env, GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), mem_idx,
+ GETPC());
+ }
- if (GET_LMASK64(arg2) >= 5)
- do_sb(env, GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), mem_idx);
+ if (GET_LMASK64(arg2) >= 5) {
+ do_sb(env, GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), mem_idx,
+ GETPC());
+ }
- if (GET_LMASK64(arg2) >= 6)
- do_sb(env, GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), mem_idx);
+ if (GET_LMASK64(arg2) >= 6) {
+ do_sb(env, GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), mem_idx,
+ GETPC());
+ }
- if (GET_LMASK64(arg2) == 7)
- do_sb(env, GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), mem_idx);
+ if (GET_LMASK64(arg2) == 7) {
+ do_sb(env, GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), mem_idx,
+ GETPC());
+ }
}
#endif /* TARGET_MIPS64 */
@@ -464,13 +483,14 @@ void helper_lwm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
for (i = 0; i < base_reglist; i++) {
env->active_tc.gpr[multiple_regs[i]] =
- (target_long)do_lw(env, addr, mem_idx);
+ (target_long)do_lw(env, addr, mem_idx, GETPC());
addr += 4;
}
}
if (do_r31) {
- env->active_tc.gpr[31] = (target_long)do_lw(env, addr, mem_idx);
+ env->active_tc.gpr[31] = (target_long)do_lw(env, addr, mem_idx,
+ GETPC());
}
}
@@ -484,13 +504,14 @@ void helper_swm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
target_ulong i;
for (i = 0; i < base_reglist; i++) {
- do_sw(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx);
+ do_sw(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx,
+ GETPC());
addr += 4;
}
}
if (do_r31) {
- do_sw(env, addr, env->active_tc.gpr[31], mem_idx);
+ do_sw(env, addr, env->active_tc.gpr[31], mem_idx, GETPC());
}
}
@@ -505,13 +526,14 @@ void helper_ldm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
target_ulong i;
for (i = 0; i < base_reglist; i++) {
- env->active_tc.gpr[multiple_regs[i]] = do_ld(env, addr, mem_idx);
+ env->active_tc.gpr[multiple_regs[i]] = do_ld(env, addr, mem_idx,
+ GETPC());
addr += 8;
}
}
if (do_r31) {
- env->active_tc.gpr[31] = do_ld(env, addr, mem_idx);
+ env->active_tc.gpr[31] = do_ld(env, addr, mem_idx, GETPC());
}
}
@@ -525,13 +547,14 @@ void helper_sdm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
target_ulong i;
for (i = 0; i < base_reglist; i++) {
- do_sd(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx);
+ do_sd(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx,
+ GETPC());
addr += 8;
}
}
if (do_r31) {
- do_sd(env, addr, env->active_tc.gpr[31], mem_idx);
+ do_sd(env, addr, env->active_tc.gpr[31], mem_idx, GETPC());
}
}
#endif
@@ -548,6 +571,14 @@ static bool mips_vpe_is_wfi(MIPSCPU *c)
return cpu->halted && mips_vpe_active(env);
}
+static bool mips_vp_is_wfi(MIPSCPU *c)
+{
+ CPUState *cpu = CPU(c);
+ CPUMIPSState *env = &c->env;
+
+ return cpu->halted && mips_vp_active(env);
+}
+
static inline void mips_vpe_wake(MIPSCPU *c)
{
/* Dont set ->halted = 0 directly, let it be done via cpu_has_work
@@ -858,6 +889,16 @@ target_ulong helper_mfc0_lladdr(CPUMIPSState *env)
return (int32_t)(env->lladdr >> env->CP0_LLAddr_shift);
}
+target_ulong helper_mfc0_maar(CPUMIPSState *env)
+{
+ return (int32_t) env->CP0_MAAR[env->CP0_MAARI];
+}
+
+target_ulong helper_mfhc0_maar(CPUMIPSState *env)
+{
+ return env->CP0_MAAR[env->CP0_MAARI] >> 32;
+}
+
target_ulong helper_mfc0_watchlo(CPUMIPSState *env, uint32_t sel)
{
return (int32_t)env->CP0_WatchLo[sel];
@@ -924,6 +965,11 @@ target_ulong helper_dmfc0_lladdr(CPUMIPSState *env)
return env->lladdr >> env->CP0_LLAddr_shift;
}
+target_ulong helper_dmfc0_maar(CPUMIPSState *env)
+{
+ return env->CP0_MAAR[env->CP0_MAARI];
+}
+
target_ulong helper_dmfc0_watchlo(CPUMIPSState *env, uint32_t sel)
{
return env->CP0_WatchLo[sel];
@@ -1330,6 +1376,13 @@ void helper_mtc0_hwrena(CPUMIPSState *env, target_ulong arg1)
{
uint32_t mask = 0x0000000F;
+ if ((env->CP0_Config1 & (1 << CP0C1_PC)) &&
+ (env->insn_flags & ISA_MIPS32R6)) {
+ mask |= (1 << 4);
+ }
+ if (env->insn_flags & ISA_MIPS32R6) {
+ mask |= (1 << 5);
+ }
if (env->CP0_Config3 & (1 << CP0C3_ULRI)) {
mask |= (1 << 29);
@@ -1540,6 +1593,36 @@ void helper_mtc0_lladdr(CPUMIPSState *env, target_ulong arg1)
env->lladdr = (env->lladdr & ~mask) | (arg1 & mask);
}
+#define MTC0_MAAR_MASK(env) \
+ ((0x1ULL << 63) | ((env->PAMask >> 4) & ~0xFFFull) | 0x3)
+
+void helper_mtc0_maar(CPUMIPSState *env, target_ulong arg1)
+{
+ env->CP0_MAAR[env->CP0_MAARI] = arg1 & MTC0_MAAR_MASK(env);
+}
+
+void helper_mthc0_maar(CPUMIPSState *env, target_ulong arg1)
+{
+ env->CP0_MAAR[env->CP0_MAARI] =
+ (((uint64_t) arg1 << 32) & MTC0_MAAR_MASK(env)) |
+ (env->CP0_MAAR[env->CP0_MAARI] & 0x00000000ffffffffULL);
+}
+
+void helper_mtc0_maari(CPUMIPSState *env, target_ulong arg1)
+{
+ int index = arg1 & 0x3f;
+ if (index == 0x3f) {
+ /* Software may write all ones to INDEX to determine the
+ maximum value supported. */
+ env->CP0_MAARI = MIPS_MAAR_MAX - 1;
+ } else if (index < MIPS_MAAR_MAX) {
+ env->CP0_MAARI = index;
+ }
+ /* Other than the all ones, if the
+ value written is not supported, then INDEX is unchanged
+ from its previous value. */
+}
+
void helper_mtc0_watchlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
{
/* Watch exceptions for instructions, data loads, data stores
@@ -1594,9 +1677,31 @@ void helper_mtc0_performance0(CPUMIPSState *env, target_ulong arg1)
env->CP0_Performance0 = arg1 & 0x000007ff;
}
+void helper_mtc0_errctl(CPUMIPSState *env, target_ulong arg1)
+{
+ int32_t wst = arg1 & (1 << CP0EC_WST);
+ int32_t spr = arg1 & (1 << CP0EC_SPR);
+ int32_t itc = env->itc_tag ? (arg1 & (1 << CP0EC_ITC)) : 0;
+
+ env->CP0_ErrCtl = wst | spr | itc;
+
+ if (itc && !wst && !spr) {
+ env->hflags |= MIPS_HFLAG_ITC_CACHE;
+ } else {
+ env->hflags &= ~MIPS_HFLAG_ITC_CACHE;
+ }
+}
+
void helper_mtc0_taglo(CPUMIPSState *env, target_ulong arg1)
{
- env->CP0_TagLo = arg1 & 0xFFFFFCF6;
+ if (env->hflags & MIPS_HFLAG_ITC_CACHE) {
+ /* If CACHE instruction is configured for ITC tags then make all
+ CP0.TagLo bits writable. The actual write to ITC Configuration
+ Tag will take care of the read-only bits. */
+ env->CP0_TagLo = arg1;
+ } else {
+ env->CP0_TagLo = arg1 & 0xFFFFFCF6;
+ }
}
void helper_mtc0_datalo(CPUMIPSState *env, target_ulong arg1)
@@ -1791,13 +1896,13 @@ target_ulong helper_yield(CPUMIPSState *env, target_ulong arg)
env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
- helper_raise_exception(env, EXCP_THREAD);
+ do_raise_exception(env, EXCP_THREAD, GETPC());
}
}
} else if (arg1 == 0) {
if (0 /* TODO: TC underflow */) {
env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
- helper_raise_exception(env, EXCP_THREAD);
+ do_raise_exception(env, EXCP_THREAD, GETPC());
} else {
// TODO: Deallocate TC
}
@@ -1805,22 +1910,53 @@ target_ulong helper_yield(CPUMIPSState *env, target_ulong arg)
/* Yield qualifier inputs not implemented. */
env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
- helper_raise_exception(env, EXCP_THREAD);
+ do_raise_exception(env, EXCP_THREAD, GETPC());
}
return env->CP0_YQMask;
}
+/* R6 Multi-threading */
#ifndef CONFIG_USER_ONLY
-/* TLB management */
-static void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global)
+target_ulong helper_dvp(CPUMIPSState *env)
{
- MIPSCPU *cpu = mips_env_get_cpu(env);
+ CPUState *other_cs = first_cpu;
+ target_ulong prev = env->CP0_VPControl;
+
+ if (!((env->CP0_VPControl >> CP0VPCtl_DIS) & 1)) {
+ CPU_FOREACH(other_cs) {
+ MIPSCPU *other_cpu = MIPS_CPU(other_cs);
+ /* Turn off all VPs except the one executing the dvp. */
+ if (&other_cpu->env != env) {
+ mips_vpe_sleep(other_cpu);
+ }
+ }
+ env->CP0_VPControl |= (1 << CP0VPCtl_DIS);
+ }
+ return prev;
+}
- /* Flush qemu's TLB and discard all shadowed entries. */
- tlb_flush(CPU(cpu), flush_global);
- env->tlb->tlb_in_use = env->tlb->nb_tlb;
+target_ulong helper_evp(CPUMIPSState *env)
+{
+ CPUState *other_cs = first_cpu;
+ target_ulong prev = env->CP0_VPControl;
+
+ if ((env->CP0_VPControl >> CP0VPCtl_DIS) & 1) {
+ CPU_FOREACH(other_cs) {
+ MIPSCPU *other_cpu = MIPS_CPU(other_cs);
+ if ((&other_cpu->env != env) && !mips_vp_is_wfi(other_cpu)) {
+ /* If the VP is WFI, don't disturb its sleep.
+ * Otherwise, wake it up. */
+ mips_vpe_wake(other_cpu);
+ }
+ }
+ env->CP0_VPControl &= ~(1 << CP0VPCtl_DIS);
+ }
+ return prev;
}
+#endif /* !CONFIG_USER_ONLY */
+#ifndef CONFIG_USER_ONLY
+/* TLB management */
static void r4k_mips_tlb_flush_extra (CPUMIPSState *env, int first)
{
/* Discard entries from env->tlb[first] onwards. */
@@ -2158,48 +2294,52 @@ void helper_deret(CPUMIPSState *env)
}
#endif /* !CONFIG_USER_ONLY */
-target_ulong helper_rdhwr_cpunum(CPUMIPSState *env)
+static inline void check_hwrena(CPUMIPSState *env, int reg, uintptr_t pc)
{
- if ((env->hflags & MIPS_HFLAG_CP0) ||
- (env->CP0_HWREna & (1 << 0)))
- return env->CP0_EBase & 0x3ff;
- else
- helper_raise_exception(env, EXCP_RI);
+ if ((env->hflags & MIPS_HFLAG_CP0) || (env->CP0_HWREna & (1 << reg))) {
+ return;
+ }
+ do_raise_exception(env, EXCP_RI, pc);
+}
- return 0;
+target_ulong helper_rdhwr_cpunum(CPUMIPSState *env)
+{
+ check_hwrena(env, 0, GETPC());
+ return env->CP0_EBase & 0x3ff;
}
target_ulong helper_rdhwr_synci_step(CPUMIPSState *env)
{
- if ((env->hflags & MIPS_HFLAG_CP0) ||
- (env->CP0_HWREna & (1 << 1)))
- return env->SYNCI_Step;
- else
- helper_raise_exception(env, EXCP_RI);
-
- return 0;
+ check_hwrena(env, 1, GETPC());
+ return env->SYNCI_Step;
}
target_ulong helper_rdhwr_cc(CPUMIPSState *env)
{
- if ((env->hflags & MIPS_HFLAG_CP0) ||
- (env->CP0_HWREna & (1 << 2)))
- return env->CP0_Count;
- else
- helper_raise_exception(env, EXCP_RI);
-
- return 0;
+ check_hwrena(env, 2, GETPC());
+#ifdef CONFIG_USER_ONLY
+ return env->CP0_Count;
+#else
+ return (int32_t)cpu_mips_get_count(env);
+#endif
}
target_ulong helper_rdhwr_ccres(CPUMIPSState *env)
{
- if ((env->hflags & MIPS_HFLAG_CP0) ||
- (env->CP0_HWREna & (1 << 3)))
- return env->CCRes;
- else
- helper_raise_exception(env, EXCP_RI);
+ check_hwrena(env, 3, GETPC());
+ return env->CCRes;
+}
- return 0;
+target_ulong helper_rdhwr_performance(CPUMIPSState *env)
+{
+ check_hwrena(env, 4, GETPC());
+ return env->CP0_Performance0;
+}
+
+target_ulong helper_rdhwr_xnp(CPUMIPSState *env)
+{
+ check_hwrena(env, 5, GETPC());
+ return (env->CP0_Config5 >> CP0C5_XNP) & 1;
}
void helper_pmon(CPUMIPSState *env, int function)
@@ -2234,7 +2374,9 @@ void helper_wait(CPUMIPSState *env)
cs->halted = 1;
cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
- helper_raise_exception(env, EXCP_HLT);
+ /* Last instruction in the block, PC was updated before
+ - no need to recover PC and icount */
+ raise_exception(env, EXCP_HLT);
}
#if !defined(CONFIG_USER_ONLY)
@@ -2295,9 +2437,9 @@ void mips_cpu_unassigned_access(CPUState *cs, hwaddr addr,
}
if (is_exec) {
- helper_raise_exception(env, EXCP_IBE);
+ raise_exception(env, EXCP_IBE);
} else {
- helper_raise_exception(env, EXCP_DBE);
+ raise_exception(env, EXCP_DBE);
}
}
#endif /* !CONFIG_USER_ONLY */
@@ -2332,7 +2474,7 @@ target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg)
arg1 = (int32_t)
((env->CP0_Status & (1 << CP0St_FR)) >> CP0St_FR);
} else {
- helper_raise_exception(env, EXCP_RI);
+ do_raise_exception(env, EXCP_RI, GETPC());
}
}
break;
@@ -2375,7 +2517,7 @@ void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt)
env->CP0_Status &= ~(1 << CP0St_FR);
compute_hflags(env);
} else {
- helper_raise_exception(env, EXCP_RI);
+ do_raise_exception(env, EXCP_RI, GETPC());
}
break;
case 4:
@@ -2387,7 +2529,7 @@ void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt)
env->CP0_Status |= (1 << CP0St_FR);
compute_hflags(env);
} else {
- helper_raise_exception(env, EXCP_RI);
+ do_raise_exception(env, EXCP_RI, GETPC());
}
break;
case 5:
@@ -2518,6 +2660,7 @@ uint64_t helper_float_cvtd_s(CPUMIPSState *env, uint32_t fst0)
uint64_t fdt2;
fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
+ fdt2 = float64_maybe_silence_nan(fdt2);
update_fcr31(env, GETPC());
return fdt2;
}
@@ -2607,6 +2750,7 @@ uint32_t helper_float_cvts_d(CPUMIPSState *env, uint64_t fdt0)
uint32_t fst2;
fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
+ fst2 = float32_maybe_silence_nan(fst2);
update_fcr31(env, GETPC());
return fst2;
}
@@ -3628,7 +3772,7 @@ FOP_CONDN_S(sne, (float32_lt(fst1, fst0, &env->active_fpu.fp_status)
#if !defined(CONFIG_USER_ONLY)
#define MEMOP_IDX(DF) \
TCGMemOpIdx oi = make_memop_idx(MO_TE | DF | MO_UNALN, \
- cpu_mmu_index(env));
+ cpu_mmu_index(env, false));
#else
#define MEMOP_IDX(DF)
#endif
@@ -3684,7 +3828,7 @@ void helper_msa_st_ ## TYPE(CPUMIPSState *env, uint32_t wd, \
target_ulong addr) \
{ \
wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \
- int mmu_idx = cpu_mmu_index(env); \
+ int mmu_idx = cpu_mmu_index(env, false); \
int i; \
MEMOP_IDX(DF) \
ensure_writable_pages(env, addr, mmu_idx, GETRA()); \
@@ -3704,3 +3848,19 @@ MSA_ST_DF(DF_HALF, h, cpu_stw_data)
MSA_ST_DF(DF_WORD, w, cpu_stl_data)
MSA_ST_DF(DF_DOUBLE, d, cpu_stq_data)
#endif
+
+void helper_cache(CPUMIPSState *env, target_ulong addr, uint32_t op)
+{
+#ifndef CONFIG_USER_ONLY
+ target_ulong index = addr & 0x1fffffff;
+ if (op == 9) {
+ /* Index Store Tag */
+ memory_region_dispatch_write(env->itc_tag, index, env->CP0_TagLo,
+ 8, MEMTXATTRS_UNSPECIFIED);
+ } else if (op == 5) {
+ /* Index Load Tag */
+ memory_region_dispatch_read(env->itc_tag, index, &env->CP0_TagLo,
+ 8, MEMTXATTRS_UNSPECIFIED);
+ }
+#endif
+}