]> Git Repo - qemu.git/blame - target/mips/op_helper.c
mips: call cpu_mips_realize_env() from mips_cpu_realizefn()
[qemu.git] / target / mips / op_helper.c
CommitLineData
6af0bf9c
FB
1/*
2 * MIPS emulation helpers for qemu.
5fafdf24 3 *
6af0bf9c
FB
4 * 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
8167ee88 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
6af0bf9c 18 */
c684822a 19#include "qemu/osdep.h"
d394698d 20#include "qemu/main-loop.h"
3e457172 21#include "cpu.h"
26aa3d9a 22#include "internal.h"
1de7afc9 23#include "qemu/host-utils.h"
2ef6175a 24#include "exec/helper-proto.h"
63c91552 25#include "exec/exec-all.h"
f08b6170 26#include "exec/cpu_ldst.h"
eddedd54 27#include "sysemu/kvm.h"
3e457172 28
6af0bf9c
FB
29/*****************************************************************************/
30/* Exceptions processing helpers */
6af0bf9c 31
9c708c7f
PD
32void helper_raise_exception_err(CPUMIPSState *env, uint32_t exception,
33 int error_code)
6af0bf9c 34{
9c708c7f 35 do_raise_exception_err(env, exception, error_code, 0);
6af0bf9c
FB
36}
37
9c708c7f 38void helper_raise_exception(CPUMIPSState *env, uint32_t exception)
6af0bf9c 39{
9c708c7f 40 do_raise_exception(env, exception, GETPC());
6af0bf9c
FB
41}
42
9c708c7f 43void helper_raise_exception_debug(CPUMIPSState *env)
4ad40f36 44{
9c708c7f 45 do_raise_exception(env, EXCP_DEBUG, 0);
5f7319cd 46}
20503968 47
9c708c7f 48static void raise_exception(CPUMIPSState *env, uint32_t exception)
5f7319cd
AJ
49{
50 do_raise_exception(env, exception, 0);
4ad40f36
FB
51}
52
0ae43045
AJ
53#if defined(CONFIG_USER_ONLY)
54#define HELPER_LD(name, insn, type) \
895c2d04 55static inline type do_##name(CPUMIPSState *env, target_ulong addr, \
9c708c7f 56 int mem_idx, uintptr_t retaddr) \
0ae43045 57{ \
9c708c7f 58 return (type) cpu_##insn##_data_ra(env, addr, retaddr); \
0ae43045
AJ
59}
60#else
61#define HELPER_LD(name, insn, type) \
895c2d04 62static inline type do_##name(CPUMIPSState *env, target_ulong addr, \
9c708c7f 63 int mem_idx, uintptr_t retaddr) \
0ae43045
AJ
64{ \
65 switch (mem_idx) \
66 { \
9c708c7f
PD
67 case 0: return (type) cpu_##insn##_kernel_ra(env, addr, retaddr); \
68 case 1: return (type) cpu_##insn##_super_ra(env, addr, retaddr); \
0ae43045 69 default: \
9c708c7f 70 case 2: return (type) cpu_##insn##_user_ra(env, addr, retaddr); \
42c86612 71 case 3: return (type) cpu_##insn##_error_ra(env, addr, retaddr); \
0ae43045
AJ
72 } \
73}
74#endif
0ae43045 75HELPER_LD(lw, ldl, int32_t)
adc370a4 76#if defined(TARGET_MIPS64)
0ae43045 77HELPER_LD(ld, ldq, int64_t)
adc370a4 78#endif
0ae43045
AJ
79#undef HELPER_LD
80
81#if defined(CONFIG_USER_ONLY)
82#define HELPER_ST(name, insn, type) \
895c2d04 83static inline void do_##name(CPUMIPSState *env, target_ulong addr, \
9c708c7f 84 type val, int mem_idx, uintptr_t retaddr) \
0ae43045 85{ \
9c708c7f 86 cpu_##insn##_data_ra(env, addr, val, retaddr); \
0ae43045
AJ
87}
88#else
89#define HELPER_ST(name, insn, type) \
895c2d04 90static inline void do_##name(CPUMIPSState *env, target_ulong addr, \
9c708c7f 91 type val, int mem_idx, uintptr_t retaddr) \
0ae43045
AJ
92{ \
93 switch (mem_idx) \
94 { \
9c708c7f
PD
95 case 0: cpu_##insn##_kernel_ra(env, addr, val, retaddr); break; \
96 case 1: cpu_##insn##_super_ra(env, addr, val, retaddr); break; \
0ae43045 97 default: \
9c708c7f 98 case 2: cpu_##insn##_user_ra(env, addr, val, retaddr); break; \
42c86612
JH
99 case 3: \
100 cpu_##insn##_error_ra(env, addr, val, retaddr); \
101 break; \
0ae43045
AJ
102 } \
103}
104#endif
105HELPER_ST(sb, stb, uint8_t)
106HELPER_ST(sw, stl, uint32_t)
adc370a4 107#if defined(TARGET_MIPS64)
0ae43045 108HELPER_ST(sd, stq, uint64_t)
adc370a4 109#endif
0ae43045
AJ
110#undef HELPER_ST
111
6af0bf9c 112/* 64 bits arithmetic for 32 bits hosts */
895c2d04 113static inline uint64_t get_HILO(CPUMIPSState *env)
6af0bf9c 114{
b5dc7732 115 return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0];
6af0bf9c
FB
116}
117
895c2d04 118static inline target_ulong set_HIT0_LO(CPUMIPSState *env, uint64_t HILO)
e9c71dd1 119{
b5dc7732 120 env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
9be38598 121 return env->active_tc.HI[0] = (int32_t)(HILO >> 32);
e9c71dd1
TS
122}
123
895c2d04 124static inline target_ulong set_HI_LOT0(CPUMIPSState *env, uint64_t HILO)
e9c71dd1 125{
6fc97faf 126 target_ulong tmp = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
b5dc7732 127 env->active_tc.HI[0] = (int32_t)(HILO >> 32);
6fc97faf 128 return tmp;
e9c71dd1
TS
129}
130
e9c71dd1 131/* Multiplication variants of the vr54xx. */
895c2d04
BS
132target_ulong helper_muls(CPUMIPSState *env, target_ulong arg1,
133 target_ulong arg2)
e9c71dd1 134{
895c2d04
BS
135 return set_HI_LOT0(env, 0 - ((int64_t)(int32_t)arg1 *
136 (int64_t)(int32_t)arg2));
e9c71dd1
TS
137}
138
895c2d04
BS
139target_ulong helper_mulsu(CPUMIPSState *env, target_ulong arg1,
140 target_ulong arg2)
e9c71dd1 141{
895c2d04
BS
142 return set_HI_LOT0(env, 0 - (uint64_t)(uint32_t)arg1 *
143 (uint64_t)(uint32_t)arg2);
e9c71dd1
TS
144}
145
895c2d04
BS
146target_ulong helper_macc(CPUMIPSState *env, target_ulong arg1,
147 target_ulong arg2)
e9c71dd1 148{
895c2d04
BS
149 return set_HI_LOT0(env, (int64_t)get_HILO(env) + (int64_t)(int32_t)arg1 *
150 (int64_t)(int32_t)arg2);
e9c71dd1
TS
151}
152
895c2d04
BS
153target_ulong helper_macchi(CPUMIPSState *env, target_ulong arg1,
154 target_ulong arg2)
e9c71dd1 155{
895c2d04
BS
156 return set_HIT0_LO(env, (int64_t)get_HILO(env) + (int64_t)(int32_t)arg1 *
157 (int64_t)(int32_t)arg2);
e9c71dd1
TS
158}
159
895c2d04
BS
160target_ulong helper_maccu(CPUMIPSState *env, target_ulong arg1,
161 target_ulong arg2)
e9c71dd1 162{
895c2d04
BS
163 return set_HI_LOT0(env, (uint64_t)get_HILO(env) +
164 (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
e9c71dd1
TS
165}
166
895c2d04
BS
167target_ulong helper_macchiu(CPUMIPSState *env, target_ulong arg1,
168 target_ulong arg2)
e9c71dd1 169{
895c2d04
BS
170 return set_HIT0_LO(env, (uint64_t)get_HILO(env) +
171 (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
e9c71dd1
TS
172}
173
895c2d04
BS
174target_ulong helper_msac(CPUMIPSState *env, target_ulong arg1,
175 target_ulong arg2)
e9c71dd1 176{
895c2d04
BS
177 return set_HI_LOT0(env, (int64_t)get_HILO(env) - (int64_t)(int32_t)arg1 *
178 (int64_t)(int32_t)arg2);
e9c71dd1
TS
179}
180
895c2d04
BS
181target_ulong helper_msachi(CPUMIPSState *env, target_ulong arg1,
182 target_ulong arg2)
e9c71dd1 183{
895c2d04
BS
184 return set_HIT0_LO(env, (int64_t)get_HILO(env) - (int64_t)(int32_t)arg1 *
185 (int64_t)(int32_t)arg2);
e9c71dd1
TS
186}
187
895c2d04
BS
188target_ulong helper_msacu(CPUMIPSState *env, target_ulong arg1,
189 target_ulong arg2)
e9c71dd1 190{
895c2d04
BS
191 return set_HI_LOT0(env, (uint64_t)get_HILO(env) -
192 (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
e9c71dd1
TS
193}
194
895c2d04
BS
195target_ulong helper_msachiu(CPUMIPSState *env, target_ulong arg1,
196 target_ulong arg2)
e9c71dd1 197{
895c2d04
BS
198 return set_HIT0_LO(env, (uint64_t)get_HILO(env) -
199 (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
e9c71dd1
TS
200}
201
895c2d04
BS
202target_ulong helper_mulhi(CPUMIPSState *env, target_ulong arg1,
203 target_ulong arg2)
e9c71dd1 204{
895c2d04 205 return set_HIT0_LO(env, (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
e9c71dd1
TS
206}
207
895c2d04
BS
208target_ulong helper_mulhiu(CPUMIPSState *env, target_ulong arg1,
209 target_ulong arg2)
e9c71dd1 210{
895c2d04
BS
211 return set_HIT0_LO(env, (uint64_t)(uint32_t)arg1 *
212 (uint64_t)(uint32_t)arg2);
e9c71dd1
TS
213}
214
895c2d04
BS
215target_ulong helper_mulshi(CPUMIPSState *env, target_ulong arg1,
216 target_ulong arg2)
e9c71dd1 217{
895c2d04
BS
218 return set_HIT0_LO(env, 0 - (int64_t)(int32_t)arg1 *
219 (int64_t)(int32_t)arg2);
e9c71dd1
TS
220}
221
895c2d04
BS
222target_ulong helper_mulshiu(CPUMIPSState *env, target_ulong arg1,
223 target_ulong arg2)
e9c71dd1 224{
895c2d04
BS
225 return set_HIT0_LO(env, 0 - (uint64_t)(uint32_t)arg1 *
226 (uint64_t)(uint32_t)arg2);
e9c71dd1 227}
6af0bf9c 228
15eacb9b
YK
229static inline target_ulong bitswap(target_ulong v)
230{
74dda987
LA
231 v = ((v >> 1) & (target_ulong)0x5555555555555555ULL) |
232 ((v & (target_ulong)0x5555555555555555ULL) << 1);
233 v = ((v >> 2) & (target_ulong)0x3333333333333333ULL) |
234 ((v & (target_ulong)0x3333333333333333ULL) << 2);
235 v = ((v >> 4) & (target_ulong)0x0F0F0F0F0F0F0F0FULL) |
236 ((v & (target_ulong)0x0F0F0F0F0F0F0F0FULL) << 4);
15eacb9b
YK
237 return v;
238}
239
240#ifdef TARGET_MIPS64
241target_ulong helper_dbitswap(target_ulong rt)
242{
243 return bitswap(rt);
244}
245#endif
246
247target_ulong helper_bitswap(target_ulong rt)
248{
249 return (int32_t)bitswap(rt);
250}
251
e7139c44 252#ifndef CONFIG_USER_ONLY
c36bbb28 253
a8170e5e 254static inline hwaddr do_translate_address(CPUMIPSState *env,
895c2d04 255 target_ulong address,
9c708c7f 256 int rw, uintptr_t retaddr)
c36bbb28 257{
a8170e5e 258 hwaddr lladdr;
9c708c7f 259 CPUState *cs = CPU(mips_env_get_cpu(env));
c36bbb28
AJ
260
261 lladdr = cpu_mips_translate_address(env, address, rw);
262
263 if (lladdr == -1LL) {
9c708c7f 264 cpu_loop_exit_restore(cs, retaddr);
c36bbb28
AJ
265 } else {
266 return lladdr;
267 }
268}
269
6489dd25 270#define HELPER_LD_ATOMIC(name, insn, almask) \
895c2d04 271target_ulong helper_##name(CPUMIPSState *env, target_ulong arg, int mem_idx) \
e7139c44 272{ \
6489dd25
LA
273 if (arg & almask) { \
274 env->CP0_BadVAddr = arg; \
9c708c7f 275 do_raise_exception(env, EXCP_AdEL, GETPC()); \
6489dd25 276 } \
9c708c7f
PD
277 env->lladdr = do_translate_address(env, arg, 0, GETPC()); \
278 env->llval = do_##insn(env, arg, mem_idx, GETPC()); \
e7139c44
AJ
279 return env->llval; \
280}
6489dd25 281HELPER_LD_ATOMIC(ll, lw, 0x3)
e7139c44 282#ifdef TARGET_MIPS64
6489dd25 283HELPER_LD_ATOMIC(lld, ld, 0x7)
e7139c44
AJ
284#endif
285#undef HELPER_LD_ATOMIC
286
287#define HELPER_ST_ATOMIC(name, ld_insn, st_insn, almask) \
895c2d04
BS
288target_ulong helper_##name(CPUMIPSState *env, target_ulong arg1, \
289 target_ulong arg2, int mem_idx) \
e7139c44
AJ
290{ \
291 target_long tmp; \
292 \
293 if (arg2 & almask) { \
294 env->CP0_BadVAddr = arg2; \
9c708c7f 295 do_raise_exception(env, EXCP_AdES, GETPC()); \
e7139c44 296 } \
9c708c7f
PD
297 if (do_translate_address(env, arg2, 1, GETPC()) == env->lladdr) { \
298 tmp = do_##ld_insn(env, arg2, mem_idx, GETPC()); \
e7139c44 299 if (tmp == env->llval) { \
9c708c7f 300 do_##st_insn(env, arg2, arg1, mem_idx, GETPC()); \
e7139c44
AJ
301 return 1; \
302 } \
303 } \
304 return 0; \
305}
306HELPER_ST_ATOMIC(sc, lw, sw, 0x3)
307#ifdef TARGET_MIPS64
308HELPER_ST_ATOMIC(scd, ld, sd, 0x7)
309#endif
310#undef HELPER_ST_ATOMIC
311#endif
312
c8c2227e
TS
313#ifdef TARGET_WORDS_BIGENDIAN
314#define GET_LMASK(v) ((v) & 3)
315#define GET_OFFSET(addr, offset) (addr + (offset))
316#else
317#define GET_LMASK(v) (((v) & 3) ^ 3)
318#define GET_OFFSET(addr, offset) (addr - (offset))
319#endif
320
895c2d04
BS
321void helper_swl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
322 int mem_idx)
c8c2227e 323{
9c708c7f 324 do_sb(env, arg2, (uint8_t)(arg1 >> 24), mem_idx, GETPC());
c8c2227e 325
9c708c7f
PD
326 if (GET_LMASK(arg2) <= 2) {
327 do_sb(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16), mem_idx,
328 GETPC());
329 }
c8c2227e 330
9c708c7f
PD
331 if (GET_LMASK(arg2) <= 1) {
332 do_sb(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8), mem_idx,
333 GETPC());
334 }
c8c2227e 335
9c708c7f
PD
336 if (GET_LMASK(arg2) == 0) {
337 do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)arg1, mem_idx,
338 GETPC());
339 }
c8c2227e
TS
340}
341
895c2d04
BS
342void helper_swr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
343 int mem_idx)
c8c2227e 344{
9c708c7f 345 do_sb(env, arg2, (uint8_t)arg1, mem_idx, GETPC());
c8c2227e 346
9c708c7f
PD
347 if (GET_LMASK(arg2) >= 1) {
348 do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx,
349 GETPC());
350 }
c8c2227e 351
9c708c7f
PD
352 if (GET_LMASK(arg2) >= 2) {
353 do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx,
354 GETPC());
355 }
c8c2227e 356
9c708c7f
PD
357 if (GET_LMASK(arg2) == 3) {
358 do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx,
359 GETPC());
360 }
c8c2227e
TS
361}
362
363#if defined(TARGET_MIPS64)
364/* "half" load and stores. We must do the memory access inline,
365 or fault handling won't work. */
366
367#ifdef TARGET_WORDS_BIGENDIAN
368#define GET_LMASK64(v) ((v) & 7)
369#else
370#define GET_LMASK64(v) (((v) & 7) ^ 7)
371#endif
372
895c2d04
BS
373void helper_sdl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
374 int mem_idx)
c8c2227e 375{
9c708c7f 376 do_sb(env, arg2, (uint8_t)(arg1 >> 56), mem_idx, GETPC());
c8c2227e 377
9c708c7f
PD
378 if (GET_LMASK64(arg2) <= 6) {
379 do_sb(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48), mem_idx,
380 GETPC());
381 }
c8c2227e 382
9c708c7f
PD
383 if (GET_LMASK64(arg2) <= 5) {
384 do_sb(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40), mem_idx,
385 GETPC());
386 }
c8c2227e 387
9c708c7f
PD
388 if (GET_LMASK64(arg2) <= 4) {
389 do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32), mem_idx,
390 GETPC());
391 }
c8c2227e 392
9c708c7f
PD
393 if (GET_LMASK64(arg2) <= 3) {
394 do_sb(env, GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24), mem_idx,
395 GETPC());
396 }
c8c2227e 397
9c708c7f
PD
398 if (GET_LMASK64(arg2) <= 2) {
399 do_sb(env, GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16), mem_idx,
400 GETPC());
401 }
c8c2227e 402
9c708c7f
PD
403 if (GET_LMASK64(arg2) <= 1) {
404 do_sb(env, GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8), mem_idx,
405 GETPC());
406 }
c8c2227e 407
9c708c7f
PD
408 if (GET_LMASK64(arg2) <= 0) {
409 do_sb(env, GET_OFFSET(arg2, 7), (uint8_t)arg1, mem_idx,
410 GETPC());
411 }
c8c2227e
TS
412}
413
895c2d04
BS
414void helper_sdr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
415 int mem_idx)
c8c2227e 416{
9c708c7f 417 do_sb(env, arg2, (uint8_t)arg1, mem_idx, GETPC());
c8c2227e 418
9c708c7f
PD
419 if (GET_LMASK64(arg2) >= 1) {
420 do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx,
421 GETPC());
422 }
c8c2227e 423
9c708c7f
PD
424 if (GET_LMASK64(arg2) >= 2) {
425 do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx,
426 GETPC());
427 }
c8c2227e 428
9c708c7f
PD
429 if (GET_LMASK64(arg2) >= 3) {
430 do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx,
431 GETPC());
432 }
c8c2227e 433
9c708c7f
PD
434 if (GET_LMASK64(arg2) >= 4) {
435 do_sb(env, GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), mem_idx,
436 GETPC());
437 }
c8c2227e 438
9c708c7f
PD
439 if (GET_LMASK64(arg2) >= 5) {
440 do_sb(env, GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), mem_idx,
441 GETPC());
442 }
c8c2227e 443
9c708c7f
PD
444 if (GET_LMASK64(arg2) >= 6) {
445 do_sb(env, GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), mem_idx,
446 GETPC());
447 }
c8c2227e 448
9c708c7f
PD
449 if (GET_LMASK64(arg2) == 7) {
450 do_sb(env, GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), mem_idx,
451 GETPC());
452 }
c8c2227e
TS
453}
454#endif /* TARGET_MIPS64 */
455
3c824109
NF
456static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };
457
895c2d04
BS
458void helper_lwm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
459 uint32_t mem_idx)
3c824109
NF
460{
461 target_ulong base_reglist = reglist & 0xf;
462 target_ulong do_r31 = reglist & 0x10;
3c824109
NF
463
464 if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
465 target_ulong i;
466
467 for (i = 0; i < base_reglist; i++) {
18bba4dc 468 env->active_tc.gpr[multiple_regs[i]] =
9c708c7f 469 (target_long)do_lw(env, addr, mem_idx, GETPC());
3c824109
NF
470 addr += 4;
471 }
472 }
473
474 if (do_r31) {
9c708c7f
PD
475 env->active_tc.gpr[31] = (target_long)do_lw(env, addr, mem_idx,
476 GETPC());
3c824109
NF
477 }
478}
479
895c2d04
BS
480void helper_swm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
481 uint32_t mem_idx)
3c824109
NF
482{
483 target_ulong base_reglist = reglist & 0xf;
484 target_ulong do_r31 = reglist & 0x10;
3c824109
NF
485
486 if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
487 target_ulong i;
488
489 for (i = 0; i < base_reglist; i++) {
9c708c7f
PD
490 do_sw(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx,
491 GETPC());
3c824109
NF
492 addr += 4;
493 }
494 }
495
496 if (do_r31) {
9c708c7f 497 do_sw(env, addr, env->active_tc.gpr[31], mem_idx, GETPC());
3c824109
NF
498 }
499}
500
501#if defined(TARGET_MIPS64)
895c2d04
BS
502void helper_ldm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
503 uint32_t mem_idx)
3c824109
NF
504{
505 target_ulong base_reglist = reglist & 0xf;
506 target_ulong do_r31 = reglist & 0x10;
3c824109
NF
507
508 if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
509 target_ulong i;
510
511 for (i = 0; i < base_reglist; i++) {
9c708c7f
PD
512 env->active_tc.gpr[multiple_regs[i]] = do_ld(env, addr, mem_idx,
513 GETPC());
3c824109
NF
514 addr += 8;
515 }
516 }
517
518 if (do_r31) {
9c708c7f 519 env->active_tc.gpr[31] = do_ld(env, addr, mem_idx, GETPC());
3c824109
NF
520 }
521}
522
895c2d04
BS
523void helper_sdm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
524 uint32_t mem_idx)
3c824109
NF
525{
526 target_ulong base_reglist = reglist & 0xf;
527 target_ulong do_r31 = reglist & 0x10;
3c824109
NF
528
529 if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
530 target_ulong i;
531
532 for (i = 0; i < base_reglist; i++) {
9c708c7f
PD
533 do_sd(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx,
534 GETPC());
3c824109
NF
535 addr += 8;
536 }
537 }
538
539 if (do_r31) {
9c708c7f 540 do_sd(env, addr, env->active_tc.gpr[31], mem_idx, GETPC());
3c824109
NF
541 }
542}
543#endif
544
0eaef5aa 545#ifndef CONFIG_USER_ONLY
f249412c 546/* SMP helpers. */
b35d77d7 547static bool mips_vpe_is_wfi(MIPSCPU *c)
f249412c 548{
259186a7 549 CPUState *cpu = CPU(c);
b35d77d7
AF
550 CPUMIPSState *env = &c->env;
551
f249412c
EI
552 /* If the VPE is halted but otherwise active, it means it's waiting for
553 an interrupt. */
259186a7 554 return cpu->halted && mips_vpe_active(env);
f249412c
EI
555}
556
01bc435b
YK
557static bool mips_vp_is_wfi(MIPSCPU *c)
558{
559 CPUState *cpu = CPU(c);
560 CPUMIPSState *env = &c->env;
561
562 return cpu->halted && mips_vp_active(env);
563}
564
c3affe56 565static inline void mips_vpe_wake(MIPSCPU *c)
f249412c 566{
cb8d4c8f 567 /* Don't set ->halted = 0 directly, let it be done via cpu_has_work
f249412c
EI
568 because there might be other conditions that state that c should
569 be sleeping. */
c3affe56 570 cpu_interrupt(CPU(c), CPU_INTERRUPT_WAKE);
f249412c
EI
571}
572
6f4d6b09 573static inline void mips_vpe_sleep(MIPSCPU *cpu)
f249412c 574{
259186a7 575 CPUState *cs = CPU(cpu);
6f4d6b09 576
f249412c
EI
577 /* The VPE was shut off, really go to bed.
578 Reset any old _WAKE requests. */
259186a7 579 cs->halted = 1;
d8ed887b 580 cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
f249412c
EI
581}
582
135dd63a 583static inline void mips_tc_wake(MIPSCPU *cpu, int tc)
f249412c 584{
135dd63a
AF
585 CPUMIPSState *c = &cpu->env;
586
f249412c 587 /* FIXME: TC reschedule. */
b35d77d7 588 if (mips_vpe_active(c) && !mips_vpe_is_wfi(cpu)) {
c3affe56 589 mips_vpe_wake(cpu);
f249412c
EI
590 }
591}
592
c6679e90 593static inline void mips_tc_sleep(MIPSCPU *cpu, int tc)
f249412c 594{
c6679e90
AF
595 CPUMIPSState *c = &cpu->env;
596
f249412c
EI
597 /* FIXME: TC reschedule. */
598 if (!mips_vpe_active(c)) {
6f4d6b09 599 mips_vpe_sleep(cpu);
f249412c
EI
600 }
601}
602
66afd1ad
AF
603/**
604 * mips_cpu_map_tc:
605 * @env: CPU from which mapping is performed.
606 * @tc: Should point to an int with the value of the global TC index.
607 *
608 * This function will transform @tc into a local index within the
609 * returned #CPUMIPSState.
610 */
611/* FIXME: This code assumes that all VPEs have the same number of TCs,
b93bbdcd 612 which depends on runtime setup. Can probably be fixed by
7db13fae 613 walking the list of CPUMIPSStates. */
895c2d04 614static CPUMIPSState *mips_cpu_map_tc(CPUMIPSState *env, int *tc)
b93bbdcd 615{
38d8f5c8 616 MIPSCPU *cpu;
ce3960eb 617 CPUState *cs;
38d8f5c8 618 CPUState *other_cs;
ce3960eb 619 int vpe_idx;
b93bbdcd
EI
620 int tc_idx = *tc;
621
622 if (!(env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))) {
623 /* Not allowed to address other CPUs. */
624 *tc = env->current_tc;
625 return env;
626 }
627
ce3960eb
AF
628 cs = CPU(mips_env_get_cpu(env));
629 vpe_idx = tc_idx / cs->nr_threads;
630 *tc = tc_idx % cs->nr_threads;
38d8f5c8
AF
631 other_cs = qemu_get_cpu(vpe_idx);
632 if (other_cs == NULL) {
633 return env;
634 }
635 cpu = MIPS_CPU(other_cs);
636 return &cpu->env;
b93bbdcd
EI
637}
638
fe8dca8c
EI
639/* The per VPE CP0_Status register shares some fields with the per TC
640 CP0_TCStatus registers. These fields are wired to the same registers,
641 so changes to either of them should be reflected on both registers.
642
643 Also, EntryHi shares the bottom 8 bit ASID with TCStauts.
644
645 These helper call synchronizes the regs for a given cpu. */
646
81a423e6
MR
647/* Called for updates to CP0_Status. Defined in "cpu.h" for gdbstub.c. */
648/* static inline void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu,
649 int tc); */
fe8dca8c
EI
650
651/* Called for updates to CP0_TCStatus. */
895c2d04
BS
652static void sync_c0_tcstatus(CPUMIPSState *cpu, int tc,
653 target_ulong v)
fe8dca8c
EI
654{
655 uint32_t status;
656 uint32_t tcu, tmx, tasid, tksu;
f45cb2f4 657 uint32_t mask = ((1U << CP0St_CU3)
fe8dca8c
EI
658 | (1 << CP0St_CU2)
659 | (1 << CP0St_CU1)
660 | (1 << CP0St_CU0)
661 | (1 << CP0St_MX)
662 | (3 << CP0St_KSU));
663
664 tcu = (v >> CP0TCSt_TCU0) & 0xf;
665 tmx = (v >> CP0TCSt_TMX) & 0x1;
6ec98bd7 666 tasid = v & cpu->CP0_EntryHi_ASID_mask;
fe8dca8c
EI
667 tksu = (v >> CP0TCSt_TKSU) & 0x3;
668
669 status = tcu << CP0St_CU0;
670 status |= tmx << CP0St_MX;
671 status |= tksu << CP0St_KSU;
672
673 cpu->CP0_Status &= ~mask;
674 cpu->CP0_Status |= status;
675
676 /* Sync the TASID with EntryHi. */
6ec98bd7 677 cpu->CP0_EntryHi &= ~cpu->CP0_EntryHi_ASID_mask;
6a973e6b 678 cpu->CP0_EntryHi |= tasid;
fe8dca8c
EI
679
680 compute_hflags(cpu);
681}
682
683/* Called for updates to CP0_EntryHi. */
7db13fae 684static void sync_c0_entryhi(CPUMIPSState *cpu, int tc)
fe8dca8c
EI
685{
686 int32_t *tcst;
687 uint32_t asid, v = cpu->CP0_EntryHi;
688
6ec98bd7 689 asid = v & cpu->CP0_EntryHi_ASID_mask;
fe8dca8c
EI
690
691 if (tc == cpu->current_tc) {
692 tcst = &cpu->active_tc.CP0_TCStatus;
693 } else {
694 tcst = &cpu->tcs[tc].CP0_TCStatus;
695 }
696
6ec98bd7 697 *tcst &= ~cpu->CP0_EntryHi_ASID_mask;
fe8dca8c
EI
698 *tcst |= asid;
699}
700
6af0bf9c 701/* CP0 helpers */
895c2d04 702target_ulong helper_mfc0_mvpcontrol(CPUMIPSState *env)
f1aa6320 703{
be24bb4f 704 return env->mvp->CP0_MVPControl;
f1aa6320
TS
705}
706
895c2d04 707target_ulong helper_mfc0_mvpconf0(CPUMIPSState *env)
f1aa6320 708{
be24bb4f 709 return env->mvp->CP0_MVPConf0;
f1aa6320
TS
710}
711
895c2d04 712target_ulong helper_mfc0_mvpconf1(CPUMIPSState *env)
f1aa6320 713{
be24bb4f 714 return env->mvp->CP0_MVPConf1;
f1aa6320
TS
715}
716
895c2d04 717target_ulong helper_mfc0_random(CPUMIPSState *env)
6af0bf9c 718{
be24bb4f 719 return (int32_t)cpu_mips_get_random(env);
873eb012 720}
6af0bf9c 721
895c2d04 722target_ulong helper_mfc0_tcstatus(CPUMIPSState *env)
f1aa6320 723{
b5dc7732 724 return env->active_tc.CP0_TCStatus;
f1aa6320
TS
725}
726
895c2d04 727target_ulong helper_mftc0_tcstatus(CPUMIPSState *env)
f1aa6320
TS
728{
729 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 730 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 731
b93bbdcd
EI
732 if (other_tc == other->current_tc)
733 return other->active_tc.CP0_TCStatus;
b5dc7732 734 else
b93bbdcd 735 return other->tcs[other_tc].CP0_TCStatus;
f1aa6320
TS
736}
737
895c2d04 738target_ulong helper_mfc0_tcbind(CPUMIPSState *env)
f1aa6320 739{
b5dc7732 740 return env->active_tc.CP0_TCBind;
f1aa6320
TS
741}
742
895c2d04 743target_ulong helper_mftc0_tcbind(CPUMIPSState *env)
f1aa6320
TS
744{
745 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 746 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 747
b93bbdcd
EI
748 if (other_tc == other->current_tc)
749 return other->active_tc.CP0_TCBind;
b5dc7732 750 else
b93bbdcd 751 return other->tcs[other_tc].CP0_TCBind;
f1aa6320
TS
752}
753
895c2d04 754target_ulong helper_mfc0_tcrestart(CPUMIPSState *env)
f1aa6320 755{
b5dc7732 756 return env->active_tc.PC;
f1aa6320
TS
757}
758
895c2d04 759target_ulong helper_mftc0_tcrestart(CPUMIPSState *env)
f1aa6320
TS
760{
761 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 762 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 763
b93bbdcd
EI
764 if (other_tc == other->current_tc)
765 return other->active_tc.PC;
b5dc7732 766 else
b93bbdcd 767 return other->tcs[other_tc].PC;
f1aa6320
TS
768}
769
895c2d04 770target_ulong helper_mfc0_tchalt(CPUMIPSState *env)
f1aa6320 771{
b5dc7732 772 return env->active_tc.CP0_TCHalt;
f1aa6320
TS
773}
774
895c2d04 775target_ulong helper_mftc0_tchalt(CPUMIPSState *env)
f1aa6320
TS
776{
777 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 778 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 779
b93bbdcd
EI
780 if (other_tc == other->current_tc)
781 return other->active_tc.CP0_TCHalt;
b5dc7732 782 else
b93bbdcd 783 return other->tcs[other_tc].CP0_TCHalt;
f1aa6320
TS
784}
785
895c2d04 786target_ulong helper_mfc0_tccontext(CPUMIPSState *env)
f1aa6320 787{
b5dc7732 788 return env->active_tc.CP0_TCContext;
f1aa6320
TS
789}
790
895c2d04 791target_ulong helper_mftc0_tccontext(CPUMIPSState *env)
f1aa6320
TS
792{
793 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 794 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 795
b93bbdcd
EI
796 if (other_tc == other->current_tc)
797 return other->active_tc.CP0_TCContext;
b5dc7732 798 else
b93bbdcd 799 return other->tcs[other_tc].CP0_TCContext;
f1aa6320
TS
800}
801
895c2d04 802target_ulong helper_mfc0_tcschedule(CPUMIPSState *env)
f1aa6320 803{
b5dc7732 804 return env->active_tc.CP0_TCSchedule;
f1aa6320
TS
805}
806
895c2d04 807target_ulong helper_mftc0_tcschedule(CPUMIPSState *env)
f1aa6320
TS
808{
809 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 810 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 811
b93bbdcd
EI
812 if (other_tc == other->current_tc)
813 return other->active_tc.CP0_TCSchedule;
b5dc7732 814 else
b93bbdcd 815 return other->tcs[other_tc].CP0_TCSchedule;
f1aa6320
TS
816}
817
895c2d04 818target_ulong helper_mfc0_tcschefback(CPUMIPSState *env)
f1aa6320 819{
b5dc7732 820 return env->active_tc.CP0_TCScheFBack;
f1aa6320
TS
821}
822
895c2d04 823target_ulong helper_mftc0_tcschefback(CPUMIPSState *env)
f1aa6320
TS
824{
825 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 826 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 827
b93bbdcd
EI
828 if (other_tc == other->current_tc)
829 return other->active_tc.CP0_TCScheFBack;
b5dc7732 830 else
b93bbdcd 831 return other->tcs[other_tc].CP0_TCScheFBack;
f1aa6320
TS
832}
833
895c2d04 834target_ulong helper_mfc0_count(CPUMIPSState *env)
873eb012 835{
d394698d
YK
836 int32_t count;
837 qemu_mutex_lock_iothread();
838 count = (int32_t) cpu_mips_get_count(env);
839 qemu_mutex_unlock_iothread();
840 return count;
6af0bf9c
FB
841}
842
895c2d04 843target_ulong helper_mftc0_entryhi(CPUMIPSState *env)
f1aa6320
TS
844{
845 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 846 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 847
fe8dca8c 848 return other->CP0_EntryHi;
f1aa6320
TS
849}
850
895c2d04 851target_ulong helper_mftc0_cause(CPUMIPSState *env)
5a25ce94
EI
852{
853 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
854 int32_t tccause;
895c2d04 855 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
5a25ce94
EI
856
857 if (other_tc == other->current_tc) {
858 tccause = other->CP0_Cause;
859 } else {
860 tccause = other->CP0_Cause;
861 }
862
863 return tccause;
864}
865
895c2d04 866target_ulong helper_mftc0_status(CPUMIPSState *env)
f1aa6320
TS
867{
868 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 869 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
b5dc7732 870
fe8dca8c 871 return other->CP0_Status;
f1aa6320
TS
872}
873
895c2d04 874target_ulong helper_mfc0_lladdr(CPUMIPSState *env)
f1aa6320 875{
2a6e32dd 876 return (int32_t)(env->lladdr >> env->CP0_LLAddr_shift);
f1aa6320
TS
877}
878
f6d4dd81
YK
879target_ulong helper_mfc0_maar(CPUMIPSState *env)
880{
881 return (int32_t) env->CP0_MAAR[env->CP0_MAARI];
882}
883
884target_ulong helper_mfhc0_maar(CPUMIPSState *env)
885{
886 return env->CP0_MAAR[env->CP0_MAARI] >> 32;
887}
888
895c2d04 889target_ulong helper_mfc0_watchlo(CPUMIPSState *env, uint32_t sel)
f1aa6320 890{
be24bb4f 891 return (int32_t)env->CP0_WatchLo[sel];
f1aa6320
TS
892}
893
895c2d04 894target_ulong helper_mfc0_watchhi(CPUMIPSState *env, uint32_t sel)
f1aa6320 895{
be24bb4f 896 return env->CP0_WatchHi[sel];
f1aa6320
TS
897}
898
895c2d04 899target_ulong helper_mfc0_debug(CPUMIPSState *env)
f1aa6320 900{
1a3fd9c3 901 target_ulong t0 = env->CP0_Debug;
f1aa6320 902 if (env->hflags & MIPS_HFLAG_DM)
be24bb4f
TS
903 t0 |= 1 << CP0DB_DM;
904
905 return t0;
f1aa6320
TS
906}
907
895c2d04 908target_ulong helper_mftc0_debug(CPUMIPSState *env)
f1aa6320
TS
909{
910 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
b5dc7732 911 int32_t tcstatus;
895c2d04 912 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
b5dc7732 913
b93bbdcd
EI
914 if (other_tc == other->current_tc)
915 tcstatus = other->active_tc.CP0_Debug_tcstatus;
b5dc7732 916 else
b93bbdcd 917 tcstatus = other->tcs[other_tc].CP0_Debug_tcstatus;
f1aa6320
TS
918
919 /* XXX: Might be wrong, check with EJTAG spec. */
b93bbdcd 920 return (other->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
b5dc7732 921 (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
f1aa6320
TS
922}
923
924#if defined(TARGET_MIPS64)
895c2d04 925target_ulong helper_dmfc0_tcrestart(CPUMIPSState *env)
f1aa6320 926{
b5dc7732 927 return env->active_tc.PC;
f1aa6320
TS
928}
929
895c2d04 930target_ulong helper_dmfc0_tchalt(CPUMIPSState *env)
f1aa6320 931{
b5dc7732 932 return env->active_tc.CP0_TCHalt;
f1aa6320
TS
933}
934
895c2d04 935target_ulong helper_dmfc0_tccontext(CPUMIPSState *env)
f1aa6320 936{
b5dc7732 937 return env->active_tc.CP0_TCContext;
f1aa6320
TS
938}
939
895c2d04 940target_ulong helper_dmfc0_tcschedule(CPUMIPSState *env)
f1aa6320 941{
b5dc7732 942 return env->active_tc.CP0_TCSchedule;
f1aa6320
TS
943}
944
895c2d04 945target_ulong helper_dmfc0_tcschefback(CPUMIPSState *env)
f1aa6320 946{
b5dc7732 947 return env->active_tc.CP0_TCScheFBack;
f1aa6320
TS
948}
949
895c2d04 950target_ulong helper_dmfc0_lladdr(CPUMIPSState *env)
f1aa6320 951{
2a6e32dd 952 return env->lladdr >> env->CP0_LLAddr_shift;
f1aa6320
TS
953}
954
f6d4dd81
YK
955target_ulong helper_dmfc0_maar(CPUMIPSState *env)
956{
957 return env->CP0_MAAR[env->CP0_MAARI];
958}
959
895c2d04 960target_ulong helper_dmfc0_watchlo(CPUMIPSState *env, uint32_t sel)
f1aa6320 961{
be24bb4f 962 return env->CP0_WatchLo[sel];
f1aa6320
TS
963}
964#endif /* TARGET_MIPS64 */
965
895c2d04 966void helper_mtc0_index(CPUMIPSState *env, target_ulong arg1)
f1aa6320 967{
ba801af4
LA
968 uint32_t index_p = env->CP0_Index & 0x80000000;
969 uint32_t tlb_index = arg1 & 0x7fffffff;
970 if (tlb_index < env->tlb->nb_tlb) {
971 if (env->insn_flags & ISA_MIPS32R6) {
972 index_p |= arg1 & 0x80000000;
973 }
974 env->CP0_Index = index_p | tlb_index;
975 }
f1aa6320
TS
976}
977
895c2d04 978void helper_mtc0_mvpcontrol(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
979{
980 uint32_t mask = 0;
981 uint32_t newval;
982
983 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))
984 mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) |
985 (1 << CP0MVPCo_EVP);
986 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
987 mask |= (1 << CP0MVPCo_STLB);
d9bea114 988 newval = (env->mvp->CP0_MVPControl & ~mask) | (arg1 & mask);
f1aa6320
TS
989
990 // TODO: Enable/disable shared TLB, enable/disable VPEs.
991
992 env->mvp->CP0_MVPControl = newval;
993}
994
895c2d04 995void helper_mtc0_vpecontrol(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
996{
997 uint32_t mask;
998 uint32_t newval;
999
1000 mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
1001 (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
d9bea114 1002 newval = (env->CP0_VPEControl & ~mask) | (arg1 & mask);
f1aa6320
TS
1003
1004 /* Yield scheduler intercept not implemented. */
1005 /* Gating storage scheduler intercept not implemented. */
1006
1007 // TODO: Enable/disable TCs.
1008
1009 env->CP0_VPEControl = newval;
1010}
1011
895c2d04 1012void helper_mttc0_vpecontrol(CPUMIPSState *env, target_ulong arg1)
5a25ce94
EI
1013{
1014 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1015 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
5a25ce94
EI
1016 uint32_t mask;
1017 uint32_t newval;
1018
1019 mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
1020 (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
1021 newval = (other->CP0_VPEControl & ~mask) | (arg1 & mask);
1022
1023 /* TODO: Enable/disable TCs. */
1024
1025 other->CP0_VPEControl = newval;
1026}
1027
895c2d04 1028target_ulong helper_mftc0_vpecontrol(CPUMIPSState *env)
5a25ce94
EI
1029{
1030 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1031 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
5a25ce94
EI
1032 /* FIXME: Mask away return zero on read bits. */
1033 return other->CP0_VPEControl;
1034}
1035
895c2d04 1036target_ulong helper_mftc0_vpeconf0(CPUMIPSState *env)
5a25ce94
EI
1037{
1038 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1039 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
5a25ce94
EI
1040
1041 return other->CP0_VPEConf0;
1042}
1043
895c2d04 1044void helper_mtc0_vpeconf0(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1045{
1046 uint32_t mask = 0;
1047 uint32_t newval;
1048
1049 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) {
1050 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))
1051 mask |= (0xff << CP0VPEC0_XTC);
1052 mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
1053 }
d9bea114 1054 newval = (env->CP0_VPEConf0 & ~mask) | (arg1 & mask);
f1aa6320
TS
1055
1056 // TODO: TC exclusive handling due to ERL/EXL.
1057
1058 env->CP0_VPEConf0 = newval;
1059}
1060
895c2d04 1061void helper_mttc0_vpeconf0(CPUMIPSState *env, target_ulong arg1)
5a25ce94
EI
1062{
1063 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1064 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
5a25ce94
EI
1065 uint32_t mask = 0;
1066 uint32_t newval;
1067
1068 mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
1069 newval = (other->CP0_VPEConf0 & ~mask) | (arg1 & mask);
1070
1071 /* TODO: TC exclusive handling due to ERL/EXL. */
1072 other->CP0_VPEConf0 = newval;
1073}
1074
895c2d04 1075void helper_mtc0_vpeconf1(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1076{
1077 uint32_t mask = 0;
1078 uint32_t newval;
1079
1080 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1081 mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) |
1082 (0xff << CP0VPEC1_NCP1);
d9bea114 1083 newval = (env->CP0_VPEConf1 & ~mask) | (arg1 & mask);
f1aa6320
TS
1084
1085 /* UDI not implemented. */
1086 /* CP2 not implemented. */
1087
1088 // TODO: Handle FPU (CP1) binding.
1089
1090 env->CP0_VPEConf1 = newval;
1091}
1092
895c2d04 1093void helper_mtc0_yqmask(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1094{
1095 /* Yield qualifier inputs not implemented. */
1096 env->CP0_YQMask = 0x00000000;
1097}
1098
895c2d04 1099void helper_mtc0_vpeopt(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1100{
d9bea114 1101 env->CP0_VPEOpt = arg1 & 0x0000ffff;
f1aa6320
TS
1102}
1103
e117f526
LA
1104#define MTC0_ENTRYLO_MASK(env) ((env->PAMask >> 6) & 0x3FFFFFFF)
1105
895c2d04 1106void helper_mtc0_entrylo0(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1107{
f1aa6320 1108 /* 1k pages not implemented */
7207c7f9 1109 target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE));
e117f526
LA
1110 env->CP0_EntryLo0 = (arg1 & MTC0_ENTRYLO_MASK(env))
1111 | (rxi << (CP0EnLo_XI - 30));
f1aa6320
TS
1112}
1113
7207c7f9 1114#if defined(TARGET_MIPS64)
e117f526
LA
1115#define DMTC0_ENTRYLO_MASK(env) (env->PAMask >> 6)
1116
7207c7f9
LA
1117void helper_dmtc0_entrylo0(CPUMIPSState *env, uint64_t arg1)
1118{
1119 uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32);
e117f526 1120 env->CP0_EntryLo0 = (arg1 & DMTC0_ENTRYLO_MASK(env)) | rxi;
7207c7f9
LA
1121}
1122#endif
1123
895c2d04 1124void helper_mtc0_tcstatus(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1125{
1126 uint32_t mask = env->CP0_TCStatus_rw_bitmask;
1127 uint32_t newval;
1128
d9bea114 1129 newval = (env->active_tc.CP0_TCStatus & ~mask) | (arg1 & mask);
f1aa6320 1130
b5dc7732 1131 env->active_tc.CP0_TCStatus = newval;
fe8dca8c 1132 sync_c0_tcstatus(env, env->current_tc, newval);
f1aa6320
TS
1133}
1134
895c2d04 1135void helper_mttc0_tcstatus(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1136{
1137 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1138 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1139
b93bbdcd
EI
1140 if (other_tc == other->current_tc)
1141 other->active_tc.CP0_TCStatus = arg1;
b5dc7732 1142 else
b93bbdcd 1143 other->tcs[other_tc].CP0_TCStatus = arg1;
fe8dca8c 1144 sync_c0_tcstatus(other, other_tc, arg1);
f1aa6320
TS
1145}
1146
895c2d04 1147void helper_mtc0_tcbind(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1148{
1149 uint32_t mask = (1 << CP0TCBd_TBE);
1150 uint32_t newval;
1151
1152 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1153 mask |= (1 << CP0TCBd_CurVPE);
d9bea114 1154 newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
b5dc7732 1155 env->active_tc.CP0_TCBind = newval;
f1aa6320
TS
1156}
1157
895c2d04 1158void helper_mttc0_tcbind(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1159{
1160 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1161 uint32_t mask = (1 << CP0TCBd_TBE);
1162 uint32_t newval;
895c2d04 1163 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1164
b93bbdcd 1165 if (other->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
f1aa6320 1166 mask |= (1 << CP0TCBd_CurVPE);
b93bbdcd
EI
1167 if (other_tc == other->current_tc) {
1168 newval = (other->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
1169 other->active_tc.CP0_TCBind = newval;
b5dc7732 1170 } else {
b93bbdcd
EI
1171 newval = (other->tcs[other_tc].CP0_TCBind & ~mask) | (arg1 & mask);
1172 other->tcs[other_tc].CP0_TCBind = newval;
b5dc7732 1173 }
f1aa6320
TS
1174}
1175
895c2d04 1176void helper_mtc0_tcrestart(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1177{
d9bea114 1178 env->active_tc.PC = arg1;
b5dc7732 1179 env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
5499b6ff 1180 env->lladdr = 0ULL;
f1aa6320
TS
1181 /* MIPS16 not implemented. */
1182}
1183
895c2d04 1184void helper_mttc0_tcrestart(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1185{
1186 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1187 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1188
b93bbdcd
EI
1189 if (other_tc == other->current_tc) {
1190 other->active_tc.PC = arg1;
1191 other->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1192 other->lladdr = 0ULL;
b5dc7732
TS
1193 /* MIPS16 not implemented. */
1194 } else {
b93bbdcd
EI
1195 other->tcs[other_tc].PC = arg1;
1196 other->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1197 other->lladdr = 0ULL;
b5dc7732
TS
1198 /* MIPS16 not implemented. */
1199 }
f1aa6320
TS
1200}
1201
895c2d04 1202void helper_mtc0_tchalt(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1203{
135dd63a
AF
1204 MIPSCPU *cpu = mips_env_get_cpu(env);
1205
d9bea114 1206 env->active_tc.CP0_TCHalt = arg1 & 0x1;
f1aa6320
TS
1207
1208 // TODO: Halt TC / Restart (if allocated+active) TC.
f249412c 1209 if (env->active_tc.CP0_TCHalt & 1) {
c6679e90 1210 mips_tc_sleep(cpu, env->current_tc);
f249412c 1211 } else {
135dd63a 1212 mips_tc_wake(cpu, env->current_tc);
f249412c 1213 }
f1aa6320
TS
1214}
1215
895c2d04 1216void helper_mttc0_tchalt(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1217{
1218 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1219 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
135dd63a 1220 MIPSCPU *other_cpu = mips_env_get_cpu(other);
f1aa6320
TS
1221
1222 // TODO: Halt TC / Restart (if allocated+active) TC.
1223
b93bbdcd
EI
1224 if (other_tc == other->current_tc)
1225 other->active_tc.CP0_TCHalt = arg1;
b5dc7732 1226 else
b93bbdcd 1227 other->tcs[other_tc].CP0_TCHalt = arg1;
f249412c
EI
1228
1229 if (arg1 & 1) {
c6679e90 1230 mips_tc_sleep(other_cpu, other_tc);
f249412c 1231 } else {
135dd63a 1232 mips_tc_wake(other_cpu, other_tc);
f249412c 1233 }
f1aa6320
TS
1234}
1235
895c2d04 1236void helper_mtc0_tccontext(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1237{
d9bea114 1238 env->active_tc.CP0_TCContext = arg1;
f1aa6320
TS
1239}
1240
895c2d04 1241void helper_mttc0_tccontext(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1242{
1243 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1244 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1245
b93bbdcd
EI
1246 if (other_tc == other->current_tc)
1247 other->active_tc.CP0_TCContext = arg1;
b5dc7732 1248 else
b93bbdcd 1249 other->tcs[other_tc].CP0_TCContext = arg1;
f1aa6320
TS
1250}
1251
895c2d04 1252void helper_mtc0_tcschedule(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1253{
d9bea114 1254 env->active_tc.CP0_TCSchedule = arg1;
f1aa6320
TS
1255}
1256
895c2d04 1257void helper_mttc0_tcschedule(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1258{
1259 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1260 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1261
b93bbdcd
EI
1262 if (other_tc == other->current_tc)
1263 other->active_tc.CP0_TCSchedule = arg1;
b5dc7732 1264 else
b93bbdcd 1265 other->tcs[other_tc].CP0_TCSchedule = arg1;
f1aa6320
TS
1266}
1267
895c2d04 1268void helper_mtc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1269{
d9bea114 1270 env->active_tc.CP0_TCScheFBack = arg1;
f1aa6320
TS
1271}
1272
895c2d04 1273void helper_mttc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1274{
1275 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1276 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1277
b93bbdcd
EI
1278 if (other_tc == other->current_tc)
1279 other->active_tc.CP0_TCScheFBack = arg1;
b5dc7732 1280 else
b93bbdcd 1281 other->tcs[other_tc].CP0_TCScheFBack = arg1;
f1aa6320
TS
1282}
1283
895c2d04 1284void helper_mtc0_entrylo1(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1285{
f1aa6320 1286 /* 1k pages not implemented */
7207c7f9 1287 target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE));
e117f526
LA
1288 env->CP0_EntryLo1 = (arg1 & MTC0_ENTRYLO_MASK(env))
1289 | (rxi << (CP0EnLo_XI - 30));
f1aa6320
TS
1290}
1291
7207c7f9
LA
1292#if defined(TARGET_MIPS64)
1293void helper_dmtc0_entrylo1(CPUMIPSState *env, uint64_t arg1)
1294{
1295 uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32);
e117f526 1296 env->CP0_EntryLo1 = (arg1 & DMTC0_ENTRYLO_MASK(env)) | rxi;
7207c7f9
LA
1297}
1298#endif
1299
895c2d04 1300void helper_mtc0_context(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1301{
d9bea114 1302 env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF);
f1aa6320
TS
1303}
1304
895c2d04 1305void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1306{
ba801af4
LA
1307 uint64_t mask = arg1 >> (TARGET_PAGE_BITS + 1);
1308 if (!(env->insn_flags & ISA_MIPS32R6) || (arg1 == ~0) ||
1309 (mask == 0x0000 || mask == 0x0003 || mask == 0x000F ||
1310 mask == 0x003F || mask == 0x00FF || mask == 0x03FF ||
1311 mask == 0x0FFF || mask == 0x3FFF || mask == 0xFFFF)) {
1312 env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
1313 }
f1aa6320
TS
1314}
1315
895c2d04 1316void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1317{
1318 /* SmartMIPS not implemented */
f1aa6320 1319 /* 1k pages not implemented */
7207c7f9
LA
1320 env->CP0_PageGrain = (arg1 & env->CP0_PageGrain_rw_bitmask) |
1321 (env->CP0_PageGrain & ~env->CP0_PageGrain_rw_bitmask);
e117f526
LA
1322 compute_hflags(env);
1323 restore_pamask(env);
f1aa6320
TS
1324}
1325
cec56a73
JH
1326void helper_mtc0_segctl0(CPUMIPSState *env, target_ulong arg1)
1327{
1328 CPUState *cs = CPU(mips_env_get_cpu(env));
1329
1330 env->CP0_SegCtl0 = arg1 & CP0SC0_MASK;
1331 tlb_flush(cs);
1332}
1333
1334void helper_mtc0_segctl1(CPUMIPSState *env, target_ulong arg1)
1335{
1336 CPUState *cs = CPU(mips_env_get_cpu(env));
1337
1338 env->CP0_SegCtl1 = arg1 & CP0SC1_MASK;
1339 tlb_flush(cs);
1340}
1341
1342void helper_mtc0_segctl2(CPUMIPSState *env, target_ulong arg1)
1343{
1344 CPUState *cs = CPU(mips_env_get_cpu(env));
1345
1346 env->CP0_SegCtl2 = arg1 & CP0SC2_MASK;
1347 tlb_flush(cs);
1348}
1349
895c2d04 1350void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1351{
ba801af4
LA
1352 if (env->insn_flags & ISA_MIPS32R6) {
1353 if (arg1 < env->tlb->nb_tlb) {
1354 env->CP0_Wired = arg1;
1355 }
1356 } else {
1357 env->CP0_Wired = arg1 % env->tlb->nb_tlb;
1358 }
f1aa6320
TS
1359}
1360
895c2d04 1361void helper_mtc0_srsconf0(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1362{
d9bea114 1363 env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask;
f1aa6320
TS
1364}
1365
895c2d04 1366void helper_mtc0_srsconf1(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1367{
d9bea114 1368 env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask;
f1aa6320
TS
1369}
1370
895c2d04 1371void helper_mtc0_srsconf2(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1372{
d9bea114 1373 env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask;
f1aa6320
TS
1374}
1375
895c2d04 1376void helper_mtc0_srsconf3(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1377{
d9bea114 1378 env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask;
f1aa6320
TS
1379}
1380
895c2d04 1381void helper_mtc0_srsconf4(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1382{
d9bea114 1383 env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask;
f1aa6320
TS
1384}
1385
895c2d04 1386void helper_mtc0_hwrena(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1387{
d279279e
PJ
1388 uint32_t mask = 0x0000000F;
1389
b00c7218
YK
1390 if ((env->CP0_Config1 & (1 << CP0C1_PC)) &&
1391 (env->insn_flags & ISA_MIPS32R6)) {
1392 mask |= (1 << 4);
1393 }
1394 if (env->insn_flags & ISA_MIPS32R6) {
1395 mask |= (1 << 5);
1396 }
d279279e
PJ
1397 if (env->CP0_Config3 & (1 << CP0C3_ULRI)) {
1398 mask |= (1 << 29);
1399
1400 if (arg1 & (1 << 29)) {
1401 env->hflags |= MIPS_HFLAG_HWRENA_ULR;
1402 } else {
1403 env->hflags &= ~MIPS_HFLAG_HWRENA_ULR;
1404 }
1405 }
1406
1407 env->CP0_HWREna = arg1 & mask;
f1aa6320
TS
1408}
1409
895c2d04 1410void helper_mtc0_count(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1411{
d394698d 1412 qemu_mutex_lock_iothread();
d9bea114 1413 cpu_mips_store_count(env, arg1);
d394698d 1414 qemu_mutex_unlock_iothread();
f1aa6320
TS
1415}
1416
895c2d04 1417void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1418{
9456c2fb 1419 target_ulong old, val, mask;
6ec98bd7 1420 mask = (TARGET_PAGE_MASK << 1) | env->CP0_EntryHi_ASID_mask;
9456c2fb
LA
1421 if (((env->CP0_Config4 >> CP0C4_IE) & 0x3) >= 2) {
1422 mask |= 1 << CP0EnHi_EHINV;
1423 }
f1aa6320
TS
1424
1425 /* 1k pages not implemented */
f1aa6320 1426#if defined(TARGET_MIPS64)
ba801af4
LA
1427 if (env->insn_flags & ISA_MIPS32R6) {
1428 int entryhi_r = extract64(arg1, 62, 2);
1429 int config0_at = extract32(env->CP0_Config0, 13, 2);
1430 bool no_supervisor = (env->CP0_Status_rw_bitmask & 0x8) == 0;
1431 if ((entryhi_r == 2) ||
1432 (entryhi_r == 1 && (no_supervisor || config0_at == 1))) {
1433 /* skip EntryHi.R field if new value is reserved */
1434 mask &= ~(0x3ull << 62);
1435 }
1436 }
1437 mask &= env->SEGMask;
f1aa6320
TS
1438#endif
1439 old = env->CP0_EntryHi;
ba801af4 1440 val = (arg1 & mask) | (old & ~mask);
f1aa6320
TS
1441 env->CP0_EntryHi = val;
1442 if (env->CP0_Config3 & (1 << CP0C3_MT)) {
fe8dca8c 1443 sync_c0_entryhi(env, env->current_tc);
f1aa6320
TS
1444 }
1445 /* If the ASID changes, flush qemu's TLB. */
6ec98bd7
PB
1446 if ((old & env->CP0_EntryHi_ASID_mask) !=
1447 (val & env->CP0_EntryHi_ASID_mask)) {
9658e4c3 1448 tlb_flush(CPU(mips_env_get_cpu(env)));
6ec98bd7 1449 }
f1aa6320
TS
1450}
1451
895c2d04 1452void helper_mttc0_entryhi(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1453{
1454 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1455 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1456
fe8dca8c
EI
1457 other->CP0_EntryHi = arg1;
1458 sync_c0_entryhi(other, other_tc);
f1aa6320
TS
1459}
1460
895c2d04 1461void helper_mtc0_compare(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1462{
d394698d 1463 qemu_mutex_lock_iothread();
d9bea114 1464 cpu_mips_store_compare(env, arg1);
d394698d 1465 qemu_mutex_unlock_iothread();
f1aa6320
TS
1466}
1467
895c2d04 1468void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1469{
a47dddd7 1470 MIPSCPU *cpu = mips_env_get_cpu(env);
f1aa6320 1471 uint32_t val, old;
ba801af4 1472
f1aa6320 1473 old = env->CP0_Status;
81a423e6
MR
1474 cpu_mips_store_status(env, arg1);
1475 val = env->CP0_Status;
fe8dca8c 1476
c01fccd2
AJ
1477 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1478 qemu_log("Status %08x (%08x) => %08x (%08x) Cause %08x",
1479 old, old & env->CP0_Cause & CP0Ca_IP_mask,
1480 val, val & env->CP0_Cause & CP0Ca_IP_mask,
1481 env->CP0_Cause);
b0fc6003 1482 switch (cpu_mmu_index(env, false)) {
42c86612
JH
1483 case 3:
1484 qemu_log(", ERL\n");
1485 break;
c01fccd2
AJ
1486 case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
1487 case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
1488 case MIPS_HFLAG_KM: qemu_log("\n"); break;
a47dddd7
AF
1489 default:
1490 cpu_abort(CPU(cpu), "Invalid MMU mode!\n");
1491 break;
31e3104f 1492 }
c01fccd2 1493 }
f1aa6320
TS
1494}
1495
895c2d04 1496void helper_mttc0_status(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1497{
1498 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1d725ae9 1499 uint32_t mask = env->CP0_Status_rw_bitmask & ~0xf1000018;
895c2d04 1500 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1501
1d725ae9 1502 other->CP0_Status = (other->CP0_Status & ~mask) | (arg1 & mask);
895c2d04 1503 sync_c0_status(env, other, other_tc);
f1aa6320
TS
1504}
1505
895c2d04 1506void helper_mtc0_intctl(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1507{
bc45a67a 1508 env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000003e0) | (arg1 & 0x000003e0);
f1aa6320
TS
1509}
1510
895c2d04 1511void helper_mtc0_srsctl(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1512{
1513 uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
d9bea114 1514 env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask);
f1aa6320
TS
1515}
1516
895c2d04 1517void helper_mtc0_cause(CPUMIPSState *env, target_ulong arg1)
5a25ce94 1518{
d394698d 1519 qemu_mutex_lock_iothread();
81a423e6 1520 cpu_mips_store_cause(env, arg1);
d394698d 1521 qemu_mutex_unlock_iothread();
5a25ce94
EI
1522}
1523
895c2d04 1524void helper_mttc0_cause(CPUMIPSState *env, target_ulong arg1)
5a25ce94
EI
1525{
1526 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1527 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
5a25ce94 1528
81a423e6 1529 cpu_mips_store_cause(other, arg1);
5a25ce94
EI
1530}
1531
895c2d04 1532target_ulong helper_mftc0_epc(CPUMIPSState *env)
5a25ce94
EI
1533{
1534 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1535 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
5a25ce94
EI
1536
1537 return other->CP0_EPC;
1538}
1539
895c2d04 1540target_ulong helper_mftc0_ebase(CPUMIPSState *env)
5a25ce94
EI
1541{
1542 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1543 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
5a25ce94
EI
1544
1545 return other->CP0_EBase;
1546}
1547
895c2d04 1548void helper_mtc0_ebase(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1549{
74dbf824
JH
1550 target_ulong mask = 0x3FFFF000 | env->CP0_EBaseWG_rw_bitmask;
1551 if (arg1 & env->CP0_EBaseWG_rw_bitmask) {
1552 mask |= ~0x3FFFFFFF;
1553 }
1554 env->CP0_EBase = (env->CP0_EBase & ~mask) | (arg1 & mask);
f1aa6320
TS
1555}
1556
895c2d04 1557void helper_mttc0_ebase(CPUMIPSState *env, target_ulong arg1)
5a25ce94
EI
1558{
1559 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1560 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
74dbf824
JH
1561 target_ulong mask = 0x3FFFF000 | env->CP0_EBaseWG_rw_bitmask;
1562 if (arg1 & env->CP0_EBaseWG_rw_bitmask) {
1563 mask |= ~0x3FFFFFFF;
1564 }
1565 other->CP0_EBase = (other->CP0_EBase & ~mask) | (arg1 & mask);
5a25ce94
EI
1566}
1567
895c2d04 1568target_ulong helper_mftc0_configx(CPUMIPSState *env, target_ulong idx)
5a25ce94
EI
1569{
1570 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1571 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
5a25ce94
EI
1572
1573 switch (idx) {
1574 case 0: return other->CP0_Config0;
1575 case 1: return other->CP0_Config1;
1576 case 2: return other->CP0_Config2;
1577 case 3: return other->CP0_Config3;
1578 /* 4 and 5 are reserved. */
1579 case 6: return other->CP0_Config6;
1580 case 7: return other->CP0_Config7;
1581 default:
1582 break;
1583 }
1584 return 0;
1585}
1586
895c2d04 1587void helper_mtc0_config0(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1588{
d9bea114 1589 env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007);
f1aa6320
TS
1590}
1591
895c2d04 1592void helper_mtc0_config2(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1593{
1594 /* tertiary/secondary caches not implemented */
1595 env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
1596}
1597
90f12d73
MR
1598void helper_mtc0_config3(CPUMIPSState *env, target_ulong arg1)
1599{
1600 if (env->insn_flags & ASE_MICROMIPS) {
1601 env->CP0_Config3 = (env->CP0_Config3 & ~(1 << CP0C3_ISA_ON_EXC)) |
1602 (arg1 & (1 << CP0C3_ISA_ON_EXC));
1603 }
1604}
1605
b4160af1
PJ
1606void helper_mtc0_config4(CPUMIPSState *env, target_ulong arg1)
1607{
1608 env->CP0_Config4 = (env->CP0_Config4 & (~env->CP0_Config4_rw_bitmask)) |
1609 (arg1 & env->CP0_Config4_rw_bitmask);
1610}
1611
b4dd99a3
PJ
1612void helper_mtc0_config5(CPUMIPSState *env, target_ulong arg1)
1613{
1614 env->CP0_Config5 = (env->CP0_Config5 & (~env->CP0_Config5_rw_bitmask)) |
1615 (arg1 & env->CP0_Config5_rw_bitmask);
e97a391d 1616 compute_hflags(env);
b4dd99a3
PJ
1617}
1618
895c2d04 1619void helper_mtc0_lladdr(CPUMIPSState *env, target_ulong arg1)
2a6e32dd
AJ
1620{
1621 target_long mask = env->CP0_LLAddr_rw_bitmask;
1622 arg1 = arg1 << env->CP0_LLAddr_shift;
1623 env->lladdr = (env->lladdr & ~mask) | (arg1 & mask);
1624}
1625
f6d4dd81
YK
1626#define MTC0_MAAR_MASK(env) \
1627 ((0x1ULL << 63) | ((env->PAMask >> 4) & ~0xFFFull) | 0x3)
1628
1629void helper_mtc0_maar(CPUMIPSState *env, target_ulong arg1)
1630{
1631 env->CP0_MAAR[env->CP0_MAARI] = arg1 & MTC0_MAAR_MASK(env);
1632}
1633
1634void helper_mthc0_maar(CPUMIPSState *env, target_ulong arg1)
1635{
1636 env->CP0_MAAR[env->CP0_MAARI] =
1637 (((uint64_t) arg1 << 32) & MTC0_MAAR_MASK(env)) |
1638 (env->CP0_MAAR[env->CP0_MAARI] & 0x00000000ffffffffULL);
1639}
1640
1641void helper_mtc0_maari(CPUMIPSState *env, target_ulong arg1)
1642{
1643 int index = arg1 & 0x3f;
1644 if (index == 0x3f) {
1645 /* Software may write all ones to INDEX to determine the
1646 maximum value supported. */
1647 env->CP0_MAARI = MIPS_MAAR_MAX - 1;
1648 } else if (index < MIPS_MAAR_MAX) {
1649 env->CP0_MAARI = index;
1650 }
1651 /* Other than the all ones, if the
1652 value written is not supported, then INDEX is unchanged
1653 from its previous value. */
1654}
1655
895c2d04 1656void helper_mtc0_watchlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
f1aa6320
TS
1657{
1658 /* Watch exceptions for instructions, data loads, data stores
1659 not implemented. */
d9bea114 1660 env->CP0_WatchLo[sel] = (arg1 & ~0x7);
f1aa6320
TS
1661}
1662
895c2d04 1663void helper_mtc0_watchhi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
f1aa6320 1664{
6ec98bd7
PB
1665 int mask = 0x40000FF8 | (env->CP0_EntryHi_ASID_mask << CP0WH_ASID);
1666 env->CP0_WatchHi[sel] = arg1 & mask;
d9bea114 1667 env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7);
f1aa6320
TS
1668}
1669
895c2d04 1670void helper_mtc0_xcontext(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1671{
1672 target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
d9bea114 1673 env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask);
f1aa6320
TS
1674}
1675
895c2d04 1676void helper_mtc0_framemask(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1677{
d9bea114 1678 env->CP0_Framemask = arg1; /* XXX */
f1aa6320
TS
1679}
1680
895c2d04 1681void helper_mtc0_debug(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1682{
d9bea114
AJ
1683 env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120);
1684 if (arg1 & (1 << CP0DB_DM))
f1aa6320
TS
1685 env->hflags |= MIPS_HFLAG_DM;
1686 else
1687 env->hflags &= ~MIPS_HFLAG_DM;
1688}
1689
895c2d04 1690void helper_mttc0_debug(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1691{
1692 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
d9bea114 1693 uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
895c2d04 1694 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320
TS
1695
1696 /* XXX: Might be wrong, check with EJTAG spec. */
b93bbdcd
EI
1697 if (other_tc == other->current_tc)
1698 other->active_tc.CP0_Debug_tcstatus = val;
b5dc7732 1699 else
b93bbdcd
EI
1700 other->tcs[other_tc].CP0_Debug_tcstatus = val;
1701 other->CP0_Debug = (other->CP0_Debug &
1702 ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
d9bea114 1703 (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
f1aa6320
TS
1704}
1705
895c2d04 1706void helper_mtc0_performance0(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1707{
d9bea114 1708 env->CP0_Performance0 = arg1 & 0x000007ff;
f1aa6320
TS
1709}
1710
0d74a222
LA
1711void helper_mtc0_errctl(CPUMIPSState *env, target_ulong arg1)
1712{
1713 int32_t wst = arg1 & (1 << CP0EC_WST);
1714 int32_t spr = arg1 & (1 << CP0EC_SPR);
1715 int32_t itc = env->itc_tag ? (arg1 & (1 << CP0EC_ITC)) : 0;
1716
1717 env->CP0_ErrCtl = wst | spr | itc;
1718
1719 if (itc && !wst && !spr) {
1720 env->hflags |= MIPS_HFLAG_ITC_CACHE;
1721 } else {
1722 env->hflags &= ~MIPS_HFLAG_ITC_CACHE;
1723 }
1724}
1725
895c2d04 1726void helper_mtc0_taglo(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1727{
0d74a222
LA
1728 if (env->hflags & MIPS_HFLAG_ITC_CACHE) {
1729 /* If CACHE instruction is configured for ITC tags then make all
1730 CP0.TagLo bits writable. The actual write to ITC Configuration
1731 Tag will take care of the read-only bits. */
1732 env->CP0_TagLo = arg1;
1733 } else {
1734 env->CP0_TagLo = arg1 & 0xFFFFFCF6;
1735 }
f1aa6320
TS
1736}
1737
895c2d04 1738void helper_mtc0_datalo(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1739{
d9bea114 1740 env->CP0_DataLo = arg1; /* XXX */
f1aa6320
TS
1741}
1742
895c2d04 1743void helper_mtc0_taghi(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1744{
d9bea114 1745 env->CP0_TagHi = arg1; /* XXX */
f1aa6320
TS
1746}
1747
895c2d04 1748void helper_mtc0_datahi(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1749{
d9bea114 1750 env->CP0_DataHi = arg1; /* XXX */
f1aa6320
TS
1751}
1752
f1aa6320 1753/* MIPS MT functions */
895c2d04 1754target_ulong helper_mftgpr(CPUMIPSState *env, uint32_t sel)
f1aa6320
TS
1755{
1756 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1757 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1758
b93bbdcd
EI
1759 if (other_tc == other->current_tc)
1760 return other->active_tc.gpr[sel];
b5dc7732 1761 else
b93bbdcd 1762 return other->tcs[other_tc].gpr[sel];
f1aa6320
TS
1763}
1764
895c2d04 1765target_ulong helper_mftlo(CPUMIPSState *env, uint32_t sel)
f1aa6320
TS
1766{
1767 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1768 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1769
b93bbdcd
EI
1770 if (other_tc == other->current_tc)
1771 return other->active_tc.LO[sel];
b5dc7732 1772 else
b93bbdcd 1773 return other->tcs[other_tc].LO[sel];
f1aa6320
TS
1774}
1775
895c2d04 1776target_ulong helper_mfthi(CPUMIPSState *env, uint32_t sel)
f1aa6320
TS
1777{
1778 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1779 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1780
b93bbdcd
EI
1781 if (other_tc == other->current_tc)
1782 return other->active_tc.HI[sel];
b5dc7732 1783 else
b93bbdcd 1784 return other->tcs[other_tc].HI[sel];
f1aa6320
TS
1785}
1786
895c2d04 1787target_ulong helper_mftacx(CPUMIPSState *env, uint32_t sel)
f1aa6320
TS
1788{
1789 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1790 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1791
b93bbdcd
EI
1792 if (other_tc == other->current_tc)
1793 return other->active_tc.ACX[sel];
b5dc7732 1794 else
b93bbdcd 1795 return other->tcs[other_tc].ACX[sel];
f1aa6320
TS
1796}
1797
895c2d04 1798target_ulong helper_mftdsp(CPUMIPSState *env)
f1aa6320
TS
1799{
1800 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1801 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1802
b93bbdcd
EI
1803 if (other_tc == other->current_tc)
1804 return other->active_tc.DSPControl;
b5dc7732 1805 else
b93bbdcd 1806 return other->tcs[other_tc].DSPControl;
f1aa6320 1807}
6af0bf9c 1808
895c2d04 1809void helper_mttgpr(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
f1aa6320
TS
1810{
1811 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1812 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1813
b93bbdcd
EI
1814 if (other_tc == other->current_tc)
1815 other->active_tc.gpr[sel] = arg1;
b5dc7732 1816 else
b93bbdcd 1817 other->tcs[other_tc].gpr[sel] = arg1;
f1aa6320
TS
1818}
1819
895c2d04 1820void helper_mttlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
f1aa6320
TS
1821{
1822 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1823 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1824
b93bbdcd
EI
1825 if (other_tc == other->current_tc)
1826 other->active_tc.LO[sel] = arg1;
b5dc7732 1827 else
b93bbdcd 1828 other->tcs[other_tc].LO[sel] = arg1;
f1aa6320
TS
1829}
1830
895c2d04 1831void helper_mtthi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
f1aa6320
TS
1832{
1833 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1834 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1835
b93bbdcd
EI
1836 if (other_tc == other->current_tc)
1837 other->active_tc.HI[sel] = arg1;
b5dc7732 1838 else
b93bbdcd 1839 other->tcs[other_tc].HI[sel] = arg1;
f1aa6320
TS
1840}
1841
895c2d04 1842void helper_mttacx(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
f1aa6320
TS
1843{
1844 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1845 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1846
b93bbdcd
EI
1847 if (other_tc == other->current_tc)
1848 other->active_tc.ACX[sel] = arg1;
b5dc7732 1849 else
b93bbdcd 1850 other->tcs[other_tc].ACX[sel] = arg1;
f1aa6320
TS
1851}
1852
895c2d04 1853void helper_mttdsp(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1854{
1855 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1856 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1857
b93bbdcd
EI
1858 if (other_tc == other->current_tc)
1859 other->active_tc.DSPControl = arg1;
b5dc7732 1860 else
b93bbdcd 1861 other->tcs[other_tc].DSPControl = arg1;
f1aa6320
TS
1862}
1863
1864/* MIPS MT functions */
9ed5726c 1865target_ulong helper_dmt(void)
f1aa6320
TS
1866{
1867 // TODO
9ed5726c 1868 return 0;
f1aa6320
TS
1869}
1870
9ed5726c 1871target_ulong helper_emt(void)
f1aa6320
TS
1872{
1873 // TODO
9ed5726c 1874 return 0;
f1aa6320
TS
1875}
1876
895c2d04 1877target_ulong helper_dvpe(CPUMIPSState *env)
f1aa6320 1878{
182735ef 1879 CPUState *other_cs = first_cpu;
f249412c
EI
1880 target_ulong prev = env->mvp->CP0_MVPControl;
1881
bdc44640 1882 CPU_FOREACH(other_cs) {
182735ef 1883 MIPSCPU *other_cpu = MIPS_CPU(other_cs);
f249412c 1884 /* Turn off all VPEs except the one executing the dvpe. */
182735ef
AF
1885 if (&other_cpu->env != env) {
1886 other_cpu->env.mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP);
6f4d6b09 1887 mips_vpe_sleep(other_cpu);
f249412c 1888 }
bdc44640 1889 }
f249412c 1890 return prev;
f1aa6320
TS
1891}
1892
895c2d04 1893target_ulong helper_evpe(CPUMIPSState *env)
f1aa6320 1894{
182735ef 1895 CPUState *other_cs = first_cpu;
f249412c
EI
1896 target_ulong prev = env->mvp->CP0_MVPControl;
1897
bdc44640 1898 CPU_FOREACH(other_cs) {
182735ef 1899 MIPSCPU *other_cpu = MIPS_CPU(other_cs);
b35d77d7 1900
182735ef 1901 if (&other_cpu->env != env
81bad50e 1902 /* If the VPE is WFI, don't disturb its sleep. */
b35d77d7 1903 && !mips_vpe_is_wfi(other_cpu)) {
f249412c 1904 /* Enable the VPE. */
182735ef 1905 other_cpu->env.mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
c3affe56 1906 mips_vpe_wake(other_cpu); /* And wake it up. */
f249412c 1907 }
bdc44640 1908 }
f249412c 1909 return prev;
f1aa6320 1910}
f9480ffc 1911#endif /* !CONFIG_USER_ONLY */
f1aa6320 1912
d9bea114 1913void helper_fork(target_ulong arg1, target_ulong arg2)
f1aa6320 1914{
d9bea114 1915 // arg1 = rt, arg2 = rs
f1aa6320
TS
1916 // TODO: store to TC register
1917}
1918
895c2d04 1919target_ulong helper_yield(CPUMIPSState *env, target_ulong arg)
f1aa6320 1920{
1c7242da
BS
1921 target_long arg1 = arg;
1922
d9bea114 1923 if (arg1 < 0) {
f1aa6320 1924 /* No scheduling policy implemented. */
d9bea114 1925 if (arg1 != -2) {
f1aa6320 1926 if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
b5dc7732 1927 env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
f1aa6320
TS
1928 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1929 env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
9c708c7f 1930 do_raise_exception(env, EXCP_THREAD, GETPC());
f1aa6320
TS
1931 }
1932 }
d9bea114 1933 } else if (arg1 == 0) {
6958549d 1934 if (0 /* TODO: TC underflow */) {
f1aa6320 1935 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
9c708c7f 1936 do_raise_exception(env, EXCP_THREAD, GETPC());
f1aa6320
TS
1937 } else {
1938 // TODO: Deallocate TC
1939 }
d9bea114 1940 } else if (arg1 > 0) {
f1aa6320
TS
1941 /* Yield qualifier inputs not implemented. */
1942 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1943 env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
9c708c7f 1944 do_raise_exception(env, EXCP_THREAD, GETPC());
f1aa6320 1945 }
be24bb4f 1946 return env->CP0_YQMask;
f1aa6320
TS
1947}
1948
01bc435b
YK
1949/* R6 Multi-threading */
1950#ifndef CONFIG_USER_ONLY
1951target_ulong helper_dvp(CPUMIPSState *env)
1952{
1953 CPUState *other_cs = first_cpu;
1954 target_ulong prev = env->CP0_VPControl;
1955
1956 if (!((env->CP0_VPControl >> CP0VPCtl_DIS) & 1)) {
1957 CPU_FOREACH(other_cs) {
1958 MIPSCPU *other_cpu = MIPS_CPU(other_cs);
1959 /* Turn off all VPs except the one executing the dvp. */
1960 if (&other_cpu->env != env) {
1961 mips_vpe_sleep(other_cpu);
1962 }
1963 }
1964 env->CP0_VPControl |= (1 << CP0VPCtl_DIS);
1965 }
1966 return prev;
1967}
1968
1969target_ulong helper_evp(CPUMIPSState *env)
1970{
1971 CPUState *other_cs = first_cpu;
1972 target_ulong prev = env->CP0_VPControl;
1973
1974 if ((env->CP0_VPControl >> CP0VPCtl_DIS) & 1) {
1975 CPU_FOREACH(other_cs) {
1976 MIPSCPU *other_cpu = MIPS_CPU(other_cs);
1977 if ((&other_cpu->env != env) && !mips_vp_is_wfi(other_cpu)) {
1978 /* If the VP is WFI, don't disturb its sleep.
1979 * Otherwise, wake it up. */
1980 mips_vpe_wake(other_cpu);
1981 }
1982 }
1983 env->CP0_VPControl &= ~(1 << CP0VPCtl_DIS);
1984 }
1985 return prev;
1986}
1987#endif /* !CONFIG_USER_ONLY */
1988
f1aa6320 1989#ifndef CONFIG_USER_ONLY
6af0bf9c 1990/* TLB management */
7db13fae 1991static void r4k_mips_tlb_flush_extra (CPUMIPSState *env, int first)
814b9a47
TS
1992{
1993 /* Discard entries from env->tlb[first] onwards. */
ead9360e
TS
1994 while (env->tlb->tlb_in_use > first) {
1995 r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
814b9a47
TS
1996 }
1997}
1998
cd0d45c4
LA
1999static inline uint64_t get_tlb_pfn_from_entrylo(uint64_t entrylo)
2000{
2001#if defined(TARGET_MIPS64)
2002 return extract64(entrylo, 6, 54);
2003#else
2004 return extract64(entrylo, 6, 24) | /* PFN */
2005 (extract64(entrylo, 32, 32) << 24); /* PFNX */
2006#endif
2007}
2008
895c2d04 2009static void r4k_fill_tlb(CPUMIPSState *env, int idx)
6af0bf9c 2010{
c227f099 2011 r4k_tlb_t *tlb;
2d1847ec 2012 uint64_t mask = env->CP0_PageMask >> (TARGET_PAGE_BITS + 1);
6af0bf9c
FB
2013
2014 /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
ead9360e 2015 tlb = &env->tlb->mmu.r4k.tlb[idx];
9456c2fb
LA
2016 if (env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) {
2017 tlb->EHINV = 1;
2018 return;
2019 }
2020 tlb->EHINV = 0;
f2e9ebef 2021 tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
d26bc211 2022#if defined(TARGET_MIPS64)
e034e2c3 2023 tlb->VPN &= env->SEGMask;
100ce988 2024#endif
6ec98bd7 2025 tlb->ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
3b1c8be4 2026 tlb->PageMask = env->CP0_PageMask;
6af0bf9c 2027 tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
98c1b82b
PB
2028 tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
2029 tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
2030 tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
2fb58b73
LA
2031 tlb->XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) & 1;
2032 tlb->RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) & 1;
2d1847ec 2033 tlb->PFN[0] = (get_tlb_pfn_from_entrylo(env->CP0_EntryLo0) & ~mask) << 12;
98c1b82b
PB
2034 tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
2035 tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
2036 tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
2fb58b73
LA
2037 tlb->XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) & 1;
2038 tlb->RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) & 1;
2d1847ec 2039 tlb->PFN[1] = (get_tlb_pfn_from_entrylo(env->CP0_EntryLo1) & ~mask) << 12;
6af0bf9c
FB
2040}
2041
9456c2fb
LA
2042void r4k_helper_tlbinv(CPUMIPSState *env)
2043{
2044 int idx;
2045 r4k_tlb_t *tlb;
2d72e7b0 2046 uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
9456c2fb
LA
2047
2048 for (idx = 0; idx < env->tlb->nb_tlb; idx++) {
2049 tlb = &env->tlb->mmu.r4k.tlb[idx];
2050 if (!tlb->G && tlb->ASID == ASID) {
2051 tlb->EHINV = 1;
2052 }
2053 }
d10eb08f 2054 cpu_mips_tlb_flush(env);
9456c2fb
LA
2055}
2056
2057void r4k_helper_tlbinvf(CPUMIPSState *env)
2058{
2059 int idx;
2060
2061 for (idx = 0; idx < env->tlb->nb_tlb; idx++) {
2062 env->tlb->mmu.r4k.tlb[idx].EHINV = 1;
2063 }
d10eb08f 2064 cpu_mips_tlb_flush(env);
9456c2fb
LA
2065}
2066
895c2d04 2067void r4k_helper_tlbwi(CPUMIPSState *env)
6af0bf9c 2068{
286d52eb 2069 r4k_tlb_t *tlb;
bbc0d79c 2070 int idx;
286d52eb 2071 target_ulong VPN;
2d72e7b0 2072 uint16_t ASID;
eff6ff94 2073 bool EHINV, G, V0, D0, V1, D1, XI0, XI1, RI0, RI1;
bbc0d79c
AJ
2074
2075 idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
286d52eb
AJ
2076 tlb = &env->tlb->mmu.r4k.tlb[idx];
2077 VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
2078#if defined(TARGET_MIPS64)
2079 VPN &= env->SEGMask;
2080#endif
6ec98bd7 2081 ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
eff6ff94 2082 EHINV = (env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) != 0;
286d52eb
AJ
2083 G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
2084 V0 = (env->CP0_EntryLo0 & 2) != 0;
2085 D0 = (env->CP0_EntryLo0 & 4) != 0;
eff6ff94
JH
2086 XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) &1;
2087 RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) &1;
286d52eb
AJ
2088 V1 = (env->CP0_EntryLo1 & 2) != 0;
2089 D1 = (env->CP0_EntryLo1 & 4) != 0;
eff6ff94
JH
2090 XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) &1;
2091 RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) &1;
286d52eb
AJ
2092
2093 /* Discard cached TLB entries, unless tlbwi is just upgrading access
2094 permissions on the current entry. */
2095 if (tlb->VPN != VPN || tlb->ASID != ASID || tlb->G != G ||
eff6ff94 2096 (!tlb->EHINV && EHINV) ||
286d52eb 2097 (tlb->V0 && !V0) || (tlb->D0 && !D0) ||
eff6ff94
JH
2098 (!tlb->XI0 && XI0) || (!tlb->RI0 && RI0) ||
2099 (tlb->V1 && !V1) || (tlb->D1 && !D1) ||
2100 (!tlb->XI1 && XI1) || (!tlb->RI1 && RI1)) {
286d52eb
AJ
2101 r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
2102 }
814b9a47 2103
bbc0d79c 2104 r4k_invalidate_tlb(env, idx, 0);
895c2d04 2105 r4k_fill_tlb(env, idx);
6af0bf9c
FB
2106}
2107
895c2d04 2108void r4k_helper_tlbwr(CPUMIPSState *env)
6af0bf9c
FB
2109{
2110 int r = cpu_mips_get_random(env);
2111
29929e34 2112 r4k_invalidate_tlb(env, r, 1);
895c2d04 2113 r4k_fill_tlb(env, r);
6af0bf9c
FB
2114}
2115
895c2d04 2116void r4k_helper_tlbp(CPUMIPSState *env)
6af0bf9c 2117{
c227f099 2118 r4k_tlb_t *tlb;
f2e9ebef 2119 target_ulong mask;
6af0bf9c 2120 target_ulong tag;
f2e9ebef 2121 target_ulong VPN;
2d72e7b0 2122 uint16_t ASID;
6af0bf9c
FB
2123 int i;
2124
6ec98bd7 2125 ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
ead9360e
TS
2126 for (i = 0; i < env->tlb->nb_tlb; i++) {
2127 tlb = &env->tlb->mmu.r4k.tlb[i];
f2e9ebef
TS
2128 /* 1k pages are not supported. */
2129 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
2130 tag = env->CP0_EntryHi & ~mask;
2131 VPN = tlb->VPN & ~mask;
bc3e45e1
AJ
2132#if defined(TARGET_MIPS64)
2133 tag &= env->SEGMask;
2134#endif
6af0bf9c 2135 /* Check ASID, virtual page number & size */
9456c2fb 2136 if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag && !tlb->EHINV) {
6af0bf9c 2137 /* TLB match */
9c2149c8 2138 env->CP0_Index = i;
6af0bf9c
FB
2139 break;
2140 }
2141 }
ead9360e 2142 if (i == env->tlb->nb_tlb) {
814b9a47 2143 /* No match. Discard any shadow entries, if any of them match. */
ead9360e 2144 for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
6958549d
AJ
2145 tlb = &env->tlb->mmu.r4k.tlb[i];
2146 /* 1k pages are not supported. */
2147 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
2148 tag = env->CP0_EntryHi & ~mask;
2149 VPN = tlb->VPN & ~mask;
bc3e45e1
AJ
2150#if defined(TARGET_MIPS64)
2151 tag &= env->SEGMask;
2152#endif
6958549d
AJ
2153 /* Check ASID, virtual page number & size */
2154 if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
29929e34 2155 r4k_mips_tlb_flush_extra (env, i);
6958549d
AJ
2156 break;
2157 }
2158 }
814b9a47 2159
9c2149c8 2160 env->CP0_Index |= 0x80000000;
6af0bf9c
FB
2161 }
2162}
2163
cd0d45c4
LA
2164static inline uint64_t get_entrylo_pfn_from_tlb(uint64_t tlb_pfn)
2165{
2166#if defined(TARGET_MIPS64)
2167 return tlb_pfn << 6;
2168#else
2169 return (extract64(tlb_pfn, 0, 24) << 6) | /* PFN */
2170 (extract64(tlb_pfn, 24, 32) << 32); /* PFNX */
2171#endif
2172}
2173
895c2d04 2174void r4k_helper_tlbr(CPUMIPSState *env)
6af0bf9c 2175{
c227f099 2176 r4k_tlb_t *tlb;
2d72e7b0 2177 uint16_t ASID;
bbc0d79c 2178 int idx;
6af0bf9c 2179
6ec98bd7 2180 ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
bbc0d79c
AJ
2181 idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
2182 tlb = &env->tlb->mmu.r4k.tlb[idx];
4ad40f36
FB
2183
2184 /* If this will change the current ASID, flush qemu's TLB. */
814b9a47 2185 if (ASID != tlb->ASID)
d10eb08f 2186 cpu_mips_tlb_flush(env);
814b9a47 2187
ead9360e 2188 r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
4ad40f36 2189
9456c2fb
LA
2190 if (tlb->EHINV) {
2191 env->CP0_EntryHi = 1 << CP0EnHi_EHINV;
2192 env->CP0_PageMask = 0;
2193 env->CP0_EntryLo0 = 0;
2194 env->CP0_EntryLo1 = 0;
2195 } else {
2196 env->CP0_EntryHi = tlb->VPN | tlb->ASID;
2197 env->CP0_PageMask = tlb->PageMask;
2198 env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
284b731a 2199 ((uint64_t)tlb->RI0 << CP0EnLo_RI) |
cd0d45c4
LA
2200 ((uint64_t)tlb->XI0 << CP0EnLo_XI) | (tlb->C0 << 3) |
2201 get_entrylo_pfn_from_tlb(tlb->PFN[0] >> 12);
9456c2fb 2202 env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
284b731a 2203 ((uint64_t)tlb->RI1 << CP0EnLo_RI) |
cd0d45c4
LA
2204 ((uint64_t)tlb->XI1 << CP0EnLo_XI) | (tlb->C1 << 3) |
2205 get_entrylo_pfn_from_tlb(tlb->PFN[1] >> 12);
9456c2fb 2206 }
6af0bf9c 2207}
6af0bf9c 2208
895c2d04 2209void helper_tlbwi(CPUMIPSState *env)
a7812ae4 2210{
895c2d04 2211 env->tlb->helper_tlbwi(env);
a7812ae4
PB
2212}
2213
895c2d04 2214void helper_tlbwr(CPUMIPSState *env)
a7812ae4 2215{
895c2d04 2216 env->tlb->helper_tlbwr(env);
a7812ae4
PB
2217}
2218
895c2d04 2219void helper_tlbp(CPUMIPSState *env)
a7812ae4 2220{
895c2d04 2221 env->tlb->helper_tlbp(env);
a7812ae4
PB
2222}
2223
895c2d04 2224void helper_tlbr(CPUMIPSState *env)
a7812ae4 2225{
895c2d04 2226 env->tlb->helper_tlbr(env);
a7812ae4
PB
2227}
2228
9456c2fb
LA
2229void helper_tlbinv(CPUMIPSState *env)
2230{
2231 env->tlb->helper_tlbinv(env);
2232}
2233
2234void helper_tlbinvf(CPUMIPSState *env)
2235{
2236 env->tlb->helper_tlbinvf(env);
2237}
2238
2b0233ab 2239/* Specials */
895c2d04 2240target_ulong helper_di(CPUMIPSState *env)
2b0233ab 2241{
2796188e
TS
2242 target_ulong t0 = env->CP0_Status;
2243
be24bb4f 2244 env->CP0_Status = t0 & ~(1 << CP0St_IE);
be24bb4f 2245 return t0;
2b0233ab
TS
2246}
2247
895c2d04 2248target_ulong helper_ei(CPUMIPSState *env)
2b0233ab 2249{
2796188e
TS
2250 target_ulong t0 = env->CP0_Status;
2251
be24bb4f 2252 env->CP0_Status = t0 | (1 << CP0St_IE);
be24bb4f 2253 return t0;
2b0233ab
TS
2254}
2255
895c2d04 2256static void debug_pre_eret(CPUMIPSState *env)
6af0bf9c 2257{
8fec2b8c 2258 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
93fcfe39
AL
2259 qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
2260 env->active_tc.PC, env->CP0_EPC);
2261 if (env->CP0_Status & (1 << CP0St_ERL))
2262 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
2263 if (env->hflags & MIPS_HFLAG_DM)
2264 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
2265 qemu_log("\n");
2266 }
f41c52f1
TS
2267}
2268
895c2d04 2269static void debug_post_eret(CPUMIPSState *env)
f41c52f1 2270{
a47dddd7
AF
2271 MIPSCPU *cpu = mips_env_get_cpu(env);
2272
8fec2b8c 2273 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
93fcfe39
AL
2274 qemu_log(" => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
2275 env->active_tc.PC, env->CP0_EPC);
2276 if (env->CP0_Status & (1 << CP0St_ERL))
2277 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
2278 if (env->hflags & MIPS_HFLAG_DM)
2279 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
b0fc6003 2280 switch (cpu_mmu_index(env, false)) {
42c86612
JH
2281 case 3:
2282 qemu_log(", ERL\n");
2283 break;
93fcfe39
AL
2284 case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
2285 case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
2286 case MIPS_HFLAG_KM: qemu_log("\n"); break;
a47dddd7
AF
2287 default:
2288 cpu_abort(CPU(cpu), "Invalid MMU mode!\n");
2289 break;
93fcfe39 2290 }
623a930e 2291 }
6af0bf9c
FB
2292}
2293
895c2d04 2294static void set_pc(CPUMIPSState *env, target_ulong error_pc)
32188a03
NF
2295{
2296 env->active_tc.PC = error_pc & ~(target_ulong)1;
2297 if (error_pc & 1) {
2298 env->hflags |= MIPS_HFLAG_M16;
2299 } else {
2300 env->hflags &= ~(MIPS_HFLAG_M16);
2301 }
2302}
2303
ce9782f4 2304static inline void exception_return(CPUMIPSState *env)
2b0233ab 2305{
895c2d04 2306 debug_pre_eret(env);
2b0233ab 2307 if (env->CP0_Status & (1 << CP0St_ERL)) {
895c2d04 2308 set_pc(env, env->CP0_ErrorEPC);
2b0233ab
TS
2309 env->CP0_Status &= ~(1 << CP0St_ERL);
2310 } else {
895c2d04 2311 set_pc(env, env->CP0_EPC);
2b0233ab
TS
2312 env->CP0_Status &= ~(1 << CP0St_EXL);
2313 }
2314 compute_hflags(env);
895c2d04 2315 debug_post_eret(env);
ce9782f4
LA
2316}
2317
2318void helper_eret(CPUMIPSState *env)
2319{
2320 exception_return(env);
5499b6ff 2321 env->lladdr = 1;
2b0233ab
TS
2322}
2323
ce9782f4
LA
2324void helper_eretnc(CPUMIPSState *env)
2325{
2326 exception_return(env);
2327}
2328
895c2d04 2329void helper_deret(CPUMIPSState *env)
2b0233ab 2330{
895c2d04
BS
2331 debug_pre_eret(env);
2332 set_pc(env, env->CP0_DEPC);
32188a03 2333
fe87c2b3 2334 env->hflags &= ~MIPS_HFLAG_DM;
2b0233ab 2335 compute_hflags(env);
895c2d04 2336 debug_post_eret(env);
2b0233ab 2337}
0eaef5aa 2338#endif /* !CONFIG_USER_ONLY */
2b0233ab 2339
d96391c1 2340static inline void check_hwrena(CPUMIPSState *env, int reg, uintptr_t pc)
2b0233ab 2341{
b00c7218
YK
2342 if ((env->hflags & MIPS_HFLAG_CP0) || (env->CP0_HWREna & (1 << reg))) {
2343 return;
2344 }
d96391c1 2345 do_raise_exception(env, EXCP_RI, pc);
b00c7218 2346}
be24bb4f 2347
b00c7218
YK
2348target_ulong helper_rdhwr_cpunum(CPUMIPSState *env)
2349{
d96391c1 2350 check_hwrena(env, 0, GETPC());
b00c7218 2351 return env->CP0_EBase & 0x3ff;
2b0233ab
TS
2352}
2353
895c2d04 2354target_ulong helper_rdhwr_synci_step(CPUMIPSState *env)
2b0233ab 2355{
d96391c1 2356 check_hwrena(env, 1, GETPC());
b00c7218 2357 return env->SYNCI_Step;
2b0233ab
TS
2358}
2359
895c2d04 2360target_ulong helper_rdhwr_cc(CPUMIPSState *env)
2b0233ab 2361{
d394698d 2362 int32_t count;
d96391c1 2363 check_hwrena(env, 2, GETPC());
cdfcad78 2364#ifdef CONFIG_USER_ONLY
d394698d 2365 count = env->CP0_Count;
cdfcad78 2366#else
d394698d
YK
2367 qemu_mutex_lock_iothread();
2368 count = (int32_t)cpu_mips_get_count(env);
2369 qemu_mutex_unlock_iothread();
cdfcad78 2370#endif
d394698d 2371 return count;
2b0233ab
TS
2372}
2373
895c2d04 2374target_ulong helper_rdhwr_ccres(CPUMIPSState *env)
2b0233ab 2375{
d96391c1 2376 check_hwrena(env, 3, GETPC());
b00c7218
YK
2377 return env->CCRes;
2378}
be24bb4f 2379
b00c7218
YK
2380target_ulong helper_rdhwr_performance(CPUMIPSState *env)
2381{
d96391c1 2382 check_hwrena(env, 4, GETPC());
b00c7218
YK
2383 return env->CP0_Performance0;
2384}
2385
2386target_ulong helper_rdhwr_xnp(CPUMIPSState *env)
2387{
d96391c1 2388 check_hwrena(env, 5, GETPC());
b00c7218 2389 return (env->CP0_Config5 >> CP0C5_XNP) & 1;
2b0233ab
TS
2390}
2391
895c2d04 2392void helper_pmon(CPUMIPSState *env, int function)
6af0bf9c
FB
2393{
2394 function /= 2;
2395 switch (function) {
2396 case 2: /* TODO: char inbyte(int waitflag); */
b5dc7732
TS
2397 if (env->active_tc.gpr[4] == 0)
2398 env->active_tc.gpr[2] = -1;
6af0bf9c
FB
2399 /* Fall through */
2400 case 11: /* TODO: char inbyte (void); */
b5dc7732 2401 env->active_tc.gpr[2] = -1;
6af0bf9c
FB
2402 break;
2403 case 3:
2404 case 12:
b5dc7732 2405 printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
6af0bf9c
FB
2406 break;
2407 case 17:
2408 break;
2409 case 158:
2410 {
b69e48a8 2411 unsigned char *fmt = (void *)(uintptr_t)env->active_tc.gpr[4];
6af0bf9c
FB
2412 printf("%s", fmt);
2413 }
2414 break;
2415 }
2416}
e37e863f 2417
895c2d04 2418void helper_wait(CPUMIPSState *env)
08ba7963 2419{
259186a7
AF
2420 CPUState *cs = CPU(mips_env_get_cpu(env));
2421
2422 cs->halted = 1;
d8ed887b 2423 cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
9c708c7f
PD
2424 /* Last instruction in the block, PC was updated before
2425 - no need to recover PC and icount */
2426 raise_exception(env, EXCP_HLT);
08ba7963
TS
2427}
2428
5fafdf24 2429#if !defined(CONFIG_USER_ONLY)
e37e863f 2430
93e22326 2431void mips_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
b35399bb
SS
2432 MMUAccessType access_type,
2433 int mmu_idx, uintptr_t retaddr)
4ad40f36 2434{
93e22326
PB
2435 MIPSCPU *cpu = MIPS_CPU(cs);
2436 CPUMIPSState *env = &cpu->env;
aea14095
LA
2437 int error_code = 0;
2438 int excp;
93e22326 2439
4ad40f36 2440 env->CP0_BadVAddr = addr;
aea14095
LA
2441
2442 if (access_type == MMU_DATA_STORE) {
2443 excp = EXCP_AdES;
2444 } else {
2445 excp = EXCP_AdEL;
2446 if (access_type == MMU_INST_FETCH) {
2447 error_code |= EXCP_INST_NOTAVAIL;
2448 }
2449 }
2450
2451 do_raise_exception_err(env, excp, error_code, retaddr);
4ad40f36
FB
2452}
2453
b35399bb
SS
2454void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type,
2455 int mmu_idx, uintptr_t retaddr)
e37e863f 2456{
e37e863f
FB
2457 int ret;
2458
b35399bb 2459 ret = mips_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx);
e37e863f 2460 if (ret) {
d5a11fef
AF
2461 MIPSCPU *cpu = MIPS_CPU(cs);
2462 CPUMIPSState *env = &cpu->env;
2463
27103424 2464 do_raise_exception_err(env, cs->exception_index,
5f7319cd 2465 env->error_code, retaddr);
e37e863f 2466 }
e37e863f
FB
2467}
2468
c658b94f
AF
2469void mips_cpu_unassigned_access(CPUState *cs, hwaddr addr,
2470 bool is_write, bool is_exec, int unused,
2471 unsigned size)
647de6ca 2472{
c658b94f
AF
2473 MIPSCPU *cpu = MIPS_CPU(cs);
2474 CPUMIPSState *env = &cpu->env;
2475
eddedd54
JH
2476 /*
2477 * Raising an exception with KVM enabled will crash because it won't be from
2478 * the main execution loop so the longjmp won't have a matching setjmp.
2479 * Until we can trigger a bus error exception through KVM lets just ignore
2480 * the access.
2481 */
2482 if (kvm_enabled()) {
2483 return;
2484 }
2485
c658b94f 2486 if (is_exec) {
9c708c7f 2487 raise_exception(env, EXCP_IBE);
c658b94f 2488 } else {
9c708c7f 2489 raise_exception(env, EXCP_DBE);
c658b94f 2490 }
647de6ca 2491}
f1aa6320 2492#endif /* !CONFIG_USER_ONLY */
fd4a04eb
TS
2493
2494/* Complex FPU operations which may need stack space. */
2495
f090c9d4
PB
2496#define FLOAT_TWO32 make_float32(1 << 30)
2497#define FLOAT_TWO64 make_float64(1ULL << 62)
87552089 2498
05993cd0
AJ
2499#define FP_TO_INT32_OVERFLOW 0x7fffffff
2500#define FP_TO_INT64_OVERFLOW 0x7fffffffffffffffULL
8dfdb87c 2501
fd4a04eb 2502/* convert MIPS rounding mode in FCR31 to IEEE library */
b7651e95 2503unsigned int ieee_rm[] = {
fd4a04eb
TS
2504 float_round_nearest_even,
2505 float_round_to_zero,
2506 float_round_up,
2507 float_round_down
2508};
2509
895c2d04 2510target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg)
fd4a04eb 2511{
736d120a 2512 target_ulong arg1 = 0;
6c5c1e20 2513
ead9360e
TS
2514 switch (reg) {
2515 case 0:
d9bea114 2516 arg1 = (int32_t)env->active_fpu.fcr0;
ead9360e 2517 break;
736d120a
PJ
2518 case 1:
2519 /* UFR Support - Read Status FR */
2520 if (env->active_fpu.fcr0 & (1 << FCR0_UFRP)) {
2521 if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
2522 arg1 = (int32_t)
2523 ((env->CP0_Status & (1 << CP0St_FR)) >> CP0St_FR);
2524 } else {
9c708c7f 2525 do_raise_exception(env, EXCP_RI, GETPC());
736d120a
PJ
2526 }
2527 }
2528 break;
7c979afd
LA
2529 case 5:
2530 /* FRE Support - read Config5.FRE bit */
2531 if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) {
2532 if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
2533 arg1 = (env->CP0_Config5 >> CP0C5_FRE) & 1;
2534 } else {
2535 helper_raise_exception(env, EXCP_RI);
2536 }
2537 }
2538 break;
ead9360e 2539 case 25:
d9bea114 2540 arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
ead9360e
TS
2541 break;
2542 case 26:
d9bea114 2543 arg1 = env->active_fpu.fcr31 & 0x0003f07c;
ead9360e
TS
2544 break;
2545 case 28:
d9bea114 2546 arg1 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4);
ead9360e
TS
2547 break;
2548 default:
d9bea114 2549 arg1 = (int32_t)env->active_fpu.fcr31;
ead9360e
TS
2550 break;
2551 }
be24bb4f 2552
d9bea114 2553 return arg1;
ead9360e
TS
2554}
2555
736d120a 2556void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt)
ead9360e 2557{
736d120a
PJ
2558 switch (fs) {
2559 case 1:
2560 /* UFR Alias - Reset Status FR */
2561 if (!((env->active_fpu.fcr0 & (1 << FCR0_UFRP)) && (rt == 0))) {
2562 return;
2563 }
2564 if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
2565 env->CP0_Status &= ~(1 << CP0St_FR);
2566 compute_hflags(env);
2567 } else {
9c708c7f 2568 do_raise_exception(env, EXCP_RI, GETPC());
736d120a
PJ
2569 }
2570 break;
2571 case 4:
2572 /* UNFR Alias - Set Status FR */
2573 if (!((env->active_fpu.fcr0 & (1 << FCR0_UFRP)) && (rt == 0))) {
2574 return;
2575 }
2576 if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
2577 env->CP0_Status |= (1 << CP0St_FR);
2578 compute_hflags(env);
2579 } else {
9c708c7f 2580 do_raise_exception(env, EXCP_RI, GETPC());
736d120a
PJ
2581 }
2582 break;
7c979afd
LA
2583 case 5:
2584 /* FRE Support - clear Config5.FRE bit */
2585 if (!((env->active_fpu.fcr0 & (1 << FCR0_FREP)) && (rt == 0))) {
2586 return;
2587 }
2588 if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
2589 env->CP0_Config5 &= ~(1 << CP0C5_FRE);
2590 compute_hflags(env);
2591 } else {
2592 helper_raise_exception(env, EXCP_RI);
2593 }
2594 break;
2595 case 6:
2596 /* FRE Support - set Config5.FRE bit */
2597 if (!((env->active_fpu.fcr0 & (1 << FCR0_FREP)) && (rt == 0))) {
2598 return;
2599 }
2600 if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
2601 env->CP0_Config5 |= (1 << CP0C5_FRE);
2602 compute_hflags(env);
2603 } else {
2604 helper_raise_exception(env, EXCP_RI);
2605 }
2606 break;
fd4a04eb 2607 case 25:
ba801af4 2608 if ((env->insn_flags & ISA_MIPS32R6) || (arg1 & 0xffffff00)) {
fd4a04eb 2609 return;
ba801af4 2610 }
d9bea114
AJ
2611 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
2612 ((arg1 & 0x1) << 23);
fd4a04eb
TS
2613 break;
2614 case 26:
d9bea114 2615 if (arg1 & 0x007c0000)
fd4a04eb 2616 return;
d9bea114 2617 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (arg1 & 0x0003f07c);
fd4a04eb
TS
2618 break;
2619 case 28:
d9bea114 2620 if (arg1 & 0x007c0000)
fd4a04eb 2621 return;
d9bea114
AJ
2622 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (arg1 & 0x00000f83) |
2623 ((arg1 & 0x4) << 22);
fd4a04eb
TS
2624 break;
2625 case 31:
599bc5e8
AM
2626 env->active_fpu.fcr31 = (arg1 & env->active_fpu.fcr31_rw_bitmask) |
2627 (env->active_fpu.fcr31 & ~(env->active_fpu.fcr31_rw_bitmask));
fd4a04eb
TS
2628 break;
2629 default:
2630 return;
2631 }
599bc5e8 2632 restore_fp_status(env);
f01be154
TS
2633 set_float_exception_flags(0, &env->active_fpu.fp_status);
2634 if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31))
5f7319cd 2635 do_raise_exception(env, EXCP_FPE, GETPC());
fd4a04eb
TS
2636}
2637
b7651e95 2638int ieee_ex_to_mips(int xcpt)
fd4a04eb 2639{
353ebb7a
AJ
2640 int ret = 0;
2641 if (xcpt) {
2642 if (xcpt & float_flag_invalid) {
2643 ret |= FP_INVALID;
2644 }
2645 if (xcpt & float_flag_overflow) {
2646 ret |= FP_OVERFLOW;
2647 }
2648 if (xcpt & float_flag_underflow) {
2649 ret |= FP_UNDERFLOW;
2650 }
2651 if (xcpt & float_flag_divbyzero) {
2652 ret |= FP_DIV0;
2653 }
2654 if (xcpt & float_flag_inexact) {
2655 ret |= FP_INEXACT;
2656 }
2657 }
2658 return ret;
fd4a04eb
TS
2659}
2660
5f7319cd 2661static inline void update_fcr31(CPUMIPSState *env, uintptr_t pc)
fd4a04eb 2662{
f01be154 2663 int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
fd4a04eb 2664
f01be154 2665 SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
4a587b2c
AJ
2666
2667 if (tmp) {
2668 set_float_exception_flags(0, &env->active_fpu.fp_status);
2669
2670 if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp) {
5f7319cd 2671 do_raise_exception(env, EXCP_FPE, pc);
4a587b2c
AJ
2672 } else {
2673 UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
2674 }
2675 }
fd4a04eb
TS
2676}
2677
a16336e4
TS
2678/* Float support.
2679 Single precition routines have a "s" suffix, double precision a
2680 "d" suffix, 32bit integer "w", 64bit integer "l", paired single "ps",
2681 paired single lower "pl", paired single upper "pu". */
2682
a16336e4 2683/* unary operations, modifying fp status */
895c2d04 2684uint64_t helper_float_sqrt_d(CPUMIPSState *env, uint64_t fdt0)
b6d96bed 2685{
5dbe90bb 2686 fdt0 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
5f7319cd 2687 update_fcr31(env, GETPC());
5dbe90bb 2688 return fdt0;
b6d96bed
TS
2689}
2690
895c2d04 2691uint32_t helper_float_sqrt_s(CPUMIPSState *env, uint32_t fst0)
b6d96bed 2692{
5dbe90bb 2693 fst0 = float32_sqrt(fst0, &env->active_fpu.fp_status);
5f7319cd 2694 update_fcr31(env, GETPC());
5dbe90bb 2695 return fst0;
b6d96bed 2696}
a16336e4 2697
895c2d04 2698uint64_t helper_float_cvtd_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2699{
b6d96bed
TS
2700 uint64_t fdt2;
2701
f01be154 2702 fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
af39bc8c 2703 fdt2 = float64_maybe_silence_nan(fdt2, &env->active_fpu.fp_status);
5f7319cd 2704 update_fcr31(env, GETPC());
b6d96bed 2705 return fdt2;
fd4a04eb 2706}
b6d96bed 2707
895c2d04 2708uint64_t helper_float_cvtd_w(CPUMIPSState *env, uint32_t wt0)
fd4a04eb 2709{
b6d96bed
TS
2710 uint64_t fdt2;
2711
f01be154 2712 fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
5f7319cd 2713 update_fcr31(env, GETPC());
b6d96bed 2714 return fdt2;
fd4a04eb 2715}
b6d96bed 2716
895c2d04 2717uint64_t helper_float_cvtd_l(CPUMIPSState *env, uint64_t dt0)
fd4a04eb 2718{
b6d96bed
TS
2719 uint64_t fdt2;
2720
f01be154 2721 fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
5f7319cd 2722 update_fcr31(env, GETPC());
b6d96bed 2723 return fdt2;
fd4a04eb 2724}
b6d96bed 2725
87552089 2726uint64_t helper_float_cvt_l_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2727{
b6d96bed
TS
2728 uint64_t dt2;
2729
f01be154 2730 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2731 if (get_float_exception_flags(&env->active_fpu.fp_status)
2732 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2733 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2734 }
5f7319cd 2735 update_fcr31(env, GETPC());
b6d96bed 2736 return dt2;
fd4a04eb 2737}
b6d96bed 2738
87552089 2739uint64_t helper_float_cvt_l_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2740{
b6d96bed
TS
2741 uint64_t dt2;
2742
f01be154 2743 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2744 if (get_float_exception_flags(&env->active_fpu.fp_status)
2745 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2746 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2747 }
5f7319cd 2748 update_fcr31(env, GETPC());
b6d96bed 2749 return dt2;
fd4a04eb
TS
2750}
2751
895c2d04 2752uint64_t helper_float_cvtps_pw(CPUMIPSState *env, uint64_t dt0)
fd4a04eb 2753{
b6d96bed
TS
2754 uint32_t fst2;
2755 uint32_t fsth2;
2756
f01be154
TS
2757 fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2758 fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status);
5f7319cd 2759 update_fcr31(env, GETPC());
b6d96bed 2760 return ((uint64_t)fsth2 << 32) | fst2;
fd4a04eb 2761}
b6d96bed 2762
895c2d04 2763uint64_t helper_float_cvtpw_ps(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2764{
b6d96bed
TS
2765 uint32_t wt2;
2766 uint32_t wth2;
5dbe90bb 2767 int excp, excph;
b6d96bed 2768
f01be154 2769 wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
5dbe90bb
AJ
2770 excp = get_float_exception_flags(&env->active_fpu.fp_status);
2771 if (excp & (float_flag_overflow | float_flag_invalid)) {
05993cd0 2772 wt2 = FP_TO_INT32_OVERFLOW;
5dbe90bb
AJ
2773 }
2774
2775 set_float_exception_flags(0, &env->active_fpu.fp_status);
2776 wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status);
2777 excph = get_float_exception_flags(&env->active_fpu.fp_status);
2778 if (excph & (float_flag_overflow | float_flag_invalid)) {
05993cd0 2779 wth2 = FP_TO_INT32_OVERFLOW;
b6d96bed 2780 }
5dbe90bb
AJ
2781
2782 set_float_exception_flags(excp | excph, &env->active_fpu.fp_status);
5f7319cd 2783 update_fcr31(env, GETPC());
5dbe90bb 2784
b6d96bed 2785 return ((uint64_t)wth2 << 32) | wt2;
fd4a04eb 2786}
b6d96bed 2787
895c2d04 2788uint32_t helper_float_cvts_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2789{
b6d96bed
TS
2790 uint32_t fst2;
2791
f01be154 2792 fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
af39bc8c 2793 fst2 = float32_maybe_silence_nan(fst2, &env->active_fpu.fp_status);
5f7319cd 2794 update_fcr31(env, GETPC());
b6d96bed 2795 return fst2;
fd4a04eb 2796}
b6d96bed 2797
895c2d04 2798uint32_t helper_float_cvts_w(CPUMIPSState *env, uint32_t wt0)
fd4a04eb 2799{
b6d96bed
TS
2800 uint32_t fst2;
2801
f01be154 2802 fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status);
5f7319cd 2803 update_fcr31(env, GETPC());
b6d96bed 2804 return fst2;
fd4a04eb 2805}
b6d96bed 2806
895c2d04 2807uint32_t helper_float_cvts_l(CPUMIPSState *env, uint64_t dt0)
fd4a04eb 2808{
b6d96bed
TS
2809 uint32_t fst2;
2810
f01be154 2811 fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status);
5f7319cd 2812 update_fcr31(env, GETPC());
b6d96bed 2813 return fst2;
fd4a04eb 2814}
b6d96bed 2815
895c2d04 2816uint32_t helper_float_cvts_pl(CPUMIPSState *env, uint32_t wt0)
fd4a04eb 2817{
b6d96bed
TS
2818 uint32_t wt2;
2819
b6d96bed 2820 wt2 = wt0;
5f7319cd 2821 update_fcr31(env, GETPC());
b6d96bed 2822 return wt2;
fd4a04eb 2823}
b6d96bed 2824
895c2d04 2825uint32_t helper_float_cvts_pu(CPUMIPSState *env, uint32_t wth0)
fd4a04eb 2826{
b6d96bed
TS
2827 uint32_t wt2;
2828
b6d96bed 2829 wt2 = wth0;
5f7319cd 2830 update_fcr31(env, GETPC());
b6d96bed 2831 return wt2;
fd4a04eb 2832}
b6d96bed 2833
87552089 2834uint32_t helper_float_cvt_w_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2835{
b6d96bed
TS
2836 uint32_t wt2;
2837
f01be154 2838 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2839 if (get_float_exception_flags(&env->active_fpu.fp_status)
2840 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2841 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2842 }
2b09f94c 2843 update_fcr31(env, GETPC());
b6d96bed 2844 return wt2;
fd4a04eb 2845}
b6d96bed 2846
87552089 2847uint32_t helper_float_cvt_w_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2848{
b6d96bed
TS
2849 uint32_t wt2;
2850
f01be154 2851 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2852 if (get_float_exception_flags(&env->active_fpu.fp_status)
2853 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2854 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2855 }
5f7319cd 2856 update_fcr31(env, GETPC());
b6d96bed 2857 return wt2;
fd4a04eb
TS
2858}
2859
87552089 2860uint64_t helper_float_round_l_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2861{
b6d96bed
TS
2862 uint64_t dt2;
2863
f01be154
TS
2864 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2865 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
e320d05a 2866 restore_rounding_mode(env);
4cc2e5f9
AJ
2867 if (get_float_exception_flags(&env->active_fpu.fp_status)
2868 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2869 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2870 }
5f7319cd 2871 update_fcr31(env, GETPC());
b6d96bed 2872 return dt2;
fd4a04eb 2873}
b6d96bed 2874
87552089 2875uint64_t helper_float_round_l_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2876{
b6d96bed
TS
2877 uint64_t dt2;
2878
f01be154
TS
2879 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2880 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
e320d05a 2881 restore_rounding_mode(env);
4cc2e5f9
AJ
2882 if (get_float_exception_flags(&env->active_fpu.fp_status)
2883 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2884 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2885 }
5f7319cd 2886 update_fcr31(env, GETPC());
b6d96bed 2887 return dt2;
fd4a04eb 2888}
b6d96bed 2889
87552089 2890uint32_t helper_float_round_w_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2891{
b6d96bed
TS
2892 uint32_t wt2;
2893
f01be154
TS
2894 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2895 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
e320d05a 2896 restore_rounding_mode(env);
4cc2e5f9
AJ
2897 if (get_float_exception_flags(&env->active_fpu.fp_status)
2898 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2899 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2900 }
5f7319cd 2901 update_fcr31(env, GETPC());
b6d96bed 2902 return wt2;
fd4a04eb 2903}
b6d96bed 2904
87552089 2905uint32_t helper_float_round_w_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2906{
b6d96bed
TS
2907 uint32_t wt2;
2908
f01be154
TS
2909 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2910 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
e320d05a 2911 restore_rounding_mode(env);
4cc2e5f9
AJ
2912 if (get_float_exception_flags(&env->active_fpu.fp_status)
2913 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2914 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2915 }
5f7319cd 2916 update_fcr31(env, GETPC());
b6d96bed 2917 return wt2;
fd4a04eb
TS
2918}
2919
87552089 2920uint64_t helper_float_trunc_l_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2921{
b6d96bed
TS
2922 uint64_t dt2;
2923
f01be154 2924 dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2925 if (get_float_exception_flags(&env->active_fpu.fp_status)
2926 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2927 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2928 }
5f7319cd 2929 update_fcr31(env, GETPC());
b6d96bed 2930 return dt2;
fd4a04eb 2931}
b6d96bed 2932
87552089 2933uint64_t helper_float_trunc_l_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2934{
b6d96bed
TS
2935 uint64_t dt2;
2936
f01be154 2937 dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2938 if (get_float_exception_flags(&env->active_fpu.fp_status)
2939 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2940 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2941 }
5f7319cd 2942 update_fcr31(env, GETPC());
b6d96bed 2943 return dt2;
fd4a04eb 2944}
b6d96bed 2945
87552089 2946uint32_t helper_float_trunc_w_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2947{
b6d96bed
TS
2948 uint32_t wt2;
2949
f01be154 2950 wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2951 if (get_float_exception_flags(&env->active_fpu.fp_status)
2952 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2953 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2954 }
5f7319cd 2955 update_fcr31(env, GETPC());
b6d96bed 2956 return wt2;
fd4a04eb 2957}
b6d96bed 2958
87552089 2959uint32_t helper_float_trunc_w_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2960{
b6d96bed
TS
2961 uint32_t wt2;
2962
f01be154 2963 wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2964 if (get_float_exception_flags(&env->active_fpu.fp_status)
2965 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2966 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2967 }
5f7319cd 2968 update_fcr31(env, GETPC());
b6d96bed 2969 return wt2;
fd4a04eb
TS
2970}
2971
87552089 2972uint64_t helper_float_ceil_l_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2973{
b6d96bed
TS
2974 uint64_t dt2;
2975
f01be154
TS
2976 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2977 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
e320d05a 2978 restore_rounding_mode(env);
4cc2e5f9
AJ
2979 if (get_float_exception_flags(&env->active_fpu.fp_status)
2980 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2981 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2982 }
5f7319cd 2983 update_fcr31(env, GETPC());
b6d96bed 2984 return dt2;
fd4a04eb 2985}
b6d96bed 2986
87552089 2987uint64_t helper_float_ceil_l_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2988{
b6d96bed
TS
2989 uint64_t dt2;
2990
f01be154
TS
2991 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2992 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
e320d05a 2993 restore_rounding_mode(env);
4cc2e5f9
AJ
2994 if (get_float_exception_flags(&env->active_fpu.fp_status)
2995 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2996 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2997 }
5f7319cd 2998 update_fcr31(env, GETPC());
b6d96bed 2999 return dt2;
fd4a04eb 3000}
b6d96bed 3001
87552089 3002uint32_t helper_float_ceil_w_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 3003{
b6d96bed
TS
3004 uint32_t wt2;
3005
f01be154
TS
3006 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3007 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
e320d05a 3008 restore_rounding_mode(env);
4cc2e5f9
AJ
3009 if (get_float_exception_flags(&env->active_fpu.fp_status)
3010 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 3011 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 3012 }
5f7319cd 3013 update_fcr31(env, GETPC());
b6d96bed 3014 return wt2;
fd4a04eb 3015}
b6d96bed 3016
87552089 3017uint32_t helper_float_ceil_w_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 3018{
b6d96bed
TS
3019 uint32_t wt2;
3020
f01be154
TS
3021 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3022 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
e320d05a 3023 restore_rounding_mode(env);
4cc2e5f9
AJ
3024 if (get_float_exception_flags(&env->active_fpu.fp_status)
3025 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 3026 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 3027 }
5f7319cd 3028 update_fcr31(env, GETPC());
b6d96bed 3029 return wt2;
fd4a04eb
TS
3030}
3031
87552089 3032uint64_t helper_float_floor_l_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 3033{
b6d96bed
TS
3034 uint64_t dt2;
3035
f01be154
TS
3036 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3037 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
e320d05a 3038 restore_rounding_mode(env);
4cc2e5f9
AJ
3039 if (get_float_exception_flags(&env->active_fpu.fp_status)
3040 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 3041 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 3042 }
5f7319cd 3043 update_fcr31(env, GETPC());
b6d96bed 3044 return dt2;
fd4a04eb 3045}
b6d96bed 3046
87552089 3047uint64_t helper_float_floor_l_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 3048{
b6d96bed
TS
3049 uint64_t dt2;
3050
f01be154
TS
3051 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3052 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
e320d05a 3053 restore_rounding_mode(env);
4cc2e5f9
AJ
3054 if (get_float_exception_flags(&env->active_fpu.fp_status)
3055 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 3056 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 3057 }
5f7319cd 3058 update_fcr31(env, GETPC());
b6d96bed 3059 return dt2;
fd4a04eb 3060}
b6d96bed 3061
87552089 3062uint32_t helper_float_floor_w_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 3063{
b6d96bed
TS
3064 uint32_t wt2;
3065
f01be154
TS
3066 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3067 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
e320d05a 3068 restore_rounding_mode(env);
4cc2e5f9
AJ
3069 if (get_float_exception_flags(&env->active_fpu.fp_status)
3070 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 3071 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 3072 }
5f7319cd 3073 update_fcr31(env, GETPC());
b6d96bed 3074 return wt2;
fd4a04eb 3075}
b6d96bed 3076
87552089 3077uint32_t helper_float_floor_w_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 3078{
b6d96bed
TS
3079 uint32_t wt2;
3080
f01be154
TS
3081 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3082 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
e320d05a 3083 restore_rounding_mode(env);
4cc2e5f9
AJ
3084 if (get_float_exception_flags(&env->active_fpu.fp_status)
3085 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 3086 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 3087 }
5f7319cd 3088 update_fcr31(env, GETPC());
b6d96bed 3089 return wt2;
fd4a04eb
TS
3090}
3091
87552089
AM
3092uint64_t helper_float_cvt_2008_l_d(CPUMIPSState *env, uint64_t fdt0)
3093{
3094 uint64_t dt2;
3095
3096 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3097 if (get_float_exception_flags(&env->active_fpu.fp_status)
3098 & float_flag_invalid) {
3099 if (float64_is_any_nan(fdt0)) {
3100 dt2 = 0;
3101 }
3102 }
3103 update_fcr31(env, GETPC());
3104 return dt2;
3105}
3106
3107uint64_t helper_float_cvt_2008_l_s(CPUMIPSState *env, uint32_t fst0)
3108{
3109 uint64_t dt2;
3110
3111 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3112 if (get_float_exception_flags(&env->active_fpu.fp_status)
3113 & float_flag_invalid) {
3114 if (float32_is_any_nan(fst0)) {
3115 dt2 = 0;
3116 }
3117 }
3118 update_fcr31(env, GETPC());
3119 return dt2;
3120}
3121
3122uint32_t helper_float_cvt_2008_w_d(CPUMIPSState *env, uint64_t fdt0)
3123{
3124 uint32_t wt2;
3125
3126 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3127 if (get_float_exception_flags(&env->active_fpu.fp_status)
3128 & float_flag_invalid) {
3129 if (float64_is_any_nan(fdt0)) {
3130 wt2 = 0;
3131 }
3132 }
3133 update_fcr31(env, GETPC());
3134 return wt2;
3135}
3136
3137uint32_t helper_float_cvt_2008_w_s(CPUMIPSState *env, uint32_t fst0)
3138{
3139 uint32_t wt2;
3140
3141 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3142 if (get_float_exception_flags(&env->active_fpu.fp_status)
3143 & float_flag_invalid) {
3144 if (float32_is_any_nan(fst0)) {
3145 wt2 = 0;
3146 }
3147 }
3148 update_fcr31(env, GETPC());
3149 return wt2;
3150}
3151
3152uint64_t helper_float_round_2008_l_d(CPUMIPSState *env, uint64_t fdt0)
3153{
3154 uint64_t dt2;
3155
3156 set_float_rounding_mode(float_round_nearest_even,
3157 &env->active_fpu.fp_status);
3158 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3159 restore_rounding_mode(env);
3160 if (get_float_exception_flags(&env->active_fpu.fp_status)
3161 & float_flag_invalid) {
3162 if (float64_is_any_nan(fdt0)) {
3163 dt2 = 0;
3164 }
3165 }
3166 update_fcr31(env, GETPC());
3167 return dt2;
3168}
3169
3170uint64_t helper_float_round_2008_l_s(CPUMIPSState *env, uint32_t fst0)
3171{
3172 uint64_t dt2;
3173
3174 set_float_rounding_mode(float_round_nearest_even,
3175 &env->active_fpu.fp_status);
3176 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3177 restore_rounding_mode(env);
3178 if (get_float_exception_flags(&env->active_fpu.fp_status)
3179 & float_flag_invalid) {
3180 if (float32_is_any_nan(fst0)) {
3181 dt2 = 0;
3182 }
3183 }
3184 update_fcr31(env, GETPC());
3185 return dt2;
3186}
3187
3188uint32_t helper_float_round_2008_w_d(CPUMIPSState *env, uint64_t fdt0)
3189{
3190 uint32_t wt2;
3191
3192 set_float_rounding_mode(float_round_nearest_even,
3193 &env->active_fpu.fp_status);
3194 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3195 restore_rounding_mode(env);
3196 if (get_float_exception_flags(&env->active_fpu.fp_status)
3197 & float_flag_invalid) {
3198 if (float64_is_any_nan(fdt0)) {
3199 wt2 = 0;
3200 }
3201 }
3202 update_fcr31(env, GETPC());
3203 return wt2;
3204}
3205
3206uint32_t helper_float_round_2008_w_s(CPUMIPSState *env, uint32_t fst0)
3207{
3208 uint32_t wt2;
3209
3210 set_float_rounding_mode(float_round_nearest_even,
3211 &env->active_fpu.fp_status);
3212 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3213 restore_rounding_mode(env);
3214 if (get_float_exception_flags(&env->active_fpu.fp_status)
3215 & float_flag_invalid) {
3216 if (float32_is_any_nan(fst0)) {
3217 wt2 = 0;
3218 }
3219 }
3220 update_fcr31(env, GETPC());
3221 return wt2;
3222}
3223
3224uint64_t helper_float_trunc_2008_l_d(CPUMIPSState *env, uint64_t fdt0)
3225{
3226 uint64_t dt2;
3227
3228 dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
3229 if (get_float_exception_flags(&env->active_fpu.fp_status)
3230 & float_flag_invalid) {
3231 if (float64_is_any_nan(fdt0)) {
3232 dt2 = 0;
3233 }
3234 }
3235 update_fcr31(env, GETPC());
3236 return dt2;
3237}
3238
3239uint64_t helper_float_trunc_2008_l_s(CPUMIPSState *env, uint32_t fst0)
3240{
3241 uint64_t dt2;
3242
3243 dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
3244 if (get_float_exception_flags(&env->active_fpu.fp_status)
3245 & float_flag_invalid) {
3246 if (float32_is_any_nan(fst0)) {
3247 dt2 = 0;
3248 }
3249 }
3250 update_fcr31(env, GETPC());
3251 return dt2;
3252}
3253
3254uint32_t helper_float_trunc_2008_w_d(CPUMIPSState *env, uint64_t fdt0)
3255{
3256 uint32_t wt2;
3257
3258 wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
3259 if (get_float_exception_flags(&env->active_fpu.fp_status)
3260 & float_flag_invalid) {
3261 if (float64_is_any_nan(fdt0)) {
3262 wt2 = 0;
3263 }
3264 }
3265 update_fcr31(env, GETPC());
3266 return wt2;
3267}
3268
3269uint32_t helper_float_trunc_2008_w_s(CPUMIPSState *env, uint32_t fst0)
3270{
3271 uint32_t wt2;
3272
3273 wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
3274 if (get_float_exception_flags(&env->active_fpu.fp_status)
3275 & float_flag_invalid) {
3276 if (float32_is_any_nan(fst0)) {
3277 wt2 = 0;
3278 }
3279 }
3280 update_fcr31(env, GETPC());
3281 return wt2;
3282}
3283
3284uint64_t helper_float_ceil_2008_l_d(CPUMIPSState *env, uint64_t fdt0)
3285{
3286 uint64_t dt2;
3287
3288 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3289 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3290 restore_rounding_mode(env);
3291 if (get_float_exception_flags(&env->active_fpu.fp_status)
3292 & float_flag_invalid) {
3293 if (float64_is_any_nan(fdt0)) {
3294 dt2 = 0;
3295 }
3296 }
3297 update_fcr31(env, GETPC());
3298 return dt2;
3299}
3300
3301uint64_t helper_float_ceil_2008_l_s(CPUMIPSState *env, uint32_t fst0)
3302{
3303 uint64_t dt2;
3304
3305 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3306 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3307 restore_rounding_mode(env);
3308 if (get_float_exception_flags(&env->active_fpu.fp_status)
3309 & float_flag_invalid) {
3310 if (float32_is_any_nan(fst0)) {
3311 dt2 = 0;
3312 }
3313 }
3314 update_fcr31(env, GETPC());
3315 return dt2;
3316}
3317
3318uint32_t helper_float_ceil_2008_w_d(CPUMIPSState *env, uint64_t fdt0)
3319{
3320 uint32_t wt2;
3321
3322 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3323 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3324 restore_rounding_mode(env);
3325 if (get_float_exception_flags(&env->active_fpu.fp_status)
3326 & float_flag_invalid) {
3327 if (float64_is_any_nan(fdt0)) {
3328 wt2 = 0;
3329 }
3330 }
3331 update_fcr31(env, GETPC());
3332 return wt2;
3333}
3334
3335uint32_t helper_float_ceil_2008_w_s(CPUMIPSState *env, uint32_t fst0)
3336{
3337 uint32_t wt2;
3338
3339 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3340 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3341 restore_rounding_mode(env);
3342 if (get_float_exception_flags(&env->active_fpu.fp_status)
3343 & float_flag_invalid) {
3344 if (float32_is_any_nan(fst0)) {
3345 wt2 = 0;
3346 }
3347 }
3348 update_fcr31(env, GETPC());
3349 return wt2;
3350}
3351
3352uint64_t helper_float_floor_2008_l_d(CPUMIPSState *env, uint64_t fdt0)
3353{
3354 uint64_t dt2;
3355
3356 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3357 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3358 restore_rounding_mode(env);
3359 if (get_float_exception_flags(&env->active_fpu.fp_status)
3360 & float_flag_invalid) {
3361 if (float64_is_any_nan(fdt0)) {
3362 dt2 = 0;
3363 }
3364 }
3365 update_fcr31(env, GETPC());
3366 return dt2;
3367}
3368
3369uint64_t helper_float_floor_2008_l_s(CPUMIPSState *env, uint32_t fst0)
3370{
3371 uint64_t dt2;
3372
3373 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3374 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3375 restore_rounding_mode(env);
3376 if (get_float_exception_flags(&env->active_fpu.fp_status)
3377 & float_flag_invalid) {
3378 if (float32_is_any_nan(fst0)) {
3379 dt2 = 0;
3380 }
3381 }
3382 update_fcr31(env, GETPC());
3383 return dt2;
3384}
3385
3386uint32_t helper_float_floor_2008_w_d(CPUMIPSState *env, uint64_t fdt0)
3387{
3388 uint32_t wt2;
3389
3390 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3391 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3392 restore_rounding_mode(env);
3393 if (get_float_exception_flags(&env->active_fpu.fp_status)
3394 & float_flag_invalid) {
3395 if (float64_is_any_nan(fdt0)) {
3396 wt2 = 0;
3397 }
3398 }
3399 update_fcr31(env, GETPC());
3400 return wt2;
3401}
3402
3403uint32_t helper_float_floor_2008_w_s(CPUMIPSState *env, uint32_t fst0)
3404{
3405 uint32_t wt2;
3406
3407 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3408 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3409 restore_rounding_mode(env);
3410 if (get_float_exception_flags(&env->active_fpu.fp_status)
3411 & float_flag_invalid) {
3412 if (float32_is_any_nan(fst0)) {
3413 wt2 = 0;
3414 }
3415 }
3416 update_fcr31(env, GETPC());
3417 return wt2;
3418}
3419
a16336e4 3420/* unary operations, not modifying fp status */
b6d96bed 3421#define FLOAT_UNOP(name) \
c01fccd2 3422uint64_t helper_float_ ## name ## _d(uint64_t fdt0) \
b6d96bed
TS
3423{ \
3424 return float64_ ## name(fdt0); \
3425} \
c01fccd2 3426uint32_t helper_float_ ## name ## _s(uint32_t fst0) \
b6d96bed
TS
3427{ \
3428 return float32_ ## name(fst0); \
3429} \
c01fccd2 3430uint64_t helper_float_ ## name ## _ps(uint64_t fdt0) \
b6d96bed
TS
3431{ \
3432 uint32_t wt0; \
3433 uint32_t wth0; \
3434 \
3435 wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF); \
3436 wth0 = float32_ ## name(fdt0 >> 32); \
3437 return ((uint64_t)wth0 << 32) | wt0; \
a16336e4
TS
3438}
3439FLOAT_UNOP(abs)
3440FLOAT_UNOP(chs)
3441#undef FLOAT_UNOP
3442
8dfdb87c 3443/* MIPS specific unary operations */
895c2d04 3444uint64_t helper_float_recip_d(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 3445{
b6d96bed
TS
3446 uint64_t fdt2;
3447
05993cd0 3448 fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
5f7319cd 3449 update_fcr31(env, GETPC());
b6d96bed 3450 return fdt2;
8dfdb87c 3451}
b6d96bed 3452
895c2d04 3453uint32_t helper_float_recip_s(CPUMIPSState *env, uint32_t fst0)
8dfdb87c 3454{
b6d96bed
TS
3455 uint32_t fst2;
3456
05993cd0 3457 fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
5f7319cd 3458 update_fcr31(env, GETPC());
b6d96bed 3459 return fst2;
57fa1fb3 3460}
57fa1fb3 3461
895c2d04 3462uint64_t helper_float_rsqrt_d(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 3463{
b6d96bed
TS
3464 uint64_t fdt2;
3465
f01be154 3466 fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
05993cd0 3467 fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
5f7319cd 3468 update_fcr31(env, GETPC());
b6d96bed 3469 return fdt2;
8dfdb87c 3470}
b6d96bed 3471
895c2d04 3472uint32_t helper_float_rsqrt_s(CPUMIPSState *env, uint32_t fst0)
8dfdb87c 3473{
b6d96bed
TS
3474 uint32_t fst2;
3475
f01be154 3476 fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
05993cd0 3477 fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
5f7319cd 3478 update_fcr31(env, GETPC());
b6d96bed 3479 return fst2;
8dfdb87c
TS
3480}
3481
895c2d04 3482uint64_t helper_float_recip1_d(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 3483{
b6d96bed
TS
3484 uint64_t fdt2;
3485
05993cd0 3486 fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
5f7319cd 3487 update_fcr31(env, GETPC());
b6d96bed 3488 return fdt2;
8dfdb87c 3489}
b6d96bed 3490
895c2d04 3491uint32_t helper_float_recip1_s(CPUMIPSState *env, uint32_t fst0)
8dfdb87c 3492{
b6d96bed
TS
3493 uint32_t fst2;
3494
05993cd0 3495 fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
5f7319cd 3496 update_fcr31(env, GETPC());
b6d96bed 3497 return fst2;
8dfdb87c 3498}
b6d96bed 3499
895c2d04 3500uint64_t helper_float_recip1_ps(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 3501{
b6d96bed
TS
3502 uint32_t fst2;
3503 uint32_t fsth2;
3504
05993cd0
AJ
3505 fst2 = float32_div(float32_one, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
3506 fsth2 = float32_div(float32_one, fdt0 >> 32, &env->active_fpu.fp_status);
5f7319cd 3507 update_fcr31(env, GETPC());
b6d96bed 3508 return ((uint64_t)fsth2 << 32) | fst2;
8dfdb87c
TS
3509}
3510
895c2d04 3511uint64_t helper_float_rsqrt1_d(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 3512{
b6d96bed
TS
3513 uint64_t fdt2;
3514
f01be154 3515 fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
05993cd0 3516 fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
5f7319cd 3517 update_fcr31(env, GETPC());
b6d96bed 3518 return fdt2;
8dfdb87c 3519}
b6d96bed 3520
895c2d04 3521uint32_t helper_float_rsqrt1_s(CPUMIPSState *env, uint32_t fst0)
8dfdb87c 3522{
b6d96bed
TS
3523 uint32_t fst2;
3524
f01be154 3525 fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
05993cd0 3526 fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
5f7319cd 3527 update_fcr31(env, GETPC());
b6d96bed 3528 return fst2;
8dfdb87c 3529}
b6d96bed 3530
895c2d04 3531uint64_t helper_float_rsqrt1_ps(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 3532{
b6d96bed
TS
3533 uint32_t fst2;
3534 uint32_t fsth2;
3535
f01be154
TS
3536 fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
3537 fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status);
05993cd0
AJ
3538 fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
3539 fsth2 = float32_div(float32_one, fsth2, &env->active_fpu.fp_status);
5f7319cd 3540 update_fcr31(env, GETPC());
b6d96bed 3541 return ((uint64_t)fsth2 << 32) | fst2;
57fa1fb3 3542}
57fa1fb3 3543
8fc605b8
MR
3544#define FLOAT_RINT(name, bits) \
3545uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \
3546 uint ## bits ## _t fs) \
3547{ \
3548 uint ## bits ## _t fdret; \
3549 \
3550 fdret = float ## bits ## _round_to_int(fs, &env->active_fpu.fp_status); \
3551 update_fcr31(env, GETPC()); \
3552 return fdret; \
3553}
3554
3555FLOAT_RINT(rint_s, 32)
3556FLOAT_RINT(rint_d, 64)
3557#undef FLOAT_RINT
3558
3559#define FLOAT_CLASS_SIGNALING_NAN 0x001
3560#define FLOAT_CLASS_QUIET_NAN 0x002
3561#define FLOAT_CLASS_NEGATIVE_INFINITY 0x004
3562#define FLOAT_CLASS_NEGATIVE_NORMAL 0x008
3563#define FLOAT_CLASS_NEGATIVE_SUBNORMAL 0x010
3564#define FLOAT_CLASS_NEGATIVE_ZERO 0x020
3565#define FLOAT_CLASS_POSITIVE_INFINITY 0x040
3566#define FLOAT_CLASS_POSITIVE_NORMAL 0x080
3567#define FLOAT_CLASS_POSITIVE_SUBNORMAL 0x100
3568#define FLOAT_CLASS_POSITIVE_ZERO 0x200
3569
3570#define FLOAT_CLASS(name, bits) \
af39bc8c
AM
3571uint ## bits ## _t float_ ## name (uint ## bits ## _t arg, \
3572 float_status *status) \
8fc605b8 3573{ \
af39bc8c 3574 if (float ## bits ## _is_signaling_nan(arg, status)) { \
8fc605b8 3575 return FLOAT_CLASS_SIGNALING_NAN; \
af39bc8c 3576 } else if (float ## bits ## _is_quiet_nan(arg, status)) { \
8fc605b8
MR
3577 return FLOAT_CLASS_QUIET_NAN; \
3578 } else if (float ## bits ## _is_neg(arg)) { \
3579 if (float ## bits ## _is_infinity(arg)) { \
3580 return FLOAT_CLASS_NEGATIVE_INFINITY; \
3581 } else if (float ## bits ## _is_zero(arg)) { \
3582 return FLOAT_CLASS_NEGATIVE_ZERO; \
3583 } else if (float ## bits ## _is_zero_or_denormal(arg)) { \
3584 return FLOAT_CLASS_NEGATIVE_SUBNORMAL; \
3585 } else { \
3586 return FLOAT_CLASS_NEGATIVE_NORMAL; \
3587 } \
3588 } else { \
3589 if (float ## bits ## _is_infinity(arg)) { \
3590 return FLOAT_CLASS_POSITIVE_INFINITY; \
3591 } else if (float ## bits ## _is_zero(arg)) { \
3592 return FLOAT_CLASS_POSITIVE_ZERO; \
3593 } else if (float ## bits ## _is_zero_or_denormal(arg)) { \
3594 return FLOAT_CLASS_POSITIVE_SUBNORMAL; \
3595 } else { \
3596 return FLOAT_CLASS_POSITIVE_NORMAL; \
3597 } \
3598 } \
af39bc8c
AM
3599} \
3600 \
3601uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \
3602 uint ## bits ## _t arg) \
3603{ \
3604 return float_ ## name(arg, &env->active_fpu.fp_status); \
8fc605b8
MR
3605}
3606
3607FLOAT_CLASS(class_s, 32)
3608FLOAT_CLASS(class_d, 64)
3609#undef FLOAT_CLASS
3610
fd4a04eb 3611/* binary operations */
b6d96bed 3612#define FLOAT_BINOP(name) \
895c2d04
BS
3613uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \
3614 uint64_t fdt0, uint64_t fdt1) \
b6d96bed
TS
3615{ \
3616 uint64_t dt2; \
3617 \
f01be154 3618 dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status); \
5f7319cd 3619 update_fcr31(env, GETPC()); \
b6d96bed
TS
3620 return dt2; \
3621} \
3622 \
895c2d04
BS
3623uint32_t helper_float_ ## name ## _s(CPUMIPSState *env, \
3624 uint32_t fst0, uint32_t fst1) \
b6d96bed
TS
3625{ \
3626 uint32_t wt2; \
3627 \
f01be154 3628 wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \
5f7319cd 3629 update_fcr31(env, GETPC()); \
b6d96bed
TS
3630 return wt2; \
3631} \
3632 \
895c2d04
BS
3633uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \
3634 uint64_t fdt0, \
3635 uint64_t fdt1) \
b6d96bed
TS
3636{ \
3637 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
3638 uint32_t fsth0 = fdt0 >> 32; \
3639 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
3640 uint32_t fsth1 = fdt1 >> 32; \
3641 uint32_t wt2; \
3642 uint32_t wth2; \
3643 \
f01be154
TS
3644 wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \
3645 wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status); \
5f7319cd 3646 update_fcr31(env, GETPC()); \
b6d96bed 3647 return ((uint64_t)wth2 << 32) | wt2; \
fd4a04eb 3648}
b6d96bed 3649
fd4a04eb
TS
3650FLOAT_BINOP(add)
3651FLOAT_BINOP(sub)
3652FLOAT_BINOP(mul)
3653FLOAT_BINOP(div)
3654#undef FLOAT_BINOP
3655
8dfdb87c 3656/* MIPS specific binary operations */
895c2d04 3657uint64_t helper_float_recip2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
8dfdb87c 3658{
f01be154 3659 fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
05993cd0 3660 fdt2 = float64_chs(float64_sub(fdt2, float64_one, &env->active_fpu.fp_status));
5f7319cd 3661 update_fcr31(env, GETPC());
b6d96bed 3662 return fdt2;
8dfdb87c 3663}
b6d96bed 3664
895c2d04 3665uint32_t helper_float_recip2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
8dfdb87c 3666{
f01be154 3667 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
05993cd0 3668 fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
5f7319cd 3669 update_fcr31(env, GETPC());
b6d96bed 3670 return fst2;
8dfdb87c 3671}
b6d96bed 3672
895c2d04 3673uint64_t helper_float_recip2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
8dfdb87c 3674{
b6d96bed
TS
3675 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3676 uint32_t fsth0 = fdt0 >> 32;
3677 uint32_t fst2 = fdt2 & 0XFFFFFFFF;
3678 uint32_t fsth2 = fdt2 >> 32;
3679
f01be154
TS
3680 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3681 fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
05993cd0
AJ
3682 fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
3683 fsth2 = float32_chs(float32_sub(fsth2, float32_one, &env->active_fpu.fp_status));
5f7319cd 3684 update_fcr31(env, GETPC());
b6d96bed 3685 return ((uint64_t)fsth2 << 32) | fst2;
8dfdb87c
TS
3686}
3687
895c2d04 3688uint64_t helper_float_rsqrt2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
8dfdb87c 3689{
f01be154 3690 fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
05993cd0 3691 fdt2 = float64_sub(fdt2, float64_one, &env->active_fpu.fp_status);
f01be154 3692 fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status));
5f7319cd 3693 update_fcr31(env, GETPC());
b6d96bed 3694 return fdt2;
8dfdb87c 3695}
b6d96bed 3696
895c2d04 3697uint32_t helper_float_rsqrt2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
8dfdb87c 3698{
f01be154 3699 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
05993cd0 3700 fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
f01be154 3701 fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
5f7319cd 3702 update_fcr31(env, GETPC());
b6d96bed 3703 return fst2;
8dfdb87c 3704}
b6d96bed 3705
895c2d04 3706uint64_t helper_float_rsqrt2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
8dfdb87c 3707{
b6d96bed
TS
3708 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3709 uint32_t fsth0 = fdt0 >> 32;
3710 uint32_t fst2 = fdt2 & 0XFFFFFFFF;
3711 uint32_t fsth2 = fdt2 >> 32;
3712
f01be154
TS
3713 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3714 fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
05993cd0
AJ
3715 fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
3716 fsth2 = float32_sub(fsth2, float32_one, &env->active_fpu.fp_status);
f01be154
TS
3717 fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
3718 fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->active_fpu.fp_status));
5f7319cd 3719 update_fcr31(env, GETPC());
b6d96bed 3720 return ((uint64_t)fsth2 << 32) | fst2;
57fa1fb3 3721}
57fa1fb3 3722
895c2d04 3723uint64_t helper_float_addr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
fd4a04eb 3724{
b6d96bed
TS
3725 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3726 uint32_t fsth0 = fdt0 >> 32;
3727 uint32_t fst1 = fdt1 & 0XFFFFFFFF;
3728 uint32_t fsth1 = fdt1 >> 32;
3729 uint32_t fst2;
3730 uint32_t fsth2;
3731
f01be154
TS
3732 fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status);
3733 fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status);
5f7319cd 3734 update_fcr31(env, GETPC());
b6d96bed 3735 return ((uint64_t)fsth2 << 32) | fst2;
fd4a04eb
TS
3736}
3737
895c2d04 3738uint64_t helper_float_mulr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
57fa1fb3 3739{
b6d96bed
TS
3740 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3741 uint32_t fsth0 = fdt0 >> 32;
3742 uint32_t fst1 = fdt1 & 0XFFFFFFFF;
3743 uint32_t fsth1 = fdt1 >> 32;
3744 uint32_t fst2;
3745 uint32_t fsth2;
3746
f01be154
TS
3747 fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status);
3748 fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status);
5f7319cd 3749 update_fcr31(env, GETPC());
b6d96bed 3750 return ((uint64_t)fsth2 << 32) | fst2;
57fa1fb3
TS
3751}
3752
8fc605b8
MR
3753#define FLOAT_MINMAX(name, bits, minmaxfunc) \
3754uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \
3755 uint ## bits ## _t fs, \
3756 uint ## bits ## _t ft) \
3757{ \
3758 uint ## bits ## _t fdret; \
3759 \
3760 fdret = float ## bits ## _ ## minmaxfunc(fs, ft, \
3761 &env->active_fpu.fp_status); \
3762 update_fcr31(env, GETPC()); \
3763 return fdret; \
3764}
3765
3766FLOAT_MINMAX(max_s, 32, maxnum)
3767FLOAT_MINMAX(max_d, 64, maxnum)
3768FLOAT_MINMAX(maxa_s, 32, maxnummag)
3769FLOAT_MINMAX(maxa_d, 64, maxnummag)
3770
3771FLOAT_MINMAX(min_s, 32, minnum)
3772FLOAT_MINMAX(min_d, 64, minnum)
3773FLOAT_MINMAX(mina_s, 32, minnummag)
3774FLOAT_MINMAX(mina_d, 64, minnummag)
3775#undef FLOAT_MINMAX
3776
3777/* ternary operations */
3778#define UNFUSED_FMA(prefix, a, b, c, flags) \
3779{ \
3780 a = prefix##_mul(a, b, &env->active_fpu.fp_status); \
3781 if ((flags) & float_muladd_negate_c) { \
3782 a = prefix##_sub(a, c, &env->active_fpu.fp_status); \
3783 } else { \
3784 a = prefix##_add(a, c, &env->active_fpu.fp_status); \
3785 } \
3786 if ((flags) & float_muladd_negate_result) { \
3787 a = prefix##_chs(a); \
3788 } \
3789}
3790
3791/* FMA based operations */
3792#define FLOAT_FMA(name, type) \
3793uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \
3794 uint64_t fdt0, uint64_t fdt1, \
3795 uint64_t fdt2) \
3796{ \
3797 UNFUSED_FMA(float64, fdt0, fdt1, fdt2, type); \
3798 update_fcr31(env, GETPC()); \
3799 return fdt0; \
3800} \
3801 \
3802uint32_t helper_float_ ## name ## _s(CPUMIPSState *env, \
3803 uint32_t fst0, uint32_t fst1, \
3804 uint32_t fst2) \
3805{ \
3806 UNFUSED_FMA(float32, fst0, fst1, fst2, type); \
3807 update_fcr31(env, GETPC()); \
3808 return fst0; \
3809} \
3810 \
3811uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \
3812 uint64_t fdt0, uint64_t fdt1, \
3813 uint64_t fdt2) \
3814{ \
3815 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
3816 uint32_t fsth0 = fdt0 >> 32; \
3817 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
3818 uint32_t fsth1 = fdt1 >> 32; \
3819 uint32_t fst2 = fdt2 & 0XFFFFFFFF; \
3820 uint32_t fsth2 = fdt2 >> 32; \
3821 \
3822 UNFUSED_FMA(float32, fst0, fst1, fst2, type); \
3823 UNFUSED_FMA(float32, fsth0, fsth1, fsth2, type); \
3824 update_fcr31(env, GETPC()); \
3825 return ((uint64_t)fsth0 << 32) | fst0; \
3826}
3827FLOAT_FMA(madd, 0)
3828FLOAT_FMA(msub, float_muladd_negate_c)
3829FLOAT_FMA(nmadd, float_muladd_negate_result)
3830FLOAT_FMA(nmsub, float_muladd_negate_result | float_muladd_negate_c)
3831#undef FLOAT_FMA
3832
3833#define FLOAT_FMADDSUB(name, bits, muladd_arg) \
3834uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \
3835 uint ## bits ## _t fs, \
3836 uint ## bits ## _t ft, \
3837 uint ## bits ## _t fd) \
3838{ \
3839 uint ## bits ## _t fdret; \
3840 \
3841 fdret = float ## bits ## _muladd(fs, ft, fd, muladd_arg, \
3842 &env->active_fpu.fp_status); \
3843 update_fcr31(env, GETPC()); \
3844 return fdret; \
3845}
3846
3847FLOAT_FMADDSUB(maddf_s, 32, 0)
3848FLOAT_FMADDSUB(maddf_d, 64, 0)
3849FLOAT_FMADDSUB(msubf_s, 32, float_muladd_negate_product)
3850FLOAT_FMADDSUB(msubf_d, 64, float_muladd_negate_product)
3851#undef FLOAT_FMADDSUB
3852
8dfdb87c 3853/* compare operations */
b6d96bed 3854#define FOP_COND_D(op, cond) \
895c2d04
BS
3855void helper_cmp_d_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3856 uint64_t fdt1, int cc) \
b6d96bed 3857{ \
6a385343 3858 int c; \
6a385343 3859 c = cond; \
5f7319cd 3860 update_fcr31(env, GETPC()); \
b6d96bed 3861 if (c) \
f01be154 3862 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3863 else \
f01be154 3864 CLEAR_FP_COND(cc, env->active_fpu); \
b6d96bed 3865} \
895c2d04
BS
3866void helper_cmpabs_d_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3867 uint64_t fdt1, int cc) \
b6d96bed
TS
3868{ \
3869 int c; \
3870 fdt0 = float64_abs(fdt0); \
3871 fdt1 = float64_abs(fdt1); \
3872 c = cond; \
5f7319cd 3873 update_fcr31(env, GETPC()); \
b6d96bed 3874 if (c) \
f01be154 3875 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3876 else \
f01be154 3877 CLEAR_FP_COND(cc, env->active_fpu); \
fd4a04eb
TS
3878}
3879
fd4a04eb 3880/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3881 * but float64_unordered_quiet() is still called. */
3882FOP_COND_D(f, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
3883FOP_COND_D(un, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status))
06a0e6b1 3884FOP_COND_D(eq, float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
211315fb 3885FOP_COND_D(ueq, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
06a0e6b1
AJ
3886FOP_COND_D(olt, float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3887FOP_COND_D(ult, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3888FOP_COND_D(ole, float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3889FOP_COND_D(ule, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
fd4a04eb 3890/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3891 * but float64_unordered() is still called. */
3892FOP_COND_D(sf, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
3893FOP_COND_D(ngle,float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status))
06a0e6b1
AJ
3894FOP_COND_D(seq, float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
3895FOP_COND_D(ngl, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
3896FOP_COND_D(lt, float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
3a599383 3897FOP_COND_D(nge, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
06a0e6b1 3898FOP_COND_D(le, float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3a599383 3899FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
b6d96bed
TS
3900
3901#define FOP_COND_S(op, cond) \
895c2d04
BS
3902void helper_cmp_s_ ## op(CPUMIPSState *env, uint32_t fst0, \
3903 uint32_t fst1, int cc) \
b6d96bed 3904{ \
6a385343 3905 int c; \
6a385343 3906 c = cond; \
5f7319cd 3907 update_fcr31(env, GETPC()); \
b6d96bed 3908 if (c) \
f01be154 3909 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3910 else \
f01be154 3911 CLEAR_FP_COND(cc, env->active_fpu); \
b6d96bed 3912} \
895c2d04
BS
3913void helper_cmpabs_s_ ## op(CPUMIPSState *env, uint32_t fst0, \
3914 uint32_t fst1, int cc) \
b6d96bed
TS
3915{ \
3916 int c; \
3917 fst0 = float32_abs(fst0); \
3918 fst1 = float32_abs(fst1); \
3919 c = cond; \
5f7319cd 3920 update_fcr31(env, GETPC()); \
b6d96bed 3921 if (c) \
f01be154 3922 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3923 else \
f01be154 3924 CLEAR_FP_COND(cc, env->active_fpu); \
fd4a04eb
TS
3925}
3926
fd4a04eb 3927/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3928 * but float32_unordered_quiet() is still called. */
3929FOP_COND_S(f, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
3930FOP_COND_S(un, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status))
06a0e6b1 3931FOP_COND_S(eq, float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
211315fb 3932FOP_COND_S(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
06a0e6b1
AJ
3933FOP_COND_S(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
3934FOP_COND_S(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
3935FOP_COND_S(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
3936FOP_COND_S(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
fd4a04eb 3937/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3938 * but float32_unordered() is still called. */
3939FOP_COND_S(sf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
3940FOP_COND_S(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status))
06a0e6b1
AJ
3941FOP_COND_S(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status))
3942FOP_COND_S(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
3943FOP_COND_S(lt, float32_lt(fst0, fst1, &env->active_fpu.fp_status))
3a599383 3944FOP_COND_S(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
06a0e6b1 3945FOP_COND_S(le, float32_le(fst0, fst1, &env->active_fpu.fp_status))
3a599383 3946FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status))
b6d96bed
TS
3947
3948#define FOP_COND_PS(op, condl, condh) \
895c2d04
BS
3949void helper_cmp_ps_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3950 uint64_t fdt1, int cc) \
b6d96bed 3951{ \
6a385343
AJ
3952 uint32_t fst0, fsth0, fst1, fsth1; \
3953 int ch, cl; \
6a385343
AJ
3954 fst0 = fdt0 & 0XFFFFFFFF; \
3955 fsth0 = fdt0 >> 32; \
3956 fst1 = fdt1 & 0XFFFFFFFF; \
3957 fsth1 = fdt1 >> 32; \
3958 cl = condl; \
3959 ch = condh; \
5f7319cd 3960 update_fcr31(env, GETPC()); \
b6d96bed 3961 if (cl) \
f01be154 3962 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3963 else \
f01be154 3964 CLEAR_FP_COND(cc, env->active_fpu); \
b6d96bed 3965 if (ch) \
f01be154 3966 SET_FP_COND(cc + 1, env->active_fpu); \
b6d96bed 3967 else \
f01be154 3968 CLEAR_FP_COND(cc + 1, env->active_fpu); \
b6d96bed 3969} \
895c2d04
BS
3970void helper_cmpabs_ps_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3971 uint64_t fdt1, int cc) \
b6d96bed 3972{ \
6a385343
AJ
3973 uint32_t fst0, fsth0, fst1, fsth1; \
3974 int ch, cl; \
3975 fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \
3976 fsth0 = float32_abs(fdt0 >> 32); \
3977 fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \
3978 fsth1 = float32_abs(fdt1 >> 32); \
3979 cl = condl; \
3980 ch = condh; \
5f7319cd 3981 update_fcr31(env, GETPC()); \
b6d96bed 3982 if (cl) \
f01be154 3983 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3984 else \
f01be154 3985 CLEAR_FP_COND(cc, env->active_fpu); \
b6d96bed 3986 if (ch) \
f01be154 3987 SET_FP_COND(cc + 1, env->active_fpu); \
b6d96bed 3988 else \
f01be154 3989 CLEAR_FP_COND(cc + 1, env->active_fpu); \
fd4a04eb
TS
3990}
3991
3992/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3993 * but float32_unordered_quiet() is still called. */
3994FOP_COND_PS(f, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0),
3995 (float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status), 0))
3996FOP_COND_PS(un, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status),
3997 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status))
06a0e6b1
AJ
3998FOP_COND_PS(eq, float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
3999 float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
211315fb
AJ
4000FOP_COND_PS(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
4001 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
06a0e6b1
AJ
4002FOP_COND_PS(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
4003 float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
4004FOP_COND_PS(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
4005 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
4006FOP_COND_PS(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
4007 float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
4008FOP_COND_PS(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
4009 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
fd4a04eb 4010/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
4011 * but float32_unordered() is still called. */
4012FOP_COND_PS(sf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0),
4013 (float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status), 0))
4014FOP_COND_PS(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status),
4015 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status))
06a0e6b1
AJ
4016FOP_COND_PS(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status),
4017 float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
4018FOP_COND_PS(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
4019 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
4020FOP_COND_PS(lt, float32_lt(fst0, fst1, &env->active_fpu.fp_status),
4021 float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
3a599383
AJ
4022FOP_COND_PS(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
4023 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
06a0e6b1
AJ
4024FOP_COND_PS(le, float32_le(fst0, fst1, &env->active_fpu.fp_status),
4025 float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
3a599383
AJ
4026FOP_COND_PS(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status),
4027 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
3f493883
YK
4028
4029/* R6 compare operations */
4030#define FOP_CONDN_D(op, cond) \
4031uint64_t helper_r6_cmp_d_ ## op(CPUMIPSState * env, uint64_t fdt0, \
4032 uint64_t fdt1) \
4033{ \
4034 uint64_t c; \
4035 c = cond; \
4036 update_fcr31(env, GETPC()); \
4037 if (c) { \
4038 return -1; \
4039 } else { \
4040 return 0; \
4041 } \
4042}
4043
4044/* NOTE: the comma operator will make "cond" to eval to false,
4045 * but float64_unordered_quiet() is still called. */
4046FOP_CONDN_D(af, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
4047FOP_CONDN_D(un, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)))
4048FOP_CONDN_D(eq, (float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4049FOP_CONDN_D(ueq, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4050 || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4051FOP_CONDN_D(lt, (float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4052FOP_CONDN_D(ult, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4053 || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4054FOP_CONDN_D(le, (float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4055FOP_CONDN_D(ule, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4056 || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4057/* NOTE: the comma operator will make "cond" to eval to false,
4058 * but float64_unordered() is still called. */
4059FOP_CONDN_D(saf, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
4060FOP_CONDN_D(sun, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)))
4061FOP_CONDN_D(seq, (float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)))
4062FOP_CONDN_D(sueq, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
4063 || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)))
4064FOP_CONDN_D(slt, (float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
4065FOP_CONDN_D(sult, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
4066 || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
4067FOP_CONDN_D(sle, (float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
4068FOP_CONDN_D(sule, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
4069 || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
4070FOP_CONDN_D(or, (float64_le_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4071 || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4072FOP_CONDN_D(une, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4073 || float64_lt_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4074 || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4075FOP_CONDN_D(ne, (float64_lt_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4076 || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4077FOP_CONDN_D(sor, (float64_le(fdt1, fdt0, &env->active_fpu.fp_status)
4078 || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
4079FOP_CONDN_D(sune, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
4080 || float64_lt(fdt1, fdt0, &env->active_fpu.fp_status)
4081 || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
4082FOP_CONDN_D(sne, (float64_lt(fdt1, fdt0, &env->active_fpu.fp_status)
4083 || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
4084
4085#define FOP_CONDN_S(op, cond) \
4086uint32_t helper_r6_cmp_s_ ## op(CPUMIPSState * env, uint32_t fst0, \
4087 uint32_t fst1) \
4088{ \
4089 uint64_t c; \
4090 c = cond; \
4091 update_fcr31(env, GETPC()); \
4092 if (c) { \
4093 return -1; \
4094 } else { \
4095 return 0; \
4096 } \
4097}
4098
4099/* NOTE: the comma operator will make "cond" to eval to false,
4100 * but float32_unordered_quiet() is still called. */
4101FOP_CONDN_S(af, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
4102FOP_CONDN_S(un, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)))
4103FOP_CONDN_S(eq, (float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4104FOP_CONDN_S(ueq, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
4105 || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4106FOP_CONDN_S(lt, (float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4107FOP_CONDN_S(ult, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
4108 || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4109FOP_CONDN_S(le, (float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4110FOP_CONDN_S(ule, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
4111 || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4112/* NOTE: the comma operator will make "cond" to eval to false,
4113 * but float32_unordered() is still called. */
4114FOP_CONDN_S(saf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
4115FOP_CONDN_S(sun, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)))
4116FOP_CONDN_S(seq, (float32_eq(fst0, fst1, &env->active_fpu.fp_status)))
4117FOP_CONDN_S(sueq, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
4118 || float32_eq(fst0, fst1, &env->active_fpu.fp_status)))
4119FOP_CONDN_S(slt, (float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
4120FOP_CONDN_S(sult, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
4121 || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
4122FOP_CONDN_S(sle, (float32_le(fst0, fst1, &env->active_fpu.fp_status)))
4123FOP_CONDN_S(sule, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
4124 || float32_le(fst0, fst1, &env->active_fpu.fp_status)))
4125FOP_CONDN_S(or, (float32_le_quiet(fst1, fst0, &env->active_fpu.fp_status)
4126 || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4127FOP_CONDN_S(une, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
4128 || float32_lt_quiet(fst1, fst0, &env->active_fpu.fp_status)
4129 || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4130FOP_CONDN_S(ne, (float32_lt_quiet(fst1, fst0, &env->active_fpu.fp_status)
4131 || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4132FOP_CONDN_S(sor, (float32_le(fst1, fst0, &env->active_fpu.fp_status)
4133 || float32_le(fst0, fst1, &env->active_fpu.fp_status)))
4134FOP_CONDN_S(sune, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
4135 || float32_lt(fst1, fst0, &env->active_fpu.fp_status)
4136 || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
4137FOP_CONDN_S(sne, (float32_lt(fst1, fst0, &env->active_fpu.fp_status)
4138 || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
f7685877
YK
4139
4140/* MSA */
4141/* Data format min and max values */
4142#define DF_BITS(df) (1 << ((df) + 3))
4143
4144/* Element-by-element access macros */
4145#define DF_ELEMENTS(df) (MSA_WRLEN / DF_BITS(df))
4146
adc370a4
YK
4147#if !defined(CONFIG_USER_ONLY)
4148#define MEMOP_IDX(DF) \
4149 TCGMemOpIdx oi = make_memop_idx(MO_TE | DF | MO_UNALN, \
97ed5ccd 4150 cpu_mmu_index(env, false));
adc370a4
YK
4151#else
4152#define MEMOP_IDX(DF)
4153#endif
f7685877 4154
adc370a4
YK
4155#define MSA_LD_DF(DF, TYPE, LD_INSN, ...) \
4156void helper_msa_ld_ ## TYPE(CPUMIPSState *env, uint32_t wd, \
4157 target_ulong addr) \
4158{ \
4159 wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \
4160 wr_t wx; \
4161 int i; \
4162 MEMOP_IDX(DF) \
4163 for (i = 0; i < DF_ELEMENTS(DF); i++) { \
4164 wx.TYPE[i] = LD_INSN(env, addr + (i << DF), ##__VA_ARGS__); \
4165 } \
4166 memcpy(pwd, &wx, sizeof(wr_t)); \
f7685877
YK
4167}
4168
adc370a4 4169#if !defined(CONFIG_USER_ONLY)
01ecaf43
RH
4170MSA_LD_DF(DF_BYTE, b, helper_ret_ldub_mmu, oi, GETPC())
4171MSA_LD_DF(DF_HALF, h, helper_ret_lduw_mmu, oi, GETPC())
4172MSA_LD_DF(DF_WORD, w, helper_ret_ldul_mmu, oi, GETPC())
4173MSA_LD_DF(DF_DOUBLE, d, helper_ret_ldq_mmu, oi, GETPC())
adc370a4
YK
4174#else
4175MSA_LD_DF(DF_BYTE, b, cpu_ldub_data)
4176MSA_LD_DF(DF_HALF, h, cpu_lduw_data)
4177MSA_LD_DF(DF_WORD, w, cpu_ldl_data)
4178MSA_LD_DF(DF_DOUBLE, d, cpu_ldq_data)
4179#endif
f7685877 4180
adc370a4
YK
4181#define MSA_PAGESPAN(x) \
4182 ((((x) & ~TARGET_PAGE_MASK) + MSA_WRLEN/8 - 1) >= TARGET_PAGE_SIZE)
4183
4184static inline void ensure_writable_pages(CPUMIPSState *env,
4185 target_ulong addr,
4186 int mmu_idx,
4187 uintptr_t retaddr)
4188{
4189#if !defined(CONFIG_USER_ONLY)
4190 target_ulong page_addr;
4191 if (unlikely(MSA_PAGESPAN(addr))) {
4192 /* first page */
4193 probe_write(env, addr, mmu_idx, retaddr);
4194 /* second page */
4195 page_addr = (addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
4196 probe_write(env, page_addr, mmu_idx, retaddr);
f7685877 4197 }
adc370a4 4198#endif
f7685877 4199}
adc370a4
YK
4200
4201#define MSA_ST_DF(DF, TYPE, ST_INSN, ...) \
4202void helper_msa_st_ ## TYPE(CPUMIPSState *env, uint32_t wd, \
4203 target_ulong addr) \
4204{ \
4205 wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \
97ed5ccd 4206 int mmu_idx = cpu_mmu_index(env, false); \
adc370a4
YK
4207 int i; \
4208 MEMOP_IDX(DF) \
01ecaf43 4209 ensure_writable_pages(env, addr, mmu_idx, GETPC()); \
adc370a4
YK
4210 for (i = 0; i < DF_ELEMENTS(DF); i++) { \
4211 ST_INSN(env, addr + (i << DF), pwd->TYPE[i], ##__VA_ARGS__); \
4212 } \
4213}
4214
4215#if !defined(CONFIG_USER_ONLY)
01ecaf43
RH
4216MSA_ST_DF(DF_BYTE, b, helper_ret_stb_mmu, oi, GETPC())
4217MSA_ST_DF(DF_HALF, h, helper_ret_stw_mmu, oi, GETPC())
4218MSA_ST_DF(DF_WORD, w, helper_ret_stl_mmu, oi, GETPC())
4219MSA_ST_DF(DF_DOUBLE, d, helper_ret_stq_mmu, oi, GETPC())
adc370a4
YK
4220#else
4221MSA_ST_DF(DF_BYTE, b, cpu_stb_data)
4222MSA_ST_DF(DF_HALF, h, cpu_stw_data)
4223MSA_ST_DF(DF_WORD, w, cpu_stl_data)
4224MSA_ST_DF(DF_DOUBLE, d, cpu_stq_data)
4225#endif
0d74a222
LA
4226
4227void helper_cache(CPUMIPSState *env, target_ulong addr, uint32_t op)
4228{
4229#ifndef CONFIG_USER_ONLY
4230 target_ulong index = addr & 0x1fffffff;
4231 if (op == 9) {
4232 /* Index Store Tag */
4233 memory_region_dispatch_write(env->itc_tag, index, env->CP0_TagLo,
4234 8, MEMTXATTRS_UNSPECIFIED);
4235 } else if (op == 5) {
4236 /* Index Load Tag */
4237 memory_region_dispatch_read(env->itc_tag, index, &env->CP0_TagLo,
4238 8, MEMTXATTRS_UNSPECIFIED);
4239 }
4240#endif
4241}
This page took 1.61038 seconds and 4 git commands to generate.