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