]> git.proxmox.com Git - qemu.git/blame - target-mips/op_helper.c
Fix handling of conditional branches in delay slot of a conditional branch
[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
6af0bf9c 752/* CP0 helpers */
c01fccd2 753target_ulong helper_mfc0_mvpcontrol (void)
f1aa6320 754{
be24bb4f 755 return env->mvp->CP0_MVPControl;
f1aa6320
TS
756}
757
c01fccd2 758target_ulong helper_mfc0_mvpconf0 (void)
f1aa6320 759{
be24bb4f 760 return env->mvp->CP0_MVPConf0;
f1aa6320
TS
761}
762
c01fccd2 763target_ulong helper_mfc0_mvpconf1 (void)
f1aa6320 764{
be24bb4f 765 return env->mvp->CP0_MVPConf1;
f1aa6320
TS
766}
767
c01fccd2 768target_ulong helper_mfc0_random (void)
6af0bf9c 769{
be24bb4f 770 return (int32_t)cpu_mips_get_random(env);
873eb012 771}
6af0bf9c 772
c01fccd2 773target_ulong helper_mfc0_tcstatus (void)
f1aa6320 774{
b5dc7732 775 return env->active_tc.CP0_TCStatus;
f1aa6320
TS
776}
777
c01fccd2 778target_ulong helper_mftc0_tcstatus(void)
f1aa6320
TS
779{
780 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
781
b5dc7732
TS
782 if (other_tc == env->current_tc)
783 return env->active_tc.CP0_TCStatus;
784 else
785 return env->tcs[other_tc].CP0_TCStatus;
f1aa6320
TS
786}
787
c01fccd2 788target_ulong helper_mfc0_tcbind (void)
f1aa6320 789{
b5dc7732 790 return env->active_tc.CP0_TCBind;
f1aa6320
TS
791}
792
c01fccd2 793target_ulong helper_mftc0_tcbind(void)
f1aa6320
TS
794{
795 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
796
b5dc7732
TS
797 if (other_tc == env->current_tc)
798 return env->active_tc.CP0_TCBind;
799 else
800 return env->tcs[other_tc].CP0_TCBind;
f1aa6320
TS
801}
802
c01fccd2 803target_ulong helper_mfc0_tcrestart (void)
f1aa6320 804{
b5dc7732 805 return env->active_tc.PC;
f1aa6320
TS
806}
807
c01fccd2 808target_ulong helper_mftc0_tcrestart(void)
f1aa6320
TS
809{
810 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
811
b5dc7732
TS
812 if (other_tc == env->current_tc)
813 return env->active_tc.PC;
814 else
815 return env->tcs[other_tc].PC;
f1aa6320
TS
816}
817
c01fccd2 818target_ulong helper_mfc0_tchalt (void)
f1aa6320 819{
b5dc7732 820 return env->active_tc.CP0_TCHalt;
f1aa6320
TS
821}
822
c01fccd2 823target_ulong helper_mftc0_tchalt(void)
f1aa6320
TS
824{
825 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
826
b5dc7732
TS
827 if (other_tc == env->current_tc)
828 return env->active_tc.CP0_TCHalt;
829 else
830 return env->tcs[other_tc].CP0_TCHalt;
f1aa6320
TS
831}
832
c01fccd2 833target_ulong helper_mfc0_tccontext (void)
f1aa6320 834{
b5dc7732 835 return env->active_tc.CP0_TCContext;
f1aa6320
TS
836}
837
c01fccd2 838target_ulong helper_mftc0_tccontext(void)
f1aa6320
TS
839{
840 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
841
b5dc7732
TS
842 if (other_tc == env->current_tc)
843 return env->active_tc.CP0_TCContext;
844 else
845 return env->tcs[other_tc].CP0_TCContext;
f1aa6320
TS
846}
847
c01fccd2 848target_ulong helper_mfc0_tcschedule (void)
f1aa6320 849{
b5dc7732 850 return env->active_tc.CP0_TCSchedule;
f1aa6320
TS
851}
852
c01fccd2 853target_ulong helper_mftc0_tcschedule(void)
f1aa6320
TS
854{
855 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
856
b5dc7732
TS
857 if (other_tc == env->current_tc)
858 return env->active_tc.CP0_TCSchedule;
859 else
860 return env->tcs[other_tc].CP0_TCSchedule;
f1aa6320
TS
861}
862
c01fccd2 863target_ulong helper_mfc0_tcschefback (void)
f1aa6320 864{
b5dc7732 865 return env->active_tc.CP0_TCScheFBack;
f1aa6320
TS
866}
867
c01fccd2 868target_ulong helper_mftc0_tcschefback(void)
f1aa6320
TS
869{
870 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
871
b5dc7732
TS
872 if (other_tc == env->current_tc)
873 return env->active_tc.CP0_TCScheFBack;
874 else
875 return env->tcs[other_tc].CP0_TCScheFBack;
f1aa6320
TS
876}
877
c01fccd2 878target_ulong helper_mfc0_count (void)
873eb012 879{
be24bb4f 880 return (int32_t)cpu_mips_get_count(env);
6af0bf9c
FB
881}
882
c01fccd2 883target_ulong helper_mftc0_entryhi(void)
f1aa6320
TS
884{
885 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
b5dc7732 886 int32_t tcstatus;
f1aa6320 887
b5dc7732
TS
888 if (other_tc == env->current_tc)
889 tcstatus = env->active_tc.CP0_TCStatus;
890 else
891 tcstatus = env->tcs[other_tc].CP0_TCStatus;
892
893 return (env->CP0_EntryHi & ~0xff) | (tcstatus & 0xff);
f1aa6320
TS
894}
895
c01fccd2 896target_ulong helper_mftc0_status(void)
f1aa6320
TS
897{
898 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1a3fd9c3 899 target_ulong t0;
b5dc7732
TS
900 int32_t tcstatus;
901
902 if (other_tc == env->current_tc)
903 tcstatus = env->active_tc.CP0_TCStatus;
904 else
905 tcstatus = env->tcs[other_tc].CP0_TCStatus;
f1aa6320 906
be24bb4f
TS
907 t0 = env->CP0_Status & ~0xf1000018;
908 t0 |= tcstatus & (0xf << CP0TCSt_TCU0);
909 t0 |= (tcstatus & (1 << CP0TCSt_TMX)) >> (CP0TCSt_TMX - CP0St_MX);
910 t0 |= (tcstatus & (0x3 << CP0TCSt_TKSU)) >> (CP0TCSt_TKSU - CP0St_KSU);
911
912 return t0;
f1aa6320
TS
913}
914
c01fccd2 915target_ulong helper_mfc0_lladdr (void)
f1aa6320 916{
2a6e32dd 917 return (int32_t)(env->lladdr >> env->CP0_LLAddr_shift);
f1aa6320
TS
918}
919
c01fccd2 920target_ulong helper_mfc0_watchlo (uint32_t sel)
f1aa6320 921{
be24bb4f 922 return (int32_t)env->CP0_WatchLo[sel];
f1aa6320
TS
923}
924
c01fccd2 925target_ulong helper_mfc0_watchhi (uint32_t sel)
f1aa6320 926{
be24bb4f 927 return env->CP0_WatchHi[sel];
f1aa6320
TS
928}
929
c01fccd2 930target_ulong helper_mfc0_debug (void)
f1aa6320 931{
1a3fd9c3 932 target_ulong t0 = env->CP0_Debug;
f1aa6320 933 if (env->hflags & MIPS_HFLAG_DM)
be24bb4f
TS
934 t0 |= 1 << CP0DB_DM;
935
936 return t0;
f1aa6320
TS
937}
938
c01fccd2 939target_ulong helper_mftc0_debug(void)
f1aa6320
TS
940{
941 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
b5dc7732
TS
942 int32_t tcstatus;
943
944 if (other_tc == env->current_tc)
945 tcstatus = env->active_tc.CP0_Debug_tcstatus;
946 else
947 tcstatus = env->tcs[other_tc].CP0_Debug_tcstatus;
f1aa6320
TS
948
949 /* XXX: Might be wrong, check with EJTAG spec. */
be24bb4f 950 return (env->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
b5dc7732 951 (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
f1aa6320
TS
952}
953
954#if defined(TARGET_MIPS64)
c01fccd2 955target_ulong helper_dmfc0_tcrestart (void)
f1aa6320 956{
b5dc7732 957 return env->active_tc.PC;
f1aa6320
TS
958}
959
c01fccd2 960target_ulong helper_dmfc0_tchalt (void)
f1aa6320 961{
b5dc7732 962 return env->active_tc.CP0_TCHalt;
f1aa6320
TS
963}
964
c01fccd2 965target_ulong helper_dmfc0_tccontext (void)
f1aa6320 966{
b5dc7732 967 return env->active_tc.CP0_TCContext;
f1aa6320
TS
968}
969
c01fccd2 970target_ulong helper_dmfc0_tcschedule (void)
f1aa6320 971{
b5dc7732 972 return env->active_tc.CP0_TCSchedule;
f1aa6320
TS
973}
974
c01fccd2 975target_ulong helper_dmfc0_tcschefback (void)
f1aa6320 976{
b5dc7732 977 return env->active_tc.CP0_TCScheFBack;
f1aa6320
TS
978}
979
c01fccd2 980target_ulong helper_dmfc0_lladdr (void)
f1aa6320 981{
2a6e32dd 982 return env->lladdr >> env->CP0_LLAddr_shift;
f1aa6320
TS
983}
984
c01fccd2 985target_ulong helper_dmfc0_watchlo (uint32_t sel)
f1aa6320 986{
be24bb4f 987 return env->CP0_WatchLo[sel];
f1aa6320
TS
988}
989#endif /* TARGET_MIPS64 */
990
d9bea114 991void helper_mtc0_index (target_ulong arg1)
f1aa6320
TS
992{
993 int num = 1;
994 unsigned int tmp = env->tlb->nb_tlb;
995
996 do {
997 tmp >>= 1;
998 num <<= 1;
999 } while (tmp);
d9bea114 1000 env->CP0_Index = (env->CP0_Index & 0x80000000) | (arg1 & (num - 1));
f1aa6320
TS
1001}
1002
d9bea114 1003void helper_mtc0_mvpcontrol (target_ulong arg1)
f1aa6320
TS
1004{
1005 uint32_t mask = 0;
1006 uint32_t newval;
1007
1008 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))
1009 mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) |
1010 (1 << CP0MVPCo_EVP);
1011 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1012 mask |= (1 << CP0MVPCo_STLB);
d9bea114 1013 newval = (env->mvp->CP0_MVPControl & ~mask) | (arg1 & mask);
f1aa6320
TS
1014
1015 // TODO: Enable/disable shared TLB, enable/disable VPEs.
1016
1017 env->mvp->CP0_MVPControl = newval;
1018}
1019
d9bea114 1020void helper_mtc0_vpecontrol (target_ulong arg1)
f1aa6320
TS
1021{
1022 uint32_t mask;
1023 uint32_t newval;
1024
1025 mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
1026 (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
d9bea114 1027 newval = (env->CP0_VPEControl & ~mask) | (arg1 & mask);
f1aa6320
TS
1028
1029 /* Yield scheduler intercept not implemented. */
1030 /* Gating storage scheduler intercept not implemented. */
1031
1032 // TODO: Enable/disable TCs.
1033
1034 env->CP0_VPEControl = newval;
1035}
1036
d9bea114 1037void helper_mtc0_vpeconf0 (target_ulong arg1)
f1aa6320
TS
1038{
1039 uint32_t mask = 0;
1040 uint32_t newval;
1041
1042 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) {
1043 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))
1044 mask |= (0xff << CP0VPEC0_XTC);
1045 mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
1046 }
d9bea114 1047 newval = (env->CP0_VPEConf0 & ~mask) | (arg1 & mask);
f1aa6320
TS
1048
1049 // TODO: TC exclusive handling due to ERL/EXL.
1050
1051 env->CP0_VPEConf0 = newval;
1052}
1053
d9bea114 1054void helper_mtc0_vpeconf1 (target_ulong arg1)
f1aa6320
TS
1055{
1056 uint32_t mask = 0;
1057 uint32_t newval;
1058
1059 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1060 mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) |
1061 (0xff << CP0VPEC1_NCP1);
d9bea114 1062 newval = (env->CP0_VPEConf1 & ~mask) | (arg1 & mask);
f1aa6320
TS
1063
1064 /* UDI not implemented. */
1065 /* CP2 not implemented. */
1066
1067 // TODO: Handle FPU (CP1) binding.
1068
1069 env->CP0_VPEConf1 = newval;
1070}
1071
d9bea114 1072void helper_mtc0_yqmask (target_ulong arg1)
f1aa6320
TS
1073{
1074 /* Yield qualifier inputs not implemented. */
1075 env->CP0_YQMask = 0x00000000;
1076}
1077
d9bea114 1078void helper_mtc0_vpeopt (target_ulong arg1)
f1aa6320 1079{
d9bea114 1080 env->CP0_VPEOpt = arg1 & 0x0000ffff;
f1aa6320
TS
1081}
1082
d9bea114 1083void helper_mtc0_entrylo0 (target_ulong arg1)
f1aa6320
TS
1084{
1085 /* Large physaddr (PABITS) not implemented */
1086 /* 1k pages not implemented */
d9bea114 1087 env->CP0_EntryLo0 = arg1 & 0x3FFFFFFF;
f1aa6320
TS
1088}
1089
d9bea114 1090void helper_mtc0_tcstatus (target_ulong arg1)
f1aa6320
TS
1091{
1092 uint32_t mask = env->CP0_TCStatus_rw_bitmask;
1093 uint32_t newval;
1094
d9bea114 1095 newval = (env->active_tc.CP0_TCStatus & ~mask) | (arg1 & mask);
f1aa6320
TS
1096
1097 // TODO: Sync with CP0_Status.
1098
b5dc7732 1099 env->active_tc.CP0_TCStatus = newval;
f1aa6320
TS
1100}
1101
d9bea114 1102void helper_mttc0_tcstatus (target_ulong arg1)
f1aa6320
TS
1103{
1104 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1105
1106 // TODO: Sync with CP0_Status.
1107
b5dc7732 1108 if (other_tc == env->current_tc)
d9bea114 1109 env->active_tc.CP0_TCStatus = arg1;
b5dc7732 1110 else
d9bea114 1111 env->tcs[other_tc].CP0_TCStatus = arg1;
f1aa6320
TS
1112}
1113
d9bea114 1114void helper_mtc0_tcbind (target_ulong arg1)
f1aa6320
TS
1115{
1116 uint32_t mask = (1 << CP0TCBd_TBE);
1117 uint32_t newval;
1118
1119 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1120 mask |= (1 << CP0TCBd_CurVPE);
d9bea114 1121 newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
b5dc7732 1122 env->active_tc.CP0_TCBind = newval;
f1aa6320
TS
1123}
1124
d9bea114 1125void helper_mttc0_tcbind (target_ulong arg1)
f1aa6320
TS
1126{
1127 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1128 uint32_t mask = (1 << CP0TCBd_TBE);
1129 uint32_t newval;
1130
1131 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1132 mask |= (1 << CP0TCBd_CurVPE);
b5dc7732 1133 if (other_tc == env->current_tc) {
d9bea114 1134 newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
b5dc7732
TS
1135 env->active_tc.CP0_TCBind = newval;
1136 } else {
d9bea114 1137 newval = (env->tcs[other_tc].CP0_TCBind & ~mask) | (arg1 & mask);
b5dc7732
TS
1138 env->tcs[other_tc].CP0_TCBind = newval;
1139 }
f1aa6320
TS
1140}
1141
d9bea114 1142void helper_mtc0_tcrestart (target_ulong arg1)
f1aa6320 1143{
d9bea114 1144 env->active_tc.PC = arg1;
b5dc7732 1145 env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
5499b6ff 1146 env->lladdr = 0ULL;
f1aa6320
TS
1147 /* MIPS16 not implemented. */
1148}
1149
d9bea114 1150void helper_mttc0_tcrestart (target_ulong arg1)
f1aa6320
TS
1151{
1152 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1153
b5dc7732 1154 if (other_tc == env->current_tc) {
d9bea114 1155 env->active_tc.PC = arg1;
b5dc7732 1156 env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
5499b6ff 1157 env->lladdr = 0ULL;
b5dc7732
TS
1158 /* MIPS16 not implemented. */
1159 } else {
d9bea114 1160 env->tcs[other_tc].PC = arg1;
b5dc7732 1161 env->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
5499b6ff 1162 env->lladdr = 0ULL;
b5dc7732
TS
1163 /* MIPS16 not implemented. */
1164 }
f1aa6320
TS
1165}
1166
d9bea114 1167void helper_mtc0_tchalt (target_ulong arg1)
f1aa6320 1168{
d9bea114 1169 env->active_tc.CP0_TCHalt = arg1 & 0x1;
f1aa6320
TS
1170
1171 // TODO: Halt TC / Restart (if allocated+active) TC.
1172}
1173
d9bea114 1174void helper_mttc0_tchalt (target_ulong arg1)
f1aa6320
TS
1175{
1176 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1177
1178 // TODO: Halt TC / Restart (if allocated+active) TC.
1179
b5dc7732 1180 if (other_tc == env->current_tc)
d9bea114 1181 env->active_tc.CP0_TCHalt = arg1;
b5dc7732 1182 else
d9bea114 1183 env->tcs[other_tc].CP0_TCHalt = arg1;
f1aa6320
TS
1184}
1185
d9bea114 1186void helper_mtc0_tccontext (target_ulong arg1)
f1aa6320 1187{
d9bea114 1188 env->active_tc.CP0_TCContext = arg1;
f1aa6320
TS
1189}
1190
d9bea114 1191void helper_mttc0_tccontext (target_ulong arg1)
f1aa6320
TS
1192{
1193 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1194
b5dc7732 1195 if (other_tc == env->current_tc)
d9bea114 1196 env->active_tc.CP0_TCContext = arg1;
b5dc7732 1197 else
d9bea114 1198 env->tcs[other_tc].CP0_TCContext = arg1;
f1aa6320
TS
1199}
1200
d9bea114 1201void helper_mtc0_tcschedule (target_ulong arg1)
f1aa6320 1202{
d9bea114 1203 env->active_tc.CP0_TCSchedule = arg1;
f1aa6320
TS
1204}
1205
d9bea114 1206void helper_mttc0_tcschedule (target_ulong arg1)
f1aa6320
TS
1207{
1208 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1209
b5dc7732 1210 if (other_tc == env->current_tc)
d9bea114 1211 env->active_tc.CP0_TCSchedule = arg1;
b5dc7732 1212 else
d9bea114 1213 env->tcs[other_tc].CP0_TCSchedule = arg1;
f1aa6320
TS
1214}
1215
d9bea114 1216void helper_mtc0_tcschefback (target_ulong arg1)
f1aa6320 1217{
d9bea114 1218 env->active_tc.CP0_TCScheFBack = arg1;
f1aa6320
TS
1219}
1220
d9bea114 1221void helper_mttc0_tcschefback (target_ulong arg1)
f1aa6320
TS
1222{
1223 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1224
b5dc7732 1225 if (other_tc == env->current_tc)
d9bea114 1226 env->active_tc.CP0_TCScheFBack = arg1;
b5dc7732 1227 else
d9bea114 1228 env->tcs[other_tc].CP0_TCScheFBack = arg1;
f1aa6320
TS
1229}
1230
d9bea114 1231void helper_mtc0_entrylo1 (target_ulong arg1)
f1aa6320
TS
1232{
1233 /* Large physaddr (PABITS) not implemented */
1234 /* 1k pages not implemented */
d9bea114 1235 env->CP0_EntryLo1 = arg1 & 0x3FFFFFFF;
f1aa6320
TS
1236}
1237
d9bea114 1238void helper_mtc0_context (target_ulong arg1)
f1aa6320 1239{
d9bea114 1240 env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF);
f1aa6320
TS
1241}
1242
d9bea114 1243void helper_mtc0_pagemask (target_ulong arg1)
f1aa6320
TS
1244{
1245 /* 1k pages not implemented */
d9bea114 1246 env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
f1aa6320
TS
1247}
1248
d9bea114 1249void helper_mtc0_pagegrain (target_ulong arg1)
f1aa6320
TS
1250{
1251 /* SmartMIPS not implemented */
1252 /* Large physaddr (PABITS) not implemented */
1253 /* 1k pages not implemented */
1254 env->CP0_PageGrain = 0;
1255}
1256
d9bea114 1257void helper_mtc0_wired (target_ulong arg1)
f1aa6320 1258{
d9bea114 1259 env->CP0_Wired = arg1 % env->tlb->nb_tlb;
f1aa6320
TS
1260}
1261
d9bea114 1262void helper_mtc0_srsconf0 (target_ulong arg1)
f1aa6320 1263{
d9bea114 1264 env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask;
f1aa6320
TS
1265}
1266
d9bea114 1267void helper_mtc0_srsconf1 (target_ulong arg1)
f1aa6320 1268{
d9bea114 1269 env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask;
f1aa6320
TS
1270}
1271
d9bea114 1272void helper_mtc0_srsconf2 (target_ulong arg1)
f1aa6320 1273{
d9bea114 1274 env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask;
f1aa6320
TS
1275}
1276
d9bea114 1277void helper_mtc0_srsconf3 (target_ulong arg1)
f1aa6320 1278{
d9bea114 1279 env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask;
f1aa6320
TS
1280}
1281
d9bea114 1282void helper_mtc0_srsconf4 (target_ulong arg1)
f1aa6320 1283{
d9bea114 1284 env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask;
f1aa6320
TS
1285}
1286
d9bea114 1287void helper_mtc0_hwrena (target_ulong arg1)
f1aa6320 1288{
d9bea114 1289 env->CP0_HWREna = arg1 & 0x0000000F;
f1aa6320
TS
1290}
1291
d9bea114 1292void helper_mtc0_count (target_ulong arg1)
f1aa6320 1293{
d9bea114 1294 cpu_mips_store_count(env, arg1);
f1aa6320
TS
1295}
1296
d9bea114 1297void helper_mtc0_entryhi (target_ulong arg1)
f1aa6320
TS
1298{
1299 target_ulong old, val;
1300
1301 /* 1k pages not implemented */
d9bea114 1302 val = arg1 & ((TARGET_PAGE_MASK << 1) | 0xFF);
f1aa6320
TS
1303#if defined(TARGET_MIPS64)
1304 val &= env->SEGMask;
1305#endif
1306 old = env->CP0_EntryHi;
1307 env->CP0_EntryHi = val;
1308 if (env->CP0_Config3 & (1 << CP0C3_MT)) {
b5dc7732
TS
1309 uint32_t tcst = env->active_tc.CP0_TCStatus & ~0xff;
1310 env->active_tc.CP0_TCStatus = tcst | (val & 0xff);
f1aa6320
TS
1311 }
1312 /* If the ASID changes, flush qemu's TLB. */
1313 if ((old & 0xFF) != (val & 0xFF))
1314 cpu_mips_tlb_flush(env, 1);
1315}
1316
d9bea114 1317void helper_mttc0_entryhi(target_ulong arg1)
f1aa6320
TS
1318{
1319 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
b5dc7732 1320 int32_t tcstatus;
f1aa6320 1321
d9bea114 1322 env->CP0_EntryHi = (env->CP0_EntryHi & 0xff) | (arg1 & ~0xff);
b5dc7732 1323 if (other_tc == env->current_tc) {
d9bea114 1324 tcstatus = (env->active_tc.CP0_TCStatus & ~0xff) | (arg1 & 0xff);
b5dc7732
TS
1325 env->active_tc.CP0_TCStatus = tcstatus;
1326 } else {
d9bea114 1327 tcstatus = (env->tcs[other_tc].CP0_TCStatus & ~0xff) | (arg1 & 0xff);
b5dc7732
TS
1328 env->tcs[other_tc].CP0_TCStatus = tcstatus;
1329 }
f1aa6320
TS
1330}
1331
d9bea114 1332void helper_mtc0_compare (target_ulong arg1)
f1aa6320 1333{
d9bea114 1334 cpu_mips_store_compare(env, arg1);
f1aa6320
TS
1335}
1336
d9bea114 1337void helper_mtc0_status (target_ulong arg1)
f1aa6320
TS
1338{
1339 uint32_t val, old;
1340 uint32_t mask = env->CP0_Status_rw_bitmask;
1341
d9bea114 1342 val = arg1 & mask;
f1aa6320
TS
1343 old = env->CP0_Status;
1344 env->CP0_Status = (env->CP0_Status & ~mask) | val;
1345 compute_hflags(env);
c01fccd2
AJ
1346 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1347 qemu_log("Status %08x (%08x) => %08x (%08x) Cause %08x",
1348 old, old & env->CP0_Cause & CP0Ca_IP_mask,
1349 val, val & env->CP0_Cause & CP0Ca_IP_mask,
1350 env->CP0_Cause);
1351 switch (env->hflags & MIPS_HFLAG_KSU) {
1352 case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
1353 case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
1354 case MIPS_HFLAG_KM: qemu_log("\n"); break;
1355 default: cpu_abort(env, "Invalid MMU mode!\n"); break;
31e3104f 1356 }
c01fccd2 1357 }
f1aa6320
TS
1358}
1359
d9bea114 1360void helper_mttc0_status(target_ulong arg1)
f1aa6320
TS
1361{
1362 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
b5dc7732 1363 int32_t tcstatus = env->tcs[other_tc].CP0_TCStatus;
f1aa6320 1364
d9bea114
AJ
1365 env->CP0_Status = arg1 & ~0xf1000018;
1366 tcstatus = (tcstatus & ~(0xf << CP0TCSt_TCU0)) | (arg1 & (0xf << CP0St_CU0));
1367 tcstatus = (tcstatus & ~(1 << CP0TCSt_TMX)) | ((arg1 & (1 << CP0St_MX)) << (CP0TCSt_TMX - CP0St_MX));
1368 tcstatus = (tcstatus & ~(0x3 << CP0TCSt_TKSU)) | ((arg1 & (0x3 << CP0St_KSU)) << (CP0TCSt_TKSU - CP0St_KSU));
b5dc7732
TS
1369 if (other_tc == env->current_tc)
1370 env->active_tc.CP0_TCStatus = tcstatus;
1371 else
1372 env->tcs[other_tc].CP0_TCStatus = tcstatus;
f1aa6320
TS
1373}
1374
d9bea114 1375void helper_mtc0_intctl (target_ulong arg1)
f1aa6320
TS
1376{
1377 /* vectored interrupts not implemented, no performance counters. */
d9bea114 1378 env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000002e0) | (arg1 & 0x000002e0);
f1aa6320
TS
1379}
1380
d9bea114 1381void helper_mtc0_srsctl (target_ulong arg1)
f1aa6320
TS
1382{
1383 uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
d9bea114 1384 env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask);
f1aa6320
TS
1385}
1386
d9bea114 1387void helper_mtc0_cause (target_ulong arg1)
f1aa6320
TS
1388{
1389 uint32_t mask = 0x00C00300;
1390 uint32_t old = env->CP0_Cause;
5dc5d9f0 1391 int i;
f1aa6320
TS
1392
1393 if (env->insn_flags & ISA_MIPS32R2)
1394 mask |= 1 << CP0Ca_DC;
1395
d9bea114 1396 env->CP0_Cause = (env->CP0_Cause & ~mask) | (arg1 & mask);
f1aa6320
TS
1397
1398 if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) {
1399 if (env->CP0_Cause & (1 << CP0Ca_DC))
1400 cpu_mips_stop_count(env);
1401 else
1402 cpu_mips_start_count(env);
1403 }
5dc5d9f0
AJ
1404
1405 /* Set/reset software interrupts */
1406 for (i = 0 ; i < 2 ; i++) {
1407 if ((old ^ env->CP0_Cause) & (1 << (CP0Ca_IP + i))) {
1408 cpu_mips_soft_irq(env, i, env->CP0_Cause & (1 << (CP0Ca_IP + i)));
1409 }
1410 }
f1aa6320
TS
1411}
1412
d9bea114 1413void helper_mtc0_ebase (target_ulong arg1)
f1aa6320
TS
1414{
1415 /* vectored interrupts not implemented */
671b0f36 1416 env->CP0_EBase = (env->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
f1aa6320
TS
1417}
1418
d9bea114 1419void helper_mtc0_config0 (target_ulong arg1)
f1aa6320 1420{
d9bea114 1421 env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007);
f1aa6320
TS
1422}
1423
d9bea114 1424void helper_mtc0_config2 (target_ulong arg1)
f1aa6320
TS
1425{
1426 /* tertiary/secondary caches not implemented */
1427 env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
1428}
1429
2a6e32dd
AJ
1430void helper_mtc0_lladdr (target_ulong arg1)
1431{
1432 target_long mask = env->CP0_LLAddr_rw_bitmask;
1433 arg1 = arg1 << env->CP0_LLAddr_shift;
1434 env->lladdr = (env->lladdr & ~mask) | (arg1 & mask);
1435}
1436
d9bea114 1437void helper_mtc0_watchlo (target_ulong arg1, uint32_t sel)
f1aa6320
TS
1438{
1439 /* Watch exceptions for instructions, data loads, data stores
1440 not implemented. */
d9bea114 1441 env->CP0_WatchLo[sel] = (arg1 & ~0x7);
f1aa6320
TS
1442}
1443
d9bea114 1444void helper_mtc0_watchhi (target_ulong arg1, uint32_t sel)
f1aa6320 1445{
d9bea114
AJ
1446 env->CP0_WatchHi[sel] = (arg1 & 0x40FF0FF8);
1447 env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7);
f1aa6320
TS
1448}
1449
d9bea114 1450void helper_mtc0_xcontext (target_ulong arg1)
f1aa6320
TS
1451{
1452 target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
d9bea114 1453 env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask);
f1aa6320
TS
1454}
1455
d9bea114 1456void helper_mtc0_framemask (target_ulong arg1)
f1aa6320 1457{
d9bea114 1458 env->CP0_Framemask = arg1; /* XXX */
f1aa6320
TS
1459}
1460
d9bea114 1461void helper_mtc0_debug (target_ulong arg1)
f1aa6320 1462{
d9bea114
AJ
1463 env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120);
1464 if (arg1 & (1 << CP0DB_DM))
f1aa6320
TS
1465 env->hflags |= MIPS_HFLAG_DM;
1466 else
1467 env->hflags &= ~MIPS_HFLAG_DM;
1468}
1469
d9bea114 1470void helper_mttc0_debug(target_ulong arg1)
f1aa6320
TS
1471{
1472 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
d9bea114 1473 uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
f1aa6320
TS
1474
1475 /* XXX: Might be wrong, check with EJTAG spec. */
b5dc7732
TS
1476 if (other_tc == env->current_tc)
1477 env->active_tc.CP0_Debug_tcstatus = val;
1478 else
1479 env->tcs[other_tc].CP0_Debug_tcstatus = val;
f1aa6320 1480 env->CP0_Debug = (env->CP0_Debug & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
d9bea114 1481 (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
f1aa6320
TS
1482}
1483
d9bea114 1484void helper_mtc0_performance0 (target_ulong arg1)
f1aa6320 1485{
d9bea114 1486 env->CP0_Performance0 = arg1 & 0x000007ff;
f1aa6320
TS
1487}
1488
d9bea114 1489void helper_mtc0_taglo (target_ulong arg1)
f1aa6320 1490{
d9bea114 1491 env->CP0_TagLo = arg1 & 0xFFFFFCF6;
f1aa6320
TS
1492}
1493
d9bea114 1494void helper_mtc0_datalo (target_ulong arg1)
f1aa6320 1495{
d9bea114 1496 env->CP0_DataLo = arg1; /* XXX */
f1aa6320
TS
1497}
1498
d9bea114 1499void helper_mtc0_taghi (target_ulong arg1)
f1aa6320 1500{
d9bea114 1501 env->CP0_TagHi = arg1; /* XXX */
f1aa6320
TS
1502}
1503
d9bea114 1504void helper_mtc0_datahi (target_ulong arg1)
f1aa6320 1505{
d9bea114 1506 env->CP0_DataHi = arg1; /* XXX */
f1aa6320
TS
1507}
1508
f1aa6320 1509/* MIPS MT functions */
c01fccd2 1510target_ulong helper_mftgpr(uint32_t sel)
f1aa6320
TS
1511{
1512 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1513
b5dc7732
TS
1514 if (other_tc == env->current_tc)
1515 return env->active_tc.gpr[sel];
1516 else
1517 return env->tcs[other_tc].gpr[sel];
f1aa6320
TS
1518}
1519
c01fccd2 1520target_ulong helper_mftlo(uint32_t sel)
f1aa6320
TS
1521{
1522 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1523
b5dc7732
TS
1524 if (other_tc == env->current_tc)
1525 return env->active_tc.LO[sel];
1526 else
1527 return env->tcs[other_tc].LO[sel];
f1aa6320
TS
1528}
1529
c01fccd2 1530target_ulong helper_mfthi(uint32_t sel)
f1aa6320
TS
1531{
1532 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1533
b5dc7732
TS
1534 if (other_tc == env->current_tc)
1535 return env->active_tc.HI[sel];
1536 else
1537 return env->tcs[other_tc].HI[sel];
f1aa6320
TS
1538}
1539
c01fccd2 1540target_ulong helper_mftacx(uint32_t sel)
f1aa6320
TS
1541{
1542 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1543
b5dc7732
TS
1544 if (other_tc == env->current_tc)
1545 return env->active_tc.ACX[sel];
1546 else
1547 return env->tcs[other_tc].ACX[sel];
f1aa6320
TS
1548}
1549
c01fccd2 1550target_ulong helper_mftdsp(void)
f1aa6320
TS
1551{
1552 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1553
b5dc7732
TS
1554 if (other_tc == env->current_tc)
1555 return env->active_tc.DSPControl;
1556 else
1557 return env->tcs[other_tc].DSPControl;
f1aa6320 1558}
6af0bf9c 1559
d9bea114 1560void helper_mttgpr(target_ulong arg1, uint32_t sel)
f1aa6320
TS
1561{
1562 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1563
b5dc7732 1564 if (other_tc == env->current_tc)
d9bea114 1565 env->active_tc.gpr[sel] = arg1;
b5dc7732 1566 else
d9bea114 1567 env->tcs[other_tc].gpr[sel] = arg1;
f1aa6320
TS
1568}
1569
d9bea114 1570void helper_mttlo(target_ulong arg1, uint32_t sel)
f1aa6320
TS
1571{
1572 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1573
b5dc7732 1574 if (other_tc == env->current_tc)
d9bea114 1575 env->active_tc.LO[sel] = arg1;
b5dc7732 1576 else
d9bea114 1577 env->tcs[other_tc].LO[sel] = arg1;
f1aa6320
TS
1578}
1579
d9bea114 1580void helper_mtthi(target_ulong arg1, uint32_t sel)
f1aa6320
TS
1581{
1582 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1583
b5dc7732 1584 if (other_tc == env->current_tc)
d9bea114 1585 env->active_tc.HI[sel] = arg1;
b5dc7732 1586 else
d9bea114 1587 env->tcs[other_tc].HI[sel] = arg1;
f1aa6320
TS
1588}
1589
d9bea114 1590void helper_mttacx(target_ulong arg1, uint32_t sel)
f1aa6320
TS
1591{
1592 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1593
b5dc7732 1594 if (other_tc == env->current_tc)
d9bea114 1595 env->active_tc.ACX[sel] = arg1;
b5dc7732 1596 else
d9bea114 1597 env->tcs[other_tc].ACX[sel] = arg1;
f1aa6320
TS
1598}
1599
d9bea114 1600void helper_mttdsp(target_ulong arg1)
f1aa6320
TS
1601{
1602 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1603
b5dc7732 1604 if (other_tc == env->current_tc)
d9bea114 1605 env->active_tc.DSPControl = arg1;
b5dc7732 1606 else
d9bea114 1607 env->tcs[other_tc].DSPControl = arg1;
f1aa6320
TS
1608}
1609
1610/* MIPS MT functions */
9ed5726c 1611target_ulong helper_dmt(void)
f1aa6320
TS
1612{
1613 // TODO
9ed5726c 1614 return 0;
f1aa6320
TS
1615}
1616
9ed5726c 1617target_ulong helper_emt(void)
f1aa6320
TS
1618{
1619 // TODO
9ed5726c 1620 return 0;
f1aa6320
TS
1621}
1622
9ed5726c 1623target_ulong helper_dvpe(void)
f1aa6320
TS
1624{
1625 // TODO
9ed5726c 1626 return 0;
f1aa6320
TS
1627}
1628
9ed5726c 1629target_ulong helper_evpe(void)
f1aa6320
TS
1630{
1631 // TODO
9ed5726c 1632 return 0;
f1aa6320 1633}
f9480ffc 1634#endif /* !CONFIG_USER_ONLY */
f1aa6320 1635
d9bea114 1636void helper_fork(target_ulong arg1, target_ulong arg2)
f1aa6320 1637{
d9bea114
AJ
1638 // arg1 = rt, arg2 = rs
1639 arg1 = 0;
f1aa6320
TS
1640 // TODO: store to TC register
1641}
1642
1c7242da 1643target_ulong helper_yield(target_ulong arg)
f1aa6320 1644{
1c7242da
BS
1645 target_long arg1 = arg;
1646
d9bea114 1647 if (arg1 < 0) {
f1aa6320 1648 /* No scheduling policy implemented. */
d9bea114 1649 if (arg1 != -2) {
f1aa6320 1650 if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
b5dc7732 1651 env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
f1aa6320
TS
1652 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1653 env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
c01fccd2 1654 helper_raise_exception(EXCP_THREAD);
f1aa6320
TS
1655 }
1656 }
d9bea114 1657 } else if (arg1 == 0) {
6958549d 1658 if (0 /* TODO: TC underflow */) {
f1aa6320 1659 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
c01fccd2 1660 helper_raise_exception(EXCP_THREAD);
f1aa6320
TS
1661 } else {
1662 // TODO: Deallocate TC
1663 }
d9bea114 1664 } else if (arg1 > 0) {
f1aa6320
TS
1665 /* Yield qualifier inputs not implemented. */
1666 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1667 env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
c01fccd2 1668 helper_raise_exception(EXCP_THREAD);
f1aa6320 1669 }
be24bb4f 1670 return env->CP0_YQMask;
f1aa6320
TS
1671}
1672
f1aa6320 1673#ifndef CONFIG_USER_ONLY
6af0bf9c 1674/* TLB management */
83dae095 1675static void cpu_mips_tlb_flush (CPUState *env, int flush_global)
814b9a47
TS
1676{
1677 /* Flush qemu's TLB and discard all shadowed entries. */
1678 tlb_flush (env, flush_global);
ead9360e 1679 env->tlb->tlb_in_use = env->tlb->nb_tlb;
814b9a47
TS
1680}
1681
29929e34 1682static void r4k_mips_tlb_flush_extra (CPUState *env, int first)
814b9a47
TS
1683{
1684 /* Discard entries from env->tlb[first] onwards. */
ead9360e
TS
1685 while (env->tlb->tlb_in_use > first) {
1686 r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
814b9a47
TS
1687 }
1688}
1689
29929e34 1690static void r4k_fill_tlb (int idx)
6af0bf9c 1691{
c227f099 1692 r4k_tlb_t *tlb;
6af0bf9c
FB
1693
1694 /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
ead9360e 1695 tlb = &env->tlb->mmu.r4k.tlb[idx];
f2e9ebef 1696 tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
d26bc211 1697#if defined(TARGET_MIPS64)
e034e2c3 1698 tlb->VPN &= env->SEGMask;
100ce988 1699#endif
98c1b82b 1700 tlb->ASID = env->CP0_EntryHi & 0xFF;
3b1c8be4 1701 tlb->PageMask = env->CP0_PageMask;
6af0bf9c 1702 tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
98c1b82b
PB
1703 tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
1704 tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
1705 tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
6af0bf9c 1706 tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
98c1b82b
PB
1707 tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
1708 tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
1709 tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
6af0bf9c
FB
1710 tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
1711}
1712
c01fccd2 1713void r4k_helper_tlbwi (void)
6af0bf9c 1714{
bbc0d79c
AJ
1715 int idx;
1716
1717 idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
1718
814b9a47
TS
1719 /* Discard cached TLB entries. We could avoid doing this if the
1720 tlbwi is just upgrading access permissions on the current entry;
1721 that might be a further win. */
ead9360e 1722 r4k_mips_tlb_flush_extra (env, env->tlb->nb_tlb);
814b9a47 1723
bbc0d79c
AJ
1724 r4k_invalidate_tlb(env, idx, 0);
1725 r4k_fill_tlb(idx);
6af0bf9c
FB
1726}
1727
c01fccd2 1728void r4k_helper_tlbwr (void)
6af0bf9c
FB
1729{
1730 int r = cpu_mips_get_random(env);
1731
29929e34
TS
1732 r4k_invalidate_tlb(env, r, 1);
1733 r4k_fill_tlb(r);
6af0bf9c
FB
1734}
1735
c01fccd2 1736void r4k_helper_tlbp (void)
6af0bf9c 1737{
c227f099 1738 r4k_tlb_t *tlb;
f2e9ebef 1739 target_ulong mask;
6af0bf9c 1740 target_ulong tag;
f2e9ebef 1741 target_ulong VPN;
6af0bf9c
FB
1742 uint8_t ASID;
1743 int i;
1744
3d9fb9fe 1745 ASID = env->CP0_EntryHi & 0xFF;
ead9360e
TS
1746 for (i = 0; i < env->tlb->nb_tlb; i++) {
1747 tlb = &env->tlb->mmu.r4k.tlb[i];
f2e9ebef
TS
1748 /* 1k pages are not supported. */
1749 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
1750 tag = env->CP0_EntryHi & ~mask;
1751 VPN = tlb->VPN & ~mask;
6af0bf9c 1752 /* Check ASID, virtual page number & size */
f2e9ebef 1753 if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
6af0bf9c 1754 /* TLB match */
9c2149c8 1755 env->CP0_Index = i;
6af0bf9c
FB
1756 break;
1757 }
1758 }
ead9360e 1759 if (i == env->tlb->nb_tlb) {
814b9a47 1760 /* No match. Discard any shadow entries, if any of them match. */
ead9360e 1761 for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
6958549d
AJ
1762 tlb = &env->tlb->mmu.r4k.tlb[i];
1763 /* 1k pages are not supported. */
1764 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
1765 tag = env->CP0_EntryHi & ~mask;
1766 VPN = tlb->VPN & ~mask;
1767 /* Check ASID, virtual page number & size */
1768 if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
29929e34 1769 r4k_mips_tlb_flush_extra (env, i);
6958549d
AJ
1770 break;
1771 }
1772 }
814b9a47 1773
9c2149c8 1774 env->CP0_Index |= 0x80000000;
6af0bf9c
FB
1775 }
1776}
1777
c01fccd2 1778void r4k_helper_tlbr (void)
6af0bf9c 1779{
c227f099 1780 r4k_tlb_t *tlb;
09c56b84 1781 uint8_t ASID;
bbc0d79c 1782 int idx;
6af0bf9c 1783
09c56b84 1784 ASID = env->CP0_EntryHi & 0xFF;
bbc0d79c
AJ
1785 idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
1786 tlb = &env->tlb->mmu.r4k.tlb[idx];
4ad40f36
FB
1787
1788 /* If this will change the current ASID, flush qemu's TLB. */
814b9a47
TS
1789 if (ASID != tlb->ASID)
1790 cpu_mips_tlb_flush (env, 1);
1791
ead9360e 1792 r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
4ad40f36 1793
6af0bf9c 1794 env->CP0_EntryHi = tlb->VPN | tlb->ASID;
3b1c8be4 1795 env->CP0_PageMask = tlb->PageMask;
7495fd0f
TS
1796 env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
1797 (tlb->C0 << 3) | (tlb->PFN[0] >> 6);
1798 env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
1799 (tlb->C1 << 3) | (tlb->PFN[1] >> 6);
6af0bf9c 1800}
6af0bf9c 1801
c01fccd2 1802void helper_tlbwi(void)
a7812ae4 1803{
c01fccd2 1804 env->tlb->helper_tlbwi();
a7812ae4
PB
1805}
1806
c01fccd2 1807void helper_tlbwr(void)
a7812ae4 1808{
c01fccd2 1809 env->tlb->helper_tlbwr();
a7812ae4
PB
1810}
1811
c01fccd2 1812void helper_tlbp(void)
a7812ae4 1813{
c01fccd2 1814 env->tlb->helper_tlbp();
a7812ae4
PB
1815}
1816
c01fccd2 1817void helper_tlbr(void)
a7812ae4 1818{
c01fccd2 1819 env->tlb->helper_tlbr();
a7812ae4
PB
1820}
1821
2b0233ab 1822/* Specials */
c01fccd2 1823target_ulong helper_di (void)
2b0233ab 1824{
2796188e
TS
1825 target_ulong t0 = env->CP0_Status;
1826
be24bb4f 1827 env->CP0_Status = t0 & ~(1 << CP0St_IE);
be24bb4f 1828 return t0;
2b0233ab
TS
1829}
1830
c01fccd2 1831target_ulong helper_ei (void)
2b0233ab 1832{
2796188e
TS
1833 target_ulong t0 = env->CP0_Status;
1834
be24bb4f 1835 env->CP0_Status = t0 | (1 << CP0St_IE);
be24bb4f 1836 return t0;
2b0233ab
TS
1837}
1838
cd5158ea 1839static void debug_pre_eret (void)
6af0bf9c 1840{
8fec2b8c 1841 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
93fcfe39
AL
1842 qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
1843 env->active_tc.PC, env->CP0_EPC);
1844 if (env->CP0_Status & (1 << CP0St_ERL))
1845 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
1846 if (env->hflags & MIPS_HFLAG_DM)
1847 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
1848 qemu_log("\n");
1849 }
f41c52f1
TS
1850}
1851
cd5158ea 1852static void debug_post_eret (void)
f41c52f1 1853{
8fec2b8c 1854 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
93fcfe39
AL
1855 qemu_log(" => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
1856 env->active_tc.PC, env->CP0_EPC);
1857 if (env->CP0_Status & (1 << CP0St_ERL))
1858 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
1859 if (env->hflags & MIPS_HFLAG_DM)
1860 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
1861 switch (env->hflags & MIPS_HFLAG_KSU) {
1862 case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
1863 case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
1864 case MIPS_HFLAG_KM: qemu_log("\n"); break;
1865 default: cpu_abort(env, "Invalid MMU mode!\n"); break;
1866 }
623a930e 1867 }
6af0bf9c
FB
1868}
1869
32188a03
NF
1870static void set_pc (target_ulong error_pc)
1871{
1872 env->active_tc.PC = error_pc & ~(target_ulong)1;
1873 if (error_pc & 1) {
1874 env->hflags |= MIPS_HFLAG_M16;
1875 } else {
1876 env->hflags &= ~(MIPS_HFLAG_M16);
1877 }
1878}
1879
c01fccd2 1880void helper_eret (void)
2b0233ab 1881{
93fcfe39 1882 debug_pre_eret();
2b0233ab 1883 if (env->CP0_Status & (1 << CP0St_ERL)) {
32188a03 1884 set_pc(env->CP0_ErrorEPC);
2b0233ab
TS
1885 env->CP0_Status &= ~(1 << CP0St_ERL);
1886 } else {
32188a03 1887 set_pc(env->CP0_EPC);
2b0233ab
TS
1888 env->CP0_Status &= ~(1 << CP0St_EXL);
1889 }
1890 compute_hflags(env);
93fcfe39 1891 debug_post_eret();
5499b6ff 1892 env->lladdr = 1;
2b0233ab
TS
1893}
1894
c01fccd2 1895void helper_deret (void)
2b0233ab 1896{
93fcfe39 1897 debug_pre_eret();
32188a03
NF
1898 set_pc(env->CP0_DEPC);
1899
2b0233ab
TS
1900 env->hflags &= MIPS_HFLAG_DM;
1901 compute_hflags(env);
93fcfe39 1902 debug_post_eret();
5499b6ff 1903 env->lladdr = 1;
2b0233ab 1904}
0eaef5aa 1905#endif /* !CONFIG_USER_ONLY */
2b0233ab 1906
c01fccd2 1907target_ulong helper_rdhwr_cpunum(void)
2b0233ab
TS
1908{
1909 if ((env->hflags & MIPS_HFLAG_CP0) ||
1910 (env->CP0_HWREna & (1 << 0)))
2796188e 1911 return env->CP0_EBase & 0x3ff;
2b0233ab 1912 else
c01fccd2 1913 helper_raise_exception(EXCP_RI);
be24bb4f 1914
2796188e 1915 return 0;
2b0233ab
TS
1916}
1917
c01fccd2 1918target_ulong helper_rdhwr_synci_step(void)
2b0233ab
TS
1919{
1920 if ((env->hflags & MIPS_HFLAG_CP0) ||
1921 (env->CP0_HWREna & (1 << 1)))
2796188e 1922 return env->SYNCI_Step;
2b0233ab 1923 else
c01fccd2 1924 helper_raise_exception(EXCP_RI);
be24bb4f 1925
2796188e 1926 return 0;
2b0233ab
TS
1927}
1928
c01fccd2 1929target_ulong helper_rdhwr_cc(void)
2b0233ab
TS
1930{
1931 if ((env->hflags & MIPS_HFLAG_CP0) ||
1932 (env->CP0_HWREna & (1 << 2)))
2796188e 1933 return env->CP0_Count;
2b0233ab 1934 else
c01fccd2 1935 helper_raise_exception(EXCP_RI);
be24bb4f 1936
2796188e 1937 return 0;
2b0233ab
TS
1938}
1939
c01fccd2 1940target_ulong helper_rdhwr_ccres(void)
2b0233ab
TS
1941{
1942 if ((env->hflags & MIPS_HFLAG_CP0) ||
1943 (env->CP0_HWREna & (1 << 3)))
2796188e 1944 return env->CCRes;
2b0233ab 1945 else
c01fccd2 1946 helper_raise_exception(EXCP_RI);
be24bb4f 1947
2796188e 1948 return 0;
2b0233ab
TS
1949}
1950
c01fccd2 1951void helper_pmon (int function)
6af0bf9c
FB
1952{
1953 function /= 2;
1954 switch (function) {
1955 case 2: /* TODO: char inbyte(int waitflag); */
b5dc7732
TS
1956 if (env->active_tc.gpr[4] == 0)
1957 env->active_tc.gpr[2] = -1;
6af0bf9c
FB
1958 /* Fall through */
1959 case 11: /* TODO: char inbyte (void); */
b5dc7732 1960 env->active_tc.gpr[2] = -1;
6af0bf9c
FB
1961 break;
1962 case 3:
1963 case 12:
b5dc7732 1964 printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
6af0bf9c
FB
1965 break;
1966 case 17:
1967 break;
1968 case 158:
1969 {
b5dc7732 1970 unsigned char *fmt = (void *)(unsigned long)env->active_tc.gpr[4];
6af0bf9c
FB
1971 printf("%s", fmt);
1972 }
1973 break;
1974 }
1975}
e37e863f 1976
c01fccd2 1977void helper_wait (void)
08ba7963
TS
1978{
1979 env->halted = 1;
c01fccd2 1980 helper_raise_exception(EXCP_HLT);
08ba7963
TS
1981}
1982
5fafdf24 1983#if !defined(CONFIG_USER_ONLY)
e37e863f 1984
4ad40f36
FB
1985static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr);
1986
e37e863f 1987#define MMUSUFFIX _mmu
4ad40f36 1988#define ALIGNED_ONLY
e37e863f
FB
1989
1990#define SHIFT 0
1991#include "softmmu_template.h"
1992
1993#define SHIFT 1
1994#include "softmmu_template.h"
1995
1996#define SHIFT 2
1997#include "softmmu_template.h"
1998
1999#define SHIFT 3
2000#include "softmmu_template.h"
2001
4ad40f36
FB
2002static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr)
2003{
2004 env->CP0_BadVAddr = addr;
2005 do_restore_state (retaddr);
c01fccd2 2006 helper_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL);
4ad40f36
FB
2007}
2008
6ebbf390 2009void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
e37e863f
FB
2010{
2011 TranslationBlock *tb;
2012 CPUState *saved_env;
2013 unsigned long pc;
2014 int ret;
2015
2016 /* XXX: hack to restore env in all cases, even if not called from
2017 generated code */
2018 saved_env = env;
2019 env = cpu_single_env;
6ebbf390 2020 ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
e37e863f
FB
2021 if (ret) {
2022 if (retaddr) {
2023 /* now we have a real cpu fault */
2024 pc = (unsigned long)retaddr;
2025 tb = tb_find_pc(pc);
2026 if (tb) {
2027 /* the PC is inside the translated code. It means that we have
2028 a virtual CPU fault */
618ba8e6 2029 cpu_restore_state(tb, env, pc);
e37e863f
FB
2030 }
2031 }
c01fccd2 2032 helper_raise_exception_err(env->exception_index, env->error_code);
e37e863f
FB
2033 }
2034 env = saved_env;
2035}
2036
b14ef7c9
BS
2037void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr,
2038 int is_write, int is_exec, int unused, int size)
647de6ca 2039{
b14ef7c9
BS
2040 env = env1;
2041
647de6ca 2042 if (is_exec)
c01fccd2 2043 helper_raise_exception(EXCP_IBE);
647de6ca 2044 else
c01fccd2 2045 helper_raise_exception(EXCP_DBE);
647de6ca 2046}
f1aa6320 2047#endif /* !CONFIG_USER_ONLY */
fd4a04eb
TS
2048
2049/* Complex FPU operations which may need stack space. */
2050
f090c9d4
PB
2051#define FLOAT_ONE32 make_float32(0x3f8 << 20)
2052#define FLOAT_ONE64 make_float64(0x3ffULL << 52)
2053#define FLOAT_TWO32 make_float32(1 << 30)
2054#define FLOAT_TWO64 make_float64(1ULL << 62)
54454097
TS
2055#define FLOAT_QNAN32 0x7fbfffff
2056#define FLOAT_QNAN64 0x7ff7ffffffffffffULL
2057#define FLOAT_SNAN32 0x7fffffff
2058#define FLOAT_SNAN64 0x7fffffffffffffffULL
8dfdb87c 2059
fd4a04eb 2060/* convert MIPS rounding mode in FCR31 to IEEE library */
6f4fc367 2061static unsigned int ieee_rm[] = {
fd4a04eb
TS
2062 float_round_nearest_even,
2063 float_round_to_zero,
2064 float_round_up,
2065 float_round_down
2066};
2067
2068#define RESTORE_ROUNDING_MODE \
f01be154 2069 set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], &env->active_fpu.fp_status)
fd4a04eb 2070
41e0c701
AJ
2071#define RESTORE_FLUSH_MODE \
2072 set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, &env->active_fpu.fp_status);
2073
c01fccd2 2074target_ulong helper_cfc1 (uint32_t reg)
fd4a04eb 2075{
d9bea114 2076 target_ulong arg1;
6c5c1e20 2077
ead9360e
TS
2078 switch (reg) {
2079 case 0:
d9bea114 2080 arg1 = (int32_t)env->active_fpu.fcr0;
ead9360e
TS
2081 break;
2082 case 25:
d9bea114 2083 arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
ead9360e
TS
2084 break;
2085 case 26:
d9bea114 2086 arg1 = env->active_fpu.fcr31 & 0x0003f07c;
ead9360e
TS
2087 break;
2088 case 28:
d9bea114 2089 arg1 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4);
ead9360e
TS
2090 break;
2091 default:
d9bea114 2092 arg1 = (int32_t)env->active_fpu.fcr31;
ead9360e
TS
2093 break;
2094 }
be24bb4f 2095
d9bea114 2096 return arg1;
ead9360e
TS
2097}
2098
d9bea114 2099void helper_ctc1 (target_ulong arg1, uint32_t reg)
ead9360e
TS
2100{
2101 switch(reg) {
fd4a04eb 2102 case 25:
d9bea114 2103 if (arg1 & 0xffffff00)
fd4a04eb 2104 return;
d9bea114
AJ
2105 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
2106 ((arg1 & 0x1) << 23);
fd4a04eb
TS
2107 break;
2108 case 26:
d9bea114 2109 if (arg1 & 0x007c0000)
fd4a04eb 2110 return;
d9bea114 2111 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (arg1 & 0x0003f07c);
fd4a04eb
TS
2112 break;
2113 case 28:
d9bea114 2114 if (arg1 & 0x007c0000)
fd4a04eb 2115 return;
d9bea114
AJ
2116 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (arg1 & 0x00000f83) |
2117 ((arg1 & 0x4) << 22);
fd4a04eb
TS
2118 break;
2119 case 31:
d9bea114 2120 if (arg1 & 0x007c0000)
fd4a04eb 2121 return;
d9bea114 2122 env->active_fpu.fcr31 = arg1;
fd4a04eb
TS
2123 break;
2124 default:
2125 return;
2126 }
2127 /* set rounding mode */
2128 RESTORE_ROUNDING_MODE;
41e0c701
AJ
2129 /* set flush-to-zero mode */
2130 RESTORE_FLUSH_MODE;
f01be154
TS
2131 set_float_exception_flags(0, &env->active_fpu.fp_status);
2132 if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31))
c01fccd2 2133 helper_raise_exception(EXCP_FPE);
fd4a04eb
TS
2134}
2135
353ebb7a 2136static inline int ieee_ex_to_mips(int xcpt)
fd4a04eb 2137{
353ebb7a
AJ
2138 int ret = 0;
2139 if (xcpt) {
2140 if (xcpt & float_flag_invalid) {
2141 ret |= FP_INVALID;
2142 }
2143 if (xcpt & float_flag_overflow) {
2144 ret |= FP_OVERFLOW;
2145 }
2146 if (xcpt & float_flag_underflow) {
2147 ret |= FP_UNDERFLOW;
2148 }
2149 if (xcpt & float_flag_divbyzero) {
2150 ret |= FP_DIV0;
2151 }
2152 if (xcpt & float_flag_inexact) {
2153 ret |= FP_INEXACT;
2154 }
2155 }
2156 return ret;
fd4a04eb
TS
2157}
2158
c904ef0e 2159static inline void update_fcr31(void)
fd4a04eb 2160{
f01be154 2161 int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
fd4a04eb 2162
f01be154
TS
2163 SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
2164 if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp)
c01fccd2 2165 helper_raise_exception(EXCP_FPE);
fd4a04eb 2166 else
f01be154 2167 UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
fd4a04eb
TS
2168}
2169
a16336e4
TS
2170/* Float support.
2171 Single precition routines have a "s" suffix, double precision a
2172 "d" suffix, 32bit integer "w", 64bit integer "l", paired single "ps",
2173 paired single lower "pl", paired single upper "pu". */
2174
a16336e4 2175/* unary operations, modifying fp status */
c01fccd2 2176uint64_t helper_float_sqrt_d(uint64_t fdt0)
b6d96bed 2177{
f01be154 2178 return float64_sqrt(fdt0, &env->active_fpu.fp_status);
b6d96bed
TS
2179}
2180
c01fccd2 2181uint32_t helper_float_sqrt_s(uint32_t fst0)
b6d96bed 2182{
f01be154 2183 return float32_sqrt(fst0, &env->active_fpu.fp_status);
b6d96bed 2184}
a16336e4 2185
c01fccd2 2186uint64_t helper_float_cvtd_s(uint32_t fst0)
fd4a04eb 2187{
b6d96bed
TS
2188 uint64_t fdt2;
2189
f01be154
TS
2190 set_float_exception_flags(0, &env->active_fpu.fp_status);
2191 fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
fd4a04eb 2192 update_fcr31();
b6d96bed 2193 return fdt2;
fd4a04eb 2194}
b6d96bed 2195
c01fccd2 2196uint64_t helper_float_cvtd_w(uint32_t wt0)
fd4a04eb 2197{
b6d96bed
TS
2198 uint64_t fdt2;
2199
f01be154
TS
2200 set_float_exception_flags(0, &env->active_fpu.fp_status);
2201 fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
fd4a04eb 2202 update_fcr31();
b6d96bed 2203 return fdt2;
fd4a04eb 2204}
b6d96bed 2205
c01fccd2 2206uint64_t helper_float_cvtd_l(uint64_t dt0)
fd4a04eb 2207{
b6d96bed
TS
2208 uint64_t fdt2;
2209
f01be154
TS
2210 set_float_exception_flags(0, &env->active_fpu.fp_status);
2211 fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
fd4a04eb 2212 update_fcr31();
b6d96bed 2213 return fdt2;
fd4a04eb 2214}
b6d96bed 2215
c01fccd2 2216uint64_t helper_float_cvtl_d(uint64_t fdt0)
fd4a04eb 2217{
b6d96bed
TS
2218 uint64_t dt2;
2219
f01be154
TS
2220 set_float_exception_flags(0, &env->active_fpu.fp_status);
2221 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
fd4a04eb 2222 update_fcr31();
f01be154 2223 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
b6d96bed
TS
2224 dt2 = FLOAT_SNAN64;
2225 return dt2;
fd4a04eb 2226}
b6d96bed 2227
c01fccd2 2228uint64_t helper_float_cvtl_s(uint32_t fst0)
fd4a04eb 2229{
b6d96bed
TS
2230 uint64_t dt2;
2231
f01be154
TS
2232 set_float_exception_flags(0, &env->active_fpu.fp_status);
2233 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
fd4a04eb 2234 update_fcr31();
f01be154 2235 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
b6d96bed
TS
2236 dt2 = FLOAT_SNAN64;
2237 return dt2;
fd4a04eb
TS
2238}
2239
c01fccd2 2240uint64_t helper_float_cvtps_pw(uint64_t dt0)
fd4a04eb 2241{
b6d96bed
TS
2242 uint32_t fst2;
2243 uint32_t fsth2;
2244
f01be154
TS
2245 set_float_exception_flags(0, &env->active_fpu.fp_status);
2246 fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2247 fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status);
fd4a04eb 2248 update_fcr31();
b6d96bed 2249 return ((uint64_t)fsth2 << 32) | fst2;
fd4a04eb 2250}
b6d96bed 2251
c01fccd2 2252uint64_t helper_float_cvtpw_ps(uint64_t fdt0)
fd4a04eb 2253{
b6d96bed
TS
2254 uint32_t wt2;
2255 uint32_t wth2;
2256
f01be154
TS
2257 set_float_exception_flags(0, &env->active_fpu.fp_status);
2258 wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2259 wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status);
fd4a04eb 2260 update_fcr31();
f01be154 2261 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) {
b6d96bed
TS
2262 wt2 = FLOAT_SNAN32;
2263 wth2 = FLOAT_SNAN32;
2264 }
2265 return ((uint64_t)wth2 << 32) | wt2;
fd4a04eb 2266}
b6d96bed 2267
c01fccd2 2268uint32_t helper_float_cvts_d(uint64_t fdt0)
fd4a04eb 2269{
b6d96bed
TS
2270 uint32_t fst2;
2271
f01be154
TS
2272 set_float_exception_flags(0, &env->active_fpu.fp_status);
2273 fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
fd4a04eb 2274 update_fcr31();
b6d96bed 2275 return fst2;
fd4a04eb 2276}
b6d96bed 2277
c01fccd2 2278uint32_t helper_float_cvts_w(uint32_t wt0)
fd4a04eb 2279{
b6d96bed
TS
2280 uint32_t fst2;
2281
f01be154
TS
2282 set_float_exception_flags(0, &env->active_fpu.fp_status);
2283 fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status);
fd4a04eb 2284 update_fcr31();
b6d96bed 2285 return fst2;
fd4a04eb 2286}
b6d96bed 2287
c01fccd2 2288uint32_t helper_float_cvts_l(uint64_t dt0)
fd4a04eb 2289{
b6d96bed
TS
2290 uint32_t fst2;
2291
f01be154
TS
2292 set_float_exception_flags(0, &env->active_fpu.fp_status);
2293 fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status);
fd4a04eb 2294 update_fcr31();
b6d96bed 2295 return fst2;
fd4a04eb 2296}
b6d96bed 2297
c01fccd2 2298uint32_t helper_float_cvts_pl(uint32_t wt0)
fd4a04eb 2299{
b6d96bed
TS
2300 uint32_t wt2;
2301
f01be154 2302 set_float_exception_flags(0, &env->active_fpu.fp_status);
b6d96bed 2303 wt2 = wt0;
fd4a04eb 2304 update_fcr31();
b6d96bed 2305 return wt2;
fd4a04eb 2306}
b6d96bed 2307
c01fccd2 2308uint32_t helper_float_cvts_pu(uint32_t wth0)
fd4a04eb 2309{
b6d96bed
TS
2310 uint32_t wt2;
2311
f01be154 2312 set_float_exception_flags(0, &env->active_fpu.fp_status);
b6d96bed 2313 wt2 = wth0;
fd4a04eb 2314 update_fcr31();
b6d96bed 2315 return wt2;
fd4a04eb 2316}
b6d96bed 2317
c01fccd2 2318uint32_t helper_float_cvtw_s(uint32_t fst0)
fd4a04eb 2319{
b6d96bed
TS
2320 uint32_t wt2;
2321
f01be154
TS
2322 set_float_exception_flags(0, &env->active_fpu.fp_status);
2323 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
fd4a04eb 2324 update_fcr31();
f01be154 2325 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
b6d96bed
TS
2326 wt2 = FLOAT_SNAN32;
2327 return wt2;
fd4a04eb 2328}
b6d96bed 2329
c01fccd2 2330uint32_t helper_float_cvtw_d(uint64_t fdt0)
fd4a04eb 2331{
b6d96bed
TS
2332 uint32_t wt2;
2333
f01be154
TS
2334 set_float_exception_flags(0, &env->active_fpu.fp_status);
2335 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
fd4a04eb 2336 update_fcr31();
f01be154 2337 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
b6d96bed
TS
2338 wt2 = FLOAT_SNAN32;
2339 return wt2;
fd4a04eb
TS
2340}
2341
c01fccd2 2342uint64_t helper_float_roundl_d(uint64_t fdt0)
fd4a04eb 2343{
b6d96bed
TS
2344 uint64_t dt2;
2345
efd41037 2346 set_float_exception_flags(0, &env->active_fpu.fp_status);
f01be154
TS
2347 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2348 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
fd4a04eb
TS
2349 RESTORE_ROUNDING_MODE;
2350 update_fcr31();
f01be154 2351 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
b6d96bed
TS
2352 dt2 = FLOAT_SNAN64;
2353 return dt2;
fd4a04eb 2354}
b6d96bed 2355
c01fccd2 2356uint64_t helper_float_roundl_s(uint32_t fst0)
fd4a04eb 2357{
b6d96bed
TS
2358 uint64_t dt2;
2359
efd41037 2360 set_float_exception_flags(0, &env->active_fpu.fp_status);
f01be154
TS
2361 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2362 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
fd4a04eb
TS
2363 RESTORE_ROUNDING_MODE;
2364 update_fcr31();
f01be154 2365 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
b6d96bed
TS
2366 dt2 = FLOAT_SNAN64;
2367 return dt2;
fd4a04eb 2368}
b6d96bed 2369
c01fccd2 2370uint32_t helper_float_roundw_d(uint64_t fdt0)
fd4a04eb 2371{
b6d96bed
TS
2372 uint32_t wt2;
2373
efd41037 2374 set_float_exception_flags(0, &env->active_fpu.fp_status);
f01be154
TS
2375 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2376 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
fd4a04eb
TS
2377 RESTORE_ROUNDING_MODE;
2378 update_fcr31();
f01be154 2379 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
b6d96bed
TS
2380 wt2 = FLOAT_SNAN32;
2381 return wt2;
fd4a04eb 2382}
b6d96bed 2383
c01fccd2 2384uint32_t helper_float_roundw_s(uint32_t fst0)
fd4a04eb 2385{
b6d96bed
TS
2386 uint32_t wt2;
2387
efd41037 2388 set_float_exception_flags(0, &env->active_fpu.fp_status);
f01be154
TS
2389 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2390 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
fd4a04eb
TS
2391 RESTORE_ROUNDING_MODE;
2392 update_fcr31();
f01be154 2393 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
b6d96bed
TS
2394 wt2 = FLOAT_SNAN32;
2395 return wt2;
fd4a04eb
TS
2396}
2397
c01fccd2 2398uint64_t helper_float_truncl_d(uint64_t fdt0)
fd4a04eb 2399{
b6d96bed
TS
2400 uint64_t dt2;
2401
efd41037 2402 set_float_exception_flags(0, &env->active_fpu.fp_status);
f01be154 2403 dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
fd4a04eb 2404 update_fcr31();
f01be154 2405 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
b6d96bed
TS
2406 dt2 = FLOAT_SNAN64;
2407 return dt2;
fd4a04eb 2408}
b6d96bed 2409
c01fccd2 2410uint64_t helper_float_truncl_s(uint32_t fst0)
fd4a04eb 2411{
b6d96bed
TS
2412 uint64_t dt2;
2413
efd41037 2414 set_float_exception_flags(0, &env->active_fpu.fp_status);
f01be154 2415 dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
fd4a04eb 2416 update_fcr31();
f01be154 2417 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
b6d96bed
TS
2418 dt2 = FLOAT_SNAN64;
2419 return dt2;
fd4a04eb 2420}
b6d96bed 2421
c01fccd2 2422uint32_t helper_float_truncw_d(uint64_t fdt0)
fd4a04eb 2423{
b6d96bed
TS
2424 uint32_t wt2;
2425
efd41037 2426 set_float_exception_flags(0, &env->active_fpu.fp_status);
f01be154 2427 wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
fd4a04eb 2428 update_fcr31();
f01be154 2429 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
b6d96bed
TS
2430 wt2 = FLOAT_SNAN32;
2431 return wt2;
fd4a04eb 2432}
b6d96bed 2433
c01fccd2 2434uint32_t helper_float_truncw_s(uint32_t fst0)
fd4a04eb 2435{
b6d96bed
TS
2436 uint32_t wt2;
2437
efd41037 2438 set_float_exception_flags(0, &env->active_fpu.fp_status);
f01be154 2439 wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
fd4a04eb 2440 update_fcr31();
f01be154 2441 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
b6d96bed
TS
2442 wt2 = FLOAT_SNAN32;
2443 return wt2;
fd4a04eb
TS
2444}
2445
c01fccd2 2446uint64_t helper_float_ceill_d(uint64_t fdt0)
fd4a04eb 2447{
b6d96bed
TS
2448 uint64_t dt2;
2449
efd41037 2450 set_float_exception_flags(0, &env->active_fpu.fp_status);
f01be154
TS
2451 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2452 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
fd4a04eb
TS
2453 RESTORE_ROUNDING_MODE;
2454 update_fcr31();
f01be154 2455 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
b6d96bed
TS
2456 dt2 = FLOAT_SNAN64;
2457 return dt2;
fd4a04eb 2458}
b6d96bed 2459
c01fccd2 2460uint64_t helper_float_ceill_s(uint32_t fst0)
fd4a04eb 2461{
b6d96bed
TS
2462 uint64_t dt2;
2463
efd41037 2464 set_float_exception_flags(0, &env->active_fpu.fp_status);
f01be154
TS
2465 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2466 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
fd4a04eb
TS
2467 RESTORE_ROUNDING_MODE;
2468 update_fcr31();
f01be154 2469 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
b6d96bed
TS
2470 dt2 = FLOAT_SNAN64;
2471 return dt2;
fd4a04eb 2472}
b6d96bed 2473
c01fccd2 2474uint32_t helper_float_ceilw_d(uint64_t fdt0)
fd4a04eb 2475{
b6d96bed
TS
2476 uint32_t wt2;
2477
efd41037 2478 set_float_exception_flags(0, &env->active_fpu.fp_status);
f01be154
TS
2479 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2480 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
fd4a04eb
TS
2481 RESTORE_ROUNDING_MODE;
2482 update_fcr31();
f01be154 2483 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
b6d96bed
TS
2484 wt2 = FLOAT_SNAN32;
2485 return wt2;
fd4a04eb 2486}
b6d96bed 2487
c01fccd2 2488uint32_t helper_float_ceilw_s(uint32_t fst0)
fd4a04eb 2489{
b6d96bed
TS
2490 uint32_t wt2;
2491
efd41037 2492 set_float_exception_flags(0, &env->active_fpu.fp_status);
f01be154
TS
2493 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2494 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
fd4a04eb
TS
2495 RESTORE_ROUNDING_MODE;
2496 update_fcr31();
f01be154 2497 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
b6d96bed
TS
2498 wt2 = FLOAT_SNAN32;
2499 return wt2;
fd4a04eb
TS
2500}
2501
c01fccd2 2502uint64_t helper_float_floorl_d(uint64_t fdt0)
fd4a04eb 2503{
b6d96bed
TS
2504 uint64_t dt2;
2505
efd41037 2506 set_float_exception_flags(0, &env->active_fpu.fp_status);
f01be154
TS
2507 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2508 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
fd4a04eb
TS
2509 RESTORE_ROUNDING_MODE;
2510 update_fcr31();
f01be154 2511 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
b6d96bed
TS
2512 dt2 = FLOAT_SNAN64;
2513 return dt2;
fd4a04eb 2514}
b6d96bed 2515
c01fccd2 2516uint64_t helper_float_floorl_s(uint32_t fst0)
fd4a04eb 2517{
b6d96bed
TS
2518 uint64_t dt2;
2519
efd41037 2520 set_float_exception_flags(0, &env->active_fpu.fp_status);
f01be154
TS
2521 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2522 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
fd4a04eb
TS
2523 RESTORE_ROUNDING_MODE;
2524 update_fcr31();
f01be154 2525 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
b6d96bed
TS
2526 dt2 = FLOAT_SNAN64;
2527 return dt2;
fd4a04eb 2528}
b6d96bed 2529
c01fccd2 2530uint32_t helper_float_floorw_d(uint64_t fdt0)
fd4a04eb 2531{
b6d96bed
TS
2532 uint32_t wt2;
2533
efd41037 2534 set_float_exception_flags(0, &env->active_fpu.fp_status);
f01be154
TS
2535 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2536 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
fd4a04eb
TS
2537 RESTORE_ROUNDING_MODE;
2538 update_fcr31();
f01be154 2539 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
b6d96bed
TS
2540 wt2 = FLOAT_SNAN32;
2541 return wt2;
fd4a04eb 2542}
b6d96bed 2543
c01fccd2 2544uint32_t helper_float_floorw_s(uint32_t fst0)
fd4a04eb 2545{
b6d96bed
TS
2546 uint32_t wt2;
2547
efd41037 2548 set_float_exception_flags(0, &env->active_fpu.fp_status);
f01be154
TS
2549 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2550 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
fd4a04eb
TS
2551 RESTORE_ROUNDING_MODE;
2552 update_fcr31();
f01be154 2553 if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
b6d96bed
TS
2554 wt2 = FLOAT_SNAN32;
2555 return wt2;
fd4a04eb
TS
2556}
2557
a16336e4 2558/* unary operations, not modifying fp status */
b6d96bed 2559#define FLOAT_UNOP(name) \
c01fccd2 2560uint64_t helper_float_ ## name ## _d(uint64_t fdt0) \
b6d96bed
TS
2561{ \
2562 return float64_ ## name(fdt0); \
2563} \
c01fccd2 2564uint32_t helper_float_ ## name ## _s(uint32_t fst0) \
b6d96bed
TS
2565{ \
2566 return float32_ ## name(fst0); \
2567} \
c01fccd2 2568uint64_t helper_float_ ## name ## _ps(uint64_t fdt0) \
b6d96bed
TS
2569{ \
2570 uint32_t wt0; \
2571 uint32_t wth0; \
2572 \
2573 wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF); \
2574 wth0 = float32_ ## name(fdt0 >> 32); \
2575 return ((uint64_t)wth0 << 32) | wt0; \
a16336e4
TS
2576}
2577FLOAT_UNOP(abs)
2578FLOAT_UNOP(chs)
2579#undef FLOAT_UNOP
2580
8dfdb87c 2581/* MIPS specific unary operations */
c01fccd2 2582uint64_t helper_float_recip_d(uint64_t fdt0)
8dfdb87c 2583{
b6d96bed
TS
2584 uint64_t fdt2;
2585
f01be154
TS
2586 set_float_exception_flags(0, &env->active_fpu.fp_status);
2587 fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
8dfdb87c 2588 update_fcr31();
b6d96bed 2589 return fdt2;
8dfdb87c 2590}
b6d96bed 2591
c01fccd2 2592uint32_t helper_float_recip_s(uint32_t fst0)
8dfdb87c 2593{
b6d96bed
TS
2594 uint32_t fst2;
2595
f01be154
TS
2596 set_float_exception_flags(0, &env->active_fpu.fp_status);
2597 fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status);
8dfdb87c 2598 update_fcr31();
b6d96bed 2599 return fst2;
57fa1fb3 2600}
57fa1fb3 2601
c01fccd2 2602uint64_t helper_float_rsqrt_d(uint64_t fdt0)
8dfdb87c 2603{
b6d96bed
TS
2604 uint64_t fdt2;
2605
f01be154
TS
2606 set_float_exception_flags(0, &env->active_fpu.fp_status);
2607 fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
2608 fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status);
8dfdb87c 2609 update_fcr31();
b6d96bed 2610 return fdt2;
8dfdb87c 2611}
b6d96bed 2612
c01fccd2 2613uint32_t helper_float_rsqrt_s(uint32_t fst0)
8dfdb87c 2614{
b6d96bed
TS
2615 uint32_t fst2;
2616
f01be154
TS
2617 set_float_exception_flags(0, &env->active_fpu.fp_status);
2618 fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
2619 fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
8dfdb87c 2620 update_fcr31();
b6d96bed 2621 return fst2;
8dfdb87c
TS
2622}
2623
c01fccd2 2624uint64_t helper_float_recip1_d(uint64_t fdt0)
8dfdb87c 2625{
b6d96bed
TS
2626 uint64_t fdt2;
2627
f01be154
TS
2628 set_float_exception_flags(0, &env->active_fpu.fp_status);
2629 fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
8dfdb87c 2630 update_fcr31();
b6d96bed 2631 return fdt2;
8dfdb87c 2632}
b6d96bed 2633
c01fccd2 2634uint32_t helper_float_recip1_s(uint32_t fst0)
8dfdb87c 2635{
b6d96bed
TS
2636 uint32_t fst2;
2637
f01be154
TS
2638 set_float_exception_flags(0, &env->active_fpu.fp_status);
2639 fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status);
8dfdb87c 2640 update_fcr31();
b6d96bed 2641 return fst2;
8dfdb87c 2642}
b6d96bed 2643
c01fccd2 2644uint64_t helper_float_recip1_ps(uint64_t fdt0)
8dfdb87c 2645{
b6d96bed
TS
2646 uint32_t fst2;
2647 uint32_t fsth2;
2648
f01be154
TS
2649 set_float_exception_flags(0, &env->active_fpu.fp_status);
2650 fst2 = float32_div(FLOAT_ONE32, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2651 fsth2 = float32_div(FLOAT_ONE32, fdt0 >> 32, &env->active_fpu.fp_status);
8dfdb87c 2652 update_fcr31();
b6d96bed 2653 return ((uint64_t)fsth2 << 32) | fst2;
8dfdb87c
TS
2654}
2655
c01fccd2 2656uint64_t helper_float_rsqrt1_d(uint64_t fdt0)
8dfdb87c 2657{
b6d96bed
TS
2658 uint64_t fdt2;
2659
f01be154
TS
2660 set_float_exception_flags(0, &env->active_fpu.fp_status);
2661 fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
2662 fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status);
8dfdb87c 2663 update_fcr31();
b6d96bed 2664 return fdt2;
8dfdb87c 2665}
b6d96bed 2666
c01fccd2 2667uint32_t helper_float_rsqrt1_s(uint32_t fst0)
8dfdb87c 2668{
b6d96bed
TS
2669 uint32_t fst2;
2670
f01be154
TS
2671 set_float_exception_flags(0, &env->active_fpu.fp_status);
2672 fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
2673 fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
8dfdb87c 2674 update_fcr31();
b6d96bed 2675 return fst2;
8dfdb87c 2676}
b6d96bed 2677
c01fccd2 2678uint64_t helper_float_rsqrt1_ps(uint64_t fdt0)
8dfdb87c 2679{
b6d96bed
TS
2680 uint32_t fst2;
2681 uint32_t fsth2;
2682
f01be154
TS
2683 set_float_exception_flags(0, &env->active_fpu.fp_status);
2684 fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2685 fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status);
2686 fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
2687 fsth2 = float32_div(FLOAT_ONE32, fsth2, &env->active_fpu.fp_status);
8dfdb87c 2688 update_fcr31();
b6d96bed 2689 return ((uint64_t)fsth2 << 32) | fst2;
57fa1fb3 2690}
57fa1fb3 2691
c01fccd2 2692#define FLOAT_OP(name, p) void helper_float_##name##_##p(void)
b6d96bed 2693
fd4a04eb 2694/* binary operations */
b6d96bed 2695#define FLOAT_BINOP(name) \
c01fccd2 2696uint64_t helper_float_ ## name ## _d(uint64_t fdt0, uint64_t fdt1) \
b6d96bed
TS
2697{ \
2698 uint64_t dt2; \
2699 \
f01be154
TS
2700 set_float_exception_flags(0, &env->active_fpu.fp_status); \
2701 dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status); \
ead9360e 2702 update_fcr31(); \
f01be154 2703 if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) \
b6d96bed
TS
2704 dt2 = FLOAT_QNAN64; \
2705 return dt2; \
2706} \
2707 \
c01fccd2 2708uint32_t helper_float_ ## name ## _s(uint32_t fst0, uint32_t fst1) \
b6d96bed
TS
2709{ \
2710 uint32_t wt2; \
2711 \
f01be154
TS
2712 set_float_exception_flags(0, &env->active_fpu.fp_status); \
2713 wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \
ead9360e 2714 update_fcr31(); \
f01be154 2715 if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) \
b6d96bed
TS
2716 wt2 = FLOAT_QNAN32; \
2717 return wt2; \
2718} \
2719 \
c01fccd2 2720uint64_t helper_float_ ## name ## _ps(uint64_t fdt0, uint64_t fdt1) \
b6d96bed
TS
2721{ \
2722 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
2723 uint32_t fsth0 = fdt0 >> 32; \
2724 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
2725 uint32_t fsth1 = fdt1 >> 32; \
2726 uint32_t wt2; \
2727 uint32_t wth2; \
2728 \
f01be154
TS
2729 set_float_exception_flags(0, &env->active_fpu.fp_status); \
2730 wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \
2731 wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status); \
b6d96bed 2732 update_fcr31(); \
f01be154 2733 if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) { \
b6d96bed
TS
2734 wt2 = FLOAT_QNAN32; \
2735 wth2 = FLOAT_QNAN32; \
2736 } \
2737 return ((uint64_t)wth2 << 32) | wt2; \
fd4a04eb 2738}
b6d96bed 2739
fd4a04eb
TS
2740FLOAT_BINOP(add)
2741FLOAT_BINOP(sub)
2742FLOAT_BINOP(mul)
2743FLOAT_BINOP(div)
2744#undef FLOAT_BINOP
2745
a16336e4 2746/* ternary operations */
b6d96bed 2747#define FLOAT_TERNOP(name1, name2) \
c01fccd2 2748uint64_t helper_float_ ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1, \
b6d96bed
TS
2749 uint64_t fdt2) \
2750{ \
f01be154
TS
2751 fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status); \
2752 return float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status); \
b6d96bed
TS
2753} \
2754 \
c01fccd2 2755uint32_t helper_float_ ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1, \
b6d96bed
TS
2756 uint32_t fst2) \
2757{ \
f01be154
TS
2758 fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \
2759 return float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \
b6d96bed
TS
2760} \
2761 \
c01fccd2 2762uint64_t helper_float_ ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1, \
b6d96bed
TS
2763 uint64_t fdt2) \
2764{ \
2765 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
2766 uint32_t fsth0 = fdt0 >> 32; \
2767 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
2768 uint32_t fsth1 = fdt1 >> 32; \
2769 uint32_t fst2 = fdt2 & 0XFFFFFFFF; \
2770 uint32_t fsth2 = fdt2 >> 32; \
2771 \
f01be154
TS
2772 fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \
2773 fsth0 = float32_ ## name1 (fsth0, fsth1, &env->active_fpu.fp_status); \
2774 fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \
2775 fsth2 = float32_ ## name2 (fsth0, fsth2, &env->active_fpu.fp_status); \
b6d96bed 2776 return ((uint64_t)fsth2 << 32) | fst2; \
a16336e4 2777}
b6d96bed 2778
a16336e4
TS
2779FLOAT_TERNOP(mul, add)
2780FLOAT_TERNOP(mul, sub)
2781#undef FLOAT_TERNOP
2782
2783/* negated ternary operations */
b6d96bed 2784#define FLOAT_NTERNOP(name1, name2) \
c01fccd2 2785uint64_t helper_float_n ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1, \
b6d96bed
TS
2786 uint64_t fdt2) \
2787{ \
f01be154
TS
2788 fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status); \
2789 fdt2 = float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status); \
b6d96bed
TS
2790 return float64_chs(fdt2); \
2791} \
2792 \
c01fccd2 2793uint32_t helper_float_n ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1, \
b6d96bed
TS
2794 uint32_t fst2) \
2795{ \
f01be154
TS
2796 fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \
2797 fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \
b6d96bed
TS
2798 return float32_chs(fst2); \
2799} \
2800 \
c01fccd2 2801uint64_t helper_float_n ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1,\
b6d96bed
TS
2802 uint64_t fdt2) \
2803{ \
2804 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
2805 uint32_t fsth0 = fdt0 >> 32; \
2806 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
2807 uint32_t fsth1 = fdt1 >> 32; \
2808 uint32_t fst2 = fdt2 & 0XFFFFFFFF; \
2809 uint32_t fsth2 = fdt2 >> 32; \
2810 \
f01be154
TS
2811 fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \
2812 fsth0 = float32_ ## name1 (fsth0, fsth1, &env->active_fpu.fp_status); \
2813 fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \
2814 fsth2 = float32_ ## name2 (fsth0, fsth2, &env->active_fpu.fp_status); \
b6d96bed
TS
2815 fst2 = float32_chs(fst2); \
2816 fsth2 = float32_chs(fsth2); \
2817 return ((uint64_t)fsth2 << 32) | fst2; \
a16336e4 2818}
b6d96bed 2819
a16336e4
TS
2820FLOAT_NTERNOP(mul, add)
2821FLOAT_NTERNOP(mul, sub)
2822#undef FLOAT_NTERNOP
2823
8dfdb87c 2824/* MIPS specific binary operations */
c01fccd2 2825uint64_t helper_float_recip2_d(uint64_t fdt0, uint64_t fdt2)
8dfdb87c 2826{
f01be154
TS
2827 set_float_exception_flags(0, &env->active_fpu.fp_status);
2828 fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
2829 fdt2 = float64_chs(float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status));
8dfdb87c 2830 update_fcr31();
b6d96bed 2831 return fdt2;
8dfdb87c 2832}
b6d96bed 2833
c01fccd2 2834uint32_t helper_float_recip2_s(uint32_t fst0, uint32_t fst2)
8dfdb87c 2835{
f01be154
TS
2836 set_float_exception_flags(0, &env->active_fpu.fp_status);
2837 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
2838 fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status));
8dfdb87c 2839 update_fcr31();
b6d96bed 2840 return fst2;
8dfdb87c 2841}
b6d96bed 2842
c01fccd2 2843uint64_t helper_float_recip2_ps(uint64_t fdt0, uint64_t fdt2)
8dfdb87c 2844{
b6d96bed
TS
2845 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
2846 uint32_t fsth0 = fdt0 >> 32;
2847 uint32_t fst2 = fdt2 & 0XFFFFFFFF;
2848 uint32_t fsth2 = fdt2 >> 32;
2849
f01be154
TS
2850 set_float_exception_flags(0, &env->active_fpu.fp_status);
2851 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
2852 fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
2853 fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status));
2854 fsth2 = float32_chs(float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status));
8dfdb87c 2855 update_fcr31();
b6d96bed 2856 return ((uint64_t)fsth2 << 32) | fst2;
8dfdb87c
TS
2857}
2858
c01fccd2 2859uint64_t helper_float_rsqrt2_d(uint64_t fdt0, uint64_t fdt2)
8dfdb87c 2860{
f01be154
TS
2861 set_float_exception_flags(0, &env->active_fpu.fp_status);
2862 fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
2863 fdt2 = float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status);
2864 fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status));
8dfdb87c 2865 update_fcr31();
b6d96bed 2866 return fdt2;
8dfdb87c 2867}
b6d96bed 2868
c01fccd2 2869uint32_t helper_float_rsqrt2_s(uint32_t fst0, uint32_t fst2)
8dfdb87c 2870{
f01be154
TS
2871 set_float_exception_flags(0, &env->active_fpu.fp_status);
2872 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
2873 fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status);
2874 fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
8dfdb87c 2875 update_fcr31();
b6d96bed 2876 return fst2;
8dfdb87c 2877}
b6d96bed 2878
c01fccd2 2879uint64_t helper_float_rsqrt2_ps(uint64_t fdt0, uint64_t fdt2)
8dfdb87c 2880{
b6d96bed
TS
2881 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
2882 uint32_t fsth0 = fdt0 >> 32;
2883 uint32_t fst2 = fdt2 & 0XFFFFFFFF;
2884 uint32_t fsth2 = fdt2 >> 32;
2885
f01be154
TS
2886 set_float_exception_flags(0, &env->active_fpu.fp_status);
2887 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
2888 fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
2889 fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status);
2890 fsth2 = float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status);
2891 fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
2892 fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->active_fpu.fp_status));
8dfdb87c 2893 update_fcr31();
b6d96bed 2894 return ((uint64_t)fsth2 << 32) | fst2;
57fa1fb3 2895}
57fa1fb3 2896
c01fccd2 2897uint64_t helper_float_addr_ps(uint64_t fdt0, uint64_t fdt1)
fd4a04eb 2898{
b6d96bed
TS
2899 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
2900 uint32_t fsth0 = fdt0 >> 32;
2901 uint32_t fst1 = fdt1 & 0XFFFFFFFF;
2902 uint32_t fsth1 = fdt1 >> 32;
2903 uint32_t fst2;
2904 uint32_t fsth2;
2905
f01be154
TS
2906 set_float_exception_flags(0, &env->active_fpu.fp_status);
2907 fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status);
2908 fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status);
fd4a04eb 2909 update_fcr31();
b6d96bed 2910 return ((uint64_t)fsth2 << 32) | fst2;
fd4a04eb
TS
2911}
2912
c01fccd2 2913uint64_t helper_float_mulr_ps(uint64_t fdt0, uint64_t fdt1)
57fa1fb3 2914{
b6d96bed
TS
2915 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
2916 uint32_t fsth0 = fdt0 >> 32;
2917 uint32_t fst1 = fdt1 & 0XFFFFFFFF;
2918 uint32_t fsth1 = fdt1 >> 32;
2919 uint32_t fst2;
2920 uint32_t fsth2;
2921
f01be154
TS
2922 set_float_exception_flags(0, &env->active_fpu.fp_status);
2923 fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status);
2924 fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status);
57fa1fb3 2925 update_fcr31();
b6d96bed 2926 return ((uint64_t)fsth2 << 32) | fst2;
57fa1fb3
TS
2927}
2928
8dfdb87c 2929/* compare operations */
b6d96bed 2930#define FOP_COND_D(op, cond) \
c01fccd2 2931void helper_cmp_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
b6d96bed 2932{ \
6a385343
AJ
2933 int c; \
2934 set_float_exception_flags(0, &env->active_fpu.fp_status); \
2935 c = cond; \
b6d96bed
TS
2936 update_fcr31(); \
2937 if (c) \
f01be154 2938 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 2939 else \
f01be154 2940 CLEAR_FP_COND(cc, env->active_fpu); \
b6d96bed 2941} \
c01fccd2 2942void helper_cmpabs_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
b6d96bed
TS
2943{ \
2944 int c; \
6a385343 2945 set_float_exception_flags(0, &env->active_fpu.fp_status); \
b6d96bed
TS
2946 fdt0 = float64_abs(fdt0); \
2947 fdt1 = float64_abs(fdt1); \
2948 c = cond; \
2949 update_fcr31(); \
2950 if (c) \
f01be154 2951 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 2952 else \
f01be154 2953 CLEAR_FP_COND(cc, env->active_fpu); \
fd4a04eb
TS
2954}
2955
fd4a04eb 2956/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
2957 * but float64_unordered_quiet() is still called. */
2958FOP_COND_D(f, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
2959FOP_COND_D(un, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status))
06a0e6b1 2960FOP_COND_D(eq, float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
211315fb 2961FOP_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
2962FOP_COND_D(olt, float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
2963FOP_COND_D(ult, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
2964FOP_COND_D(ole, float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
2965FOP_COND_D(ule, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
fd4a04eb 2966/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
2967 * but float64_unordered() is still called. */
2968FOP_COND_D(sf, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
2969FOP_COND_D(ngle,float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status))
06a0e6b1
AJ
2970FOP_COND_D(seq, float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
2971FOP_COND_D(ngl, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
2972FOP_COND_D(lt, float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
3a599383 2973FOP_COND_D(nge, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
06a0e6b1 2974FOP_COND_D(le, float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3a599383 2975FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
b6d96bed
TS
2976
2977#define FOP_COND_S(op, cond) \
c01fccd2 2978void helper_cmp_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \
b6d96bed 2979{ \
6a385343
AJ
2980 int c; \
2981 set_float_exception_flags(0, &env->active_fpu.fp_status); \
2982 c = cond; \
b6d96bed
TS
2983 update_fcr31(); \
2984 if (c) \
f01be154 2985 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 2986 else \
f01be154 2987 CLEAR_FP_COND(cc, env->active_fpu); \
b6d96bed 2988} \
c01fccd2 2989void helper_cmpabs_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \
b6d96bed
TS
2990{ \
2991 int c; \
6a385343 2992 set_float_exception_flags(0, &env->active_fpu.fp_status); \
b6d96bed
TS
2993 fst0 = float32_abs(fst0); \
2994 fst1 = float32_abs(fst1); \
2995 c = cond; \
2996 update_fcr31(); \
2997 if (c) \
f01be154 2998 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 2999 else \
f01be154 3000 CLEAR_FP_COND(cc, env->active_fpu); \
fd4a04eb
TS
3001}
3002
fd4a04eb 3003/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3004 * but float32_unordered_quiet() is still called. */
3005FOP_COND_S(f, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
3006FOP_COND_S(un, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status))
06a0e6b1 3007FOP_COND_S(eq, float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
211315fb 3008FOP_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
3009FOP_COND_S(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
3010FOP_COND_S(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
3011FOP_COND_S(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
3012FOP_COND_S(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
fd4a04eb 3013/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3014 * but float32_unordered() is still called. */
3015FOP_COND_S(sf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
3016FOP_COND_S(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status))
06a0e6b1
AJ
3017FOP_COND_S(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status))
3018FOP_COND_S(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
3019FOP_COND_S(lt, float32_lt(fst0, fst1, &env->active_fpu.fp_status))
3a599383 3020FOP_COND_S(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
06a0e6b1 3021FOP_COND_S(le, float32_le(fst0, fst1, &env->active_fpu.fp_status))
3a599383 3022FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status))
b6d96bed
TS
3023
3024#define FOP_COND_PS(op, condl, condh) \
c01fccd2 3025void helper_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
b6d96bed 3026{ \
6a385343
AJ
3027 uint32_t fst0, fsth0, fst1, fsth1; \
3028 int ch, cl; \
3029 set_float_exception_flags(0, &env->active_fpu.fp_status); \
3030 fst0 = fdt0 & 0XFFFFFFFF; \
3031 fsth0 = fdt0 >> 32; \
3032 fst1 = fdt1 & 0XFFFFFFFF; \
3033 fsth1 = fdt1 >> 32; \
3034 cl = condl; \
3035 ch = condh; \
b6d96bed
TS
3036 update_fcr31(); \
3037 if (cl) \
f01be154 3038 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3039 else \
f01be154 3040 CLEAR_FP_COND(cc, env->active_fpu); \
b6d96bed 3041 if (ch) \
f01be154 3042 SET_FP_COND(cc + 1, env->active_fpu); \
b6d96bed 3043 else \
f01be154 3044 CLEAR_FP_COND(cc + 1, env->active_fpu); \
b6d96bed 3045} \
c01fccd2 3046void helper_cmpabs_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
b6d96bed 3047{ \
6a385343
AJ
3048 uint32_t fst0, fsth0, fst1, fsth1; \
3049 int ch, cl; \
3050 fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \
3051 fsth0 = float32_abs(fdt0 >> 32); \
3052 fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \
3053 fsth1 = float32_abs(fdt1 >> 32); \
3054 cl = condl; \
3055 ch = condh; \
b6d96bed
TS
3056 update_fcr31(); \
3057 if (cl) \
f01be154 3058 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3059 else \
f01be154 3060 CLEAR_FP_COND(cc, env->active_fpu); \
b6d96bed 3061 if (ch) \
f01be154 3062 SET_FP_COND(cc + 1, env->active_fpu); \
b6d96bed 3063 else \
f01be154 3064 CLEAR_FP_COND(cc + 1, env->active_fpu); \
fd4a04eb
TS
3065}
3066
3067/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3068 * but float32_unordered_quiet() is still called. */
3069FOP_COND_PS(f, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0),
3070 (float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status), 0))
3071FOP_COND_PS(un, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status),
3072 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status))
06a0e6b1
AJ
3073FOP_COND_PS(eq, float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
3074 float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
211315fb
AJ
3075FOP_COND_PS(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
3076 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
06a0e6b1
AJ
3077FOP_COND_PS(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
3078 float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3079FOP_COND_PS(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
3080 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3081FOP_COND_PS(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
3082 float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3083FOP_COND_PS(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
3084 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
fd4a04eb 3085/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3086 * but float32_unordered() is still called. */
3087FOP_COND_PS(sf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0),
3088 (float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status), 0))
3089FOP_COND_PS(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status),
3090 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status))
06a0e6b1
AJ
3091FOP_COND_PS(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status),
3092 float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
3093FOP_COND_PS(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
3094 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
3095FOP_COND_PS(lt, float32_lt(fst0, fst1, &env->active_fpu.fp_status),
3096 float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
3a599383
AJ
3097FOP_COND_PS(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
3098 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
06a0e6b1
AJ
3099FOP_COND_PS(le, float32_le(fst0, fst1, &env->active_fpu.fp_status),
3100 float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
3a599383
AJ
3101FOP_COND_PS(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status),
3102 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))