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