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