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