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