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