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