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