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