]> git.proxmox.com Git - qemu.git/blame - target-mips/op_helper.c
target-sh4: switch to AREG0 free mode
[qemu.git] / target-mips / op_helper.c
CommitLineData
6af0bf9c
FB
1/*
2 * MIPS emulation helpers for qemu.
5fafdf24 3 *
6af0bf9c
FB
4 * Copyright (c) 2004-2005 Jocelyn Mayer
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
8167ee88 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
6af0bf9c 18 */
2d0e944d 19#include <stdlib.h>
3e457172
BS
20#include "cpu.h"
21#include "dyngen-exec.h"
6af0bf9c 22
05f778c8
TS
23#include "host-utils.h"
24
a7812ae4 25#include "helper.h"
83dae095 26
3e457172
BS
27#if !defined(CONFIG_USER_ONLY)
28#include "softmmu_exec.h"
29#endif /* !defined(CONFIG_USER_ONLY) */
30
83dae095 31#ifndef CONFIG_USER_ONLY
7db13fae 32static inline void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global);
83dae095
PB
33#endif
34
6af0bf9c
FB
35/*****************************************************************************/
36/* Exceptions processing helpers */
6af0bf9c 37
c01fccd2 38void helper_raise_exception_err (uint32_t exception, int error_code)
6af0bf9c
FB
39{
40#if 1
93fcfe39
AL
41 if (exception < 0x100)
42 qemu_log("%s: %d %d\n", __func__, exception, error_code);
6af0bf9c
FB
43#endif
44 env->exception_index = exception;
45 env->error_code = error_code;
1162c041 46 cpu_loop_exit(env);
6af0bf9c
FB
47}
48
c01fccd2 49void helper_raise_exception (uint32_t exception)
6af0bf9c 50{
c01fccd2 51 helper_raise_exception_err(exception, 0);
6af0bf9c
FB
52}
53
f9480ffc 54#if !defined(CONFIG_USER_ONLY)
20503968 55static void do_restore_state(uintptr_t pc)
4ad40f36 56{
a607922c 57 TranslationBlock *tb;
20503968 58
a607922c
FB
59 tb = tb_find_pc (pc);
60 if (tb) {
618ba8e6 61 cpu_restore_state(tb, env, pc);
a607922c 62 }
4ad40f36 63}
f9480ffc 64#endif
4ad40f36 65
0ae43045
AJ
66#if defined(CONFIG_USER_ONLY)
67#define HELPER_LD(name, insn, type) \
68static inline type do_##name(target_ulong addr, int mem_idx) \
69{ \
70 return (type) insn##_raw(addr); \
71}
72#else
73#define HELPER_LD(name, insn, type) \
74static inline type do_##name(target_ulong addr, int mem_idx) \
75{ \
76 switch (mem_idx) \
77 { \
78 case 0: return (type) insn##_kernel(addr); break; \
79 case 1: return (type) insn##_super(addr); break; \
80 default: \
81 case 2: return (type) insn##_user(addr); break; \
82 } \
83}
84#endif
85HELPER_LD(lbu, ldub, uint8_t)
86HELPER_LD(lw, ldl, int32_t)
87#ifdef TARGET_MIPS64
88HELPER_LD(ld, ldq, int64_t)
89#endif
90#undef HELPER_LD
91
92#if defined(CONFIG_USER_ONLY)
93#define HELPER_ST(name, insn, type) \
94static inline void do_##name(target_ulong addr, type val, int mem_idx) \
95{ \
96 insn##_raw(addr, val); \
97}
98#else
99#define HELPER_ST(name, insn, type) \
100static inline void do_##name(target_ulong addr, type val, int mem_idx) \
101{ \
102 switch (mem_idx) \
103 { \
104 case 0: insn##_kernel(addr, val); break; \
105 case 1: insn##_super(addr, val); break; \
106 default: \
107 case 2: insn##_user(addr, val); break; \
108 } \
109}
110#endif
111HELPER_ST(sb, stb, uint8_t)
112HELPER_ST(sw, stl, uint32_t)
113#ifdef TARGET_MIPS64
114HELPER_ST(sd, stq, uint64_t)
115#endif
116#undef HELPER_ST
117
d9bea114 118target_ulong helper_clo (target_ulong arg1)
30898801 119{
d9bea114 120 return clo32(arg1);
30898801
TS
121}
122
d9bea114 123target_ulong helper_clz (target_ulong arg1)
30898801 124{
d9bea114 125 return clz32(arg1);
30898801
TS
126}
127
d26bc211 128#if defined(TARGET_MIPS64)
d9bea114 129target_ulong helper_dclo (target_ulong arg1)
05f778c8 130{
d9bea114 131 return clo64(arg1);
05f778c8
TS
132}
133
d9bea114 134target_ulong helper_dclz (target_ulong arg1)
05f778c8 135{
d9bea114 136 return clz64(arg1);
05f778c8 137}
d26bc211 138#endif /* TARGET_MIPS64 */
c570fd16 139
6af0bf9c 140/* 64 bits arithmetic for 32 bits hosts */
c904ef0e 141static inline uint64_t get_HILO (void)
6af0bf9c 142{
b5dc7732 143 return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0];
6af0bf9c
FB
144}
145
6fc97faf 146static inline target_ulong set_HIT0_LO(uint64_t HILO)
e9c71dd1 147{
6fc97faf 148 target_ulong tmp;
b5dc7732 149 env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
6fc97faf
SW
150 tmp = env->active_tc.HI[0] = (int32_t)(HILO >> 32);
151 return tmp;
e9c71dd1
TS
152}
153
6fc97faf 154static inline target_ulong set_HI_LOT0(uint64_t HILO)
e9c71dd1 155{
6fc97faf 156 target_ulong tmp = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
b5dc7732 157 env->active_tc.HI[0] = (int32_t)(HILO >> 32);
6fc97faf 158 return tmp;
e9c71dd1
TS
159}
160
e9c71dd1 161/* Multiplication variants of the vr54xx. */
d9bea114 162target_ulong helper_muls (target_ulong arg1, target_ulong arg2)
e9c71dd1 163{
6fc97faf 164 return set_HI_LOT0(0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
e9c71dd1
TS
165}
166
d9bea114 167target_ulong helper_mulsu (target_ulong arg1, target_ulong arg2)
e9c71dd1 168{
6fc97faf 169 return set_HI_LOT0(0 - (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
e9c71dd1
TS
170}
171
d9bea114 172target_ulong helper_macc (target_ulong arg1, target_ulong arg2)
e9c71dd1 173{
6fc97faf
SW
174 return set_HI_LOT0((int64_t)get_HILO() + (int64_t)(int32_t)arg1 *
175 (int64_t)(int32_t)arg2);
e9c71dd1
TS
176}
177
d9bea114 178target_ulong helper_macchi (target_ulong arg1, target_ulong arg2)
e9c71dd1 179{
6fc97faf
SW
180 return set_HIT0_LO((int64_t)get_HILO() + (int64_t)(int32_t)arg1 *
181 (int64_t)(int32_t)arg2);
e9c71dd1
TS
182}
183
d9bea114 184target_ulong helper_maccu (target_ulong arg1, target_ulong arg2)
e9c71dd1 185{
6fc97faf
SW
186 return set_HI_LOT0((uint64_t)get_HILO() + (uint64_t)(uint32_t)arg1 *
187 (uint64_t)(uint32_t)arg2);
e9c71dd1
TS
188}
189
d9bea114 190target_ulong helper_macchiu (target_ulong arg1, target_ulong arg2)
e9c71dd1 191{
6fc97faf
SW
192 return set_HIT0_LO((uint64_t)get_HILO() + (uint64_t)(uint32_t)arg1 *
193 (uint64_t)(uint32_t)arg2);
e9c71dd1
TS
194}
195
d9bea114 196target_ulong helper_msac (target_ulong arg1, target_ulong arg2)
e9c71dd1 197{
6fc97faf
SW
198 return set_HI_LOT0((int64_t)get_HILO() - (int64_t)(int32_t)arg1 *
199 (int64_t)(int32_t)arg2);
e9c71dd1
TS
200}
201
d9bea114 202target_ulong helper_msachi (target_ulong arg1, target_ulong arg2)
e9c71dd1 203{
6fc97faf
SW
204 return set_HIT0_LO((int64_t)get_HILO() - (int64_t)(int32_t)arg1 *
205 (int64_t)(int32_t)arg2);
e9c71dd1
TS
206}
207
d9bea114 208target_ulong helper_msacu (target_ulong arg1, target_ulong arg2)
e9c71dd1 209{
6fc97faf
SW
210 return set_HI_LOT0((uint64_t)get_HILO() - (uint64_t)(uint32_t)arg1 *
211 (uint64_t)(uint32_t)arg2);
e9c71dd1
TS
212}
213
d9bea114 214target_ulong helper_msachiu (target_ulong arg1, target_ulong arg2)
e9c71dd1 215{
6fc97faf
SW
216 return set_HIT0_LO((uint64_t)get_HILO() - (uint64_t)(uint32_t)arg1 *
217 (uint64_t)(uint32_t)arg2);
e9c71dd1
TS
218}
219
d9bea114 220target_ulong helper_mulhi (target_ulong arg1, target_ulong arg2)
e9c71dd1 221{
6fc97faf 222 return set_HIT0_LO((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
e9c71dd1
TS
223}
224
d9bea114 225target_ulong helper_mulhiu (target_ulong arg1, target_ulong arg2)
e9c71dd1 226{
6fc97faf 227 return set_HIT0_LO((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
e9c71dd1
TS
228}
229
d9bea114 230target_ulong helper_mulshi (target_ulong arg1, target_ulong arg2)
e9c71dd1 231{
6fc97faf 232 return set_HIT0_LO(0 - (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
e9c71dd1
TS
233}
234
d9bea114 235target_ulong helper_mulshiu (target_ulong arg1, target_ulong arg2)
e9c71dd1 236{
6fc97faf 237 return set_HIT0_LO(0 - (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
e9c71dd1 238}
6af0bf9c 239
214c465f 240#ifdef TARGET_MIPS64
d9bea114 241void helper_dmult (target_ulong arg1, target_ulong arg2)
214c465f 242{
d9bea114 243 muls64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
214c465f
TS
244}
245
d9bea114 246void helper_dmultu (target_ulong arg1, target_ulong arg2)
214c465f 247{
d9bea114 248 mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
214c465f
TS
249}
250#endif
251
e7139c44 252#ifndef CONFIG_USER_ONLY
c36bbb28
AJ
253
254static inline target_phys_addr_t do_translate_address(target_ulong address, int rw)
255{
256 target_phys_addr_t lladdr;
257
258 lladdr = cpu_mips_translate_address(env, address, rw);
259
260 if (lladdr == -1LL) {
1162c041 261 cpu_loop_exit(env);
c36bbb28
AJ
262 } else {
263 return lladdr;
264 }
265}
266
e7139c44
AJ
267#define HELPER_LD_ATOMIC(name, insn) \
268target_ulong helper_##name(target_ulong arg, int mem_idx) \
269{ \
c36bbb28 270 env->lladdr = do_translate_address(arg, 0); \
e7139c44
AJ
271 env->llval = do_##insn(arg, mem_idx); \
272 return env->llval; \
273}
274HELPER_LD_ATOMIC(ll, lw)
275#ifdef TARGET_MIPS64
276HELPER_LD_ATOMIC(lld, ld)
277#endif
278#undef HELPER_LD_ATOMIC
279
280#define HELPER_ST_ATOMIC(name, ld_insn, st_insn, almask) \
281target_ulong helper_##name(target_ulong arg1, target_ulong arg2, int mem_idx) \
282{ \
283 target_long tmp; \
284 \
285 if (arg2 & almask) { \
286 env->CP0_BadVAddr = arg2; \
287 helper_raise_exception(EXCP_AdES); \
288 } \
c36bbb28 289 if (do_translate_address(arg2, 1) == env->lladdr) { \
e7139c44
AJ
290 tmp = do_##ld_insn(arg2, mem_idx); \
291 if (tmp == env->llval) { \
292 do_##st_insn(arg2, arg1, mem_idx); \
293 return 1; \
294 } \
295 } \
296 return 0; \
297}
298HELPER_ST_ATOMIC(sc, lw, sw, 0x3)
299#ifdef TARGET_MIPS64
300HELPER_ST_ATOMIC(scd, ld, sd, 0x7)
301#endif
302#undef HELPER_ST_ATOMIC
303#endif
304
c8c2227e
TS
305#ifdef TARGET_WORDS_BIGENDIAN
306#define GET_LMASK(v) ((v) & 3)
307#define GET_OFFSET(addr, offset) (addr + (offset))
308#else
309#define GET_LMASK(v) (((v) & 3) ^ 3)
310#define GET_OFFSET(addr, offset) (addr - (offset))
311#endif
312
d9bea114 313target_ulong helper_lwl(target_ulong arg1, target_ulong arg2, int mem_idx)
c8c2227e
TS
314{
315 target_ulong tmp;
316
0ae43045 317 tmp = do_lbu(arg2, mem_idx);
d9bea114 318 arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
c8c2227e 319
d9bea114 320 if (GET_LMASK(arg2) <= 2) {
0ae43045 321 tmp = do_lbu(GET_OFFSET(arg2, 1), mem_idx);
d9bea114 322 arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
c8c2227e
TS
323 }
324
d9bea114 325 if (GET_LMASK(arg2) <= 1) {
0ae43045 326 tmp = do_lbu(GET_OFFSET(arg2, 2), mem_idx);
d9bea114 327 arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
c8c2227e
TS
328 }
329
d9bea114 330 if (GET_LMASK(arg2) == 0) {
0ae43045 331 tmp = do_lbu(GET_OFFSET(arg2, 3), mem_idx);
d9bea114 332 arg1 = (arg1 & 0xFFFFFF00) | tmp;
c8c2227e 333 }
d9bea114 334 return (int32_t)arg1;
c8c2227e
TS
335}
336
d9bea114 337target_ulong helper_lwr(target_ulong arg1, target_ulong arg2, int mem_idx)
c8c2227e
TS
338{
339 target_ulong tmp;
340
0ae43045 341 tmp = do_lbu(arg2, mem_idx);
d9bea114 342 arg1 = (arg1 & 0xFFFFFF00) | tmp;
c8c2227e 343
d9bea114 344 if (GET_LMASK(arg2) >= 1) {
0ae43045 345 tmp = do_lbu(GET_OFFSET(arg2, -1), mem_idx);
d9bea114 346 arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
c8c2227e
TS
347 }
348
d9bea114 349 if (GET_LMASK(arg2) >= 2) {
0ae43045 350 tmp = do_lbu(GET_OFFSET(arg2, -2), mem_idx);
d9bea114 351 arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
c8c2227e
TS
352 }
353
d9bea114 354 if (GET_LMASK(arg2) == 3) {
0ae43045 355 tmp = do_lbu(GET_OFFSET(arg2, -3), mem_idx);
d9bea114 356 arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
c8c2227e 357 }
d9bea114 358 return (int32_t)arg1;
c8c2227e
TS
359}
360
d9bea114 361void helper_swl(target_ulong arg1, target_ulong arg2, int mem_idx)
c8c2227e 362{
0ae43045 363 do_sb(arg2, (uint8_t)(arg1 >> 24), mem_idx);
c8c2227e 364
d9bea114 365 if (GET_LMASK(arg2) <= 2)
0ae43045 366 do_sb(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16), mem_idx);
c8c2227e 367
d9bea114 368 if (GET_LMASK(arg2) <= 1)
0ae43045 369 do_sb(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8), mem_idx);
c8c2227e 370
d9bea114 371 if (GET_LMASK(arg2) == 0)
0ae43045 372 do_sb(GET_OFFSET(arg2, 3), (uint8_t)arg1, mem_idx);
c8c2227e
TS
373}
374
d9bea114 375void helper_swr(target_ulong arg1, target_ulong arg2, int mem_idx)
c8c2227e 376{
0ae43045 377 do_sb(arg2, (uint8_t)arg1, mem_idx);
c8c2227e 378
d9bea114 379 if (GET_LMASK(arg2) >= 1)
0ae43045 380 do_sb(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
c8c2227e 381
d9bea114 382 if (GET_LMASK(arg2) >= 2)
0ae43045 383 do_sb(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
c8c2227e 384
d9bea114 385 if (GET_LMASK(arg2) == 3)
0ae43045 386 do_sb(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
c8c2227e
TS
387}
388
389#if defined(TARGET_MIPS64)
390/* "half" load and stores. We must do the memory access inline,
391 or fault handling won't work. */
392
393#ifdef TARGET_WORDS_BIGENDIAN
394#define GET_LMASK64(v) ((v) & 7)
395#else
396#define GET_LMASK64(v) (((v) & 7) ^ 7)
397#endif
398
d9bea114 399target_ulong helper_ldl(target_ulong arg1, target_ulong arg2, int mem_idx)
c8c2227e
TS
400{
401 uint64_t tmp;
402
0ae43045 403 tmp = do_lbu(arg2, mem_idx);
d9bea114 404 arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
c8c2227e 405
d9bea114 406 if (GET_LMASK64(arg2) <= 6) {
0ae43045 407 tmp = do_lbu(GET_OFFSET(arg2, 1), mem_idx);
d9bea114 408 arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
c8c2227e
TS
409 }
410
d9bea114 411 if (GET_LMASK64(arg2) <= 5) {
0ae43045 412 tmp = do_lbu(GET_OFFSET(arg2, 2), mem_idx);
d9bea114 413 arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
c8c2227e
TS
414 }
415
d9bea114 416 if (GET_LMASK64(arg2) <= 4) {
0ae43045 417 tmp = do_lbu(GET_OFFSET(arg2, 3), mem_idx);
d9bea114 418 arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
c8c2227e
TS
419 }
420
d9bea114 421 if (GET_LMASK64(arg2) <= 3) {
0ae43045 422 tmp = do_lbu(GET_OFFSET(arg2, 4), mem_idx);
d9bea114 423 arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
c8c2227e
TS
424 }
425
d9bea114 426 if (GET_LMASK64(arg2) <= 2) {
0ae43045 427 tmp = do_lbu(GET_OFFSET(arg2, 5), mem_idx);
d9bea114 428 arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
c8c2227e
TS
429 }
430
d9bea114 431 if (GET_LMASK64(arg2) <= 1) {
0ae43045 432 tmp = do_lbu(GET_OFFSET(arg2, 6), mem_idx);
d9bea114 433 arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8);
c8c2227e
TS
434 }
435
d9bea114 436 if (GET_LMASK64(arg2) == 0) {
0ae43045 437 tmp = do_lbu(GET_OFFSET(arg2, 7), mem_idx);
d9bea114 438 arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
c8c2227e 439 }
be24bb4f 440
d9bea114 441 return arg1;
c8c2227e
TS
442}
443
d9bea114 444target_ulong helper_ldr(target_ulong arg1, target_ulong arg2, int mem_idx)
c8c2227e
TS
445{
446 uint64_t tmp;
447
0ae43045 448 tmp = do_lbu(arg2, mem_idx);
d9bea114 449 arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
c8c2227e 450
d9bea114 451 if (GET_LMASK64(arg2) >= 1) {
0ae43045 452 tmp = do_lbu(GET_OFFSET(arg2, -1), mem_idx);
d9bea114 453 arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8);
c8c2227e
TS
454 }
455
d9bea114 456 if (GET_LMASK64(arg2) >= 2) {
0ae43045 457 tmp = do_lbu(GET_OFFSET(arg2, -2), mem_idx);
d9bea114 458 arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
c8c2227e
TS
459 }
460
d9bea114 461 if (GET_LMASK64(arg2) >= 3) {
0ae43045 462 tmp = do_lbu(GET_OFFSET(arg2, -3), mem_idx);
d9bea114 463 arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
c8c2227e
TS
464 }
465
d9bea114 466 if (GET_LMASK64(arg2) >= 4) {
0ae43045 467 tmp = do_lbu(GET_OFFSET(arg2, -4), mem_idx);
d9bea114 468 arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
c8c2227e
TS
469 }
470
d9bea114 471 if (GET_LMASK64(arg2) >= 5) {
0ae43045 472 tmp = do_lbu(GET_OFFSET(arg2, -5), mem_idx);
d9bea114 473 arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
c8c2227e
TS
474 }
475
d9bea114 476 if (GET_LMASK64(arg2) >= 6) {
0ae43045 477 tmp = do_lbu(GET_OFFSET(arg2, -6), mem_idx);
d9bea114 478 arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
c8c2227e
TS
479 }
480
d9bea114 481 if (GET_LMASK64(arg2) == 7) {
0ae43045 482 tmp = do_lbu(GET_OFFSET(arg2, -7), mem_idx);
d9bea114 483 arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
c8c2227e 484 }
be24bb4f 485
d9bea114 486 return arg1;
c8c2227e
TS
487}
488
d9bea114 489void helper_sdl(target_ulong arg1, target_ulong arg2, int mem_idx)
c8c2227e 490{
0ae43045 491 do_sb(arg2, (uint8_t)(arg1 >> 56), mem_idx);
c8c2227e 492
d9bea114 493 if (GET_LMASK64(arg2) <= 6)
0ae43045 494 do_sb(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48), mem_idx);
c8c2227e 495
d9bea114 496 if (GET_LMASK64(arg2) <= 5)
0ae43045 497 do_sb(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40), mem_idx);
c8c2227e 498
d9bea114 499 if (GET_LMASK64(arg2) <= 4)
0ae43045 500 do_sb(GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32), mem_idx);
c8c2227e 501
d9bea114 502 if (GET_LMASK64(arg2) <= 3)
0ae43045 503 do_sb(GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24), mem_idx);
c8c2227e 504
d9bea114 505 if (GET_LMASK64(arg2) <= 2)
0ae43045 506 do_sb(GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16), mem_idx);
c8c2227e 507
d9bea114 508 if (GET_LMASK64(arg2) <= 1)
0ae43045 509 do_sb(GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8), mem_idx);
c8c2227e 510
d9bea114 511 if (GET_LMASK64(arg2) <= 0)
0ae43045 512 do_sb(GET_OFFSET(arg2, 7), (uint8_t)arg1, mem_idx);
c8c2227e
TS
513}
514
d9bea114 515void helper_sdr(target_ulong arg1, target_ulong arg2, int mem_idx)
c8c2227e 516{
0ae43045 517 do_sb(arg2, (uint8_t)arg1, mem_idx);
c8c2227e 518
d9bea114 519 if (GET_LMASK64(arg2) >= 1)
0ae43045 520 do_sb(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
c8c2227e 521
d9bea114 522 if (GET_LMASK64(arg2) >= 2)
0ae43045 523 do_sb(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
c8c2227e 524
d9bea114 525 if (GET_LMASK64(arg2) >= 3)
0ae43045 526 do_sb(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
c8c2227e 527
d9bea114 528 if (GET_LMASK64(arg2) >= 4)
0ae43045 529 do_sb(GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), mem_idx);
c8c2227e 530
d9bea114 531 if (GET_LMASK64(arg2) >= 5)
0ae43045 532 do_sb(GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), mem_idx);
c8c2227e 533
d9bea114 534 if (GET_LMASK64(arg2) >= 6)
0ae43045 535 do_sb(GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), mem_idx);
c8c2227e 536
d9bea114 537 if (GET_LMASK64(arg2) == 7)
0ae43045 538 do_sb(GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), mem_idx);
c8c2227e
TS
539}
540#endif /* TARGET_MIPS64 */
541
3c824109
NF
542static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };
543
544void helper_lwm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
545{
546 target_ulong base_reglist = reglist & 0xf;
547 target_ulong do_r31 = reglist & 0x10;
548#ifdef CONFIG_USER_ONLY
549#undef ldfun
550#define ldfun ldl_raw
551#else
552 uint32_t (*ldfun)(target_ulong);
553
554 switch (mem_idx)
555 {
556 case 0: ldfun = ldl_kernel; break;
557 case 1: ldfun = ldl_super; break;
558 default:
559 case 2: ldfun = ldl_user; break;
560 }
561#endif
562
563 if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
564 target_ulong i;
565
566 for (i = 0; i < base_reglist; i++) {
567 env->active_tc.gpr[multiple_regs[i]] = (target_long) ldfun(addr);
568 addr += 4;
569 }
570 }
571
572 if (do_r31) {
573 env->active_tc.gpr[31] = (target_long) ldfun(addr);
574 }
575}
576
577void helper_swm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
578{
579 target_ulong base_reglist = reglist & 0xf;
580 target_ulong do_r31 = reglist & 0x10;
581#ifdef CONFIG_USER_ONLY
582#undef stfun
583#define stfun stl_raw
584#else
585 void (*stfun)(target_ulong, uint32_t);
586
587 switch (mem_idx)
588 {
589 case 0: stfun = stl_kernel; break;
590 case 1: stfun = stl_super; break;
591 default:
592 case 2: stfun = stl_user; break;
593 }
594#endif
595
596 if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
597 target_ulong i;
598
599 for (i = 0; i < base_reglist; i++) {
600 stfun(addr, env->active_tc.gpr[multiple_regs[i]]);
601 addr += 4;
602 }
603 }
604
605 if (do_r31) {
606 stfun(addr, env->active_tc.gpr[31]);
607 }
608}
609
610#if defined(TARGET_MIPS64)
611void helper_ldm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
612{
613 target_ulong base_reglist = reglist & 0xf;
614 target_ulong do_r31 = reglist & 0x10;
615#ifdef CONFIG_USER_ONLY
616#undef ldfun
617#define ldfun ldq_raw
618#else
619 uint64_t (*ldfun)(target_ulong);
620
621 switch (mem_idx)
622 {
623 case 0: ldfun = ldq_kernel; break;
624 case 1: ldfun = ldq_super; break;
625 default:
626 case 2: ldfun = ldq_user; break;
627 }
628#endif
629
630 if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
631 target_ulong i;
632
633 for (i = 0; i < base_reglist; i++) {
634 env->active_tc.gpr[multiple_regs[i]] = ldfun(addr);
635 addr += 8;
636 }
637 }
638
639 if (do_r31) {
640 env->active_tc.gpr[31] = ldfun(addr);
641 }
642}
643
644void helper_sdm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
645{
646 target_ulong base_reglist = reglist & 0xf;
647 target_ulong do_r31 = reglist & 0x10;
648#ifdef CONFIG_USER_ONLY
649#undef stfun
650#define stfun stq_raw
651#else
652 void (*stfun)(target_ulong, uint64_t);
653
654 switch (mem_idx)
655 {
656 case 0: stfun = stq_kernel; break;
657 case 1: stfun = stq_super; break;
658 default:
659 case 2: stfun = stq_user; break;
660 }
661#endif
662
663 if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
664 target_ulong i;
665
666 for (i = 0; i < base_reglist; i++) {
667 stfun(addr, env->active_tc.gpr[multiple_regs[i]]);
668 addr += 8;
669 }
670 }
671
672 if (do_r31) {
673 stfun(addr, env->active_tc.gpr[31]);
674 }
675}
676#endif
677
0eaef5aa 678#ifndef CONFIG_USER_ONLY
f249412c 679/* SMP helpers. */
7db13fae 680static int mips_vpe_is_wfi(CPUMIPSState *c)
f249412c
EI
681{
682 /* If the VPE is halted but otherwise active, it means it's waiting for
683 an interrupt. */
684 return c->halted && mips_vpe_active(c);
685}
686
7db13fae 687static inline void mips_vpe_wake(CPUMIPSState *c)
f249412c
EI
688{
689 /* Dont set ->halted = 0 directly, let it be done via cpu_has_work
690 because there might be other conditions that state that c should
691 be sleeping. */
692 cpu_interrupt(c, CPU_INTERRUPT_WAKE);
693}
694
7db13fae 695static inline void mips_vpe_sleep(CPUMIPSState *c)
f249412c
EI
696{
697 /* The VPE was shut off, really go to bed.
698 Reset any old _WAKE requests. */
699 c->halted = 1;
700 cpu_reset_interrupt(c, CPU_INTERRUPT_WAKE);
701}
702
7db13fae 703static inline void mips_tc_wake(CPUMIPSState *c, int tc)
f249412c
EI
704{
705 /* FIXME: TC reschedule. */
706 if (mips_vpe_active(c) && !mips_vpe_is_wfi(c)) {
707 mips_vpe_wake(c);
708 }
709}
710
7db13fae 711static inline void mips_tc_sleep(CPUMIPSState *c, int tc)
f249412c
EI
712{
713 /* FIXME: TC reschedule. */
714 if (!mips_vpe_active(c)) {
715 mips_vpe_sleep(c);
716 }
717}
718
b93bbdcd
EI
719/* tc should point to an int with the value of the global TC index.
720 This function will transform it into a local index within the
7db13fae 721 returned CPUMIPSState.
b93bbdcd
EI
722
723 FIXME: This code assumes that all VPEs have the same number of TCs,
724 which depends on runtime setup. Can probably be fixed by
7db13fae
AF
725 walking the list of CPUMIPSStates. */
726static CPUMIPSState *mips_cpu_map_tc(int *tc)
b93bbdcd 727{
7db13fae 728 CPUMIPSState *other;
b93bbdcd
EI
729 int vpe_idx, nr_threads = env->nr_threads;
730 int tc_idx = *tc;
731
732 if (!(env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))) {
733 /* Not allowed to address other CPUs. */
734 *tc = env->current_tc;
735 return env;
736 }
737
738 vpe_idx = tc_idx / nr_threads;
739 *tc = tc_idx % nr_threads;
740 other = qemu_get_cpu(vpe_idx);
741 return other ? other : env;
742}
743
fe8dca8c
EI
744/* The per VPE CP0_Status register shares some fields with the per TC
745 CP0_TCStatus registers. These fields are wired to the same registers,
746 so changes to either of them should be reflected on both registers.
747
748 Also, EntryHi shares the bottom 8 bit ASID with TCStauts.
749
750 These helper call synchronizes the regs for a given cpu. */
751
752/* Called for updates to CP0_Status. */
7db13fae 753static void sync_c0_status(CPUMIPSState *cpu, int tc)
fe8dca8c
EI
754{
755 int32_t tcstatus, *tcst;
756 uint32_t v = cpu->CP0_Status;
757 uint32_t cu, mx, asid, ksu;
758 uint32_t mask = ((1 << CP0TCSt_TCU3)
759 | (1 << CP0TCSt_TCU2)
760 | (1 << CP0TCSt_TCU1)
761 | (1 << CP0TCSt_TCU0)
762 | (1 << CP0TCSt_TMX)
763 | (3 << CP0TCSt_TKSU)
764 | (0xff << CP0TCSt_TASID));
765
766 cu = (v >> CP0St_CU0) & 0xf;
767 mx = (v >> CP0St_MX) & 0x1;
768 ksu = (v >> CP0St_KSU) & 0x3;
769 asid = env->CP0_EntryHi & 0xff;
770
771 tcstatus = cu << CP0TCSt_TCU0;
772 tcstatus |= mx << CP0TCSt_TMX;
773 tcstatus |= ksu << CP0TCSt_TKSU;
774 tcstatus |= asid;
775
776 if (tc == cpu->current_tc) {
777 tcst = &cpu->active_tc.CP0_TCStatus;
778 } else {
779 tcst = &cpu->tcs[tc].CP0_TCStatus;
780 }
781
782 *tcst &= ~mask;
783 *tcst |= tcstatus;
784 compute_hflags(cpu);
785}
786
787/* Called for updates to CP0_TCStatus. */
7db13fae 788static void sync_c0_tcstatus(CPUMIPSState *cpu, int tc, target_ulong v)
fe8dca8c
EI
789{
790 uint32_t status;
791 uint32_t tcu, tmx, tasid, tksu;
792 uint32_t mask = ((1 << CP0St_CU3)
793 | (1 << CP0St_CU2)
794 | (1 << CP0St_CU1)
795 | (1 << CP0St_CU0)
796 | (1 << CP0St_MX)
797 | (3 << CP0St_KSU));
798
799 tcu = (v >> CP0TCSt_TCU0) & 0xf;
800 tmx = (v >> CP0TCSt_TMX) & 0x1;
801 tasid = v & 0xff;
802 tksu = (v >> CP0TCSt_TKSU) & 0x3;
803
804 status = tcu << CP0St_CU0;
805 status |= tmx << CP0St_MX;
806 status |= tksu << CP0St_KSU;
807
808 cpu->CP0_Status &= ~mask;
809 cpu->CP0_Status |= status;
810
811 /* Sync the TASID with EntryHi. */
812 cpu->CP0_EntryHi &= ~0xff;
813 cpu->CP0_EntryHi = tasid;
814
815 compute_hflags(cpu);
816}
817
818/* Called for updates to CP0_EntryHi. */
7db13fae 819static void sync_c0_entryhi(CPUMIPSState *cpu, int tc)
fe8dca8c
EI
820{
821 int32_t *tcst;
822 uint32_t asid, v = cpu->CP0_EntryHi;
823
824 asid = v & 0xff;
825
826 if (tc == cpu->current_tc) {
827 tcst = &cpu->active_tc.CP0_TCStatus;
828 } else {
829 tcst = &cpu->tcs[tc].CP0_TCStatus;
830 }
831
832 *tcst &= ~0xff;
833 *tcst |= asid;
834}
835
6af0bf9c 836/* CP0 helpers */
c01fccd2 837target_ulong helper_mfc0_mvpcontrol (void)
f1aa6320 838{
be24bb4f 839 return env->mvp->CP0_MVPControl;
f1aa6320
TS
840}
841
c01fccd2 842target_ulong helper_mfc0_mvpconf0 (void)
f1aa6320 843{
be24bb4f 844 return env->mvp->CP0_MVPConf0;
f1aa6320
TS
845}
846
c01fccd2 847target_ulong helper_mfc0_mvpconf1 (void)
f1aa6320 848{
be24bb4f 849 return env->mvp->CP0_MVPConf1;
f1aa6320
TS
850}
851
c01fccd2 852target_ulong helper_mfc0_random (void)
6af0bf9c 853{
be24bb4f 854 return (int32_t)cpu_mips_get_random(env);
873eb012 855}
6af0bf9c 856
c01fccd2 857target_ulong helper_mfc0_tcstatus (void)
f1aa6320 858{
b5dc7732 859 return env->active_tc.CP0_TCStatus;
f1aa6320
TS
860}
861
c01fccd2 862target_ulong helper_mftc0_tcstatus(void)
f1aa6320
TS
863{
864 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 865 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 866
b93bbdcd
EI
867 if (other_tc == other->current_tc)
868 return other->active_tc.CP0_TCStatus;
b5dc7732 869 else
b93bbdcd 870 return other->tcs[other_tc].CP0_TCStatus;
f1aa6320
TS
871}
872
c01fccd2 873target_ulong helper_mfc0_tcbind (void)
f1aa6320 874{
b5dc7732 875 return env->active_tc.CP0_TCBind;
f1aa6320
TS
876}
877
c01fccd2 878target_ulong helper_mftc0_tcbind(void)
f1aa6320
TS
879{
880 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 881 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 882
b93bbdcd
EI
883 if (other_tc == other->current_tc)
884 return other->active_tc.CP0_TCBind;
b5dc7732 885 else
b93bbdcd 886 return other->tcs[other_tc].CP0_TCBind;
f1aa6320
TS
887}
888
c01fccd2 889target_ulong helper_mfc0_tcrestart (void)
f1aa6320 890{
b5dc7732 891 return env->active_tc.PC;
f1aa6320
TS
892}
893
c01fccd2 894target_ulong helper_mftc0_tcrestart(void)
f1aa6320
TS
895{
896 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 897 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 898
b93bbdcd
EI
899 if (other_tc == other->current_tc)
900 return other->active_tc.PC;
b5dc7732 901 else
b93bbdcd 902 return other->tcs[other_tc].PC;
f1aa6320
TS
903}
904
c01fccd2 905target_ulong helper_mfc0_tchalt (void)
f1aa6320 906{
b5dc7732 907 return env->active_tc.CP0_TCHalt;
f1aa6320
TS
908}
909
c01fccd2 910target_ulong helper_mftc0_tchalt(void)
f1aa6320
TS
911{
912 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 913 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 914
b93bbdcd
EI
915 if (other_tc == other->current_tc)
916 return other->active_tc.CP0_TCHalt;
b5dc7732 917 else
b93bbdcd 918 return other->tcs[other_tc].CP0_TCHalt;
f1aa6320
TS
919}
920
c01fccd2 921target_ulong helper_mfc0_tccontext (void)
f1aa6320 922{
b5dc7732 923 return env->active_tc.CP0_TCContext;
f1aa6320
TS
924}
925
c01fccd2 926target_ulong helper_mftc0_tccontext(void)
f1aa6320
TS
927{
928 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 929 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 930
b93bbdcd
EI
931 if (other_tc == other->current_tc)
932 return other->active_tc.CP0_TCContext;
b5dc7732 933 else
b93bbdcd 934 return other->tcs[other_tc].CP0_TCContext;
f1aa6320
TS
935}
936
c01fccd2 937target_ulong helper_mfc0_tcschedule (void)
f1aa6320 938{
b5dc7732 939 return env->active_tc.CP0_TCSchedule;
f1aa6320
TS
940}
941
c01fccd2 942target_ulong helper_mftc0_tcschedule(void)
f1aa6320
TS
943{
944 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 945 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 946
b93bbdcd
EI
947 if (other_tc == other->current_tc)
948 return other->active_tc.CP0_TCSchedule;
b5dc7732 949 else
b93bbdcd 950 return other->tcs[other_tc].CP0_TCSchedule;
f1aa6320
TS
951}
952
c01fccd2 953target_ulong helper_mfc0_tcschefback (void)
f1aa6320 954{
b5dc7732 955 return env->active_tc.CP0_TCScheFBack;
f1aa6320
TS
956}
957
c01fccd2 958target_ulong helper_mftc0_tcschefback(void)
f1aa6320
TS
959{
960 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 961 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 962
b93bbdcd
EI
963 if (other_tc == other->current_tc)
964 return other->active_tc.CP0_TCScheFBack;
b5dc7732 965 else
b93bbdcd 966 return other->tcs[other_tc].CP0_TCScheFBack;
f1aa6320
TS
967}
968
c01fccd2 969target_ulong helper_mfc0_count (void)
873eb012 970{
be24bb4f 971 return (int32_t)cpu_mips_get_count(env);
6af0bf9c
FB
972}
973
c01fccd2 974target_ulong helper_mftc0_entryhi(void)
f1aa6320
TS
975{
976 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 977 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 978
fe8dca8c 979 return other->CP0_EntryHi;
f1aa6320
TS
980}
981
5a25ce94
EI
982target_ulong helper_mftc0_cause(void)
983{
984 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
985 int32_t tccause;
7db13fae 986 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
5a25ce94
EI
987
988 if (other_tc == other->current_tc) {
989 tccause = other->CP0_Cause;
990 } else {
991 tccause = other->CP0_Cause;
992 }
993
994 return tccause;
995}
996
c01fccd2 997target_ulong helper_mftc0_status(void)
f1aa6320
TS
998{
999 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1000 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
b5dc7732 1001
fe8dca8c 1002 return other->CP0_Status;
f1aa6320
TS
1003}
1004
c01fccd2 1005target_ulong helper_mfc0_lladdr (void)
f1aa6320 1006{
2a6e32dd 1007 return (int32_t)(env->lladdr >> env->CP0_LLAddr_shift);
f1aa6320
TS
1008}
1009
c01fccd2 1010target_ulong helper_mfc0_watchlo (uint32_t sel)
f1aa6320 1011{
be24bb4f 1012 return (int32_t)env->CP0_WatchLo[sel];
f1aa6320
TS
1013}
1014
c01fccd2 1015target_ulong helper_mfc0_watchhi (uint32_t sel)
f1aa6320 1016{
be24bb4f 1017 return env->CP0_WatchHi[sel];
f1aa6320
TS
1018}
1019
c01fccd2 1020target_ulong helper_mfc0_debug (void)
f1aa6320 1021{
1a3fd9c3 1022 target_ulong t0 = env->CP0_Debug;
f1aa6320 1023 if (env->hflags & MIPS_HFLAG_DM)
be24bb4f
TS
1024 t0 |= 1 << CP0DB_DM;
1025
1026 return t0;
f1aa6320
TS
1027}
1028
c01fccd2 1029target_ulong helper_mftc0_debug(void)
f1aa6320
TS
1030{
1031 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
b5dc7732 1032 int32_t tcstatus;
7db13fae 1033 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
b5dc7732 1034
b93bbdcd
EI
1035 if (other_tc == other->current_tc)
1036 tcstatus = other->active_tc.CP0_Debug_tcstatus;
b5dc7732 1037 else
b93bbdcd 1038 tcstatus = other->tcs[other_tc].CP0_Debug_tcstatus;
f1aa6320
TS
1039
1040 /* XXX: Might be wrong, check with EJTAG spec. */
b93bbdcd 1041 return (other->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
b5dc7732 1042 (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
f1aa6320
TS
1043}
1044
1045#if defined(TARGET_MIPS64)
c01fccd2 1046target_ulong helper_dmfc0_tcrestart (void)
f1aa6320 1047{
b5dc7732 1048 return env->active_tc.PC;
f1aa6320
TS
1049}
1050
c01fccd2 1051target_ulong helper_dmfc0_tchalt (void)
f1aa6320 1052{
b5dc7732 1053 return env->active_tc.CP0_TCHalt;
f1aa6320
TS
1054}
1055
c01fccd2 1056target_ulong helper_dmfc0_tccontext (void)
f1aa6320 1057{
b5dc7732 1058 return env->active_tc.CP0_TCContext;
f1aa6320
TS
1059}
1060
c01fccd2 1061target_ulong helper_dmfc0_tcschedule (void)
f1aa6320 1062{
b5dc7732 1063 return env->active_tc.CP0_TCSchedule;
f1aa6320
TS
1064}
1065
c01fccd2 1066target_ulong helper_dmfc0_tcschefback (void)
f1aa6320 1067{
b5dc7732 1068 return env->active_tc.CP0_TCScheFBack;
f1aa6320
TS
1069}
1070
c01fccd2 1071target_ulong helper_dmfc0_lladdr (void)
f1aa6320 1072{
2a6e32dd 1073 return env->lladdr >> env->CP0_LLAddr_shift;
f1aa6320
TS
1074}
1075
c01fccd2 1076target_ulong helper_dmfc0_watchlo (uint32_t sel)
f1aa6320 1077{
be24bb4f 1078 return env->CP0_WatchLo[sel];
f1aa6320
TS
1079}
1080#endif /* TARGET_MIPS64 */
1081
d9bea114 1082void helper_mtc0_index (target_ulong arg1)
f1aa6320
TS
1083{
1084 int num = 1;
1085 unsigned int tmp = env->tlb->nb_tlb;
1086
1087 do {
1088 tmp >>= 1;
1089 num <<= 1;
1090 } while (tmp);
d9bea114 1091 env->CP0_Index = (env->CP0_Index & 0x80000000) | (arg1 & (num - 1));
f1aa6320
TS
1092}
1093
d9bea114 1094void helper_mtc0_mvpcontrol (target_ulong arg1)
f1aa6320
TS
1095{
1096 uint32_t mask = 0;
1097 uint32_t newval;
1098
1099 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))
1100 mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) |
1101 (1 << CP0MVPCo_EVP);
1102 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1103 mask |= (1 << CP0MVPCo_STLB);
d9bea114 1104 newval = (env->mvp->CP0_MVPControl & ~mask) | (arg1 & mask);
f1aa6320
TS
1105
1106 // TODO: Enable/disable shared TLB, enable/disable VPEs.
1107
1108 env->mvp->CP0_MVPControl = newval;
1109}
1110
d9bea114 1111void helper_mtc0_vpecontrol (target_ulong arg1)
f1aa6320
TS
1112{
1113 uint32_t mask;
1114 uint32_t newval;
1115
1116 mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
1117 (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
d9bea114 1118 newval = (env->CP0_VPEControl & ~mask) | (arg1 & mask);
f1aa6320
TS
1119
1120 /* Yield scheduler intercept not implemented. */
1121 /* Gating storage scheduler intercept not implemented. */
1122
1123 // TODO: Enable/disable TCs.
1124
1125 env->CP0_VPEControl = newval;
1126}
1127
5a25ce94
EI
1128void helper_mttc0_vpecontrol(target_ulong arg1)
1129{
1130 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1131 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
5a25ce94
EI
1132 uint32_t mask;
1133 uint32_t newval;
1134
1135 mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
1136 (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
1137 newval = (other->CP0_VPEControl & ~mask) | (arg1 & mask);
1138
1139 /* TODO: Enable/disable TCs. */
1140
1141 other->CP0_VPEControl = newval;
1142}
1143
1144target_ulong helper_mftc0_vpecontrol(void)
1145{
1146 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1147 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
5a25ce94
EI
1148 /* FIXME: Mask away return zero on read bits. */
1149 return other->CP0_VPEControl;
1150}
1151
1152target_ulong helper_mftc0_vpeconf0(void)
1153{
1154 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1155 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
5a25ce94
EI
1156
1157 return other->CP0_VPEConf0;
1158}
1159
d9bea114 1160void helper_mtc0_vpeconf0 (target_ulong arg1)
f1aa6320
TS
1161{
1162 uint32_t mask = 0;
1163 uint32_t newval;
1164
1165 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) {
1166 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))
1167 mask |= (0xff << CP0VPEC0_XTC);
1168 mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
1169 }
d9bea114 1170 newval = (env->CP0_VPEConf0 & ~mask) | (arg1 & mask);
f1aa6320
TS
1171
1172 // TODO: TC exclusive handling due to ERL/EXL.
1173
1174 env->CP0_VPEConf0 = newval;
1175}
1176
5a25ce94
EI
1177void helper_mttc0_vpeconf0(target_ulong arg1)
1178{
1179 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1180 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
5a25ce94
EI
1181 uint32_t mask = 0;
1182 uint32_t newval;
1183
1184 mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
1185 newval = (other->CP0_VPEConf0 & ~mask) | (arg1 & mask);
1186
1187 /* TODO: TC exclusive handling due to ERL/EXL. */
1188 other->CP0_VPEConf0 = newval;
1189}
1190
d9bea114 1191void helper_mtc0_vpeconf1 (target_ulong arg1)
f1aa6320
TS
1192{
1193 uint32_t mask = 0;
1194 uint32_t newval;
1195
1196 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1197 mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) |
1198 (0xff << CP0VPEC1_NCP1);
d9bea114 1199 newval = (env->CP0_VPEConf1 & ~mask) | (arg1 & mask);
f1aa6320
TS
1200
1201 /* UDI not implemented. */
1202 /* CP2 not implemented. */
1203
1204 // TODO: Handle FPU (CP1) binding.
1205
1206 env->CP0_VPEConf1 = newval;
1207}
1208
d9bea114 1209void helper_mtc0_yqmask (target_ulong arg1)
f1aa6320
TS
1210{
1211 /* Yield qualifier inputs not implemented. */
1212 env->CP0_YQMask = 0x00000000;
1213}
1214
d9bea114 1215void helper_mtc0_vpeopt (target_ulong arg1)
f1aa6320 1216{
d9bea114 1217 env->CP0_VPEOpt = arg1 & 0x0000ffff;
f1aa6320
TS
1218}
1219
d9bea114 1220void helper_mtc0_entrylo0 (target_ulong arg1)
f1aa6320
TS
1221{
1222 /* Large physaddr (PABITS) not implemented */
1223 /* 1k pages not implemented */
d9bea114 1224 env->CP0_EntryLo0 = arg1 & 0x3FFFFFFF;
f1aa6320
TS
1225}
1226
d9bea114 1227void helper_mtc0_tcstatus (target_ulong arg1)
f1aa6320
TS
1228{
1229 uint32_t mask = env->CP0_TCStatus_rw_bitmask;
1230 uint32_t newval;
1231
d9bea114 1232 newval = (env->active_tc.CP0_TCStatus & ~mask) | (arg1 & mask);
f1aa6320 1233
b5dc7732 1234 env->active_tc.CP0_TCStatus = newval;
fe8dca8c 1235 sync_c0_tcstatus(env, env->current_tc, newval);
f1aa6320
TS
1236}
1237
d9bea114 1238void helper_mttc0_tcstatus (target_ulong arg1)
f1aa6320
TS
1239{
1240 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1241 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 1242
b93bbdcd
EI
1243 if (other_tc == other->current_tc)
1244 other->active_tc.CP0_TCStatus = arg1;
b5dc7732 1245 else
b93bbdcd 1246 other->tcs[other_tc].CP0_TCStatus = arg1;
fe8dca8c 1247 sync_c0_tcstatus(other, other_tc, arg1);
f1aa6320
TS
1248}
1249
d9bea114 1250void helper_mtc0_tcbind (target_ulong arg1)
f1aa6320
TS
1251{
1252 uint32_t mask = (1 << CP0TCBd_TBE);
1253 uint32_t newval;
1254
1255 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1256 mask |= (1 << CP0TCBd_CurVPE);
d9bea114 1257 newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
b5dc7732 1258 env->active_tc.CP0_TCBind = newval;
f1aa6320
TS
1259}
1260
d9bea114 1261void helper_mttc0_tcbind (target_ulong arg1)
f1aa6320
TS
1262{
1263 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1264 uint32_t mask = (1 << CP0TCBd_TBE);
1265 uint32_t newval;
7db13fae 1266 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 1267
b93bbdcd 1268 if (other->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
f1aa6320 1269 mask |= (1 << CP0TCBd_CurVPE);
b93bbdcd
EI
1270 if (other_tc == other->current_tc) {
1271 newval = (other->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
1272 other->active_tc.CP0_TCBind = newval;
b5dc7732 1273 } else {
b93bbdcd
EI
1274 newval = (other->tcs[other_tc].CP0_TCBind & ~mask) | (arg1 & mask);
1275 other->tcs[other_tc].CP0_TCBind = newval;
b5dc7732 1276 }
f1aa6320
TS
1277}
1278
d9bea114 1279void helper_mtc0_tcrestart (target_ulong arg1)
f1aa6320 1280{
d9bea114 1281 env->active_tc.PC = arg1;
b5dc7732 1282 env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
5499b6ff 1283 env->lladdr = 0ULL;
f1aa6320
TS
1284 /* MIPS16 not implemented. */
1285}
1286
d9bea114 1287void helper_mttc0_tcrestart (target_ulong arg1)
f1aa6320
TS
1288{
1289 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1290 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 1291
b93bbdcd
EI
1292 if (other_tc == other->current_tc) {
1293 other->active_tc.PC = arg1;
1294 other->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1295 other->lladdr = 0ULL;
b5dc7732
TS
1296 /* MIPS16 not implemented. */
1297 } else {
b93bbdcd
EI
1298 other->tcs[other_tc].PC = arg1;
1299 other->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1300 other->lladdr = 0ULL;
b5dc7732
TS
1301 /* MIPS16 not implemented. */
1302 }
f1aa6320
TS
1303}
1304
d9bea114 1305void helper_mtc0_tchalt (target_ulong arg1)
f1aa6320 1306{
d9bea114 1307 env->active_tc.CP0_TCHalt = arg1 & 0x1;
f1aa6320
TS
1308
1309 // TODO: Halt TC / Restart (if allocated+active) TC.
f249412c
EI
1310 if (env->active_tc.CP0_TCHalt & 1) {
1311 mips_tc_sleep(env, env->current_tc);
1312 } else {
1313 mips_tc_wake(env, env->current_tc);
1314 }
f1aa6320
TS
1315}
1316
d9bea114 1317void helper_mttc0_tchalt (target_ulong arg1)
f1aa6320
TS
1318{
1319 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1320 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320
TS
1321
1322 // TODO: Halt TC / Restart (if allocated+active) TC.
1323
b93bbdcd
EI
1324 if (other_tc == other->current_tc)
1325 other->active_tc.CP0_TCHalt = arg1;
b5dc7732 1326 else
b93bbdcd 1327 other->tcs[other_tc].CP0_TCHalt = arg1;
f249412c
EI
1328
1329 if (arg1 & 1) {
1330 mips_tc_sleep(other, other_tc);
1331 } else {
1332 mips_tc_wake(other, other_tc);
1333 }
f1aa6320
TS
1334}
1335
d9bea114 1336void helper_mtc0_tccontext (target_ulong arg1)
f1aa6320 1337{
d9bea114 1338 env->active_tc.CP0_TCContext = arg1;
f1aa6320
TS
1339}
1340
d9bea114 1341void helper_mttc0_tccontext (target_ulong arg1)
f1aa6320
TS
1342{
1343 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1344 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 1345
b93bbdcd
EI
1346 if (other_tc == other->current_tc)
1347 other->active_tc.CP0_TCContext = arg1;
b5dc7732 1348 else
b93bbdcd 1349 other->tcs[other_tc].CP0_TCContext = arg1;
f1aa6320
TS
1350}
1351
d9bea114 1352void helper_mtc0_tcschedule (target_ulong arg1)
f1aa6320 1353{
d9bea114 1354 env->active_tc.CP0_TCSchedule = arg1;
f1aa6320
TS
1355}
1356
d9bea114 1357void helper_mttc0_tcschedule (target_ulong arg1)
f1aa6320
TS
1358{
1359 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1360 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 1361
b93bbdcd
EI
1362 if (other_tc == other->current_tc)
1363 other->active_tc.CP0_TCSchedule = arg1;
b5dc7732 1364 else
b93bbdcd 1365 other->tcs[other_tc].CP0_TCSchedule = arg1;
f1aa6320
TS
1366}
1367
d9bea114 1368void helper_mtc0_tcschefback (target_ulong arg1)
f1aa6320 1369{
d9bea114 1370 env->active_tc.CP0_TCScheFBack = arg1;
f1aa6320
TS
1371}
1372
d9bea114 1373void helper_mttc0_tcschefback (target_ulong arg1)
f1aa6320
TS
1374{
1375 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1376 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 1377
b93bbdcd
EI
1378 if (other_tc == other->current_tc)
1379 other->active_tc.CP0_TCScheFBack = arg1;
b5dc7732 1380 else
b93bbdcd 1381 other->tcs[other_tc].CP0_TCScheFBack = arg1;
f1aa6320
TS
1382}
1383
d9bea114 1384void helper_mtc0_entrylo1 (target_ulong arg1)
f1aa6320
TS
1385{
1386 /* Large physaddr (PABITS) not implemented */
1387 /* 1k pages not implemented */
d9bea114 1388 env->CP0_EntryLo1 = arg1 & 0x3FFFFFFF;
f1aa6320
TS
1389}
1390
d9bea114 1391void helper_mtc0_context (target_ulong arg1)
f1aa6320 1392{
d9bea114 1393 env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF);
f1aa6320
TS
1394}
1395
d9bea114 1396void helper_mtc0_pagemask (target_ulong arg1)
f1aa6320
TS
1397{
1398 /* 1k pages not implemented */
d9bea114 1399 env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
f1aa6320
TS
1400}
1401
d9bea114 1402void helper_mtc0_pagegrain (target_ulong arg1)
f1aa6320
TS
1403{
1404 /* SmartMIPS not implemented */
1405 /* Large physaddr (PABITS) not implemented */
1406 /* 1k pages not implemented */
1407 env->CP0_PageGrain = 0;
1408}
1409
d9bea114 1410void helper_mtc0_wired (target_ulong arg1)
f1aa6320 1411{
d9bea114 1412 env->CP0_Wired = arg1 % env->tlb->nb_tlb;
f1aa6320
TS
1413}
1414
d9bea114 1415void helper_mtc0_srsconf0 (target_ulong arg1)
f1aa6320 1416{
d9bea114 1417 env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask;
f1aa6320
TS
1418}
1419
d9bea114 1420void helper_mtc0_srsconf1 (target_ulong arg1)
f1aa6320 1421{
d9bea114 1422 env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask;
f1aa6320
TS
1423}
1424
d9bea114 1425void helper_mtc0_srsconf2 (target_ulong arg1)
f1aa6320 1426{
d9bea114 1427 env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask;
f1aa6320
TS
1428}
1429
d9bea114 1430void helper_mtc0_srsconf3 (target_ulong arg1)
f1aa6320 1431{
d9bea114 1432 env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask;
f1aa6320
TS
1433}
1434
d9bea114 1435void helper_mtc0_srsconf4 (target_ulong arg1)
f1aa6320 1436{
d9bea114 1437 env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask;
f1aa6320
TS
1438}
1439
d9bea114 1440void helper_mtc0_hwrena (target_ulong arg1)
f1aa6320 1441{
d9bea114 1442 env->CP0_HWREna = arg1 & 0x0000000F;
f1aa6320
TS
1443}
1444
d9bea114 1445void helper_mtc0_count (target_ulong arg1)
f1aa6320 1446{
d9bea114 1447 cpu_mips_store_count(env, arg1);
f1aa6320
TS
1448}
1449
d9bea114 1450void helper_mtc0_entryhi (target_ulong arg1)
f1aa6320
TS
1451{
1452 target_ulong old, val;
1453
1454 /* 1k pages not implemented */
d9bea114 1455 val = arg1 & ((TARGET_PAGE_MASK << 1) | 0xFF);
f1aa6320
TS
1456#if defined(TARGET_MIPS64)
1457 val &= env->SEGMask;
1458#endif
1459 old = env->CP0_EntryHi;
1460 env->CP0_EntryHi = val;
1461 if (env->CP0_Config3 & (1 << CP0C3_MT)) {
fe8dca8c 1462 sync_c0_entryhi(env, env->current_tc);
f1aa6320
TS
1463 }
1464 /* If the ASID changes, flush qemu's TLB. */
1465 if ((old & 0xFF) != (val & 0xFF))
1466 cpu_mips_tlb_flush(env, 1);
1467}
1468
d9bea114 1469void helper_mttc0_entryhi(target_ulong arg1)
f1aa6320
TS
1470{
1471 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1472 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 1473
fe8dca8c
EI
1474 other->CP0_EntryHi = arg1;
1475 sync_c0_entryhi(other, other_tc);
f1aa6320
TS
1476}
1477
d9bea114 1478void helper_mtc0_compare (target_ulong arg1)
f1aa6320 1479{
d9bea114 1480 cpu_mips_store_compare(env, arg1);
f1aa6320
TS
1481}
1482
d9bea114 1483void helper_mtc0_status (target_ulong arg1)
f1aa6320
TS
1484{
1485 uint32_t val, old;
1486 uint32_t mask = env->CP0_Status_rw_bitmask;
1487
d9bea114 1488 val = arg1 & mask;
f1aa6320
TS
1489 old = env->CP0_Status;
1490 env->CP0_Status = (env->CP0_Status & ~mask) | val;
fe8dca8c
EI
1491 if (env->CP0_Config3 & (1 << CP0C3_MT)) {
1492 sync_c0_status(env, env->current_tc);
1493 } else {
1494 compute_hflags(env);
1495 }
1496
c01fccd2
AJ
1497 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1498 qemu_log("Status %08x (%08x) => %08x (%08x) Cause %08x",
1499 old, old & env->CP0_Cause & CP0Ca_IP_mask,
1500 val, val & env->CP0_Cause & CP0Ca_IP_mask,
1501 env->CP0_Cause);
1502 switch (env->hflags & MIPS_HFLAG_KSU) {
1503 case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
1504 case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
1505 case MIPS_HFLAG_KM: qemu_log("\n"); break;
1506 default: cpu_abort(env, "Invalid MMU mode!\n"); break;
31e3104f 1507 }
c01fccd2 1508 }
f1aa6320
TS
1509}
1510
d9bea114 1511void helper_mttc0_status(target_ulong arg1)
f1aa6320
TS
1512{
1513 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1514 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 1515
b93bbdcd 1516 other->CP0_Status = arg1 & ~0xf1000018;
fe8dca8c 1517 sync_c0_status(other, other_tc);
f1aa6320
TS
1518}
1519
d9bea114 1520void helper_mtc0_intctl (target_ulong arg1)
f1aa6320
TS
1521{
1522 /* vectored interrupts not implemented, no performance counters. */
bc45a67a 1523 env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000003e0) | (arg1 & 0x000003e0);
f1aa6320
TS
1524}
1525
d9bea114 1526void helper_mtc0_srsctl (target_ulong arg1)
f1aa6320
TS
1527{
1528 uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
d9bea114 1529 env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask);
f1aa6320
TS
1530}
1531
7db13fae 1532static void mtc0_cause(CPUMIPSState *cpu, target_ulong arg1)
f1aa6320
TS
1533{
1534 uint32_t mask = 0x00C00300;
5a25ce94 1535 uint32_t old = cpu->CP0_Cause;
5dc5d9f0 1536 int i;
f1aa6320 1537
5a25ce94 1538 if (cpu->insn_flags & ISA_MIPS32R2) {
f1aa6320 1539 mask |= 1 << CP0Ca_DC;
5a25ce94 1540 }
f1aa6320 1541
5a25ce94 1542 cpu->CP0_Cause = (cpu->CP0_Cause & ~mask) | (arg1 & mask);
f1aa6320 1543
5a25ce94
EI
1544 if ((old ^ cpu->CP0_Cause) & (1 << CP0Ca_DC)) {
1545 if (cpu->CP0_Cause & (1 << CP0Ca_DC)) {
1546 cpu_mips_stop_count(cpu);
1547 } else {
1548 cpu_mips_start_count(cpu);
1549 }
f1aa6320 1550 }
5dc5d9f0
AJ
1551
1552 /* Set/reset software interrupts */
1553 for (i = 0 ; i < 2 ; i++) {
5a25ce94
EI
1554 if ((old ^ cpu->CP0_Cause) & (1 << (CP0Ca_IP + i))) {
1555 cpu_mips_soft_irq(cpu, i, cpu->CP0_Cause & (1 << (CP0Ca_IP + i)));
5dc5d9f0
AJ
1556 }
1557 }
f1aa6320
TS
1558}
1559
5a25ce94
EI
1560void helper_mtc0_cause(target_ulong arg1)
1561{
1562 mtc0_cause(env, arg1);
1563}
1564
1565void helper_mttc0_cause(target_ulong arg1)
1566{
1567 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1568 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
5a25ce94
EI
1569
1570 mtc0_cause(other, arg1);
1571}
1572
1573target_ulong helper_mftc0_epc(void)
1574{
1575 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1576 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
5a25ce94
EI
1577
1578 return other->CP0_EPC;
1579}
1580
1581target_ulong helper_mftc0_ebase(void)
1582{
1583 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1584 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
5a25ce94
EI
1585
1586 return other->CP0_EBase;
1587}
1588
d9bea114 1589void helper_mtc0_ebase (target_ulong arg1)
f1aa6320
TS
1590{
1591 /* vectored interrupts not implemented */
671b0f36 1592 env->CP0_EBase = (env->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
f1aa6320
TS
1593}
1594
5a25ce94
EI
1595void helper_mttc0_ebase(target_ulong arg1)
1596{
1597 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1598 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
5a25ce94
EI
1599 other->CP0_EBase = (other->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
1600}
1601
1602target_ulong helper_mftc0_configx(target_ulong idx)
1603{
1604 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1605 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
5a25ce94
EI
1606
1607 switch (idx) {
1608 case 0: return other->CP0_Config0;
1609 case 1: return other->CP0_Config1;
1610 case 2: return other->CP0_Config2;
1611 case 3: return other->CP0_Config3;
1612 /* 4 and 5 are reserved. */
1613 case 6: return other->CP0_Config6;
1614 case 7: return other->CP0_Config7;
1615 default:
1616 break;
1617 }
1618 return 0;
1619}
1620
d9bea114 1621void helper_mtc0_config0 (target_ulong arg1)
f1aa6320 1622{
d9bea114 1623 env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007);
f1aa6320
TS
1624}
1625
d9bea114 1626void helper_mtc0_config2 (target_ulong arg1)
f1aa6320
TS
1627{
1628 /* tertiary/secondary caches not implemented */
1629 env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
1630}
1631
2a6e32dd
AJ
1632void helper_mtc0_lladdr (target_ulong arg1)
1633{
1634 target_long mask = env->CP0_LLAddr_rw_bitmask;
1635 arg1 = arg1 << env->CP0_LLAddr_shift;
1636 env->lladdr = (env->lladdr & ~mask) | (arg1 & mask);
1637}
1638
d9bea114 1639void helper_mtc0_watchlo (target_ulong arg1, uint32_t sel)
f1aa6320
TS
1640{
1641 /* Watch exceptions for instructions, data loads, data stores
1642 not implemented. */
d9bea114 1643 env->CP0_WatchLo[sel] = (arg1 & ~0x7);
f1aa6320
TS
1644}
1645
d9bea114 1646void helper_mtc0_watchhi (target_ulong arg1, uint32_t sel)
f1aa6320 1647{
d9bea114
AJ
1648 env->CP0_WatchHi[sel] = (arg1 & 0x40FF0FF8);
1649 env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7);
f1aa6320
TS
1650}
1651
d9bea114 1652void helper_mtc0_xcontext (target_ulong arg1)
f1aa6320
TS
1653{
1654 target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
d9bea114 1655 env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask);
f1aa6320
TS
1656}
1657
d9bea114 1658void helper_mtc0_framemask (target_ulong arg1)
f1aa6320 1659{
d9bea114 1660 env->CP0_Framemask = arg1; /* XXX */
f1aa6320
TS
1661}
1662
d9bea114 1663void helper_mtc0_debug (target_ulong arg1)
f1aa6320 1664{
d9bea114
AJ
1665 env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120);
1666 if (arg1 & (1 << CP0DB_DM))
f1aa6320
TS
1667 env->hflags |= MIPS_HFLAG_DM;
1668 else
1669 env->hflags &= ~MIPS_HFLAG_DM;
1670}
1671
d9bea114 1672void helper_mttc0_debug(target_ulong arg1)
f1aa6320
TS
1673{
1674 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
d9bea114 1675 uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
7db13fae 1676 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320
TS
1677
1678 /* XXX: Might be wrong, check with EJTAG spec. */
b93bbdcd
EI
1679 if (other_tc == other->current_tc)
1680 other->active_tc.CP0_Debug_tcstatus = val;
b5dc7732 1681 else
b93bbdcd
EI
1682 other->tcs[other_tc].CP0_Debug_tcstatus = val;
1683 other->CP0_Debug = (other->CP0_Debug &
1684 ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
d9bea114 1685 (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
f1aa6320
TS
1686}
1687
d9bea114 1688void helper_mtc0_performance0 (target_ulong arg1)
f1aa6320 1689{
d9bea114 1690 env->CP0_Performance0 = arg1 & 0x000007ff;
f1aa6320
TS
1691}
1692
d9bea114 1693void helper_mtc0_taglo (target_ulong arg1)
f1aa6320 1694{
d9bea114 1695 env->CP0_TagLo = arg1 & 0xFFFFFCF6;
f1aa6320
TS
1696}
1697
d9bea114 1698void helper_mtc0_datalo (target_ulong arg1)
f1aa6320 1699{
d9bea114 1700 env->CP0_DataLo = arg1; /* XXX */
f1aa6320
TS
1701}
1702
d9bea114 1703void helper_mtc0_taghi (target_ulong arg1)
f1aa6320 1704{
d9bea114 1705 env->CP0_TagHi = arg1; /* XXX */
f1aa6320
TS
1706}
1707
d9bea114 1708void helper_mtc0_datahi (target_ulong arg1)
f1aa6320 1709{
d9bea114 1710 env->CP0_DataHi = arg1; /* XXX */
f1aa6320
TS
1711}
1712
f1aa6320 1713/* MIPS MT functions */
c01fccd2 1714target_ulong helper_mftgpr(uint32_t sel)
f1aa6320
TS
1715{
1716 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1717 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 1718
b93bbdcd
EI
1719 if (other_tc == other->current_tc)
1720 return other->active_tc.gpr[sel];
b5dc7732 1721 else
b93bbdcd 1722 return other->tcs[other_tc].gpr[sel];
f1aa6320
TS
1723}
1724
c01fccd2 1725target_ulong helper_mftlo(uint32_t sel)
f1aa6320
TS
1726{
1727 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1728 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 1729
b93bbdcd
EI
1730 if (other_tc == other->current_tc)
1731 return other->active_tc.LO[sel];
b5dc7732 1732 else
b93bbdcd 1733 return other->tcs[other_tc].LO[sel];
f1aa6320
TS
1734}
1735
c01fccd2 1736target_ulong helper_mfthi(uint32_t sel)
f1aa6320
TS
1737{
1738 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1739 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 1740
b93bbdcd
EI
1741 if (other_tc == other->current_tc)
1742 return other->active_tc.HI[sel];
b5dc7732 1743 else
b93bbdcd 1744 return other->tcs[other_tc].HI[sel];
f1aa6320
TS
1745}
1746
c01fccd2 1747target_ulong helper_mftacx(uint32_t sel)
f1aa6320
TS
1748{
1749 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1750 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 1751
b93bbdcd
EI
1752 if (other_tc == other->current_tc)
1753 return other->active_tc.ACX[sel];
b5dc7732 1754 else
b93bbdcd 1755 return other->tcs[other_tc].ACX[sel];
f1aa6320
TS
1756}
1757
c01fccd2 1758target_ulong helper_mftdsp(void)
f1aa6320
TS
1759{
1760 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1761 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 1762
b93bbdcd
EI
1763 if (other_tc == other->current_tc)
1764 return other->active_tc.DSPControl;
b5dc7732 1765 else
b93bbdcd 1766 return other->tcs[other_tc].DSPControl;
f1aa6320 1767}
6af0bf9c 1768
d9bea114 1769void helper_mttgpr(target_ulong arg1, uint32_t sel)
f1aa6320
TS
1770{
1771 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1772 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 1773
b93bbdcd
EI
1774 if (other_tc == other->current_tc)
1775 other->active_tc.gpr[sel] = arg1;
b5dc7732 1776 else
b93bbdcd 1777 other->tcs[other_tc].gpr[sel] = arg1;
f1aa6320
TS
1778}
1779
d9bea114 1780void helper_mttlo(target_ulong arg1, uint32_t sel)
f1aa6320
TS
1781{
1782 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1783 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 1784
b93bbdcd
EI
1785 if (other_tc == other->current_tc)
1786 other->active_tc.LO[sel] = arg1;
b5dc7732 1787 else
b93bbdcd 1788 other->tcs[other_tc].LO[sel] = arg1;
f1aa6320
TS
1789}
1790
d9bea114 1791void helper_mtthi(target_ulong arg1, uint32_t sel)
f1aa6320
TS
1792{
1793 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1794 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 1795
b93bbdcd
EI
1796 if (other_tc == other->current_tc)
1797 other->active_tc.HI[sel] = arg1;
b5dc7732 1798 else
b93bbdcd 1799 other->tcs[other_tc].HI[sel] = arg1;
f1aa6320
TS
1800}
1801
d9bea114 1802void helper_mttacx(target_ulong arg1, uint32_t sel)
f1aa6320
TS
1803{
1804 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1805 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 1806
b93bbdcd
EI
1807 if (other_tc == other->current_tc)
1808 other->active_tc.ACX[sel] = arg1;
b5dc7732 1809 else
b93bbdcd 1810 other->tcs[other_tc].ACX[sel] = arg1;
f1aa6320
TS
1811}
1812
d9bea114 1813void helper_mttdsp(target_ulong arg1)
f1aa6320
TS
1814{
1815 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
7db13fae 1816 CPUMIPSState *other = mips_cpu_map_tc(&other_tc);
f1aa6320 1817
b93bbdcd
EI
1818 if (other_tc == other->current_tc)
1819 other->active_tc.DSPControl = arg1;
b5dc7732 1820 else
b93bbdcd 1821 other->tcs[other_tc].DSPControl = arg1;
f1aa6320
TS
1822}
1823
1824/* MIPS MT functions */
9ed5726c 1825target_ulong helper_dmt(void)
f1aa6320
TS
1826{
1827 // TODO
9ed5726c 1828 return 0;
f1aa6320
TS
1829}
1830
9ed5726c 1831target_ulong helper_emt(void)
f1aa6320
TS
1832{
1833 // TODO
9ed5726c 1834 return 0;
f1aa6320
TS
1835}
1836
9ed5726c 1837target_ulong helper_dvpe(void)
f1aa6320 1838{
7db13fae 1839 CPUMIPSState *other_cpu = first_cpu;
f249412c
EI
1840 target_ulong prev = env->mvp->CP0_MVPControl;
1841
1842 do {
1843 /* Turn off all VPEs except the one executing the dvpe. */
1844 if (other_cpu != env) {
1845 other_cpu->mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP);
1846 mips_vpe_sleep(other_cpu);
1847 }
1848 other_cpu = other_cpu->next_cpu;
1849 } while (other_cpu);
1850 return prev;
f1aa6320
TS
1851}
1852
9ed5726c 1853target_ulong helper_evpe(void)
f1aa6320 1854{
7db13fae 1855 CPUMIPSState *other_cpu = first_cpu;
f249412c
EI
1856 target_ulong prev = env->mvp->CP0_MVPControl;
1857
1858 do {
1859 if (other_cpu != env
93148aa5 1860 /* If the VPE is WFI, don't disturb its sleep. */
f249412c
EI
1861 && !mips_vpe_is_wfi(other_cpu)) {
1862 /* Enable the VPE. */
1863 other_cpu->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
1864 mips_vpe_wake(other_cpu); /* And wake it up. */
1865 }
1866 other_cpu = other_cpu->next_cpu;
1867 } while (other_cpu);
1868 return prev;
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 */
7db13fae 1911static void cpu_mips_tlb_flush (CPUMIPSState *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
7db13fae 1918static void r4k_mips_tlb_flush_extra (CPUMIPSState *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 {
b69e48a8 2206 unsigned char *fmt = (void *)(uintptr_t)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;
f249412c 2216 cpu_reset_interrupt(env, CPU_INTERRUPT_WAKE);
c01fccd2 2217 helper_raise_exception(EXCP_HLT);
08ba7963
TS
2218}
2219
5fafdf24 2220#if !defined(CONFIG_USER_ONLY)
e37e863f 2221
59821ae8 2222static void QEMU_NORETURN do_unaligned_access(target_ulong addr, int is_write,
20503968 2223 int is_user, uintptr_t retaddr);
4ad40f36 2224
e37e863f 2225#define MMUSUFFIX _mmu
4ad40f36 2226#define ALIGNED_ONLY
e37e863f
FB
2227
2228#define SHIFT 0
2229#include "softmmu_template.h"
2230
2231#define SHIFT 1
2232#include "softmmu_template.h"
2233
2234#define SHIFT 2
2235#include "softmmu_template.h"
2236
2237#define SHIFT 3
2238#include "softmmu_template.h"
2239
20503968
BS
2240static void do_unaligned_access(target_ulong addr, int is_write,
2241 int is_user, uintptr_t retaddr)
4ad40f36
FB
2242{
2243 env->CP0_BadVAddr = addr;
2244 do_restore_state (retaddr);
c01fccd2 2245 helper_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL);
4ad40f36
FB
2246}
2247
7db13fae 2248void tlb_fill(CPUMIPSState *env1, target_ulong addr, int is_write, int mmu_idx,
20503968 2249 uintptr_t retaddr)
e37e863f
FB
2250{
2251 TranslationBlock *tb;
7db13fae 2252 CPUMIPSState *saved_env;
e37e863f
FB
2253 int ret;
2254
e37e863f 2255 saved_env = env;
bccd9ec5 2256 env = env1;
97b348e7 2257 ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx);
e37e863f
FB
2258 if (ret) {
2259 if (retaddr) {
2260 /* now we have a real cpu fault */
20503968 2261 tb = tb_find_pc(retaddr);
e37e863f
FB
2262 if (tb) {
2263 /* the PC is inside the translated code. It means that we have
2264 a virtual CPU fault */
20503968 2265 cpu_restore_state(tb, env, retaddr);
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
7db13fae 2273void cpu_unassigned_access(CPUMIPSState *env1, target_phys_addr_t addr,
b14ef7c9 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))