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