]> git.proxmox.com Git - qemu.git/blame - target-mips/op_helper.c
cpu: Make first_cpu and next_cpu CPUState
[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
AJ
1737 // arg1 = rt, arg2 = rs
1738 arg1 = 0;
f1aa6320
TS
1739 // TODO: store to TC register
1740}
1741
895c2d04 1742target_ulong helper_yield(CPUMIPSState *env, target_ulong arg)
f1aa6320 1743{
1c7242da
BS
1744 target_long arg1 = arg;
1745
d9bea114 1746 if (arg1 < 0) {
f1aa6320 1747 /* No scheduling policy implemented. */
d9bea114 1748 if (arg1 != -2) {
f1aa6320 1749 if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
b5dc7732 1750 env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
f1aa6320
TS
1751 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1752 env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
895c2d04 1753 helper_raise_exception(env, EXCP_THREAD);
f1aa6320
TS
1754 }
1755 }
d9bea114 1756 } else if (arg1 == 0) {
6958549d 1757 if (0 /* TODO: TC underflow */) {
f1aa6320 1758 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
895c2d04 1759 helper_raise_exception(env, EXCP_THREAD);
f1aa6320
TS
1760 } else {
1761 // TODO: Deallocate TC
1762 }
d9bea114 1763 } else if (arg1 > 0) {
f1aa6320
TS
1764 /* Yield qualifier inputs not implemented. */
1765 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1766 env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
895c2d04 1767 helper_raise_exception(env, EXCP_THREAD);
f1aa6320 1768 }
be24bb4f 1769 return env->CP0_YQMask;
f1aa6320
TS
1770}
1771
f1aa6320 1772#ifndef CONFIG_USER_ONLY
6af0bf9c 1773/* TLB management */
7db13fae 1774static void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global)
814b9a47
TS
1775{
1776 /* Flush qemu's TLB and discard all shadowed entries. */
1777 tlb_flush (env, flush_global);
ead9360e 1778 env->tlb->tlb_in_use = env->tlb->nb_tlb;
814b9a47
TS
1779}
1780
7db13fae 1781static void r4k_mips_tlb_flush_extra (CPUMIPSState *env, int first)
814b9a47
TS
1782{
1783 /* Discard entries from env->tlb[first] onwards. */
ead9360e
TS
1784 while (env->tlb->tlb_in_use > first) {
1785 r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
814b9a47
TS
1786 }
1787}
1788
895c2d04 1789static void r4k_fill_tlb(CPUMIPSState *env, int idx)
6af0bf9c 1790{
c227f099 1791 r4k_tlb_t *tlb;
6af0bf9c
FB
1792
1793 /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
ead9360e 1794 tlb = &env->tlb->mmu.r4k.tlb[idx];
f2e9ebef 1795 tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
d26bc211 1796#if defined(TARGET_MIPS64)
e034e2c3 1797 tlb->VPN &= env->SEGMask;
100ce988 1798#endif
98c1b82b 1799 tlb->ASID = env->CP0_EntryHi & 0xFF;
3b1c8be4 1800 tlb->PageMask = env->CP0_PageMask;
6af0bf9c 1801 tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
98c1b82b
PB
1802 tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
1803 tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
1804 tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
6af0bf9c 1805 tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
98c1b82b
PB
1806 tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
1807 tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
1808 tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
6af0bf9c
FB
1809 tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
1810}
1811
895c2d04 1812void r4k_helper_tlbwi(CPUMIPSState *env)
6af0bf9c 1813{
286d52eb 1814 r4k_tlb_t *tlb;
bbc0d79c 1815 int idx;
286d52eb
AJ
1816 target_ulong VPN;
1817 uint8_t ASID;
1818 bool G, V0, D0, V1, D1;
bbc0d79c
AJ
1819
1820 idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
286d52eb
AJ
1821 tlb = &env->tlb->mmu.r4k.tlb[idx];
1822 VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
1823#if defined(TARGET_MIPS64)
1824 VPN &= env->SEGMask;
1825#endif
1826 ASID = env->CP0_EntryHi & 0xff;
1827 G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
1828 V0 = (env->CP0_EntryLo0 & 2) != 0;
1829 D0 = (env->CP0_EntryLo0 & 4) != 0;
1830 V1 = (env->CP0_EntryLo1 & 2) != 0;
1831 D1 = (env->CP0_EntryLo1 & 4) != 0;
1832
1833 /* Discard cached TLB entries, unless tlbwi is just upgrading access
1834 permissions on the current entry. */
1835 if (tlb->VPN != VPN || tlb->ASID != ASID || tlb->G != G ||
1836 (tlb->V0 && !V0) || (tlb->D0 && !D0) ||
1837 (tlb->V1 && !V1) || (tlb->D1 && !D1)) {
1838 r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
1839 }
814b9a47 1840
bbc0d79c 1841 r4k_invalidate_tlb(env, idx, 0);
895c2d04 1842 r4k_fill_tlb(env, idx);
6af0bf9c
FB
1843}
1844
895c2d04 1845void r4k_helper_tlbwr(CPUMIPSState *env)
6af0bf9c
FB
1846{
1847 int r = cpu_mips_get_random(env);
1848
29929e34 1849 r4k_invalidate_tlb(env, r, 1);
895c2d04 1850 r4k_fill_tlb(env, r);
6af0bf9c
FB
1851}
1852
895c2d04 1853void r4k_helper_tlbp(CPUMIPSState *env)
6af0bf9c 1854{
c227f099 1855 r4k_tlb_t *tlb;
f2e9ebef 1856 target_ulong mask;
6af0bf9c 1857 target_ulong tag;
f2e9ebef 1858 target_ulong VPN;
6af0bf9c
FB
1859 uint8_t ASID;
1860 int i;
1861
3d9fb9fe 1862 ASID = env->CP0_EntryHi & 0xFF;
ead9360e
TS
1863 for (i = 0; i < env->tlb->nb_tlb; i++) {
1864 tlb = &env->tlb->mmu.r4k.tlb[i];
f2e9ebef
TS
1865 /* 1k pages are not supported. */
1866 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
1867 tag = env->CP0_EntryHi & ~mask;
1868 VPN = tlb->VPN & ~mask;
bc3e45e1
AJ
1869#if defined(TARGET_MIPS64)
1870 tag &= env->SEGMask;
1871#endif
6af0bf9c 1872 /* Check ASID, virtual page number & size */
f2e9ebef 1873 if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
6af0bf9c 1874 /* TLB match */
9c2149c8 1875 env->CP0_Index = i;
6af0bf9c
FB
1876 break;
1877 }
1878 }
ead9360e 1879 if (i == env->tlb->nb_tlb) {
814b9a47 1880 /* No match. Discard any shadow entries, if any of them match. */
ead9360e 1881 for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
6958549d
AJ
1882 tlb = &env->tlb->mmu.r4k.tlb[i];
1883 /* 1k pages are not supported. */
1884 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
1885 tag = env->CP0_EntryHi & ~mask;
1886 VPN = tlb->VPN & ~mask;
bc3e45e1
AJ
1887#if defined(TARGET_MIPS64)
1888 tag &= env->SEGMask;
1889#endif
6958549d
AJ
1890 /* Check ASID, virtual page number & size */
1891 if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
29929e34 1892 r4k_mips_tlb_flush_extra (env, i);
6958549d
AJ
1893 break;
1894 }
1895 }
814b9a47 1896
9c2149c8 1897 env->CP0_Index |= 0x80000000;
6af0bf9c
FB
1898 }
1899}
1900
895c2d04 1901void r4k_helper_tlbr(CPUMIPSState *env)
6af0bf9c 1902{
c227f099 1903 r4k_tlb_t *tlb;
09c56b84 1904 uint8_t ASID;
bbc0d79c 1905 int idx;
6af0bf9c 1906
09c56b84 1907 ASID = env->CP0_EntryHi & 0xFF;
bbc0d79c
AJ
1908 idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
1909 tlb = &env->tlb->mmu.r4k.tlb[idx];
4ad40f36
FB
1910
1911 /* If this will change the current ASID, flush qemu's TLB. */
814b9a47
TS
1912 if (ASID != tlb->ASID)
1913 cpu_mips_tlb_flush (env, 1);
1914
ead9360e 1915 r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
4ad40f36 1916
6af0bf9c 1917 env->CP0_EntryHi = tlb->VPN | tlb->ASID;
3b1c8be4 1918 env->CP0_PageMask = tlb->PageMask;
7495fd0f
TS
1919 env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
1920 (tlb->C0 << 3) | (tlb->PFN[0] >> 6);
1921 env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
1922 (tlb->C1 << 3) | (tlb->PFN[1] >> 6);
6af0bf9c 1923}
6af0bf9c 1924
895c2d04 1925void helper_tlbwi(CPUMIPSState *env)
a7812ae4 1926{
895c2d04 1927 env->tlb->helper_tlbwi(env);
a7812ae4
PB
1928}
1929
895c2d04 1930void helper_tlbwr(CPUMIPSState *env)
a7812ae4 1931{
895c2d04 1932 env->tlb->helper_tlbwr(env);
a7812ae4
PB
1933}
1934
895c2d04 1935void helper_tlbp(CPUMIPSState *env)
a7812ae4 1936{
895c2d04 1937 env->tlb->helper_tlbp(env);
a7812ae4
PB
1938}
1939
895c2d04 1940void helper_tlbr(CPUMIPSState *env)
a7812ae4 1941{
895c2d04 1942 env->tlb->helper_tlbr(env);
a7812ae4
PB
1943}
1944
2b0233ab 1945/* Specials */
895c2d04 1946target_ulong helper_di(CPUMIPSState *env)
2b0233ab 1947{
2796188e
TS
1948 target_ulong t0 = env->CP0_Status;
1949
be24bb4f 1950 env->CP0_Status = t0 & ~(1 << CP0St_IE);
be24bb4f 1951 return t0;
2b0233ab
TS
1952}
1953
895c2d04 1954target_ulong helper_ei(CPUMIPSState *env)
2b0233ab 1955{
2796188e
TS
1956 target_ulong t0 = env->CP0_Status;
1957
be24bb4f 1958 env->CP0_Status = t0 | (1 << CP0St_IE);
be24bb4f 1959 return t0;
2b0233ab
TS
1960}
1961
895c2d04 1962static void debug_pre_eret(CPUMIPSState *env)
6af0bf9c 1963{
8fec2b8c 1964 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
93fcfe39
AL
1965 qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
1966 env->active_tc.PC, env->CP0_EPC);
1967 if (env->CP0_Status & (1 << CP0St_ERL))
1968 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
1969 if (env->hflags & MIPS_HFLAG_DM)
1970 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
1971 qemu_log("\n");
1972 }
f41c52f1
TS
1973}
1974
895c2d04 1975static void debug_post_eret(CPUMIPSState *env)
f41c52f1 1976{
8fec2b8c 1977 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
93fcfe39
AL
1978 qemu_log(" => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
1979 env->active_tc.PC, env->CP0_EPC);
1980 if (env->CP0_Status & (1 << CP0St_ERL))
1981 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
1982 if (env->hflags & MIPS_HFLAG_DM)
1983 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
1984 switch (env->hflags & MIPS_HFLAG_KSU) {
1985 case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
1986 case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
1987 case MIPS_HFLAG_KM: qemu_log("\n"); break;
1988 default: cpu_abort(env, "Invalid MMU mode!\n"); break;
1989 }
623a930e 1990 }
6af0bf9c
FB
1991}
1992
895c2d04 1993static void set_pc(CPUMIPSState *env, target_ulong error_pc)
32188a03
NF
1994{
1995 env->active_tc.PC = error_pc & ~(target_ulong)1;
1996 if (error_pc & 1) {
1997 env->hflags |= MIPS_HFLAG_M16;
1998 } else {
1999 env->hflags &= ~(MIPS_HFLAG_M16);
2000 }
2001}
2002
895c2d04 2003void helper_eret(CPUMIPSState *env)
2b0233ab 2004{
895c2d04 2005 debug_pre_eret(env);
2b0233ab 2006 if (env->CP0_Status & (1 << CP0St_ERL)) {
895c2d04 2007 set_pc(env, env->CP0_ErrorEPC);
2b0233ab
TS
2008 env->CP0_Status &= ~(1 << CP0St_ERL);
2009 } else {
895c2d04 2010 set_pc(env, env->CP0_EPC);
2b0233ab
TS
2011 env->CP0_Status &= ~(1 << CP0St_EXL);
2012 }
2013 compute_hflags(env);
895c2d04 2014 debug_post_eret(env);
5499b6ff 2015 env->lladdr = 1;
2b0233ab
TS
2016}
2017
895c2d04 2018void helper_deret(CPUMIPSState *env)
2b0233ab 2019{
895c2d04
BS
2020 debug_pre_eret(env);
2021 set_pc(env, env->CP0_DEPC);
32188a03 2022
2b0233ab
TS
2023 env->hflags &= MIPS_HFLAG_DM;
2024 compute_hflags(env);
895c2d04 2025 debug_post_eret(env);
5499b6ff 2026 env->lladdr = 1;
2b0233ab 2027}
0eaef5aa 2028#endif /* !CONFIG_USER_ONLY */
2b0233ab 2029
895c2d04 2030target_ulong helper_rdhwr_cpunum(CPUMIPSState *env)
2b0233ab
TS
2031{
2032 if ((env->hflags & MIPS_HFLAG_CP0) ||
2033 (env->CP0_HWREna & (1 << 0)))
2796188e 2034 return env->CP0_EBase & 0x3ff;
2b0233ab 2035 else
895c2d04 2036 helper_raise_exception(env, EXCP_RI);
be24bb4f 2037
2796188e 2038 return 0;
2b0233ab
TS
2039}
2040
895c2d04 2041target_ulong helper_rdhwr_synci_step(CPUMIPSState *env)
2b0233ab
TS
2042{
2043 if ((env->hflags & MIPS_HFLAG_CP0) ||
2044 (env->CP0_HWREna & (1 << 1)))
2796188e 2045 return env->SYNCI_Step;
2b0233ab 2046 else
895c2d04 2047 helper_raise_exception(env, EXCP_RI);
be24bb4f 2048
2796188e 2049 return 0;
2b0233ab
TS
2050}
2051
895c2d04 2052target_ulong helper_rdhwr_cc(CPUMIPSState *env)
2b0233ab
TS
2053{
2054 if ((env->hflags & MIPS_HFLAG_CP0) ||
2055 (env->CP0_HWREna & (1 << 2)))
2796188e 2056 return env->CP0_Count;
2b0233ab 2057 else
895c2d04 2058 helper_raise_exception(env, EXCP_RI);
be24bb4f 2059
2796188e 2060 return 0;
2b0233ab
TS
2061}
2062
895c2d04 2063target_ulong helper_rdhwr_ccres(CPUMIPSState *env)
2b0233ab
TS
2064{
2065 if ((env->hflags & MIPS_HFLAG_CP0) ||
2066 (env->CP0_HWREna & (1 << 3)))
2796188e 2067 return env->CCRes;
2b0233ab 2068 else
895c2d04 2069 helper_raise_exception(env, EXCP_RI);
be24bb4f 2070
2796188e 2071 return 0;
2b0233ab
TS
2072}
2073
895c2d04 2074void helper_pmon(CPUMIPSState *env, int function)
6af0bf9c
FB
2075{
2076 function /= 2;
2077 switch (function) {
2078 case 2: /* TODO: char inbyte(int waitflag); */
b5dc7732
TS
2079 if (env->active_tc.gpr[4] == 0)
2080 env->active_tc.gpr[2] = -1;
6af0bf9c
FB
2081 /* Fall through */
2082 case 11: /* TODO: char inbyte (void); */
b5dc7732 2083 env->active_tc.gpr[2] = -1;
6af0bf9c
FB
2084 break;
2085 case 3:
2086 case 12:
b5dc7732 2087 printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
6af0bf9c
FB
2088 break;
2089 case 17:
2090 break;
2091 case 158:
2092 {
b69e48a8 2093 unsigned char *fmt = (void *)(uintptr_t)env->active_tc.gpr[4];
6af0bf9c
FB
2094 printf("%s", fmt);
2095 }
2096 break;
2097 }
2098}
e37e863f 2099
895c2d04 2100void helper_wait(CPUMIPSState *env)
08ba7963 2101{
259186a7
AF
2102 CPUState *cs = CPU(mips_env_get_cpu(env));
2103
2104 cs->halted = 1;
d8ed887b 2105 cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
895c2d04 2106 helper_raise_exception(env, EXCP_HLT);
08ba7963
TS
2107}
2108
5fafdf24 2109#if !defined(CONFIG_USER_ONLY)
e37e863f 2110
895c2d04
BS
2111static void QEMU_NORETURN do_unaligned_access(CPUMIPSState *env,
2112 target_ulong addr, int is_write,
20503968 2113 int is_user, uintptr_t retaddr);
4ad40f36 2114
e37e863f 2115#define MMUSUFFIX _mmu
4ad40f36 2116#define ALIGNED_ONLY
e37e863f
FB
2117
2118#define SHIFT 0
022c62cb 2119#include "exec/softmmu_template.h"
e37e863f
FB
2120
2121#define SHIFT 1
022c62cb 2122#include "exec/softmmu_template.h"
e37e863f
FB
2123
2124#define SHIFT 2
022c62cb 2125#include "exec/softmmu_template.h"
e37e863f
FB
2126
2127#define SHIFT 3
022c62cb 2128#include "exec/softmmu_template.h"
e37e863f 2129
895c2d04
BS
2130static void do_unaligned_access(CPUMIPSState *env, target_ulong addr,
2131 int is_write, int is_user, uintptr_t retaddr)
4ad40f36
FB
2132{
2133 env->CP0_BadVAddr = addr;
5f7319cd 2134 do_raise_exception(env, (is_write == 1) ? EXCP_AdES : EXCP_AdEL, retaddr);
4ad40f36
FB
2135}
2136
895c2d04 2137void tlb_fill(CPUMIPSState *env, target_ulong addr, int is_write, int mmu_idx,
20503968 2138 uintptr_t retaddr)
e37e863f 2139{
e37e863f
FB
2140 int ret;
2141
97b348e7 2142 ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx);
e37e863f 2143 if (ret) {
5f7319cd
AJ
2144 do_raise_exception_err(env, env->exception_index,
2145 env->error_code, retaddr);
e37e863f 2146 }
e37e863f
FB
2147}
2148
c658b94f
AF
2149void mips_cpu_unassigned_access(CPUState *cs, hwaddr addr,
2150 bool is_write, bool is_exec, int unused,
2151 unsigned size)
647de6ca 2152{
c658b94f
AF
2153 MIPSCPU *cpu = MIPS_CPU(cs);
2154 CPUMIPSState *env = &cpu->env;
2155
2156 if (is_exec) {
895c2d04 2157 helper_raise_exception(env, EXCP_IBE);
c658b94f 2158 } else {
895c2d04 2159 helper_raise_exception(env, EXCP_DBE);
c658b94f 2160 }
647de6ca 2161}
f1aa6320 2162#endif /* !CONFIG_USER_ONLY */
fd4a04eb
TS
2163
2164/* Complex FPU operations which may need stack space. */
2165
f090c9d4
PB
2166#define FLOAT_TWO32 make_float32(1 << 30)
2167#define FLOAT_TWO64 make_float64(1ULL << 62)
05993cd0
AJ
2168#define FP_TO_INT32_OVERFLOW 0x7fffffff
2169#define FP_TO_INT64_OVERFLOW 0x7fffffffffffffffULL
8dfdb87c 2170
fd4a04eb 2171/* convert MIPS rounding mode in FCR31 to IEEE library */
6f4fc367 2172static unsigned int ieee_rm[] = {
fd4a04eb
TS
2173 float_round_nearest_even,
2174 float_round_to_zero,
2175 float_round_up,
2176 float_round_down
2177};
2178
e320d05a
SW
2179static inline void restore_rounding_mode(CPUMIPSState *env)
2180{
2181 set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3],
2182 &env->active_fpu.fp_status);
2183}
fd4a04eb 2184
e320d05a
SW
2185static inline void restore_flush_mode(CPUMIPSState *env)
2186{
2187 set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0,
2188 &env->active_fpu.fp_status);
2189}
41e0c701 2190
895c2d04 2191target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg)
fd4a04eb 2192{
d9bea114 2193 target_ulong arg1;
6c5c1e20 2194
ead9360e
TS
2195 switch (reg) {
2196 case 0:
d9bea114 2197 arg1 = (int32_t)env->active_fpu.fcr0;
ead9360e
TS
2198 break;
2199 case 25:
d9bea114 2200 arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
ead9360e
TS
2201 break;
2202 case 26:
d9bea114 2203 arg1 = env->active_fpu.fcr31 & 0x0003f07c;
ead9360e
TS
2204 break;
2205 case 28:
d9bea114 2206 arg1 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4);
ead9360e
TS
2207 break;
2208 default:
d9bea114 2209 arg1 = (int32_t)env->active_fpu.fcr31;
ead9360e
TS
2210 break;
2211 }
be24bb4f 2212
d9bea114 2213 return arg1;
ead9360e
TS
2214}
2215
895c2d04 2216void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t reg)
ead9360e
TS
2217{
2218 switch(reg) {
fd4a04eb 2219 case 25:
d9bea114 2220 if (arg1 & 0xffffff00)
fd4a04eb 2221 return;
d9bea114
AJ
2222 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
2223 ((arg1 & 0x1) << 23);
fd4a04eb
TS
2224 break;
2225 case 26:
d9bea114 2226 if (arg1 & 0x007c0000)
fd4a04eb 2227 return;
d9bea114 2228 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (arg1 & 0x0003f07c);
fd4a04eb
TS
2229 break;
2230 case 28:
d9bea114 2231 if (arg1 & 0x007c0000)
fd4a04eb 2232 return;
d9bea114
AJ
2233 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (arg1 & 0x00000f83) |
2234 ((arg1 & 0x4) << 22);
fd4a04eb
TS
2235 break;
2236 case 31:
d9bea114 2237 if (arg1 & 0x007c0000)
fd4a04eb 2238 return;
d9bea114 2239 env->active_fpu.fcr31 = arg1;
fd4a04eb
TS
2240 break;
2241 default:
2242 return;
2243 }
2244 /* set rounding mode */
e320d05a 2245 restore_rounding_mode(env);
41e0c701 2246 /* set flush-to-zero mode */
e320d05a 2247 restore_flush_mode(env);
f01be154
TS
2248 set_float_exception_flags(0, &env->active_fpu.fp_status);
2249 if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31))
5f7319cd 2250 do_raise_exception(env, EXCP_FPE, GETPC());
fd4a04eb
TS
2251}
2252
353ebb7a 2253static inline int ieee_ex_to_mips(int xcpt)
fd4a04eb 2254{
353ebb7a
AJ
2255 int ret = 0;
2256 if (xcpt) {
2257 if (xcpt & float_flag_invalid) {
2258 ret |= FP_INVALID;
2259 }
2260 if (xcpt & float_flag_overflow) {
2261 ret |= FP_OVERFLOW;
2262 }
2263 if (xcpt & float_flag_underflow) {
2264 ret |= FP_UNDERFLOW;
2265 }
2266 if (xcpt & float_flag_divbyzero) {
2267 ret |= FP_DIV0;
2268 }
2269 if (xcpt & float_flag_inexact) {
2270 ret |= FP_INEXACT;
2271 }
2272 }
2273 return ret;
fd4a04eb
TS
2274}
2275
5f7319cd 2276static inline void update_fcr31(CPUMIPSState *env, uintptr_t pc)
fd4a04eb 2277{
f01be154 2278 int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
fd4a04eb 2279
f01be154 2280 SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
4a587b2c
AJ
2281
2282 if (tmp) {
2283 set_float_exception_flags(0, &env->active_fpu.fp_status);
2284
2285 if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp) {
5f7319cd 2286 do_raise_exception(env, EXCP_FPE, pc);
4a587b2c
AJ
2287 } else {
2288 UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
2289 }
2290 }
fd4a04eb
TS
2291}
2292
a16336e4
TS
2293/* Float support.
2294 Single precition routines have a "s" suffix, double precision a
2295 "d" suffix, 32bit integer "w", 64bit integer "l", paired single "ps",
2296 paired single lower "pl", paired single upper "pu". */
2297
a16336e4 2298/* unary operations, modifying fp status */
895c2d04 2299uint64_t helper_float_sqrt_d(CPUMIPSState *env, uint64_t fdt0)
b6d96bed 2300{
5dbe90bb 2301 fdt0 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
5f7319cd 2302 update_fcr31(env, GETPC());
5dbe90bb 2303 return fdt0;
b6d96bed
TS
2304}
2305
895c2d04 2306uint32_t helper_float_sqrt_s(CPUMIPSState *env, uint32_t fst0)
b6d96bed 2307{
5dbe90bb 2308 fst0 = float32_sqrt(fst0, &env->active_fpu.fp_status);
5f7319cd 2309 update_fcr31(env, GETPC());
5dbe90bb 2310 return fst0;
b6d96bed 2311}
a16336e4 2312
895c2d04 2313uint64_t helper_float_cvtd_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2314{
b6d96bed
TS
2315 uint64_t fdt2;
2316
f01be154 2317 fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
5f7319cd 2318 update_fcr31(env, GETPC());
b6d96bed 2319 return fdt2;
fd4a04eb 2320}
b6d96bed 2321
895c2d04 2322uint64_t helper_float_cvtd_w(CPUMIPSState *env, uint32_t wt0)
fd4a04eb 2323{
b6d96bed
TS
2324 uint64_t fdt2;
2325
f01be154 2326 fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
5f7319cd 2327 update_fcr31(env, GETPC());
b6d96bed 2328 return fdt2;
fd4a04eb 2329}
b6d96bed 2330
895c2d04 2331uint64_t helper_float_cvtd_l(CPUMIPSState *env, uint64_t dt0)
fd4a04eb 2332{
b6d96bed
TS
2333 uint64_t fdt2;
2334
f01be154 2335 fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
5f7319cd 2336 update_fcr31(env, GETPC());
b6d96bed 2337 return fdt2;
fd4a04eb 2338}
b6d96bed 2339
895c2d04 2340uint64_t helper_float_cvtl_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2341{
b6d96bed
TS
2342 uint64_t dt2;
2343
f01be154 2344 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2345 if (get_float_exception_flags(&env->active_fpu.fp_status)
2346 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2347 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2348 }
5f7319cd 2349 update_fcr31(env, GETPC());
b6d96bed 2350 return dt2;
fd4a04eb 2351}
b6d96bed 2352
895c2d04 2353uint64_t helper_float_cvtl_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2354{
b6d96bed
TS
2355 uint64_t dt2;
2356
f01be154 2357 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2358 if (get_float_exception_flags(&env->active_fpu.fp_status)
2359 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2360 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2361 }
5f7319cd 2362 update_fcr31(env, GETPC());
b6d96bed 2363 return dt2;
fd4a04eb
TS
2364}
2365
895c2d04 2366uint64_t helper_float_cvtps_pw(CPUMIPSState *env, uint64_t dt0)
fd4a04eb 2367{
b6d96bed
TS
2368 uint32_t fst2;
2369 uint32_t fsth2;
2370
f01be154
TS
2371 fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2372 fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status);
5f7319cd 2373 update_fcr31(env, GETPC());
b6d96bed 2374 return ((uint64_t)fsth2 << 32) | fst2;
fd4a04eb 2375}
b6d96bed 2376
895c2d04 2377uint64_t helper_float_cvtpw_ps(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2378{
b6d96bed
TS
2379 uint32_t wt2;
2380 uint32_t wth2;
5dbe90bb 2381 int excp, excph;
b6d96bed 2382
f01be154 2383 wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
5dbe90bb
AJ
2384 excp = get_float_exception_flags(&env->active_fpu.fp_status);
2385 if (excp & (float_flag_overflow | float_flag_invalid)) {
05993cd0 2386 wt2 = FP_TO_INT32_OVERFLOW;
5dbe90bb
AJ
2387 }
2388
2389 set_float_exception_flags(0, &env->active_fpu.fp_status);
2390 wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status);
2391 excph = get_float_exception_flags(&env->active_fpu.fp_status);
2392 if (excph & (float_flag_overflow | float_flag_invalid)) {
05993cd0 2393 wth2 = FP_TO_INT32_OVERFLOW;
b6d96bed 2394 }
5dbe90bb
AJ
2395
2396 set_float_exception_flags(excp | excph, &env->active_fpu.fp_status);
5f7319cd 2397 update_fcr31(env, GETPC());
5dbe90bb 2398
b6d96bed 2399 return ((uint64_t)wth2 << 32) | wt2;
fd4a04eb 2400}
b6d96bed 2401
895c2d04 2402uint32_t helper_float_cvts_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2403{
b6d96bed
TS
2404 uint32_t fst2;
2405
f01be154 2406 fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
5f7319cd 2407 update_fcr31(env, GETPC());
b6d96bed 2408 return fst2;
fd4a04eb 2409}
b6d96bed 2410
895c2d04 2411uint32_t helper_float_cvts_w(CPUMIPSState *env, uint32_t wt0)
fd4a04eb 2412{
b6d96bed
TS
2413 uint32_t fst2;
2414
f01be154 2415 fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status);
5f7319cd 2416 update_fcr31(env, GETPC());
b6d96bed 2417 return fst2;
fd4a04eb 2418}
b6d96bed 2419
895c2d04 2420uint32_t helper_float_cvts_l(CPUMIPSState *env, uint64_t dt0)
fd4a04eb 2421{
b6d96bed
TS
2422 uint32_t fst2;
2423
f01be154 2424 fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status);
5f7319cd 2425 update_fcr31(env, GETPC());
b6d96bed 2426 return fst2;
fd4a04eb 2427}
b6d96bed 2428
895c2d04 2429uint32_t helper_float_cvts_pl(CPUMIPSState *env, uint32_t wt0)
fd4a04eb 2430{
b6d96bed
TS
2431 uint32_t wt2;
2432
b6d96bed 2433 wt2 = wt0;
5f7319cd 2434 update_fcr31(env, GETPC());
b6d96bed 2435 return wt2;
fd4a04eb 2436}
b6d96bed 2437
895c2d04 2438uint32_t helper_float_cvts_pu(CPUMIPSState *env, uint32_t wth0)
fd4a04eb 2439{
b6d96bed
TS
2440 uint32_t wt2;
2441
b6d96bed 2442 wt2 = wth0;
5f7319cd 2443 update_fcr31(env, GETPC());
b6d96bed 2444 return wt2;
fd4a04eb 2445}
b6d96bed 2446
895c2d04 2447uint32_t helper_float_cvtw_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2448{
b6d96bed
TS
2449 uint32_t wt2;
2450
f01be154 2451 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
5f7319cd 2452 update_fcr31(env, GETPC());
4cc2e5f9
AJ
2453 if (get_float_exception_flags(&env->active_fpu.fp_status)
2454 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2455 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2456 }
b6d96bed 2457 return wt2;
fd4a04eb 2458}
b6d96bed 2459
895c2d04 2460uint32_t helper_float_cvtw_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2461{
b6d96bed
TS
2462 uint32_t wt2;
2463
f01be154 2464 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2465 if (get_float_exception_flags(&env->active_fpu.fp_status)
2466 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2467 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2468 }
5f7319cd 2469 update_fcr31(env, GETPC());
b6d96bed 2470 return wt2;
fd4a04eb
TS
2471}
2472
895c2d04 2473uint64_t helper_float_roundl_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2474{
b6d96bed
TS
2475 uint64_t dt2;
2476
f01be154
TS
2477 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2478 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
e320d05a 2479 restore_rounding_mode(env);
4cc2e5f9
AJ
2480 if (get_float_exception_flags(&env->active_fpu.fp_status)
2481 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2482 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2483 }
5f7319cd 2484 update_fcr31(env, GETPC());
b6d96bed 2485 return dt2;
fd4a04eb 2486}
b6d96bed 2487
895c2d04 2488uint64_t helper_float_roundl_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2489{
b6d96bed
TS
2490 uint64_t dt2;
2491
f01be154
TS
2492 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2493 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
e320d05a 2494 restore_rounding_mode(env);
4cc2e5f9
AJ
2495 if (get_float_exception_flags(&env->active_fpu.fp_status)
2496 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2497 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2498 }
5f7319cd 2499 update_fcr31(env, GETPC());
b6d96bed 2500 return dt2;
fd4a04eb 2501}
b6d96bed 2502
895c2d04 2503uint32_t helper_float_roundw_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2504{
b6d96bed
TS
2505 uint32_t wt2;
2506
f01be154
TS
2507 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2508 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
e320d05a 2509 restore_rounding_mode(env);
4cc2e5f9
AJ
2510 if (get_float_exception_flags(&env->active_fpu.fp_status)
2511 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2512 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2513 }
5f7319cd 2514 update_fcr31(env, GETPC());
b6d96bed 2515 return wt2;
fd4a04eb 2516}
b6d96bed 2517
895c2d04 2518uint32_t helper_float_roundw_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2519{
b6d96bed
TS
2520 uint32_t wt2;
2521
f01be154
TS
2522 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2523 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
e320d05a 2524 restore_rounding_mode(env);
4cc2e5f9
AJ
2525 if (get_float_exception_flags(&env->active_fpu.fp_status)
2526 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2527 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2528 }
5f7319cd 2529 update_fcr31(env, GETPC());
b6d96bed 2530 return wt2;
fd4a04eb
TS
2531}
2532
895c2d04 2533uint64_t helper_float_truncl_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2534{
b6d96bed
TS
2535 uint64_t dt2;
2536
f01be154 2537 dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2538 if (get_float_exception_flags(&env->active_fpu.fp_status)
2539 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2540 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2541 }
5f7319cd 2542 update_fcr31(env, GETPC());
b6d96bed 2543 return dt2;
fd4a04eb 2544}
b6d96bed 2545
895c2d04 2546uint64_t helper_float_truncl_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2547{
b6d96bed
TS
2548 uint64_t dt2;
2549
f01be154 2550 dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2551 if (get_float_exception_flags(&env->active_fpu.fp_status)
2552 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2553 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2554 }
5f7319cd 2555 update_fcr31(env, GETPC());
b6d96bed 2556 return dt2;
fd4a04eb 2557}
b6d96bed 2558
895c2d04 2559uint32_t helper_float_truncw_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2560{
b6d96bed
TS
2561 uint32_t wt2;
2562
f01be154 2563 wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2564 if (get_float_exception_flags(&env->active_fpu.fp_status)
2565 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2566 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2567 }
5f7319cd 2568 update_fcr31(env, GETPC());
b6d96bed 2569 return wt2;
fd4a04eb 2570}
b6d96bed 2571
895c2d04 2572uint32_t helper_float_truncw_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2573{
b6d96bed
TS
2574 uint32_t wt2;
2575
f01be154 2576 wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2577 if (get_float_exception_flags(&env->active_fpu.fp_status)
2578 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2579 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2580 }
5f7319cd 2581 update_fcr31(env, GETPC());
b6d96bed 2582 return wt2;
fd4a04eb
TS
2583}
2584
895c2d04 2585uint64_t helper_float_ceill_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2586{
b6d96bed
TS
2587 uint64_t dt2;
2588
f01be154
TS
2589 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2590 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
e320d05a 2591 restore_rounding_mode(env);
4cc2e5f9
AJ
2592 if (get_float_exception_flags(&env->active_fpu.fp_status)
2593 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2594 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2595 }
5f7319cd 2596 update_fcr31(env, GETPC());
b6d96bed 2597 return dt2;
fd4a04eb 2598}
b6d96bed 2599
895c2d04 2600uint64_t helper_float_ceill_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2601{
b6d96bed
TS
2602 uint64_t dt2;
2603
f01be154
TS
2604 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2605 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
e320d05a 2606 restore_rounding_mode(env);
4cc2e5f9
AJ
2607 if (get_float_exception_flags(&env->active_fpu.fp_status)
2608 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2609 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2610 }
5f7319cd 2611 update_fcr31(env, GETPC());
b6d96bed 2612 return dt2;
fd4a04eb 2613}
b6d96bed 2614
895c2d04 2615uint32_t helper_float_ceilw_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2616{
b6d96bed
TS
2617 uint32_t wt2;
2618
f01be154
TS
2619 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2620 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
e320d05a 2621 restore_rounding_mode(env);
4cc2e5f9
AJ
2622 if (get_float_exception_flags(&env->active_fpu.fp_status)
2623 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2624 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2625 }
5f7319cd 2626 update_fcr31(env, GETPC());
b6d96bed 2627 return wt2;
fd4a04eb 2628}
b6d96bed 2629
895c2d04 2630uint32_t helper_float_ceilw_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2631{
b6d96bed
TS
2632 uint32_t wt2;
2633
f01be154
TS
2634 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2635 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
e320d05a 2636 restore_rounding_mode(env);
4cc2e5f9
AJ
2637 if (get_float_exception_flags(&env->active_fpu.fp_status)
2638 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2639 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2640 }
5f7319cd 2641 update_fcr31(env, GETPC());
b6d96bed 2642 return wt2;
fd4a04eb
TS
2643}
2644
895c2d04 2645uint64_t helper_float_floorl_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2646{
b6d96bed
TS
2647 uint64_t dt2;
2648
f01be154
TS
2649 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2650 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
e320d05a 2651 restore_rounding_mode(env);
4cc2e5f9
AJ
2652 if (get_float_exception_flags(&env->active_fpu.fp_status)
2653 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2654 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2655 }
5f7319cd 2656 update_fcr31(env, GETPC());
b6d96bed 2657 return dt2;
fd4a04eb 2658}
b6d96bed 2659
895c2d04 2660uint64_t helper_float_floorl_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2661{
b6d96bed
TS
2662 uint64_t dt2;
2663
f01be154
TS
2664 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2665 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
e320d05a 2666 restore_rounding_mode(env);
4cc2e5f9
AJ
2667 if (get_float_exception_flags(&env->active_fpu.fp_status)
2668 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2669 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2670 }
5f7319cd 2671 update_fcr31(env, GETPC());
b6d96bed 2672 return dt2;
fd4a04eb 2673}
b6d96bed 2674
895c2d04 2675uint32_t helper_float_floorw_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2676{
b6d96bed
TS
2677 uint32_t wt2;
2678
f01be154
TS
2679 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2680 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
e320d05a 2681 restore_rounding_mode(env);
4cc2e5f9
AJ
2682 if (get_float_exception_flags(&env->active_fpu.fp_status)
2683 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2684 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2685 }
5f7319cd 2686 update_fcr31(env, GETPC());
b6d96bed 2687 return wt2;
fd4a04eb 2688}
b6d96bed 2689
895c2d04 2690uint32_t helper_float_floorw_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2691{
b6d96bed
TS
2692 uint32_t wt2;
2693
f01be154
TS
2694 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2695 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
e320d05a 2696 restore_rounding_mode(env);
4cc2e5f9
AJ
2697 if (get_float_exception_flags(&env->active_fpu.fp_status)
2698 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2699 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2700 }
5f7319cd 2701 update_fcr31(env, GETPC());
b6d96bed 2702 return wt2;
fd4a04eb
TS
2703}
2704
a16336e4 2705/* unary operations, not modifying fp status */
b6d96bed 2706#define FLOAT_UNOP(name) \
c01fccd2 2707uint64_t helper_float_ ## name ## _d(uint64_t fdt0) \
b6d96bed
TS
2708{ \
2709 return float64_ ## name(fdt0); \
2710} \
c01fccd2 2711uint32_t helper_float_ ## name ## _s(uint32_t fst0) \
b6d96bed
TS
2712{ \
2713 return float32_ ## name(fst0); \
2714} \
c01fccd2 2715uint64_t helper_float_ ## name ## _ps(uint64_t fdt0) \
b6d96bed
TS
2716{ \
2717 uint32_t wt0; \
2718 uint32_t wth0; \
2719 \
2720 wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF); \
2721 wth0 = float32_ ## name(fdt0 >> 32); \
2722 return ((uint64_t)wth0 << 32) | wt0; \
a16336e4
TS
2723}
2724FLOAT_UNOP(abs)
2725FLOAT_UNOP(chs)
2726#undef FLOAT_UNOP
2727
8dfdb87c 2728/* MIPS specific unary operations */
895c2d04 2729uint64_t helper_float_recip_d(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 2730{
b6d96bed
TS
2731 uint64_t fdt2;
2732
05993cd0 2733 fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
5f7319cd 2734 update_fcr31(env, GETPC());
b6d96bed 2735 return fdt2;
8dfdb87c 2736}
b6d96bed 2737
895c2d04 2738uint32_t helper_float_recip_s(CPUMIPSState *env, uint32_t fst0)
8dfdb87c 2739{
b6d96bed
TS
2740 uint32_t fst2;
2741
05993cd0 2742 fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
5f7319cd 2743 update_fcr31(env, GETPC());
b6d96bed 2744 return fst2;
57fa1fb3 2745}
57fa1fb3 2746
895c2d04 2747uint64_t helper_float_rsqrt_d(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 2748{
b6d96bed
TS
2749 uint64_t fdt2;
2750
f01be154 2751 fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
05993cd0 2752 fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
5f7319cd 2753 update_fcr31(env, GETPC());
b6d96bed 2754 return fdt2;
8dfdb87c 2755}
b6d96bed 2756
895c2d04 2757uint32_t helper_float_rsqrt_s(CPUMIPSState *env, uint32_t fst0)
8dfdb87c 2758{
b6d96bed
TS
2759 uint32_t fst2;
2760
f01be154 2761 fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
05993cd0 2762 fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
5f7319cd 2763 update_fcr31(env, GETPC());
b6d96bed 2764 return fst2;
8dfdb87c
TS
2765}
2766
895c2d04 2767uint64_t helper_float_recip1_d(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 2768{
b6d96bed
TS
2769 uint64_t fdt2;
2770
05993cd0 2771 fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
5f7319cd 2772 update_fcr31(env, GETPC());
b6d96bed 2773 return fdt2;
8dfdb87c 2774}
b6d96bed 2775
895c2d04 2776uint32_t helper_float_recip1_s(CPUMIPSState *env, uint32_t fst0)
8dfdb87c 2777{
b6d96bed
TS
2778 uint32_t fst2;
2779
05993cd0 2780 fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
5f7319cd 2781 update_fcr31(env, GETPC());
b6d96bed 2782 return fst2;
8dfdb87c 2783}
b6d96bed 2784
895c2d04 2785uint64_t helper_float_recip1_ps(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 2786{
b6d96bed
TS
2787 uint32_t fst2;
2788 uint32_t fsth2;
2789
05993cd0
AJ
2790 fst2 = float32_div(float32_one, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2791 fsth2 = float32_div(float32_one, fdt0 >> 32, &env->active_fpu.fp_status);
5f7319cd 2792 update_fcr31(env, GETPC());
b6d96bed 2793 return ((uint64_t)fsth2 << 32) | fst2;
8dfdb87c
TS
2794}
2795
895c2d04 2796uint64_t helper_float_rsqrt1_d(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 2797{
b6d96bed
TS
2798 uint64_t fdt2;
2799
f01be154 2800 fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
05993cd0 2801 fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
5f7319cd 2802 update_fcr31(env, GETPC());
b6d96bed 2803 return fdt2;
8dfdb87c 2804}
b6d96bed 2805
895c2d04 2806uint32_t helper_float_rsqrt1_s(CPUMIPSState *env, uint32_t fst0)
8dfdb87c 2807{
b6d96bed
TS
2808 uint32_t fst2;
2809
f01be154 2810 fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
05993cd0 2811 fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
5f7319cd 2812 update_fcr31(env, GETPC());
b6d96bed 2813 return fst2;
8dfdb87c 2814}
b6d96bed 2815
895c2d04 2816uint64_t helper_float_rsqrt1_ps(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 2817{
b6d96bed
TS
2818 uint32_t fst2;
2819 uint32_t fsth2;
2820
f01be154
TS
2821 fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2822 fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status);
05993cd0
AJ
2823 fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
2824 fsth2 = float32_div(float32_one, fsth2, &env->active_fpu.fp_status);
5f7319cd 2825 update_fcr31(env, GETPC());
b6d96bed 2826 return ((uint64_t)fsth2 << 32) | fst2;
57fa1fb3 2827}
57fa1fb3 2828
895c2d04 2829#define FLOAT_OP(name, p) void helper_float_##name##_##p(CPUMIPSState *env)
b6d96bed 2830
fd4a04eb 2831/* binary operations */
b6d96bed 2832#define FLOAT_BINOP(name) \
895c2d04
BS
2833uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \
2834 uint64_t fdt0, uint64_t fdt1) \
b6d96bed
TS
2835{ \
2836 uint64_t dt2; \
2837 \
f01be154 2838 dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status); \
5f7319cd 2839 update_fcr31(env, GETPC()); \
b6d96bed
TS
2840 return dt2; \
2841} \
2842 \
895c2d04
BS
2843uint32_t helper_float_ ## name ## _s(CPUMIPSState *env, \
2844 uint32_t fst0, uint32_t fst1) \
b6d96bed
TS
2845{ \
2846 uint32_t wt2; \
2847 \
f01be154 2848 wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \
5f7319cd 2849 update_fcr31(env, GETPC()); \
b6d96bed
TS
2850 return wt2; \
2851} \
2852 \
895c2d04
BS
2853uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \
2854 uint64_t fdt0, \
2855 uint64_t fdt1) \
b6d96bed
TS
2856{ \
2857 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
2858 uint32_t fsth0 = fdt0 >> 32; \
2859 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
2860 uint32_t fsth1 = fdt1 >> 32; \
2861 uint32_t wt2; \
2862 uint32_t wth2; \
2863 \
f01be154
TS
2864 wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \
2865 wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status); \
5f7319cd 2866 update_fcr31(env, GETPC()); \
b6d96bed 2867 return ((uint64_t)wth2 << 32) | wt2; \
fd4a04eb 2868}
b6d96bed 2869
fd4a04eb
TS
2870FLOAT_BINOP(add)
2871FLOAT_BINOP(sub)
2872FLOAT_BINOP(mul)
2873FLOAT_BINOP(div)
2874#undef FLOAT_BINOP
2875
f54c35d1
RS
2876#define UNFUSED_FMA(prefix, a, b, c, flags) \
2877{ \
2878 a = prefix##_mul(a, b, &env->active_fpu.fp_status); \
2879 if ((flags) & float_muladd_negate_c) { \
2880 a = prefix##_sub(a, c, &env->active_fpu.fp_status); \
2881 } else { \
2882 a = prefix##_add(a, c, &env->active_fpu.fp_status); \
2883 } \
2884 if ((flags) & float_muladd_negate_result) { \
2885 a = prefix##_chs(a); \
2886 } \
2887}
2888
b3d6cd44
AJ
2889/* FMA based operations */
2890#define FLOAT_FMA(name, type) \
2891uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \
2892 uint64_t fdt0, uint64_t fdt1, \
2893 uint64_t fdt2) \
2894{ \
f54c35d1 2895 UNFUSED_FMA(float64, fdt0, fdt1, fdt2, type); \
5f7319cd 2896 update_fcr31(env, GETPC()); \
b3d6cd44
AJ
2897 return fdt0; \
2898} \
2899 \
2900uint32_t helper_float_ ## name ## _s(CPUMIPSState *env, \
2901 uint32_t fst0, uint32_t fst1, \
2902 uint32_t fst2) \
2903{ \
f54c35d1 2904 UNFUSED_FMA(float32, fst0, fst1, fst2, type); \
5f7319cd 2905 update_fcr31(env, GETPC()); \
b3d6cd44
AJ
2906 return fst0; \
2907} \
2908 \
2909uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \
2910 uint64_t fdt0, uint64_t fdt1, \
2911 uint64_t fdt2) \
2912{ \
2913 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
2914 uint32_t fsth0 = fdt0 >> 32; \
2915 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
2916 uint32_t fsth1 = fdt1 >> 32; \
2917 uint32_t fst2 = fdt2 & 0XFFFFFFFF; \
2918 uint32_t fsth2 = fdt2 >> 32; \
2919 \
f54c35d1
RS
2920 UNFUSED_FMA(float32, fst0, fst1, fst2, type); \
2921 UNFUSED_FMA(float32, fsth0, fsth1, fsth2, type); \
5f7319cd 2922 update_fcr31(env, GETPC()); \
b3d6cd44
AJ
2923 return ((uint64_t)fsth0 << 32) | fst0; \
2924}
2925FLOAT_FMA(madd, 0)
2926FLOAT_FMA(msub, float_muladd_negate_c)
2927FLOAT_FMA(nmadd, float_muladd_negate_result)
2928FLOAT_FMA(nmsub, float_muladd_negate_result | float_muladd_negate_c)
2929#undef FLOAT_FMA
a16336e4 2930
8dfdb87c 2931/* MIPS specific binary operations */
895c2d04 2932uint64_t helper_float_recip2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
8dfdb87c 2933{
f01be154 2934 fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
05993cd0 2935 fdt2 = float64_chs(float64_sub(fdt2, float64_one, &env->active_fpu.fp_status));
5f7319cd 2936 update_fcr31(env, GETPC());
b6d96bed 2937 return fdt2;
8dfdb87c 2938}
b6d96bed 2939
895c2d04 2940uint32_t helper_float_recip2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
8dfdb87c 2941{
f01be154 2942 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
05993cd0 2943 fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
5f7319cd 2944 update_fcr31(env, GETPC());
b6d96bed 2945 return fst2;
8dfdb87c 2946}
b6d96bed 2947
895c2d04 2948uint64_t helper_float_recip2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
8dfdb87c 2949{
b6d96bed
TS
2950 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
2951 uint32_t fsth0 = fdt0 >> 32;
2952 uint32_t fst2 = fdt2 & 0XFFFFFFFF;
2953 uint32_t fsth2 = fdt2 >> 32;
2954
f01be154
TS
2955 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
2956 fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
05993cd0
AJ
2957 fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
2958 fsth2 = float32_chs(float32_sub(fsth2, float32_one, &env->active_fpu.fp_status));
5f7319cd 2959 update_fcr31(env, GETPC());
b6d96bed 2960 return ((uint64_t)fsth2 << 32) | fst2;
8dfdb87c
TS
2961}
2962
895c2d04 2963uint64_t helper_float_rsqrt2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
8dfdb87c 2964{
f01be154 2965 fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
05993cd0 2966 fdt2 = float64_sub(fdt2, float64_one, &env->active_fpu.fp_status);
f01be154 2967 fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status));
5f7319cd 2968 update_fcr31(env, GETPC());
b6d96bed 2969 return fdt2;
8dfdb87c 2970}
b6d96bed 2971
895c2d04 2972uint32_t helper_float_rsqrt2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
8dfdb87c 2973{
f01be154 2974 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
05993cd0 2975 fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
f01be154 2976 fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
5f7319cd 2977 update_fcr31(env, GETPC());
b6d96bed 2978 return fst2;
8dfdb87c 2979}
b6d96bed 2980
895c2d04 2981uint64_t helper_float_rsqrt2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
8dfdb87c 2982{
b6d96bed
TS
2983 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
2984 uint32_t fsth0 = fdt0 >> 32;
2985 uint32_t fst2 = fdt2 & 0XFFFFFFFF;
2986 uint32_t fsth2 = fdt2 >> 32;
2987
f01be154
TS
2988 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
2989 fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
05993cd0
AJ
2990 fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
2991 fsth2 = float32_sub(fsth2, float32_one, &env->active_fpu.fp_status);
f01be154
TS
2992 fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
2993 fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->active_fpu.fp_status));
5f7319cd 2994 update_fcr31(env, GETPC());
b6d96bed 2995 return ((uint64_t)fsth2 << 32) | fst2;
57fa1fb3 2996}
57fa1fb3 2997
895c2d04 2998uint64_t helper_float_addr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
fd4a04eb 2999{
b6d96bed
TS
3000 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3001 uint32_t fsth0 = fdt0 >> 32;
3002 uint32_t fst1 = fdt1 & 0XFFFFFFFF;
3003 uint32_t fsth1 = fdt1 >> 32;
3004 uint32_t fst2;
3005 uint32_t fsth2;
3006
f01be154
TS
3007 fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status);
3008 fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status);
5f7319cd 3009 update_fcr31(env, GETPC());
b6d96bed 3010 return ((uint64_t)fsth2 << 32) | fst2;
fd4a04eb
TS
3011}
3012
895c2d04 3013uint64_t helper_float_mulr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
57fa1fb3 3014{
b6d96bed
TS
3015 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3016 uint32_t fsth0 = fdt0 >> 32;
3017 uint32_t fst1 = fdt1 & 0XFFFFFFFF;
3018 uint32_t fsth1 = fdt1 >> 32;
3019 uint32_t fst2;
3020 uint32_t fsth2;
3021
f01be154
TS
3022 fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status);
3023 fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status);
5f7319cd 3024 update_fcr31(env, GETPC());
b6d96bed 3025 return ((uint64_t)fsth2 << 32) | fst2;
57fa1fb3
TS
3026}
3027
8dfdb87c 3028/* compare operations */
b6d96bed 3029#define FOP_COND_D(op, cond) \
895c2d04
BS
3030void helper_cmp_d_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3031 uint64_t fdt1, int cc) \
b6d96bed 3032{ \
6a385343 3033 int c; \
6a385343 3034 c = cond; \
5f7319cd 3035 update_fcr31(env, GETPC()); \
b6d96bed 3036 if (c) \
f01be154 3037 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3038 else \
f01be154 3039 CLEAR_FP_COND(cc, env->active_fpu); \
b6d96bed 3040} \
895c2d04
BS
3041void helper_cmpabs_d_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3042 uint64_t fdt1, int cc) \
b6d96bed
TS
3043{ \
3044 int c; \
3045 fdt0 = float64_abs(fdt0); \
3046 fdt1 = float64_abs(fdt1); \
3047 c = cond; \
5f7319cd 3048 update_fcr31(env, GETPC()); \
b6d96bed 3049 if (c) \
f01be154 3050 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3051 else \
f01be154 3052 CLEAR_FP_COND(cc, env->active_fpu); \
fd4a04eb
TS
3053}
3054
fd4a04eb 3055/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3056 * but float64_unordered_quiet() is still called. */
3057FOP_COND_D(f, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
3058FOP_COND_D(un, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status))
06a0e6b1 3059FOP_COND_D(eq, float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
211315fb 3060FOP_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
3061FOP_COND_D(olt, float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3062FOP_COND_D(ult, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3063FOP_COND_D(ole, float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3064FOP_COND_D(ule, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
fd4a04eb 3065/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3066 * but float64_unordered() is still called. */
3067FOP_COND_D(sf, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
3068FOP_COND_D(ngle,float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status))
06a0e6b1
AJ
3069FOP_COND_D(seq, float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
3070FOP_COND_D(ngl, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
3071FOP_COND_D(lt, float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
3a599383 3072FOP_COND_D(nge, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
06a0e6b1 3073FOP_COND_D(le, float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3a599383 3074FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
b6d96bed
TS
3075
3076#define FOP_COND_S(op, cond) \
895c2d04
BS
3077void helper_cmp_s_ ## op(CPUMIPSState *env, uint32_t fst0, \
3078 uint32_t fst1, int cc) \
b6d96bed 3079{ \
6a385343 3080 int c; \
6a385343 3081 c = cond; \
5f7319cd 3082 update_fcr31(env, GETPC()); \
b6d96bed 3083 if (c) \
f01be154 3084 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3085 else \
f01be154 3086 CLEAR_FP_COND(cc, env->active_fpu); \
b6d96bed 3087} \
895c2d04
BS
3088void helper_cmpabs_s_ ## op(CPUMIPSState *env, uint32_t fst0, \
3089 uint32_t fst1, int cc) \
b6d96bed
TS
3090{ \
3091 int c; \
3092 fst0 = float32_abs(fst0); \
3093 fst1 = float32_abs(fst1); \
3094 c = cond; \
5f7319cd 3095 update_fcr31(env, GETPC()); \
b6d96bed 3096 if (c) \
f01be154 3097 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3098 else \
f01be154 3099 CLEAR_FP_COND(cc, env->active_fpu); \
fd4a04eb
TS
3100}
3101
fd4a04eb 3102/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3103 * but float32_unordered_quiet() is still called. */
3104FOP_COND_S(f, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
3105FOP_COND_S(un, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status))
06a0e6b1 3106FOP_COND_S(eq, float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
211315fb 3107FOP_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
3108FOP_COND_S(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
3109FOP_COND_S(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
3110FOP_COND_S(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
3111FOP_COND_S(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
fd4a04eb 3112/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3113 * but float32_unordered() is still called. */
3114FOP_COND_S(sf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
3115FOP_COND_S(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status))
06a0e6b1
AJ
3116FOP_COND_S(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status))
3117FOP_COND_S(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
3118FOP_COND_S(lt, float32_lt(fst0, fst1, &env->active_fpu.fp_status))
3a599383 3119FOP_COND_S(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
06a0e6b1 3120FOP_COND_S(le, float32_le(fst0, fst1, &env->active_fpu.fp_status))
3a599383 3121FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status))
b6d96bed
TS
3122
3123#define FOP_COND_PS(op, condl, condh) \
895c2d04
BS
3124void helper_cmp_ps_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3125 uint64_t fdt1, int cc) \
b6d96bed 3126{ \
6a385343
AJ
3127 uint32_t fst0, fsth0, fst1, fsth1; \
3128 int ch, cl; \
6a385343
AJ
3129 fst0 = fdt0 & 0XFFFFFFFF; \
3130 fsth0 = fdt0 >> 32; \
3131 fst1 = fdt1 & 0XFFFFFFFF; \
3132 fsth1 = fdt1 >> 32; \
3133 cl = condl; \
3134 ch = condh; \
5f7319cd 3135 update_fcr31(env, GETPC()); \
b6d96bed 3136 if (cl) \
f01be154 3137 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3138 else \
f01be154 3139 CLEAR_FP_COND(cc, env->active_fpu); \
b6d96bed 3140 if (ch) \
f01be154 3141 SET_FP_COND(cc + 1, env->active_fpu); \
b6d96bed 3142 else \
f01be154 3143 CLEAR_FP_COND(cc + 1, env->active_fpu); \
b6d96bed 3144} \
895c2d04
BS
3145void helper_cmpabs_ps_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3146 uint64_t fdt1, int cc) \
b6d96bed 3147{ \
6a385343
AJ
3148 uint32_t fst0, fsth0, fst1, fsth1; \
3149 int ch, cl; \
3150 fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \
3151 fsth0 = float32_abs(fdt0 >> 32); \
3152 fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \
3153 fsth1 = float32_abs(fdt1 >> 32); \
3154 cl = condl; \
3155 ch = condh; \
5f7319cd 3156 update_fcr31(env, GETPC()); \
b6d96bed 3157 if (cl) \
f01be154 3158 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3159 else \
f01be154 3160 CLEAR_FP_COND(cc, env->active_fpu); \
b6d96bed 3161 if (ch) \
f01be154 3162 SET_FP_COND(cc + 1, env->active_fpu); \
b6d96bed 3163 else \
f01be154 3164 CLEAR_FP_COND(cc + 1, env->active_fpu); \
fd4a04eb
TS
3165}
3166
3167/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3168 * but float32_unordered_quiet() is still called. */
3169FOP_COND_PS(f, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0),
3170 (float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status), 0))
3171FOP_COND_PS(un, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status),
3172 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status))
06a0e6b1
AJ
3173FOP_COND_PS(eq, float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
3174 float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
211315fb
AJ
3175FOP_COND_PS(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
3176 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
06a0e6b1
AJ
3177FOP_COND_PS(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
3178 float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3179FOP_COND_PS(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
3180 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3181FOP_COND_PS(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
3182 float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3183FOP_COND_PS(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
3184 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
fd4a04eb 3185/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3186 * but float32_unordered() is still called. */
3187FOP_COND_PS(sf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0),
3188 (float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status), 0))
3189FOP_COND_PS(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status),
3190 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status))
06a0e6b1
AJ
3191FOP_COND_PS(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status),
3192 float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
3193FOP_COND_PS(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
3194 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
3195FOP_COND_PS(lt, float32_lt(fst0, fst1, &env->active_fpu.fp_status),
3196 float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
3a599383
AJ
3197FOP_COND_PS(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
3198 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
06a0e6b1
AJ
3199FOP_COND_PS(le, float32_le(fst0, fst1, &env->active_fpu.fp_status),
3200 float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
3a599383
AJ
3201FOP_COND_PS(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status),
3202 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))