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