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