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