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