]> Git Repo - qemu.git/blob - target/mips/op_helper.c
Merge remote-tracking branch 'remotes/rth/tags/pull-tcg-20170803' into staging
[qemu.git] / target / mips / op_helper.c
1 /*
2  *  MIPS emulation helpers for qemu.
3  *
4  *  Copyright (c) 2004-2005 Jocelyn Mayer
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  */
19 #include "qemu/osdep.h"
20 #include "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     uint64_t mask = env->CP0_PageMask >> (TARGET_PAGE_BITS + 1);
2012
2013     /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
2014     tlb = &env->tlb->mmu.r4k.tlb[idx];
2015     if (env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) {
2016         tlb->EHINV = 1;
2017         return;
2018     }
2019     tlb->EHINV = 0;
2020     tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
2021 #if defined(TARGET_MIPS64)
2022     tlb->VPN &= env->SEGMask;
2023 #endif
2024     tlb->ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
2025     tlb->PageMask = env->CP0_PageMask;
2026     tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
2027     tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
2028     tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
2029     tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
2030     tlb->XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) & 1;
2031     tlb->RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) & 1;
2032     tlb->PFN[0] = (get_tlb_pfn_from_entrylo(env->CP0_EntryLo0) & ~mask) << 12;
2033     tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
2034     tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
2035     tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
2036     tlb->XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) & 1;
2037     tlb->RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) & 1;
2038     tlb->PFN[1] = (get_tlb_pfn_from_entrylo(env->CP0_EntryLo1) & ~mask) << 12;
2039 }
2040
2041 void r4k_helper_tlbinv(CPUMIPSState *env)
2042 {
2043     int idx;
2044     r4k_tlb_t *tlb;
2045     uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
2046
2047     for (idx = 0; idx < env->tlb->nb_tlb; idx++) {
2048         tlb = &env->tlb->mmu.r4k.tlb[idx];
2049         if (!tlb->G && tlb->ASID == ASID) {
2050             tlb->EHINV = 1;
2051         }
2052     }
2053     cpu_mips_tlb_flush(env);
2054 }
2055
2056 void r4k_helper_tlbinvf(CPUMIPSState *env)
2057 {
2058     int idx;
2059
2060     for (idx = 0; idx < env->tlb->nb_tlb; idx++) {
2061         env->tlb->mmu.r4k.tlb[idx].EHINV = 1;
2062     }
2063     cpu_mips_tlb_flush(env);
2064 }
2065
2066 void r4k_helper_tlbwi(CPUMIPSState *env)
2067 {
2068     r4k_tlb_t *tlb;
2069     int idx;
2070     target_ulong VPN;
2071     uint16_t ASID;
2072     bool EHINV, G, V0, D0, V1, D1, XI0, XI1, RI0, RI1;
2073
2074     idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
2075     tlb = &env->tlb->mmu.r4k.tlb[idx];
2076     VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
2077 #if defined(TARGET_MIPS64)
2078     VPN &= env->SEGMask;
2079 #endif
2080     ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
2081     EHINV = (env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) != 0;
2082     G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
2083     V0 = (env->CP0_EntryLo0 & 2) != 0;
2084     D0 = (env->CP0_EntryLo0 & 4) != 0;
2085     XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) &1;
2086     RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) &1;
2087     V1 = (env->CP0_EntryLo1 & 2) != 0;
2088     D1 = (env->CP0_EntryLo1 & 4) != 0;
2089     XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) &1;
2090     RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) &1;
2091
2092     /* Discard cached TLB entries, unless tlbwi is just upgrading access
2093        permissions on the current entry. */
2094     if (tlb->VPN != VPN || tlb->ASID != ASID || tlb->G != G ||
2095         (!tlb->EHINV && EHINV) ||
2096         (tlb->V0 && !V0) || (tlb->D0 && !D0) ||
2097         (!tlb->XI0 && XI0) || (!tlb->RI0 && RI0) ||
2098         (tlb->V1 && !V1) || (tlb->D1 && !D1) ||
2099         (!tlb->XI1 && XI1) || (!tlb->RI1 && RI1)) {
2100         r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
2101     }
2102
2103     r4k_invalidate_tlb(env, idx, 0);
2104     r4k_fill_tlb(env, idx);
2105 }
2106
2107 void r4k_helper_tlbwr(CPUMIPSState *env)
2108 {
2109     int r = cpu_mips_get_random(env);
2110
2111     r4k_invalidate_tlb(env, r, 1);
2112     r4k_fill_tlb(env, r);
2113 }
2114
2115 void r4k_helper_tlbp(CPUMIPSState *env)
2116 {
2117     r4k_tlb_t *tlb;
2118     target_ulong mask;
2119     target_ulong tag;
2120     target_ulong VPN;
2121     uint16_t ASID;
2122     int i;
2123
2124     ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
2125     for (i = 0; i < env->tlb->nb_tlb; i++) {
2126         tlb = &env->tlb->mmu.r4k.tlb[i];
2127         /* 1k pages are not supported. */
2128         mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
2129         tag = env->CP0_EntryHi & ~mask;
2130         VPN = tlb->VPN & ~mask;
2131 #if defined(TARGET_MIPS64)
2132         tag &= env->SEGMask;
2133 #endif
2134         /* Check ASID, virtual page number & size */
2135         if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag && !tlb->EHINV) {
2136             /* TLB match */
2137             env->CP0_Index = i;
2138             break;
2139         }
2140     }
2141     if (i == env->tlb->nb_tlb) {
2142         /* No match.  Discard any shadow entries, if any of them match.  */
2143         for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
2144             tlb = &env->tlb->mmu.r4k.tlb[i];
2145             /* 1k pages are not supported. */
2146             mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
2147             tag = env->CP0_EntryHi & ~mask;
2148             VPN = tlb->VPN & ~mask;
2149 #if defined(TARGET_MIPS64)
2150             tag &= env->SEGMask;
2151 #endif
2152             /* Check ASID, virtual page number & size */
2153             if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
2154                 r4k_mips_tlb_flush_extra (env, i);
2155                 break;
2156             }
2157         }
2158
2159         env->CP0_Index |= 0x80000000;
2160     }
2161 }
2162
2163 static inline uint64_t get_entrylo_pfn_from_tlb(uint64_t tlb_pfn)
2164 {
2165 #if defined(TARGET_MIPS64)
2166     return tlb_pfn << 6;
2167 #else
2168     return (extract64(tlb_pfn, 0, 24) << 6) | /* PFN */
2169            (extract64(tlb_pfn, 24, 32) << 32); /* PFNX */
2170 #endif
2171 }
2172
2173 void r4k_helper_tlbr(CPUMIPSState *env)
2174 {
2175     r4k_tlb_t *tlb;
2176     uint16_t ASID;
2177     int idx;
2178
2179     ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
2180     idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
2181     tlb = &env->tlb->mmu.r4k.tlb[idx];
2182
2183     /* If this will change the current ASID, flush qemu's TLB.  */
2184     if (ASID != tlb->ASID)
2185         cpu_mips_tlb_flush(env);
2186
2187     r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
2188
2189     if (tlb->EHINV) {
2190         env->CP0_EntryHi = 1 << CP0EnHi_EHINV;
2191         env->CP0_PageMask = 0;
2192         env->CP0_EntryLo0 = 0;
2193         env->CP0_EntryLo1 = 0;
2194     } else {
2195         env->CP0_EntryHi = tlb->VPN | tlb->ASID;
2196         env->CP0_PageMask = tlb->PageMask;
2197         env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
2198                         ((uint64_t)tlb->RI0 << CP0EnLo_RI) |
2199                         ((uint64_t)tlb->XI0 << CP0EnLo_XI) | (tlb->C0 << 3) |
2200                         get_entrylo_pfn_from_tlb(tlb->PFN[0] >> 12);
2201         env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
2202                         ((uint64_t)tlb->RI1 << CP0EnLo_RI) |
2203                         ((uint64_t)tlb->XI1 << CP0EnLo_XI) | (tlb->C1 << 3) |
2204                         get_entrylo_pfn_from_tlb(tlb->PFN[1] >> 12);
2205     }
2206 }
2207
2208 void helper_tlbwi(CPUMIPSState *env)
2209 {
2210     env->tlb->helper_tlbwi(env);
2211 }
2212
2213 void helper_tlbwr(CPUMIPSState *env)
2214 {
2215     env->tlb->helper_tlbwr(env);
2216 }
2217
2218 void helper_tlbp(CPUMIPSState *env)
2219 {
2220     env->tlb->helper_tlbp(env);
2221 }
2222
2223 void helper_tlbr(CPUMIPSState *env)
2224 {
2225     env->tlb->helper_tlbr(env);
2226 }
2227
2228 void helper_tlbinv(CPUMIPSState *env)
2229 {
2230     env->tlb->helper_tlbinv(env);
2231 }
2232
2233 void helper_tlbinvf(CPUMIPSState *env)
2234 {
2235     env->tlb->helper_tlbinvf(env);
2236 }
2237
2238 /* Specials */
2239 target_ulong helper_di(CPUMIPSState *env)
2240 {
2241     target_ulong t0 = env->CP0_Status;
2242
2243     env->CP0_Status = t0 & ~(1 << CP0St_IE);
2244     return t0;
2245 }
2246
2247 target_ulong helper_ei(CPUMIPSState *env)
2248 {
2249     target_ulong t0 = env->CP0_Status;
2250
2251     env->CP0_Status = t0 | (1 << CP0St_IE);
2252     return t0;
2253 }
2254
2255 static void debug_pre_eret(CPUMIPSState *env)
2256 {
2257     if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
2258         qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
2259                 env->active_tc.PC, env->CP0_EPC);
2260         if (env->CP0_Status & (1 << CP0St_ERL))
2261             qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
2262         if (env->hflags & MIPS_HFLAG_DM)
2263             qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
2264         qemu_log("\n");
2265     }
2266 }
2267
2268 static void debug_post_eret(CPUMIPSState *env)
2269 {
2270     MIPSCPU *cpu = mips_env_get_cpu(env);
2271
2272     if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
2273         qemu_log("  =>  PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
2274                 env->active_tc.PC, env->CP0_EPC);
2275         if (env->CP0_Status & (1 << CP0St_ERL))
2276             qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
2277         if (env->hflags & MIPS_HFLAG_DM)
2278             qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
2279         switch (cpu_mmu_index(env, false)) {
2280         case 3:
2281             qemu_log(", ERL\n");
2282             break;
2283         case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
2284         case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
2285         case MIPS_HFLAG_KM: qemu_log("\n"); break;
2286         default:
2287             cpu_abort(CPU(cpu), "Invalid MMU mode!\n");
2288             break;
2289         }
2290     }
2291 }
2292
2293 static void set_pc(CPUMIPSState *env, target_ulong error_pc)
2294 {
2295     env->active_tc.PC = error_pc & ~(target_ulong)1;
2296     if (error_pc & 1) {
2297         env->hflags |= MIPS_HFLAG_M16;
2298     } else {
2299         env->hflags &= ~(MIPS_HFLAG_M16);
2300     }
2301 }
2302
2303 static inline void exception_return(CPUMIPSState *env)
2304 {
2305     debug_pre_eret(env);
2306     if (env->CP0_Status & (1 << CP0St_ERL)) {
2307         set_pc(env, env->CP0_ErrorEPC);
2308         env->CP0_Status &= ~(1 << CP0St_ERL);
2309     } else {
2310         set_pc(env, env->CP0_EPC);
2311         env->CP0_Status &= ~(1 << CP0St_EXL);
2312     }
2313     compute_hflags(env);
2314     debug_post_eret(env);
2315 }
2316
2317 void helper_eret(CPUMIPSState *env)
2318 {
2319     exception_return(env);
2320     env->lladdr = 1;
2321 }
2322
2323 void helper_eretnc(CPUMIPSState *env)
2324 {
2325     exception_return(env);
2326 }
2327
2328 void helper_deret(CPUMIPSState *env)
2329 {
2330     debug_pre_eret(env);
2331     set_pc(env, env->CP0_DEPC);
2332
2333     env->hflags &= ~MIPS_HFLAG_DM;
2334     compute_hflags(env);
2335     debug_post_eret(env);
2336 }
2337 #endif /* !CONFIG_USER_ONLY */
2338
2339 static inline void check_hwrena(CPUMIPSState *env, int reg, uintptr_t pc)
2340 {
2341     if ((env->hflags & MIPS_HFLAG_CP0) || (env->CP0_HWREna & (1 << reg))) {
2342         return;
2343     }
2344     do_raise_exception(env, EXCP_RI, pc);
2345 }
2346
2347 target_ulong helper_rdhwr_cpunum(CPUMIPSState *env)
2348 {
2349     check_hwrena(env, 0, GETPC());
2350     return env->CP0_EBase & 0x3ff;
2351 }
2352
2353 target_ulong helper_rdhwr_synci_step(CPUMIPSState *env)
2354 {
2355     check_hwrena(env, 1, GETPC());
2356     return env->SYNCI_Step;
2357 }
2358
2359 target_ulong helper_rdhwr_cc(CPUMIPSState *env)
2360 {
2361     int32_t count;
2362     check_hwrena(env, 2, GETPC());
2363 #ifdef CONFIG_USER_ONLY
2364     count = env->CP0_Count;
2365 #else
2366     qemu_mutex_lock_iothread();
2367     count = (int32_t)cpu_mips_get_count(env);
2368     qemu_mutex_unlock_iothread();
2369 #endif
2370     return count;
2371 }
2372
2373 target_ulong helper_rdhwr_ccres(CPUMIPSState *env)
2374 {
2375     check_hwrena(env, 3, GETPC());
2376     return env->CCRes;
2377 }
2378
2379 target_ulong helper_rdhwr_performance(CPUMIPSState *env)
2380 {
2381     check_hwrena(env, 4, GETPC());
2382     return env->CP0_Performance0;
2383 }
2384
2385 target_ulong helper_rdhwr_xnp(CPUMIPSState *env)
2386 {
2387     check_hwrena(env, 5, GETPC());
2388     return (env->CP0_Config5 >> CP0C5_XNP) & 1;
2389 }
2390
2391 void helper_pmon(CPUMIPSState *env, int function)
2392 {
2393     function /= 2;
2394     switch (function) {
2395     case 2: /* TODO: char inbyte(int waitflag); */
2396         if (env->active_tc.gpr[4] == 0)
2397             env->active_tc.gpr[2] = -1;
2398         /* Fall through */
2399     case 11: /* TODO: char inbyte (void); */
2400         env->active_tc.gpr[2] = -1;
2401         break;
2402     case 3:
2403     case 12:
2404         printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
2405         break;
2406     case 17:
2407         break;
2408     case 158:
2409         {
2410             unsigned char *fmt = (void *)(uintptr_t)env->active_tc.gpr[4];
2411             printf("%s", fmt);
2412         }
2413         break;
2414     }
2415 }
2416
2417 void helper_wait(CPUMIPSState *env)
2418 {
2419     CPUState *cs = CPU(mips_env_get_cpu(env));
2420
2421     cs->halted = 1;
2422     cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
2423     /* Last instruction in the block, PC was updated before
2424        - no need to recover PC and icount */
2425     raise_exception(env, EXCP_HLT);
2426 }
2427
2428 #if !defined(CONFIG_USER_ONLY)
2429
2430 void mips_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
2431                                   MMUAccessType access_type,
2432                                   int mmu_idx, uintptr_t retaddr)
2433 {
2434     MIPSCPU *cpu = MIPS_CPU(cs);
2435     CPUMIPSState *env = &cpu->env;
2436     int error_code = 0;
2437     int excp;
2438
2439     env->CP0_BadVAddr = addr;
2440
2441     if (access_type == MMU_DATA_STORE) {
2442         excp = EXCP_AdES;
2443     } else {
2444         excp = EXCP_AdEL;
2445         if (access_type == MMU_INST_FETCH) {
2446             error_code |= EXCP_INST_NOTAVAIL;
2447         }
2448     }
2449
2450     do_raise_exception_err(env, excp, error_code, retaddr);
2451 }
2452
2453 void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type,
2454               int mmu_idx, uintptr_t retaddr)
2455 {
2456     int ret;
2457
2458     ret = mips_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx);
2459     if (ret) {
2460         MIPSCPU *cpu = MIPS_CPU(cs);
2461         CPUMIPSState *env = &cpu->env;
2462
2463         do_raise_exception_err(env, cs->exception_index,
2464                                env->error_code, retaddr);
2465     }
2466 }
2467
2468 void mips_cpu_unassigned_access(CPUState *cs, hwaddr addr,
2469                                 bool is_write, bool is_exec, int unused,
2470                                 unsigned size)
2471 {
2472     MIPSCPU *cpu = MIPS_CPU(cs);
2473     CPUMIPSState *env = &cpu->env;
2474
2475     /*
2476      * Raising an exception with KVM enabled will crash because it won't be from
2477      * the main execution loop so the longjmp won't have a matching setjmp.
2478      * Until we can trigger a bus error exception through KVM lets just ignore
2479      * the access.
2480      */
2481     if (kvm_enabled()) {
2482         return;
2483     }
2484
2485     if (is_exec) {
2486         raise_exception(env, EXCP_IBE);
2487     } else {
2488         raise_exception(env, EXCP_DBE);
2489     }
2490 }
2491 #endif /* !CONFIG_USER_ONLY */
2492
2493 /* Complex FPU operations which may need stack space. */
2494
2495 #define FLOAT_TWO32 make_float32(1 << 30)
2496 #define FLOAT_TWO64 make_float64(1ULL << 62)
2497
2498 #define FP_TO_INT32_OVERFLOW 0x7fffffff
2499 #define FP_TO_INT64_OVERFLOW 0x7fffffffffffffffULL
2500
2501 /* convert MIPS rounding mode in FCR31 to IEEE library */
2502 unsigned int ieee_rm[] = {
2503     float_round_nearest_even,
2504     float_round_to_zero,
2505     float_round_up,
2506     float_round_down
2507 };
2508
2509 target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg)
2510 {
2511     target_ulong arg1 = 0;
2512
2513     switch (reg) {
2514     case 0:
2515         arg1 = (int32_t)env->active_fpu.fcr0;
2516         break;
2517     case 1:
2518         /* UFR Support - Read Status FR */
2519         if (env->active_fpu.fcr0 & (1 << FCR0_UFRP)) {
2520             if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
2521                 arg1 = (int32_t)
2522                        ((env->CP0_Status & (1  << CP0St_FR)) >> CP0St_FR);
2523             } else {
2524                 do_raise_exception(env, EXCP_RI, GETPC());
2525             }
2526         }
2527         break;
2528     case 5:
2529         /* FRE Support - read Config5.FRE bit */
2530         if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) {
2531             if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
2532                 arg1 = (env->CP0_Config5 >> CP0C5_FRE) & 1;
2533             } else {
2534                 helper_raise_exception(env, EXCP_RI);
2535             }
2536         }
2537         break;
2538     case 25:
2539         arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
2540         break;
2541     case 26:
2542         arg1 = env->active_fpu.fcr31 & 0x0003f07c;
2543         break;
2544     case 28:
2545         arg1 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4);
2546         break;
2547     default:
2548         arg1 = (int32_t)env->active_fpu.fcr31;
2549         break;
2550     }
2551
2552     return arg1;
2553 }
2554
2555 void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt)
2556 {
2557     switch (fs) {
2558     case 1:
2559         /* UFR Alias - Reset Status FR */
2560         if (!((env->active_fpu.fcr0 & (1 << FCR0_UFRP)) && (rt == 0))) {
2561             return;
2562         }
2563         if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
2564             env->CP0_Status &= ~(1 << CP0St_FR);
2565             compute_hflags(env);
2566         } else {
2567             do_raise_exception(env, EXCP_RI, GETPC());
2568         }
2569         break;
2570     case 4:
2571         /* UNFR Alias - Set Status FR */
2572         if (!((env->active_fpu.fcr0 & (1 << FCR0_UFRP)) && (rt == 0))) {
2573             return;
2574         }
2575         if (env->CP0_Config5 & (1 << CP0C5_UFR)) {
2576             env->CP0_Status |= (1 << CP0St_FR);
2577             compute_hflags(env);
2578         } else {
2579             do_raise_exception(env, EXCP_RI, GETPC());
2580         }
2581         break;
2582     case 5:
2583         /* FRE Support - clear Config5.FRE bit */
2584         if (!((env->active_fpu.fcr0 & (1 << FCR0_FREP)) && (rt == 0))) {
2585             return;
2586         }
2587         if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
2588             env->CP0_Config5 &= ~(1 << CP0C5_FRE);
2589             compute_hflags(env);
2590         } else {
2591             helper_raise_exception(env, EXCP_RI);
2592         }
2593         break;
2594     case 6:
2595         /* FRE Support - set Config5.FRE bit */
2596         if (!((env->active_fpu.fcr0 & (1 << FCR0_FREP)) && (rt == 0))) {
2597             return;
2598         }
2599         if (env->CP0_Config5 & (1 << CP0C5_UFE)) {
2600             env->CP0_Config5 |= (1 << CP0C5_FRE);
2601             compute_hflags(env);
2602         } else {
2603             helper_raise_exception(env, EXCP_RI);
2604         }
2605         break;
2606     case 25:
2607         if ((env->insn_flags & ISA_MIPS32R6) || (arg1 & 0xffffff00)) {
2608             return;
2609         }
2610         env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
2611                      ((arg1 & 0x1) << 23);
2612         break;
2613     case 26:
2614         if (arg1 & 0x007c0000)
2615             return;
2616         env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (arg1 & 0x0003f07c);
2617         break;
2618     case 28:
2619         if (arg1 & 0x007c0000)
2620             return;
2621         env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (arg1 & 0x00000f83) |
2622                      ((arg1 & 0x4) << 22);
2623         break;
2624     case 31:
2625         env->active_fpu.fcr31 = (arg1 & env->active_fpu.fcr31_rw_bitmask) |
2626                (env->active_fpu.fcr31 & ~(env->active_fpu.fcr31_rw_bitmask));
2627         break;
2628     default:
2629         return;
2630     }
2631     restore_fp_status(env);
2632     set_float_exception_flags(0, &env->active_fpu.fp_status);
2633     if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31))
2634         do_raise_exception(env, EXCP_FPE, GETPC());
2635 }
2636
2637 int ieee_ex_to_mips(int xcpt)
2638 {
2639     int ret = 0;
2640     if (xcpt) {
2641         if (xcpt & float_flag_invalid) {
2642             ret |= FP_INVALID;
2643         }
2644         if (xcpt & float_flag_overflow) {
2645             ret |= FP_OVERFLOW;
2646         }
2647         if (xcpt & float_flag_underflow) {
2648             ret |= FP_UNDERFLOW;
2649         }
2650         if (xcpt & float_flag_divbyzero) {
2651             ret |= FP_DIV0;
2652         }
2653         if (xcpt & float_flag_inexact) {
2654             ret |= FP_INEXACT;
2655         }
2656     }
2657     return ret;
2658 }
2659
2660 static inline void update_fcr31(CPUMIPSState *env, uintptr_t pc)
2661 {
2662     int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
2663
2664     SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
2665
2666     if (tmp) {
2667         set_float_exception_flags(0, &env->active_fpu.fp_status);
2668
2669         if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp) {
2670             do_raise_exception(env, EXCP_FPE, pc);
2671         } else {
2672             UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
2673         }
2674     }
2675 }
2676
2677 /* Float support.
2678    Single precition routines have a "s" suffix, double precision a
2679    "d" suffix, 32bit integer "w", 64bit integer "l", paired single "ps",
2680    paired single lower "pl", paired single upper "pu".  */
2681
2682 /* unary operations, modifying fp status  */
2683 uint64_t helper_float_sqrt_d(CPUMIPSState *env, uint64_t fdt0)
2684 {
2685     fdt0 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
2686     update_fcr31(env, GETPC());
2687     return fdt0;
2688 }
2689
2690 uint32_t helper_float_sqrt_s(CPUMIPSState *env, uint32_t fst0)
2691 {
2692     fst0 = float32_sqrt(fst0, &env->active_fpu.fp_status);
2693     update_fcr31(env, GETPC());
2694     return fst0;
2695 }
2696
2697 uint64_t helper_float_cvtd_s(CPUMIPSState *env, uint32_t fst0)
2698 {
2699     uint64_t fdt2;
2700
2701     fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
2702     fdt2 = float64_maybe_silence_nan(fdt2, &env->active_fpu.fp_status);
2703     update_fcr31(env, GETPC());
2704     return fdt2;
2705 }
2706
2707 uint64_t helper_float_cvtd_w(CPUMIPSState *env, uint32_t wt0)
2708 {
2709     uint64_t fdt2;
2710
2711     fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
2712     update_fcr31(env, GETPC());
2713     return fdt2;
2714 }
2715
2716 uint64_t helper_float_cvtd_l(CPUMIPSState *env, uint64_t dt0)
2717 {
2718     uint64_t fdt2;
2719
2720     fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
2721     update_fcr31(env, GETPC());
2722     return fdt2;
2723 }
2724
2725 uint64_t helper_float_cvt_l_d(CPUMIPSState *env, uint64_t fdt0)
2726 {
2727     uint64_t dt2;
2728
2729     dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2730     if (get_float_exception_flags(&env->active_fpu.fp_status)
2731         & (float_flag_invalid | float_flag_overflow)) {
2732         dt2 = FP_TO_INT64_OVERFLOW;
2733     }
2734     update_fcr31(env, GETPC());
2735     return dt2;
2736 }
2737
2738 uint64_t helper_float_cvt_l_s(CPUMIPSState *env, uint32_t fst0)
2739 {
2740     uint64_t dt2;
2741
2742     dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2743     if (get_float_exception_flags(&env->active_fpu.fp_status)
2744         & (float_flag_invalid | float_flag_overflow)) {
2745         dt2 = FP_TO_INT64_OVERFLOW;
2746     }
2747     update_fcr31(env, GETPC());
2748     return dt2;
2749 }
2750
2751 uint64_t helper_float_cvtps_pw(CPUMIPSState *env, uint64_t dt0)
2752 {
2753     uint32_t fst2;
2754     uint32_t fsth2;
2755
2756     fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2757     fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status);
2758     update_fcr31(env, GETPC());
2759     return ((uint64_t)fsth2 << 32) | fst2;
2760 }
2761
2762 uint64_t helper_float_cvtpw_ps(CPUMIPSState *env, uint64_t fdt0)
2763 {
2764     uint32_t wt2;
2765     uint32_t wth2;
2766     int excp, excph;
2767
2768     wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2769     excp = get_float_exception_flags(&env->active_fpu.fp_status);
2770     if (excp & (float_flag_overflow | float_flag_invalid)) {
2771         wt2 = FP_TO_INT32_OVERFLOW;
2772     }
2773
2774     set_float_exception_flags(0, &env->active_fpu.fp_status);
2775     wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status);
2776     excph = get_float_exception_flags(&env->active_fpu.fp_status);
2777     if (excph & (float_flag_overflow | float_flag_invalid)) {
2778         wth2 = FP_TO_INT32_OVERFLOW;
2779     }
2780
2781     set_float_exception_flags(excp | excph, &env->active_fpu.fp_status);
2782     update_fcr31(env, GETPC());
2783
2784     return ((uint64_t)wth2 << 32) | wt2;
2785 }
2786
2787 uint32_t helper_float_cvts_d(CPUMIPSState *env, uint64_t fdt0)
2788 {
2789     uint32_t fst2;
2790
2791     fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
2792     fst2 = float32_maybe_silence_nan(fst2, &env->active_fpu.fp_status);
2793     update_fcr31(env, GETPC());
2794     return fst2;
2795 }
2796
2797 uint32_t helper_float_cvts_w(CPUMIPSState *env, uint32_t wt0)
2798 {
2799     uint32_t fst2;
2800
2801     fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status);
2802     update_fcr31(env, GETPC());
2803     return fst2;
2804 }
2805
2806 uint32_t helper_float_cvts_l(CPUMIPSState *env, uint64_t dt0)
2807 {
2808     uint32_t fst2;
2809
2810     fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status);
2811     update_fcr31(env, GETPC());
2812     return fst2;
2813 }
2814
2815 uint32_t helper_float_cvts_pl(CPUMIPSState *env, uint32_t wt0)
2816 {
2817     uint32_t wt2;
2818
2819     wt2 = wt0;
2820     update_fcr31(env, GETPC());
2821     return wt2;
2822 }
2823
2824 uint32_t helper_float_cvts_pu(CPUMIPSState *env, uint32_t wth0)
2825 {
2826     uint32_t wt2;
2827
2828     wt2 = wth0;
2829     update_fcr31(env, GETPC());
2830     return wt2;
2831 }
2832
2833 uint32_t helper_float_cvt_w_s(CPUMIPSState *env, uint32_t fst0)
2834 {
2835     uint32_t wt2;
2836
2837     wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2838     if (get_float_exception_flags(&env->active_fpu.fp_status)
2839         & (float_flag_invalid | float_flag_overflow)) {
2840         wt2 = FP_TO_INT32_OVERFLOW;
2841     }
2842     update_fcr31(env, GETPC());
2843     return wt2;
2844 }
2845
2846 uint32_t helper_float_cvt_w_d(CPUMIPSState *env, uint64_t fdt0)
2847 {
2848     uint32_t wt2;
2849
2850     wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2851     if (get_float_exception_flags(&env->active_fpu.fp_status)
2852         & (float_flag_invalid | float_flag_overflow)) {
2853         wt2 = FP_TO_INT32_OVERFLOW;
2854     }
2855     update_fcr31(env, GETPC());
2856     return wt2;
2857 }
2858
2859 uint64_t helper_float_round_l_d(CPUMIPSState *env, uint64_t fdt0)
2860 {
2861     uint64_t dt2;
2862
2863     set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2864     dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2865     restore_rounding_mode(env);
2866     if (get_float_exception_flags(&env->active_fpu.fp_status)
2867         & (float_flag_invalid | float_flag_overflow)) {
2868         dt2 = FP_TO_INT64_OVERFLOW;
2869     }
2870     update_fcr31(env, GETPC());
2871     return dt2;
2872 }
2873
2874 uint64_t helper_float_round_l_s(CPUMIPSState *env, uint32_t fst0)
2875 {
2876     uint64_t dt2;
2877
2878     set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2879     dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2880     restore_rounding_mode(env);
2881     if (get_float_exception_flags(&env->active_fpu.fp_status)
2882         & (float_flag_invalid | float_flag_overflow)) {
2883         dt2 = FP_TO_INT64_OVERFLOW;
2884     }
2885     update_fcr31(env, GETPC());
2886     return dt2;
2887 }
2888
2889 uint32_t helper_float_round_w_d(CPUMIPSState *env, uint64_t fdt0)
2890 {
2891     uint32_t wt2;
2892
2893     set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2894     wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2895     restore_rounding_mode(env);
2896     if (get_float_exception_flags(&env->active_fpu.fp_status)
2897         & (float_flag_invalid | float_flag_overflow)) {
2898         wt2 = FP_TO_INT32_OVERFLOW;
2899     }
2900     update_fcr31(env, GETPC());
2901     return wt2;
2902 }
2903
2904 uint32_t helper_float_round_w_s(CPUMIPSState *env, uint32_t fst0)
2905 {
2906     uint32_t wt2;
2907
2908     set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2909     wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2910     restore_rounding_mode(env);
2911     if (get_float_exception_flags(&env->active_fpu.fp_status)
2912         & (float_flag_invalid | float_flag_overflow)) {
2913         wt2 = FP_TO_INT32_OVERFLOW;
2914     }
2915     update_fcr31(env, GETPC());
2916     return wt2;
2917 }
2918
2919 uint64_t helper_float_trunc_l_d(CPUMIPSState *env, uint64_t fdt0)
2920 {
2921     uint64_t dt2;
2922
2923     dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
2924     if (get_float_exception_flags(&env->active_fpu.fp_status)
2925         & (float_flag_invalid | float_flag_overflow)) {
2926         dt2 = FP_TO_INT64_OVERFLOW;
2927     }
2928     update_fcr31(env, GETPC());
2929     return dt2;
2930 }
2931
2932 uint64_t helper_float_trunc_l_s(CPUMIPSState *env, uint32_t fst0)
2933 {
2934     uint64_t dt2;
2935
2936     dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
2937     if (get_float_exception_flags(&env->active_fpu.fp_status)
2938         & (float_flag_invalid | float_flag_overflow)) {
2939         dt2 = FP_TO_INT64_OVERFLOW;
2940     }
2941     update_fcr31(env, GETPC());
2942     return dt2;
2943 }
2944
2945 uint32_t helper_float_trunc_w_d(CPUMIPSState *env, uint64_t fdt0)
2946 {
2947     uint32_t wt2;
2948
2949     wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
2950     if (get_float_exception_flags(&env->active_fpu.fp_status)
2951         & (float_flag_invalid | float_flag_overflow)) {
2952         wt2 = FP_TO_INT32_OVERFLOW;
2953     }
2954     update_fcr31(env, GETPC());
2955     return wt2;
2956 }
2957
2958 uint32_t helper_float_trunc_w_s(CPUMIPSState *env, uint32_t fst0)
2959 {
2960     uint32_t wt2;
2961
2962     wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
2963     if (get_float_exception_flags(&env->active_fpu.fp_status)
2964         & (float_flag_invalid | float_flag_overflow)) {
2965         wt2 = FP_TO_INT32_OVERFLOW;
2966     }
2967     update_fcr31(env, GETPC());
2968     return wt2;
2969 }
2970
2971 uint64_t helper_float_ceil_l_d(CPUMIPSState *env, uint64_t fdt0)
2972 {
2973     uint64_t dt2;
2974
2975     set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2976     dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2977     restore_rounding_mode(env);
2978     if (get_float_exception_flags(&env->active_fpu.fp_status)
2979         & (float_flag_invalid | float_flag_overflow)) {
2980         dt2 = FP_TO_INT64_OVERFLOW;
2981     }
2982     update_fcr31(env, GETPC());
2983     return dt2;
2984 }
2985
2986 uint64_t helper_float_ceil_l_s(CPUMIPSState *env, uint32_t fst0)
2987 {
2988     uint64_t dt2;
2989
2990     set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2991     dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2992     restore_rounding_mode(env);
2993     if (get_float_exception_flags(&env->active_fpu.fp_status)
2994         & (float_flag_invalid | float_flag_overflow)) {
2995         dt2 = FP_TO_INT64_OVERFLOW;
2996     }
2997     update_fcr31(env, GETPC());
2998     return dt2;
2999 }
3000
3001 uint32_t helper_float_ceil_w_d(CPUMIPSState *env, uint64_t fdt0)
3002 {
3003     uint32_t wt2;
3004
3005     set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3006     wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3007     restore_rounding_mode(env);
3008     if (get_float_exception_flags(&env->active_fpu.fp_status)
3009         & (float_flag_invalid | float_flag_overflow)) {
3010         wt2 = FP_TO_INT32_OVERFLOW;
3011     }
3012     update_fcr31(env, GETPC());
3013     return wt2;
3014 }
3015
3016 uint32_t helper_float_ceil_w_s(CPUMIPSState *env, uint32_t fst0)
3017 {
3018     uint32_t wt2;
3019
3020     set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3021     wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3022     restore_rounding_mode(env);
3023     if (get_float_exception_flags(&env->active_fpu.fp_status)
3024         & (float_flag_invalid | float_flag_overflow)) {
3025         wt2 = FP_TO_INT32_OVERFLOW;
3026     }
3027     update_fcr31(env, GETPC());
3028     return wt2;
3029 }
3030
3031 uint64_t helper_float_floor_l_d(CPUMIPSState *env, uint64_t fdt0)
3032 {
3033     uint64_t dt2;
3034
3035     set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3036     dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3037     restore_rounding_mode(env);
3038     if (get_float_exception_flags(&env->active_fpu.fp_status)
3039         & (float_flag_invalid | float_flag_overflow)) {
3040         dt2 = FP_TO_INT64_OVERFLOW;
3041     }
3042     update_fcr31(env, GETPC());
3043     return dt2;
3044 }
3045
3046 uint64_t helper_float_floor_l_s(CPUMIPSState *env, uint32_t fst0)
3047 {
3048     uint64_t dt2;
3049
3050     set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3051     dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3052     restore_rounding_mode(env);
3053     if (get_float_exception_flags(&env->active_fpu.fp_status)
3054         & (float_flag_invalid | float_flag_overflow)) {
3055         dt2 = FP_TO_INT64_OVERFLOW;
3056     }
3057     update_fcr31(env, GETPC());
3058     return dt2;
3059 }
3060
3061 uint32_t helper_float_floor_w_d(CPUMIPSState *env, uint64_t fdt0)
3062 {
3063     uint32_t wt2;
3064
3065     set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3066     wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3067     restore_rounding_mode(env);
3068     if (get_float_exception_flags(&env->active_fpu.fp_status)
3069         & (float_flag_invalid | float_flag_overflow)) {
3070         wt2 = FP_TO_INT32_OVERFLOW;
3071     }
3072     update_fcr31(env, GETPC());
3073     return wt2;
3074 }
3075
3076 uint32_t helper_float_floor_w_s(CPUMIPSState *env, uint32_t fst0)
3077 {
3078     uint32_t wt2;
3079
3080     set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3081     wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3082     restore_rounding_mode(env);
3083     if (get_float_exception_flags(&env->active_fpu.fp_status)
3084         & (float_flag_invalid | float_flag_overflow)) {
3085         wt2 = FP_TO_INT32_OVERFLOW;
3086     }
3087     update_fcr31(env, GETPC());
3088     return wt2;
3089 }
3090
3091 uint64_t helper_float_cvt_2008_l_d(CPUMIPSState *env, uint64_t fdt0)
3092 {
3093     uint64_t dt2;
3094
3095     dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3096     if (get_float_exception_flags(&env->active_fpu.fp_status)
3097             & float_flag_invalid) {
3098         if (float64_is_any_nan(fdt0)) {
3099             dt2 = 0;
3100         }
3101     }
3102     update_fcr31(env, GETPC());
3103     return dt2;
3104 }
3105
3106 uint64_t helper_float_cvt_2008_l_s(CPUMIPSState *env, uint32_t fst0)
3107 {
3108     uint64_t dt2;
3109
3110     dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3111     if (get_float_exception_flags(&env->active_fpu.fp_status)
3112             & float_flag_invalid) {
3113         if (float32_is_any_nan(fst0)) {
3114             dt2 = 0;
3115         }
3116     }
3117     update_fcr31(env, GETPC());
3118     return dt2;
3119 }
3120
3121 uint32_t helper_float_cvt_2008_w_d(CPUMIPSState *env, uint64_t fdt0)
3122 {
3123     uint32_t wt2;
3124
3125     wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3126     if (get_float_exception_flags(&env->active_fpu.fp_status)
3127             & float_flag_invalid) {
3128         if (float64_is_any_nan(fdt0)) {
3129             wt2 = 0;
3130         }
3131     }
3132     update_fcr31(env, GETPC());
3133     return wt2;
3134 }
3135
3136 uint32_t helper_float_cvt_2008_w_s(CPUMIPSState *env, uint32_t fst0)
3137 {
3138     uint32_t wt2;
3139
3140     wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3141     if (get_float_exception_flags(&env->active_fpu.fp_status)
3142             & float_flag_invalid) {
3143         if (float32_is_any_nan(fst0)) {
3144             wt2 = 0;
3145         }
3146     }
3147     update_fcr31(env, GETPC());
3148     return wt2;
3149 }
3150
3151 uint64_t helper_float_round_2008_l_d(CPUMIPSState *env, uint64_t fdt0)
3152 {
3153     uint64_t dt2;
3154
3155     set_float_rounding_mode(float_round_nearest_even,
3156             &env->active_fpu.fp_status);
3157     dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3158     restore_rounding_mode(env);
3159     if (get_float_exception_flags(&env->active_fpu.fp_status)
3160             & float_flag_invalid) {
3161         if (float64_is_any_nan(fdt0)) {
3162             dt2 = 0;
3163         }
3164     }
3165     update_fcr31(env, GETPC());
3166     return dt2;
3167 }
3168
3169 uint64_t helper_float_round_2008_l_s(CPUMIPSState *env, uint32_t fst0)
3170 {
3171     uint64_t dt2;
3172
3173     set_float_rounding_mode(float_round_nearest_even,
3174             &env->active_fpu.fp_status);
3175     dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3176     restore_rounding_mode(env);
3177     if (get_float_exception_flags(&env->active_fpu.fp_status)
3178             & float_flag_invalid) {
3179         if (float32_is_any_nan(fst0)) {
3180             dt2 = 0;
3181         }
3182     }
3183     update_fcr31(env, GETPC());
3184     return dt2;
3185 }
3186
3187 uint32_t helper_float_round_2008_w_d(CPUMIPSState *env, uint64_t fdt0)
3188 {
3189     uint32_t wt2;
3190
3191     set_float_rounding_mode(float_round_nearest_even,
3192             &env->active_fpu.fp_status);
3193     wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3194     restore_rounding_mode(env);
3195     if (get_float_exception_flags(&env->active_fpu.fp_status)
3196             & float_flag_invalid) {
3197         if (float64_is_any_nan(fdt0)) {
3198             wt2 = 0;
3199         }
3200     }
3201     update_fcr31(env, GETPC());
3202     return wt2;
3203 }
3204
3205 uint32_t helper_float_round_2008_w_s(CPUMIPSState *env, uint32_t fst0)
3206 {
3207     uint32_t wt2;
3208
3209     set_float_rounding_mode(float_round_nearest_even,
3210             &env->active_fpu.fp_status);
3211     wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3212     restore_rounding_mode(env);
3213     if (get_float_exception_flags(&env->active_fpu.fp_status)
3214             & float_flag_invalid) {
3215         if (float32_is_any_nan(fst0)) {
3216             wt2 = 0;
3217         }
3218     }
3219     update_fcr31(env, GETPC());
3220     return wt2;
3221 }
3222
3223 uint64_t helper_float_trunc_2008_l_d(CPUMIPSState *env, uint64_t fdt0)
3224 {
3225     uint64_t dt2;
3226
3227     dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
3228     if (get_float_exception_flags(&env->active_fpu.fp_status)
3229             & float_flag_invalid) {
3230         if (float64_is_any_nan(fdt0)) {
3231             dt2 = 0;
3232         }
3233     }
3234     update_fcr31(env, GETPC());
3235     return dt2;
3236 }
3237
3238 uint64_t helper_float_trunc_2008_l_s(CPUMIPSState *env, uint32_t fst0)
3239 {
3240     uint64_t dt2;
3241
3242     dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
3243     if (get_float_exception_flags(&env->active_fpu.fp_status)
3244             & float_flag_invalid) {
3245         if (float32_is_any_nan(fst0)) {
3246             dt2 = 0;
3247         }
3248     }
3249     update_fcr31(env, GETPC());
3250     return dt2;
3251 }
3252
3253 uint32_t helper_float_trunc_2008_w_d(CPUMIPSState *env, uint64_t fdt0)
3254 {
3255     uint32_t wt2;
3256
3257     wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
3258     if (get_float_exception_flags(&env->active_fpu.fp_status)
3259             & float_flag_invalid) {
3260         if (float64_is_any_nan(fdt0)) {
3261             wt2 = 0;
3262         }
3263     }
3264     update_fcr31(env, GETPC());
3265     return wt2;
3266 }
3267
3268 uint32_t helper_float_trunc_2008_w_s(CPUMIPSState *env, uint32_t fst0)
3269 {
3270     uint32_t wt2;
3271
3272     wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
3273     if (get_float_exception_flags(&env->active_fpu.fp_status)
3274             & float_flag_invalid) {
3275         if (float32_is_any_nan(fst0)) {
3276             wt2 = 0;
3277         }
3278     }
3279     update_fcr31(env, GETPC());
3280     return wt2;
3281 }
3282
3283 uint64_t helper_float_ceil_2008_l_d(CPUMIPSState *env, uint64_t fdt0)
3284 {
3285     uint64_t dt2;
3286
3287     set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3288     dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3289     restore_rounding_mode(env);
3290     if (get_float_exception_flags(&env->active_fpu.fp_status)
3291             & float_flag_invalid) {
3292         if (float64_is_any_nan(fdt0)) {
3293             dt2 = 0;
3294         }
3295     }
3296     update_fcr31(env, GETPC());
3297     return dt2;
3298 }
3299
3300 uint64_t helper_float_ceil_2008_l_s(CPUMIPSState *env, uint32_t fst0)
3301 {
3302     uint64_t dt2;
3303
3304     set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3305     dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3306     restore_rounding_mode(env);
3307     if (get_float_exception_flags(&env->active_fpu.fp_status)
3308             & float_flag_invalid) {
3309         if (float32_is_any_nan(fst0)) {
3310             dt2 = 0;
3311         }
3312     }
3313     update_fcr31(env, GETPC());
3314     return dt2;
3315 }
3316
3317 uint32_t helper_float_ceil_2008_w_d(CPUMIPSState *env, uint64_t fdt0)
3318 {
3319     uint32_t wt2;
3320
3321     set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3322     wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3323     restore_rounding_mode(env);
3324     if (get_float_exception_flags(&env->active_fpu.fp_status)
3325             & float_flag_invalid) {
3326         if (float64_is_any_nan(fdt0)) {
3327             wt2 = 0;
3328         }
3329     }
3330     update_fcr31(env, GETPC());
3331     return wt2;
3332 }
3333
3334 uint32_t helper_float_ceil_2008_w_s(CPUMIPSState *env, uint32_t fst0)
3335 {
3336     uint32_t wt2;
3337
3338     set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
3339     wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3340     restore_rounding_mode(env);
3341     if (get_float_exception_flags(&env->active_fpu.fp_status)
3342             & float_flag_invalid) {
3343         if (float32_is_any_nan(fst0)) {
3344             wt2 = 0;
3345         }
3346     }
3347     update_fcr31(env, GETPC());
3348     return wt2;
3349 }
3350
3351 uint64_t helper_float_floor_2008_l_d(CPUMIPSState *env, uint64_t fdt0)
3352 {
3353     uint64_t dt2;
3354
3355     set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3356     dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
3357     restore_rounding_mode(env);
3358     if (get_float_exception_flags(&env->active_fpu.fp_status)
3359             & float_flag_invalid) {
3360         if (float64_is_any_nan(fdt0)) {
3361             dt2 = 0;
3362         }
3363     }
3364     update_fcr31(env, GETPC());
3365     return dt2;
3366 }
3367
3368 uint64_t helper_float_floor_2008_l_s(CPUMIPSState *env, uint32_t fst0)
3369 {
3370     uint64_t dt2;
3371
3372     set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3373     dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
3374     restore_rounding_mode(env);
3375     if (get_float_exception_flags(&env->active_fpu.fp_status)
3376             & float_flag_invalid) {
3377         if (float32_is_any_nan(fst0)) {
3378             dt2 = 0;
3379         }
3380     }
3381     update_fcr31(env, GETPC());
3382     return dt2;
3383 }
3384
3385 uint32_t helper_float_floor_2008_w_d(CPUMIPSState *env, uint64_t fdt0)
3386 {
3387     uint32_t wt2;
3388
3389     set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3390     wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
3391     restore_rounding_mode(env);
3392     if (get_float_exception_flags(&env->active_fpu.fp_status)
3393             & float_flag_invalid) {
3394         if (float64_is_any_nan(fdt0)) {
3395             wt2 = 0;
3396         }
3397     }
3398     update_fcr31(env, GETPC());
3399     return wt2;
3400 }
3401
3402 uint32_t helper_float_floor_2008_w_s(CPUMIPSState *env, uint32_t fst0)
3403 {
3404     uint32_t wt2;
3405
3406     set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
3407     wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
3408     restore_rounding_mode(env);
3409     if (get_float_exception_flags(&env->active_fpu.fp_status)
3410             & float_flag_invalid) {
3411         if (float32_is_any_nan(fst0)) {
3412             wt2 = 0;
3413         }
3414     }
3415     update_fcr31(env, GETPC());
3416     return wt2;
3417 }
3418
3419 /* unary operations, not modifying fp status  */
3420 #define FLOAT_UNOP(name)                                       \
3421 uint64_t helper_float_ ## name ## _d(uint64_t fdt0)                \
3422 {                                                              \
3423     return float64_ ## name(fdt0);                             \
3424 }                                                              \
3425 uint32_t helper_float_ ## name ## _s(uint32_t fst0)                \
3426 {                                                              \
3427     return float32_ ## name(fst0);                             \
3428 }                                                              \
3429 uint64_t helper_float_ ## name ## _ps(uint64_t fdt0)               \
3430 {                                                              \
3431     uint32_t wt0;                                              \
3432     uint32_t wth0;                                             \
3433                                                                \
3434     wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF);                 \
3435     wth0 = float32_ ## name(fdt0 >> 32);                       \
3436     return ((uint64_t)wth0 << 32) | wt0;                       \
3437 }
3438 FLOAT_UNOP(abs)
3439 FLOAT_UNOP(chs)
3440 #undef FLOAT_UNOP
3441
3442 /* MIPS specific unary operations */
3443 uint64_t helper_float_recip_d(CPUMIPSState *env, uint64_t fdt0)
3444 {
3445     uint64_t fdt2;
3446
3447     fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
3448     update_fcr31(env, GETPC());
3449     return fdt2;
3450 }
3451
3452 uint32_t helper_float_recip_s(CPUMIPSState *env, uint32_t fst0)
3453 {
3454     uint32_t fst2;
3455
3456     fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
3457     update_fcr31(env, GETPC());
3458     return fst2;
3459 }
3460
3461 uint64_t helper_float_rsqrt_d(CPUMIPSState *env, uint64_t fdt0)
3462 {
3463     uint64_t fdt2;
3464
3465     fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
3466     fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
3467     update_fcr31(env, GETPC());
3468     return fdt2;
3469 }
3470
3471 uint32_t helper_float_rsqrt_s(CPUMIPSState *env, uint32_t fst0)
3472 {
3473     uint32_t fst2;
3474
3475     fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
3476     fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
3477     update_fcr31(env, GETPC());
3478     return fst2;
3479 }
3480
3481 uint64_t helper_float_recip1_d(CPUMIPSState *env, uint64_t fdt0)
3482 {
3483     uint64_t fdt2;
3484
3485     fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
3486     update_fcr31(env, GETPC());
3487     return fdt2;
3488 }
3489
3490 uint32_t helper_float_recip1_s(CPUMIPSState *env, uint32_t fst0)
3491 {
3492     uint32_t fst2;
3493
3494     fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
3495     update_fcr31(env, GETPC());
3496     return fst2;
3497 }
3498
3499 uint64_t helper_float_recip1_ps(CPUMIPSState *env, uint64_t fdt0)
3500 {
3501     uint32_t fst2;
3502     uint32_t fsth2;
3503
3504     fst2 = float32_div(float32_one, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
3505     fsth2 = float32_div(float32_one, fdt0 >> 32, &env->active_fpu.fp_status);
3506     update_fcr31(env, GETPC());
3507     return ((uint64_t)fsth2 << 32) | fst2;
3508 }
3509
3510 uint64_t helper_float_rsqrt1_d(CPUMIPSState *env, uint64_t fdt0)
3511 {
3512     uint64_t fdt2;
3513
3514     fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
3515     fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
3516     update_fcr31(env, GETPC());
3517     return fdt2;
3518 }
3519
3520 uint32_t helper_float_rsqrt1_s(CPUMIPSState *env, uint32_t fst0)
3521 {
3522     uint32_t fst2;
3523
3524     fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
3525     fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
3526     update_fcr31(env, GETPC());
3527     return fst2;
3528 }
3529
3530 uint64_t helper_float_rsqrt1_ps(CPUMIPSState *env, uint64_t fdt0)
3531 {
3532     uint32_t fst2;
3533     uint32_t fsth2;
3534
3535     fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
3536     fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status);
3537     fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
3538     fsth2 = float32_div(float32_one, fsth2, &env->active_fpu.fp_status);
3539     update_fcr31(env, GETPC());
3540     return ((uint64_t)fsth2 << 32) | fst2;
3541 }
3542
3543 #define FLOAT_RINT(name, bits)                                              \
3544 uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env,                \
3545                                           uint ## bits ## _t fs)            \
3546 {                                                                           \
3547     uint ## bits ## _t fdret;                                               \
3548                                                                             \
3549     fdret = float ## bits ## _round_to_int(fs, &env->active_fpu.fp_status); \
3550     update_fcr31(env, GETPC());                                             \
3551     return fdret;                                                           \
3552 }
3553
3554 FLOAT_RINT(rint_s, 32)
3555 FLOAT_RINT(rint_d, 64)
3556 #undef FLOAT_RINT
3557
3558 #define FLOAT_CLASS_SIGNALING_NAN      0x001
3559 #define FLOAT_CLASS_QUIET_NAN          0x002
3560 #define FLOAT_CLASS_NEGATIVE_INFINITY  0x004
3561 #define FLOAT_CLASS_NEGATIVE_NORMAL    0x008
3562 #define FLOAT_CLASS_NEGATIVE_SUBNORMAL 0x010
3563 #define FLOAT_CLASS_NEGATIVE_ZERO      0x020
3564 #define FLOAT_CLASS_POSITIVE_INFINITY  0x040
3565 #define FLOAT_CLASS_POSITIVE_NORMAL    0x080
3566 #define FLOAT_CLASS_POSITIVE_SUBNORMAL 0x100
3567 #define FLOAT_CLASS_POSITIVE_ZERO      0x200
3568
3569 #define FLOAT_CLASS(name, bits)                                      \
3570 uint ## bits ## _t float_ ## name (uint ## bits ## _t arg,           \
3571                                    float_status *status)             \
3572 {                                                                    \
3573     if (float ## bits ## _is_signaling_nan(arg, status)) {           \
3574         return FLOAT_CLASS_SIGNALING_NAN;                            \
3575     } else if (float ## bits ## _is_quiet_nan(arg, status)) {        \
3576         return FLOAT_CLASS_QUIET_NAN;                                \
3577     } else if (float ## bits ## _is_neg(arg)) {                      \
3578         if (float ## bits ## _is_infinity(arg)) {                    \
3579             return FLOAT_CLASS_NEGATIVE_INFINITY;                    \
3580         } else if (float ## bits ## _is_zero(arg)) {                 \
3581             return FLOAT_CLASS_NEGATIVE_ZERO;                        \
3582         } else if (float ## bits ## _is_zero_or_denormal(arg)) {     \
3583             return FLOAT_CLASS_NEGATIVE_SUBNORMAL;                   \
3584         } else {                                                     \
3585             return FLOAT_CLASS_NEGATIVE_NORMAL;                      \
3586         }                                                            \
3587     } else {                                                         \
3588         if (float ## bits ## _is_infinity(arg)) {                    \
3589             return FLOAT_CLASS_POSITIVE_INFINITY;                    \
3590         } else if (float ## bits ## _is_zero(arg)) {                 \
3591             return FLOAT_CLASS_POSITIVE_ZERO;                        \
3592         } else if (float ## bits ## _is_zero_or_denormal(arg)) {     \
3593             return FLOAT_CLASS_POSITIVE_SUBNORMAL;                   \
3594         } else {                                                     \
3595             return FLOAT_CLASS_POSITIVE_NORMAL;                      \
3596         }                                                            \
3597     }                                                                \
3598 }                                                                    \
3599                                                                      \
3600 uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env,         \
3601                                           uint ## bits ## _t arg)    \
3602 {                                                                    \
3603     return float_ ## name(arg, &env->active_fpu.fp_status);          \
3604 }
3605
3606 FLOAT_CLASS(class_s, 32)
3607 FLOAT_CLASS(class_d, 64)
3608 #undef FLOAT_CLASS
3609
3610 /* binary operations */
3611 #define FLOAT_BINOP(name)                                          \
3612 uint64_t helper_float_ ## name ## _d(CPUMIPSState *env,            \
3613                                      uint64_t fdt0, uint64_t fdt1) \
3614 {                                                                  \
3615     uint64_t dt2;                                                  \
3616                                                                    \
3617     dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status);     \
3618     update_fcr31(env, GETPC());                                    \
3619     return dt2;                                                    \
3620 }                                                                  \
3621                                                                    \
3622 uint32_t helper_float_ ## name ## _s(CPUMIPSState *env,            \
3623                                      uint32_t fst0, uint32_t fst1) \
3624 {                                                                  \
3625     uint32_t wt2;                                                  \
3626                                                                    \
3627     wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
3628     update_fcr31(env, GETPC());                                    \
3629     return wt2;                                                    \
3630 }                                                                  \
3631                                                                    \
3632 uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env,           \
3633                                       uint64_t fdt0,               \
3634                                       uint64_t fdt1)               \
3635 {                                                                  \
3636     uint32_t fst0 = fdt0 & 0XFFFFFFFF;                             \
3637     uint32_t fsth0 = fdt0 >> 32;                                   \
3638     uint32_t fst1 = fdt1 & 0XFFFFFFFF;                             \
3639     uint32_t fsth1 = fdt1 >> 32;                                   \
3640     uint32_t wt2;                                                  \
3641     uint32_t wth2;                                                 \
3642                                                                    \
3643     wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
3644     wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status);  \
3645     update_fcr31(env, GETPC());                                    \
3646     return ((uint64_t)wth2 << 32) | wt2;                           \
3647 }
3648
3649 FLOAT_BINOP(add)
3650 FLOAT_BINOP(sub)
3651 FLOAT_BINOP(mul)
3652 FLOAT_BINOP(div)
3653 #undef FLOAT_BINOP
3654
3655 /* MIPS specific binary operations */
3656 uint64_t helper_float_recip2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
3657 {
3658     fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
3659     fdt2 = float64_chs(float64_sub(fdt2, float64_one, &env->active_fpu.fp_status));
3660     update_fcr31(env, GETPC());
3661     return fdt2;
3662 }
3663
3664 uint32_t helper_float_recip2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
3665 {
3666     fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3667     fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
3668     update_fcr31(env, GETPC());
3669     return fst2;
3670 }
3671
3672 uint64_t helper_float_recip2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
3673 {
3674     uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3675     uint32_t fsth0 = fdt0 >> 32;
3676     uint32_t fst2 = fdt2 & 0XFFFFFFFF;
3677     uint32_t fsth2 = fdt2 >> 32;
3678
3679     fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3680     fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
3681     fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
3682     fsth2 = float32_chs(float32_sub(fsth2, float32_one, &env->active_fpu.fp_status));
3683     update_fcr31(env, GETPC());
3684     return ((uint64_t)fsth2 << 32) | fst2;
3685 }
3686
3687 uint64_t helper_float_rsqrt2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
3688 {
3689     fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
3690     fdt2 = float64_sub(fdt2, float64_one, &env->active_fpu.fp_status);
3691     fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status));
3692     update_fcr31(env, GETPC());
3693     return fdt2;
3694 }
3695
3696 uint32_t helper_float_rsqrt2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
3697 {
3698     fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3699     fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
3700     fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
3701     update_fcr31(env, GETPC());
3702     return fst2;
3703 }
3704
3705 uint64_t helper_float_rsqrt2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
3706 {
3707     uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3708     uint32_t fsth0 = fdt0 >> 32;
3709     uint32_t fst2 = fdt2 & 0XFFFFFFFF;
3710     uint32_t fsth2 = fdt2 >> 32;
3711
3712     fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
3713     fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
3714     fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
3715     fsth2 = float32_sub(fsth2, float32_one, &env->active_fpu.fp_status);
3716     fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
3717     fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->active_fpu.fp_status));
3718     update_fcr31(env, GETPC());
3719     return ((uint64_t)fsth2 << 32) | fst2;
3720 }
3721
3722 uint64_t helper_float_addr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
3723 {
3724     uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3725     uint32_t fsth0 = fdt0 >> 32;
3726     uint32_t fst1 = fdt1 & 0XFFFFFFFF;
3727     uint32_t fsth1 = fdt1 >> 32;
3728     uint32_t fst2;
3729     uint32_t fsth2;
3730
3731     fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status);
3732     fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status);
3733     update_fcr31(env, GETPC());
3734     return ((uint64_t)fsth2 << 32) | fst2;
3735 }
3736
3737 uint64_t helper_float_mulr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1)
3738 {
3739     uint32_t fst0 = fdt0 & 0XFFFFFFFF;
3740     uint32_t fsth0 = fdt0 >> 32;
3741     uint32_t fst1 = fdt1 & 0XFFFFFFFF;
3742     uint32_t fsth1 = fdt1 >> 32;
3743     uint32_t fst2;
3744     uint32_t fsth2;
3745
3746     fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status);
3747     fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status);
3748     update_fcr31(env, GETPC());
3749     return ((uint64_t)fsth2 << 32) | fst2;
3750 }
3751
3752 #define FLOAT_MINMAX(name, bits, minmaxfunc)                            \
3753 uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env,            \
3754                                           uint ## bits ## _t fs,        \
3755                                           uint ## bits ## _t ft)        \
3756 {                                                                       \
3757     uint ## bits ## _t fdret;                                           \
3758                                                                         \
3759     fdret = float ## bits ## _ ## minmaxfunc(fs, ft,                    \
3760                                            &env->active_fpu.fp_status); \
3761     update_fcr31(env, GETPC());                                         \
3762     return fdret;                                                       \
3763 }
3764
3765 FLOAT_MINMAX(max_s, 32, maxnum)
3766 FLOAT_MINMAX(max_d, 64, maxnum)
3767 FLOAT_MINMAX(maxa_s, 32, maxnummag)
3768 FLOAT_MINMAX(maxa_d, 64, maxnummag)
3769
3770 FLOAT_MINMAX(min_s, 32, minnum)
3771 FLOAT_MINMAX(min_d, 64, minnum)
3772 FLOAT_MINMAX(mina_s, 32, minnummag)
3773 FLOAT_MINMAX(mina_d, 64, minnummag)
3774 #undef FLOAT_MINMAX
3775
3776 /* ternary operations */
3777 #define UNFUSED_FMA(prefix, a, b, c, flags)                          \
3778 {                                                                    \
3779     a = prefix##_mul(a, b, &env->active_fpu.fp_status);              \
3780     if ((flags) & float_muladd_negate_c) {                           \
3781         a = prefix##_sub(a, c, &env->active_fpu.fp_status);          \
3782     } else {                                                         \
3783         a = prefix##_add(a, c, &env->active_fpu.fp_status);          \
3784     }                                                                \
3785     if ((flags) & float_muladd_negate_result) {                      \
3786         a = prefix##_chs(a);                                         \
3787     }                                                                \
3788 }
3789
3790 /* FMA based operations */
3791 #define FLOAT_FMA(name, type)                                        \
3792 uint64_t helper_float_ ## name ## _d(CPUMIPSState *env,              \
3793                                      uint64_t fdt0, uint64_t fdt1,   \
3794                                      uint64_t fdt2)                  \
3795 {                                                                    \
3796     UNFUSED_FMA(float64, fdt0, fdt1, fdt2, type);                    \
3797     update_fcr31(env, GETPC());                                      \
3798     return fdt0;                                                     \
3799 }                                                                    \
3800                                                                      \
3801 uint32_t helper_float_ ## name ## _s(CPUMIPSState *env,              \
3802                                      uint32_t fst0, uint32_t fst1,   \
3803                                      uint32_t fst2)                  \
3804 {                                                                    \
3805     UNFUSED_FMA(float32, fst0, fst1, fst2, type);                    \
3806     update_fcr31(env, GETPC());                                      \
3807     return fst0;                                                     \
3808 }                                                                    \
3809                                                                      \
3810 uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env,             \
3811                                       uint64_t fdt0, uint64_t fdt1,  \
3812                                       uint64_t fdt2)                 \
3813 {                                                                    \
3814     uint32_t fst0 = fdt0 & 0XFFFFFFFF;                               \
3815     uint32_t fsth0 = fdt0 >> 32;                                     \
3816     uint32_t fst1 = fdt1 & 0XFFFFFFFF;                               \
3817     uint32_t fsth1 = fdt1 >> 32;                                     \
3818     uint32_t fst2 = fdt2 & 0XFFFFFFFF;                               \
3819     uint32_t fsth2 = fdt2 >> 32;                                     \
3820                                                                      \
3821     UNFUSED_FMA(float32, fst0, fst1, fst2, type);                    \
3822     UNFUSED_FMA(float32, fsth0, fsth1, fsth2, type);                 \
3823     update_fcr31(env, GETPC());                                      \
3824     return ((uint64_t)fsth0 << 32) | fst0;                           \
3825 }
3826 FLOAT_FMA(madd, 0)
3827 FLOAT_FMA(msub, float_muladd_negate_c)
3828 FLOAT_FMA(nmadd, float_muladd_negate_result)
3829 FLOAT_FMA(nmsub, float_muladd_negate_result | float_muladd_negate_c)
3830 #undef FLOAT_FMA
3831
3832 #define FLOAT_FMADDSUB(name, bits, muladd_arg)                          \
3833 uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env,            \
3834                                           uint ## bits ## _t fs,        \
3835                                           uint ## bits ## _t ft,        \
3836                                           uint ## bits ## _t fd)        \
3837 {                                                                       \
3838     uint ## bits ## _t fdret;                                           \
3839                                                                         \
3840     fdret = float ## bits ## _muladd(fs, ft, fd, muladd_arg,            \
3841                                      &env->active_fpu.fp_status);       \
3842     update_fcr31(env, GETPC());                                         \
3843     return fdret;                                                       \
3844 }
3845
3846 FLOAT_FMADDSUB(maddf_s, 32, 0)
3847 FLOAT_FMADDSUB(maddf_d, 64, 0)
3848 FLOAT_FMADDSUB(msubf_s, 32, float_muladd_negate_product)
3849 FLOAT_FMADDSUB(msubf_d, 64, float_muladd_negate_product)
3850 #undef FLOAT_FMADDSUB
3851
3852 /* compare operations */
3853 #define FOP_COND_D(op, cond)                                   \
3854 void helper_cmp_d_ ## op(CPUMIPSState *env, uint64_t fdt0,     \
3855                          uint64_t fdt1, int cc)                \
3856 {                                                              \
3857     int c;                                                     \
3858     c = cond;                                                  \
3859     update_fcr31(env, GETPC());                                \
3860     if (c)                                                     \
3861         SET_FP_COND(cc, env->active_fpu);                      \
3862     else                                                       \
3863         CLEAR_FP_COND(cc, env->active_fpu);                    \
3864 }                                                              \
3865 void helper_cmpabs_d_ ## op(CPUMIPSState *env, uint64_t fdt0,  \
3866                             uint64_t fdt1, int cc)             \
3867 {                                                              \
3868     int c;                                                     \
3869     fdt0 = float64_abs(fdt0);                                  \
3870     fdt1 = float64_abs(fdt1);                                  \
3871     c = cond;                                                  \
3872     update_fcr31(env, GETPC());                                \
3873     if (c)                                                     \
3874         SET_FP_COND(cc, env->active_fpu);                      \
3875     else                                                       \
3876         CLEAR_FP_COND(cc, env->active_fpu);                    \
3877 }
3878
3879 /* NOTE: the comma operator will make "cond" to eval to false,
3880  * but float64_unordered_quiet() is still called. */
3881 FOP_COND_D(f,   (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
3882 FOP_COND_D(un,  float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status))
3883 FOP_COND_D(eq,  float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3884 FOP_COND_D(ueq, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3885 FOP_COND_D(olt, float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3886 FOP_COND_D(ult, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3887 FOP_COND_D(ole, float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3888 FOP_COND_D(ule, float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status))
3889 /* NOTE: the comma operator will make "cond" to eval to false,
3890  * but float64_unordered() is still called. */
3891 FOP_COND_D(sf,  (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
3892 FOP_COND_D(ngle,float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status))
3893 FOP_COND_D(seq, float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
3894 FOP_COND_D(ngl, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
3895 FOP_COND_D(lt,  float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
3896 FOP_COND_D(nge, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
3897 FOP_COND_D(le,  float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3898 FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
3899
3900 #define FOP_COND_S(op, cond)                                   \
3901 void helper_cmp_s_ ## op(CPUMIPSState *env, uint32_t fst0,     \
3902                          uint32_t fst1, int cc)                \
3903 {                                                              \
3904     int c;                                                     \
3905     c = cond;                                                  \
3906     update_fcr31(env, GETPC());                                \
3907     if (c)                                                     \
3908         SET_FP_COND(cc, env->active_fpu);                      \
3909     else                                                       \
3910         CLEAR_FP_COND(cc, env->active_fpu);                    \
3911 }                                                              \
3912 void helper_cmpabs_s_ ## op(CPUMIPSState *env, uint32_t fst0,  \
3913                             uint32_t fst1, int cc)             \
3914 {                                                              \
3915     int c;                                                     \
3916     fst0 = float32_abs(fst0);                                  \
3917     fst1 = float32_abs(fst1);                                  \
3918     c = cond;                                                  \
3919     update_fcr31(env, GETPC());                                \
3920     if (c)                                                     \
3921         SET_FP_COND(cc, env->active_fpu);                      \
3922     else                                                       \
3923         CLEAR_FP_COND(cc, env->active_fpu);                    \
3924 }
3925
3926 /* NOTE: the comma operator will make "cond" to eval to false,
3927  * but float32_unordered_quiet() is still called. */
3928 FOP_COND_S(f,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
3929 FOP_COND_S(un,  float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status))
3930 FOP_COND_S(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
3931 FOP_COND_S(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status))
3932 FOP_COND_S(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
3933 FOP_COND_S(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status))
3934 FOP_COND_S(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
3935 FOP_COND_S(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)  || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status))
3936 /* NOTE: the comma operator will make "cond" to eval to false,
3937  * but float32_unordered() is still called. */
3938 FOP_COND_S(sf,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
3939 FOP_COND_S(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status))
3940 FOP_COND_S(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status))
3941 FOP_COND_S(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
3942 FOP_COND_S(lt,  float32_lt(fst0, fst1, &env->active_fpu.fp_status))
3943 FOP_COND_S(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
3944 FOP_COND_S(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status))
3945 FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)  || float32_le(fst0, fst1, &env->active_fpu.fp_status))
3946
3947 #define FOP_COND_PS(op, condl, condh)                           \
3948 void helper_cmp_ps_ ## op(CPUMIPSState *env, uint64_t fdt0,     \
3949                           uint64_t fdt1, int cc)                \
3950 {                                                               \
3951     uint32_t fst0, fsth0, fst1, fsth1;                          \
3952     int ch, cl;                                                 \
3953     fst0 = fdt0 & 0XFFFFFFFF;                                   \
3954     fsth0 = fdt0 >> 32;                                         \
3955     fst1 = fdt1 & 0XFFFFFFFF;                                   \
3956     fsth1 = fdt1 >> 32;                                         \
3957     cl = condl;                                                 \
3958     ch = condh;                                                 \
3959     update_fcr31(env, GETPC());                                 \
3960     if (cl)                                                     \
3961         SET_FP_COND(cc, env->active_fpu);                       \
3962     else                                                        \
3963         CLEAR_FP_COND(cc, env->active_fpu);                     \
3964     if (ch)                                                     \
3965         SET_FP_COND(cc + 1, env->active_fpu);                   \
3966     else                                                        \
3967         CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
3968 }                                                               \
3969 void helper_cmpabs_ps_ ## op(CPUMIPSState *env, uint64_t fdt0,  \
3970                              uint64_t fdt1, int cc)             \
3971 {                                                               \
3972     uint32_t fst0, fsth0, fst1, fsth1;                          \
3973     int ch, cl;                                                 \
3974     fst0 = float32_abs(fdt0 & 0XFFFFFFFF);                      \
3975     fsth0 = float32_abs(fdt0 >> 32);                            \
3976     fst1 = float32_abs(fdt1 & 0XFFFFFFFF);                      \
3977     fsth1 = float32_abs(fdt1 >> 32);                            \
3978     cl = condl;                                                 \
3979     ch = condh;                                                 \
3980     update_fcr31(env, GETPC());                                 \
3981     if (cl)                                                     \
3982         SET_FP_COND(cc, env->active_fpu);                       \
3983     else                                                        \
3984         CLEAR_FP_COND(cc, env->active_fpu);                     \
3985     if (ch)                                                     \
3986         SET_FP_COND(cc + 1, env->active_fpu);                   \
3987     else                                                        \
3988         CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
3989 }
3990
3991 /* NOTE: the comma operator will make "cond" to eval to false,
3992  * but float32_unordered_quiet() is still called. */
3993 FOP_COND_PS(f,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0),
3994                  (float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status), 0))
3995 FOP_COND_PS(un,  float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status),
3996                  float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status))
3997 FOP_COND_PS(eq,  float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
3998                  float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
3999 FOP_COND_PS(ueq, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)    || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status),
4000                  float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
4001 FOP_COND_PS(olt, float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
4002                  float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
4003 FOP_COND_PS(ult, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)    || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status),
4004                  float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
4005 FOP_COND_PS(ole, float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
4006                  float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
4007 FOP_COND_PS(ule, float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)    || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status),
4008                  float32_unordered_quiet(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le_quiet(fsth0, fsth1, &env->active_fpu.fp_status))
4009 /* NOTE: the comma operator will make "cond" to eval to false,
4010  * but float32_unordered() is still called. */
4011 FOP_COND_PS(sf,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0),
4012                  (float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status), 0))
4013 FOP_COND_PS(ngle,float32_unordered(fst1, fst0, &env->active_fpu.fp_status),
4014                  float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status))
4015 FOP_COND_PS(seq, float32_eq(fst0, fst1, &env->active_fpu.fp_status),
4016                  float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
4017 FOP_COND_PS(ngl, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)    || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
4018                  float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
4019 FOP_COND_PS(lt,  float32_lt(fst0, fst1, &env->active_fpu.fp_status),
4020                  float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
4021 FOP_COND_PS(nge, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)    || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
4022                  float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
4023 FOP_COND_PS(le,  float32_le(fst0, fst1, &env->active_fpu.fp_status),
4024                  float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
4025 FOP_COND_PS(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status)    || float32_le(fst0, fst1, &env->active_fpu.fp_status),
4026                  float32_unordered(fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
4027
4028 /* R6 compare operations */
4029 #define FOP_CONDN_D(op, cond)                                       \
4030 uint64_t helper_r6_cmp_d_ ## op(CPUMIPSState * env, uint64_t fdt0,  \
4031                          uint64_t fdt1)                             \
4032 {                                                                   \
4033     uint64_t c;                                                     \
4034     c = cond;                                                       \
4035     update_fcr31(env, GETPC());                                     \
4036     if (c) {                                                        \
4037         return -1;                                                  \
4038     } else {                                                        \
4039         return 0;                                                   \
4040     }                                                               \
4041 }
4042
4043 /* NOTE: the comma operator will make "cond" to eval to false,
4044  * but float64_unordered_quiet() is still called. */
4045 FOP_CONDN_D(af,  (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status), 0))
4046 FOP_CONDN_D(un,  (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)))
4047 FOP_CONDN_D(eq,  (float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4048 FOP_CONDN_D(ueq, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4049                   || float64_eq_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4050 FOP_CONDN_D(lt,  (float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4051 FOP_CONDN_D(ult, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4052                   || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4053 FOP_CONDN_D(le,  (float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4054 FOP_CONDN_D(ule, (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4055                   || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4056 /* NOTE: the comma operator will make "cond" to eval to false,
4057  * but float64_unordered() is still called. */
4058 FOP_CONDN_D(saf,  (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status), 0))
4059 FOP_CONDN_D(sun,  (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)))
4060 FOP_CONDN_D(seq,  (float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)))
4061 FOP_CONDN_D(sueq, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
4062                    || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status)))
4063 FOP_CONDN_D(slt,  (float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
4064 FOP_CONDN_D(sult, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
4065                    || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
4066 FOP_CONDN_D(sle,  (float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
4067 FOP_CONDN_D(sule, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
4068                    || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
4069 FOP_CONDN_D(or,   (float64_le_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4070                    || float64_le_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4071 FOP_CONDN_D(une,  (float64_unordered_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4072                    || float64_lt_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4073                    || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4074 FOP_CONDN_D(ne,   (float64_lt_quiet(fdt1, fdt0, &env->active_fpu.fp_status)
4075                    || float64_lt_quiet(fdt0, fdt1, &env->active_fpu.fp_status)))
4076 FOP_CONDN_D(sor,  (float64_le(fdt1, fdt0, &env->active_fpu.fp_status)
4077                    || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)))
4078 FOP_CONDN_D(sune, (float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status)
4079                    || float64_lt(fdt1, fdt0, &env->active_fpu.fp_status)
4080                    || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
4081 FOP_CONDN_D(sne,  (float64_lt(fdt1, fdt0, &env->active_fpu.fp_status)
4082                    || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status)))
4083
4084 #define FOP_CONDN_S(op, cond)                                       \
4085 uint32_t helper_r6_cmp_s_ ## op(CPUMIPSState * env, uint32_t fst0,  \
4086                          uint32_t fst1)                             \
4087 {                                                                   \
4088     uint64_t c;                                                     \
4089     c = cond;                                                       \
4090     update_fcr31(env, GETPC());                                     \
4091     if (c) {                                                        \
4092         return -1;                                                  \
4093     } else {                                                        \
4094         return 0;                                                   \
4095     }                                                               \
4096 }
4097
4098 /* NOTE: the comma operator will make "cond" to eval to false,
4099  * but float32_unordered_quiet() is still called. */
4100 FOP_CONDN_S(af,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status), 0))
4101 FOP_CONDN_S(un,   (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)))
4102 FOP_CONDN_S(eq,   (float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4103 FOP_CONDN_S(ueq,  (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
4104                    || float32_eq_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4105 FOP_CONDN_S(lt,   (float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4106 FOP_CONDN_S(ult,  (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
4107                    || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4108 FOP_CONDN_S(le,   (float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4109 FOP_CONDN_S(ule,  (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
4110                    || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4111 /* NOTE: the comma operator will make "cond" to eval to false,
4112  * but float32_unordered() is still called. */
4113 FOP_CONDN_S(saf,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status), 0))
4114 FOP_CONDN_S(sun,  (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)))
4115 FOP_CONDN_S(seq,  (float32_eq(fst0, fst1, &env->active_fpu.fp_status)))
4116 FOP_CONDN_S(sueq, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
4117                    || float32_eq(fst0, fst1, &env->active_fpu.fp_status)))
4118 FOP_CONDN_S(slt,  (float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
4119 FOP_CONDN_S(sult, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
4120                    || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
4121 FOP_CONDN_S(sle,  (float32_le(fst0, fst1, &env->active_fpu.fp_status)))
4122 FOP_CONDN_S(sule, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
4123                    || float32_le(fst0, fst1, &env->active_fpu.fp_status)))
4124 FOP_CONDN_S(or,   (float32_le_quiet(fst1, fst0, &env->active_fpu.fp_status)
4125                    || float32_le_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4126 FOP_CONDN_S(une,  (float32_unordered_quiet(fst1, fst0, &env->active_fpu.fp_status)
4127                    || float32_lt_quiet(fst1, fst0, &env->active_fpu.fp_status)
4128                    || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4129 FOP_CONDN_S(ne,   (float32_lt_quiet(fst1, fst0, &env->active_fpu.fp_status)
4130                    || float32_lt_quiet(fst0, fst1, &env->active_fpu.fp_status)))
4131 FOP_CONDN_S(sor,  (float32_le(fst1, fst0, &env->active_fpu.fp_status)
4132                    || float32_le(fst0, fst1, &env->active_fpu.fp_status)))
4133 FOP_CONDN_S(sune, (float32_unordered(fst1, fst0, &env->active_fpu.fp_status)
4134                    || float32_lt(fst1, fst0, &env->active_fpu.fp_status)
4135                    || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
4136 FOP_CONDN_S(sne,  (float32_lt(fst1, fst0, &env->active_fpu.fp_status)
4137                    || float32_lt(fst0, fst1, &env->active_fpu.fp_status)))
4138
4139 /* MSA */
4140 /* Data format min and max values */
4141 #define DF_BITS(df) (1 << ((df) + 3))
4142
4143 /* Element-by-element access macros */
4144 #define DF_ELEMENTS(df) (MSA_WRLEN / DF_BITS(df))
4145
4146 #if !defined(CONFIG_USER_ONLY)
4147 #define MEMOP_IDX(DF)                                           \
4148         TCGMemOpIdx oi = make_memop_idx(MO_TE | DF | MO_UNALN,  \
4149                                         cpu_mmu_index(env, false));
4150 #else
4151 #define MEMOP_IDX(DF)
4152 #endif
4153
4154 #define MSA_LD_DF(DF, TYPE, LD_INSN, ...)                               \
4155 void helper_msa_ld_ ## TYPE(CPUMIPSState *env, uint32_t wd,             \
4156                             target_ulong addr)                          \
4157 {                                                                       \
4158     wr_t *pwd = &(env->active_fpu.fpr[wd].wr);                          \
4159     wr_t wx;                                                            \
4160     int i;                                                              \
4161     MEMOP_IDX(DF)                                                       \
4162     for (i = 0; i < DF_ELEMENTS(DF); i++) {                             \
4163         wx.TYPE[i] = LD_INSN(env, addr + (i << DF), ##__VA_ARGS__);     \
4164     }                                                                   \
4165     memcpy(pwd, &wx, sizeof(wr_t));                                     \
4166 }
4167
4168 #if !defined(CONFIG_USER_ONLY)
4169 MSA_LD_DF(DF_BYTE,   b, helper_ret_ldub_mmu, oi, GETPC())
4170 MSA_LD_DF(DF_HALF,   h, helper_ret_lduw_mmu, oi, GETPC())
4171 MSA_LD_DF(DF_WORD,   w, helper_ret_ldul_mmu, oi, GETPC())
4172 MSA_LD_DF(DF_DOUBLE, d, helper_ret_ldq_mmu,  oi, GETPC())
4173 #else
4174 MSA_LD_DF(DF_BYTE,   b, cpu_ldub_data)
4175 MSA_LD_DF(DF_HALF,   h, cpu_lduw_data)
4176 MSA_LD_DF(DF_WORD,   w, cpu_ldl_data)
4177 MSA_LD_DF(DF_DOUBLE, d, cpu_ldq_data)
4178 #endif
4179
4180 #define MSA_PAGESPAN(x) \
4181         ((((x) & ~TARGET_PAGE_MASK) + MSA_WRLEN/8 - 1) >= TARGET_PAGE_SIZE)
4182
4183 static inline void ensure_writable_pages(CPUMIPSState *env,
4184                                          target_ulong addr,
4185                                          int mmu_idx,
4186                                          uintptr_t retaddr)
4187 {
4188 #if !defined(CONFIG_USER_ONLY)
4189     target_ulong page_addr;
4190     if (unlikely(MSA_PAGESPAN(addr))) {
4191         /* first page */
4192         probe_write(env, addr, mmu_idx, retaddr);
4193         /* second page */
4194         page_addr = (addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
4195         probe_write(env, page_addr, mmu_idx, retaddr);
4196     }
4197 #endif
4198 }
4199
4200 #define MSA_ST_DF(DF, TYPE, ST_INSN, ...)                               \
4201 void helper_msa_st_ ## TYPE(CPUMIPSState *env, uint32_t wd,             \
4202                             target_ulong addr)                          \
4203 {                                                                       \
4204     wr_t *pwd = &(env->active_fpu.fpr[wd].wr);                          \
4205     int mmu_idx = cpu_mmu_index(env, false);                            \
4206     int i;                                                              \
4207     MEMOP_IDX(DF)                                                       \
4208     ensure_writable_pages(env, addr, mmu_idx, GETPC());                 \
4209     for (i = 0; i < DF_ELEMENTS(DF); i++) {                             \
4210         ST_INSN(env, addr + (i << DF), pwd->TYPE[i], ##__VA_ARGS__);    \
4211     }                                                                   \
4212 }
4213
4214 #if !defined(CONFIG_USER_ONLY)
4215 MSA_ST_DF(DF_BYTE,   b, helper_ret_stb_mmu, oi, GETPC())
4216 MSA_ST_DF(DF_HALF,   h, helper_ret_stw_mmu, oi, GETPC())
4217 MSA_ST_DF(DF_WORD,   w, helper_ret_stl_mmu, oi, GETPC())
4218 MSA_ST_DF(DF_DOUBLE, d, helper_ret_stq_mmu, oi, GETPC())
4219 #else
4220 MSA_ST_DF(DF_BYTE,   b, cpu_stb_data)
4221 MSA_ST_DF(DF_HALF,   h, cpu_stw_data)
4222 MSA_ST_DF(DF_WORD,   w, cpu_stl_data)
4223 MSA_ST_DF(DF_DOUBLE, d, cpu_stq_data)
4224 #endif
4225
4226 void helper_cache(CPUMIPSState *env, target_ulong addr, uint32_t op)
4227 {
4228 #ifndef CONFIG_USER_ONLY
4229     target_ulong index = addr & 0x1fffffff;
4230     if (op == 9) {
4231         /* Index Store Tag */
4232         memory_region_dispatch_write(env->itc_tag, index, env->CP0_TagLo,
4233                                      8, MEMTXATTRS_UNSPECIFIED);
4234     } else if (op == 5) {
4235         /* Index Load Tag */
4236         memory_region_dispatch_read(env->itc_tag, index, &env->CP0_TagLo,
4237                                     8, MEMTXATTRS_UNSPECIFIED);
4238     }
4239 #endif
4240 }
This page took 0.258915 seconds and 4 git commands to generate.