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