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