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