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