]> git.proxmox.com Git - mirror_qemu.git/blame - target-mips/op_helper.c
ivshmem: Fix 64 bit memory bar configuration
[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;
6ec98bd7 682 tasid = v & cpu->CP0_EntryHi_ASID_mask;
fe8dca8c
EI
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. */
6ec98bd7 693 cpu->CP0_EntryHi &= ~cpu->CP0_EntryHi_ASID_mask;
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
6ec98bd7 705 asid = v & cpu->CP0_EntryHi_ASID_mask;
fe8dca8c
EI
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
6ec98bd7 713 *tcst &= ~cpu->CP0_EntryHi_ASID_mask;
fe8dca8c
EI
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 1405 target_ulong old, val, mask;
6ec98bd7 1406 mask = (TARGET_PAGE_MASK << 1) | env->CP0_EntryHi_ASID_mask;
9456c2fb
LA
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. */
6ec98bd7
PB
1432 if ((old & env->CP0_EntryHi_ASID_mask) !=
1433 (val & env->CP0_EntryHi_ASID_mask)) {
f1aa6320 1434 cpu_mips_tlb_flush(env, 1);
6ec98bd7 1435 }
f1aa6320
TS
1436}
1437
895c2d04 1438void helper_mttc0_entryhi(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1439{
1440 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1441 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1442
fe8dca8c
EI
1443 other->CP0_EntryHi = arg1;
1444 sync_c0_entryhi(other, other_tc);
f1aa6320
TS
1445}
1446
895c2d04 1447void helper_mtc0_compare(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1448{
d9bea114 1449 cpu_mips_store_compare(env, arg1);
f1aa6320
TS
1450}
1451
895c2d04 1452void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1453{
a47dddd7 1454 MIPSCPU *cpu = mips_env_get_cpu(env);
f1aa6320 1455 uint32_t val, old;
ba801af4 1456
f1aa6320 1457 old = env->CP0_Status;
81a423e6
MR
1458 cpu_mips_store_status(env, arg1);
1459 val = env->CP0_Status;
fe8dca8c 1460
c01fccd2
AJ
1461 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1462 qemu_log("Status %08x (%08x) => %08x (%08x) Cause %08x",
1463 old, old & env->CP0_Cause & CP0Ca_IP_mask,
1464 val, val & env->CP0_Cause & CP0Ca_IP_mask,
1465 env->CP0_Cause);
1466 switch (env->hflags & MIPS_HFLAG_KSU) {
1467 case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
1468 case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
1469 case MIPS_HFLAG_KM: qemu_log("\n"); break;
a47dddd7
AF
1470 default:
1471 cpu_abort(CPU(cpu), "Invalid MMU mode!\n");
1472 break;
31e3104f 1473 }
c01fccd2 1474 }
f1aa6320
TS
1475}
1476
895c2d04 1477void helper_mttc0_status(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1478{
1479 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1d725ae9 1480 uint32_t mask = env->CP0_Status_rw_bitmask & ~0xf1000018;
895c2d04 1481 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1482
1d725ae9 1483 other->CP0_Status = (other->CP0_Status & ~mask) | (arg1 & mask);
895c2d04 1484 sync_c0_status(env, other, other_tc);
f1aa6320
TS
1485}
1486
895c2d04 1487void helper_mtc0_intctl(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1488{
bc45a67a 1489 env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000003e0) | (arg1 & 0x000003e0);
f1aa6320
TS
1490}
1491
895c2d04 1492void helper_mtc0_srsctl(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1493{
1494 uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
d9bea114 1495 env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask);
f1aa6320
TS
1496}
1497
895c2d04 1498void helper_mtc0_cause(CPUMIPSState *env, target_ulong arg1)
5a25ce94 1499{
81a423e6 1500 cpu_mips_store_cause(env, arg1);
5a25ce94
EI
1501}
1502
895c2d04 1503void helper_mttc0_cause(CPUMIPSState *env, target_ulong arg1)
5a25ce94
EI
1504{
1505 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1506 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
5a25ce94 1507
81a423e6 1508 cpu_mips_store_cause(other, arg1);
5a25ce94
EI
1509}
1510
895c2d04 1511target_ulong helper_mftc0_epc(CPUMIPSState *env)
5a25ce94
EI
1512{
1513 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1514 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
5a25ce94
EI
1515
1516 return other->CP0_EPC;
1517}
1518
895c2d04 1519target_ulong helper_mftc0_ebase(CPUMIPSState *env)
5a25ce94
EI
1520{
1521 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1522 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
5a25ce94
EI
1523
1524 return other->CP0_EBase;
1525}
1526
895c2d04 1527void helper_mtc0_ebase(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1528{
671b0f36 1529 env->CP0_EBase = (env->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
f1aa6320
TS
1530}
1531
895c2d04 1532void helper_mttc0_ebase(CPUMIPSState *env, target_ulong arg1)
5a25ce94
EI
1533{
1534 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1535 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
5a25ce94
EI
1536 other->CP0_EBase = (other->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
1537}
1538
895c2d04 1539target_ulong helper_mftc0_configx(CPUMIPSState *env, target_ulong idx)
5a25ce94
EI
1540{
1541 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1542 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
5a25ce94
EI
1543
1544 switch (idx) {
1545 case 0: return other->CP0_Config0;
1546 case 1: return other->CP0_Config1;
1547 case 2: return other->CP0_Config2;
1548 case 3: return other->CP0_Config3;
1549 /* 4 and 5 are reserved. */
1550 case 6: return other->CP0_Config6;
1551 case 7: return other->CP0_Config7;
1552 default:
1553 break;
1554 }
1555 return 0;
1556}
1557
895c2d04 1558void helper_mtc0_config0(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1559{
d9bea114 1560 env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007);
f1aa6320
TS
1561}
1562
895c2d04 1563void helper_mtc0_config2(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1564{
1565 /* tertiary/secondary caches not implemented */
1566 env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
1567}
1568
90f12d73
MR
1569void helper_mtc0_config3(CPUMIPSState *env, target_ulong arg1)
1570{
1571 if (env->insn_flags & ASE_MICROMIPS) {
1572 env->CP0_Config3 = (env->CP0_Config3 & ~(1 << CP0C3_ISA_ON_EXC)) |
1573 (arg1 & (1 << CP0C3_ISA_ON_EXC));
1574 }
1575}
1576
b4160af1
PJ
1577void helper_mtc0_config4(CPUMIPSState *env, target_ulong arg1)
1578{
1579 env->CP0_Config4 = (env->CP0_Config4 & (~env->CP0_Config4_rw_bitmask)) |
1580 (arg1 & env->CP0_Config4_rw_bitmask);
1581}
1582
b4dd99a3
PJ
1583void helper_mtc0_config5(CPUMIPSState *env, target_ulong arg1)
1584{
1585 env->CP0_Config5 = (env->CP0_Config5 & (~env->CP0_Config5_rw_bitmask)) |
1586 (arg1 & env->CP0_Config5_rw_bitmask);
e97a391d 1587 compute_hflags(env);
b4dd99a3
PJ
1588}
1589
895c2d04 1590void helper_mtc0_lladdr(CPUMIPSState *env, target_ulong arg1)
2a6e32dd
AJ
1591{
1592 target_long mask = env->CP0_LLAddr_rw_bitmask;
1593 arg1 = arg1 << env->CP0_LLAddr_shift;
1594 env->lladdr = (env->lladdr & ~mask) | (arg1 & mask);
1595}
1596
f6d4dd81
YK
1597#define MTC0_MAAR_MASK(env) \
1598 ((0x1ULL << 63) | ((env->PAMask >> 4) & ~0xFFFull) | 0x3)
1599
1600void helper_mtc0_maar(CPUMIPSState *env, target_ulong arg1)
1601{
1602 env->CP0_MAAR[env->CP0_MAARI] = arg1 & MTC0_MAAR_MASK(env);
1603}
1604
1605void helper_mthc0_maar(CPUMIPSState *env, target_ulong arg1)
1606{
1607 env->CP0_MAAR[env->CP0_MAARI] =
1608 (((uint64_t) arg1 << 32) & MTC0_MAAR_MASK(env)) |
1609 (env->CP0_MAAR[env->CP0_MAARI] & 0x00000000ffffffffULL);
1610}
1611
1612void helper_mtc0_maari(CPUMIPSState *env, target_ulong arg1)
1613{
1614 int index = arg1 & 0x3f;
1615 if (index == 0x3f) {
1616 /* Software may write all ones to INDEX to determine the
1617 maximum value supported. */
1618 env->CP0_MAARI = MIPS_MAAR_MAX - 1;
1619 } else if (index < MIPS_MAAR_MAX) {
1620 env->CP0_MAARI = index;
1621 }
1622 /* Other than the all ones, if the
1623 value written is not supported, then INDEX is unchanged
1624 from its previous value. */
1625}
1626
895c2d04 1627void helper_mtc0_watchlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
f1aa6320
TS
1628{
1629 /* Watch exceptions for instructions, data loads, data stores
1630 not implemented. */
d9bea114 1631 env->CP0_WatchLo[sel] = (arg1 & ~0x7);
f1aa6320
TS
1632}
1633
895c2d04 1634void helper_mtc0_watchhi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
f1aa6320 1635{
6ec98bd7
PB
1636 int mask = 0x40000FF8 | (env->CP0_EntryHi_ASID_mask << CP0WH_ASID);
1637 env->CP0_WatchHi[sel] = arg1 & mask;
d9bea114 1638 env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7);
f1aa6320
TS
1639}
1640
895c2d04 1641void helper_mtc0_xcontext(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1642{
1643 target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
d9bea114 1644 env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask);
f1aa6320
TS
1645}
1646
895c2d04 1647void helper_mtc0_framemask(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1648{
d9bea114 1649 env->CP0_Framemask = arg1; /* XXX */
f1aa6320
TS
1650}
1651
895c2d04 1652void helper_mtc0_debug(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1653{
d9bea114
AJ
1654 env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120);
1655 if (arg1 & (1 << CP0DB_DM))
f1aa6320
TS
1656 env->hflags |= MIPS_HFLAG_DM;
1657 else
1658 env->hflags &= ~MIPS_HFLAG_DM;
1659}
1660
895c2d04 1661void helper_mttc0_debug(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1662{
1663 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
d9bea114 1664 uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
895c2d04 1665 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320
TS
1666
1667 /* XXX: Might be wrong, check with EJTAG spec. */
b93bbdcd
EI
1668 if (other_tc == other->current_tc)
1669 other->active_tc.CP0_Debug_tcstatus = val;
b5dc7732 1670 else
b93bbdcd
EI
1671 other->tcs[other_tc].CP0_Debug_tcstatus = val;
1672 other->CP0_Debug = (other->CP0_Debug &
1673 ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
d9bea114 1674 (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
f1aa6320
TS
1675}
1676
895c2d04 1677void helper_mtc0_performance0(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1678{
d9bea114 1679 env->CP0_Performance0 = arg1 & 0x000007ff;
f1aa6320
TS
1680}
1681
0d74a222
LA
1682void helper_mtc0_errctl(CPUMIPSState *env, target_ulong arg1)
1683{
1684 int32_t wst = arg1 & (1 << CP0EC_WST);
1685 int32_t spr = arg1 & (1 << CP0EC_SPR);
1686 int32_t itc = env->itc_tag ? (arg1 & (1 << CP0EC_ITC)) : 0;
1687
1688 env->CP0_ErrCtl = wst | spr | itc;
1689
1690 if (itc && !wst && !spr) {
1691 env->hflags |= MIPS_HFLAG_ITC_CACHE;
1692 } else {
1693 env->hflags &= ~MIPS_HFLAG_ITC_CACHE;
1694 }
1695}
1696
895c2d04 1697void helper_mtc0_taglo(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1698{
0d74a222
LA
1699 if (env->hflags & MIPS_HFLAG_ITC_CACHE) {
1700 /* If CACHE instruction is configured for ITC tags then make all
1701 CP0.TagLo bits writable. The actual write to ITC Configuration
1702 Tag will take care of the read-only bits. */
1703 env->CP0_TagLo = arg1;
1704 } else {
1705 env->CP0_TagLo = arg1 & 0xFFFFFCF6;
1706 }
f1aa6320
TS
1707}
1708
895c2d04 1709void helper_mtc0_datalo(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1710{
d9bea114 1711 env->CP0_DataLo = arg1; /* XXX */
f1aa6320
TS
1712}
1713
895c2d04 1714void helper_mtc0_taghi(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1715{
d9bea114 1716 env->CP0_TagHi = arg1; /* XXX */
f1aa6320
TS
1717}
1718
895c2d04 1719void helper_mtc0_datahi(CPUMIPSState *env, target_ulong arg1)
f1aa6320 1720{
d9bea114 1721 env->CP0_DataHi = arg1; /* XXX */
f1aa6320
TS
1722}
1723
f1aa6320 1724/* MIPS MT functions */
895c2d04 1725target_ulong helper_mftgpr(CPUMIPSState *env, uint32_t sel)
f1aa6320
TS
1726{
1727 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1728 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1729
b93bbdcd
EI
1730 if (other_tc == other->current_tc)
1731 return other->active_tc.gpr[sel];
b5dc7732 1732 else
b93bbdcd 1733 return other->tcs[other_tc].gpr[sel];
f1aa6320
TS
1734}
1735
895c2d04 1736target_ulong helper_mftlo(CPUMIPSState *env, uint32_t sel)
f1aa6320
TS
1737{
1738 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1739 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1740
b93bbdcd
EI
1741 if (other_tc == other->current_tc)
1742 return other->active_tc.LO[sel];
b5dc7732 1743 else
b93bbdcd 1744 return other->tcs[other_tc].LO[sel];
f1aa6320
TS
1745}
1746
895c2d04 1747target_ulong helper_mfthi(CPUMIPSState *env, uint32_t sel)
f1aa6320
TS
1748{
1749 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1750 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1751
b93bbdcd
EI
1752 if (other_tc == other->current_tc)
1753 return other->active_tc.HI[sel];
b5dc7732 1754 else
b93bbdcd 1755 return other->tcs[other_tc].HI[sel];
f1aa6320
TS
1756}
1757
895c2d04 1758target_ulong helper_mftacx(CPUMIPSState *env, uint32_t sel)
f1aa6320
TS
1759{
1760 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1761 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1762
b93bbdcd
EI
1763 if (other_tc == other->current_tc)
1764 return other->active_tc.ACX[sel];
b5dc7732 1765 else
b93bbdcd 1766 return other->tcs[other_tc].ACX[sel];
f1aa6320
TS
1767}
1768
895c2d04 1769target_ulong helper_mftdsp(CPUMIPSState *env)
f1aa6320
TS
1770{
1771 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1772 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1773
b93bbdcd
EI
1774 if (other_tc == other->current_tc)
1775 return other->active_tc.DSPControl;
b5dc7732 1776 else
b93bbdcd 1777 return other->tcs[other_tc].DSPControl;
f1aa6320 1778}
6af0bf9c 1779
895c2d04 1780void helper_mttgpr(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
f1aa6320
TS
1781{
1782 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1783 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1784
b93bbdcd
EI
1785 if (other_tc == other->current_tc)
1786 other->active_tc.gpr[sel] = arg1;
b5dc7732 1787 else
b93bbdcd 1788 other->tcs[other_tc].gpr[sel] = arg1;
f1aa6320
TS
1789}
1790
895c2d04 1791void helper_mttlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
f1aa6320
TS
1792{
1793 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1794 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1795
b93bbdcd
EI
1796 if (other_tc == other->current_tc)
1797 other->active_tc.LO[sel] = arg1;
b5dc7732 1798 else
b93bbdcd 1799 other->tcs[other_tc].LO[sel] = arg1;
f1aa6320
TS
1800}
1801
895c2d04 1802void helper_mtthi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
f1aa6320
TS
1803{
1804 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1805 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1806
b93bbdcd
EI
1807 if (other_tc == other->current_tc)
1808 other->active_tc.HI[sel] = arg1;
b5dc7732 1809 else
b93bbdcd 1810 other->tcs[other_tc].HI[sel] = arg1;
f1aa6320
TS
1811}
1812
895c2d04 1813void helper_mttacx(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
f1aa6320
TS
1814{
1815 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1816 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1817
b93bbdcd
EI
1818 if (other_tc == other->current_tc)
1819 other->active_tc.ACX[sel] = arg1;
b5dc7732 1820 else
b93bbdcd 1821 other->tcs[other_tc].ACX[sel] = arg1;
f1aa6320
TS
1822}
1823
895c2d04 1824void helper_mttdsp(CPUMIPSState *env, target_ulong arg1)
f1aa6320
TS
1825{
1826 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
895c2d04 1827 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
f1aa6320 1828
b93bbdcd
EI
1829 if (other_tc == other->current_tc)
1830 other->active_tc.DSPControl = arg1;
b5dc7732 1831 else
b93bbdcd 1832 other->tcs[other_tc].DSPControl = arg1;
f1aa6320
TS
1833}
1834
1835/* MIPS MT functions */
9ed5726c 1836target_ulong helper_dmt(void)
f1aa6320
TS
1837{
1838 // TODO
9ed5726c 1839 return 0;
f1aa6320
TS
1840}
1841
9ed5726c 1842target_ulong helper_emt(void)
f1aa6320
TS
1843{
1844 // TODO
9ed5726c 1845 return 0;
f1aa6320
TS
1846}
1847
895c2d04 1848target_ulong helper_dvpe(CPUMIPSState *env)
f1aa6320 1849{
182735ef 1850 CPUState *other_cs = first_cpu;
f249412c
EI
1851 target_ulong prev = env->mvp->CP0_MVPControl;
1852
bdc44640 1853 CPU_FOREACH(other_cs) {
182735ef 1854 MIPSCPU *other_cpu = MIPS_CPU(other_cs);
f249412c 1855 /* Turn off all VPEs except the one executing the dvpe. */
182735ef
AF
1856 if (&other_cpu->env != env) {
1857 other_cpu->env.mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP);
6f4d6b09 1858 mips_vpe_sleep(other_cpu);
f249412c 1859 }
bdc44640 1860 }
f249412c 1861 return prev;
f1aa6320
TS
1862}
1863
895c2d04 1864target_ulong helper_evpe(CPUMIPSState *env)
f1aa6320 1865{
182735ef 1866 CPUState *other_cs = first_cpu;
f249412c
EI
1867 target_ulong prev = env->mvp->CP0_MVPControl;
1868
bdc44640 1869 CPU_FOREACH(other_cs) {
182735ef 1870 MIPSCPU *other_cpu = MIPS_CPU(other_cs);
b35d77d7 1871
182735ef 1872 if (&other_cpu->env != env
81bad50e 1873 /* If the VPE is WFI, don't disturb its sleep. */
b35d77d7 1874 && !mips_vpe_is_wfi(other_cpu)) {
f249412c 1875 /* Enable the VPE. */
182735ef 1876 other_cpu->env.mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
c3affe56 1877 mips_vpe_wake(other_cpu); /* And wake it up. */
f249412c 1878 }
bdc44640 1879 }
f249412c 1880 return prev;
f1aa6320 1881}
f9480ffc 1882#endif /* !CONFIG_USER_ONLY */
f1aa6320 1883
d9bea114 1884void helper_fork(target_ulong arg1, target_ulong arg2)
f1aa6320 1885{
d9bea114 1886 // arg1 = rt, arg2 = rs
f1aa6320
TS
1887 // TODO: store to TC register
1888}
1889
895c2d04 1890target_ulong helper_yield(CPUMIPSState *env, target_ulong arg)
f1aa6320 1891{
1c7242da
BS
1892 target_long arg1 = arg;
1893
d9bea114 1894 if (arg1 < 0) {
f1aa6320 1895 /* No scheduling policy implemented. */
d9bea114 1896 if (arg1 != -2) {
f1aa6320 1897 if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
b5dc7732 1898 env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
f1aa6320
TS
1899 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1900 env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
9c708c7f 1901 do_raise_exception(env, EXCP_THREAD, GETPC());
f1aa6320
TS
1902 }
1903 }
d9bea114 1904 } else if (arg1 == 0) {
6958549d 1905 if (0 /* TODO: TC underflow */) {
f1aa6320 1906 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
9c708c7f 1907 do_raise_exception(env, EXCP_THREAD, GETPC());
f1aa6320
TS
1908 } else {
1909 // TODO: Deallocate TC
1910 }
d9bea114 1911 } else if (arg1 > 0) {
f1aa6320
TS
1912 /* Yield qualifier inputs not implemented. */
1913 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1914 env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
9c708c7f 1915 do_raise_exception(env, EXCP_THREAD, GETPC());
f1aa6320 1916 }
be24bb4f 1917 return env->CP0_YQMask;
f1aa6320
TS
1918}
1919
01bc435b
YK
1920/* R6 Multi-threading */
1921#ifndef CONFIG_USER_ONLY
1922target_ulong helper_dvp(CPUMIPSState *env)
1923{
1924 CPUState *other_cs = first_cpu;
1925 target_ulong prev = env->CP0_VPControl;
1926
1927 if (!((env->CP0_VPControl >> CP0VPCtl_DIS) & 1)) {
1928 CPU_FOREACH(other_cs) {
1929 MIPSCPU *other_cpu = MIPS_CPU(other_cs);
1930 /* Turn off all VPs except the one executing the dvp. */
1931 if (&other_cpu->env != env) {
1932 mips_vpe_sleep(other_cpu);
1933 }
1934 }
1935 env->CP0_VPControl |= (1 << CP0VPCtl_DIS);
1936 }
1937 return prev;
1938}
1939
1940target_ulong helper_evp(CPUMIPSState *env)
1941{
1942 CPUState *other_cs = first_cpu;
1943 target_ulong prev = env->CP0_VPControl;
1944
1945 if ((env->CP0_VPControl >> CP0VPCtl_DIS) & 1) {
1946 CPU_FOREACH(other_cs) {
1947 MIPSCPU *other_cpu = MIPS_CPU(other_cs);
1948 if ((&other_cpu->env != env) && !mips_vp_is_wfi(other_cpu)) {
1949 /* If the VP is WFI, don't disturb its sleep.
1950 * Otherwise, wake it up. */
1951 mips_vpe_wake(other_cpu);
1952 }
1953 }
1954 env->CP0_VPControl &= ~(1 << CP0VPCtl_DIS);
1955 }
1956 return prev;
1957}
1958#endif /* !CONFIG_USER_ONLY */
1959
f1aa6320 1960#ifndef CONFIG_USER_ONLY
6af0bf9c 1961/* TLB management */
7db13fae 1962static void r4k_mips_tlb_flush_extra (CPUMIPSState *env, int first)
814b9a47
TS
1963{
1964 /* Discard entries from env->tlb[first] onwards. */
ead9360e
TS
1965 while (env->tlb->tlb_in_use > first) {
1966 r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
814b9a47
TS
1967 }
1968}
1969
cd0d45c4
LA
1970static inline uint64_t get_tlb_pfn_from_entrylo(uint64_t entrylo)
1971{
1972#if defined(TARGET_MIPS64)
1973 return extract64(entrylo, 6, 54);
1974#else
1975 return extract64(entrylo, 6, 24) | /* PFN */
1976 (extract64(entrylo, 32, 32) << 24); /* PFNX */
1977#endif
1978}
1979
895c2d04 1980static void r4k_fill_tlb(CPUMIPSState *env, int idx)
6af0bf9c 1981{
c227f099 1982 r4k_tlb_t *tlb;
6af0bf9c
FB
1983
1984 /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
ead9360e 1985 tlb = &env->tlb->mmu.r4k.tlb[idx];
9456c2fb
LA
1986 if (env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) {
1987 tlb->EHINV = 1;
1988 return;
1989 }
1990 tlb->EHINV = 0;
f2e9ebef 1991 tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
d26bc211 1992#if defined(TARGET_MIPS64)
e034e2c3 1993 tlb->VPN &= env->SEGMask;
100ce988 1994#endif
6ec98bd7 1995 tlb->ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
3b1c8be4 1996 tlb->PageMask = env->CP0_PageMask;
6af0bf9c 1997 tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
98c1b82b
PB
1998 tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
1999 tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
2000 tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
2fb58b73
LA
2001 tlb->XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) & 1;
2002 tlb->RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) & 1;
cd0d45c4 2003 tlb->PFN[0] = get_tlb_pfn_from_entrylo(env->CP0_EntryLo0) << 12;
98c1b82b
PB
2004 tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
2005 tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
2006 tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
2fb58b73
LA
2007 tlb->XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) & 1;
2008 tlb->RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) & 1;
cd0d45c4 2009 tlb->PFN[1] = get_tlb_pfn_from_entrylo(env->CP0_EntryLo1) << 12;
6af0bf9c
FB
2010}
2011
9456c2fb
LA
2012void r4k_helper_tlbinv(CPUMIPSState *env)
2013{
2014 int idx;
2015 r4k_tlb_t *tlb;
2d72e7b0 2016 uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
9456c2fb
LA
2017
2018 for (idx = 0; idx < env->tlb->nb_tlb; idx++) {
2019 tlb = &env->tlb->mmu.r4k.tlb[idx];
2020 if (!tlb->G && tlb->ASID == ASID) {
2021 tlb->EHINV = 1;
2022 }
2023 }
2024 cpu_mips_tlb_flush(env, 1);
2025}
2026
2027void r4k_helper_tlbinvf(CPUMIPSState *env)
2028{
2029 int idx;
2030
2031 for (idx = 0; idx < env->tlb->nb_tlb; idx++) {
2032 env->tlb->mmu.r4k.tlb[idx].EHINV = 1;
2033 }
2034 cpu_mips_tlb_flush(env, 1);
2035}
2036
895c2d04 2037void r4k_helper_tlbwi(CPUMIPSState *env)
6af0bf9c 2038{
286d52eb 2039 r4k_tlb_t *tlb;
bbc0d79c 2040 int idx;
286d52eb 2041 target_ulong VPN;
2d72e7b0 2042 uint16_t ASID;
286d52eb 2043 bool G, V0, D0, V1, D1;
bbc0d79c
AJ
2044
2045 idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
286d52eb
AJ
2046 tlb = &env->tlb->mmu.r4k.tlb[idx];
2047 VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
2048#if defined(TARGET_MIPS64)
2049 VPN &= env->SEGMask;
2050#endif
6ec98bd7 2051 ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
286d52eb
AJ
2052 G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
2053 V0 = (env->CP0_EntryLo0 & 2) != 0;
2054 D0 = (env->CP0_EntryLo0 & 4) != 0;
2055 V1 = (env->CP0_EntryLo1 & 2) != 0;
2056 D1 = (env->CP0_EntryLo1 & 4) != 0;
2057
2058 /* Discard cached TLB entries, unless tlbwi is just upgrading access
2059 permissions on the current entry. */
2060 if (tlb->VPN != VPN || tlb->ASID != ASID || tlb->G != G ||
2061 (tlb->V0 && !V0) || (tlb->D0 && !D0) ||
2062 (tlb->V1 && !V1) || (tlb->D1 && !D1)) {
2063 r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
2064 }
814b9a47 2065
bbc0d79c 2066 r4k_invalidate_tlb(env, idx, 0);
895c2d04 2067 r4k_fill_tlb(env, idx);
6af0bf9c
FB
2068}
2069
895c2d04 2070void r4k_helper_tlbwr(CPUMIPSState *env)
6af0bf9c
FB
2071{
2072 int r = cpu_mips_get_random(env);
2073
29929e34 2074 r4k_invalidate_tlb(env, r, 1);
895c2d04 2075 r4k_fill_tlb(env, r);
6af0bf9c
FB
2076}
2077
895c2d04 2078void r4k_helper_tlbp(CPUMIPSState *env)
6af0bf9c 2079{
c227f099 2080 r4k_tlb_t *tlb;
f2e9ebef 2081 target_ulong mask;
6af0bf9c 2082 target_ulong tag;
f2e9ebef 2083 target_ulong VPN;
2d72e7b0 2084 uint16_t ASID;
6af0bf9c
FB
2085 int i;
2086
6ec98bd7 2087 ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
ead9360e
TS
2088 for (i = 0; i < env->tlb->nb_tlb; i++) {
2089 tlb = &env->tlb->mmu.r4k.tlb[i];
f2e9ebef
TS
2090 /* 1k pages are not supported. */
2091 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
2092 tag = env->CP0_EntryHi & ~mask;
2093 VPN = tlb->VPN & ~mask;
bc3e45e1
AJ
2094#if defined(TARGET_MIPS64)
2095 tag &= env->SEGMask;
2096#endif
6af0bf9c 2097 /* Check ASID, virtual page number & size */
9456c2fb 2098 if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag && !tlb->EHINV) {
6af0bf9c 2099 /* TLB match */
9c2149c8 2100 env->CP0_Index = i;
6af0bf9c
FB
2101 break;
2102 }
2103 }
ead9360e 2104 if (i == env->tlb->nb_tlb) {
814b9a47 2105 /* No match. Discard any shadow entries, if any of them match. */
ead9360e 2106 for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
6958549d
AJ
2107 tlb = &env->tlb->mmu.r4k.tlb[i];
2108 /* 1k pages are not supported. */
2109 mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
2110 tag = env->CP0_EntryHi & ~mask;
2111 VPN = tlb->VPN & ~mask;
bc3e45e1
AJ
2112#if defined(TARGET_MIPS64)
2113 tag &= env->SEGMask;
2114#endif
6958549d
AJ
2115 /* Check ASID, virtual page number & size */
2116 if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
29929e34 2117 r4k_mips_tlb_flush_extra (env, i);
6958549d
AJ
2118 break;
2119 }
2120 }
814b9a47 2121
9c2149c8 2122 env->CP0_Index |= 0x80000000;
6af0bf9c
FB
2123 }
2124}
2125
cd0d45c4
LA
2126static inline uint64_t get_entrylo_pfn_from_tlb(uint64_t tlb_pfn)
2127{
2128#if defined(TARGET_MIPS64)
2129 return tlb_pfn << 6;
2130#else
2131 return (extract64(tlb_pfn, 0, 24) << 6) | /* PFN */
2132 (extract64(tlb_pfn, 24, 32) << 32); /* PFNX */
2133#endif
2134}
2135
895c2d04 2136void r4k_helper_tlbr(CPUMIPSState *env)
6af0bf9c 2137{
c227f099 2138 r4k_tlb_t *tlb;
2d72e7b0 2139 uint16_t ASID;
bbc0d79c 2140 int idx;
6af0bf9c 2141
6ec98bd7 2142 ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
bbc0d79c
AJ
2143 idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
2144 tlb = &env->tlb->mmu.r4k.tlb[idx];
4ad40f36
FB
2145
2146 /* If this will change the current ASID, flush qemu's TLB. */
814b9a47
TS
2147 if (ASID != tlb->ASID)
2148 cpu_mips_tlb_flush (env, 1);
2149
ead9360e 2150 r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
4ad40f36 2151
9456c2fb
LA
2152 if (tlb->EHINV) {
2153 env->CP0_EntryHi = 1 << CP0EnHi_EHINV;
2154 env->CP0_PageMask = 0;
2155 env->CP0_EntryLo0 = 0;
2156 env->CP0_EntryLo1 = 0;
2157 } else {
2158 env->CP0_EntryHi = tlb->VPN | tlb->ASID;
2159 env->CP0_PageMask = tlb->PageMask;
2160 env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
284b731a 2161 ((uint64_t)tlb->RI0 << CP0EnLo_RI) |
cd0d45c4
LA
2162 ((uint64_t)tlb->XI0 << CP0EnLo_XI) | (tlb->C0 << 3) |
2163 get_entrylo_pfn_from_tlb(tlb->PFN[0] >> 12);
9456c2fb 2164 env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
284b731a 2165 ((uint64_t)tlb->RI1 << CP0EnLo_RI) |
cd0d45c4
LA
2166 ((uint64_t)tlb->XI1 << CP0EnLo_XI) | (tlb->C1 << 3) |
2167 get_entrylo_pfn_from_tlb(tlb->PFN[1] >> 12);
9456c2fb 2168 }
6af0bf9c 2169}
6af0bf9c 2170
895c2d04 2171void helper_tlbwi(CPUMIPSState *env)
a7812ae4 2172{
895c2d04 2173 env->tlb->helper_tlbwi(env);
a7812ae4
PB
2174}
2175
895c2d04 2176void helper_tlbwr(CPUMIPSState *env)
a7812ae4 2177{
895c2d04 2178 env->tlb->helper_tlbwr(env);
a7812ae4
PB
2179}
2180
895c2d04 2181void helper_tlbp(CPUMIPSState *env)
a7812ae4 2182{
895c2d04 2183 env->tlb->helper_tlbp(env);
a7812ae4
PB
2184}
2185
895c2d04 2186void helper_tlbr(CPUMIPSState *env)
a7812ae4 2187{
895c2d04 2188 env->tlb->helper_tlbr(env);
a7812ae4
PB
2189}
2190
9456c2fb
LA
2191void helper_tlbinv(CPUMIPSState *env)
2192{
2193 env->tlb->helper_tlbinv(env);
2194}
2195
2196void helper_tlbinvf(CPUMIPSState *env)
2197{
2198 env->tlb->helper_tlbinvf(env);
2199}
2200
2b0233ab 2201/* Specials */
895c2d04 2202target_ulong helper_di(CPUMIPSState *env)
2b0233ab 2203{
2796188e
TS
2204 target_ulong t0 = env->CP0_Status;
2205
be24bb4f 2206 env->CP0_Status = t0 & ~(1 << CP0St_IE);
be24bb4f 2207 return t0;
2b0233ab
TS
2208}
2209
895c2d04 2210target_ulong helper_ei(CPUMIPSState *env)
2b0233ab 2211{
2796188e
TS
2212 target_ulong t0 = env->CP0_Status;
2213
be24bb4f 2214 env->CP0_Status = t0 | (1 << CP0St_IE);
be24bb4f 2215 return t0;
2b0233ab
TS
2216}
2217
895c2d04 2218static void debug_pre_eret(CPUMIPSState *env)
6af0bf9c 2219{
8fec2b8c 2220 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
93fcfe39
AL
2221 qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
2222 env->active_tc.PC, env->CP0_EPC);
2223 if (env->CP0_Status & (1 << CP0St_ERL))
2224 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
2225 if (env->hflags & MIPS_HFLAG_DM)
2226 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
2227 qemu_log("\n");
2228 }
f41c52f1
TS
2229}
2230
895c2d04 2231static void debug_post_eret(CPUMIPSState *env)
f41c52f1 2232{
a47dddd7
AF
2233 MIPSCPU *cpu = mips_env_get_cpu(env);
2234
8fec2b8c 2235 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
93fcfe39
AL
2236 qemu_log(" => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
2237 env->active_tc.PC, env->CP0_EPC);
2238 if (env->CP0_Status & (1 << CP0St_ERL))
2239 qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
2240 if (env->hflags & MIPS_HFLAG_DM)
2241 qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
2242 switch (env->hflags & MIPS_HFLAG_KSU) {
2243 case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
2244 case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
2245 case MIPS_HFLAG_KM: qemu_log("\n"); break;
a47dddd7
AF
2246 default:
2247 cpu_abort(CPU(cpu), "Invalid MMU mode!\n");
2248 break;
93fcfe39 2249 }
623a930e 2250 }
6af0bf9c
FB
2251}
2252
895c2d04 2253static void set_pc(CPUMIPSState *env, target_ulong error_pc)
32188a03
NF
2254{
2255 env->active_tc.PC = error_pc & ~(target_ulong)1;
2256 if (error_pc & 1) {
2257 env->hflags |= MIPS_HFLAG_M16;
2258 } else {
2259 env->hflags &= ~(MIPS_HFLAG_M16);
2260 }
2261}
2262
ce9782f4 2263static inline void exception_return(CPUMIPSState *env)
2b0233ab 2264{
895c2d04 2265 debug_pre_eret(env);
2b0233ab 2266 if (env->CP0_Status & (1 << CP0St_ERL)) {
895c2d04 2267 set_pc(env, env->CP0_ErrorEPC);
2b0233ab
TS
2268 env->CP0_Status &= ~(1 << CP0St_ERL);
2269 } else {
895c2d04 2270 set_pc(env, env->CP0_EPC);
2b0233ab
TS
2271 env->CP0_Status &= ~(1 << CP0St_EXL);
2272 }
2273 compute_hflags(env);
895c2d04 2274 debug_post_eret(env);
ce9782f4
LA
2275}
2276
2277void helper_eret(CPUMIPSState *env)
2278{
2279 exception_return(env);
5499b6ff 2280 env->lladdr = 1;
2b0233ab
TS
2281}
2282
ce9782f4
LA
2283void helper_eretnc(CPUMIPSState *env)
2284{
2285 exception_return(env);
2286}
2287
895c2d04 2288void helper_deret(CPUMIPSState *env)
2b0233ab 2289{
895c2d04
BS
2290 debug_pre_eret(env);
2291 set_pc(env, env->CP0_DEPC);
32188a03 2292
fe87c2b3 2293 env->hflags &= ~MIPS_HFLAG_DM;
2b0233ab 2294 compute_hflags(env);
895c2d04 2295 debug_post_eret(env);
2b0233ab 2296}
0eaef5aa 2297#endif /* !CONFIG_USER_ONLY */
2b0233ab 2298
d96391c1 2299static inline void check_hwrena(CPUMIPSState *env, int reg, uintptr_t pc)
2b0233ab 2300{
b00c7218
YK
2301 if ((env->hflags & MIPS_HFLAG_CP0) || (env->CP0_HWREna & (1 << reg))) {
2302 return;
2303 }
d96391c1 2304 do_raise_exception(env, EXCP_RI, pc);
b00c7218 2305}
be24bb4f 2306
b00c7218
YK
2307target_ulong helper_rdhwr_cpunum(CPUMIPSState *env)
2308{
d96391c1 2309 check_hwrena(env, 0, GETPC());
b00c7218 2310 return env->CP0_EBase & 0x3ff;
2b0233ab
TS
2311}
2312
895c2d04 2313target_ulong helper_rdhwr_synci_step(CPUMIPSState *env)
2b0233ab 2314{
d96391c1 2315 check_hwrena(env, 1, GETPC());
b00c7218 2316 return env->SYNCI_Step;
2b0233ab
TS
2317}
2318
895c2d04 2319target_ulong helper_rdhwr_cc(CPUMIPSState *env)
2b0233ab 2320{
d96391c1 2321 check_hwrena(env, 2, GETPC());
cdfcad78 2322#ifdef CONFIG_USER_ONLY
b00c7218 2323 return env->CP0_Count;
cdfcad78 2324#else
b00c7218 2325 return (int32_t)cpu_mips_get_count(env);
cdfcad78 2326#endif
2b0233ab
TS
2327}
2328
895c2d04 2329target_ulong helper_rdhwr_ccres(CPUMIPSState *env)
2b0233ab 2330{
d96391c1 2331 check_hwrena(env, 3, GETPC());
b00c7218
YK
2332 return env->CCRes;
2333}
be24bb4f 2334
b00c7218
YK
2335target_ulong helper_rdhwr_performance(CPUMIPSState *env)
2336{
d96391c1 2337 check_hwrena(env, 4, GETPC());
b00c7218
YK
2338 return env->CP0_Performance0;
2339}
2340
2341target_ulong helper_rdhwr_xnp(CPUMIPSState *env)
2342{
d96391c1 2343 check_hwrena(env, 5, GETPC());
b00c7218 2344 return (env->CP0_Config5 >> CP0C5_XNP) & 1;
2b0233ab
TS
2345}
2346
895c2d04 2347void helper_pmon(CPUMIPSState *env, int function)
6af0bf9c
FB
2348{
2349 function /= 2;
2350 switch (function) {
2351 case 2: /* TODO: char inbyte(int waitflag); */
b5dc7732
TS
2352 if (env->active_tc.gpr[4] == 0)
2353 env->active_tc.gpr[2] = -1;
6af0bf9c
FB
2354 /* Fall through */
2355 case 11: /* TODO: char inbyte (void); */
b5dc7732 2356 env->active_tc.gpr[2] = -1;
6af0bf9c
FB
2357 break;
2358 case 3:
2359 case 12:
b5dc7732 2360 printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
6af0bf9c
FB
2361 break;
2362 case 17:
2363 break;
2364 case 158:
2365 {
b69e48a8 2366 unsigned char *fmt = (void *)(uintptr_t)env->active_tc.gpr[4];
6af0bf9c
FB
2367 printf("%s", fmt);
2368 }
2369 break;
2370 }
2371}
e37e863f 2372
895c2d04 2373void helper_wait(CPUMIPSState *env)
08ba7963 2374{
259186a7
AF
2375 CPUState *cs = CPU(mips_env_get_cpu(env));
2376
2377 cs->halted = 1;
d8ed887b 2378 cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
9c708c7f
PD
2379 /* Last instruction in the block, PC was updated before
2380 - no need to recover PC and icount */
2381 raise_exception(env, EXCP_HLT);
08ba7963
TS
2382}
2383
5fafdf24 2384#if !defined(CONFIG_USER_ONLY)
e37e863f 2385
93e22326 2386void mips_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
b35399bb
SS
2387 MMUAccessType access_type,
2388 int mmu_idx, uintptr_t retaddr)
4ad40f36 2389{
93e22326
PB
2390 MIPSCPU *cpu = MIPS_CPU(cs);
2391 CPUMIPSState *env = &cpu->env;
aea14095
LA
2392 int error_code = 0;
2393 int excp;
93e22326 2394
4ad40f36 2395 env->CP0_BadVAddr = addr;
aea14095
LA
2396
2397 if (access_type == MMU_DATA_STORE) {
2398 excp = EXCP_AdES;
2399 } else {
2400 excp = EXCP_AdEL;
2401 if (access_type == MMU_INST_FETCH) {
2402 error_code |= EXCP_INST_NOTAVAIL;
2403 }
2404 }
2405
2406 do_raise_exception_err(env, excp, error_code, retaddr);
4ad40f36
FB
2407}
2408
b35399bb
SS
2409void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type,
2410 int mmu_idx, uintptr_t retaddr)
e37e863f 2411{
e37e863f
FB
2412 int ret;
2413
b35399bb 2414 ret = mips_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx);
e37e863f 2415 if (ret) {
d5a11fef
AF
2416 MIPSCPU *cpu = MIPS_CPU(cs);
2417 CPUMIPSState *env = &cpu->env;
2418
27103424 2419 do_raise_exception_err(env, cs->exception_index,
5f7319cd 2420 env->error_code, retaddr);
e37e863f 2421 }
e37e863f
FB
2422}
2423
c658b94f
AF
2424void mips_cpu_unassigned_access(CPUState *cs, hwaddr addr,
2425 bool is_write, bool is_exec, int unused,
2426 unsigned size)
647de6ca 2427{
c658b94f
AF
2428 MIPSCPU *cpu = MIPS_CPU(cs);
2429 CPUMIPSState *env = &cpu->env;
2430
eddedd54
JH
2431 /*
2432 * Raising an exception with KVM enabled will crash because it won't be from
2433 * the main execution loop so the longjmp won't have a matching setjmp.
2434 * Until we can trigger a bus error exception through KVM lets just ignore
2435 * the access.
2436 */
2437 if (kvm_enabled()) {
2438 return;
2439 }
2440
c658b94f 2441 if (is_exec) {
9c708c7f 2442 raise_exception(env, EXCP_IBE);
c658b94f 2443 } else {
9c708c7f 2444 raise_exception(env, EXCP_DBE);
c658b94f 2445 }
647de6ca 2446}
f1aa6320 2447#endif /* !CONFIG_USER_ONLY */
fd4a04eb
TS
2448
2449/* Complex FPU operations which may need stack space. */
2450
f090c9d4
PB
2451#define FLOAT_TWO32 make_float32(1 << 30)
2452#define FLOAT_TWO64 make_float64(1ULL << 62)
87552089 2453
05993cd0
AJ
2454#define FP_TO_INT32_OVERFLOW 0x7fffffff
2455#define FP_TO_INT64_OVERFLOW 0x7fffffffffffffffULL
8dfdb87c 2456
fd4a04eb 2457/* convert MIPS rounding mode in FCR31 to IEEE library */
b7651e95 2458unsigned int ieee_rm[] = {
fd4a04eb
TS
2459 float_round_nearest_even,
2460 float_round_to_zero,
2461 float_round_up,
2462 float_round_down
2463};
2464
895c2d04 2465target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg)
fd4a04eb 2466{
736d120a 2467 target_ulong arg1 = 0;
6c5c1e20 2468
ead9360e
TS
2469 switch (reg) {
2470 case 0:
d9bea114 2471 arg1 = (int32_t)env->active_fpu.fcr0;
ead9360e 2472 break;
736d120a
PJ
2473 case 1:
2474 /* UFR Support - Read Status FR */
2475 if (env->active_fpu.fcr0 & (1 << FCR0_UFRP)) {
2476 if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
2477 arg1 = (int32_t)
2478 ((env->CP0_Status & (1 << CP0St_FR)) >> CP0St_FR);
2479 } else {
9c708c7f 2480 do_raise_exception(env, EXCP_RI, GETPC());
736d120a
PJ
2481 }
2482 }
2483 break;
7c979afd
LA
2484 case 5:
2485 /* FRE Support - read Config5.FRE bit */
2486 if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) {
2487 if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
2488 arg1 = (env->CP0_Config5 >> CP0C5_FRE) & 1;
2489 } else {
2490 helper_raise_exception(env, EXCP_RI);
2491 }
2492 }
2493 break;
ead9360e 2494 case 25:
d9bea114 2495 arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
ead9360e
TS
2496 break;
2497 case 26:
d9bea114 2498 arg1 = env->active_fpu.fcr31 & 0x0003f07c;
ead9360e
TS
2499 break;
2500 case 28:
d9bea114 2501 arg1 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4);
ead9360e
TS
2502 break;
2503 default:
d9bea114 2504 arg1 = (int32_t)env->active_fpu.fcr31;
ead9360e
TS
2505 break;
2506 }
be24bb4f 2507
d9bea114 2508 return arg1;
ead9360e
TS
2509}
2510
736d120a 2511void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt)
ead9360e 2512{
736d120a
PJ
2513 switch (fs) {
2514 case 1:
2515 /* UFR Alias - Reset Status FR */
2516 if (!((env->active_fpu.fcr0 & (1 << FCR0_UFRP)) && (rt == 0))) {
2517 return;
2518 }
2519 if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
2520 env->CP0_Status &= ~(1 << CP0St_FR);
2521 compute_hflags(env);
2522 } else {
9c708c7f 2523 do_raise_exception(env, EXCP_RI, GETPC());
736d120a
PJ
2524 }
2525 break;
2526 case 4:
2527 /* UNFR Alias - Set Status FR */
2528 if (!((env->active_fpu.fcr0 & (1 << FCR0_UFRP)) && (rt == 0))) {
2529 return;
2530 }
2531 if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
2532 env->CP0_Status |= (1 << CP0St_FR);
2533 compute_hflags(env);
2534 } else {
9c708c7f 2535 do_raise_exception(env, EXCP_RI, GETPC());
736d120a
PJ
2536 }
2537 break;
7c979afd
LA
2538 case 5:
2539 /* FRE Support - clear Config5.FRE bit */
2540 if (!((env->active_fpu.fcr0 & (1 << FCR0_FREP)) && (rt == 0))) {
2541 return;
2542 }
2543 if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
2544 env->CP0_Config5 &= ~(1 << CP0C5_FRE);
2545 compute_hflags(env);
2546 } else {
2547 helper_raise_exception(env, EXCP_RI);
2548 }
2549 break;
2550 case 6:
2551 /* FRE Support - set Config5.FRE bit */
2552 if (!((env->active_fpu.fcr0 & (1 << FCR0_FREP)) && (rt == 0))) {
2553 return;
2554 }
2555 if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
2556 env->CP0_Config5 |= (1 << CP0C5_FRE);
2557 compute_hflags(env);
2558 } else {
2559 helper_raise_exception(env, EXCP_RI);
2560 }
2561 break;
fd4a04eb 2562 case 25:
ba801af4 2563 if ((env->insn_flags & ISA_MIPS32R6) || (arg1 & 0xffffff00)) {
fd4a04eb 2564 return;
ba801af4 2565 }
d9bea114
AJ
2566 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
2567 ((arg1 & 0x1) << 23);
fd4a04eb
TS
2568 break;
2569 case 26:
d9bea114 2570 if (arg1 & 0x007c0000)
fd4a04eb 2571 return;
d9bea114 2572 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (arg1 & 0x0003f07c);
fd4a04eb
TS
2573 break;
2574 case 28:
d9bea114 2575 if (arg1 & 0x007c0000)
fd4a04eb 2576 return;
d9bea114
AJ
2577 env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (arg1 & 0x00000f83) |
2578 ((arg1 & 0x4) << 22);
fd4a04eb
TS
2579 break;
2580 case 31:
599bc5e8
AM
2581 env->active_fpu.fcr31 = (arg1 & env->active_fpu.fcr31_rw_bitmask) |
2582 (env->active_fpu.fcr31 & ~(env->active_fpu.fcr31_rw_bitmask));
fd4a04eb
TS
2583 break;
2584 default:
2585 return;
2586 }
599bc5e8 2587 restore_fp_status(env);
f01be154
TS
2588 set_float_exception_flags(0, &env->active_fpu.fp_status);
2589 if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31))
5f7319cd 2590 do_raise_exception(env, EXCP_FPE, GETPC());
fd4a04eb
TS
2591}
2592
b7651e95 2593int ieee_ex_to_mips(int xcpt)
fd4a04eb 2594{
353ebb7a
AJ
2595 int ret = 0;
2596 if (xcpt) {
2597 if (xcpt & float_flag_invalid) {
2598 ret |= FP_INVALID;
2599 }
2600 if (xcpt & float_flag_overflow) {
2601 ret |= FP_OVERFLOW;
2602 }
2603 if (xcpt & float_flag_underflow) {
2604 ret |= FP_UNDERFLOW;
2605 }
2606 if (xcpt & float_flag_divbyzero) {
2607 ret |= FP_DIV0;
2608 }
2609 if (xcpt & float_flag_inexact) {
2610 ret |= FP_INEXACT;
2611 }
2612 }
2613 return ret;
fd4a04eb
TS
2614}
2615
5f7319cd 2616static inline void update_fcr31(CPUMIPSState *env, uintptr_t pc)
fd4a04eb 2617{
f01be154 2618 int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
fd4a04eb 2619
f01be154 2620 SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
4a587b2c
AJ
2621
2622 if (tmp) {
2623 set_float_exception_flags(0, &env->active_fpu.fp_status);
2624
2625 if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp) {
5f7319cd 2626 do_raise_exception(env, EXCP_FPE, pc);
4a587b2c
AJ
2627 } else {
2628 UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
2629 }
2630 }
fd4a04eb
TS
2631}
2632
a16336e4
TS
2633/* Float support.
2634 Single precition routines have a "s" suffix, double precision a
2635 "d" suffix, 32bit integer "w", 64bit integer "l", paired single "ps",
2636 paired single lower "pl", paired single upper "pu". */
2637
a16336e4 2638/* unary operations, modifying fp status */
895c2d04 2639uint64_t helper_float_sqrt_d(CPUMIPSState *env, uint64_t fdt0)
b6d96bed 2640{
5dbe90bb 2641 fdt0 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
5f7319cd 2642 update_fcr31(env, GETPC());
5dbe90bb 2643 return fdt0;
b6d96bed
TS
2644}
2645
895c2d04 2646uint32_t helper_float_sqrt_s(CPUMIPSState *env, uint32_t fst0)
b6d96bed 2647{
5dbe90bb 2648 fst0 = float32_sqrt(fst0, &env->active_fpu.fp_status);
5f7319cd 2649 update_fcr31(env, GETPC());
5dbe90bb 2650 return fst0;
b6d96bed 2651}
a16336e4 2652
895c2d04 2653uint64_t helper_float_cvtd_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2654{
b6d96bed
TS
2655 uint64_t fdt2;
2656
f01be154 2657 fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
af39bc8c 2658 fdt2 = float64_maybe_silence_nan(fdt2, &env->active_fpu.fp_status);
5f7319cd 2659 update_fcr31(env, GETPC());
b6d96bed 2660 return fdt2;
fd4a04eb 2661}
b6d96bed 2662
895c2d04 2663uint64_t helper_float_cvtd_w(CPUMIPSState *env, uint32_t wt0)
fd4a04eb 2664{
b6d96bed
TS
2665 uint64_t fdt2;
2666
f01be154 2667 fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
5f7319cd 2668 update_fcr31(env, GETPC());
b6d96bed 2669 return fdt2;
fd4a04eb 2670}
b6d96bed 2671
895c2d04 2672uint64_t helper_float_cvtd_l(CPUMIPSState *env, uint64_t dt0)
fd4a04eb 2673{
b6d96bed
TS
2674 uint64_t fdt2;
2675
f01be154 2676 fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
5f7319cd 2677 update_fcr31(env, GETPC());
b6d96bed 2678 return fdt2;
fd4a04eb 2679}
b6d96bed 2680
87552089 2681uint64_t helper_float_cvt_l_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2682{
b6d96bed
TS
2683 uint64_t dt2;
2684
f01be154 2685 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2686 if (get_float_exception_flags(&env->active_fpu.fp_status)
2687 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2688 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2689 }
5f7319cd 2690 update_fcr31(env, GETPC());
b6d96bed 2691 return dt2;
fd4a04eb 2692}
b6d96bed 2693
87552089 2694uint64_t helper_float_cvt_l_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2695{
b6d96bed
TS
2696 uint64_t dt2;
2697
f01be154 2698 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2699 if (get_float_exception_flags(&env->active_fpu.fp_status)
2700 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2701 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2702 }
5f7319cd 2703 update_fcr31(env, GETPC());
b6d96bed 2704 return dt2;
fd4a04eb
TS
2705}
2706
895c2d04 2707uint64_t helper_float_cvtps_pw(CPUMIPSState *env, uint64_t dt0)
fd4a04eb 2708{
b6d96bed
TS
2709 uint32_t fst2;
2710 uint32_t fsth2;
2711
f01be154
TS
2712 fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2713 fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status);
5f7319cd 2714 update_fcr31(env, GETPC());
b6d96bed 2715 return ((uint64_t)fsth2 << 32) | fst2;
fd4a04eb 2716}
b6d96bed 2717
895c2d04 2718uint64_t helper_float_cvtpw_ps(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2719{
b6d96bed
TS
2720 uint32_t wt2;
2721 uint32_t wth2;
5dbe90bb 2722 int excp, excph;
b6d96bed 2723
f01be154 2724 wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
5dbe90bb
AJ
2725 excp = get_float_exception_flags(&env->active_fpu.fp_status);
2726 if (excp & (float_flag_overflow | float_flag_invalid)) {
05993cd0 2727 wt2 = FP_TO_INT32_OVERFLOW;
5dbe90bb
AJ
2728 }
2729
2730 set_float_exception_flags(0, &env->active_fpu.fp_status);
2731 wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status);
2732 excph = get_float_exception_flags(&env->active_fpu.fp_status);
2733 if (excph & (float_flag_overflow | float_flag_invalid)) {
05993cd0 2734 wth2 = FP_TO_INT32_OVERFLOW;
b6d96bed 2735 }
5dbe90bb
AJ
2736
2737 set_float_exception_flags(excp | excph, &env->active_fpu.fp_status);
5f7319cd 2738 update_fcr31(env, GETPC());
5dbe90bb 2739
b6d96bed 2740 return ((uint64_t)wth2 << 32) | wt2;
fd4a04eb 2741}
b6d96bed 2742
895c2d04 2743uint32_t helper_float_cvts_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2744{
b6d96bed
TS
2745 uint32_t fst2;
2746
f01be154 2747 fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
af39bc8c 2748 fst2 = float32_maybe_silence_nan(fst2, &env->active_fpu.fp_status);
5f7319cd 2749 update_fcr31(env, GETPC());
b6d96bed 2750 return fst2;
fd4a04eb 2751}
b6d96bed 2752
895c2d04 2753uint32_t helper_float_cvts_w(CPUMIPSState *env, uint32_t wt0)
fd4a04eb 2754{
b6d96bed
TS
2755 uint32_t fst2;
2756
f01be154 2757 fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status);
5f7319cd 2758 update_fcr31(env, GETPC());
b6d96bed 2759 return fst2;
fd4a04eb 2760}
b6d96bed 2761
895c2d04 2762uint32_t helper_float_cvts_l(CPUMIPSState *env, uint64_t dt0)
fd4a04eb 2763{
b6d96bed
TS
2764 uint32_t fst2;
2765
f01be154 2766 fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status);
5f7319cd 2767 update_fcr31(env, GETPC());
b6d96bed 2768 return fst2;
fd4a04eb 2769}
b6d96bed 2770
895c2d04 2771uint32_t helper_float_cvts_pl(CPUMIPSState *env, uint32_t wt0)
fd4a04eb 2772{
b6d96bed
TS
2773 uint32_t wt2;
2774
b6d96bed 2775 wt2 = wt0;
5f7319cd 2776 update_fcr31(env, GETPC());
b6d96bed 2777 return wt2;
fd4a04eb 2778}
b6d96bed 2779
895c2d04 2780uint32_t helper_float_cvts_pu(CPUMIPSState *env, uint32_t wth0)
fd4a04eb 2781{
b6d96bed
TS
2782 uint32_t wt2;
2783
b6d96bed 2784 wt2 = wth0;
5f7319cd 2785 update_fcr31(env, GETPC());
b6d96bed 2786 return wt2;
fd4a04eb 2787}
b6d96bed 2788
87552089 2789uint32_t helper_float_cvt_w_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2790{
b6d96bed
TS
2791 uint32_t wt2;
2792
f01be154 2793 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2794 if (get_float_exception_flags(&env->active_fpu.fp_status)
2795 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2796 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2797 }
2b09f94c 2798 update_fcr31(env, GETPC());
b6d96bed 2799 return wt2;
fd4a04eb 2800}
b6d96bed 2801
87552089 2802uint32_t helper_float_cvt_w_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2803{
b6d96bed
TS
2804 uint32_t wt2;
2805
f01be154 2806 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2807 if (get_float_exception_flags(&env->active_fpu.fp_status)
2808 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2809 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2810 }
5f7319cd 2811 update_fcr31(env, GETPC());
b6d96bed 2812 return wt2;
fd4a04eb
TS
2813}
2814
87552089 2815uint64_t helper_float_round_l_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2816{
b6d96bed
TS
2817 uint64_t dt2;
2818
f01be154
TS
2819 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2820 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
e320d05a 2821 restore_rounding_mode(env);
4cc2e5f9
AJ
2822 if (get_float_exception_flags(&env->active_fpu.fp_status)
2823 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2824 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2825 }
5f7319cd 2826 update_fcr31(env, GETPC());
b6d96bed 2827 return dt2;
fd4a04eb 2828}
b6d96bed 2829
87552089 2830uint64_t helper_float_round_l_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2831{
b6d96bed
TS
2832 uint64_t dt2;
2833
f01be154
TS
2834 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2835 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
e320d05a 2836 restore_rounding_mode(env);
4cc2e5f9
AJ
2837 if (get_float_exception_flags(&env->active_fpu.fp_status)
2838 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2839 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2840 }
5f7319cd 2841 update_fcr31(env, GETPC());
b6d96bed 2842 return dt2;
fd4a04eb 2843}
b6d96bed 2844
87552089 2845uint32_t helper_float_round_w_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2846{
b6d96bed
TS
2847 uint32_t wt2;
2848
f01be154
TS
2849 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2850 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
e320d05a 2851 restore_rounding_mode(env);
4cc2e5f9
AJ
2852 if (get_float_exception_flags(&env->active_fpu.fp_status)
2853 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2854 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2855 }
5f7319cd 2856 update_fcr31(env, GETPC());
b6d96bed 2857 return wt2;
fd4a04eb 2858}
b6d96bed 2859
87552089 2860uint32_t helper_float_round_w_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2861{
b6d96bed
TS
2862 uint32_t wt2;
2863
f01be154
TS
2864 set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2865 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
e320d05a 2866 restore_rounding_mode(env);
4cc2e5f9
AJ
2867 if (get_float_exception_flags(&env->active_fpu.fp_status)
2868 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2869 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2870 }
5f7319cd 2871 update_fcr31(env, GETPC());
b6d96bed 2872 return wt2;
fd4a04eb
TS
2873}
2874
87552089 2875uint64_t helper_float_trunc_l_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2876{
b6d96bed
TS
2877 uint64_t dt2;
2878
f01be154 2879 dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2880 if (get_float_exception_flags(&env->active_fpu.fp_status)
2881 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2882 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2883 }
5f7319cd 2884 update_fcr31(env, GETPC());
b6d96bed 2885 return dt2;
fd4a04eb 2886}
b6d96bed 2887
87552089 2888uint64_t helper_float_trunc_l_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2889{
b6d96bed
TS
2890 uint64_t dt2;
2891
f01be154 2892 dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2893 if (get_float_exception_flags(&env->active_fpu.fp_status)
2894 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2895 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2896 }
5f7319cd 2897 update_fcr31(env, GETPC());
b6d96bed 2898 return dt2;
fd4a04eb 2899}
b6d96bed 2900
87552089 2901uint32_t helper_float_trunc_w_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2902{
b6d96bed
TS
2903 uint32_t wt2;
2904
f01be154 2905 wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2906 if (get_float_exception_flags(&env->active_fpu.fp_status)
2907 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2908 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2909 }
5f7319cd 2910 update_fcr31(env, GETPC());
b6d96bed 2911 return wt2;
fd4a04eb 2912}
b6d96bed 2913
87552089 2914uint32_t helper_float_trunc_w_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2915{
b6d96bed
TS
2916 uint32_t wt2;
2917
f01be154 2918 wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
4cc2e5f9
AJ
2919 if (get_float_exception_flags(&env->active_fpu.fp_status)
2920 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2921 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2922 }
5f7319cd 2923 update_fcr31(env, GETPC());
b6d96bed 2924 return wt2;
fd4a04eb
TS
2925}
2926
87552089 2927uint64_t helper_float_ceil_l_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2928{
b6d96bed
TS
2929 uint64_t dt2;
2930
f01be154
TS
2931 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2932 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
e320d05a 2933 restore_rounding_mode(env);
4cc2e5f9
AJ
2934 if (get_float_exception_flags(&env->active_fpu.fp_status)
2935 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2936 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2937 }
5f7319cd 2938 update_fcr31(env, GETPC());
b6d96bed 2939 return dt2;
fd4a04eb 2940}
b6d96bed 2941
87552089 2942uint64_t helper_float_ceil_l_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2943{
b6d96bed
TS
2944 uint64_t dt2;
2945
f01be154
TS
2946 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2947 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
e320d05a 2948 restore_rounding_mode(env);
4cc2e5f9
AJ
2949 if (get_float_exception_flags(&env->active_fpu.fp_status)
2950 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2951 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2952 }
5f7319cd 2953 update_fcr31(env, GETPC());
b6d96bed 2954 return dt2;
fd4a04eb 2955}
b6d96bed 2956
87552089 2957uint32_t helper_float_ceil_w_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2958{
b6d96bed
TS
2959 uint32_t wt2;
2960
f01be154
TS
2961 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2962 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
e320d05a 2963 restore_rounding_mode(env);
4cc2e5f9
AJ
2964 if (get_float_exception_flags(&env->active_fpu.fp_status)
2965 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2966 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2967 }
5f7319cd 2968 update_fcr31(env, GETPC());
b6d96bed 2969 return wt2;
fd4a04eb 2970}
b6d96bed 2971
87552089 2972uint32_t helper_float_ceil_w_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 2973{
b6d96bed
TS
2974 uint32_t wt2;
2975
f01be154
TS
2976 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2977 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
e320d05a 2978 restore_rounding_mode(env);
4cc2e5f9
AJ
2979 if (get_float_exception_flags(&env->active_fpu.fp_status)
2980 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2981 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 2982 }
5f7319cd 2983 update_fcr31(env, GETPC());
b6d96bed 2984 return wt2;
fd4a04eb
TS
2985}
2986
87552089 2987uint64_t helper_float_floor_l_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 2988{
b6d96bed
TS
2989 uint64_t dt2;
2990
f01be154
TS
2991 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2992 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
e320d05a 2993 restore_rounding_mode(env);
4cc2e5f9
AJ
2994 if (get_float_exception_flags(&env->active_fpu.fp_status)
2995 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 2996 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 2997 }
5f7319cd 2998 update_fcr31(env, GETPC());
b6d96bed 2999 return dt2;
fd4a04eb 3000}
b6d96bed 3001
87552089 3002uint64_t helper_float_floor_l_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 3003{
b6d96bed
TS
3004 uint64_t dt2;
3005
f01be154
TS
3006 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3007 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
e320d05a 3008 restore_rounding_mode(env);
4cc2e5f9
AJ
3009 if (get_float_exception_flags(&env->active_fpu.fp_status)
3010 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 3011 dt2 = FP_TO_INT64_OVERFLOW;
4cc2e5f9 3012 }
5f7319cd 3013 update_fcr31(env, GETPC());
b6d96bed 3014 return dt2;
fd4a04eb 3015}
b6d96bed 3016
87552089 3017uint32_t helper_float_floor_w_d(CPUMIPSState *env, uint64_t fdt0)
fd4a04eb 3018{
b6d96bed
TS
3019 uint32_t wt2;
3020
f01be154
TS
3021 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3022 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
e320d05a 3023 restore_rounding_mode(env);
4cc2e5f9
AJ
3024 if (get_float_exception_flags(&env->active_fpu.fp_status)
3025 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 3026 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 3027 }
5f7319cd 3028 update_fcr31(env, GETPC());
b6d96bed 3029 return wt2;
fd4a04eb 3030}
b6d96bed 3031
87552089 3032uint32_t helper_float_floor_w_s(CPUMIPSState *env, uint32_t fst0)
fd4a04eb 3033{
b6d96bed
TS
3034 uint32_t wt2;
3035
f01be154
TS
3036 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3037 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
e320d05a 3038 restore_rounding_mode(env);
4cc2e5f9
AJ
3039 if (get_float_exception_flags(&env->active_fpu.fp_status)
3040 & (float_flag_invalid | float_flag_overflow)) {
05993cd0 3041 wt2 = FP_TO_INT32_OVERFLOW;
4cc2e5f9 3042 }
5f7319cd 3043 update_fcr31(env, GETPC());
b6d96bed 3044 return wt2;
fd4a04eb
TS
3045}
3046
87552089
AM
3047uint64_t helper_float_cvt_2008_l_d(CPUMIPSState *env, uint64_t fdt0)
3048{
3049 uint64_t dt2;
3050
3051 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3052 if (get_float_exception_flags(&env->active_fpu.fp_status)
3053 & float_flag_invalid) {
3054 if (float64_is_any_nan(fdt0)) {
3055 dt2 = 0;
3056 }
3057 }
3058 update_fcr31(env, GETPC());
3059 return dt2;
3060}
3061
3062uint64_t helper_float_cvt_2008_l_s(CPUMIPSState *env, uint32_t fst0)
3063{
3064 uint64_t dt2;
3065
3066 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3067 if (get_float_exception_flags(&env->active_fpu.fp_status)
3068 & float_flag_invalid) {
3069 if (float32_is_any_nan(fst0)) {
3070 dt2 = 0;
3071 }
3072 }
3073 update_fcr31(env, GETPC());
3074 return dt2;
3075}
3076
3077uint32_t helper_float_cvt_2008_w_d(CPUMIPSState *env, uint64_t fdt0)
3078{
3079 uint32_t wt2;
3080
3081 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3082 if (get_float_exception_flags(&env->active_fpu.fp_status)
3083 & float_flag_invalid) {
3084 if (float64_is_any_nan(fdt0)) {
3085 wt2 = 0;
3086 }
3087 }
3088 update_fcr31(env, GETPC());
3089 return wt2;
3090}
3091
3092uint32_t helper_float_cvt_2008_w_s(CPUMIPSState *env, uint32_t fst0)
3093{
3094 uint32_t wt2;
3095
3096 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3097 if (get_float_exception_flags(&env->active_fpu.fp_status)
3098 & float_flag_invalid) {
3099 if (float32_is_any_nan(fst0)) {
3100 wt2 = 0;
3101 }
3102 }
3103 update_fcr31(env, GETPC());
3104 return wt2;
3105}
3106
3107uint64_t helper_float_round_2008_l_d(CPUMIPSState *env, uint64_t fdt0)
3108{
3109 uint64_t dt2;
3110
3111 set_float_rounding_mode(float_round_nearest_even,
3112 &env->active_fpu.fp_status);
3113 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3114 restore_rounding_mode(env);
3115 if (get_float_exception_flags(&env->active_fpu.fp_status)
3116 & float_flag_invalid) {
3117 if (float64_is_any_nan(fdt0)) {
3118 dt2 = 0;
3119 }
3120 }
3121 update_fcr31(env, GETPC());
3122 return dt2;
3123}
3124
3125uint64_t helper_float_round_2008_l_s(CPUMIPSState *env, uint32_t fst0)
3126{
3127 uint64_t dt2;
3128
3129 set_float_rounding_mode(float_round_nearest_even,
3130 &env->active_fpu.fp_status);
3131 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3132 restore_rounding_mode(env);
3133 if (get_float_exception_flags(&env->active_fpu.fp_status)
3134 & float_flag_invalid) {
3135 if (float32_is_any_nan(fst0)) {
3136 dt2 = 0;
3137 }
3138 }
3139 update_fcr31(env, GETPC());
3140 return dt2;
3141}
3142
3143uint32_t helper_float_round_2008_w_d(CPUMIPSState *env, uint64_t fdt0)
3144{
3145 uint32_t wt2;
3146
3147 set_float_rounding_mode(float_round_nearest_even,
3148 &env->active_fpu.fp_status);
3149 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3150 restore_rounding_mode(env);
3151 if (get_float_exception_flags(&env->active_fpu.fp_status)
3152 & float_flag_invalid) {
3153 if (float64_is_any_nan(fdt0)) {
3154 wt2 = 0;
3155 }
3156 }
3157 update_fcr31(env, GETPC());
3158 return wt2;
3159}
3160
3161uint32_t helper_float_round_2008_w_s(CPUMIPSState *env, uint32_t fst0)
3162{
3163 uint32_t wt2;
3164
3165 set_float_rounding_mode(float_round_nearest_even,
3166 &env->active_fpu.fp_status);
3167 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3168 restore_rounding_mode(env);
3169 if (get_float_exception_flags(&env->active_fpu.fp_status)
3170 & float_flag_invalid) {
3171 if (float32_is_any_nan(fst0)) {
3172 wt2 = 0;
3173 }
3174 }
3175 update_fcr31(env, GETPC());
3176 return wt2;
3177}
3178
3179uint64_t helper_float_trunc_2008_l_d(CPUMIPSState *env, uint64_t fdt0)
3180{
3181 uint64_t dt2;
3182
3183 dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
3184 if (get_float_exception_flags(&env->active_fpu.fp_status)
3185 & float_flag_invalid) {
3186 if (float64_is_any_nan(fdt0)) {
3187 dt2 = 0;
3188 }
3189 }
3190 update_fcr31(env, GETPC());
3191 return dt2;
3192}
3193
3194uint64_t helper_float_trunc_2008_l_s(CPUMIPSState *env, uint32_t fst0)
3195{
3196 uint64_t dt2;
3197
3198 dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
3199 if (get_float_exception_flags(&env->active_fpu.fp_status)
3200 & float_flag_invalid) {
3201 if (float32_is_any_nan(fst0)) {
3202 dt2 = 0;
3203 }
3204 }
3205 update_fcr31(env, GETPC());
3206 return dt2;
3207}
3208
3209uint32_t helper_float_trunc_2008_w_d(CPUMIPSState *env, uint64_t fdt0)
3210{
3211 uint32_t wt2;
3212
3213 wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
3214 if (get_float_exception_flags(&env->active_fpu.fp_status)
3215 & float_flag_invalid) {
3216 if (float64_is_any_nan(fdt0)) {
3217 wt2 = 0;
3218 }
3219 }
3220 update_fcr31(env, GETPC());
3221 return wt2;
3222}
3223
3224uint32_t helper_float_trunc_2008_w_s(CPUMIPSState *env, uint32_t fst0)
3225{
3226 uint32_t wt2;
3227
3228 wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
3229 if (get_float_exception_flags(&env->active_fpu.fp_status)
3230 & float_flag_invalid) {
3231 if (float32_is_any_nan(fst0)) {
3232 wt2 = 0;
3233 }
3234 }
3235 update_fcr31(env, GETPC());
3236 return wt2;
3237}
3238
3239uint64_t helper_float_ceil_2008_l_d(CPUMIPSState *env, uint64_t fdt0)
3240{
3241 uint64_t dt2;
3242
3243 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3244 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3245 restore_rounding_mode(env);
3246 if (get_float_exception_flags(&env->active_fpu.fp_status)
3247 & float_flag_invalid) {
3248 if (float64_is_any_nan(fdt0)) {
3249 dt2 = 0;
3250 }
3251 }
3252 update_fcr31(env, GETPC());
3253 return dt2;
3254}
3255
3256uint64_t helper_float_ceil_2008_l_s(CPUMIPSState *env, uint32_t fst0)
3257{
3258 uint64_t dt2;
3259
3260 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3261 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3262 restore_rounding_mode(env);
3263 if (get_float_exception_flags(&env->active_fpu.fp_status)
3264 & float_flag_invalid) {
3265 if (float32_is_any_nan(fst0)) {
3266 dt2 = 0;
3267 }
3268 }
3269 update_fcr31(env, GETPC());
3270 return dt2;
3271}
3272
3273uint32_t helper_float_ceil_2008_w_d(CPUMIPSState *env, uint64_t fdt0)
3274{
3275 uint32_t wt2;
3276
3277 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3278 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3279 restore_rounding_mode(env);
3280 if (get_float_exception_flags(&env->active_fpu.fp_status)
3281 & float_flag_invalid) {
3282 if (float64_is_any_nan(fdt0)) {
3283 wt2 = 0;
3284 }
3285 }
3286 update_fcr31(env, GETPC());
3287 return wt2;
3288}
3289
3290uint32_t helper_float_ceil_2008_w_s(CPUMIPSState *env, uint32_t fst0)
3291{
3292 uint32_t wt2;
3293
3294 set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3295 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3296 restore_rounding_mode(env);
3297 if (get_float_exception_flags(&env->active_fpu.fp_status)
3298 & float_flag_invalid) {
3299 if (float32_is_any_nan(fst0)) {
3300 wt2 = 0;
3301 }
3302 }
3303 update_fcr31(env, GETPC());
3304 return wt2;
3305}
3306
3307uint64_t helper_float_floor_2008_l_d(CPUMIPSState *env, uint64_t fdt0)
3308{
3309 uint64_t dt2;
3310
3311 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3312 dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3313 restore_rounding_mode(env);
3314 if (get_float_exception_flags(&env->active_fpu.fp_status)
3315 & float_flag_invalid) {
3316 if (float64_is_any_nan(fdt0)) {
3317 dt2 = 0;
3318 }
3319 }
3320 update_fcr31(env, GETPC());
3321 return dt2;
3322}
3323
3324uint64_t helper_float_floor_2008_l_s(CPUMIPSState *env, uint32_t fst0)
3325{
3326 uint64_t dt2;
3327
3328 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3329 dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3330 restore_rounding_mode(env);
3331 if (get_float_exception_flags(&env->active_fpu.fp_status)
3332 & float_flag_invalid) {
3333 if (float32_is_any_nan(fst0)) {
3334 dt2 = 0;
3335 }
3336 }
3337 update_fcr31(env, GETPC());
3338 return dt2;
3339}
3340
3341uint32_t helper_float_floor_2008_w_d(CPUMIPSState *env, uint64_t fdt0)
3342{
3343 uint32_t wt2;
3344
3345 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3346 wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3347 restore_rounding_mode(env);
3348 if (get_float_exception_flags(&env->active_fpu.fp_status)
3349 & float_flag_invalid) {
3350 if (float64_is_any_nan(fdt0)) {
3351 wt2 = 0;
3352 }
3353 }
3354 update_fcr31(env, GETPC());
3355 return wt2;
3356}
3357
3358uint32_t helper_float_floor_2008_w_s(CPUMIPSState *env, uint32_t fst0)
3359{
3360 uint32_t wt2;
3361
3362 set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3363 wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3364 restore_rounding_mode(env);
3365 if (get_float_exception_flags(&env->active_fpu.fp_status)
3366 & float_flag_invalid) {
3367 if (float32_is_any_nan(fst0)) {
3368 wt2 = 0;
3369 }
3370 }
3371 update_fcr31(env, GETPC());
3372 return wt2;
3373}
3374
a16336e4 3375/* unary operations, not modifying fp status */
b6d96bed 3376#define FLOAT_UNOP(name) \
c01fccd2 3377uint64_t helper_float_ ## name ## _d(uint64_t fdt0) \
b6d96bed
TS
3378{ \
3379 return float64_ ## name(fdt0); \
3380} \
c01fccd2 3381uint32_t helper_float_ ## name ## _s(uint32_t fst0) \
b6d96bed
TS
3382{ \
3383 return float32_ ## name(fst0); \
3384} \
c01fccd2 3385uint64_t helper_float_ ## name ## _ps(uint64_t fdt0) \
b6d96bed
TS
3386{ \
3387 uint32_t wt0; \
3388 uint32_t wth0; \
3389 \
3390 wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF); \
3391 wth0 = float32_ ## name(fdt0 >> 32); \
3392 return ((uint64_t)wth0 << 32) | wt0; \
a16336e4
TS
3393}
3394FLOAT_UNOP(abs)
3395FLOAT_UNOP(chs)
3396#undef FLOAT_UNOP
3397
8dfdb87c 3398/* MIPS specific unary operations */
895c2d04 3399uint64_t helper_float_recip_d(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 3400{
b6d96bed
TS
3401 uint64_t fdt2;
3402
05993cd0 3403 fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
5f7319cd 3404 update_fcr31(env, GETPC());
b6d96bed 3405 return fdt2;
8dfdb87c 3406}
b6d96bed 3407
895c2d04 3408uint32_t helper_float_recip_s(CPUMIPSState *env, uint32_t fst0)
8dfdb87c 3409{
b6d96bed
TS
3410 uint32_t fst2;
3411
05993cd0 3412 fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
5f7319cd 3413 update_fcr31(env, GETPC());
b6d96bed 3414 return fst2;
57fa1fb3 3415}
57fa1fb3 3416
895c2d04 3417uint64_t helper_float_rsqrt_d(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 3418{
b6d96bed
TS
3419 uint64_t fdt2;
3420
f01be154 3421 fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
05993cd0 3422 fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
5f7319cd 3423 update_fcr31(env, GETPC());
b6d96bed 3424 return fdt2;
8dfdb87c 3425}
b6d96bed 3426
895c2d04 3427uint32_t helper_float_rsqrt_s(CPUMIPSState *env, uint32_t fst0)
8dfdb87c 3428{
b6d96bed
TS
3429 uint32_t fst2;
3430
f01be154 3431 fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
05993cd0 3432 fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
5f7319cd 3433 update_fcr31(env, GETPC());
b6d96bed 3434 return fst2;
8dfdb87c
TS
3435}
3436
895c2d04 3437uint64_t helper_float_recip1_d(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 3438{
b6d96bed
TS
3439 uint64_t fdt2;
3440
05993cd0 3441 fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
5f7319cd 3442 update_fcr31(env, GETPC());
b6d96bed 3443 return fdt2;
8dfdb87c 3444}
b6d96bed 3445
895c2d04 3446uint32_t helper_float_recip1_s(CPUMIPSState *env, uint32_t fst0)
8dfdb87c 3447{
b6d96bed
TS
3448 uint32_t fst2;
3449
05993cd0 3450 fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
5f7319cd 3451 update_fcr31(env, GETPC());
b6d96bed 3452 return fst2;
8dfdb87c 3453}
b6d96bed 3454
895c2d04 3455uint64_t helper_float_recip1_ps(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 3456{
b6d96bed
TS
3457 uint32_t fst2;
3458 uint32_t fsth2;
3459
05993cd0
AJ
3460 fst2 = float32_div(float32_one, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
3461 fsth2 = float32_div(float32_one, fdt0 >> 32, &env->active_fpu.fp_status);
5f7319cd 3462 update_fcr31(env, GETPC());
b6d96bed 3463 return ((uint64_t)fsth2 << 32) | fst2;
8dfdb87c
TS
3464}
3465
895c2d04 3466uint64_t helper_float_rsqrt1_d(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 3467{
b6d96bed
TS
3468 uint64_t fdt2;
3469
f01be154 3470 fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
05993cd0 3471 fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
5f7319cd 3472 update_fcr31(env, GETPC());
b6d96bed 3473 return fdt2;
8dfdb87c 3474}
b6d96bed 3475
895c2d04 3476uint32_t helper_float_rsqrt1_s(CPUMIPSState *env, uint32_t fst0)
8dfdb87c 3477{
b6d96bed
TS
3478 uint32_t fst2;
3479
f01be154 3480 fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
05993cd0 3481 fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
5f7319cd 3482 update_fcr31(env, GETPC());
b6d96bed 3483 return fst2;
8dfdb87c 3484}
b6d96bed 3485
895c2d04 3486uint64_t helper_float_rsqrt1_ps(CPUMIPSState *env, uint64_t fdt0)
8dfdb87c 3487{
b6d96bed
TS
3488 uint32_t fst2;
3489 uint32_t fsth2;
3490
f01be154
TS
3491 fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
3492 fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status);
05993cd0
AJ
3493 fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
3494 fsth2 = float32_div(float32_one, fsth2, &env->active_fpu.fp_status);
5f7319cd 3495 update_fcr31(env, GETPC());
b6d96bed 3496 return ((uint64_t)fsth2 << 32) | fst2;
57fa1fb3 3497}
57fa1fb3 3498
8fc605b8
MR
3499#define FLOAT_RINT(name, bits) \
3500uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \
3501 uint ## bits ## _t fs) \
3502{ \
3503 uint ## bits ## _t fdret; \
3504 \
3505 fdret = float ## bits ## _round_to_int(fs, &env->active_fpu.fp_status); \
3506 update_fcr31(env, GETPC()); \
3507 return fdret; \
3508}
3509
3510FLOAT_RINT(rint_s, 32)
3511FLOAT_RINT(rint_d, 64)
3512#undef FLOAT_RINT
3513
3514#define FLOAT_CLASS_SIGNALING_NAN 0x001
3515#define FLOAT_CLASS_QUIET_NAN 0x002
3516#define FLOAT_CLASS_NEGATIVE_INFINITY 0x004
3517#define FLOAT_CLASS_NEGATIVE_NORMAL 0x008
3518#define FLOAT_CLASS_NEGATIVE_SUBNORMAL 0x010
3519#define FLOAT_CLASS_NEGATIVE_ZERO 0x020
3520#define FLOAT_CLASS_POSITIVE_INFINITY 0x040
3521#define FLOAT_CLASS_POSITIVE_NORMAL 0x080
3522#define FLOAT_CLASS_POSITIVE_SUBNORMAL 0x100
3523#define FLOAT_CLASS_POSITIVE_ZERO 0x200
3524
3525#define FLOAT_CLASS(name, bits) \
af39bc8c
AM
3526uint ## bits ## _t float_ ## name (uint ## bits ## _t arg, \
3527 float_status *status) \
8fc605b8 3528{ \
af39bc8c 3529 if (float ## bits ## _is_signaling_nan(arg, status)) { \
8fc605b8 3530 return FLOAT_CLASS_SIGNALING_NAN; \
af39bc8c 3531 } else if (float ## bits ## _is_quiet_nan(arg, status)) { \
8fc605b8
MR
3532 return FLOAT_CLASS_QUIET_NAN; \
3533 } else if (float ## bits ## _is_neg(arg)) { \
3534 if (float ## bits ## _is_infinity(arg)) { \
3535 return FLOAT_CLASS_NEGATIVE_INFINITY; \
3536 } else if (float ## bits ## _is_zero(arg)) { \
3537 return FLOAT_CLASS_NEGATIVE_ZERO; \
3538 } else if (float ## bits ## _is_zero_or_denormal(arg)) { \
3539 return FLOAT_CLASS_NEGATIVE_SUBNORMAL; \
3540 } else { \
3541 return FLOAT_CLASS_NEGATIVE_NORMAL; \
3542 } \
3543 } else { \
3544 if (float ## bits ## _is_infinity(arg)) { \
3545 return FLOAT_CLASS_POSITIVE_INFINITY; \
3546 } else if (float ## bits ## _is_zero(arg)) { \
3547 return FLOAT_CLASS_POSITIVE_ZERO; \
3548 } else if (float ## bits ## _is_zero_or_denormal(arg)) { \
3549 return FLOAT_CLASS_POSITIVE_SUBNORMAL; \
3550 } else { \
3551 return FLOAT_CLASS_POSITIVE_NORMAL; \
3552 } \
3553 } \
af39bc8c
AM
3554} \
3555 \
3556uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \
3557 uint ## bits ## _t arg) \
3558{ \
3559 return float_ ## name(arg, &env->active_fpu.fp_status); \
8fc605b8
MR
3560}
3561
3562FLOAT_CLASS(class_s, 32)
3563FLOAT_CLASS(class_d, 64)
3564#undef FLOAT_CLASS
3565
fd4a04eb 3566/* binary operations */
b6d96bed 3567#define FLOAT_BINOP(name) \
895c2d04
BS
3568uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \
3569 uint64_t fdt0, uint64_t fdt1) \
b6d96bed
TS
3570{ \
3571 uint64_t dt2; \
3572 \
f01be154 3573 dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status); \
5f7319cd 3574 update_fcr31(env, GETPC()); \
b6d96bed
TS
3575 return dt2; \
3576} \
3577 \
895c2d04
BS
3578uint32_t helper_float_ ## name ## _s(CPUMIPSState *env, \
3579 uint32_t fst0, uint32_t fst1) \
b6d96bed
TS
3580{ \
3581 uint32_t wt2; \
3582 \
f01be154 3583 wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \
5f7319cd 3584 update_fcr31(env, GETPC()); \
b6d96bed
TS
3585 return wt2; \
3586} \
3587 \
895c2d04
BS
3588uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \
3589 uint64_t fdt0, \
3590 uint64_t fdt1) \
b6d96bed
TS
3591{ \
3592 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
3593 uint32_t fsth0 = fdt0 >> 32; \
3594 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
3595 uint32_t fsth1 = fdt1 >> 32; \
3596 uint32_t wt2; \
3597 uint32_t wth2; \
3598 \
f01be154
TS
3599 wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \
3600 wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status); \
5f7319cd 3601 update_fcr31(env, GETPC()); \
b6d96bed 3602 return ((uint64_t)wth2 << 32) | wt2; \
fd4a04eb 3603}
b6d96bed 3604
fd4a04eb
TS
3605FLOAT_BINOP(add)
3606FLOAT_BINOP(sub)
3607FLOAT_BINOP(mul)
3608FLOAT_BINOP(div)
3609#undef FLOAT_BINOP
3610
8dfdb87c 3611/* MIPS specific binary operations */
895c2d04 3612uint64_t helper_float_recip2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
8dfdb87c 3613{
f01be154 3614 fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
05993cd0 3615 fdt2 = float64_chs(float64_sub(fdt2, float64_one, &env->active_fpu.fp_status));
5f7319cd 3616 update_fcr31(env, GETPC());
b6d96bed 3617 return fdt2;
8dfdb87c 3618}
b6d96bed 3619
895c2d04 3620uint32_t helper_float_recip2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
8dfdb87c 3621{
f01be154 3622 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
05993cd0 3623 fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
5f7319cd 3624 update_fcr31(env, GETPC());
b6d96bed 3625 return fst2;
8dfdb87c 3626}
b6d96bed 3627
895c2d04 3628uint64_t helper_float_recip2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
8dfdb87c 3629{
b6d96bed
TS
3630 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3631 uint32_t fsth0 = fdt0 >> 32;
3632 uint32_t fst2 = fdt2 & 0XFFFFFFFF;
3633 uint32_t fsth2 = fdt2 >> 32;
3634
f01be154
TS
3635 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3636 fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
05993cd0
AJ
3637 fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
3638 fsth2 = float32_chs(float32_sub(fsth2, float32_one, &env->active_fpu.fp_status));
5f7319cd 3639 update_fcr31(env, GETPC());
b6d96bed 3640 return ((uint64_t)fsth2 << 32) | fst2;
8dfdb87c
TS
3641}
3642
895c2d04 3643uint64_t helper_float_rsqrt2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
8dfdb87c 3644{
f01be154 3645 fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
05993cd0 3646 fdt2 = float64_sub(fdt2, float64_one, &env->active_fpu.fp_status);
f01be154 3647 fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status));
5f7319cd 3648 update_fcr31(env, GETPC());
b6d96bed 3649 return fdt2;
8dfdb87c 3650}
b6d96bed 3651
895c2d04 3652uint32_t helper_float_rsqrt2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
8dfdb87c 3653{
f01be154 3654 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
05993cd0 3655 fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
f01be154 3656 fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
5f7319cd 3657 update_fcr31(env, GETPC());
b6d96bed 3658 return fst2;
8dfdb87c 3659}
b6d96bed 3660
895c2d04 3661uint64_t helper_float_rsqrt2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
8dfdb87c 3662{
b6d96bed
TS
3663 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3664 uint32_t fsth0 = fdt0 >> 32;
3665 uint32_t fst2 = fdt2 & 0XFFFFFFFF;
3666 uint32_t fsth2 = fdt2 >> 32;
3667
f01be154
TS
3668 fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3669 fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
05993cd0
AJ
3670 fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
3671 fsth2 = float32_sub(fsth2, float32_one, &env->active_fpu.fp_status);
f01be154
TS
3672 fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
3673 fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->active_fpu.fp_status));
5f7319cd 3674 update_fcr31(env, GETPC());
b6d96bed 3675 return ((uint64_t)fsth2 << 32) | fst2;
57fa1fb3 3676}
57fa1fb3 3677
895c2d04 3678uint64_t helper_float_addr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
fd4a04eb 3679{
b6d96bed
TS
3680 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3681 uint32_t fsth0 = fdt0 >> 32;
3682 uint32_t fst1 = fdt1 & 0XFFFFFFFF;
3683 uint32_t fsth1 = fdt1 >> 32;
3684 uint32_t fst2;
3685 uint32_t fsth2;
3686
f01be154
TS
3687 fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status);
3688 fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status);
5f7319cd 3689 update_fcr31(env, GETPC());
b6d96bed 3690 return ((uint64_t)fsth2 << 32) | fst2;
fd4a04eb
TS
3691}
3692
895c2d04 3693uint64_t helper_float_mulr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
57fa1fb3 3694{
b6d96bed
TS
3695 uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3696 uint32_t fsth0 = fdt0 >> 32;
3697 uint32_t fst1 = fdt1 & 0XFFFFFFFF;
3698 uint32_t fsth1 = fdt1 >> 32;
3699 uint32_t fst2;
3700 uint32_t fsth2;
3701
f01be154
TS
3702 fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status);
3703 fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status);
5f7319cd 3704 update_fcr31(env, GETPC());
b6d96bed 3705 return ((uint64_t)fsth2 << 32) | fst2;
57fa1fb3
TS
3706}
3707
8fc605b8
MR
3708#define FLOAT_MINMAX(name, bits, minmaxfunc) \
3709uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \
3710 uint ## bits ## _t fs, \
3711 uint ## bits ## _t ft) \
3712{ \
3713 uint ## bits ## _t fdret; \
3714 \
3715 fdret = float ## bits ## _ ## minmaxfunc(fs, ft, \
3716 &env->active_fpu.fp_status); \
3717 update_fcr31(env, GETPC()); \
3718 return fdret; \
3719}
3720
3721FLOAT_MINMAX(max_s, 32, maxnum)
3722FLOAT_MINMAX(max_d, 64, maxnum)
3723FLOAT_MINMAX(maxa_s, 32, maxnummag)
3724FLOAT_MINMAX(maxa_d, 64, maxnummag)
3725
3726FLOAT_MINMAX(min_s, 32, minnum)
3727FLOAT_MINMAX(min_d, 64, minnum)
3728FLOAT_MINMAX(mina_s, 32, minnummag)
3729FLOAT_MINMAX(mina_d, 64, minnummag)
3730#undef FLOAT_MINMAX
3731
3732/* ternary operations */
3733#define UNFUSED_FMA(prefix, a, b, c, flags) \
3734{ \
3735 a = prefix##_mul(a, b, &env->active_fpu.fp_status); \
3736 if ((flags) & float_muladd_negate_c) { \
3737 a = prefix##_sub(a, c, &env->active_fpu.fp_status); \
3738 } else { \
3739 a = prefix##_add(a, c, &env->active_fpu.fp_status); \
3740 } \
3741 if ((flags) & float_muladd_negate_result) { \
3742 a = prefix##_chs(a); \
3743 } \
3744}
3745
3746/* FMA based operations */
3747#define FLOAT_FMA(name, type) \
3748uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \
3749 uint64_t fdt0, uint64_t fdt1, \
3750 uint64_t fdt2) \
3751{ \
3752 UNFUSED_FMA(float64, fdt0, fdt1, fdt2, type); \
3753 update_fcr31(env, GETPC()); \
3754 return fdt0; \
3755} \
3756 \
3757uint32_t helper_float_ ## name ## _s(CPUMIPSState *env, \
3758 uint32_t fst0, uint32_t fst1, \
3759 uint32_t fst2) \
3760{ \
3761 UNFUSED_FMA(float32, fst0, fst1, fst2, type); \
3762 update_fcr31(env, GETPC()); \
3763 return fst0; \
3764} \
3765 \
3766uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \
3767 uint64_t fdt0, uint64_t fdt1, \
3768 uint64_t fdt2) \
3769{ \
3770 uint32_t fst0 = fdt0 & 0XFFFFFFFF; \
3771 uint32_t fsth0 = fdt0 >> 32; \
3772 uint32_t fst1 = fdt1 & 0XFFFFFFFF; \
3773 uint32_t fsth1 = fdt1 >> 32; \
3774 uint32_t fst2 = fdt2 & 0XFFFFFFFF; \
3775 uint32_t fsth2 = fdt2 >> 32; \
3776 \
3777 UNFUSED_FMA(float32, fst0, fst1, fst2, type); \
3778 UNFUSED_FMA(float32, fsth0, fsth1, fsth2, type); \
3779 update_fcr31(env, GETPC()); \
3780 return ((uint64_t)fsth0 << 32) | fst0; \
3781}
3782FLOAT_FMA(madd, 0)
3783FLOAT_FMA(msub, float_muladd_negate_c)
3784FLOAT_FMA(nmadd, float_muladd_negate_result)
3785FLOAT_FMA(nmsub, float_muladd_negate_result | float_muladd_negate_c)
3786#undef FLOAT_FMA
3787
3788#define FLOAT_FMADDSUB(name, bits, muladd_arg) \
3789uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \
3790 uint ## bits ## _t fs, \
3791 uint ## bits ## _t ft, \
3792 uint ## bits ## _t fd) \
3793{ \
3794 uint ## bits ## _t fdret; \
3795 \
3796 fdret = float ## bits ## _muladd(fs, ft, fd, muladd_arg, \
3797 &env->active_fpu.fp_status); \
3798 update_fcr31(env, GETPC()); \
3799 return fdret; \
3800}
3801
3802FLOAT_FMADDSUB(maddf_s, 32, 0)
3803FLOAT_FMADDSUB(maddf_d, 64, 0)
3804FLOAT_FMADDSUB(msubf_s, 32, float_muladd_negate_product)
3805FLOAT_FMADDSUB(msubf_d, 64, float_muladd_negate_product)
3806#undef FLOAT_FMADDSUB
3807
8dfdb87c 3808/* compare operations */
b6d96bed 3809#define FOP_COND_D(op, cond) \
895c2d04
BS
3810void helper_cmp_d_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3811 uint64_t fdt1, int cc) \
b6d96bed 3812{ \
6a385343 3813 int c; \
6a385343 3814 c = cond; \
5f7319cd 3815 update_fcr31(env, GETPC()); \
b6d96bed 3816 if (c) \
f01be154 3817 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3818 else \
f01be154 3819 CLEAR_FP_COND(cc, env->active_fpu); \
b6d96bed 3820} \
895c2d04
BS
3821void helper_cmpabs_d_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3822 uint64_t fdt1, int cc) \
b6d96bed
TS
3823{ \
3824 int c; \
3825 fdt0 = float64_abs(fdt0); \
3826 fdt1 = float64_abs(fdt1); \
3827 c = cond; \
5f7319cd 3828 update_fcr31(env, GETPC()); \
b6d96bed 3829 if (c) \
f01be154 3830 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3831 else \
f01be154 3832 CLEAR_FP_COND(cc, env->active_fpu); \
fd4a04eb
TS
3833}
3834
fd4a04eb 3835/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3836 * but float64_unordered_quiet() is still called. */
3837FOP_COND_D(f, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
3838FOP_COND_D(un, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status))
06a0e6b1 3839FOP_COND_D(eq, float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
211315fb 3840FOP_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
3841FOP_COND_D(olt, float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3842FOP_COND_D(ult, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3843FOP_COND_D(ole, float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3844FOP_COND_D(ule, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status) || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
fd4a04eb 3845/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3846 * but float64_unordered() is still called. */
3847FOP_COND_D(sf, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
3848FOP_COND_D(ngle,float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status))
06a0e6b1
AJ
3849FOP_COND_D(seq, float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
3850FOP_COND_D(ngl, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
3851FOP_COND_D(lt, float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
3a599383 3852FOP_COND_D(nge, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
06a0e6b1 3853FOP_COND_D(le, float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3a599383 3854FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
b6d96bed
TS
3855
3856#define FOP_COND_S(op, cond) \
895c2d04
BS
3857void helper_cmp_s_ ## op(CPUMIPSState *env, uint32_t fst0, \
3858 uint32_t fst1, int cc) \
b6d96bed 3859{ \
6a385343 3860 int c; \
6a385343 3861 c = cond; \
5f7319cd 3862 update_fcr31(env, GETPC()); \
b6d96bed 3863 if (c) \
f01be154 3864 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3865 else \
f01be154 3866 CLEAR_FP_COND(cc, env->active_fpu); \
b6d96bed 3867} \
895c2d04
BS
3868void helper_cmpabs_s_ ## op(CPUMIPSState *env, uint32_t fst0, \
3869 uint32_t fst1, int cc) \
b6d96bed
TS
3870{ \
3871 int c; \
3872 fst0 = float32_abs(fst0); \
3873 fst1 = float32_abs(fst1); \
3874 c = cond; \
5f7319cd 3875 update_fcr31(env, GETPC()); \
b6d96bed 3876 if (c) \
f01be154 3877 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3878 else \
f01be154 3879 CLEAR_FP_COND(cc, env->active_fpu); \
fd4a04eb
TS
3880}
3881
fd4a04eb 3882/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3883 * but float32_unordered_quiet() is still called. */
3884FOP_COND_S(f, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
3885FOP_COND_S(un, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status))
06a0e6b1 3886FOP_COND_S(eq, float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
211315fb 3887FOP_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
3888FOP_COND_S(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
3889FOP_COND_S(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
3890FOP_COND_S(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
3891FOP_COND_S(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
fd4a04eb 3892/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3893 * but float32_unordered() is still called. */
3894FOP_COND_S(sf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
3895FOP_COND_S(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status))
06a0e6b1
AJ
3896FOP_COND_S(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status))
3897FOP_COND_S(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
3898FOP_COND_S(lt, float32_lt(fst0, fst1, &env->active_fpu.fp_status))
3a599383 3899FOP_COND_S(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
06a0e6b1 3900FOP_COND_S(le, float32_le(fst0, fst1, &env->active_fpu.fp_status))
3a599383 3901FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status))
b6d96bed
TS
3902
3903#define FOP_COND_PS(op, condl, condh) \
895c2d04
BS
3904void helper_cmp_ps_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3905 uint64_t fdt1, int cc) \
b6d96bed 3906{ \
6a385343
AJ
3907 uint32_t fst0, fsth0, fst1, fsth1; \
3908 int ch, cl; \
6a385343
AJ
3909 fst0 = fdt0 & 0XFFFFFFFF; \
3910 fsth0 = fdt0 >> 32; \
3911 fst1 = fdt1 & 0XFFFFFFFF; \
3912 fsth1 = fdt1 >> 32; \
3913 cl = condl; \
3914 ch = condh; \
5f7319cd 3915 update_fcr31(env, GETPC()); \
b6d96bed 3916 if (cl) \
f01be154 3917 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3918 else \
f01be154 3919 CLEAR_FP_COND(cc, env->active_fpu); \
b6d96bed 3920 if (ch) \
f01be154 3921 SET_FP_COND(cc + 1, env->active_fpu); \
b6d96bed 3922 else \
f01be154 3923 CLEAR_FP_COND(cc + 1, env->active_fpu); \
b6d96bed 3924} \
895c2d04
BS
3925void helper_cmpabs_ps_ ## op(CPUMIPSState *env, uint64_t fdt0, \
3926 uint64_t fdt1, int cc) \
b6d96bed 3927{ \
6a385343
AJ
3928 uint32_t fst0, fsth0, fst1, fsth1; \
3929 int ch, cl; \
3930 fst0 = float32_abs(fdt0 & 0XFFFFFFFF); \
3931 fsth0 = float32_abs(fdt0 >> 32); \
3932 fst1 = float32_abs(fdt1 & 0XFFFFFFFF); \
3933 fsth1 = float32_abs(fdt1 >> 32); \
3934 cl = condl; \
3935 ch = condh; \
5f7319cd 3936 update_fcr31(env, GETPC()); \
b6d96bed 3937 if (cl) \
f01be154 3938 SET_FP_COND(cc, env->active_fpu); \
b6d96bed 3939 else \
f01be154 3940 CLEAR_FP_COND(cc, env->active_fpu); \
b6d96bed 3941 if (ch) \
f01be154 3942 SET_FP_COND(cc + 1, env->active_fpu); \
b6d96bed 3943 else \
f01be154 3944 CLEAR_FP_COND(cc + 1, env->active_fpu); \
fd4a04eb
TS
3945}
3946
3947/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3948 * but float32_unordered_quiet() is still called. */
3949FOP_COND_PS(f, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0),
3950 (float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status), 0))
3951FOP_COND_PS(un, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status),
3952 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status))
06a0e6b1
AJ
3953FOP_COND_PS(eq, float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
3954 float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
211315fb
AJ
3955FOP_COND_PS(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
3956 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
06a0e6b1
AJ
3957FOP_COND_PS(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
3958 float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3959FOP_COND_PS(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
3960 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3961FOP_COND_PS(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
3962 float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3963FOP_COND_PS(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status) || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
3964 float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status) || float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
fd4a04eb 3965/* NOTE: the comma operator will make "cond" to eval to false,
3a599383
AJ
3966 * but float32_unordered() is still called. */
3967FOP_COND_PS(sf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0),
3968 (float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status), 0))
3969FOP_COND_PS(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status),
3970 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status))
06a0e6b1
AJ
3971FOP_COND_PS(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status),
3972 float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
3973FOP_COND_PS(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
3974 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
3975FOP_COND_PS(lt, float32_lt(fst0, fst1, &env->active_fpu.fp_status),
3976 float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
3a599383
AJ
3977FOP_COND_PS(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
3978 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
06a0e6b1
AJ
3979FOP_COND_PS(le, float32_le(fst0, fst1, &env->active_fpu.fp_status),
3980 float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
3a599383
AJ
3981FOP_COND_PS(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status),
3982 float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status) || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
3f493883
YK
3983
3984/* R6 compare operations */
3985#define FOP_CONDN_D(op, cond) \
3986uint64_t helper_r6_cmp_d_ ## op(CPUMIPSState * env, uint64_t fdt0, \
3987 uint64_t fdt1) \
3988{ \
3989 uint64_t c; \
3990 c = cond; \
3991 update_fcr31(env, GETPC()); \
3992 if (c) { \
3993 return -1; \
3994 } else { \
3995 return 0; \
3996 } \
3997}
3998
3999/* NOTE: the comma operator will make "cond" to eval to false,
4000 * but float64_unordered_quiet() is still called. */
4001FOP_CONDN_D(af, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
4002FOP_CONDN_D(un, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)))
4003FOP_CONDN_D(eq, (float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4004FOP_CONDN_D(ueq, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4005 || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4006FOP_CONDN_D(lt, (float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4007FOP_CONDN_D(ult, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4008 || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4009FOP_CONDN_D(le, (float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4010FOP_CONDN_D(ule, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4011 || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4012/* NOTE: the comma operator will make "cond" to eval to false,
4013 * but float64_unordered() is still called. */
4014FOP_CONDN_D(saf, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
4015FOP_CONDN_D(sun, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)))
4016FOP_CONDN_D(seq, (float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)))
4017FOP_CONDN_D(sueq, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
4018 || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)))
4019FOP_CONDN_D(slt, (float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
4020FOP_CONDN_D(sult, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
4021 || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
4022FOP_CONDN_D(sle, (float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
4023FOP_CONDN_D(sule, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
4024 || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
4025FOP_CONDN_D(or, (float64_le_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4026 || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4027FOP_CONDN_D(une, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4028 || float64_lt_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4029 || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4030FOP_CONDN_D(ne, (float64_lt_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4031 || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4032FOP_CONDN_D(sor, (float64_le(fdt1, fdt0, &env->active_fpu.fp_status)
4033 || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
4034FOP_CONDN_D(sune, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
4035 || float64_lt(fdt1, fdt0, &env->active_fpu.fp_status)
4036 || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
4037FOP_CONDN_D(sne, (float64_lt(fdt1, fdt0, &env->active_fpu.fp_status)
4038 || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
4039
4040#define FOP_CONDN_S(op, cond) \
4041uint32_t helper_r6_cmp_s_ ## op(CPUMIPSState * env, uint32_t fst0, \
4042 uint32_t fst1) \
4043{ \
4044 uint64_t c; \
4045 c = cond; \
4046 update_fcr31(env, GETPC()); \
4047 if (c) { \
4048 return -1; \
4049 } else { \
4050 return 0; \
4051 } \
4052}
4053
4054/* NOTE: the comma operator will make "cond" to eval to false,
4055 * but float32_unordered_quiet() is still called. */
4056FOP_CONDN_S(af, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
4057FOP_CONDN_S(un, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)))
4058FOP_CONDN_S(eq, (float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4059FOP_CONDN_S(ueq, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
4060 || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4061FOP_CONDN_S(lt, (float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4062FOP_CONDN_S(ult, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
4063 || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4064FOP_CONDN_S(le, (float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4065FOP_CONDN_S(ule, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
4066 || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4067/* NOTE: the comma operator will make "cond" to eval to false,
4068 * but float32_unordered() is still called. */
4069FOP_CONDN_S(saf, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
4070FOP_CONDN_S(sun, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)))
4071FOP_CONDN_S(seq, (float32_eq(fst0, fst1, &env->active_fpu.fp_status)))
4072FOP_CONDN_S(sueq, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
4073 || float32_eq(fst0, fst1, &env->active_fpu.fp_status)))
4074FOP_CONDN_S(slt, (float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
4075FOP_CONDN_S(sult, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
4076 || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
4077FOP_CONDN_S(sle, (float32_le(fst0, fst1, &env->active_fpu.fp_status)))
4078FOP_CONDN_S(sule, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
4079 || float32_le(fst0, fst1, &env->active_fpu.fp_status)))
4080FOP_CONDN_S(or, (float32_le_quiet(fst1, fst0, &env->active_fpu.fp_status)
4081 || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4082FOP_CONDN_S(une, (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
4083 || float32_lt_quiet(fst1, fst0, &env->active_fpu.fp_status)
4084 || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4085FOP_CONDN_S(ne, (float32_lt_quiet(fst1, fst0, &env->active_fpu.fp_status)
4086 || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4087FOP_CONDN_S(sor, (float32_le(fst1, fst0, &env->active_fpu.fp_status)
4088 || float32_le(fst0, fst1, &env->active_fpu.fp_status)))
4089FOP_CONDN_S(sune, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
4090 || float32_lt(fst1, fst0, &env->active_fpu.fp_status)
4091 || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
4092FOP_CONDN_S(sne, (float32_lt(fst1, fst0, &env->active_fpu.fp_status)
4093 || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
f7685877
YK
4094
4095/* MSA */
4096/* Data format min and max values */
4097#define DF_BITS(df) (1 << ((df) + 3))
4098
4099/* Element-by-element access macros */
4100#define DF_ELEMENTS(df) (MSA_WRLEN / DF_BITS(df))
4101
adc370a4
YK
4102#if !defined(CONFIG_USER_ONLY)
4103#define MEMOP_IDX(DF) \
4104 TCGMemOpIdx oi = make_memop_idx(MO_TE | DF | MO_UNALN, \
97ed5ccd 4105 cpu_mmu_index(env, false));
adc370a4
YK
4106#else
4107#define MEMOP_IDX(DF)
4108#endif
f7685877 4109
adc370a4
YK
4110#define MSA_LD_DF(DF, TYPE, LD_INSN, ...) \
4111void helper_msa_ld_ ## TYPE(CPUMIPSState *env, uint32_t wd, \
4112 target_ulong addr) \
4113{ \
4114 wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \
4115 wr_t wx; \
4116 int i; \
4117 MEMOP_IDX(DF) \
4118 for (i = 0; i < DF_ELEMENTS(DF); i++) { \
4119 wx.TYPE[i] = LD_INSN(env, addr + (i << DF), ##__VA_ARGS__); \
4120 } \
4121 memcpy(pwd, &wx, sizeof(wr_t)); \
f7685877
YK
4122}
4123
adc370a4
YK
4124#if !defined(CONFIG_USER_ONLY)
4125MSA_LD_DF(DF_BYTE, b, helper_ret_ldub_mmu, oi, GETRA())
4126MSA_LD_DF(DF_HALF, h, helper_ret_lduw_mmu, oi, GETRA())
4127MSA_LD_DF(DF_WORD, w, helper_ret_ldul_mmu, oi, GETRA())
4128MSA_LD_DF(DF_DOUBLE, d, helper_ret_ldq_mmu, oi, GETRA())
4129#else
4130MSA_LD_DF(DF_BYTE, b, cpu_ldub_data)
4131MSA_LD_DF(DF_HALF, h, cpu_lduw_data)
4132MSA_LD_DF(DF_WORD, w, cpu_ldl_data)
4133MSA_LD_DF(DF_DOUBLE, d, cpu_ldq_data)
4134#endif
f7685877 4135
adc370a4
YK
4136#define MSA_PAGESPAN(x) \
4137 ((((x) & ~TARGET_PAGE_MASK) + MSA_WRLEN/8 - 1) >= TARGET_PAGE_SIZE)
4138
4139static inline void ensure_writable_pages(CPUMIPSState *env,
4140 target_ulong addr,
4141 int mmu_idx,
4142 uintptr_t retaddr)
4143{
4144#if !defined(CONFIG_USER_ONLY)
4145 target_ulong page_addr;
4146 if (unlikely(MSA_PAGESPAN(addr))) {
4147 /* first page */
4148 probe_write(env, addr, mmu_idx, retaddr);
4149 /* second page */
4150 page_addr = (addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
4151 probe_write(env, page_addr, mmu_idx, retaddr);
f7685877 4152 }
adc370a4 4153#endif
f7685877 4154}
adc370a4
YK
4155
4156#define MSA_ST_DF(DF, TYPE, ST_INSN, ...) \
4157void helper_msa_st_ ## TYPE(CPUMIPSState *env, uint32_t wd, \
4158 target_ulong addr) \
4159{ \
4160 wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \
97ed5ccd 4161 int mmu_idx = cpu_mmu_index(env, false); \
adc370a4
YK
4162 int i; \
4163 MEMOP_IDX(DF) \
4164 ensure_writable_pages(env, addr, mmu_idx, GETRA()); \
4165 for (i = 0; i < DF_ELEMENTS(DF); i++) { \
4166 ST_INSN(env, addr + (i << DF), pwd->TYPE[i], ##__VA_ARGS__); \
4167 } \
4168}
4169
4170#if !defined(CONFIG_USER_ONLY)
4171MSA_ST_DF(DF_BYTE, b, helper_ret_stb_mmu, oi, GETRA())
4172MSA_ST_DF(DF_HALF, h, helper_ret_stw_mmu, oi, GETRA())
4173MSA_ST_DF(DF_WORD, w, helper_ret_stl_mmu, oi, GETRA())
4174MSA_ST_DF(DF_DOUBLE, d, helper_ret_stq_mmu, oi, GETRA())
4175#else
4176MSA_ST_DF(DF_BYTE, b, cpu_stb_data)
4177MSA_ST_DF(DF_HALF, h, cpu_stw_data)
4178MSA_ST_DF(DF_WORD, w, cpu_stl_data)
4179MSA_ST_DF(DF_DOUBLE, d, cpu_stq_data)
4180#endif
0d74a222
LA
4181
4182void helper_cache(CPUMIPSState *env, target_ulong addr, uint32_t op)
4183{
4184#ifndef CONFIG_USER_ONLY
4185 target_ulong index = addr & 0x1fffffff;
4186 if (op == 9) {
4187 /* Index Store Tag */
4188 memory_region_dispatch_write(env->itc_tag, index, env->CP0_TagLo,
4189 8, MEMTXATTRS_UNSPECIFIED);
4190 } else if (op == 5) {
4191 /* Index Load Tag */
4192 memory_region_dispatch_read(env->itc_tag, index, &env->CP0_TagLo,
4193 8, MEMTXATTRS_UNSPECIFIED);
4194 }
4195#endif
4196}