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