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