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