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