blob: 809a061e296b607ac821a913b5b33eac7c9b48f5 [file] [log] [blame]
bellard6af0bf92005-07-02 14:58:51 +00001/*
2 * MIPS emulation helpers for qemu.
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard6af0bf92005-07-02 14:58:51 +00004 * Copyright (c) 2004-2005 Jocelyn Mayer
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
bellard6af0bf92005-07-02 14:58:51 +000018 */
ths2d0e9442007-04-02 15:54:05 +000019#include <stdlib.h>
Blue Swirl3e457172011-07-13 12:44:15 +000020#include "cpu.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010021#include "qemu/host-utils.h"
Richard Henderson2ef61752014-04-07 22:31:41 -070022#include "exec/helper-proto.h"
Paolo Bonzinif08b6172014-03-28 19:42:10 +010023#include "exec/cpu_ldst.h"
James Hoganeddedd52014-07-28 12:37:50 +010024#include "sysemu/kvm.h"
Blue Swirl3e457172011-07-13 12:44:15 +000025
Paolo Bonzini83dae092010-06-29 09:58:49 +020026#ifndef CONFIG_USER_ONLY
Andreas Färber7db13fa2012-03-14 01:38:22 +010027static inline void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global);
Paolo Bonzini83dae092010-06-29 09:58:49 +020028#endif
29
bellard6af0bf92005-07-02 14:58:51 +000030/*****************************************************************************/
31/* Exceptions processing helpers */
bellard6af0bf92005-07-02 14:58:51 +000032
Aurelien Jarno5f7319c2012-10-28 19:34:03 +010033static inline void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env,
34 uint32_t exception,
35 int error_code,
36 uintptr_t pc)
bellard6af0bf92005-07-02 14:58:51 +000037{
Andreas Färber27103422013-08-26 08:31:06 +020038 CPUState *cs = CPU(mips_env_get_cpu(env));
39
陳韋任 (Wei-Ren Chen)0f0b9392012-12-11 00:15:55 +080040 if (exception < EXCP_SC) {
Richard Hendersonc8557012015-08-03 11:49:12 -070041 qemu_log_mask(CPU_LOG_INT, "%s: %d %d\n",
42 __func__, exception, error_code);
陳韋任 (Wei-Ren Chen)0f0b9392012-12-11 00:15:55 +080043 }
Andreas Färber27103422013-08-26 08:31:06 +020044 cs->exception_index = exception;
bellard6af0bf92005-07-02 14:58:51 +000045 env->error_code = error_code;
Aurelien Jarno5f7319c2012-10-28 19:34:03 +010046
47 if (pc) {
48 /* now we have a real cpu fault */
Andreas Färber3f38f302013-09-01 16:51:34 +020049 cpu_restore_state(cs, pc);
Aurelien Jarno5f7319c2012-10-28 19:34:03 +010050 }
51
Andreas Färber5638d182013-08-27 17:52:12 +020052 cpu_loop_exit(cs);
bellard6af0bf92005-07-02 14:58:51 +000053}
54
Aurelien Jarno5f7319c2012-10-28 19:34:03 +010055static inline void QEMU_NORETURN do_raise_exception(CPUMIPSState *env,
56 uint32_t exception,
57 uintptr_t pc)
58{
59 do_raise_exception_err(env, exception, 0, pc);
60}
61
62void helper_raise_exception_err(CPUMIPSState *env, uint32_t exception,
63 int error_code)
64{
65 do_raise_exception_err(env, exception, error_code, 0);
66}
67
Blue Swirl895c2d02012-09-02 14:52:59 +000068void helper_raise_exception(CPUMIPSState *env, uint32_t exception)
bellard6af0bf92005-07-02 14:58:51 +000069{
Aurelien Jarno5f7319c2012-10-28 19:34:03 +010070 do_raise_exception(env, exception, 0);
bellard6af0bf92005-07-02 14:58:51 +000071}
72
Aurelien Jarno0ae43042009-11-30 15:32:47 +010073#if defined(CONFIG_USER_ONLY)
74#define HELPER_LD(name, insn, type) \
Blue Swirl895c2d02012-09-02 14:52:59 +000075static inline type do_##name(CPUMIPSState *env, target_ulong addr, \
76 int mem_idx) \
Aurelien Jarno0ae43042009-11-30 15:32:47 +010077{ \
Peter Maydell15353002015-01-20 15:19:33 +000078 return (type) cpu_##insn##_data(env, addr); \
Aurelien Jarno0ae43042009-11-30 15:32:47 +010079}
80#else
81#define HELPER_LD(name, insn, type) \
Blue Swirl895c2d02012-09-02 14:52:59 +000082static inline type do_##name(CPUMIPSState *env, target_ulong addr, \
83 int mem_idx) \
Aurelien Jarno0ae43042009-11-30 15:32:47 +010084{ \
85 switch (mem_idx) \
86 { \
Blue Swirl895c2d02012-09-02 14:52:59 +000087 case 0: return (type) cpu_##insn##_kernel(env, addr); break; \
88 case 1: return (type) cpu_##insn##_super(env, addr); break; \
Aurelien Jarno0ae43042009-11-30 15:32:47 +010089 default: \
Blue Swirl895c2d02012-09-02 14:52:59 +000090 case 2: return (type) cpu_##insn##_user(env, addr); break; \
Aurelien Jarno0ae43042009-11-30 15:32:47 +010091 } \
92}
93#endif
Aurelien Jarno0ae43042009-11-30 15:32:47 +010094HELPER_LD(lw, ldl, int32_t)
Yongbok Kimadc370a2015-06-01 12:13:24 +010095#if defined(TARGET_MIPS64)
Aurelien Jarno0ae43042009-11-30 15:32:47 +010096HELPER_LD(ld, ldq, int64_t)
Yongbok Kimadc370a2015-06-01 12:13:24 +010097#endif
Aurelien Jarno0ae43042009-11-30 15:32:47 +010098#undef HELPER_LD
99
100#if defined(CONFIG_USER_ONLY)
101#define HELPER_ST(name, insn, type) \
Blue Swirl895c2d02012-09-02 14:52:59 +0000102static inline void do_##name(CPUMIPSState *env, target_ulong addr, \
103 type val, int mem_idx) \
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100104{ \
Peter Maydell15353002015-01-20 15:19:33 +0000105 cpu_##insn##_data(env, addr, val); \
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100106}
107#else
108#define HELPER_ST(name, insn, type) \
Blue Swirl895c2d02012-09-02 14:52:59 +0000109static inline void do_##name(CPUMIPSState *env, target_ulong addr, \
110 type val, int mem_idx) \
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100111{ \
112 switch (mem_idx) \
113 { \
Blue Swirl895c2d02012-09-02 14:52:59 +0000114 case 0: cpu_##insn##_kernel(env, addr, val); break; \
115 case 1: cpu_##insn##_super(env, addr, val); break; \
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100116 default: \
Blue Swirl895c2d02012-09-02 14:52:59 +0000117 case 2: cpu_##insn##_user(env, addr, val); break; \
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100118 } \
119}
120#endif
121HELPER_ST(sb, stb, uint8_t)
122HELPER_ST(sw, stl, uint32_t)
Yongbok Kimadc370a2015-06-01 12:13:24 +0100123#if defined(TARGET_MIPS64)
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100124HELPER_ST(sd, stq, uint64_t)
Yongbok Kimadc370a2015-06-01 12:13:24 +0100125#endif
Aurelien Jarno0ae43042009-11-30 15:32:47 +0100126#undef HELPER_ST
127
aurel32d9bea112009-04-15 14:41:44 +0000128target_ulong helper_clo (target_ulong arg1)
ths30898802008-05-21 02:04:15 +0000129{
aurel32d9bea112009-04-15 14:41:44 +0000130 return clo32(arg1);
ths30898802008-05-21 02:04:15 +0000131}
132
aurel32d9bea112009-04-15 14:41:44 +0000133target_ulong helper_clz (target_ulong arg1)
ths30898802008-05-21 02:04:15 +0000134{
aurel32d9bea112009-04-15 14:41:44 +0000135 return clz32(arg1);
ths30898802008-05-21 02:04:15 +0000136}
137
thsd26bc212007-11-08 18:05:37 +0000138#if defined(TARGET_MIPS64)
aurel32d9bea112009-04-15 14:41:44 +0000139target_ulong helper_dclo (target_ulong arg1)
thsc570fd12006-12-21 01:19:56 +0000140{
aurel32d9bea112009-04-15 14:41:44 +0000141 return clo64(arg1);
thsc570fd12006-12-21 01:19:56 +0000142}
143
aurel32d9bea112009-04-15 14:41:44 +0000144target_ulong helper_dclz (target_ulong arg1)
thsc570fd12006-12-21 01:19:56 +0000145{
aurel32d9bea112009-04-15 14:41:44 +0000146 return clz64(arg1);
thsc570fd12006-12-21 01:19:56 +0000147}
thsd26bc212007-11-08 18:05:37 +0000148#endif /* TARGET_MIPS64 */
thsc570fd12006-12-21 01:19:56 +0000149
bellard6af0bf92005-07-02 14:58:51 +0000150/* 64 bits arithmetic for 32 bits hosts */
Blue Swirl895c2d02012-09-02 14:52:59 +0000151static inline uint64_t get_HILO(CPUMIPSState *env)
bellard6af0bf92005-07-02 14:58:51 +0000152{
thsb5dc7732008-06-27 10:02:35 +0000153 return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0];
bellard6af0bf92005-07-02 14:58:51 +0000154}
155
Blue Swirl895c2d02012-09-02 14:52:59 +0000156static inline target_ulong set_HIT0_LO(CPUMIPSState *env, uint64_t HILO)
thse9c71dd2007-12-25 20:46:56 +0000157{
Stefan Weil6fc97fa2012-03-04 08:21:39 +0100158 target_ulong tmp;
thsb5dc7732008-06-27 10:02:35 +0000159 env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
Stefan Weil6fc97fa2012-03-04 08:21:39 +0100160 tmp = env->active_tc.HI[0] = (int32_t)(HILO >> 32);
161 return tmp;
thse9c71dd2007-12-25 20:46:56 +0000162}
163
Blue Swirl895c2d02012-09-02 14:52:59 +0000164static inline target_ulong set_HI_LOT0(CPUMIPSState *env, uint64_t HILO)
thse9c71dd2007-12-25 20:46:56 +0000165{
Stefan Weil6fc97fa2012-03-04 08:21:39 +0100166 target_ulong tmp = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
thsb5dc7732008-06-27 10:02:35 +0000167 env->active_tc.HI[0] = (int32_t)(HILO >> 32);
Stefan Weil6fc97fa2012-03-04 08:21:39 +0100168 return tmp;
thse9c71dd2007-12-25 20:46:56 +0000169}
170
thse9c71dd2007-12-25 20:46:56 +0000171/* Multiplication variants of the vr54xx. */
Blue Swirl895c2d02012-09-02 14:52:59 +0000172target_ulong helper_muls(CPUMIPSState *env, target_ulong arg1,
173 target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000174{
Blue Swirl895c2d02012-09-02 14:52:59 +0000175 return set_HI_LOT0(env, 0 - ((int64_t)(int32_t)arg1 *
176 (int64_t)(int32_t)arg2));
thse9c71dd2007-12-25 20:46:56 +0000177}
178
Blue Swirl895c2d02012-09-02 14:52:59 +0000179target_ulong helper_mulsu(CPUMIPSState *env, target_ulong arg1,
180 target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000181{
Blue Swirl895c2d02012-09-02 14:52:59 +0000182 return set_HI_LOT0(env, 0 - (uint64_t)(uint32_t)arg1 *
183 (uint64_t)(uint32_t)arg2);
thse9c71dd2007-12-25 20:46:56 +0000184}
185
Blue Swirl895c2d02012-09-02 14:52:59 +0000186target_ulong helper_macc(CPUMIPSState *env, target_ulong arg1,
187 target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000188{
Blue Swirl895c2d02012-09-02 14:52:59 +0000189 return set_HI_LOT0(env, (int64_t)get_HILO(env) + (int64_t)(int32_t)arg1 *
190 (int64_t)(int32_t)arg2);
thse9c71dd2007-12-25 20:46:56 +0000191}
192
Blue Swirl895c2d02012-09-02 14:52:59 +0000193target_ulong helper_macchi(CPUMIPSState *env, target_ulong arg1,
194 target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000195{
Blue Swirl895c2d02012-09-02 14:52:59 +0000196 return set_HIT0_LO(env, (int64_t)get_HILO(env) + (int64_t)(int32_t)arg1 *
197 (int64_t)(int32_t)arg2);
thse9c71dd2007-12-25 20:46:56 +0000198}
199
Blue Swirl895c2d02012-09-02 14:52:59 +0000200target_ulong helper_maccu(CPUMIPSState *env, target_ulong arg1,
201 target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000202{
Blue Swirl895c2d02012-09-02 14:52:59 +0000203 return set_HI_LOT0(env, (uint64_t)get_HILO(env) +
204 (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
thse9c71dd2007-12-25 20:46:56 +0000205}
206
Blue Swirl895c2d02012-09-02 14:52:59 +0000207target_ulong helper_macchiu(CPUMIPSState *env, target_ulong arg1,
208 target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000209{
Blue Swirl895c2d02012-09-02 14:52:59 +0000210 return set_HIT0_LO(env, (uint64_t)get_HILO(env) +
211 (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
thse9c71dd2007-12-25 20:46:56 +0000212}
213
Blue Swirl895c2d02012-09-02 14:52:59 +0000214target_ulong helper_msac(CPUMIPSState *env, target_ulong arg1,
215 target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000216{
Blue Swirl895c2d02012-09-02 14:52:59 +0000217 return set_HI_LOT0(env, (int64_t)get_HILO(env) - (int64_t)(int32_t)arg1 *
218 (int64_t)(int32_t)arg2);
thse9c71dd2007-12-25 20:46:56 +0000219}
220
Blue Swirl895c2d02012-09-02 14:52:59 +0000221target_ulong helper_msachi(CPUMIPSState *env, target_ulong arg1,
222 target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000223{
Blue Swirl895c2d02012-09-02 14:52:59 +0000224 return set_HIT0_LO(env, (int64_t)get_HILO(env) - (int64_t)(int32_t)arg1 *
225 (int64_t)(int32_t)arg2);
thse9c71dd2007-12-25 20:46:56 +0000226}
227
Blue Swirl895c2d02012-09-02 14:52:59 +0000228target_ulong helper_msacu(CPUMIPSState *env, target_ulong arg1,
229 target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000230{
Blue Swirl895c2d02012-09-02 14:52:59 +0000231 return set_HI_LOT0(env, (uint64_t)get_HILO(env) -
232 (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
thse9c71dd2007-12-25 20:46:56 +0000233}
234
Blue Swirl895c2d02012-09-02 14:52:59 +0000235target_ulong helper_msachiu(CPUMIPSState *env, target_ulong arg1,
236 target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000237{
Blue Swirl895c2d02012-09-02 14:52:59 +0000238 return set_HIT0_LO(env, (uint64_t)get_HILO(env) -
239 (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
thse9c71dd2007-12-25 20:46:56 +0000240}
241
Blue Swirl895c2d02012-09-02 14:52:59 +0000242target_ulong helper_mulhi(CPUMIPSState *env, target_ulong arg1,
243 target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000244{
Blue Swirl895c2d02012-09-02 14:52:59 +0000245 return set_HIT0_LO(env, (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
thse9c71dd2007-12-25 20:46:56 +0000246}
247
Blue Swirl895c2d02012-09-02 14:52:59 +0000248target_ulong helper_mulhiu(CPUMIPSState *env, target_ulong arg1,
249 target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000250{
Blue Swirl895c2d02012-09-02 14:52:59 +0000251 return set_HIT0_LO(env, (uint64_t)(uint32_t)arg1 *
252 (uint64_t)(uint32_t)arg2);
thse9c71dd2007-12-25 20:46:56 +0000253}
254
Blue Swirl895c2d02012-09-02 14:52:59 +0000255target_ulong helper_mulshi(CPUMIPSState *env, target_ulong arg1,
256 target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000257{
Blue Swirl895c2d02012-09-02 14:52:59 +0000258 return set_HIT0_LO(env, 0 - (int64_t)(int32_t)arg1 *
259 (int64_t)(int32_t)arg2);
thse9c71dd2007-12-25 20:46:56 +0000260}
261
Blue Swirl895c2d02012-09-02 14:52:59 +0000262target_ulong helper_mulshiu(CPUMIPSState *env, target_ulong arg1,
263 target_ulong arg2)
thse9c71dd2007-12-25 20:46:56 +0000264{
Blue Swirl895c2d02012-09-02 14:52:59 +0000265 return set_HIT0_LO(env, 0 - (uint64_t)(uint32_t)arg1 *
266 (uint64_t)(uint32_t)arg2);
thse9c71dd2007-12-25 20:46:56 +0000267}
bellard6af0bf92005-07-02 14:58:51 +0000268
Yongbok Kim15eacb92014-06-27 08:49:05 +0100269static inline target_ulong bitswap(target_ulong v)
270{
Leon Alrae74dda9872014-10-22 14:00:29 +0100271 v = ((v >> 1) & (target_ulong)0x5555555555555555ULL) |
272 ((v & (target_ulong)0x5555555555555555ULL) << 1);
273 v = ((v >> 2) & (target_ulong)0x3333333333333333ULL) |
274 ((v & (target_ulong)0x3333333333333333ULL) << 2);
275 v = ((v >> 4) & (target_ulong)0x0F0F0F0F0F0F0F0FULL) |
276 ((v & (target_ulong)0x0F0F0F0F0F0F0F0FULL) << 4);
Yongbok Kim15eacb92014-06-27 08:49:05 +0100277 return v;
278}
279
280#ifdef TARGET_MIPS64
281target_ulong helper_dbitswap(target_ulong rt)
282{
283 return bitswap(rt);
284}
285#endif
286
287target_ulong helper_bitswap(target_ulong rt)
288{
289 return (int32_t)bitswap(rt);
290}
291
Aurelien Jarnoe7139c42009-11-30 15:39:54 +0100292#ifndef CONFIG_USER_ONLY
Aurelien Jarnoc36bbb22010-02-06 17:02:45 +0100293
Avi Kivitya8170e52012-10-23 12:30:10 +0200294static inline hwaddr do_translate_address(CPUMIPSState *env,
Blue Swirl895c2d02012-09-02 14:52:59 +0000295 target_ulong address,
296 int rw)
Aurelien Jarnoc36bbb22010-02-06 17:02:45 +0100297{
Avi Kivitya8170e52012-10-23 12:30:10 +0200298 hwaddr lladdr;
Aurelien Jarnoc36bbb22010-02-06 17:02:45 +0100299
300 lladdr = cpu_mips_translate_address(env, address, rw);
301
302 if (lladdr == -1LL) {
Andreas Färber5638d182013-08-27 17:52:12 +0200303 cpu_loop_exit(CPU(mips_env_get_cpu(env)));
Aurelien Jarnoc36bbb22010-02-06 17:02:45 +0100304 } else {
305 return lladdr;
306 }
307}
308
Leon Alrae6489dd22015-01-26 16:06:43 +0000309#define HELPER_LD_ATOMIC(name, insn, almask) \
Blue Swirl895c2d02012-09-02 14:52:59 +0000310target_ulong helper_##name(CPUMIPSState *env, target_ulong arg, int mem_idx) \
Aurelien Jarnoe7139c42009-11-30 15:39:54 +0100311{ \
Leon Alrae6489dd22015-01-26 16:06:43 +0000312 if (arg & almask) { \
313 env->CP0_BadVAddr = arg; \
314 helper_raise_exception(env, EXCP_AdEL); \
315 } \
Blue Swirl895c2d02012-09-02 14:52:59 +0000316 env->lladdr = do_translate_address(env, arg, 0); \
317 env->llval = do_##insn(env, arg, mem_idx); \
Aurelien Jarnoe7139c42009-11-30 15:39:54 +0100318 return env->llval; \
319}
Leon Alrae6489dd22015-01-26 16:06:43 +0000320HELPER_LD_ATOMIC(ll, lw, 0x3)
Aurelien Jarnoe7139c42009-11-30 15:39:54 +0100321#ifdef TARGET_MIPS64
Leon Alrae6489dd22015-01-26 16:06:43 +0000322HELPER_LD_ATOMIC(lld, ld, 0x7)
Aurelien Jarnoe7139c42009-11-30 15:39:54 +0100323#endif
324#undef HELPER_LD_ATOMIC
325
326#define HELPER_ST_ATOMIC(name, ld_insn, st_insn, almask) \
Blue Swirl895c2d02012-09-02 14:52:59 +0000327target_ulong helper_##name(CPUMIPSState *env, target_ulong arg1, \
328 target_ulong arg2, int mem_idx) \
Aurelien Jarnoe7139c42009-11-30 15:39:54 +0100329{ \
330 target_long tmp; \
331 \
332 if (arg2 & almask) { \
333 env->CP0_BadVAddr = arg2; \
Blue Swirl895c2d02012-09-02 14:52:59 +0000334 helper_raise_exception(env, EXCP_AdES); \
Aurelien Jarnoe7139c42009-11-30 15:39:54 +0100335 } \
Blue Swirl895c2d02012-09-02 14:52:59 +0000336 if (do_translate_address(env, arg2, 1) == env->lladdr) { \
337 tmp = do_##ld_insn(env, arg2, mem_idx); \
Aurelien Jarnoe7139c42009-11-30 15:39:54 +0100338 if (tmp == env->llval) { \
Blue Swirl895c2d02012-09-02 14:52:59 +0000339 do_##st_insn(env, arg2, arg1, mem_idx); \
Aurelien Jarnoe7139c42009-11-30 15:39:54 +0100340 return 1; \
341 } \
342 } \
343 return 0; \
344}
345HELPER_ST_ATOMIC(sc, lw, sw, 0x3)
346#ifdef TARGET_MIPS64
347HELPER_ST_ATOMIC(scd, ld, sd, 0x7)
348#endif
349#undef HELPER_ST_ATOMIC
350#endif
351
thsc8c22272008-06-20 15:12:14 +0000352#ifdef TARGET_WORDS_BIGENDIAN
353#define GET_LMASK(v) ((v) & 3)
354#define GET_OFFSET(addr, offset) (addr + (offset))
355#else
356#define GET_LMASK(v) (((v) & 3) ^ 3)
357#define GET_OFFSET(addr, offset) (addr - (offset))
358#endif
359
Blue Swirl895c2d02012-09-02 14:52:59 +0000360void helper_swl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
361 int mem_idx)
thsc8c22272008-06-20 15:12:14 +0000362{
Blue Swirl895c2d02012-09-02 14:52:59 +0000363 do_sb(env, arg2, (uint8_t)(arg1 >> 24), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000364
aurel32d9bea112009-04-15 14:41:44 +0000365 if (GET_LMASK(arg2) <= 2)
Blue Swirl895c2d02012-09-02 14:52:59 +0000366 do_sb(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000367
aurel32d9bea112009-04-15 14:41:44 +0000368 if (GET_LMASK(arg2) <= 1)
Blue Swirl895c2d02012-09-02 14:52:59 +0000369 do_sb(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000370
aurel32d9bea112009-04-15 14:41:44 +0000371 if (GET_LMASK(arg2) == 0)
Blue Swirl895c2d02012-09-02 14:52:59 +0000372 do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)arg1, mem_idx);
thsc8c22272008-06-20 15:12:14 +0000373}
374
Blue Swirl895c2d02012-09-02 14:52:59 +0000375void helper_swr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
376 int mem_idx)
thsc8c22272008-06-20 15:12:14 +0000377{
Blue Swirl895c2d02012-09-02 14:52:59 +0000378 do_sb(env, arg2, (uint8_t)arg1, mem_idx);
thsc8c22272008-06-20 15:12:14 +0000379
aurel32d9bea112009-04-15 14:41:44 +0000380 if (GET_LMASK(arg2) >= 1)
Blue Swirl895c2d02012-09-02 14:52:59 +0000381 do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000382
aurel32d9bea112009-04-15 14:41:44 +0000383 if (GET_LMASK(arg2) >= 2)
Blue Swirl895c2d02012-09-02 14:52:59 +0000384 do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000385
aurel32d9bea112009-04-15 14:41:44 +0000386 if (GET_LMASK(arg2) == 3)
Blue Swirl895c2d02012-09-02 14:52:59 +0000387 do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000388}
389
390#if defined(TARGET_MIPS64)
391/* "half" load and stores. We must do the memory access inline,
392 or fault handling won't work. */
393
394#ifdef TARGET_WORDS_BIGENDIAN
395#define GET_LMASK64(v) ((v) & 7)
396#else
397#define GET_LMASK64(v) (((v) & 7) ^ 7)
398#endif
399
Blue Swirl895c2d02012-09-02 14:52:59 +0000400void helper_sdl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
401 int mem_idx)
thsc8c22272008-06-20 15:12:14 +0000402{
Blue Swirl895c2d02012-09-02 14:52:59 +0000403 do_sb(env, arg2, (uint8_t)(arg1 >> 56), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000404
aurel32d9bea112009-04-15 14:41:44 +0000405 if (GET_LMASK64(arg2) <= 6)
Blue Swirl895c2d02012-09-02 14:52:59 +0000406 do_sb(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000407
aurel32d9bea112009-04-15 14:41:44 +0000408 if (GET_LMASK64(arg2) <= 5)
Blue Swirl895c2d02012-09-02 14:52:59 +0000409 do_sb(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000410
aurel32d9bea112009-04-15 14:41:44 +0000411 if (GET_LMASK64(arg2) <= 4)
Blue Swirl895c2d02012-09-02 14:52:59 +0000412 do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000413
aurel32d9bea112009-04-15 14:41:44 +0000414 if (GET_LMASK64(arg2) <= 3)
Blue Swirl895c2d02012-09-02 14:52:59 +0000415 do_sb(env, GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000416
aurel32d9bea112009-04-15 14:41:44 +0000417 if (GET_LMASK64(arg2) <= 2)
Blue Swirl895c2d02012-09-02 14:52:59 +0000418 do_sb(env, GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000419
aurel32d9bea112009-04-15 14:41:44 +0000420 if (GET_LMASK64(arg2) <= 1)
Blue Swirl895c2d02012-09-02 14:52:59 +0000421 do_sb(env, GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000422
aurel32d9bea112009-04-15 14:41:44 +0000423 if (GET_LMASK64(arg2) <= 0)
Blue Swirl895c2d02012-09-02 14:52:59 +0000424 do_sb(env, GET_OFFSET(arg2, 7), (uint8_t)arg1, mem_idx);
thsc8c22272008-06-20 15:12:14 +0000425}
426
Blue Swirl895c2d02012-09-02 14:52:59 +0000427void helper_sdr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
428 int mem_idx)
thsc8c22272008-06-20 15:12:14 +0000429{
Blue Swirl895c2d02012-09-02 14:52:59 +0000430 do_sb(env, arg2, (uint8_t)arg1, mem_idx);
thsc8c22272008-06-20 15:12:14 +0000431
aurel32d9bea112009-04-15 14:41:44 +0000432 if (GET_LMASK64(arg2) >= 1)
Blue Swirl895c2d02012-09-02 14:52:59 +0000433 do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000434
aurel32d9bea112009-04-15 14:41:44 +0000435 if (GET_LMASK64(arg2) >= 2)
Blue Swirl895c2d02012-09-02 14:52:59 +0000436 do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000437
aurel32d9bea112009-04-15 14:41:44 +0000438 if (GET_LMASK64(arg2) >= 3)
Blue Swirl895c2d02012-09-02 14:52:59 +0000439 do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000440
aurel32d9bea112009-04-15 14:41:44 +0000441 if (GET_LMASK64(arg2) >= 4)
Blue Swirl895c2d02012-09-02 14:52:59 +0000442 do_sb(env, GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000443
aurel32d9bea112009-04-15 14:41:44 +0000444 if (GET_LMASK64(arg2) >= 5)
Blue Swirl895c2d02012-09-02 14:52:59 +0000445 do_sb(env, GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000446
aurel32d9bea112009-04-15 14:41:44 +0000447 if (GET_LMASK64(arg2) >= 6)
Blue Swirl895c2d02012-09-02 14:52:59 +0000448 do_sb(env, GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000449
aurel32d9bea112009-04-15 14:41:44 +0000450 if (GET_LMASK64(arg2) == 7)
Blue Swirl895c2d02012-09-02 14:52:59 +0000451 do_sb(env, GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), mem_idx);
thsc8c22272008-06-20 15:12:14 +0000452}
453#endif /* TARGET_MIPS64 */
454
Nathan Froyd3c824102010-06-08 13:29:59 -0700455static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };
456
Blue Swirl895c2d02012-09-02 14:52:59 +0000457void helper_lwm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
458 uint32_t mem_idx)
Nathan Froyd3c824102010-06-08 13:29:59 -0700459{
460 target_ulong base_reglist = reglist & 0xf;
461 target_ulong do_r31 = reglist & 0x10;
Nathan Froyd3c824102010-06-08 13:29:59 -0700462
463 if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
464 target_ulong i;
465
466 for (i = 0; i < base_reglist; i++) {
Aurelien Jarno18bba4d2012-10-09 21:53:20 +0200467 env->active_tc.gpr[multiple_regs[i]] =
468 (target_long)do_lw(env, addr, mem_idx);
Nathan Froyd3c824102010-06-08 13:29:59 -0700469 addr += 4;
470 }
471 }
472
473 if (do_r31) {
Aurelien Jarno18bba4d2012-10-09 21:53:20 +0200474 env->active_tc.gpr[31] = (target_long)do_lw(env, addr, mem_idx);
Nathan Froyd3c824102010-06-08 13:29:59 -0700475 }
476}
477
Blue Swirl895c2d02012-09-02 14:52:59 +0000478void helper_swm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
479 uint32_t mem_idx)
Nathan Froyd3c824102010-06-08 13:29:59 -0700480{
481 target_ulong base_reglist = reglist & 0xf;
482 target_ulong do_r31 = reglist & 0x10;
Nathan Froyd3c824102010-06-08 13:29:59 -0700483
484 if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
485 target_ulong i;
486
487 for (i = 0; i < base_reglist; i++) {
Aurelien Jarno18bba4d2012-10-09 21:53:20 +0200488 do_sw(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx);
Nathan Froyd3c824102010-06-08 13:29:59 -0700489 addr += 4;
490 }
491 }
492
493 if (do_r31) {
Aurelien Jarno18bba4d2012-10-09 21:53:20 +0200494 do_sw(env, addr, env->active_tc.gpr[31], mem_idx);
Nathan Froyd3c824102010-06-08 13:29:59 -0700495 }
496}
497
498#if defined(TARGET_MIPS64)
Blue Swirl895c2d02012-09-02 14:52:59 +0000499void helper_ldm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
500 uint32_t mem_idx)
Nathan Froyd3c824102010-06-08 13:29:59 -0700501{
502 target_ulong base_reglist = reglist & 0xf;
503 target_ulong do_r31 = reglist & 0x10;
Nathan Froyd3c824102010-06-08 13:29:59 -0700504
505 if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
506 target_ulong i;
507
508 for (i = 0; i < base_reglist; i++) {
Aurelien Jarno18bba4d2012-10-09 21:53:20 +0200509 env->active_tc.gpr[multiple_regs[i]] = do_ld(env, addr, mem_idx);
Nathan Froyd3c824102010-06-08 13:29:59 -0700510 addr += 8;
511 }
512 }
513
514 if (do_r31) {
Aurelien Jarno18bba4d2012-10-09 21:53:20 +0200515 env->active_tc.gpr[31] = do_ld(env, addr, mem_idx);
Nathan Froyd3c824102010-06-08 13:29:59 -0700516 }
517}
518
Blue Swirl895c2d02012-09-02 14:52:59 +0000519void helper_sdm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
520 uint32_t mem_idx)
Nathan Froyd3c824102010-06-08 13:29:59 -0700521{
522 target_ulong base_reglist = reglist & 0xf;
523 target_ulong do_r31 = reglist & 0x10;
Nathan Froyd3c824102010-06-08 13:29:59 -0700524
525 if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
526 target_ulong i;
527
528 for (i = 0; i < base_reglist; i++) {
Aurelien Jarno18bba4d2012-10-09 21:53:20 +0200529 do_sd(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx);
Nathan Froyd3c824102010-06-08 13:29:59 -0700530 addr += 8;
531 }
532 }
533
534 if (do_r31) {
Aurelien Jarno18bba4d2012-10-09 21:53:20 +0200535 do_sd(env, addr, env->active_tc.gpr[31], mem_idx);
Nathan Froyd3c824102010-06-08 13:29:59 -0700536 }
537}
538#endif
539
ths0eaef5a2008-07-23 16:14:22 +0000540#ifndef CONFIG_USER_ONLY
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +0200541/* SMP helpers. */
Andreas Färberb35d77d2012-10-12 00:56:35 +0200542static bool mips_vpe_is_wfi(MIPSCPU *c)
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +0200543{
Andreas Färber259186a2013-01-17 18:51:17 +0100544 CPUState *cpu = CPU(c);
Andreas Färberb35d77d2012-10-12 00:56:35 +0200545 CPUMIPSState *env = &c->env;
546
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +0200547 /* If the VPE is halted but otherwise active, it means it's waiting for
548 an interrupt. */
Andreas Färber259186a2013-01-17 18:51:17 +0100549 return cpu->halted && mips_vpe_active(env);
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +0200550}
551
Andreas Färberc3affe52013-01-18 15:03:43 +0100552static inline void mips_vpe_wake(MIPSCPU *c)
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +0200553{
554 /* Dont set ->halted = 0 directly, let it be done via cpu_has_work
555 because there might be other conditions that state that c should
556 be sleeping. */
Andreas Färberc3affe52013-01-18 15:03:43 +0100557 cpu_interrupt(CPU(c), CPU_INTERRUPT_WAKE);
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +0200558}
559
Andreas Färber6f4d6b02012-10-12 00:56:37 +0200560static inline void mips_vpe_sleep(MIPSCPU *cpu)
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +0200561{
Andreas Färber259186a2013-01-17 18:51:17 +0100562 CPUState *cs = CPU(cpu);
Andreas Färber6f4d6b02012-10-12 00:56:37 +0200563
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +0200564 /* The VPE was shut off, really go to bed.
565 Reset any old _WAKE requests. */
Andreas Färber259186a2013-01-17 18:51:17 +0100566 cs->halted = 1;
Andreas Färberd8ed8872013-01-17 22:30:20 +0100567 cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +0200568}
569
Andreas Färber135dd632012-10-12 00:56:34 +0200570static inline void mips_tc_wake(MIPSCPU *cpu, int tc)
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +0200571{
Andreas Färber135dd632012-10-12 00:56:34 +0200572 CPUMIPSState *c = &cpu->env;
573
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +0200574 /* FIXME: TC reschedule. */
Andreas Färberb35d77d2012-10-12 00:56:35 +0200575 if (mips_vpe_active(c) && !mips_vpe_is_wfi(cpu)) {
Andreas Färberc3affe52013-01-18 15:03:43 +0100576 mips_vpe_wake(cpu);
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +0200577 }
578}
579
Andreas Färberc6679e92012-10-12 00:56:36 +0200580static inline void mips_tc_sleep(MIPSCPU *cpu, int tc)
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +0200581{
Andreas Färberc6679e92012-10-12 00:56:36 +0200582 CPUMIPSState *c = &cpu->env;
583
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +0200584 /* FIXME: TC reschedule. */
585 if (!mips_vpe_active(c)) {
Andreas Färber6f4d6b02012-10-12 00:56:37 +0200586 mips_vpe_sleep(cpu);
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +0200587 }
588}
589
Andreas Färber66afd1a2012-12-17 20:36:30 +0100590/**
591 * mips_cpu_map_tc:
592 * @env: CPU from which mapping is performed.
593 * @tc: Should point to an int with the value of the global TC index.
594 *
595 * This function will transform @tc into a local index within the
596 * returned #CPUMIPSState.
597 */
598/* FIXME: This code assumes that all VPEs have the same number of TCs,
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +0200599 which depends on runtime setup. Can probably be fixed by
Andreas Färber7db13fa2012-03-14 01:38:22 +0100600 walking the list of CPUMIPSStates. */
Blue Swirl895c2d02012-09-02 14:52:59 +0000601static CPUMIPSState *mips_cpu_map_tc(CPUMIPSState *env, int *tc)
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +0200602{
Andreas Färber38d8f5c2012-12-17 19:47:15 +0100603 MIPSCPU *cpu;
Andreas Färberce3960e2012-12-17 03:27:07 +0100604 CPUState *cs;
Andreas Färber38d8f5c2012-12-17 19:47:15 +0100605 CPUState *other_cs;
Andreas Färberce3960e2012-12-17 03:27:07 +0100606 int vpe_idx;
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +0200607 int tc_idx = *tc;
608
609 if (!(env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))) {
610 /* Not allowed to address other CPUs. */
611 *tc = env->current_tc;
612 return env;
613 }
614
Andreas Färberce3960e2012-12-17 03:27:07 +0100615 cs = CPU(mips_env_get_cpu(env));
616 vpe_idx = tc_idx / cs->nr_threads;
617 *tc = tc_idx % cs->nr_threads;
Andreas Färber38d8f5c2012-12-17 19:47:15 +0100618 other_cs = qemu_get_cpu(vpe_idx);
619 if (other_cs == NULL) {
620 return env;
621 }
622 cpu = MIPS_CPU(other_cs);
623 return &cpu->env;
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +0200624}
625
Edgar E. Iglesiasfe8dca82011-08-29 23:07:33 +0200626/* The per VPE CP0_Status register shares some fields with the per TC
627 CP0_TCStatus registers. These fields are wired to the same registers,
628 so changes to either of them should be reflected on both registers.
629
630 Also, EntryHi shares the bottom 8 bit ASID with TCStauts.
631
632 These helper call synchronizes the regs for a given cpu. */
633
Maciej W. Rozycki81a423e2014-11-10 13:46:35 +0000634/* Called for updates to CP0_Status. Defined in "cpu.h" for gdbstub.c. */
635/* static inline void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu,
636 int tc); */
Edgar E. Iglesiasfe8dca82011-08-29 23:07:33 +0200637
638/* Called for updates to CP0_TCStatus. */
Blue Swirl895c2d02012-09-02 14:52:59 +0000639static void sync_c0_tcstatus(CPUMIPSState *cpu, int tc,
640 target_ulong v)
Edgar E. Iglesiasfe8dca82011-08-29 23:07:33 +0200641{
642 uint32_t status;
643 uint32_t tcu, tmx, tasid, tksu;
Peter Maydellf45cb2f2014-03-17 16:00:34 +0000644 uint32_t mask = ((1U << CP0St_CU3)
Edgar E. Iglesiasfe8dca82011-08-29 23:07:33 +0200645 | (1 << CP0St_CU2)
646 | (1 << CP0St_CU1)
647 | (1 << CP0St_CU0)
648 | (1 << CP0St_MX)
649 | (3 << CP0St_KSU));
650
651 tcu = (v >> CP0TCSt_TCU0) & 0xf;
652 tmx = (v >> CP0TCSt_TMX) & 0x1;
653 tasid = v & 0xff;
654 tksu = (v >> CP0TCSt_TKSU) & 0x3;
655
656 status = tcu << CP0St_CU0;
657 status |= tmx << CP0St_MX;
658 status |= tksu << CP0St_KSU;
659
660 cpu->CP0_Status &= ~mask;
661 cpu->CP0_Status |= status;
662
663 /* Sync the TASID with EntryHi. */
664 cpu->CP0_EntryHi &= ~0xff;
Aurelien Jarno6a973e62015-07-01 15:59:13 +0200665 cpu->CP0_EntryHi |= tasid;
Edgar E. Iglesiasfe8dca82011-08-29 23:07:33 +0200666
667 compute_hflags(cpu);
668}
669
670/* Called for updates to CP0_EntryHi. */
Andreas Färber7db13fa2012-03-14 01:38:22 +0100671static void sync_c0_entryhi(CPUMIPSState *cpu, int tc)
Edgar E. Iglesiasfe8dca82011-08-29 23:07:33 +0200672{
673 int32_t *tcst;
674 uint32_t asid, v = cpu->CP0_EntryHi;
675
676 asid = v & 0xff;
677
678 if (tc == cpu->current_tc) {
679 tcst = &cpu->active_tc.CP0_TCStatus;
680 } else {
681 tcst = &cpu->tcs[tc].CP0_TCStatus;
682 }
683
684 *tcst &= ~0xff;
685 *tcst |= asid;
686}
687
bellard6af0bf92005-07-02 14:58:51 +0000688/* CP0 helpers */
Blue Swirl895c2d02012-09-02 14:52:59 +0000689target_ulong helper_mfc0_mvpcontrol(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000690{
thsbe24bb42008-06-23 12:57:09 +0000691 return env->mvp->CP0_MVPControl;
thsf1aa6322008-06-09 07:13:38 +0000692}
693
Blue Swirl895c2d02012-09-02 14:52:59 +0000694target_ulong helper_mfc0_mvpconf0(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000695{
thsbe24bb42008-06-23 12:57:09 +0000696 return env->mvp->CP0_MVPConf0;
thsf1aa6322008-06-09 07:13:38 +0000697}
698
Blue Swirl895c2d02012-09-02 14:52:59 +0000699target_ulong helper_mfc0_mvpconf1(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000700{
thsbe24bb42008-06-23 12:57:09 +0000701 return env->mvp->CP0_MVPConf1;
thsf1aa6322008-06-09 07:13:38 +0000702}
703
Blue Swirl895c2d02012-09-02 14:52:59 +0000704target_ulong helper_mfc0_random(CPUMIPSState *env)
bellard6af0bf92005-07-02 14:58:51 +0000705{
thsbe24bb42008-06-23 12:57:09 +0000706 return (int32_t)cpu_mips_get_random(env);
ths873eb012006-12-06 17:59:07 +0000707}
bellard6af0bf92005-07-02 14:58:51 +0000708
Blue Swirl895c2d02012-09-02 14:52:59 +0000709target_ulong helper_mfc0_tcstatus(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000710{
thsb5dc7732008-06-27 10:02:35 +0000711 return env->active_tc.CP0_TCStatus;
thsf1aa6322008-06-09 07:13:38 +0000712}
713
Blue Swirl895c2d02012-09-02 14:52:59 +0000714target_ulong helper_mftc0_tcstatus(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000715{
716 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +0000717 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +0000718
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +0200719 if (other_tc == other->current_tc)
720 return other->active_tc.CP0_TCStatus;
thsb5dc7732008-06-27 10:02:35 +0000721 else
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +0200722 return other->tcs[other_tc].CP0_TCStatus;
thsf1aa6322008-06-09 07:13:38 +0000723}
724
Blue Swirl895c2d02012-09-02 14:52:59 +0000725target_ulong helper_mfc0_tcbind(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000726{
thsb5dc7732008-06-27 10:02:35 +0000727 return env->active_tc.CP0_TCBind;
thsf1aa6322008-06-09 07:13:38 +0000728}
729
Blue Swirl895c2d02012-09-02 14:52:59 +0000730target_ulong helper_mftc0_tcbind(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000731{
732 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +0000733 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +0000734
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +0200735 if (other_tc == other->current_tc)
736 return other->active_tc.CP0_TCBind;
thsb5dc7732008-06-27 10:02:35 +0000737 else
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +0200738 return other->tcs[other_tc].CP0_TCBind;
thsf1aa6322008-06-09 07:13:38 +0000739}
740
Blue Swirl895c2d02012-09-02 14:52:59 +0000741target_ulong helper_mfc0_tcrestart(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000742{
thsb5dc7732008-06-27 10:02:35 +0000743 return env->active_tc.PC;
thsf1aa6322008-06-09 07:13:38 +0000744}
745
Blue Swirl895c2d02012-09-02 14:52:59 +0000746target_ulong helper_mftc0_tcrestart(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000747{
748 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +0000749 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +0000750
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +0200751 if (other_tc == other->current_tc)
752 return other->active_tc.PC;
thsb5dc7732008-06-27 10:02:35 +0000753 else
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +0200754 return other->tcs[other_tc].PC;
thsf1aa6322008-06-09 07:13:38 +0000755}
756
Blue Swirl895c2d02012-09-02 14:52:59 +0000757target_ulong helper_mfc0_tchalt(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000758{
thsb5dc7732008-06-27 10:02:35 +0000759 return env->active_tc.CP0_TCHalt;
thsf1aa6322008-06-09 07:13:38 +0000760}
761
Blue Swirl895c2d02012-09-02 14:52:59 +0000762target_ulong helper_mftc0_tchalt(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000763{
764 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +0000765 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +0000766
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +0200767 if (other_tc == other->current_tc)
768 return other->active_tc.CP0_TCHalt;
thsb5dc7732008-06-27 10:02:35 +0000769 else
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +0200770 return other->tcs[other_tc].CP0_TCHalt;
thsf1aa6322008-06-09 07:13:38 +0000771}
772
Blue Swirl895c2d02012-09-02 14:52:59 +0000773target_ulong helper_mfc0_tccontext(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000774{
thsb5dc7732008-06-27 10:02:35 +0000775 return env->active_tc.CP0_TCContext;
thsf1aa6322008-06-09 07:13:38 +0000776}
777
Blue Swirl895c2d02012-09-02 14:52:59 +0000778target_ulong helper_mftc0_tccontext(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000779{
780 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +0000781 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +0000782
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +0200783 if (other_tc == other->current_tc)
784 return other->active_tc.CP0_TCContext;
thsb5dc7732008-06-27 10:02:35 +0000785 else
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +0200786 return other->tcs[other_tc].CP0_TCContext;
thsf1aa6322008-06-09 07:13:38 +0000787}
788
Blue Swirl895c2d02012-09-02 14:52:59 +0000789target_ulong helper_mfc0_tcschedule(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000790{
thsb5dc7732008-06-27 10:02:35 +0000791 return env->active_tc.CP0_TCSchedule;
thsf1aa6322008-06-09 07:13:38 +0000792}
793
Blue Swirl895c2d02012-09-02 14:52:59 +0000794target_ulong helper_mftc0_tcschedule(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000795{
796 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +0000797 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +0000798
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +0200799 if (other_tc == other->current_tc)
800 return other->active_tc.CP0_TCSchedule;
thsb5dc7732008-06-27 10:02:35 +0000801 else
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +0200802 return other->tcs[other_tc].CP0_TCSchedule;
thsf1aa6322008-06-09 07:13:38 +0000803}
804
Blue Swirl895c2d02012-09-02 14:52:59 +0000805target_ulong helper_mfc0_tcschefback(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000806{
thsb5dc7732008-06-27 10:02:35 +0000807 return env->active_tc.CP0_TCScheFBack;
thsf1aa6322008-06-09 07:13:38 +0000808}
809
Blue Swirl895c2d02012-09-02 14:52:59 +0000810target_ulong helper_mftc0_tcschefback(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000811{
812 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +0000813 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +0000814
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +0200815 if (other_tc == other->current_tc)
816 return other->active_tc.CP0_TCScheFBack;
thsb5dc7732008-06-27 10:02:35 +0000817 else
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +0200818 return other->tcs[other_tc].CP0_TCScheFBack;
thsf1aa6322008-06-09 07:13:38 +0000819}
820
Blue Swirl895c2d02012-09-02 14:52:59 +0000821target_ulong helper_mfc0_count(CPUMIPSState *env)
ths873eb012006-12-06 17:59:07 +0000822{
thsbe24bb42008-06-23 12:57:09 +0000823 return (int32_t)cpu_mips_get_count(env);
bellard6af0bf92005-07-02 14:58:51 +0000824}
825
Blue Swirl895c2d02012-09-02 14:52:59 +0000826target_ulong helper_mftc0_entryhi(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000827{
828 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +0000829 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +0000830
Edgar E. Iglesiasfe8dca82011-08-29 23:07:33 +0200831 return other->CP0_EntryHi;
thsf1aa6322008-06-09 07:13:38 +0000832}
833
Blue Swirl895c2d02012-09-02 14:52:59 +0000834target_ulong helper_mftc0_cause(CPUMIPSState *env)
Edgar E. Iglesias5a25ce92011-08-29 23:07:34 +0200835{
836 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
837 int32_t tccause;
Blue Swirl895c2d02012-09-02 14:52:59 +0000838 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Edgar E. Iglesias5a25ce92011-08-29 23:07:34 +0200839
840 if (other_tc == other->current_tc) {
841 tccause = other->CP0_Cause;
842 } else {
843 tccause = other->CP0_Cause;
844 }
845
846 return tccause;
847}
848
Blue Swirl895c2d02012-09-02 14:52:59 +0000849target_ulong helper_mftc0_status(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000850{
851 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +0000852 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsb5dc7732008-06-27 10:02:35 +0000853
Edgar E. Iglesiasfe8dca82011-08-29 23:07:33 +0200854 return other->CP0_Status;
thsf1aa6322008-06-09 07:13:38 +0000855}
856
Blue Swirl895c2d02012-09-02 14:52:59 +0000857target_ulong helper_mfc0_lladdr(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000858{
Aurelien Jarno2a6e32d2009-11-22 13:22:54 +0100859 return (int32_t)(env->lladdr >> env->CP0_LLAddr_shift);
thsf1aa6322008-06-09 07:13:38 +0000860}
861
Blue Swirl895c2d02012-09-02 14:52:59 +0000862target_ulong helper_mfc0_watchlo(CPUMIPSState *env, uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +0000863{
thsbe24bb42008-06-23 12:57:09 +0000864 return (int32_t)env->CP0_WatchLo[sel];
thsf1aa6322008-06-09 07:13:38 +0000865}
866
Blue Swirl895c2d02012-09-02 14:52:59 +0000867target_ulong helper_mfc0_watchhi(CPUMIPSState *env, uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +0000868{
thsbe24bb42008-06-23 12:57:09 +0000869 return env->CP0_WatchHi[sel];
thsf1aa6322008-06-09 07:13:38 +0000870}
871
Blue Swirl895c2d02012-09-02 14:52:59 +0000872target_ulong helper_mfc0_debug(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000873{
ths1a3fd9c2008-06-24 21:58:35 +0000874 target_ulong t0 = env->CP0_Debug;
thsf1aa6322008-06-09 07:13:38 +0000875 if (env->hflags & MIPS_HFLAG_DM)
thsbe24bb42008-06-23 12:57:09 +0000876 t0 |= 1 << CP0DB_DM;
877
878 return t0;
thsf1aa6322008-06-09 07:13:38 +0000879}
880
Blue Swirl895c2d02012-09-02 14:52:59 +0000881target_ulong helper_mftc0_debug(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000882{
883 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
thsb5dc7732008-06-27 10:02:35 +0000884 int32_t tcstatus;
Blue Swirl895c2d02012-09-02 14:52:59 +0000885 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsb5dc7732008-06-27 10:02:35 +0000886
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +0200887 if (other_tc == other->current_tc)
888 tcstatus = other->active_tc.CP0_Debug_tcstatus;
thsb5dc7732008-06-27 10:02:35 +0000889 else
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +0200890 tcstatus = other->tcs[other_tc].CP0_Debug_tcstatus;
thsf1aa6322008-06-09 07:13:38 +0000891
892 /* XXX: Might be wrong, check with EJTAG spec. */
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +0200893 return (other->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
thsb5dc7732008-06-27 10:02:35 +0000894 (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
thsf1aa6322008-06-09 07:13:38 +0000895}
896
897#if defined(TARGET_MIPS64)
Blue Swirl895c2d02012-09-02 14:52:59 +0000898target_ulong helper_dmfc0_tcrestart(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000899{
thsb5dc7732008-06-27 10:02:35 +0000900 return env->active_tc.PC;
thsf1aa6322008-06-09 07:13:38 +0000901}
902
Blue Swirl895c2d02012-09-02 14:52:59 +0000903target_ulong helper_dmfc0_tchalt(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000904{
thsb5dc7732008-06-27 10:02:35 +0000905 return env->active_tc.CP0_TCHalt;
thsf1aa6322008-06-09 07:13:38 +0000906}
907
Blue Swirl895c2d02012-09-02 14:52:59 +0000908target_ulong helper_dmfc0_tccontext(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000909{
thsb5dc7732008-06-27 10:02:35 +0000910 return env->active_tc.CP0_TCContext;
thsf1aa6322008-06-09 07:13:38 +0000911}
912
Blue Swirl895c2d02012-09-02 14:52:59 +0000913target_ulong helper_dmfc0_tcschedule(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000914{
thsb5dc7732008-06-27 10:02:35 +0000915 return env->active_tc.CP0_TCSchedule;
thsf1aa6322008-06-09 07:13:38 +0000916}
917
Blue Swirl895c2d02012-09-02 14:52:59 +0000918target_ulong helper_dmfc0_tcschefback(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000919{
thsb5dc7732008-06-27 10:02:35 +0000920 return env->active_tc.CP0_TCScheFBack;
thsf1aa6322008-06-09 07:13:38 +0000921}
922
Blue Swirl895c2d02012-09-02 14:52:59 +0000923target_ulong helper_dmfc0_lladdr(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +0000924{
Aurelien Jarno2a6e32d2009-11-22 13:22:54 +0100925 return env->lladdr >> env->CP0_LLAddr_shift;
thsf1aa6322008-06-09 07:13:38 +0000926}
927
Blue Swirl895c2d02012-09-02 14:52:59 +0000928target_ulong helper_dmfc0_watchlo(CPUMIPSState *env, uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +0000929{
thsbe24bb42008-06-23 12:57:09 +0000930 return env->CP0_WatchLo[sel];
thsf1aa6322008-06-09 07:13:38 +0000931}
932#endif /* TARGET_MIPS64 */
933
Blue Swirl895c2d02012-09-02 14:52:59 +0000934void helper_mtc0_index(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +0000935{
Leon Alraeba801af2014-07-11 16:11:34 +0100936 uint32_t index_p = env->CP0_Index & 0x80000000;
937 uint32_t tlb_index = arg1 & 0x7fffffff;
938 if (tlb_index < env->tlb->nb_tlb) {
939 if (env->insn_flags & ISA_MIPS32R6) {
940 index_p |= arg1 & 0x80000000;
941 }
942 env->CP0_Index = index_p | tlb_index;
943 }
thsf1aa6322008-06-09 07:13:38 +0000944}
945
Blue Swirl895c2d02012-09-02 14:52:59 +0000946void helper_mtc0_mvpcontrol(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +0000947{
948 uint32_t mask = 0;
949 uint32_t newval;
950
951 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))
952 mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) |
953 (1 << CP0MVPCo_EVP);
954 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
955 mask |= (1 << CP0MVPCo_STLB);
aurel32d9bea112009-04-15 14:41:44 +0000956 newval = (env->mvp->CP0_MVPControl & ~mask) | (arg1 & mask);
thsf1aa6322008-06-09 07:13:38 +0000957
958 // TODO: Enable/disable shared TLB, enable/disable VPEs.
959
960 env->mvp->CP0_MVPControl = newval;
961}
962
Blue Swirl895c2d02012-09-02 14:52:59 +0000963void helper_mtc0_vpecontrol(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +0000964{
965 uint32_t mask;
966 uint32_t newval;
967
968 mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
969 (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
aurel32d9bea112009-04-15 14:41:44 +0000970 newval = (env->CP0_VPEControl & ~mask) | (arg1 & mask);
thsf1aa6322008-06-09 07:13:38 +0000971
972 /* Yield scheduler intercept not implemented. */
973 /* Gating storage scheduler intercept not implemented. */
974
975 // TODO: Enable/disable TCs.
976
977 env->CP0_VPEControl = newval;
978}
979
Blue Swirl895c2d02012-09-02 14:52:59 +0000980void helper_mttc0_vpecontrol(CPUMIPSState *env, target_ulong arg1)
Edgar E. Iglesias5a25ce92011-08-29 23:07:34 +0200981{
982 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +0000983 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Edgar E. Iglesias5a25ce92011-08-29 23:07:34 +0200984 uint32_t mask;
985 uint32_t newval;
986
987 mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
988 (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
989 newval = (other->CP0_VPEControl & ~mask) | (arg1 & mask);
990
991 /* TODO: Enable/disable TCs. */
992
993 other->CP0_VPEControl = newval;
994}
995
Blue Swirl895c2d02012-09-02 14:52:59 +0000996target_ulong helper_mftc0_vpecontrol(CPUMIPSState *env)
Edgar E. Iglesias5a25ce92011-08-29 23:07:34 +0200997{
998 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +0000999 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Edgar E. Iglesias5a25ce92011-08-29 23:07:34 +02001000 /* FIXME: Mask away return zero on read bits. */
1001 return other->CP0_VPEControl;
1002}
1003
Blue Swirl895c2d02012-09-02 14:52:59 +00001004target_ulong helper_mftc0_vpeconf0(CPUMIPSState *env)
Edgar E. Iglesias5a25ce92011-08-29 23:07:34 +02001005{
1006 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +00001007 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Edgar E. Iglesias5a25ce92011-08-29 23:07:34 +02001008
1009 return other->CP0_VPEConf0;
1010}
1011
Blue Swirl895c2d02012-09-02 14:52:59 +00001012void helper_mtc0_vpeconf0(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001013{
1014 uint32_t mask = 0;
1015 uint32_t newval;
1016
1017 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) {
1018 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))
1019 mask |= (0xff << CP0VPEC0_XTC);
1020 mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
1021 }
aurel32d9bea112009-04-15 14:41:44 +00001022 newval = (env->CP0_VPEConf0 & ~mask) | (arg1 & mask);
thsf1aa6322008-06-09 07:13:38 +00001023
1024 // TODO: TC exclusive handling due to ERL/EXL.
1025
1026 env->CP0_VPEConf0 = newval;
1027}
1028
Blue Swirl895c2d02012-09-02 14:52:59 +00001029void helper_mttc0_vpeconf0(CPUMIPSState *env, target_ulong arg1)
Edgar E. Iglesias5a25ce92011-08-29 23:07:34 +02001030{
1031 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +00001032 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Edgar E. Iglesias5a25ce92011-08-29 23:07:34 +02001033 uint32_t mask = 0;
1034 uint32_t newval;
1035
1036 mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
1037 newval = (other->CP0_VPEConf0 & ~mask) | (arg1 & mask);
1038
1039 /* TODO: TC exclusive handling due to ERL/EXL. */
1040 other->CP0_VPEConf0 = newval;
1041}
1042
Blue Swirl895c2d02012-09-02 14:52:59 +00001043void helper_mtc0_vpeconf1(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001044{
1045 uint32_t mask = 0;
1046 uint32_t newval;
1047
1048 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1049 mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) |
1050 (0xff << CP0VPEC1_NCP1);
aurel32d9bea112009-04-15 14:41:44 +00001051 newval = (env->CP0_VPEConf1 & ~mask) | (arg1 & mask);
thsf1aa6322008-06-09 07:13:38 +00001052
1053 /* UDI not implemented. */
1054 /* CP2 not implemented. */
1055
1056 // TODO: Handle FPU (CP1) binding.
1057
1058 env->CP0_VPEConf1 = newval;
1059}
1060
Blue Swirl895c2d02012-09-02 14:52:59 +00001061void helper_mtc0_yqmask(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001062{
1063 /* Yield qualifier inputs not implemented. */
1064 env->CP0_YQMask = 0x00000000;
1065}
1066
Blue Swirl895c2d02012-09-02 14:52:59 +00001067void helper_mtc0_vpeopt(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001068{
aurel32d9bea112009-04-15 14:41:44 +00001069 env->CP0_VPEOpt = arg1 & 0x0000ffff;
thsf1aa6322008-06-09 07:13:38 +00001070}
1071
Leon Alraee117f522015-04-14 10:09:38 +01001072#define MTC0_ENTRYLO_MASK(env) ((env->PAMask >> 6) & 0x3FFFFFFF)
1073
Blue Swirl895c2d02012-09-02 14:52:59 +00001074void helper_mtc0_entrylo0(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001075{
thsf1aa6322008-06-09 07:13:38 +00001076 /* 1k pages not implemented */
Leon Alrae7207c7f2014-07-07 11:23:59 +01001077 target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE));
Leon Alraee117f522015-04-14 10:09:38 +01001078 env->CP0_EntryLo0 = (arg1 & MTC0_ENTRYLO_MASK(env))
1079 | (rxi << (CP0EnLo_XI - 30));
thsf1aa6322008-06-09 07:13:38 +00001080}
1081
Leon Alrae7207c7f2014-07-07 11:23:59 +01001082#if defined(TARGET_MIPS64)
Leon Alraee117f522015-04-14 10:09:38 +01001083#define DMTC0_ENTRYLO_MASK(env) (env->PAMask >> 6)
1084
Leon Alrae7207c7f2014-07-07 11:23:59 +01001085void helper_dmtc0_entrylo0(CPUMIPSState *env, uint64_t arg1)
1086{
1087 uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32);
Leon Alraee117f522015-04-14 10:09:38 +01001088 env->CP0_EntryLo0 = (arg1 & DMTC0_ENTRYLO_MASK(env)) | rxi;
Leon Alrae7207c7f2014-07-07 11:23:59 +01001089}
1090#endif
1091
Blue Swirl895c2d02012-09-02 14:52:59 +00001092void helper_mtc0_tcstatus(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001093{
1094 uint32_t mask = env->CP0_TCStatus_rw_bitmask;
1095 uint32_t newval;
1096
aurel32d9bea112009-04-15 14:41:44 +00001097 newval = (env->active_tc.CP0_TCStatus & ~mask) | (arg1 & mask);
thsf1aa6322008-06-09 07:13:38 +00001098
thsb5dc7732008-06-27 10:02:35 +00001099 env->active_tc.CP0_TCStatus = newval;
Edgar E. Iglesiasfe8dca82011-08-29 23:07:33 +02001100 sync_c0_tcstatus(env, env->current_tc, newval);
thsf1aa6322008-06-09 07:13:38 +00001101}
1102
Blue Swirl895c2d02012-09-02 14:52:59 +00001103void helper_mttc0_tcstatus(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001104{
1105 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +00001106 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +00001107
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001108 if (other_tc == other->current_tc)
1109 other->active_tc.CP0_TCStatus = arg1;
thsb5dc7732008-06-27 10:02:35 +00001110 else
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001111 other->tcs[other_tc].CP0_TCStatus = arg1;
Edgar E. Iglesiasfe8dca82011-08-29 23:07:33 +02001112 sync_c0_tcstatus(other, other_tc, arg1);
thsf1aa6322008-06-09 07:13:38 +00001113}
1114
Blue Swirl895c2d02012-09-02 14:52:59 +00001115void helper_mtc0_tcbind(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001116{
1117 uint32_t mask = (1 << CP0TCBd_TBE);
1118 uint32_t newval;
1119
1120 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1121 mask |= (1 << CP0TCBd_CurVPE);
aurel32d9bea112009-04-15 14:41:44 +00001122 newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
thsb5dc7732008-06-27 10:02:35 +00001123 env->active_tc.CP0_TCBind = newval;
thsf1aa6322008-06-09 07:13:38 +00001124}
1125
Blue Swirl895c2d02012-09-02 14:52:59 +00001126void helper_mttc0_tcbind(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001127{
1128 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1129 uint32_t mask = (1 << CP0TCBd_TBE);
1130 uint32_t newval;
Blue Swirl895c2d02012-09-02 14:52:59 +00001131 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +00001132
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001133 if (other->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
thsf1aa6322008-06-09 07:13:38 +00001134 mask |= (1 << CP0TCBd_CurVPE);
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001135 if (other_tc == other->current_tc) {
1136 newval = (other->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
1137 other->active_tc.CP0_TCBind = newval;
thsb5dc7732008-06-27 10:02:35 +00001138 } else {
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001139 newval = (other->tcs[other_tc].CP0_TCBind & ~mask) | (arg1 & mask);
1140 other->tcs[other_tc].CP0_TCBind = newval;
thsb5dc7732008-06-27 10:02:35 +00001141 }
thsf1aa6322008-06-09 07:13:38 +00001142}
1143
Blue Swirl895c2d02012-09-02 14:52:59 +00001144void helper_mtc0_tcrestart(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001145{
aurel32d9bea112009-04-15 14:41:44 +00001146 env->active_tc.PC = arg1;
thsb5dc7732008-06-27 10:02:35 +00001147 env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
Aurelien Jarno5499b6f2009-11-22 13:08:14 +01001148 env->lladdr = 0ULL;
thsf1aa6322008-06-09 07:13:38 +00001149 /* MIPS16 not implemented. */
1150}
1151
Blue Swirl895c2d02012-09-02 14:52:59 +00001152void helper_mttc0_tcrestart(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001153{
1154 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +00001155 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +00001156
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001157 if (other_tc == other->current_tc) {
1158 other->active_tc.PC = arg1;
1159 other->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1160 other->lladdr = 0ULL;
thsb5dc7732008-06-27 10:02:35 +00001161 /* MIPS16 not implemented. */
1162 } else {
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001163 other->tcs[other_tc].PC = arg1;
1164 other->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1165 other->lladdr = 0ULL;
thsb5dc7732008-06-27 10:02:35 +00001166 /* MIPS16 not implemented. */
1167 }
thsf1aa6322008-06-09 07:13:38 +00001168}
1169
Blue Swirl895c2d02012-09-02 14:52:59 +00001170void helper_mtc0_tchalt(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001171{
Andreas Färber135dd632012-10-12 00:56:34 +02001172 MIPSCPU *cpu = mips_env_get_cpu(env);
1173
aurel32d9bea112009-04-15 14:41:44 +00001174 env->active_tc.CP0_TCHalt = arg1 & 0x1;
thsf1aa6322008-06-09 07:13:38 +00001175
1176 // TODO: Halt TC / Restart (if allocated+active) TC.
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +02001177 if (env->active_tc.CP0_TCHalt & 1) {
Andreas Färberc6679e92012-10-12 00:56:36 +02001178 mips_tc_sleep(cpu, env->current_tc);
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +02001179 } else {
Andreas Färber135dd632012-10-12 00:56:34 +02001180 mips_tc_wake(cpu, env->current_tc);
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +02001181 }
thsf1aa6322008-06-09 07:13:38 +00001182}
1183
Blue Swirl895c2d02012-09-02 14:52:59 +00001184void helper_mttc0_tchalt(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001185{
1186 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +00001187 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Andreas Färber135dd632012-10-12 00:56:34 +02001188 MIPSCPU *other_cpu = mips_env_get_cpu(other);
thsf1aa6322008-06-09 07:13:38 +00001189
1190 // TODO: Halt TC / Restart (if allocated+active) TC.
1191
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001192 if (other_tc == other->current_tc)
1193 other->active_tc.CP0_TCHalt = arg1;
thsb5dc7732008-06-27 10:02:35 +00001194 else
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001195 other->tcs[other_tc].CP0_TCHalt = arg1;
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +02001196
1197 if (arg1 & 1) {
Andreas Färberc6679e92012-10-12 00:56:36 +02001198 mips_tc_sleep(other_cpu, other_tc);
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +02001199 } else {
Andreas Färber135dd632012-10-12 00:56:34 +02001200 mips_tc_wake(other_cpu, other_tc);
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +02001201 }
thsf1aa6322008-06-09 07:13:38 +00001202}
1203
Blue Swirl895c2d02012-09-02 14:52:59 +00001204void helper_mtc0_tccontext(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001205{
aurel32d9bea112009-04-15 14:41:44 +00001206 env->active_tc.CP0_TCContext = arg1;
thsf1aa6322008-06-09 07:13:38 +00001207}
1208
Blue Swirl895c2d02012-09-02 14:52:59 +00001209void helper_mttc0_tccontext(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001210{
1211 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +00001212 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +00001213
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001214 if (other_tc == other->current_tc)
1215 other->active_tc.CP0_TCContext = arg1;
thsb5dc7732008-06-27 10:02:35 +00001216 else
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001217 other->tcs[other_tc].CP0_TCContext = arg1;
thsf1aa6322008-06-09 07:13:38 +00001218}
1219
Blue Swirl895c2d02012-09-02 14:52:59 +00001220void helper_mtc0_tcschedule(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001221{
aurel32d9bea112009-04-15 14:41:44 +00001222 env->active_tc.CP0_TCSchedule = arg1;
thsf1aa6322008-06-09 07:13:38 +00001223}
1224
Blue Swirl895c2d02012-09-02 14:52:59 +00001225void helper_mttc0_tcschedule(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001226{
1227 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +00001228 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +00001229
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001230 if (other_tc == other->current_tc)
1231 other->active_tc.CP0_TCSchedule = arg1;
thsb5dc7732008-06-27 10:02:35 +00001232 else
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001233 other->tcs[other_tc].CP0_TCSchedule = arg1;
thsf1aa6322008-06-09 07:13:38 +00001234}
1235
Blue Swirl895c2d02012-09-02 14:52:59 +00001236void helper_mtc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001237{
aurel32d9bea112009-04-15 14:41:44 +00001238 env->active_tc.CP0_TCScheFBack = arg1;
thsf1aa6322008-06-09 07:13:38 +00001239}
1240
Blue Swirl895c2d02012-09-02 14:52:59 +00001241void helper_mttc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001242{
1243 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +00001244 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +00001245
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001246 if (other_tc == other->current_tc)
1247 other->active_tc.CP0_TCScheFBack = arg1;
thsb5dc7732008-06-27 10:02:35 +00001248 else
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001249 other->tcs[other_tc].CP0_TCScheFBack = arg1;
thsf1aa6322008-06-09 07:13:38 +00001250}
1251
Blue Swirl895c2d02012-09-02 14:52:59 +00001252void helper_mtc0_entrylo1(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001253{
thsf1aa6322008-06-09 07:13:38 +00001254 /* 1k pages not implemented */
Leon Alrae7207c7f2014-07-07 11:23:59 +01001255 target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE));
Leon Alraee117f522015-04-14 10:09:38 +01001256 env->CP0_EntryLo1 = (arg1 & MTC0_ENTRYLO_MASK(env))
1257 | (rxi << (CP0EnLo_XI - 30));
thsf1aa6322008-06-09 07:13:38 +00001258}
1259
Leon Alrae7207c7f2014-07-07 11:23:59 +01001260#if defined(TARGET_MIPS64)
1261void helper_dmtc0_entrylo1(CPUMIPSState *env, uint64_t arg1)
1262{
1263 uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32);
Leon Alraee117f522015-04-14 10:09:38 +01001264 env->CP0_EntryLo1 = (arg1 & DMTC0_ENTRYLO_MASK(env)) | rxi;
Leon Alrae7207c7f2014-07-07 11:23:59 +01001265}
1266#endif
1267
Blue Swirl895c2d02012-09-02 14:52:59 +00001268void helper_mtc0_context(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001269{
aurel32d9bea112009-04-15 14:41:44 +00001270 env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF);
thsf1aa6322008-06-09 07:13:38 +00001271}
1272
Blue Swirl895c2d02012-09-02 14:52:59 +00001273void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001274{
Leon Alraeba801af2014-07-11 16:11:34 +01001275 uint64_t mask = arg1 >> (TARGET_PAGE_BITS + 1);
1276 if (!(env->insn_flags & ISA_MIPS32R6) || (arg1 == ~0) ||
1277 (mask == 0x0000 || mask == 0x0003 || mask == 0x000F ||
1278 mask == 0x003F || mask == 0x00FF || mask == 0x03FF ||
1279 mask == 0x0FFF || mask == 0x3FFF || mask == 0xFFFF)) {
1280 env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
1281 }
thsf1aa6322008-06-09 07:13:38 +00001282}
1283
Blue Swirl895c2d02012-09-02 14:52:59 +00001284void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001285{
1286 /* SmartMIPS not implemented */
thsf1aa6322008-06-09 07:13:38 +00001287 /* 1k pages not implemented */
Leon Alrae7207c7f2014-07-07 11:23:59 +01001288 env->CP0_PageGrain = (arg1 & env->CP0_PageGrain_rw_bitmask) |
1289 (env->CP0_PageGrain & ~env->CP0_PageGrain_rw_bitmask);
Leon Alraee117f522015-04-14 10:09:38 +01001290 compute_hflags(env);
1291 restore_pamask(env);
thsf1aa6322008-06-09 07:13:38 +00001292}
1293
Blue Swirl895c2d02012-09-02 14:52:59 +00001294void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001295{
Leon Alraeba801af2014-07-11 16:11:34 +01001296 if (env->insn_flags & ISA_MIPS32R6) {
1297 if (arg1 < env->tlb->nb_tlb) {
1298 env->CP0_Wired = arg1;
1299 }
1300 } else {
1301 env->CP0_Wired = arg1 % env->tlb->nb_tlb;
1302 }
thsf1aa6322008-06-09 07:13:38 +00001303}
1304
Blue Swirl895c2d02012-09-02 14:52:59 +00001305void helper_mtc0_srsconf0(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001306{
aurel32d9bea112009-04-15 14:41:44 +00001307 env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask;
thsf1aa6322008-06-09 07:13:38 +00001308}
1309
Blue Swirl895c2d02012-09-02 14:52:59 +00001310void helper_mtc0_srsconf1(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001311{
aurel32d9bea112009-04-15 14:41:44 +00001312 env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask;
thsf1aa6322008-06-09 07:13:38 +00001313}
1314
Blue Swirl895c2d02012-09-02 14:52:59 +00001315void helper_mtc0_srsconf2(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001316{
aurel32d9bea112009-04-15 14:41:44 +00001317 env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask;
thsf1aa6322008-06-09 07:13:38 +00001318}
1319
Blue Swirl895c2d02012-09-02 14:52:59 +00001320void helper_mtc0_srsconf3(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001321{
aurel32d9bea112009-04-15 14:41:44 +00001322 env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask;
thsf1aa6322008-06-09 07:13:38 +00001323}
1324
Blue Swirl895c2d02012-09-02 14:52:59 +00001325void helper_mtc0_srsconf4(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001326{
aurel32d9bea112009-04-15 14:41:44 +00001327 env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask;
thsf1aa6322008-06-09 07:13:38 +00001328}
1329
Blue Swirl895c2d02012-09-02 14:52:59 +00001330void helper_mtc0_hwrena(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001331{
Petar Jovanovicd2792792014-06-18 17:48:20 +02001332 uint32_t mask = 0x0000000F;
1333
1334 if (env->CP0_Config3 & (1 << CP0C3_ULRI)) {
1335 mask |= (1 << 29);
1336
1337 if (arg1 & (1 << 29)) {
1338 env->hflags |= MIPS_HFLAG_HWRENA_ULR;
1339 } else {
1340 env->hflags &= ~MIPS_HFLAG_HWRENA_ULR;
1341 }
1342 }
1343
1344 env->CP0_HWREna = arg1 & mask;
thsf1aa6322008-06-09 07:13:38 +00001345}
1346
Blue Swirl895c2d02012-09-02 14:52:59 +00001347void helper_mtc0_count(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001348{
aurel32d9bea112009-04-15 14:41:44 +00001349 cpu_mips_store_count(env, arg1);
thsf1aa6322008-06-09 07:13:38 +00001350}
1351
Blue Swirl895c2d02012-09-02 14:52:59 +00001352void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001353{
Leon Alrae9456c2f2014-07-07 11:24:00 +01001354 target_ulong old, val, mask;
1355 mask = (TARGET_PAGE_MASK << 1) | 0xFF;
1356 if (((env->CP0_Config4 >> CP0C4_IE) & 0x3) >= 2) {
1357 mask |= 1 << CP0EnHi_EHINV;
1358 }
thsf1aa6322008-06-09 07:13:38 +00001359
1360 /* 1k pages not implemented */
thsf1aa6322008-06-09 07:13:38 +00001361#if defined(TARGET_MIPS64)
Leon Alraeba801af2014-07-11 16:11:34 +01001362 if (env->insn_flags & ISA_MIPS32R6) {
1363 int entryhi_r = extract64(arg1, 62, 2);
1364 int config0_at = extract32(env->CP0_Config0, 13, 2);
1365 bool no_supervisor = (env->CP0_Status_rw_bitmask & 0x8) == 0;
1366 if ((entryhi_r == 2) ||
1367 (entryhi_r == 1 && (no_supervisor || config0_at == 1))) {
1368 /* skip EntryHi.R field if new value is reserved */
1369 mask &= ~(0x3ull << 62);
1370 }
1371 }
1372 mask &= env->SEGMask;
thsf1aa6322008-06-09 07:13:38 +00001373#endif
1374 old = env->CP0_EntryHi;
Leon Alraeba801af2014-07-11 16:11:34 +01001375 val = (arg1 & mask) | (old & ~mask);
thsf1aa6322008-06-09 07:13:38 +00001376 env->CP0_EntryHi = val;
1377 if (env->CP0_Config3 & (1 << CP0C3_MT)) {
Edgar E. Iglesiasfe8dca82011-08-29 23:07:33 +02001378 sync_c0_entryhi(env, env->current_tc);
thsf1aa6322008-06-09 07:13:38 +00001379 }
1380 /* If the ASID changes, flush qemu's TLB. */
1381 if ((old & 0xFF) != (val & 0xFF))
1382 cpu_mips_tlb_flush(env, 1);
1383}
1384
Blue Swirl895c2d02012-09-02 14:52:59 +00001385void helper_mttc0_entryhi(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001386{
1387 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +00001388 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +00001389
Edgar E. Iglesiasfe8dca82011-08-29 23:07:33 +02001390 other->CP0_EntryHi = arg1;
1391 sync_c0_entryhi(other, other_tc);
thsf1aa6322008-06-09 07:13:38 +00001392}
1393
Blue Swirl895c2d02012-09-02 14:52:59 +00001394void helper_mtc0_compare(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001395{
aurel32d9bea112009-04-15 14:41:44 +00001396 cpu_mips_store_compare(env, arg1);
thsf1aa6322008-06-09 07:13:38 +00001397}
1398
Blue Swirl895c2d02012-09-02 14:52:59 +00001399void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001400{
Andreas Färbera47dddd2013-09-03 17:38:47 +02001401 MIPSCPU *cpu = mips_env_get_cpu(env);
thsf1aa6322008-06-09 07:13:38 +00001402 uint32_t val, old;
thsf1aa6322008-06-09 07:13:38 +00001403
thsf1aa6322008-06-09 07:13:38 +00001404 old = env->CP0_Status;
Maciej W. Rozycki81a423e2014-11-10 13:46:35 +00001405 cpu_mips_store_status(env, arg1);
1406 val = env->CP0_Status;
Edgar E. Iglesiasfe8dca82011-08-29 23:07:33 +02001407
aurel32c01fccd2009-03-08 00:06:01 +00001408 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1409 qemu_log("Status %08x (%08x) => %08x (%08x) Cause %08x",
1410 old, old & env->CP0_Cause & CP0Ca_IP_mask,
1411 val, val & env->CP0_Cause & CP0Ca_IP_mask,
1412 env->CP0_Cause);
1413 switch (env->hflags & MIPS_HFLAG_KSU) {
1414 case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
1415 case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
1416 case MIPS_HFLAG_KM: qemu_log("\n"); break;
Andreas Färbera47dddd2013-09-03 17:38:47 +02001417 default:
1418 cpu_abort(CPU(cpu), "Invalid MMU mode!\n");
1419 break;
Aurelien Jarno31e31042009-11-14 13:10:00 +01001420 }
aurel32c01fccd2009-03-08 00:06:01 +00001421 }
thsf1aa6322008-06-09 07:13:38 +00001422}
1423
Blue Swirl895c2d02012-09-02 14:52:59 +00001424void helper_mttc0_status(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001425{
1426 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Maciej W. Rozycki1d725ae2014-11-20 11:15:34 +00001427 uint32_t mask = env->CP0_Status_rw_bitmask & ~0xf1000018;
Blue Swirl895c2d02012-09-02 14:52:59 +00001428 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +00001429
Maciej W. Rozycki1d725ae2014-11-20 11:15:34 +00001430 other->CP0_Status = (other->CP0_Status & ~mask) | (arg1 & mask);
Blue Swirl895c2d02012-09-02 14:52:59 +00001431 sync_c0_status(env, other, other_tc);
thsf1aa6322008-06-09 07:13:38 +00001432}
1433
Blue Swirl895c2d02012-09-02 14:52:59 +00001434void helper_mtc0_intctl(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001435{
Edgar E. Iglesiasbc45a672011-08-29 23:07:35 +02001436 env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000003e0) | (arg1 & 0x000003e0);
thsf1aa6322008-06-09 07:13:38 +00001437}
1438
Blue Swirl895c2d02012-09-02 14:52:59 +00001439void helper_mtc0_srsctl(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001440{
1441 uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
aurel32d9bea112009-04-15 14:41:44 +00001442 env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask);
thsf1aa6322008-06-09 07:13:38 +00001443}
1444
Blue Swirl895c2d02012-09-02 14:52:59 +00001445void helper_mtc0_cause(CPUMIPSState *env, target_ulong arg1)
Edgar E. Iglesias5a25ce92011-08-29 23:07:34 +02001446{
Maciej W. Rozycki81a423e2014-11-10 13:46:35 +00001447 cpu_mips_store_cause(env, arg1);
Edgar E. Iglesias5a25ce92011-08-29 23:07:34 +02001448}
1449
Blue Swirl895c2d02012-09-02 14:52:59 +00001450void helper_mttc0_cause(CPUMIPSState *env, target_ulong arg1)
Edgar E. Iglesias5a25ce92011-08-29 23:07:34 +02001451{
1452 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +00001453 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Edgar E. Iglesias5a25ce92011-08-29 23:07:34 +02001454
Maciej W. Rozycki81a423e2014-11-10 13:46:35 +00001455 cpu_mips_store_cause(other, arg1);
Edgar E. Iglesias5a25ce92011-08-29 23:07:34 +02001456}
1457
Blue Swirl895c2d02012-09-02 14:52:59 +00001458target_ulong helper_mftc0_epc(CPUMIPSState *env)
Edgar E. Iglesias5a25ce92011-08-29 23:07:34 +02001459{
1460 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +00001461 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Edgar E. Iglesias5a25ce92011-08-29 23:07:34 +02001462
1463 return other->CP0_EPC;
1464}
1465
Blue Swirl895c2d02012-09-02 14:52:59 +00001466target_ulong helper_mftc0_ebase(CPUMIPSState *env)
Edgar E. Iglesias5a25ce92011-08-29 23:07:34 +02001467{
1468 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +00001469 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Edgar E. Iglesias5a25ce92011-08-29 23:07:34 +02001470
1471 return other->CP0_EBase;
1472}
1473
Blue Swirl895c2d02012-09-02 14:52:59 +00001474void helper_mtc0_ebase(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001475{
Hervé Poussineau671b0f32010-07-31 12:29:03 +02001476 env->CP0_EBase = (env->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
thsf1aa6322008-06-09 07:13:38 +00001477}
1478
Blue Swirl895c2d02012-09-02 14:52:59 +00001479void helper_mttc0_ebase(CPUMIPSState *env, target_ulong arg1)
Edgar E. Iglesias5a25ce92011-08-29 23:07:34 +02001480{
1481 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +00001482 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Edgar E. Iglesias5a25ce92011-08-29 23:07:34 +02001483 other->CP0_EBase = (other->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
1484}
1485
Blue Swirl895c2d02012-09-02 14:52:59 +00001486target_ulong helper_mftc0_configx(CPUMIPSState *env, target_ulong idx)
Edgar E. Iglesias5a25ce92011-08-29 23:07:34 +02001487{
1488 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +00001489 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
Edgar E. Iglesias5a25ce92011-08-29 23:07:34 +02001490
1491 switch (idx) {
1492 case 0: return other->CP0_Config0;
1493 case 1: return other->CP0_Config1;
1494 case 2: return other->CP0_Config2;
1495 case 3: return other->CP0_Config3;
1496 /* 4 and 5 are reserved. */
1497 case 6: return other->CP0_Config6;
1498 case 7: return other->CP0_Config7;
1499 default:
1500 break;
1501 }
1502 return 0;
1503}
1504
Blue Swirl895c2d02012-09-02 14:52:59 +00001505void helper_mtc0_config0(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001506{
aurel32d9bea112009-04-15 14:41:44 +00001507 env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007);
thsf1aa6322008-06-09 07:13:38 +00001508}
1509
Blue Swirl895c2d02012-09-02 14:52:59 +00001510void helper_mtc0_config2(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001511{
1512 /* tertiary/secondary caches not implemented */
1513 env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
1514}
1515
Maciej W. Rozycki90f12d72014-11-18 03:59:07 +00001516void helper_mtc0_config3(CPUMIPSState *env, target_ulong arg1)
1517{
1518 if (env->insn_flags & ASE_MICROMIPS) {
1519 env->CP0_Config3 = (env->CP0_Config3 & ~(1 << CP0C3_ISA_ON_EXC)) |
1520 (arg1 & (1 << CP0C3_ISA_ON_EXC));
1521 }
1522}
1523
Petar Jovanovicb4160af2014-01-24 13:45:05 +01001524void helper_mtc0_config4(CPUMIPSState *env, target_ulong arg1)
1525{
1526 env->CP0_Config4 = (env->CP0_Config4 & (~env->CP0_Config4_rw_bitmask)) |
1527 (arg1 & env->CP0_Config4_rw_bitmask);
1528}
1529
Petar Jovanovicb4dd99a2014-01-17 19:25:57 +01001530void helper_mtc0_config5(CPUMIPSState *env, target_ulong arg1)
1531{
1532 env->CP0_Config5 = (env->CP0_Config5 & (~env->CP0_Config5_rw_bitmask)) |
1533 (arg1 & env->CP0_Config5_rw_bitmask);
Yongbok Kime97a3912014-11-01 05:28:35 +00001534 compute_hflags(env);
Petar Jovanovicb4dd99a2014-01-17 19:25:57 +01001535}
1536
Blue Swirl895c2d02012-09-02 14:52:59 +00001537void helper_mtc0_lladdr(CPUMIPSState *env, target_ulong arg1)
Aurelien Jarno2a6e32d2009-11-22 13:22:54 +01001538{
1539 target_long mask = env->CP0_LLAddr_rw_bitmask;
1540 arg1 = arg1 << env->CP0_LLAddr_shift;
1541 env->lladdr = (env->lladdr & ~mask) | (arg1 & mask);
1542}
1543
Blue Swirl895c2d02012-09-02 14:52:59 +00001544void helper_mtc0_watchlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +00001545{
1546 /* Watch exceptions for instructions, data loads, data stores
1547 not implemented. */
aurel32d9bea112009-04-15 14:41:44 +00001548 env->CP0_WatchLo[sel] = (arg1 & ~0x7);
thsf1aa6322008-06-09 07:13:38 +00001549}
1550
Blue Swirl895c2d02012-09-02 14:52:59 +00001551void helper_mtc0_watchhi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +00001552{
aurel32d9bea112009-04-15 14:41:44 +00001553 env->CP0_WatchHi[sel] = (arg1 & 0x40FF0FF8);
1554 env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7);
thsf1aa6322008-06-09 07:13:38 +00001555}
1556
Blue Swirl895c2d02012-09-02 14:52:59 +00001557void helper_mtc0_xcontext(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001558{
1559 target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
aurel32d9bea112009-04-15 14:41:44 +00001560 env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask);
thsf1aa6322008-06-09 07:13:38 +00001561}
1562
Blue Swirl895c2d02012-09-02 14:52:59 +00001563void helper_mtc0_framemask(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001564{
aurel32d9bea112009-04-15 14:41:44 +00001565 env->CP0_Framemask = arg1; /* XXX */
thsf1aa6322008-06-09 07:13:38 +00001566}
1567
Blue Swirl895c2d02012-09-02 14:52:59 +00001568void helper_mtc0_debug(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001569{
aurel32d9bea112009-04-15 14:41:44 +00001570 env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120);
1571 if (arg1 & (1 << CP0DB_DM))
thsf1aa6322008-06-09 07:13:38 +00001572 env->hflags |= MIPS_HFLAG_DM;
1573 else
1574 env->hflags &= ~MIPS_HFLAG_DM;
1575}
1576
Blue Swirl895c2d02012-09-02 14:52:59 +00001577void helper_mttc0_debug(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001578{
1579 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
aurel32d9bea112009-04-15 14:41:44 +00001580 uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
Blue Swirl895c2d02012-09-02 14:52:59 +00001581 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +00001582
1583 /* XXX: Might be wrong, check with EJTAG spec. */
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001584 if (other_tc == other->current_tc)
1585 other->active_tc.CP0_Debug_tcstatus = val;
thsb5dc7732008-06-27 10:02:35 +00001586 else
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001587 other->tcs[other_tc].CP0_Debug_tcstatus = val;
1588 other->CP0_Debug = (other->CP0_Debug &
1589 ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
aurel32d9bea112009-04-15 14:41:44 +00001590 (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
thsf1aa6322008-06-09 07:13:38 +00001591}
1592
Blue Swirl895c2d02012-09-02 14:52:59 +00001593void helper_mtc0_performance0(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001594{
aurel32d9bea112009-04-15 14:41:44 +00001595 env->CP0_Performance0 = arg1 & 0x000007ff;
thsf1aa6322008-06-09 07:13:38 +00001596}
1597
Blue Swirl895c2d02012-09-02 14:52:59 +00001598void helper_mtc0_taglo(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001599{
aurel32d9bea112009-04-15 14:41:44 +00001600 env->CP0_TagLo = arg1 & 0xFFFFFCF6;
thsf1aa6322008-06-09 07:13:38 +00001601}
1602
Blue Swirl895c2d02012-09-02 14:52:59 +00001603void helper_mtc0_datalo(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001604{
aurel32d9bea112009-04-15 14:41:44 +00001605 env->CP0_DataLo = arg1; /* XXX */
thsf1aa6322008-06-09 07:13:38 +00001606}
1607
Blue Swirl895c2d02012-09-02 14:52:59 +00001608void helper_mtc0_taghi(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001609{
aurel32d9bea112009-04-15 14:41:44 +00001610 env->CP0_TagHi = arg1; /* XXX */
thsf1aa6322008-06-09 07:13:38 +00001611}
1612
Blue Swirl895c2d02012-09-02 14:52:59 +00001613void helper_mtc0_datahi(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001614{
aurel32d9bea112009-04-15 14:41:44 +00001615 env->CP0_DataHi = arg1; /* XXX */
thsf1aa6322008-06-09 07:13:38 +00001616}
1617
thsf1aa6322008-06-09 07:13:38 +00001618/* MIPS MT functions */
Blue Swirl895c2d02012-09-02 14:52:59 +00001619target_ulong helper_mftgpr(CPUMIPSState *env, uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +00001620{
1621 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +00001622 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +00001623
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001624 if (other_tc == other->current_tc)
1625 return other->active_tc.gpr[sel];
thsb5dc7732008-06-27 10:02:35 +00001626 else
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001627 return other->tcs[other_tc].gpr[sel];
thsf1aa6322008-06-09 07:13:38 +00001628}
1629
Blue Swirl895c2d02012-09-02 14:52:59 +00001630target_ulong helper_mftlo(CPUMIPSState *env, uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +00001631{
1632 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +00001633 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +00001634
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001635 if (other_tc == other->current_tc)
1636 return other->active_tc.LO[sel];
thsb5dc7732008-06-27 10:02:35 +00001637 else
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001638 return other->tcs[other_tc].LO[sel];
thsf1aa6322008-06-09 07:13:38 +00001639}
1640
Blue Swirl895c2d02012-09-02 14:52:59 +00001641target_ulong helper_mfthi(CPUMIPSState *env, uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +00001642{
1643 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +00001644 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +00001645
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001646 if (other_tc == other->current_tc)
1647 return other->active_tc.HI[sel];
thsb5dc7732008-06-27 10:02:35 +00001648 else
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001649 return other->tcs[other_tc].HI[sel];
thsf1aa6322008-06-09 07:13:38 +00001650}
1651
Blue Swirl895c2d02012-09-02 14:52:59 +00001652target_ulong helper_mftacx(CPUMIPSState *env, uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +00001653{
1654 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +00001655 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +00001656
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001657 if (other_tc == other->current_tc)
1658 return other->active_tc.ACX[sel];
thsb5dc7732008-06-27 10:02:35 +00001659 else
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001660 return other->tcs[other_tc].ACX[sel];
thsf1aa6322008-06-09 07:13:38 +00001661}
1662
Blue Swirl895c2d02012-09-02 14:52:59 +00001663target_ulong helper_mftdsp(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +00001664{
1665 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +00001666 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +00001667
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001668 if (other_tc == other->current_tc)
1669 return other->active_tc.DSPControl;
thsb5dc7732008-06-27 10:02:35 +00001670 else
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001671 return other->tcs[other_tc].DSPControl;
thsf1aa6322008-06-09 07:13:38 +00001672}
1673
Blue Swirl895c2d02012-09-02 14:52:59 +00001674void helper_mttgpr(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +00001675{
1676 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +00001677 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +00001678
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001679 if (other_tc == other->current_tc)
1680 other->active_tc.gpr[sel] = arg1;
thsb5dc7732008-06-27 10:02:35 +00001681 else
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001682 other->tcs[other_tc].gpr[sel] = arg1;
thsf1aa6322008-06-09 07:13:38 +00001683}
1684
Blue Swirl895c2d02012-09-02 14:52:59 +00001685void helper_mttlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +00001686{
1687 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +00001688 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +00001689
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001690 if (other_tc == other->current_tc)
1691 other->active_tc.LO[sel] = arg1;
thsb5dc7732008-06-27 10:02:35 +00001692 else
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001693 other->tcs[other_tc].LO[sel] = arg1;
thsf1aa6322008-06-09 07:13:38 +00001694}
1695
Blue Swirl895c2d02012-09-02 14:52:59 +00001696void helper_mtthi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +00001697{
1698 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +00001699 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +00001700
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001701 if (other_tc == other->current_tc)
1702 other->active_tc.HI[sel] = arg1;
thsb5dc7732008-06-27 10:02:35 +00001703 else
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001704 other->tcs[other_tc].HI[sel] = arg1;
thsf1aa6322008-06-09 07:13:38 +00001705}
1706
Blue Swirl895c2d02012-09-02 14:52:59 +00001707void helper_mttacx(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
thsf1aa6322008-06-09 07:13:38 +00001708{
1709 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +00001710 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +00001711
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001712 if (other_tc == other->current_tc)
1713 other->active_tc.ACX[sel] = arg1;
thsb5dc7732008-06-27 10:02:35 +00001714 else
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001715 other->tcs[other_tc].ACX[sel] = arg1;
thsf1aa6322008-06-09 07:13:38 +00001716}
1717
Blue Swirl895c2d02012-09-02 14:52:59 +00001718void helper_mttdsp(CPUMIPSState *env, target_ulong arg1)
thsf1aa6322008-06-09 07:13:38 +00001719{
1720 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
Blue Swirl895c2d02012-09-02 14:52:59 +00001721 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
thsf1aa6322008-06-09 07:13:38 +00001722
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001723 if (other_tc == other->current_tc)
1724 other->active_tc.DSPControl = arg1;
thsb5dc7732008-06-27 10:02:35 +00001725 else
Edgar E. Iglesiasb93bbdc2011-08-29 23:07:32 +02001726 other->tcs[other_tc].DSPControl = arg1;
thsf1aa6322008-06-09 07:13:38 +00001727}
1728
1729/* MIPS MT functions */
Nathan Froyd9ed57262010-10-29 07:48:46 -07001730target_ulong helper_dmt(void)
thsf1aa6322008-06-09 07:13:38 +00001731{
1732 // TODO
Nathan Froyd9ed57262010-10-29 07:48:46 -07001733 return 0;
thsf1aa6322008-06-09 07:13:38 +00001734}
1735
Nathan Froyd9ed57262010-10-29 07:48:46 -07001736target_ulong helper_emt(void)
thsf1aa6322008-06-09 07:13:38 +00001737{
1738 // TODO
Nathan Froyd9ed57262010-10-29 07:48:46 -07001739 return 0;
thsf1aa6322008-06-09 07:13:38 +00001740}
1741
Blue Swirl895c2d02012-09-02 14:52:59 +00001742target_ulong helper_dvpe(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +00001743{
Andreas Färber182735e2013-05-29 22:29:20 +02001744 CPUState *other_cs = first_cpu;
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +02001745 target_ulong prev = env->mvp->CP0_MVPControl;
1746
Andreas Färberbdc44642013-06-24 23:50:24 +02001747 CPU_FOREACH(other_cs) {
Andreas Färber182735e2013-05-29 22:29:20 +02001748 MIPSCPU *other_cpu = MIPS_CPU(other_cs);
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +02001749 /* Turn off all VPEs except the one executing the dvpe. */
Andreas Färber182735e2013-05-29 22:29:20 +02001750 if (&other_cpu->env != env) {
1751 other_cpu->env.mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP);
Andreas Färber6f4d6b02012-10-12 00:56:37 +02001752 mips_vpe_sleep(other_cpu);
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +02001753 }
Andreas Färberbdc44642013-06-24 23:50:24 +02001754 }
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +02001755 return prev;
thsf1aa6322008-06-09 07:13:38 +00001756}
1757
Blue Swirl895c2d02012-09-02 14:52:59 +00001758target_ulong helper_evpe(CPUMIPSState *env)
thsf1aa6322008-06-09 07:13:38 +00001759{
Andreas Färber182735e2013-05-29 22:29:20 +02001760 CPUState *other_cs = first_cpu;
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +02001761 target_ulong prev = env->mvp->CP0_MVPControl;
1762
Andreas Färberbdc44642013-06-24 23:50:24 +02001763 CPU_FOREACH(other_cs) {
Andreas Färber182735e2013-05-29 22:29:20 +02001764 MIPSCPU *other_cpu = MIPS_CPU(other_cs);
Andreas Färberb35d77d2012-10-12 00:56:35 +02001765
Andreas Färber182735e2013-05-29 22:29:20 +02001766 if (&other_cpu->env != env
Andreas Färber81bad502012-10-12 00:56:33 +02001767 /* If the VPE is WFI, don't disturb its sleep. */
Andreas Färberb35d77d2012-10-12 00:56:35 +02001768 && !mips_vpe_is_wfi(other_cpu)) {
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +02001769 /* Enable the VPE. */
Andreas Färber182735e2013-05-29 22:29:20 +02001770 other_cpu->env.mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
Andreas Färberc3affe52013-01-18 15:03:43 +01001771 mips_vpe_wake(other_cpu); /* And wake it up. */
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +02001772 }
Andreas Färberbdc44642013-06-24 23:50:24 +02001773 }
Edgar E. Iglesiasf2494122011-08-29 23:07:40 +02001774 return prev;
thsf1aa6322008-06-09 07:13:38 +00001775}
thsf9480ff2008-12-20 19:42:14 +00001776#endif /* !CONFIG_USER_ONLY */
thsf1aa6322008-06-09 07:13:38 +00001777
aurel32d9bea112009-04-15 14:41:44 +00001778void helper_fork(target_ulong arg1, target_ulong arg2)
thsf1aa6322008-06-09 07:13:38 +00001779{
aurel32d9bea112009-04-15 14:41:44 +00001780 // arg1 = rt, arg2 = rs
thsf1aa6322008-06-09 07:13:38 +00001781 // TODO: store to TC register
1782}
1783
Blue Swirl895c2d02012-09-02 14:52:59 +00001784target_ulong helper_yield(CPUMIPSState *env, target_ulong arg)
thsf1aa6322008-06-09 07:13:38 +00001785{
Blue Swirl1c7242d2010-09-18 05:53:15 +00001786 target_long arg1 = arg;
1787
aurel32d9bea112009-04-15 14:41:44 +00001788 if (arg1 < 0) {
thsf1aa6322008-06-09 07:13:38 +00001789 /* No scheduling policy implemented. */
aurel32d9bea112009-04-15 14:41:44 +00001790 if (arg1 != -2) {
thsf1aa6322008-06-09 07:13:38 +00001791 if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
thsb5dc7732008-06-27 10:02:35 +00001792 env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
thsf1aa6322008-06-09 07:13:38 +00001793 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1794 env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
Blue Swirl895c2d02012-09-02 14:52:59 +00001795 helper_raise_exception(env, EXCP_THREAD);
thsf1aa6322008-06-09 07:13:38 +00001796 }
1797 }
aurel32d9bea112009-04-15 14:41:44 +00001798 } else if (arg1 == 0) {
aurel3269585492009-01-14 19:40:36 +00001799 if (0 /* TODO: TC underflow */) {
thsf1aa6322008-06-09 07:13:38 +00001800 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
Blue Swirl895c2d02012-09-02 14:52:59 +00001801 helper_raise_exception(env, EXCP_THREAD);
thsf1aa6322008-06-09 07:13:38 +00001802 } else {
1803 // TODO: Deallocate TC
1804 }
aurel32d9bea112009-04-15 14:41:44 +00001805 } else if (arg1 > 0) {
thsf1aa6322008-06-09 07:13:38 +00001806 /* Yield qualifier inputs not implemented. */
1807 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1808 env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
Blue Swirl895c2d02012-09-02 14:52:59 +00001809 helper_raise_exception(env, EXCP_THREAD);
thsf1aa6322008-06-09 07:13:38 +00001810 }
thsbe24bb42008-06-23 12:57:09 +00001811 return env->CP0_YQMask;
thsf1aa6322008-06-09 07:13:38 +00001812}
1813
thsf1aa6322008-06-09 07:13:38 +00001814#ifndef CONFIG_USER_ONLY
bellard6af0bf92005-07-02 14:58:51 +00001815/* TLB management */
Andreas Färber7db13fa2012-03-14 01:38:22 +01001816static void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global)
ths814b9a42006-12-06 17:42:40 +00001817{
Andreas Färber00c8cb02013-09-04 02:19:44 +02001818 MIPSCPU *cpu = mips_env_get_cpu(env);
1819
ths814b9a42006-12-06 17:42:40 +00001820 /* Flush qemu's TLB and discard all shadowed entries. */
Andreas Färber00c8cb02013-09-04 02:19:44 +02001821 tlb_flush(CPU(cpu), flush_global);
thsead93602007-09-06 00:18:15 +00001822 env->tlb->tlb_in_use = env->tlb->nb_tlb;
ths814b9a42006-12-06 17:42:40 +00001823}
1824
Andreas Färber7db13fa2012-03-14 01:38:22 +01001825static void r4k_mips_tlb_flush_extra (CPUMIPSState *env, int first)
ths814b9a42006-12-06 17:42:40 +00001826{
1827 /* Discard entries from env->tlb[first] onwards. */
thsead93602007-09-06 00:18:15 +00001828 while (env->tlb->tlb_in_use > first) {
1829 r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
ths814b9a42006-12-06 17:42:40 +00001830 }
1831}
1832
Leon Alraecd0d45c2014-09-11 16:28:16 +01001833static inline uint64_t get_tlb_pfn_from_entrylo(uint64_t entrylo)
1834{
1835#if defined(TARGET_MIPS64)
1836 return extract64(entrylo, 6, 54);
1837#else
1838 return extract64(entrylo, 6, 24) | /* PFN */
1839 (extract64(entrylo, 32, 32) << 24); /* PFNX */
1840#endif
1841}
1842
Blue Swirl895c2d02012-09-02 14:52:59 +00001843static void r4k_fill_tlb(CPUMIPSState *env, int idx)
bellard6af0bf92005-07-02 14:58:51 +00001844{
Anthony Liguoric227f092009-10-01 16:12:16 -05001845 r4k_tlb_t *tlb;
bellard6af0bf92005-07-02 14:58:51 +00001846
1847 /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
thsead93602007-09-06 00:18:15 +00001848 tlb = &env->tlb->mmu.r4k.tlb[idx];
Leon Alrae9456c2f2014-07-07 11:24:00 +01001849 if (env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) {
1850 tlb->EHINV = 1;
1851 return;
1852 }
1853 tlb->EHINV = 0;
thsf2e9ebe2007-05-13 14:07:26 +00001854 tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
thsd26bc212007-11-08 18:05:37 +00001855#if defined(TARGET_MIPS64)
thse034e2c2007-06-23 18:04:12 +00001856 tlb->VPN &= env->SEGMask;
ths100ce982007-05-13 19:22:13 +00001857#endif
pbrook98c1b822006-03-11 16:20:36 +00001858 tlb->ASID = env->CP0_EntryHi & 0xFF;
ths3b1c8be2007-01-22 20:50:42 +00001859 tlb->PageMask = env->CP0_PageMask;
bellard6af0bf92005-07-02 14:58:51 +00001860 tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
pbrook98c1b822006-03-11 16:20:36 +00001861 tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
1862 tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
1863 tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
Leon Alrae2fb58b72014-07-07 11:23:58 +01001864 tlb->XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) & 1;
1865 tlb->RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) & 1;
Leon Alraecd0d45c2014-09-11 16:28:16 +01001866 tlb->PFN[0] = get_tlb_pfn_from_entrylo(env->CP0_EntryLo0) << 12;
pbrook98c1b822006-03-11 16:20:36 +00001867 tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
1868 tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
1869 tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
Leon Alrae2fb58b72014-07-07 11:23:58 +01001870 tlb->XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) & 1;
1871 tlb->RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) & 1;
Leon Alraecd0d45c2014-09-11 16:28:16 +01001872 tlb->PFN[1] = get_tlb_pfn_from_entrylo(env->CP0_EntryLo1) << 12;
bellard6af0bf92005-07-02 14:58:51 +00001873}
1874
Leon Alrae9456c2f2014-07-07 11:24:00 +01001875void r4k_helper_tlbinv(CPUMIPSState *env)
1876{
1877 int idx;
1878 r4k_tlb_t *tlb;
1879 uint8_t ASID = env->CP0_EntryHi & 0xFF;
1880
1881 for (idx = 0; idx < env->tlb->nb_tlb; idx++) {
1882 tlb = &env->tlb->mmu.r4k.tlb[idx];
1883 if (!tlb->G && tlb->ASID == ASID) {
1884 tlb->EHINV = 1;
1885 }
1886 }
1887 cpu_mips_tlb_flush(env, 1);
1888}
1889
1890void r4k_helper_tlbinvf(CPUMIPSState *env)
1891{
1892 int idx;
1893
1894 for (idx = 0; idx < env->tlb->nb_tlb; idx++) {
1895 env->tlb->mmu.r4k.tlb[idx].EHINV = 1;
1896 }
1897 cpu_mips_tlb_flush(env, 1);
1898}
1899
Blue Swirl895c2d02012-09-02 14:52:59 +00001900void r4k_helper_tlbwi(CPUMIPSState *env)
bellard6af0bf92005-07-02 14:58:51 +00001901{
Aurelien Jarno286d52e2012-10-09 21:53:21 +02001902 r4k_tlb_t *tlb;
aurel32bbc0d792008-09-14 17:09:56 +00001903 int idx;
Aurelien Jarno286d52e2012-10-09 21:53:21 +02001904 target_ulong VPN;
1905 uint8_t ASID;
1906 bool G, V0, D0, V1, D1;
aurel32bbc0d792008-09-14 17:09:56 +00001907
1908 idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
Aurelien Jarno286d52e2012-10-09 21:53:21 +02001909 tlb = &env->tlb->mmu.r4k.tlb[idx];
1910 VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
1911#if defined(TARGET_MIPS64)
1912 VPN &= env->SEGMask;
1913#endif
1914 ASID = env->CP0_EntryHi & 0xff;
1915 G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
1916 V0 = (env->CP0_EntryLo0 & 2) != 0;
1917 D0 = (env->CP0_EntryLo0 & 4) != 0;
1918 V1 = (env->CP0_EntryLo1 & 2) != 0;
1919 D1 = (env->CP0_EntryLo1 & 4) != 0;
aurel32bbc0d792008-09-14 17:09:56 +00001920
Aurelien Jarno286d52e2012-10-09 21:53:21 +02001921 /* Discard cached TLB entries, unless tlbwi is just upgrading access
1922 permissions on the current entry. */
1923 if (tlb->VPN != VPN || tlb->ASID != ASID || tlb->G != G ||
1924 (tlb->V0 && !V0) || (tlb->D0 && !D0) ||
1925 (tlb->V1 && !V1) || (tlb->D1 && !D1)) {
1926 r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
1927 }
ths814b9a42006-12-06 17:42:40 +00001928
aurel32bbc0d792008-09-14 17:09:56 +00001929 r4k_invalidate_tlb(env, idx, 0);
Blue Swirl895c2d02012-09-02 14:52:59 +00001930 r4k_fill_tlb(env, idx);
bellard6af0bf92005-07-02 14:58:51 +00001931}
1932
Blue Swirl895c2d02012-09-02 14:52:59 +00001933void r4k_helper_tlbwr(CPUMIPSState *env)
bellard6af0bf92005-07-02 14:58:51 +00001934{
1935 int r = cpu_mips_get_random(env);
1936
ths29929e32007-05-13 13:49:44 +00001937 r4k_invalidate_tlb(env, r, 1);
Blue Swirl895c2d02012-09-02 14:52:59 +00001938 r4k_fill_tlb(env, r);
bellard6af0bf92005-07-02 14:58:51 +00001939}
1940
Blue Swirl895c2d02012-09-02 14:52:59 +00001941void r4k_helper_tlbp(CPUMIPSState *env)
bellard6af0bf92005-07-02 14:58:51 +00001942{
Anthony Liguoric227f092009-10-01 16:12:16 -05001943 r4k_tlb_t *tlb;
thsf2e9ebe2007-05-13 14:07:26 +00001944 target_ulong mask;
bellard6af0bf92005-07-02 14:58:51 +00001945 target_ulong tag;
thsf2e9ebe2007-05-13 14:07:26 +00001946 target_ulong VPN;
bellard6af0bf92005-07-02 14:58:51 +00001947 uint8_t ASID;
1948 int i;
1949
bellard3d9fb9fe2006-05-22 22:13:29 +00001950 ASID = env->CP0_EntryHi & 0xFF;
thsead93602007-09-06 00:18:15 +00001951 for (i = 0; i < env->tlb->nb_tlb; i++) {
1952 tlb = &env->tlb->mmu.r4k.tlb[i];
thsf2e9ebe2007-05-13 14:07:26 +00001953 /* 1k pages are not supported. */
1954 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
1955 tag = env->CP0_EntryHi & ~mask;
1956 VPN = tlb->VPN & ~mask;
Aurelien Jarnobc3e45e2012-10-09 21:53:21 +02001957#if defined(TARGET_MIPS64)
1958 tag &= env->SEGMask;
1959#endif
bellard6af0bf92005-07-02 14:58:51 +00001960 /* Check ASID, virtual page number & size */
Leon Alrae9456c2f2014-07-07 11:24:00 +01001961 if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag && !tlb->EHINV) {
bellard6af0bf92005-07-02 14:58:51 +00001962 /* TLB match */
ths9c2149c2007-01-23 22:45:22 +00001963 env->CP0_Index = i;
bellard6af0bf92005-07-02 14:58:51 +00001964 break;
1965 }
1966 }
thsead93602007-09-06 00:18:15 +00001967 if (i == env->tlb->nb_tlb) {
ths814b9a42006-12-06 17:42:40 +00001968 /* No match. Discard any shadow entries, if any of them match. */
thsead93602007-09-06 00:18:15 +00001969 for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
aurel3269585492009-01-14 19:40:36 +00001970 tlb = &env->tlb->mmu.r4k.tlb[i];
1971 /* 1k pages are not supported. */
1972 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
1973 tag = env->CP0_EntryHi & ~mask;
1974 VPN = tlb->VPN & ~mask;
Aurelien Jarnobc3e45e2012-10-09 21:53:21 +02001975#if defined(TARGET_MIPS64)
1976 tag &= env->SEGMask;
1977#endif
aurel3269585492009-01-14 19:40:36 +00001978 /* Check ASID, virtual page number & size */
1979 if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
ths29929e32007-05-13 13:49:44 +00001980 r4k_mips_tlb_flush_extra (env, i);
aurel3269585492009-01-14 19:40:36 +00001981 break;
1982 }
1983 }
ths814b9a42006-12-06 17:42:40 +00001984
ths9c2149c2007-01-23 22:45:22 +00001985 env->CP0_Index |= 0x80000000;
bellard6af0bf92005-07-02 14:58:51 +00001986 }
1987}
1988
Leon Alraecd0d45c2014-09-11 16:28:16 +01001989static inline uint64_t get_entrylo_pfn_from_tlb(uint64_t tlb_pfn)
1990{
1991#if defined(TARGET_MIPS64)
1992 return tlb_pfn << 6;
1993#else
1994 return (extract64(tlb_pfn, 0, 24) << 6) | /* PFN */
1995 (extract64(tlb_pfn, 24, 32) << 32); /* PFNX */
1996#endif
1997}
1998
Blue Swirl895c2d02012-09-02 14:52:59 +00001999void r4k_helper_tlbr(CPUMIPSState *env)
bellard6af0bf92005-07-02 14:58:51 +00002000{
Anthony Liguoric227f092009-10-01 16:12:16 -05002001 r4k_tlb_t *tlb;
pbrook09c56b82006-03-11 16:39:23 +00002002 uint8_t ASID;
aurel32bbc0d792008-09-14 17:09:56 +00002003 int idx;
bellard6af0bf92005-07-02 14:58:51 +00002004
pbrook09c56b82006-03-11 16:39:23 +00002005 ASID = env->CP0_EntryHi & 0xFF;
aurel32bbc0d792008-09-14 17:09:56 +00002006 idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
2007 tlb = &env->tlb->mmu.r4k.tlb[idx];
bellard4ad40f32005-12-05 19:59:36 +00002008
2009 /* If this will change the current ASID, flush qemu's TLB. */
ths814b9a42006-12-06 17:42:40 +00002010 if (ASID != tlb->ASID)
2011 cpu_mips_tlb_flush (env, 1);
2012
thsead93602007-09-06 00:18:15 +00002013 r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
bellard4ad40f32005-12-05 19:59:36 +00002014
Leon Alrae9456c2f2014-07-07 11:24:00 +01002015 if (tlb->EHINV) {
2016 env->CP0_EntryHi = 1 << CP0EnHi_EHINV;
2017 env->CP0_PageMask = 0;
2018 env->CP0_EntryLo0 = 0;
2019 env->CP0_EntryLo1 = 0;
2020 } else {
2021 env->CP0_EntryHi = tlb->VPN | tlb->ASID;
2022 env->CP0_PageMask = tlb->PageMask;
2023 env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
Leon Alrae284b7312015-06-09 17:14:13 +01002024 ((uint64_t)tlb->RI0 << CP0EnLo_RI) |
Leon Alraecd0d45c2014-09-11 16:28:16 +01002025 ((uint64_t)tlb->XI0 << CP0EnLo_XI) | (tlb->C0 << 3) |
2026 get_entrylo_pfn_from_tlb(tlb->PFN[0] >> 12);
Leon Alrae9456c2f2014-07-07 11:24:00 +01002027 env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
Leon Alrae284b7312015-06-09 17:14:13 +01002028 ((uint64_t)tlb->RI1 << CP0EnLo_RI) |
Leon Alraecd0d45c2014-09-11 16:28:16 +01002029 ((uint64_t)tlb->XI1 << CP0EnLo_XI) | (tlb->C1 << 3) |
2030 get_entrylo_pfn_from_tlb(tlb->PFN[1] >> 12);
Leon Alrae9456c2f2014-07-07 11:24:00 +01002031 }
bellard6af0bf92005-07-02 14:58:51 +00002032}
bellard6af0bf92005-07-02 14:58:51 +00002033
Blue Swirl895c2d02012-09-02 14:52:59 +00002034void helper_tlbwi(CPUMIPSState *env)
pbrooka7812ae2008-11-17 14:43:54 +00002035{
Blue Swirl895c2d02012-09-02 14:52:59 +00002036 env->tlb->helper_tlbwi(env);
pbrooka7812ae2008-11-17 14:43:54 +00002037}
2038
Blue Swirl895c2d02012-09-02 14:52:59 +00002039void helper_tlbwr(CPUMIPSState *env)
pbrooka7812ae2008-11-17 14:43:54 +00002040{
Blue Swirl895c2d02012-09-02 14:52:59 +00002041 env->tlb->helper_tlbwr(env);
pbrooka7812ae2008-11-17 14:43:54 +00002042}
2043
Blue Swirl895c2d02012-09-02 14:52:59 +00002044void helper_tlbp(CPUMIPSState *env)
pbrooka7812ae2008-11-17 14:43:54 +00002045{
Blue Swirl895c2d02012-09-02 14:52:59 +00002046 env->tlb->helper_tlbp(env);
pbrooka7812ae2008-11-17 14:43:54 +00002047}
2048
Blue Swirl895c2d02012-09-02 14:52:59 +00002049void helper_tlbr(CPUMIPSState *env)
pbrooka7812ae2008-11-17 14:43:54 +00002050{
Blue Swirl895c2d02012-09-02 14:52:59 +00002051 env->tlb->helper_tlbr(env);
pbrooka7812ae2008-11-17 14:43:54 +00002052}
2053
Leon Alrae9456c2f2014-07-07 11:24:00 +01002054void helper_tlbinv(CPUMIPSState *env)
2055{
2056 env->tlb->helper_tlbinv(env);
2057}
2058
2059void helper_tlbinvf(CPUMIPSState *env)
2060{
2061 env->tlb->helper_tlbinvf(env);
2062}
2063
ths2b0233a2008-06-12 12:42:35 +00002064/* Specials */
Blue Swirl895c2d02012-09-02 14:52:59 +00002065target_ulong helper_di(CPUMIPSState *env)
ths2b0233a2008-06-12 12:42:35 +00002066{
ths27961882008-06-27 10:03:42 +00002067 target_ulong t0 = env->CP0_Status;
2068
thsbe24bb42008-06-23 12:57:09 +00002069 env->CP0_Status = t0 & ~(1 << CP0St_IE);
thsbe24bb42008-06-23 12:57:09 +00002070 return t0;
ths2b0233a2008-06-12 12:42:35 +00002071}
2072
Blue Swirl895c2d02012-09-02 14:52:59 +00002073target_ulong helper_ei(CPUMIPSState *env)
ths2b0233a2008-06-12 12:42:35 +00002074{
ths27961882008-06-27 10:03:42 +00002075 target_ulong t0 = env->CP0_Status;
2076
thsbe24bb42008-06-23 12:57:09 +00002077 env->CP0_Status = t0 | (1 << CP0St_IE);
thsbe24bb42008-06-23 12:57:09 +00002078 return t0;
ths2b0233a2008-06-12 12:42:35 +00002079}
2080
Blue Swirl895c2d02012-09-02 14:52:59 +00002081static void debug_pre_eret(CPUMIPSState *env)
bellard6af0bf92005-07-02 14:58:51 +00002082{
aliguori8fec2b82009-01-15 22:36:53 +00002083 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
aliguori93fcfe32009-01-15 22:34:14 +00002084 qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
2085 env->active_tc.PC, env->CP0_EPC);
2086 if (env->CP0_Status & (1 << CP0St_ERL))
2087 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
2088 if (env->hflags & MIPS_HFLAG_DM)
2089 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
2090 qemu_log("\n");
2091 }
thsf41c52f2007-04-06 18:46:01 +00002092}
2093
Blue Swirl895c2d02012-09-02 14:52:59 +00002094static void debug_post_eret(CPUMIPSState *env)
thsf41c52f2007-04-06 18:46:01 +00002095{
Andreas Färbera47dddd2013-09-03 17:38:47 +02002096 MIPSCPU *cpu = mips_env_get_cpu(env);
2097
aliguori8fec2b82009-01-15 22:36:53 +00002098 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
aliguori93fcfe32009-01-15 22:34:14 +00002099 qemu_log(" => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
2100 env->active_tc.PC, env->CP0_EPC);
2101 if (env->CP0_Status & (1 << CP0St_ERL))
2102 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
2103 if (env->hflags & MIPS_HFLAG_DM)
2104 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
2105 switch (env->hflags & MIPS_HFLAG_KSU) {
2106 case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
2107 case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
2108 case MIPS_HFLAG_KM: qemu_log("\n"); break;
Andreas Färbera47dddd2013-09-03 17:38:47 +02002109 default:
2110 cpu_abort(CPU(cpu), "Invalid MMU mode!\n");
2111 break;
aliguori93fcfe32009-01-15 22:34:14 +00002112 }
ths623a9302007-10-28 19:45:05 +00002113 }
bellard6af0bf92005-07-02 14:58:51 +00002114}
2115
Blue Swirl895c2d02012-09-02 14:52:59 +00002116static void set_pc(CPUMIPSState *env, target_ulong error_pc)
Nathan Froyd32188a02009-12-08 08:06:23 -08002117{
2118 env->active_tc.PC = error_pc & ~(target_ulong)1;
2119 if (error_pc & 1) {
2120 env->hflags |= MIPS_HFLAG_M16;
2121 } else {
2122 env->hflags &= ~(MIPS_HFLAG_M16);
2123 }
2124}
2125
Leon Alraece9782f2015-06-04 17:00:31 +01002126static inline void exception_return(CPUMIPSState *env)
ths2b0233a2008-06-12 12:42:35 +00002127{
Blue Swirl895c2d02012-09-02 14:52:59 +00002128 debug_pre_eret(env);
ths2b0233a2008-06-12 12:42:35 +00002129 if (env->CP0_Status & (1 << CP0St_ERL)) {
Blue Swirl895c2d02012-09-02 14:52:59 +00002130 set_pc(env, env->CP0_ErrorEPC);
ths2b0233a2008-06-12 12:42:35 +00002131 env->CP0_Status &= ~(1 << CP0St_ERL);
2132 } else {
Blue Swirl895c2d02012-09-02 14:52:59 +00002133 set_pc(env, env->CP0_EPC);
ths2b0233a2008-06-12 12:42:35 +00002134 env->CP0_Status &= ~(1 << CP0St_EXL);
2135 }
2136 compute_hflags(env);
Blue Swirl895c2d02012-09-02 14:52:59 +00002137 debug_post_eret(env);
Leon Alraece9782f2015-06-04 17:00:31 +01002138}
2139
2140void helper_eret(CPUMIPSState *env)
2141{
2142 exception_return(env);
Aurelien Jarno5499b6f2009-11-22 13:08:14 +01002143 env->lladdr = 1;
ths2b0233a2008-06-12 12:42:35 +00002144}
2145
Leon Alraece9782f2015-06-04 17:00:31 +01002146void helper_eretnc(CPUMIPSState *env)
2147{
2148 exception_return(env);
2149}
2150
Blue Swirl895c2d02012-09-02 14:52:59 +00002151void helper_deret(CPUMIPSState *env)
ths2b0233a2008-06-12 12:42:35 +00002152{
Blue Swirl895c2d02012-09-02 14:52:59 +00002153 debug_pre_eret(env);
2154 set_pc(env, env->CP0_DEPC);
Nathan Froyd32188a02009-12-08 08:06:23 -08002155
Leon Alraefe87c2b2015-07-14 11:08:13 +01002156 env->hflags &= ~MIPS_HFLAG_DM;
ths2b0233a2008-06-12 12:42:35 +00002157 compute_hflags(env);
Blue Swirl895c2d02012-09-02 14:52:59 +00002158 debug_post_eret(env);
ths2b0233a2008-06-12 12:42:35 +00002159}
ths0eaef5a2008-07-23 16:14:22 +00002160#endif /* !CONFIG_USER_ONLY */
ths2b0233a2008-06-12 12:42:35 +00002161
Blue Swirl895c2d02012-09-02 14:52:59 +00002162target_ulong helper_rdhwr_cpunum(CPUMIPSState *env)
ths2b0233a2008-06-12 12:42:35 +00002163{
2164 if ((env->hflags & MIPS_HFLAG_CP0) ||
2165 (env->CP0_HWREna & (1 << 0)))
ths27961882008-06-27 10:03:42 +00002166 return env->CP0_EBase & 0x3ff;
ths2b0233a2008-06-12 12:42:35 +00002167 else
Blue Swirl895c2d02012-09-02 14:52:59 +00002168 helper_raise_exception(env, EXCP_RI);
thsbe24bb42008-06-23 12:57:09 +00002169
ths27961882008-06-27 10:03:42 +00002170 return 0;
ths2b0233a2008-06-12 12:42:35 +00002171}
2172
Blue Swirl895c2d02012-09-02 14:52:59 +00002173target_ulong helper_rdhwr_synci_step(CPUMIPSState *env)
ths2b0233a2008-06-12 12:42:35 +00002174{
2175 if ((env->hflags & MIPS_HFLAG_CP0) ||
2176 (env->CP0_HWREna & (1 << 1)))
ths27961882008-06-27 10:03:42 +00002177 return env->SYNCI_Step;
ths2b0233a2008-06-12 12:42:35 +00002178 else
Blue Swirl895c2d02012-09-02 14:52:59 +00002179 helper_raise_exception(env, EXCP_RI);
thsbe24bb42008-06-23 12:57:09 +00002180
ths27961882008-06-27 10:03:42 +00002181 return 0;
ths2b0233a2008-06-12 12:42:35 +00002182}
2183
Blue Swirl895c2d02012-09-02 14:52:59 +00002184target_ulong helper_rdhwr_cc(CPUMIPSState *env)
ths2b0233a2008-06-12 12:42:35 +00002185{
2186 if ((env->hflags & MIPS_HFLAG_CP0) ||
2187 (env->CP0_HWREna & (1 << 2)))
ths27961882008-06-27 10:03:42 +00002188 return env->CP0_Count;
ths2b0233a2008-06-12 12:42:35 +00002189 else
Blue Swirl895c2d02012-09-02 14:52:59 +00002190 helper_raise_exception(env, EXCP_RI);
thsbe24bb42008-06-23 12:57:09 +00002191
ths27961882008-06-27 10:03:42 +00002192 return 0;
ths2b0233a2008-06-12 12:42:35 +00002193}
2194
Blue Swirl895c2d02012-09-02 14:52:59 +00002195target_ulong helper_rdhwr_ccres(CPUMIPSState *env)
ths2b0233a2008-06-12 12:42:35 +00002196{
2197 if ((env->hflags & MIPS_HFLAG_CP0) ||
2198 (env->CP0_HWREna & (1 << 3)))
ths27961882008-06-27 10:03:42 +00002199 return env->CCRes;
ths2b0233a2008-06-12 12:42:35 +00002200 else
Blue Swirl895c2d02012-09-02 14:52:59 +00002201 helper_raise_exception(env, EXCP_RI);
thsbe24bb42008-06-23 12:57:09 +00002202
ths27961882008-06-27 10:03:42 +00002203 return 0;
ths2b0233a2008-06-12 12:42:35 +00002204}
2205
Blue Swirl895c2d02012-09-02 14:52:59 +00002206void helper_pmon(CPUMIPSState *env, int function)
bellard6af0bf92005-07-02 14:58:51 +00002207{
2208 function /= 2;
2209 switch (function) {
2210 case 2: /* TODO: char inbyte(int waitflag); */
thsb5dc7732008-06-27 10:02:35 +00002211 if (env->active_tc.gpr[4] == 0)
2212 env->active_tc.gpr[2] = -1;
bellard6af0bf92005-07-02 14:58:51 +00002213 /* Fall through */
2214 case 11: /* TODO: char inbyte (void); */
thsb5dc7732008-06-27 10:02:35 +00002215 env->active_tc.gpr[2] = -1;
bellard6af0bf92005-07-02 14:58:51 +00002216 break;
2217 case 3:
2218 case 12:
thsb5dc7732008-06-27 10:02:35 +00002219 printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
bellard6af0bf92005-07-02 14:58:51 +00002220 break;
2221 case 17:
2222 break;
2223 case 158:
2224 {
Stefan Weilb69e48a2012-04-12 15:43:09 +02002225 unsigned char *fmt = (void *)(uintptr_t)env->active_tc.gpr[4];
bellard6af0bf92005-07-02 14:58:51 +00002226 printf("%s", fmt);
2227 }
2228 break;
2229 }
2230}
bellarde37e8632005-07-04 22:17:33 +00002231
Blue Swirl895c2d02012-09-02 14:52:59 +00002232void helper_wait(CPUMIPSState *env)
ths08ba7962008-06-12 03:15:13 +00002233{
Andreas Färber259186a2013-01-17 18:51:17 +01002234 CPUState *cs = CPU(mips_env_get_cpu(env));
2235
2236 cs->halted = 1;
Andreas Färberd8ed8872013-01-17 22:30:20 +01002237 cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
Blue Swirl895c2d02012-09-02 14:52:59 +00002238 helper_raise_exception(env, EXCP_HLT);
ths08ba7962008-06-12 03:15:13 +00002239}
2240
ths5fafdf22007-09-16 21:08:06 +00002241#if !defined(CONFIG_USER_ONLY)
bellarde37e8632005-07-04 22:17:33 +00002242
Paolo Bonzini93e22322014-03-28 18:14:58 +01002243void mips_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
Leon Alraeaea14092014-07-07 11:24:01 +01002244 int access_type, int is_user,
2245 uintptr_t retaddr)
bellard4ad40f32005-12-05 19:59:36 +00002246{
Paolo Bonzini93e22322014-03-28 18:14:58 +01002247 MIPSCPU *cpu = MIPS_CPU(cs);
2248 CPUMIPSState *env = &cpu->env;
Leon Alraeaea14092014-07-07 11:24:01 +01002249 int error_code = 0;
2250 int excp;
Paolo Bonzini93e22322014-03-28 18:14:58 +01002251
bellard4ad40f32005-12-05 19:59:36 +00002252 env->CP0_BadVAddr = addr;
Leon Alraeaea14092014-07-07 11:24:01 +01002253
2254 if (access_type == MMU_DATA_STORE) {
2255 excp = EXCP_AdES;
2256 } else {
2257 excp = EXCP_AdEL;
2258 if (access_type == MMU_INST_FETCH) {
2259 error_code |= EXCP_INST_NOTAVAIL;
2260 }
2261 }
2262
2263 do_raise_exception_err(env, excp, error_code, retaddr);
bellard4ad40f32005-12-05 19:59:36 +00002264}
2265
Andreas Färberd5a11fe2013-08-27 00:28:06 +02002266void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
Blue Swirl20503962012-04-09 14:20:20 +00002267 uintptr_t retaddr)
bellarde37e8632005-07-04 22:17:33 +00002268{
bellarde37e8632005-07-04 22:17:33 +00002269 int ret;
2270
Andreas Färber27103422013-08-26 08:31:06 +02002271 ret = mips_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
bellarde37e8632005-07-04 22:17:33 +00002272 if (ret) {
Andreas Färberd5a11fe2013-08-27 00:28:06 +02002273 MIPSCPU *cpu = MIPS_CPU(cs);
2274 CPUMIPSState *env = &cpu->env;
2275
Andreas Färber27103422013-08-26 08:31:06 +02002276 do_raise_exception_err(env, cs->exception_index,
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002277 env->error_code, retaddr);
bellarde37e8632005-07-04 22:17:33 +00002278 }
bellarde37e8632005-07-04 22:17:33 +00002279}
2280
Andreas Färberc658b942013-05-27 06:49:53 +02002281void mips_cpu_unassigned_access(CPUState *cs, hwaddr addr,
2282 bool is_write, bool is_exec, int unused,
2283 unsigned size)
ths647de6c2007-10-20 19:45:44 +00002284{
Andreas Färberc658b942013-05-27 06:49:53 +02002285 MIPSCPU *cpu = MIPS_CPU(cs);
2286 CPUMIPSState *env = &cpu->env;
2287
James Hoganeddedd52014-07-28 12:37:50 +01002288 /*
2289 * Raising an exception with KVM enabled will crash because it won't be from
2290 * the main execution loop so the longjmp won't have a matching setjmp.
2291 * Until we can trigger a bus error exception through KVM lets just ignore
2292 * the access.
2293 */
2294 if (kvm_enabled()) {
2295 return;
2296 }
2297
Andreas Färberc658b942013-05-27 06:49:53 +02002298 if (is_exec) {
Blue Swirl895c2d02012-09-02 14:52:59 +00002299 helper_raise_exception(env, EXCP_IBE);
Andreas Färberc658b942013-05-27 06:49:53 +02002300 } else {
Blue Swirl895c2d02012-09-02 14:52:59 +00002301 helper_raise_exception(env, EXCP_DBE);
Andreas Färberc658b942013-05-27 06:49:53 +02002302 }
ths647de6c2007-10-20 19:45:44 +00002303}
thsf1aa6322008-06-09 07:13:38 +00002304#endif /* !CONFIG_USER_ONLY */
thsfd4a04e2007-05-18 11:55:54 +00002305
2306/* Complex FPU operations which may need stack space. */
2307
pbrookf090c9d2007-11-18 14:33:24 +00002308#define FLOAT_TWO32 make_float32(1 << 30)
2309#define FLOAT_TWO64 make_float64(1ULL << 62)
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002310#define FP_TO_INT32_OVERFLOW 0x7fffffff
2311#define FP_TO_INT64_OVERFLOW 0x7fffffffffffffffULL
ths8dfdb872007-06-26 20:26:03 +00002312
thsfd4a04e2007-05-18 11:55:54 +00002313/* convert MIPS rounding mode in FCR31 to IEEE library */
Yongbok Kimb7651e92014-11-01 05:28:37 +00002314unsigned int ieee_rm[] = {
thsfd4a04e2007-05-18 11:55:54 +00002315 float_round_nearest_even,
2316 float_round_to_zero,
2317 float_round_up,
2318 float_round_down
2319};
2320
Blue Swirl895c2d02012-09-02 14:52:59 +00002321target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg)
thsfd4a04e2007-05-18 11:55:54 +00002322{
Petar Jovanovic736d1202014-01-22 18:35:32 +01002323 target_ulong arg1 = 0;
ths6c5c1e22008-06-24 15:12:27 +00002324
thsead93602007-09-06 00:18:15 +00002325 switch (reg) {
2326 case 0:
aurel32d9bea112009-04-15 14:41:44 +00002327 arg1 = (int32_t)env->active_fpu.fcr0;
thsead93602007-09-06 00:18:15 +00002328 break;
Petar Jovanovic736d1202014-01-22 18:35:32 +01002329 case 1:
2330 /* UFR Support - Read Status FR */
2331 if (env->active_fpu.fcr0 & (1 << FCR0_UFRP)) {
2332 if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
2333 arg1 = (int32_t)
2334 ((env->CP0_Status & (1 << CP0St_FR)) >> CP0St_FR);
2335 } else {
2336 helper_raise_exception(env, EXCP_RI);
2337 }
2338 }
2339 break;
Leon Alrae7c979af2015-04-21 16:06:28 +01002340 case 5:
2341 /* FRE Support - read Config5.FRE bit */
2342 if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) {
2343 if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
2344 arg1 = (env->CP0_Config5 >> CP0C5_FRE) & 1;
2345 } else {
2346 helper_raise_exception(env, EXCP_RI);
2347 }
2348 }
2349 break;
thsead93602007-09-06 00:18:15 +00002350 case 25:
aurel32d9bea112009-04-15 14:41:44 +00002351 arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
thsead93602007-09-06 00:18:15 +00002352 break;
2353 case 26:
aurel32d9bea112009-04-15 14:41:44 +00002354 arg1 = env->active_fpu.fcr31 & 0x0003f07c;
thsead93602007-09-06 00:18:15 +00002355 break;
2356 case 28:
aurel32d9bea112009-04-15 14:41:44 +00002357 arg1 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4);
thsead93602007-09-06 00:18:15 +00002358 break;
2359 default:
aurel32d9bea112009-04-15 14:41:44 +00002360 arg1 = (int32_t)env->active_fpu.fcr31;
thsead93602007-09-06 00:18:15 +00002361 break;
2362 }
thsbe24bb42008-06-23 12:57:09 +00002363
aurel32d9bea112009-04-15 14:41:44 +00002364 return arg1;
thsead93602007-09-06 00:18:15 +00002365}
2366
Petar Jovanovic736d1202014-01-22 18:35:32 +01002367void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt)
thsead93602007-09-06 00:18:15 +00002368{
Petar Jovanovic736d1202014-01-22 18:35:32 +01002369 switch (fs) {
2370 case 1:
2371 /* UFR Alias - Reset Status FR */
2372 if (!((env->active_fpu.fcr0 & (1 << FCR0_UFRP)) && (rt == 0))) {
2373 return;
2374 }
2375 if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
2376 env->CP0_Status &= ~(1 << CP0St_FR);
2377 compute_hflags(env);
2378 } else {
2379 helper_raise_exception(env, EXCP_RI);
2380 }
2381 break;
2382 case 4:
2383 /* UNFR Alias - Set Status FR */
2384 if (!((env->active_fpu.fcr0 & (1 << FCR0_UFRP)) && (rt == 0))) {
2385 return;
2386 }
2387 if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
2388 env->CP0_Status |= (1 << CP0St_FR);
2389 compute_hflags(env);
2390 } else {
2391 helper_raise_exception(env, EXCP_RI);
2392 }
2393 break;
Leon Alrae7c979af2015-04-21 16:06:28 +01002394 case 5:
2395 /* FRE Support - clear Config5.FRE bit */
2396 if (!((env->active_fpu.fcr0 & (1 << FCR0_FREP)) && (rt == 0))) {
2397 return;
2398 }
2399 if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
2400 env->CP0_Config5 &= ~(1 << CP0C5_FRE);
2401 compute_hflags(env);
2402 } else {
2403 helper_raise_exception(env, EXCP_RI);
2404 }
2405 break;
2406 case 6:
2407 /* FRE Support - set Config5.FRE bit */
2408 if (!((env->active_fpu.fcr0 & (1 << FCR0_FREP)) && (rt == 0))) {
2409 return;
2410 }
2411 if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
2412 env->CP0_Config5 |= (1 << CP0C5_FRE);
2413 compute_hflags(env);
2414 } else {
2415 helper_raise_exception(env, EXCP_RI);
2416 }
2417 break;
thsfd4a04e2007-05-18 11:55:54 +00002418 case 25:
Leon Alraeba801af2014-07-11 16:11:34 +01002419 if ((env->insn_flags & ISA_MIPS32R6) || (arg1 & 0xffffff00)) {
thsfd4a04e2007-05-18 11:55:54 +00002420 return;
Leon Alraeba801af2014-07-11 16:11:34 +01002421 }
aurel32d9bea112009-04-15 14:41:44 +00002422 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
2423 ((arg1 & 0x1) << 23);
thsfd4a04e2007-05-18 11:55:54 +00002424 break;
2425 case 26:
aurel32d9bea112009-04-15 14:41:44 +00002426 if (arg1 & 0x007c0000)
thsfd4a04e2007-05-18 11:55:54 +00002427 return;
aurel32d9bea112009-04-15 14:41:44 +00002428 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (arg1 & 0x0003f07c);
thsfd4a04e2007-05-18 11:55:54 +00002429 break;
2430 case 28:
aurel32d9bea112009-04-15 14:41:44 +00002431 if (arg1 & 0x007c0000)
thsfd4a04e2007-05-18 11:55:54 +00002432 return;
aurel32d9bea112009-04-15 14:41:44 +00002433 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (arg1 & 0x00000f83) |
2434 ((arg1 & 0x4) << 22);
thsfd4a04e2007-05-18 11:55:54 +00002435 break;
2436 case 31:
Leon Alraeba801af2014-07-11 16:11:34 +01002437 if (env->insn_flags & ISA_MIPS32R6) {
2438 uint32_t mask = 0xfefc0000;
2439 env->active_fpu.fcr31 = (arg1 & ~mask) |
2440 (env->active_fpu.fcr31 & mask);
2441 } else if (!(arg1 & 0x007c0000)) {
2442 env->active_fpu.fcr31 = arg1;
2443 }
thsfd4a04e2007-05-18 11:55:54 +00002444 break;
2445 default:
2446 return;
2447 }
2448 /* set rounding mode */
Stefan Weile320d052013-01-01 19:44:31 +01002449 restore_rounding_mode(env);
aurel3241e0c702009-03-28 22:22:40 +00002450 /* set flush-to-zero mode */
Stefan Weile320d052013-01-01 19:44:31 +01002451 restore_flush_mode(env);
thsf01be152008-09-18 11:57:27 +00002452 set_float_exception_flags(0, &env->active_fpu.fp_status);
2453 if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31))
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002454 do_raise_exception(env, EXCP_FPE, GETPC());
thsfd4a04e2007-05-18 11:55:54 +00002455}
2456
Yongbok Kimb7651e92014-11-01 05:28:37 +00002457int ieee_ex_to_mips(int xcpt)
thsfd4a04e2007-05-18 11:55:54 +00002458{
Aurelien Jarno353ebb72011-04-14 00:49:30 +02002459 int ret = 0;
2460 if (xcpt) {
2461 if (xcpt & float_flag_invalid) {
2462 ret |= FP_INVALID;
2463 }
2464 if (xcpt & float_flag_overflow) {
2465 ret |= FP_OVERFLOW;
2466 }
2467 if (xcpt & float_flag_underflow) {
2468 ret |= FP_UNDERFLOW;
2469 }
2470 if (xcpt & float_flag_divbyzero) {
2471 ret |= FP_DIV0;
2472 }
2473 if (xcpt & float_flag_inexact) {
2474 ret |= FP_INEXACT;
2475 }
2476 }
2477 return ret;
thsfd4a04e2007-05-18 11:55:54 +00002478}
2479
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002480static inline void update_fcr31(CPUMIPSState *env, uintptr_t pc)
thsfd4a04e2007-05-18 11:55:54 +00002481{
thsf01be152008-09-18 11:57:27 +00002482 int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
thsfd4a04e2007-05-18 11:55:54 +00002483
thsf01be152008-09-18 11:57:27 +00002484 SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
Aurelien Jarno4a587b22012-10-28 18:08:27 +01002485
2486 if (tmp) {
2487 set_float_exception_flags(0, &env->active_fpu.fp_status);
2488
2489 if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp) {
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002490 do_raise_exception(env, EXCP_FPE, pc);
Aurelien Jarno4a587b22012-10-28 18:08:27 +01002491 } else {
2492 UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
2493 }
2494 }
thsfd4a04e2007-05-18 11:55:54 +00002495}
2496
thsa16336e2008-06-19 18:35:02 +00002497/* Float support.
2498 Single precition routines have a "s" suffix, double precision a
2499 "d" suffix, 32bit integer "w", 64bit integer "l", paired single "ps",
2500 paired single lower "pl", paired single upper "pu". */
2501
thsa16336e2008-06-19 18:35:02 +00002502/* unary operations, modifying fp status */
Blue Swirl895c2d02012-09-02 14:52:59 +00002503uint64_t helper_float_sqrt_d(CPUMIPSState *env, uint64_t fdt0)
thsfd4a04e2007-05-18 11:55:54 +00002504{
Aurelien Jarno5dbe90b2012-10-09 21:53:20 +02002505 fdt0 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002506 update_fcr31(env, GETPC());
Aurelien Jarno5dbe90b2012-10-09 21:53:20 +02002507 return fdt0;
thsfd4a04e2007-05-18 11:55:54 +00002508}
2509
Blue Swirl895c2d02012-09-02 14:52:59 +00002510uint32_t helper_float_sqrt_s(CPUMIPSState *env, uint32_t fst0)
thsfd4a04e2007-05-18 11:55:54 +00002511{
Aurelien Jarno5dbe90b2012-10-09 21:53:20 +02002512 fst0 = float32_sqrt(fst0, &env->active_fpu.fp_status);
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002513 update_fcr31(env, GETPC());
Aurelien Jarno5dbe90b2012-10-09 21:53:20 +02002514 return fst0;
thsfd4a04e2007-05-18 11:55:54 +00002515}
2516
Blue Swirl895c2d02012-09-02 14:52:59 +00002517uint64_t helper_float_cvtd_s(CPUMIPSState *env, uint32_t fst0)
thsfd4a04e2007-05-18 11:55:54 +00002518{
thsb6d96be2008-07-09 11:05:10 +00002519 uint64_t fdt2;
2520
thsf01be152008-09-18 11:57:27 +00002521 fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002522 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002523 return fdt2;
2524}
2525
Blue Swirl895c2d02012-09-02 14:52:59 +00002526uint64_t helper_float_cvtd_w(CPUMIPSState *env, uint32_t wt0)
thsb6d96be2008-07-09 11:05:10 +00002527{
2528 uint64_t fdt2;
2529
thsf01be152008-09-18 11:57:27 +00002530 fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002531 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002532 return fdt2;
2533}
2534
Blue Swirl895c2d02012-09-02 14:52:59 +00002535uint64_t helper_float_cvtd_l(CPUMIPSState *env, uint64_t dt0)
thsb6d96be2008-07-09 11:05:10 +00002536{
2537 uint64_t fdt2;
2538
thsf01be152008-09-18 11:57:27 +00002539 fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002540 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002541 return fdt2;
2542}
2543
Blue Swirl895c2d02012-09-02 14:52:59 +00002544uint64_t helper_float_cvtl_d(CPUMIPSState *env, uint64_t fdt0)
thsb6d96be2008-07-09 11:05:10 +00002545{
2546 uint64_t dt2;
2547
thsf01be152008-09-18 11:57:27 +00002548 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002549 if (get_float_exception_flags(&env->active_fpu.fp_status)
2550 & (float_flag_invalid | float_flag_overflow)) {
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002551 dt2 = FP_TO_INT64_OVERFLOW;
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002552 }
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002553 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002554 return dt2;
2555}
2556
Blue Swirl895c2d02012-09-02 14:52:59 +00002557uint64_t helper_float_cvtl_s(CPUMIPSState *env, uint32_t fst0)
thsb6d96be2008-07-09 11:05:10 +00002558{
2559 uint64_t dt2;
2560
thsf01be152008-09-18 11:57:27 +00002561 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002562 if (get_float_exception_flags(&env->active_fpu.fp_status)
2563 & (float_flag_invalid | float_flag_overflow)) {
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002564 dt2 = FP_TO_INT64_OVERFLOW;
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002565 }
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002566 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002567 return dt2;
2568}
2569
Blue Swirl895c2d02012-09-02 14:52:59 +00002570uint64_t helper_float_cvtps_pw(CPUMIPSState *env, uint64_t dt0)
thsb6d96be2008-07-09 11:05:10 +00002571{
2572 uint32_t fst2;
2573 uint32_t fsth2;
2574
thsf01be152008-09-18 11:57:27 +00002575 fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2576 fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status);
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002577 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002578 return ((uint64_t)fsth2 << 32) | fst2;
2579}
2580
Blue Swirl895c2d02012-09-02 14:52:59 +00002581uint64_t helper_float_cvtpw_ps(CPUMIPSState *env, uint64_t fdt0)
thsb6d96be2008-07-09 11:05:10 +00002582{
2583 uint32_t wt2;
2584 uint32_t wth2;
Aurelien Jarno5dbe90b2012-10-09 21:53:20 +02002585 int excp, excph;
thsb6d96be2008-07-09 11:05:10 +00002586
thsf01be152008-09-18 11:57:27 +00002587 wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
Aurelien Jarno5dbe90b2012-10-09 21:53:20 +02002588 excp = get_float_exception_flags(&env->active_fpu.fp_status);
2589 if (excp & (float_flag_overflow | float_flag_invalid)) {
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002590 wt2 = FP_TO_INT32_OVERFLOW;
Aurelien Jarno5dbe90b2012-10-09 21:53:20 +02002591 }
2592
2593 set_float_exception_flags(0, &env->active_fpu.fp_status);
2594 wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status);
2595 excph = get_float_exception_flags(&env->active_fpu.fp_status);
2596 if (excph & (float_flag_overflow | float_flag_invalid)) {
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002597 wth2 = FP_TO_INT32_OVERFLOW;
thsb6d96be2008-07-09 11:05:10 +00002598 }
Aurelien Jarno5dbe90b2012-10-09 21:53:20 +02002599
2600 set_float_exception_flags(excp | excph, &env->active_fpu.fp_status);
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002601 update_fcr31(env, GETPC());
Aurelien Jarno5dbe90b2012-10-09 21:53:20 +02002602
thsb6d96be2008-07-09 11:05:10 +00002603 return ((uint64_t)wth2 << 32) | wt2;
2604}
2605
Blue Swirl895c2d02012-09-02 14:52:59 +00002606uint32_t helper_float_cvts_d(CPUMIPSState *env, uint64_t fdt0)
thsb6d96be2008-07-09 11:05:10 +00002607{
2608 uint32_t fst2;
2609
thsf01be152008-09-18 11:57:27 +00002610 fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002611 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002612 return fst2;
2613}
2614
Blue Swirl895c2d02012-09-02 14:52:59 +00002615uint32_t helper_float_cvts_w(CPUMIPSState *env, uint32_t wt0)
thsb6d96be2008-07-09 11:05:10 +00002616{
2617 uint32_t fst2;
2618
thsf01be152008-09-18 11:57:27 +00002619 fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status);
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002620 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002621 return fst2;
2622}
2623
Blue Swirl895c2d02012-09-02 14:52:59 +00002624uint32_t helper_float_cvts_l(CPUMIPSState *env, uint64_t dt0)
thsb6d96be2008-07-09 11:05:10 +00002625{
2626 uint32_t fst2;
2627
thsf01be152008-09-18 11:57:27 +00002628 fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status);
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002629 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002630 return fst2;
2631}
2632
Blue Swirl895c2d02012-09-02 14:52:59 +00002633uint32_t helper_float_cvts_pl(CPUMIPSState *env, uint32_t wt0)
thsb6d96be2008-07-09 11:05:10 +00002634{
2635 uint32_t wt2;
2636
thsb6d96be2008-07-09 11:05:10 +00002637 wt2 = wt0;
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002638 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002639 return wt2;
2640}
2641
Blue Swirl895c2d02012-09-02 14:52:59 +00002642uint32_t helper_float_cvts_pu(CPUMIPSState *env, uint32_t wth0)
thsb6d96be2008-07-09 11:05:10 +00002643{
2644 uint32_t wt2;
2645
thsb6d96be2008-07-09 11:05:10 +00002646 wt2 = wth0;
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002647 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002648 return wt2;
2649}
2650
Blue Swirl895c2d02012-09-02 14:52:59 +00002651uint32_t helper_float_cvtw_s(CPUMIPSState *env, uint32_t fst0)
thsb6d96be2008-07-09 11:05:10 +00002652{
2653 uint32_t wt2;
2654
thsf01be152008-09-18 11:57:27 +00002655 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002656 if (get_float_exception_flags(&env->active_fpu.fp_status)
2657 & (float_flag_invalid | float_flag_overflow)) {
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002658 wt2 = FP_TO_INT32_OVERFLOW;
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002659 }
Maciej W. Rozycki2b09f942014-11-05 15:35:59 +00002660 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002661 return wt2;
2662}
2663
Blue Swirl895c2d02012-09-02 14:52:59 +00002664uint32_t helper_float_cvtw_d(CPUMIPSState *env, uint64_t fdt0)
thsb6d96be2008-07-09 11:05:10 +00002665{
2666 uint32_t wt2;
2667
thsf01be152008-09-18 11:57:27 +00002668 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002669 if (get_float_exception_flags(&env->active_fpu.fp_status)
2670 & (float_flag_invalid | float_flag_overflow)) {
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002671 wt2 = FP_TO_INT32_OVERFLOW;
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002672 }
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002673 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002674 return wt2;
2675}
2676
Blue Swirl895c2d02012-09-02 14:52:59 +00002677uint64_t helper_float_roundl_d(CPUMIPSState *env, uint64_t fdt0)
thsb6d96be2008-07-09 11:05:10 +00002678{
2679 uint64_t dt2;
2680
thsf01be152008-09-18 11:57:27 +00002681 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2682 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
Stefan Weile320d052013-01-01 19:44:31 +01002683 restore_rounding_mode(env);
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002684 if (get_float_exception_flags(&env->active_fpu.fp_status)
2685 & (float_flag_invalid | float_flag_overflow)) {
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002686 dt2 = FP_TO_INT64_OVERFLOW;
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002687 }
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002688 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002689 return dt2;
thsfd4a04e2007-05-18 11:55:54 +00002690}
2691
Blue Swirl895c2d02012-09-02 14:52:59 +00002692uint64_t helper_float_roundl_s(CPUMIPSState *env, uint32_t fst0)
thsfd4a04e2007-05-18 11:55:54 +00002693{
thsb6d96be2008-07-09 11:05:10 +00002694 uint64_t dt2;
2695
thsf01be152008-09-18 11:57:27 +00002696 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2697 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
Stefan Weile320d052013-01-01 19:44:31 +01002698 restore_rounding_mode(env);
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002699 if (get_float_exception_flags(&env->active_fpu.fp_status)
2700 & (float_flag_invalid | float_flag_overflow)) {
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002701 dt2 = FP_TO_INT64_OVERFLOW;
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002702 }
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002703 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002704 return dt2;
thsfd4a04e2007-05-18 11:55:54 +00002705}
2706
Blue Swirl895c2d02012-09-02 14:52:59 +00002707uint32_t helper_float_roundw_d(CPUMIPSState *env, uint64_t fdt0)
thsfd4a04e2007-05-18 11:55:54 +00002708{
thsb6d96be2008-07-09 11:05:10 +00002709 uint32_t wt2;
2710
thsf01be152008-09-18 11:57:27 +00002711 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2712 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
Stefan Weile320d052013-01-01 19:44:31 +01002713 restore_rounding_mode(env);
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002714 if (get_float_exception_flags(&env->active_fpu.fp_status)
2715 & (float_flag_invalid | float_flag_overflow)) {
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002716 wt2 = FP_TO_INT32_OVERFLOW;
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002717 }
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002718 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002719 return wt2;
thsfd4a04e2007-05-18 11:55:54 +00002720}
2721
Blue Swirl895c2d02012-09-02 14:52:59 +00002722uint32_t helper_float_roundw_s(CPUMIPSState *env, uint32_t fst0)
thsfd4a04e2007-05-18 11:55:54 +00002723{
thsb6d96be2008-07-09 11:05:10 +00002724 uint32_t wt2;
2725
thsf01be152008-09-18 11:57:27 +00002726 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2727 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
Stefan Weile320d052013-01-01 19:44:31 +01002728 restore_rounding_mode(env);
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002729 if (get_float_exception_flags(&env->active_fpu.fp_status)
2730 & (float_flag_invalid | float_flag_overflow)) {
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002731 wt2 = FP_TO_INT32_OVERFLOW;
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002732 }
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002733 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002734 return wt2;
thsfd4a04e2007-05-18 11:55:54 +00002735}
thsb6d96be2008-07-09 11:05:10 +00002736
Blue Swirl895c2d02012-09-02 14:52:59 +00002737uint64_t helper_float_truncl_d(CPUMIPSState *env, uint64_t fdt0)
thsfd4a04e2007-05-18 11:55:54 +00002738{
thsb6d96be2008-07-09 11:05:10 +00002739 uint64_t dt2;
2740
thsf01be152008-09-18 11:57:27 +00002741 dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002742 if (get_float_exception_flags(&env->active_fpu.fp_status)
2743 & (float_flag_invalid | float_flag_overflow)) {
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002744 dt2 = FP_TO_INT64_OVERFLOW;
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002745 }
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002746 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002747 return dt2;
thsfd4a04e2007-05-18 11:55:54 +00002748}
thsb6d96be2008-07-09 11:05:10 +00002749
Blue Swirl895c2d02012-09-02 14:52:59 +00002750uint64_t helper_float_truncl_s(CPUMIPSState *env, uint32_t fst0)
thsfd4a04e2007-05-18 11:55:54 +00002751{
thsb6d96be2008-07-09 11:05:10 +00002752 uint64_t dt2;
2753
thsf01be152008-09-18 11:57:27 +00002754 dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002755 if (get_float_exception_flags(&env->active_fpu.fp_status)
2756 & (float_flag_invalid | float_flag_overflow)) {
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002757 dt2 = FP_TO_INT64_OVERFLOW;
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002758 }
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002759 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002760 return dt2;
thsfd4a04e2007-05-18 11:55:54 +00002761}
thsb6d96be2008-07-09 11:05:10 +00002762
Blue Swirl895c2d02012-09-02 14:52:59 +00002763uint32_t helper_float_truncw_d(CPUMIPSState *env, uint64_t fdt0)
thsfd4a04e2007-05-18 11:55:54 +00002764{
thsb6d96be2008-07-09 11:05:10 +00002765 uint32_t wt2;
2766
thsf01be152008-09-18 11:57:27 +00002767 wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002768 if (get_float_exception_flags(&env->active_fpu.fp_status)
2769 & (float_flag_invalid | float_flag_overflow)) {
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002770 wt2 = FP_TO_INT32_OVERFLOW;
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002771 }
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002772 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002773 return wt2;
2774}
2775
Blue Swirl895c2d02012-09-02 14:52:59 +00002776uint32_t helper_float_truncw_s(CPUMIPSState *env, uint32_t fst0)
thsb6d96be2008-07-09 11:05:10 +00002777{
2778 uint32_t wt2;
2779
thsf01be152008-09-18 11:57:27 +00002780 wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002781 if (get_float_exception_flags(&env->active_fpu.fp_status)
2782 & (float_flag_invalid | float_flag_overflow)) {
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002783 wt2 = FP_TO_INT32_OVERFLOW;
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002784 }
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002785 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002786 return wt2;
2787}
2788
Blue Swirl895c2d02012-09-02 14:52:59 +00002789uint64_t helper_float_ceill_d(CPUMIPSState *env, uint64_t fdt0)
thsb6d96be2008-07-09 11:05:10 +00002790{
2791 uint64_t dt2;
2792
thsf01be152008-09-18 11:57:27 +00002793 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2794 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
Stefan Weile320d052013-01-01 19:44:31 +01002795 restore_rounding_mode(env);
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002796 if (get_float_exception_flags(&env->active_fpu.fp_status)
2797 & (float_flag_invalid | float_flag_overflow)) {
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002798 dt2 = FP_TO_INT64_OVERFLOW;
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002799 }
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002800 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002801 return dt2;
2802}
2803
Blue Swirl895c2d02012-09-02 14:52:59 +00002804uint64_t helper_float_ceill_s(CPUMIPSState *env, uint32_t fst0)
thsb6d96be2008-07-09 11:05:10 +00002805{
2806 uint64_t dt2;
2807
thsf01be152008-09-18 11:57:27 +00002808 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2809 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
Stefan Weile320d052013-01-01 19:44:31 +01002810 restore_rounding_mode(env);
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002811 if (get_float_exception_flags(&env->active_fpu.fp_status)
2812 & (float_flag_invalid | float_flag_overflow)) {
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002813 dt2 = FP_TO_INT64_OVERFLOW;
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002814 }
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002815 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002816 return dt2;
2817}
2818
Blue Swirl895c2d02012-09-02 14:52:59 +00002819uint32_t helper_float_ceilw_d(CPUMIPSState *env, uint64_t fdt0)
thsb6d96be2008-07-09 11:05:10 +00002820{
2821 uint32_t wt2;
2822
thsf01be152008-09-18 11:57:27 +00002823 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2824 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
Stefan Weile320d052013-01-01 19:44:31 +01002825 restore_rounding_mode(env);
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002826 if (get_float_exception_flags(&env->active_fpu.fp_status)
2827 & (float_flag_invalid | float_flag_overflow)) {
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002828 wt2 = FP_TO_INT32_OVERFLOW;
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002829 }
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002830 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002831 return wt2;
2832}
2833
Blue Swirl895c2d02012-09-02 14:52:59 +00002834uint32_t helper_float_ceilw_s(CPUMIPSState *env, uint32_t fst0)
thsb6d96be2008-07-09 11:05:10 +00002835{
2836 uint32_t wt2;
2837
thsf01be152008-09-18 11:57:27 +00002838 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2839 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
Stefan Weile320d052013-01-01 19:44:31 +01002840 restore_rounding_mode(env);
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002841 if (get_float_exception_flags(&env->active_fpu.fp_status)
2842 & (float_flag_invalid | float_flag_overflow)) {
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002843 wt2 = FP_TO_INT32_OVERFLOW;
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002844 }
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002845 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002846 return wt2;
2847}
2848
Blue Swirl895c2d02012-09-02 14:52:59 +00002849uint64_t helper_float_floorl_d(CPUMIPSState *env, uint64_t fdt0)
thsb6d96be2008-07-09 11:05:10 +00002850{
2851 uint64_t dt2;
2852
thsf01be152008-09-18 11:57:27 +00002853 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2854 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
Stefan Weile320d052013-01-01 19:44:31 +01002855 restore_rounding_mode(env);
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002856 if (get_float_exception_flags(&env->active_fpu.fp_status)
2857 & (float_flag_invalid | float_flag_overflow)) {
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002858 dt2 = FP_TO_INT64_OVERFLOW;
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002859 }
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002860 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002861 return dt2;
2862}
2863
Blue Swirl895c2d02012-09-02 14:52:59 +00002864uint64_t helper_float_floorl_s(CPUMIPSState *env, uint32_t fst0)
thsb6d96be2008-07-09 11:05:10 +00002865{
2866 uint64_t dt2;
2867
thsf01be152008-09-18 11:57:27 +00002868 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2869 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
Stefan Weile320d052013-01-01 19:44:31 +01002870 restore_rounding_mode(env);
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002871 if (get_float_exception_flags(&env->active_fpu.fp_status)
2872 & (float_flag_invalid | float_flag_overflow)) {
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002873 dt2 = FP_TO_INT64_OVERFLOW;
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002874 }
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002875 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002876 return dt2;
2877}
2878
Blue Swirl895c2d02012-09-02 14:52:59 +00002879uint32_t helper_float_floorw_d(CPUMIPSState *env, uint64_t fdt0)
thsb6d96be2008-07-09 11:05:10 +00002880{
2881 uint32_t wt2;
2882
thsf01be152008-09-18 11:57:27 +00002883 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2884 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
Stefan Weile320d052013-01-01 19:44:31 +01002885 restore_rounding_mode(env);
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002886 if (get_float_exception_flags(&env->active_fpu.fp_status)
2887 & (float_flag_invalid | float_flag_overflow)) {
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002888 wt2 = FP_TO_INT32_OVERFLOW;
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002889 }
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002890 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002891 return wt2;
2892}
2893
Blue Swirl895c2d02012-09-02 14:52:59 +00002894uint32_t helper_float_floorw_s(CPUMIPSState *env, uint32_t fst0)
thsb6d96be2008-07-09 11:05:10 +00002895{
2896 uint32_t wt2;
2897
thsf01be152008-09-18 11:57:27 +00002898 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2899 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
Stefan Weile320d052013-01-01 19:44:31 +01002900 restore_rounding_mode(env);
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002901 if (get_float_exception_flags(&env->active_fpu.fp_status)
2902 & (float_flag_invalid | float_flag_overflow)) {
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002903 wt2 = FP_TO_INT32_OVERFLOW;
Aurelien Jarno4cc2e5f2012-10-23 09:53:50 +02002904 }
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002905 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002906 return wt2;
thsfd4a04e2007-05-18 11:55:54 +00002907}
2908
thsa16336e2008-06-19 18:35:02 +00002909/* unary operations, not modifying fp status */
thsb6d96be2008-07-09 11:05:10 +00002910#define FLOAT_UNOP(name) \
aurel32c01fccd2009-03-08 00:06:01 +00002911uint64_t helper_float_ ## name ## _d(uint64_t fdt0) \
thsb6d96be2008-07-09 11:05:10 +00002912{ \
2913 return float64_ ## name(fdt0); \
2914} \
aurel32c01fccd2009-03-08 00:06:01 +00002915uint32_t helper_float_ ## name ## _s(uint32_t fst0) \
thsb6d96be2008-07-09 11:05:10 +00002916{ \
2917 return float32_ ## name(fst0); \
2918} \
aurel32c01fccd2009-03-08 00:06:01 +00002919uint64_t helper_float_ ## name ## _ps(uint64_t fdt0) \
thsb6d96be2008-07-09 11:05:10 +00002920{ \
2921 uint32_t wt0; \
2922 uint32_t wth0; \
2923 \
2924 wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF); \
2925 wth0 = float32_ ## name(fdt0 >> 32); \
2926 return ((uint64_t)wth0 << 32) | wt0; \
thsa16336e2008-06-19 18:35:02 +00002927}
2928FLOAT_UNOP(abs)
2929FLOAT_UNOP(chs)
2930#undef FLOAT_UNOP
2931
ths8dfdb872007-06-26 20:26:03 +00002932/* MIPS specific unary operations */
Blue Swirl895c2d02012-09-02 14:52:59 +00002933uint64_t helper_float_recip_d(CPUMIPSState *env, uint64_t fdt0)
ths8dfdb872007-06-26 20:26:03 +00002934{
thsb6d96be2008-07-09 11:05:10 +00002935 uint64_t fdt2;
2936
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002937 fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002938 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002939 return fdt2;
ths8dfdb872007-06-26 20:26:03 +00002940}
ths57fa1fb2007-05-19 20:29:41 +00002941
Blue Swirl895c2d02012-09-02 14:52:59 +00002942uint32_t helper_float_recip_s(CPUMIPSState *env, uint32_t fst0)
ths8dfdb872007-06-26 20:26:03 +00002943{
thsb6d96be2008-07-09 11:05:10 +00002944 uint32_t fst2;
2945
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002946 fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002947 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002948 return fst2;
ths8dfdb872007-06-26 20:26:03 +00002949}
2950
Blue Swirl895c2d02012-09-02 14:52:59 +00002951uint64_t helper_float_rsqrt_d(CPUMIPSState *env, uint64_t fdt0)
ths8dfdb872007-06-26 20:26:03 +00002952{
thsb6d96be2008-07-09 11:05:10 +00002953 uint64_t fdt2;
2954
thsf01be152008-09-18 11:57:27 +00002955 fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002956 fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002957 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002958 return fdt2;
ths8dfdb872007-06-26 20:26:03 +00002959}
2960
Blue Swirl895c2d02012-09-02 14:52:59 +00002961uint32_t helper_float_rsqrt_s(CPUMIPSState *env, uint32_t fst0)
ths8dfdb872007-06-26 20:26:03 +00002962{
thsb6d96be2008-07-09 11:05:10 +00002963 uint32_t fst2;
2964
thsf01be152008-09-18 11:57:27 +00002965 fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002966 fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002967 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002968 return fst2;
ths8dfdb872007-06-26 20:26:03 +00002969}
thsb6d96be2008-07-09 11:05:10 +00002970
Blue Swirl895c2d02012-09-02 14:52:59 +00002971uint64_t helper_float_recip1_d(CPUMIPSState *env, uint64_t fdt0)
ths8dfdb872007-06-26 20:26:03 +00002972{
thsb6d96be2008-07-09 11:05:10 +00002973 uint64_t fdt2;
2974
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002975 fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002976 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002977 return fdt2;
ths8dfdb872007-06-26 20:26:03 +00002978}
thsb6d96be2008-07-09 11:05:10 +00002979
Blue Swirl895c2d02012-09-02 14:52:59 +00002980uint32_t helper_float_recip1_s(CPUMIPSState *env, uint32_t fst0)
ths8dfdb872007-06-26 20:26:03 +00002981{
thsb6d96be2008-07-09 11:05:10 +00002982 uint32_t fst2;
2983
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002984 fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002985 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002986 return fst2;
ths8dfdb872007-06-26 20:26:03 +00002987}
ths57fa1fb2007-05-19 20:29:41 +00002988
Blue Swirl895c2d02012-09-02 14:52:59 +00002989uint64_t helper_float_recip1_ps(CPUMIPSState *env, uint64_t fdt0)
thsb6d96be2008-07-09 11:05:10 +00002990{
2991 uint32_t fst2;
2992 uint32_t fsth2;
2993
Aurelien Jarno05993cd2012-10-23 10:12:00 +02002994 fst2 = float32_div(float32_one, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2995 fsth2 = float32_div(float32_one, fdt0 >> 32, &env->active_fpu.fp_status);
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01002996 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00002997 return ((uint64_t)fsth2 << 32) | fst2;
2998}
2999
Blue Swirl895c2d02012-09-02 14:52:59 +00003000uint64_t helper_float_rsqrt1_d(CPUMIPSState *env, uint64_t fdt0)
thsb6d96be2008-07-09 11:05:10 +00003001{
3002 uint64_t fdt2;
3003
thsf01be152008-09-18 11:57:27 +00003004 fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
Aurelien Jarno05993cd2012-10-23 10:12:00 +02003005 fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01003006 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00003007 return fdt2;
3008}
3009
Blue Swirl895c2d02012-09-02 14:52:59 +00003010uint32_t helper_float_rsqrt1_s(CPUMIPSState *env, uint32_t fst0)
thsb6d96be2008-07-09 11:05:10 +00003011{
3012 uint32_t fst2;
3013
thsf01be152008-09-18 11:57:27 +00003014 fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
Aurelien Jarno05993cd2012-10-23 10:12:00 +02003015 fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01003016 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00003017 return fst2;
3018}
3019
Blue Swirl895c2d02012-09-02 14:52:59 +00003020uint64_t helper_float_rsqrt1_ps(CPUMIPSState *env, uint64_t fdt0)
thsb6d96be2008-07-09 11:05:10 +00003021{
3022 uint32_t fst2;
3023 uint32_t fsth2;
3024
thsf01be152008-09-18 11:57:27 +00003025 fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
3026 fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status);
Aurelien Jarno05993cd2012-10-23 10:12:00 +02003027 fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
3028 fsth2 = float32_div(float32_one, fsth2, &env->active_fpu.fp_status);
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01003029 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00003030 return ((uint64_t)fsth2 << 32) | fst2;
3031}
3032
Maciej W. Rozycki8fc605b2014-11-05 15:38:01 +00003033#define FLOAT_RINT(name, bits) \
3034uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \
3035 uint ## bits ## _t fs) \
3036{ \
3037 uint ## bits ## _t fdret; \
3038 \
3039 fdret = float ## bits ## _round_to_int(fs, &env->active_fpu.fp_status); \
3040 update_fcr31(env, GETPC()); \
3041 return fdret; \
3042}
3043
3044FLOAT_RINT(rint_s, 32)
3045FLOAT_RINT(rint_d, 64)
3046#undef FLOAT_RINT
3047
3048#define FLOAT_CLASS_SIGNALING_NAN 0x001
3049#define FLOAT_CLASS_QUIET_NAN 0x002
3050#define FLOAT_CLASS_NEGATIVE_INFINITY 0x004
3051#define FLOAT_CLASS_NEGATIVE_NORMAL 0x008
3052#define FLOAT_CLASS_NEGATIVE_SUBNORMAL 0x010
3053#define FLOAT_CLASS_NEGATIVE_ZERO 0x020
3054#define FLOAT_CLASS_POSITIVE_INFINITY 0x040
3055#define FLOAT_CLASS_POSITIVE_NORMAL 0x080
3056#define FLOAT_CLASS_POSITIVE_SUBNORMAL 0x100
3057#define FLOAT_CLASS_POSITIVE_ZERO 0x200
3058
3059#define FLOAT_CLASS(name, bits) \
3060uint ## bits ## _t helper_float_ ## name (uint ## bits ## _t arg) \
3061{ \
3062 if (float ## bits ## _is_signaling_nan(arg)) { \
3063 return FLOAT_CLASS_SIGNALING_NAN; \
3064 } else if (float ## bits ## _is_quiet_nan(arg)) { \
3065 return FLOAT_CLASS_QUIET_NAN; \
3066 } else if (float ## bits ## _is_neg(arg)) { \
3067 if (float ## bits ## _is_infinity(arg)) { \
3068 return FLOAT_CLASS_NEGATIVE_INFINITY; \
3069 } else if (float ## bits ## _is_zero(arg)) { \
3070 return FLOAT_CLASS_NEGATIVE_ZERO; \
3071 } else if (float ## bits ## _is_zero_or_denormal(arg)) { \
3072 return FLOAT_CLASS_NEGATIVE_SUBNORMAL; \
3073 } else { \
3074 return FLOAT_CLASS_NEGATIVE_NORMAL; \
3075 } \
3076 } else { \
3077 if (float ## bits ## _is_infinity(arg)) { \
3078 return FLOAT_CLASS_POSITIVE_INFINITY; \
3079 } else if (float ## bits ## _is_zero(arg)) { \
3080 return FLOAT_CLASS_POSITIVE_ZERO; \
3081 } else if (float ## bits ## _is_zero_or_denormal(arg)) { \
3082 return FLOAT_CLASS_POSITIVE_SUBNORMAL; \
3083 } else { \
3084 return FLOAT_CLASS_POSITIVE_NORMAL; \
3085 } \
3086 } \
3087}
3088
3089FLOAT_CLASS(class_s, 32)
3090FLOAT_CLASS(class_d, 64)
3091#undef FLOAT_CLASS
3092
thsfd4a04e2007-05-18 11:55:54 +00003093/* binary operations */
thsb6d96be2008-07-09 11:05:10 +00003094#define FLOAT_BINOP(name) \
Blue Swirl895c2d02012-09-02 14:52:59 +00003095uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \
3096 uint64_t fdt0, uint64_t fdt1) \
thsb6d96be2008-07-09 11:05:10 +00003097{ \
3098 uint64_t dt2; \
3099 \
thsf01be152008-09-18 11:57:27 +00003100 dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status); \
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01003101 update_fcr31(env, GETPC()); \
thsb6d96be2008-07-09 11:05:10 +00003102 return dt2; \
3103} \
3104 \
Blue Swirl895c2d02012-09-02 14:52:59 +00003105uint32_t helper_float_ ## name ## _s(CPUMIPSState *env, \
3106 uint32_t fst0, uint32_t fst1) \
thsb6d96be2008-07-09 11:05:10 +00003107{ \
3108 uint32_t wt2; \
3109 \
thsf01be152008-09-18 11:57:27 +00003110 wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01003111 update_fcr31(env, GETPC()); \
thsb6d96be2008-07-09 11:05:10 +00003112 return wt2; \
3113} \
3114 \
Blue Swirl895c2d02012-09-02 14:52:59 +00003115uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \
3116 uint64_t fdt0, \
3117 uint64_t fdt1) \
thsb6d96be2008-07-09 11:05:10 +00003118{ \
3119 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
3120 uint32_t fsth0 = fdt0 >> 32; \
3121 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
3122 uint32_t fsth1 = fdt1 >> 32; \
3123 uint32_t wt2; \
3124 uint32_t wth2; \
3125 \
thsf01be152008-09-18 11:57:27 +00003126 wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \
3127 wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status); \
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01003128 update_fcr31(env, GETPC()); \
thsb6d96be2008-07-09 11:05:10 +00003129 return ((uint64_t)wth2 << 32) | wt2; \
thsfd4a04e2007-05-18 11:55:54 +00003130}
thsb6d96be2008-07-09 11:05:10 +00003131
thsfd4a04e2007-05-18 11:55:54 +00003132FLOAT_BINOP(add)
3133FLOAT_BINOP(sub)
3134FLOAT_BINOP(mul)
3135FLOAT_BINOP(div)
3136#undef FLOAT_BINOP
3137
ths8dfdb872007-06-26 20:26:03 +00003138/* MIPS specific binary operations */
Blue Swirl895c2d02012-09-02 14:52:59 +00003139uint64_t helper_float_recip2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
ths8dfdb872007-06-26 20:26:03 +00003140{
thsf01be152008-09-18 11:57:27 +00003141 fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
Aurelien Jarno05993cd2012-10-23 10:12:00 +02003142 fdt2 = float64_chs(float64_sub(fdt2, float64_one, &env->active_fpu.fp_status));
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01003143 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00003144 return fdt2;
ths8dfdb872007-06-26 20:26:03 +00003145}
3146
Blue Swirl895c2d02012-09-02 14:52:59 +00003147uint32_t helper_float_recip2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
ths8dfdb872007-06-26 20:26:03 +00003148{
thsf01be152008-09-18 11:57:27 +00003149 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
Aurelien Jarno05993cd2012-10-23 10:12:00 +02003150 fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01003151 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00003152 return fst2;
ths8dfdb872007-06-26 20:26:03 +00003153}
ths57fa1fb2007-05-19 20:29:41 +00003154
Blue Swirl895c2d02012-09-02 14:52:59 +00003155uint64_t helper_float_recip2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
thsfd4a04e2007-05-18 11:55:54 +00003156{
thsb6d96be2008-07-09 11:05:10 +00003157 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3158 uint32_t fsth0 = fdt0 >> 32;
3159 uint32_t fst2 = fdt2 & 0XFFFFFFFF;
3160 uint32_t fsth2 = fdt2 >> 32;
3161
thsf01be152008-09-18 11:57:27 +00003162 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3163 fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
Aurelien Jarno05993cd2012-10-23 10:12:00 +02003164 fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
3165 fsth2 = float32_chs(float32_sub(fsth2, float32_one, &env->active_fpu.fp_status));
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01003166 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00003167 return ((uint64_t)fsth2 << 32) | fst2;
thsfd4a04e2007-05-18 11:55:54 +00003168}
3169
Blue Swirl895c2d02012-09-02 14:52:59 +00003170uint64_t helper_float_rsqrt2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
ths57fa1fb2007-05-19 20:29:41 +00003171{
thsf01be152008-09-18 11:57:27 +00003172 fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
Aurelien Jarno05993cd2012-10-23 10:12:00 +02003173 fdt2 = float64_sub(fdt2, float64_one, &env->active_fpu.fp_status);
thsf01be152008-09-18 11:57:27 +00003174 fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status));
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01003175 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00003176 return fdt2;
3177}
3178
Blue Swirl895c2d02012-09-02 14:52:59 +00003179uint32_t helper_float_rsqrt2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
thsb6d96be2008-07-09 11:05:10 +00003180{
thsf01be152008-09-18 11:57:27 +00003181 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
Aurelien Jarno05993cd2012-10-23 10:12:00 +02003182 fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
thsf01be152008-09-18 11:57:27 +00003183 fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01003184 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00003185 return fst2;
3186}
3187
Blue Swirl895c2d02012-09-02 14:52:59 +00003188uint64_t helper_float_rsqrt2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
thsb6d96be2008-07-09 11:05:10 +00003189{
3190 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3191 uint32_t fsth0 = fdt0 >> 32;
3192 uint32_t fst2 = fdt2 & 0XFFFFFFFF;
3193 uint32_t fsth2 = fdt2 >> 32;
3194
thsf01be152008-09-18 11:57:27 +00003195 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3196 fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
Aurelien Jarno05993cd2012-10-23 10:12:00 +02003197 fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
3198 fsth2 = float32_sub(fsth2, float32_one, &env->active_fpu.fp_status);
thsf01be152008-09-18 11:57:27 +00003199 fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
3200 fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->active_fpu.fp_status));
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01003201 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00003202 return ((uint64_t)fsth2 << 32) | fst2;
3203}
3204
Blue Swirl895c2d02012-09-02 14:52:59 +00003205uint64_t helper_float_addr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
thsb6d96be2008-07-09 11:05:10 +00003206{
3207 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3208 uint32_t fsth0 = fdt0 >> 32;
3209 uint32_t fst1 = fdt1 & 0XFFFFFFFF;
3210 uint32_t fsth1 = fdt1 >> 32;
3211 uint32_t fst2;
3212 uint32_t fsth2;
3213
thsf01be152008-09-18 11:57:27 +00003214 fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status);
3215 fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status);
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01003216 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00003217 return ((uint64_t)fsth2 << 32) | fst2;
3218}
3219
Blue Swirl895c2d02012-09-02 14:52:59 +00003220uint64_t helper_float_mulr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
thsb6d96be2008-07-09 11:05:10 +00003221{
3222 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3223 uint32_t fsth0 = fdt0 >> 32;
3224 uint32_t fst1 = fdt1 & 0XFFFFFFFF;
3225 uint32_t fsth1 = fdt1 >> 32;
3226 uint32_t fst2;
3227 uint32_t fsth2;
3228
thsf01be152008-09-18 11:57:27 +00003229 fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status);
3230 fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status);
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01003231 update_fcr31(env, GETPC());
thsb6d96be2008-07-09 11:05:10 +00003232 return ((uint64_t)fsth2 << 32) | fst2;
ths57fa1fb2007-05-19 20:29:41 +00003233}
3234
Maciej W. Rozycki8fc605b2014-11-05 15:38:01 +00003235#define FLOAT_MINMAX(name, bits, minmaxfunc) \
3236uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \
3237 uint ## bits ## _t fs, \
3238 uint ## bits ## _t ft) \
3239{ \
3240 uint ## bits ## _t fdret; \
3241 \
3242 fdret = float ## bits ## _ ## minmaxfunc(fs, ft, \
3243 &env->active_fpu.fp_status); \
3244 update_fcr31(env, GETPC()); \
3245 return fdret; \
3246}
3247
3248FLOAT_MINMAX(max_s, 32, maxnum)
3249FLOAT_MINMAX(max_d, 64, maxnum)
3250FLOAT_MINMAX(maxa_s, 32, maxnummag)
3251FLOAT_MINMAX(maxa_d, 64, maxnummag)
3252
3253FLOAT_MINMAX(min_s, 32, minnum)
3254FLOAT_MINMAX(min_d, 64, minnum)
3255FLOAT_MINMAX(mina_s, 32, minnummag)
3256FLOAT_MINMAX(mina_d, 64, minnummag)
3257#undef FLOAT_MINMAX
3258
3259/* ternary operations */
3260#define UNFUSED_FMA(prefix, a, b, c, flags) \
3261{ \
3262 a = prefix##_mul(a, b, &env->active_fpu.fp_status); \
3263 if ((flags) & float_muladd_negate_c) { \
3264 a = prefix##_sub(a, c, &env->active_fpu.fp_status); \
3265 } else { \
3266 a = prefix##_add(a, c, &env->active_fpu.fp_status); \
3267 } \
3268 if ((flags) & float_muladd_negate_result) { \
3269 a = prefix##_chs(a); \
3270 } \
3271}
3272
3273/* FMA based operations */
3274#define FLOAT_FMA(name, type) \
3275uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \
3276 uint64_t fdt0, uint64_t fdt1, \
3277 uint64_t fdt2) \
3278{ \
3279 UNFUSED_FMA(float64, fdt0, fdt1, fdt2, type); \
3280 update_fcr31(env, GETPC()); \
3281 return fdt0; \
3282} \
3283 \
3284uint32_t helper_float_ ## name ## _s(CPUMIPSState *env, \
3285 uint32_t fst0, uint32_t fst1, \
3286 uint32_t fst2) \
3287{ \
3288 UNFUSED_FMA(float32, fst0, fst1, fst2, type); \
3289 update_fcr31(env, GETPC()); \
3290 return fst0; \
3291} \
3292 \
3293uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \
3294 uint64_t fdt0, uint64_t fdt1, \
3295 uint64_t fdt2) \
3296{ \
3297 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
3298 uint32_t fsth0 = fdt0 >> 32; \
3299 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
3300 uint32_t fsth1 = fdt1 >> 32; \
3301 uint32_t fst2 = fdt2 & 0XFFFFFFFF; \
3302 uint32_t fsth2 = fdt2 >> 32; \
3303 \
3304 UNFUSED_FMA(float32, fst0, fst1, fst2, type); \
3305 UNFUSED_FMA(float32, fsth0, fsth1, fsth2, type); \
3306 update_fcr31(env, GETPC()); \
3307 return ((uint64_t)fsth0 << 32) | fst0; \
3308}
3309FLOAT_FMA(madd, 0)
3310FLOAT_FMA(msub, float_muladd_negate_c)
3311FLOAT_FMA(nmadd, float_muladd_negate_result)
3312FLOAT_FMA(nmsub, float_muladd_negate_result | float_muladd_negate_c)
3313#undef FLOAT_FMA
3314
3315#define FLOAT_FMADDSUB(name, bits, muladd_arg) \
3316uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \
3317 uint ## bits ## _t fs, \
3318 uint ## bits ## _t ft, \
3319 uint ## bits ## _t fd) \
3320{ \
3321 uint ## bits ## _t fdret; \
3322 \
3323 fdret = float ## bits ## _muladd(fs, ft, fd, muladd_arg, \
3324 &env->active_fpu.fp_status); \
3325 update_fcr31(env, GETPC()); \
3326 return fdret; \
3327}
3328
3329FLOAT_FMADDSUB(maddf_s, 32, 0)
3330FLOAT_FMADDSUB(maddf_d, 64, 0)
3331FLOAT_FMADDSUB(msubf_s, 32, float_muladd_negate_product)
3332FLOAT_FMADDSUB(msubf_d, 64, float_muladd_negate_product)
3333#undef FLOAT_FMADDSUB
3334
ths8dfdb872007-06-26 20:26:03 +00003335/* compare operations */
thsb6d96be2008-07-09 11:05:10 +00003336#define FOP_COND_D(op, cond) \
Blue Swirl895c2d02012-09-02 14:52:59 +00003337void helper_cmp_d_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3338 uint64_t fdt1, int cc) \
thsb6d96be2008-07-09 11:05:10 +00003339{ \
Aurelien Jarno6a385342011-04-14 00:49:30 +02003340 int c; \
Aurelien Jarno6a385342011-04-14 00:49:30 +02003341 c = cond; \
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01003342 update_fcr31(env, GETPC()); \
thsb6d96be2008-07-09 11:05:10 +00003343 if (c) \
thsf01be152008-09-18 11:57:27 +00003344 SET_FP_COND(cc, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00003345 else \
thsf01be152008-09-18 11:57:27 +00003346 CLEAR_FP_COND(cc, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00003347} \
Blue Swirl895c2d02012-09-02 14:52:59 +00003348void helper_cmpabs_d_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3349 uint64_t fdt1, int cc) \
thsb6d96be2008-07-09 11:05:10 +00003350{ \
3351 int c; \
3352 fdt0 = float64_abs(fdt0); \
3353 fdt1 = float64_abs(fdt1); \
3354 c = cond; \
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01003355 update_fcr31(env, GETPC()); \
thsb6d96be2008-07-09 11:05:10 +00003356 if (c) \
thsf01be152008-09-18 11:57:27 +00003357 SET_FP_COND(cc, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00003358 else \
thsf01be152008-09-18 11:57:27 +00003359 CLEAR_FP_COND(cc, env->active_fpu); \
thsfd4a04e2007-05-18 11:55:54 +00003360}
3361
thsfd4a04e2007-05-18 11:55:54 +00003362/* NOTE: the comma operator will make "cond" to eval to false,
Aurelien Jarno3a599382011-04-14 00:49:29 +02003363 * but float64_unordered_quiet() is still called. */
3364FOP_COND_D(f, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
3365FOP_COND_D(un, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status))
Aurelien Jarno06a0e6b2011-04-14 00:49:30 +02003366FOP_COND_D(eq, float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
Aurelien Jarno211315f2011-04-14 00:49:29 +02003367FOP_COND_D(ueq, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
Aurelien Jarno06a0e6b2011-04-14 00:49:30 +02003368FOP_COND_D(olt, float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3369FOP_COND_D(ult, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3370FOP_COND_D(ole, float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3371FOP_COND_D(ule, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
thsfd4a04e2007-05-18 11:55:54 +00003372/* NOTE: the comma operator will make "cond" to eval to false,
Aurelien Jarno3a599382011-04-14 00:49:29 +02003373 * but float64_unordered() is still called. */
3374FOP_COND_D(sf, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
3375FOP_COND_D(ngle,float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status))
Aurelien Jarno06a0e6b2011-04-14 00:49:30 +02003376FOP_COND_D(seq, float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
3377FOP_COND_D(ngl, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
3378FOP_COND_D(lt, float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
Aurelien Jarno3a599382011-04-14 00:49:29 +02003379FOP_COND_D(nge, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
Aurelien Jarno06a0e6b2011-04-14 00:49:30 +02003380FOP_COND_D(le, float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
Aurelien Jarno3a599382011-04-14 00:49:29 +02003381FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
thsfd4a04e2007-05-18 11:55:54 +00003382
thsb6d96be2008-07-09 11:05:10 +00003383#define FOP_COND_S(op, cond) \
Blue Swirl895c2d02012-09-02 14:52:59 +00003384void helper_cmp_s_ ## op(CPUMIPSState *env, uint32_t fst0, \
3385 uint32_t fst1, int cc) \
thsb6d96be2008-07-09 11:05:10 +00003386{ \
Aurelien Jarno6a385342011-04-14 00:49:30 +02003387 int c; \
Aurelien Jarno6a385342011-04-14 00:49:30 +02003388 c = cond; \
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01003389 update_fcr31(env, GETPC()); \
thsb6d96be2008-07-09 11:05:10 +00003390 if (c) \
thsf01be152008-09-18 11:57:27 +00003391 SET_FP_COND(cc, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00003392 else \
thsf01be152008-09-18 11:57:27 +00003393 CLEAR_FP_COND(cc, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00003394} \
Blue Swirl895c2d02012-09-02 14:52:59 +00003395void helper_cmpabs_s_ ## op(CPUMIPSState *env, uint32_t fst0, \
3396 uint32_t fst1, int cc) \
thsb6d96be2008-07-09 11:05:10 +00003397{ \
3398 int c; \
3399 fst0 = float32_abs(fst0); \
3400 fst1 = float32_abs(fst1); \
3401 c = cond; \
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01003402 update_fcr31(env, GETPC()); \
thsb6d96be2008-07-09 11:05:10 +00003403 if (c) \
thsf01be152008-09-18 11:57:27 +00003404 SET_FP_COND(cc, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00003405 else \
thsf01be152008-09-18 11:57:27 +00003406 CLEAR_FP_COND(cc, env->active_fpu); \
thsfd4a04e2007-05-18 11:55:54 +00003407}
3408
thsfd4a04e2007-05-18 11:55:54 +00003409/* NOTE: the comma operator will make "cond" to eval to false,
Aurelien Jarno3a599382011-04-14 00:49:29 +02003410 * but float32_unordered_quiet() is still called. */
3411FOP_COND_S(f, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
3412FOP_COND_S(un, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status))
Aurelien Jarno06a0e6b2011-04-14 00:49:30 +02003413FOP_COND_S(eq, float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
Aurelien Jarno211315f2011-04-14 00:49:29 +02003414FOP_COND_S(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
Aurelien Jarno06a0e6b2011-04-14 00:49:30 +02003415FOP_COND_S(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
3416FOP_COND_S(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
3417FOP_COND_S(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
3418FOP_COND_S(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
thsfd4a04e2007-05-18 11:55:54 +00003419/* NOTE: the comma operator will make "cond" to eval to false,
Aurelien Jarno3a599382011-04-14 00:49:29 +02003420 * but float32_unordered() is still called. */
3421FOP_COND_S(sf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
3422FOP_COND_S(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status))
Aurelien Jarno06a0e6b2011-04-14 00:49:30 +02003423FOP_COND_S(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status))
3424FOP_COND_S(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
3425FOP_COND_S(lt, float32_lt(fst0, fst1, &env->active_fpu.fp_status))
Aurelien Jarno3a599382011-04-14 00:49:29 +02003426FOP_COND_S(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
Aurelien Jarno06a0e6b2011-04-14 00:49:30 +02003427FOP_COND_S(le, float32_le(fst0, fst1, &env->active_fpu.fp_status))
Aurelien Jarno3a599382011-04-14 00:49:29 +02003428FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status))
thsfd4a04e2007-05-18 11:55:54 +00003429
thsb6d96be2008-07-09 11:05:10 +00003430#define FOP_COND_PS(op, condl, condh) \
Blue Swirl895c2d02012-09-02 14:52:59 +00003431void helper_cmp_ps_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3432 uint64_t fdt1, int cc) \
thsb6d96be2008-07-09 11:05:10 +00003433{ \
Aurelien Jarno6a385342011-04-14 00:49:30 +02003434 uint32_t fst0, fsth0, fst1, fsth1; \
3435 int ch, cl; \
Aurelien Jarno6a385342011-04-14 00:49:30 +02003436 fst0 = fdt0 & 0XFFFFFFFF; \
3437 fsth0 = fdt0 >> 32; \
3438 fst1 = fdt1 & 0XFFFFFFFF; \
3439 fsth1 = fdt1 >> 32; \
3440 cl = condl; \
3441 ch = condh; \
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01003442 update_fcr31(env, GETPC()); \
thsb6d96be2008-07-09 11:05:10 +00003443 if (cl) \
thsf01be152008-09-18 11:57:27 +00003444 SET_FP_COND(cc, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00003445 else \
thsf01be152008-09-18 11:57:27 +00003446 CLEAR_FP_COND(cc, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00003447 if (ch) \
thsf01be152008-09-18 11:57:27 +00003448 SET_FP_COND(cc + 1, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00003449 else \
thsf01be152008-09-18 11:57:27 +00003450 CLEAR_FP_COND(cc + 1, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00003451} \
Blue Swirl895c2d02012-09-02 14:52:59 +00003452void helper_cmpabs_ps_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3453 uint64_t fdt1, int cc) \
thsb6d96be2008-07-09 11:05:10 +00003454{ \
Aurelien Jarno6a385342011-04-14 00:49:30 +02003455 uint32_t fst0, fsth0, fst1, fsth1; \
3456 int ch, cl; \
3457 fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \
3458 fsth0 = float32_abs(fdt0 >> 32); \
3459 fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \
3460 fsth1 = float32_abs(fdt1 >> 32); \
3461 cl = condl; \
3462 ch = condh; \
Aurelien Jarno5f7319c2012-10-28 19:34:03 +01003463 update_fcr31(env, GETPC()); \
thsb6d96be2008-07-09 11:05:10 +00003464 if (cl) \
thsf01be152008-09-18 11:57:27 +00003465 SET_FP_COND(cc, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00003466 else \
thsf01be152008-09-18 11:57:27 +00003467 CLEAR_FP_COND(cc, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00003468 if (ch) \
thsf01be152008-09-18 11:57:27 +00003469 SET_FP_COND(cc + 1, env->active_fpu); \
thsb6d96be2008-07-09 11:05:10 +00003470 else \
thsf01be152008-09-18 11:57:27 +00003471 CLEAR_FP_COND(cc + 1, env->active_fpu); \
thsfd4a04e2007-05-18 11:55:54 +00003472}
3473
3474/* NOTE: the comma operator will make "cond" to eval to false,
Aurelien Jarno3a599382011-04-14 00:49:29 +02003475 * but float32_unordered_quiet() is still called. */
3476FOP_COND_PS(f, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0),
3477 (float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status), 0))
3478FOP_COND_PS(un, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status),
3479 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status))
Aurelien Jarno06a0e6b2011-04-14 00:49:30 +02003480FOP_COND_PS(eq, float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
3481 float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
Aurelien Jarno211315f2011-04-14 00:49:29 +02003482FOP_COND_PS(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
3483 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
Aurelien Jarno06a0e6b2011-04-14 00:49:30 +02003484FOP_COND_PS(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
3485 float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3486FOP_COND_PS(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
3487 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3488FOP_COND_PS(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
3489 float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3490FOP_COND_PS(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
3491 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
thsfd4a04e2007-05-18 11:55:54 +00003492/* NOTE: the comma operator will make "cond" to eval to false,
Aurelien Jarno3a599382011-04-14 00:49:29 +02003493 * but float32_unordered() is still called. */
3494FOP_COND_PS(sf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0),
3495 (float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status), 0))
3496FOP_COND_PS(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status),
3497 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status))
Aurelien Jarno06a0e6b2011-04-14 00:49:30 +02003498FOP_COND_PS(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status),
3499 float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
3500FOP_COND_PS(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
3501 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
3502FOP_COND_PS(lt, float32_lt(fst0, fst1, &env->active_fpu.fp_status),
3503 float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
Aurelien Jarno3a599382011-04-14 00:49:29 +02003504FOP_COND_PS(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
3505 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
Aurelien Jarno06a0e6b2011-04-14 00:49:30 +02003506FOP_COND_PS(le, float32_le(fst0, fst1, &env->active_fpu.fp_status),
3507 float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
Aurelien Jarno3a599382011-04-14 00:49:29 +02003508FOP_COND_PS(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status),
3509 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
Yongbok Kim3f493882014-06-27 08:49:07 +01003510
3511/* R6 compare operations */
3512#define FOP_CONDN_D(op, cond) \
3513uint64_t helper_r6_cmp_d_ ## op(CPUMIPSState * env, uint64_t fdt0, \
3514 uint64_t fdt1) \
3515{ \
3516 uint64_t c; \
3517 c = cond; \
3518 update_fcr31(env, GETPC()); \
3519 if (c) { \
3520 return -1; \
3521 } else { \
3522 return 0; \
3523 } \
3524}
3525
3526/* NOTE: the comma operator will make "cond" to eval to false,
3527 * but float64_unordered_quiet() is still called. */
3528FOP_CONDN_D(af, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
3529FOP_CONDN_D(un, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)))
3530FOP_CONDN_D(eq, (float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
3531FOP_CONDN_D(ueq, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
3532 || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
3533FOP_CONDN_D(lt, (float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
3534FOP_CONDN_D(ult, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
3535 || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
3536FOP_CONDN_D(le, (float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
3537FOP_CONDN_D(ule, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
3538 || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
3539/* NOTE: the comma operator will make "cond" to eval to false,
3540 * but float64_unordered() is still called. */
3541FOP_CONDN_D(saf, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
3542FOP_CONDN_D(sun, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)))
3543FOP_CONDN_D(seq, (float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)))
3544FOP_CONDN_D(sueq, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
3545 || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)))
3546FOP_CONDN_D(slt, (float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
3547FOP_CONDN_D(sult, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
3548 || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
3549FOP_CONDN_D(sle, (float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
3550FOP_CONDN_D(sule, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
3551 || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
3552FOP_CONDN_D(or, (float64_le_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
3553 || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
3554FOP_CONDN_D(une, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
3555 || float64_lt_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
3556 || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
3557FOP_CONDN_D(ne, (float64_lt_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
3558 || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
3559FOP_CONDN_D(sor, (float64_le(fdt1, fdt0, &env->active_fpu.fp_status)
3560 || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
3561FOP_CONDN_D(sune, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
3562 || float64_lt(fdt1, fdt0, &env->active_fpu.fp_status)
3563 || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
3564FOP_CONDN_D(sne, (float64_lt(fdt1, fdt0, &env->active_fpu.fp_status)
3565 || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
3566
3567#define FOP_CONDN_S(op, cond) \
3568uint32_t helper_r6_cmp_s_ ## op(CPUMIPSState * env, uint32_t fst0, \
3569 uint32_t fst1) \
3570{ \
3571 uint64_t c; \
3572 c = cond; \
3573 update_fcr31(env, GETPC()); \
3574 if (c) { \
3575 return -1; \
3576 } else { \
3577 return 0; \
3578 } \
3579}
3580
3581/* NOTE: the comma operator will make "cond" to eval to false,
3582 * but float32_unordered_quiet() is still called. */
3583FOP_CONDN_S(af, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
3584FOP_CONDN_S(un, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)))
3585FOP_CONDN_S(eq, (float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)))
3586FOP_CONDN_S(ueq, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
3587 || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)))
3588FOP_CONDN_S(lt, (float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
3589FOP_CONDN_S(ult, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
3590 || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
3591FOP_CONDN_S(le, (float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
3592FOP_CONDN_S(ule, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
3593 || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
3594/* NOTE: the comma operator will make "cond" to eval to false,
3595 * but float32_unordered() is still called. */
3596FOP_CONDN_S(saf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
3597FOP_CONDN_S(sun, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)))
3598FOP_CONDN_S(seq, (float32_eq(fst0, fst1, &env->active_fpu.fp_status)))
3599FOP_CONDN_S(sueq, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
3600 || float32_eq(fst0, fst1, &env->active_fpu.fp_status)))
3601FOP_CONDN_S(slt, (float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
3602FOP_CONDN_S(sult, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
3603 || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
3604FOP_CONDN_S(sle, (float32_le(fst0, fst1, &env->active_fpu.fp_status)))
3605FOP_CONDN_S(sule, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
3606 || float32_le(fst0, fst1, &env->active_fpu.fp_status)))
3607FOP_CONDN_S(or, (float32_le_quiet(fst1, fst0, &env->active_fpu.fp_status)
3608 || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
3609FOP_CONDN_S(une, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
3610 || float32_lt_quiet(fst1, fst0, &env->active_fpu.fp_status)
3611 || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
3612FOP_CONDN_S(ne, (float32_lt_quiet(fst1, fst0, &env->active_fpu.fp_status)
3613 || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
3614FOP_CONDN_S(sor, (float32_le(fst1, fst0, &env->active_fpu.fp_status)
3615 || float32_le(fst0, fst1, &env->active_fpu.fp_status)))
3616FOP_CONDN_S(sune, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
3617 || float32_lt(fst1, fst0, &env->active_fpu.fp_status)
3618 || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
3619FOP_CONDN_S(sne, (float32_lt(fst1, fst0, &env->active_fpu.fp_status)
3620 || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
Yongbok Kimf7685872014-11-01 05:28:51 +00003621
3622/* MSA */
3623/* Data format min and max values */
3624#define DF_BITS(df) (1 << ((df) + 3))
3625
3626/* Element-by-element access macros */
3627#define DF_ELEMENTS(df) (MSA_WRLEN / DF_BITS(df))
3628
Yongbok Kimadc370a2015-06-01 12:13:24 +01003629#if !defined(CONFIG_USER_ONLY)
3630#define MEMOP_IDX(DF) \
3631 TCGMemOpIdx oi = make_memop_idx(MO_TE | DF | MO_UNALN, \
3632 cpu_mmu_index(env));
3633#else
3634#define MEMOP_IDX(DF)
3635#endif
Yongbok Kimf7685872014-11-01 05:28:51 +00003636
Yongbok Kimadc370a2015-06-01 12:13:24 +01003637#define MSA_LD_DF(DF, TYPE, LD_INSN, ...) \
3638void helper_msa_ld_ ## TYPE(CPUMIPSState *env, uint32_t wd, \
3639 target_ulong addr) \
3640{ \
3641 wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \
3642 wr_t wx; \
3643 int i; \
3644 MEMOP_IDX(DF) \
3645 for (i = 0; i < DF_ELEMENTS(DF); i++) { \
3646 wx.TYPE[i] = LD_INSN(env, addr + (i << DF), ##__VA_ARGS__); \
3647 } \
3648 memcpy(pwd, &wx, sizeof(wr_t)); \
Yongbok Kimf7685872014-11-01 05:28:51 +00003649}
3650
Yongbok Kimadc370a2015-06-01 12:13:24 +01003651#if !defined(CONFIG_USER_ONLY)
3652MSA_LD_DF(DF_BYTE, b, helper_ret_ldub_mmu, oi, GETRA())
3653MSA_LD_DF(DF_HALF, h, helper_ret_lduw_mmu, oi, GETRA())
3654MSA_LD_DF(DF_WORD, w, helper_ret_ldul_mmu, oi, GETRA())
3655MSA_LD_DF(DF_DOUBLE, d, helper_ret_ldq_mmu, oi, GETRA())
3656#else
3657MSA_LD_DF(DF_BYTE, b, cpu_ldub_data)
3658MSA_LD_DF(DF_HALF, h, cpu_lduw_data)
3659MSA_LD_DF(DF_WORD, w, cpu_ldl_data)
3660MSA_LD_DF(DF_DOUBLE, d, cpu_ldq_data)
3661#endif
Yongbok Kimf7685872014-11-01 05:28:51 +00003662
Yongbok Kimadc370a2015-06-01 12:13:24 +01003663#define MSA_PAGESPAN(x) \
3664 ((((x) & ~TARGET_PAGE_MASK) + MSA_WRLEN/8 - 1) >= TARGET_PAGE_SIZE)
3665
3666static inline void ensure_writable_pages(CPUMIPSState *env,
3667 target_ulong addr,
3668 int mmu_idx,
3669 uintptr_t retaddr)
3670{
3671#if !defined(CONFIG_USER_ONLY)
3672 target_ulong page_addr;
3673 if (unlikely(MSA_PAGESPAN(addr))) {
3674 /* first page */
3675 probe_write(env, addr, mmu_idx, retaddr);
3676 /* second page */
3677 page_addr = (addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
3678 probe_write(env, page_addr, mmu_idx, retaddr);
Yongbok Kimf7685872014-11-01 05:28:51 +00003679 }
Yongbok Kimadc370a2015-06-01 12:13:24 +01003680#endif
Yongbok Kimf7685872014-11-01 05:28:51 +00003681}
Yongbok Kimadc370a2015-06-01 12:13:24 +01003682
3683#define MSA_ST_DF(DF, TYPE, ST_INSN, ...) \
3684void helper_msa_st_ ## TYPE(CPUMIPSState *env, uint32_t wd, \
3685 target_ulong addr) \
3686{ \
3687 wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \
3688 int mmu_idx = cpu_mmu_index(env); \
3689 int i; \
3690 MEMOP_IDX(DF) \
3691 ensure_writable_pages(env, addr, mmu_idx, GETRA()); \
3692 for (i = 0; i < DF_ELEMENTS(DF); i++) { \
3693 ST_INSN(env, addr + (i << DF), pwd->TYPE[i], ##__VA_ARGS__); \
3694 } \
3695}
3696
3697#if !defined(CONFIG_USER_ONLY)
3698MSA_ST_DF(DF_BYTE, b, helper_ret_stb_mmu, oi, GETRA())
3699MSA_ST_DF(DF_HALF, h, helper_ret_stw_mmu, oi, GETRA())
3700MSA_ST_DF(DF_WORD, w, helper_ret_stl_mmu, oi, GETRA())
3701MSA_ST_DF(DF_DOUBLE, d, helper_ret_stq_mmu, oi, GETRA())
3702#else
3703MSA_ST_DF(DF_BYTE, b, cpu_stb_data)
3704MSA_ST_DF(DF_HALF, h, cpu_stw_data)
3705MSA_ST_DF(DF_WORD, w, cpu_stl_data)
3706MSA_ST_DF(DF_DOUBLE, d, cpu_stq_data)
3707#endif