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