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