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