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