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