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