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