New option -net nic,model=? (Mark Glines)
[qemu] / 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, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include <stdlib.h>
21 #include "exec.h"
22
23 #define GETPC() (__builtin_return_address(0))
24
25 /*****************************************************************************/
26 /* Exceptions processing helpers */
27 void cpu_loop_exit(void)
28 {
29     longjmp(env->jmp_env, 1);
30 }
31
32 void do_raise_exception_err (uint32_t exception, int error_code)
33 {
34 #if 1
35     if (logfile && exception < 0x100)
36         fprintf(logfile, "%s: %d %d\n", __func__, exception, error_code);
37 #endif
38     env->exception_index = exception;
39     env->error_code = error_code;
40     T0 = 0;
41     cpu_loop_exit();
42 }
43
44 void do_raise_exception (uint32_t exception)
45 {
46     do_raise_exception_err(exception, 0);
47 }
48
49 void do_restore_state (void *pc_ptr)
50 {
51   TranslationBlock *tb;
52   unsigned long pc = (unsigned long) pc_ptr;
53
54   tb = tb_find_pc (pc);
55   cpu_restore_state (tb, env, pc, NULL);
56 }
57
58 void do_raise_exception_direct_err (uint32_t exception, int error_code)
59 {
60     do_restore_state (GETPC ());
61     do_raise_exception_err (exception, error_code);
62 }
63
64 void do_raise_exception_direct (uint32_t exception)
65 {
66     do_raise_exception_direct_err (exception, 0);
67 }
68
69 #define MEMSUFFIX _raw
70 #include "op_helper_mem.c"
71 #undef MEMSUFFIX
72 #if !defined(CONFIG_USER_ONLY)
73 #define MEMSUFFIX _user
74 #include "op_helper_mem.c"
75 #undef MEMSUFFIX
76 #define MEMSUFFIX _kernel
77 #include "op_helper_mem.c"
78 #undef MEMSUFFIX
79 #endif
80
81 #ifdef TARGET_MIPS64
82 #if TARGET_LONG_BITS > HOST_LONG_BITS
83 /* Those might call libgcc functions.  */
84 void do_dsll (void)
85 {
86     T0 = T0 << T1;
87 }
88
89 void do_dsll32 (void)
90 {
91     T0 = T0 << (T1 + 32);
92 }
93
94 void do_dsra (void)
95 {
96     T0 = (int64_t)T0 >> T1;
97 }
98
99 void do_dsra32 (void)
100 {
101     T0 = (int64_t)T0 >> (T1 + 32);
102 }
103
104 void do_dsrl (void)
105 {
106     T0 = T0 >> T1;
107 }
108
109 void do_dsrl32 (void)
110 {
111     T0 = T0 >> (T1 + 32);
112 }
113
114 void do_drotr (void)
115 {
116     target_ulong tmp;
117
118     if (T1) {
119        tmp = T0 << (0x40 - T1);
120        T0 = (T0 >> T1) | tmp;
121     }
122 }
123
124 void do_drotr32 (void)
125 {
126     target_ulong tmp;
127
128     if (T1) {
129        tmp = T0 << (0x40 - (32 + T1));
130        T0 = (T0 >> (32 + T1)) | tmp;
131     }
132 }
133
134 void do_dsllv (void)
135 {
136     T0 = T1 << (T0 & 0x3F);
137 }
138
139 void do_dsrav (void)
140 {
141     T0 = (int64_t)T1 >> (T0 & 0x3F);
142 }
143
144 void do_dsrlv (void)
145 {
146     T0 = T1 >> (T0 & 0x3F);
147 }
148
149 void do_drotrv (void)
150 {
151     target_ulong tmp;
152
153     T0 &= 0x3F;
154     if (T0) {
155        tmp = T1 << (0x40 - T0);
156        T0 = (T1 >> T0) | tmp;
157     } else
158        T0 = T1;
159 }
160 #endif /* TARGET_LONG_BITS > HOST_LONG_BITS */
161 #endif /* TARGET_MIPS64 */
162
163 /* 64 bits arithmetic for 32 bits hosts */
164 #if TARGET_LONG_BITS > HOST_LONG_BITS
165 static inline uint64_t get_HILO (void)
166 {
167     return (env->HI << 32) | (uint32_t)env->LO;
168 }
169
170 static inline void set_HILO (uint64_t HILO)
171 {
172     env->LO = (int32_t)HILO;
173     env->HI = (int32_t)(HILO >> 32);
174 }
175
176 void do_mult (void)
177 {
178     set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
179 }
180
181 void do_multu (void)
182 {
183     set_HILO((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
184 }
185
186 void do_madd (void)
187 {
188     int64_t tmp;
189
190     tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
191     set_HILO((int64_t)get_HILO() + tmp);
192 }
193
194 void do_maddu (void)
195 {
196     uint64_t tmp;
197
198     tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
199     set_HILO(get_HILO() + tmp);
200 }
201
202 void do_msub (void)
203 {
204     int64_t tmp;
205
206     tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
207     set_HILO((int64_t)get_HILO() - tmp);
208 }
209
210 void do_msubu (void)
211 {
212     uint64_t tmp;
213
214     tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
215     set_HILO(get_HILO() - tmp);
216 }
217 #endif
218
219 #if HOST_LONG_BITS < 64
220 void do_div (void)
221 {
222     /* 64bit datatypes because we may see overflow/underflow. */
223     if (T1 != 0) {
224         env->LO = (int32_t)((int64_t)(int32_t)T0 / (int32_t)T1);
225         env->HI = (int32_t)((int64_t)(int32_t)T0 % (int32_t)T1);
226     }
227 }
228 #endif
229
230 #ifdef TARGET_MIPS64
231 void do_ddiv (void)
232 {
233     if (T1 != 0) {
234         lldiv_t res = lldiv((int64_t)T0, (int64_t)T1);
235         env->LO = res.quot;
236         env->HI = res.rem;
237     }
238 }
239
240 void do_ddivu (void)
241 {
242     if (T1 != 0) {
243         /* XXX: lldivu? */
244         lldiv_t res = lldiv(T0, T1);
245         env->LO = (uint64_t)res.quot;
246         env->HI = (uint64_t)res.rem;
247     }
248 }
249 #endif
250
251 #if defined(CONFIG_USER_ONLY) 
252 void do_mfc0_random (void)
253 {
254     cpu_abort(env, "mfc0 random\n");
255 }
256
257 void do_mfc0_count (void)
258 {
259     cpu_abort(env, "mfc0 count\n");
260 }
261
262 void cpu_mips_store_count(CPUState *env, uint32_t value)
263 {
264     cpu_abort(env, "mtc0 count\n");
265 }
266
267 void cpu_mips_store_compare(CPUState *env, uint32_t value)
268 {
269     cpu_abort(env, "mtc0 compare\n");
270 }
271
272 void cpu_mips_update_irq(CPUState *env)
273 {
274     cpu_abort(env, "mtc0 status / mtc0 cause\n");
275 }
276
277 void do_mtc0_status_debug(uint32_t old, uint32_t val)
278 {
279     cpu_abort(env, "mtc0 status debug\n");
280 }
281
282 void do_mtc0_status_irqraise_debug (void)
283 {
284     cpu_abort(env, "mtc0 status irqraise debug\n");
285 }
286
287 void cpu_mips_tlb_flush (CPUState *env, int flush_global)
288 {
289     cpu_abort(env, "mips_tlb_flush\n");
290 }
291
292 #else
293
294 /* CP0 helpers */
295 void do_mfc0_random (void)
296 {
297     T0 = (int32_t)cpu_mips_get_random(env);
298 }
299
300 void do_mfc0_count (void)
301 {
302     T0 = (int32_t)cpu_mips_get_count(env);
303 }
304
305 void do_mtc0_status_debug(uint32_t old, uint32_t val)
306 {
307     fprintf(logfile, "Status %08x (%08x) => %08x (%08x) Cause %08x",
308             old, old & env->CP0_Cause & CP0Ca_IP_mask,
309             val, val & env->CP0_Cause & CP0Ca_IP_mask,
310             env->CP0_Cause);
311     (env->hflags & MIPS_HFLAG_UM) ? fputs(", UM\n", logfile)
312                                   : fputs("\n", logfile);
313 }
314
315 void do_mtc0_status_irqraise_debug(void)
316 {
317     fprintf(logfile, "Raise pending IRQs\n");
318 }
319
320 void fpu_handle_exception(void)
321 {
322 #ifdef CONFIG_SOFTFLOAT
323     int flags = get_float_exception_flags(&env->fp_status);
324     unsigned int cpuflags = 0, enable, cause = 0;
325
326     enable = GET_FP_ENABLE(env->fcr31);
327
328     /* determine current flags */   
329     if (flags & float_flag_invalid) {
330         cpuflags |= FP_INVALID;
331         cause |= FP_INVALID & enable;
332     }
333     if (flags & float_flag_divbyzero) {
334         cpuflags |= FP_DIV0;    
335         cause |= FP_DIV0 & enable;
336     }
337     if (flags & float_flag_overflow) {
338         cpuflags |= FP_OVERFLOW;    
339         cause |= FP_OVERFLOW & enable;
340     }
341     if (flags & float_flag_underflow) {
342         cpuflags |= FP_UNDERFLOW;   
343         cause |= FP_UNDERFLOW & enable;
344     }
345     if (flags & float_flag_inexact) {
346         cpuflags |= FP_INEXACT; 
347         cause |= FP_INEXACT & enable;
348     }
349     SET_FP_FLAGS(env->fcr31, cpuflags);
350     SET_FP_CAUSE(env->fcr31, cause);
351 #else
352     SET_FP_FLAGS(env->fcr31, 0);
353     SET_FP_CAUSE(env->fcr31, 0);
354 #endif
355 }
356
357 /* TLB management */
358 void cpu_mips_tlb_flush (CPUState *env, int flush_global)
359 {
360     /* Flush qemu's TLB and discard all shadowed entries.  */
361     tlb_flush (env, flush_global);
362     env->tlb_in_use = env->nb_tlb;
363 }
364
365 static void r4k_mips_tlb_flush_extra (CPUState *env, int first)
366 {
367     /* Discard entries from env->tlb[first] onwards.  */
368     while (env->tlb_in_use > first) {
369         r4k_invalidate_tlb(env, --env->tlb_in_use, 0);
370     }
371 }
372
373 static void r4k_fill_tlb (int idx)
374 {
375     r4k_tlb_t *tlb;
376
377     /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
378     tlb = &env->mmu.r4k.tlb[idx];
379     tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
380 #ifdef TARGET_MIPS64
381     tlb->VPN &= 0xC00000FFFFFFFFFFULL;
382 #endif
383     tlb->ASID = env->CP0_EntryHi & 0xFF;
384     tlb->PageMask = env->CP0_PageMask;
385     tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
386     tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
387     tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
388     tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
389     tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
390     tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
391     tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
392     tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
393     tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
394 }
395
396 void r4k_do_tlbwi (void)
397 {
398     /* Discard cached TLB entries.  We could avoid doing this if the
399        tlbwi is just upgrading access permissions on the current entry;
400        that might be a further win.  */
401     r4k_mips_tlb_flush_extra (env, env->nb_tlb);
402
403     r4k_invalidate_tlb(env, env->CP0_Index % env->nb_tlb, 0);
404     r4k_fill_tlb(env->CP0_Index % env->nb_tlb);
405 }
406
407 void r4k_do_tlbwr (void)
408 {
409     int r = cpu_mips_get_random(env);
410
411     r4k_invalidate_tlb(env, r, 1);
412     r4k_fill_tlb(r);
413 }
414
415 void r4k_do_tlbp (void)
416 {
417     r4k_tlb_t *tlb;
418     target_ulong mask;
419     target_ulong tag;
420     target_ulong VPN;
421     uint8_t ASID;
422     int i;
423
424     ASID = env->CP0_EntryHi & 0xFF;
425     for (i = 0; i < env->nb_tlb; i++) {
426         tlb = &env->mmu.r4k.tlb[i];
427         /* 1k pages are not supported. */
428         mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
429         tag = env->CP0_EntryHi & ~mask;
430         VPN = tlb->VPN & ~mask;
431         /* Check ASID, virtual page number & size */
432         if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
433             /* TLB match */
434             env->CP0_Index = i;
435             break;
436         }
437     }
438     if (i == env->nb_tlb) {
439         /* No match.  Discard any shadow entries, if any of them match.  */
440         for (i = env->nb_tlb; i < env->tlb_in_use; i++) {
441             tlb = &env->mmu.r4k.tlb[i];
442             /* 1k pages are not supported. */
443             mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
444             tag = env->CP0_EntryHi & ~mask;
445             VPN = tlb->VPN & ~mask;
446             /* Check ASID, virtual page number & size */
447             if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
448                 r4k_mips_tlb_flush_extra (env, i);
449                 break;
450             }
451         }
452
453         env->CP0_Index |= 0x80000000;
454     }
455 }
456
457 void r4k_do_tlbr (void)
458 {
459     r4k_tlb_t *tlb;
460     uint8_t ASID;
461
462     ASID = env->CP0_EntryHi & 0xFF;
463     tlb = &env->mmu.r4k.tlb[env->CP0_Index % env->nb_tlb];
464
465     /* If this will change the current ASID, flush qemu's TLB.  */
466     if (ASID != tlb->ASID)
467         cpu_mips_tlb_flush (env, 1);
468
469     r4k_mips_tlb_flush_extra(env, env->nb_tlb);
470
471     env->CP0_EntryHi = tlb->VPN | tlb->ASID;
472     env->CP0_PageMask = tlb->PageMask;
473     env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
474                         (tlb->C0 << 3) | (tlb->PFN[0] >> 6);
475     env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
476                         (tlb->C1 << 3) | (tlb->PFN[1] >> 6);
477 }
478
479 #endif /* !CONFIG_USER_ONLY */
480
481 void dump_ldst (const unsigned char *func)
482 {
483     if (loglevel)
484         fprintf(logfile, "%s => " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__, T0, T1);
485 }
486
487 void dump_sc (void)
488 {
489     if (loglevel) {
490         fprintf(logfile, "%s " TARGET_FMT_lx " at " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", __func__,
491                 T1, T0, env->CP0_LLAddr);
492     }
493 }
494
495 void debug_pre_eret (void)
496 {
497     fprintf(logfile, "ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
498             env->PC, env->CP0_EPC);
499     if (env->CP0_Status & (1 << CP0St_ERL))
500         fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
501     if (env->hflags & MIPS_HFLAG_DM)
502         fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC);
503     fputs("\n", logfile);
504 }
505
506 void debug_post_eret (void)
507 {
508     fprintf(logfile, "  =>  PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
509             env->PC, env->CP0_EPC);
510     if (env->CP0_Status & (1 << CP0St_ERL))
511         fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
512     if (env->hflags & MIPS_HFLAG_DM)
513         fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC);
514     if (env->hflags & MIPS_HFLAG_UM)
515         fputs(", UM\n", logfile);
516     else
517         fputs("\n", logfile);
518 }
519
520 void do_pmon (int function)
521 {
522     function /= 2;
523     switch (function) {
524     case 2: /* TODO: char inbyte(int waitflag); */
525         if (env->gpr[4] == 0)
526             env->gpr[2] = -1;
527         /* Fall through */
528     case 11: /* TODO: char inbyte (void); */
529         env->gpr[2] = -1;
530         break;
531     case 3:
532     case 12:
533         printf("%c", (char)(env->gpr[4] & 0xFF));
534         break;
535     case 17:
536         break;
537     case 158:
538         {
539             unsigned char *fmt = (void *)(unsigned long)env->gpr[4];
540             printf("%s", fmt);
541         }
542         break;
543     }
544 }
545
546 #if !defined(CONFIG_USER_ONLY) 
547
548 static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr);
549
550 #define MMUSUFFIX _mmu
551 #define ALIGNED_ONLY
552
553 #define SHIFT 0
554 #include "softmmu_template.h"
555
556 #define SHIFT 1
557 #include "softmmu_template.h"
558
559 #define SHIFT 2
560 #include "softmmu_template.h"
561
562 #define SHIFT 3
563 #include "softmmu_template.h"
564
565 static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr)
566 {
567     env->CP0_BadVAddr = addr;
568     do_restore_state (retaddr);
569     do_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL);
570 }
571
572 void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
573 {
574     TranslationBlock *tb;
575     CPUState *saved_env;
576     unsigned long pc;
577     int ret;
578
579     /* XXX: hack to restore env in all cases, even if not called from
580        generated code */
581     saved_env = env;
582     env = cpu_single_env;
583     ret = cpu_mips_handle_mmu_fault(env, addr, is_write, is_user, 1);
584     if (ret) {
585         if (retaddr) {
586             /* now we have a real cpu fault */
587             pc = (unsigned long)retaddr;
588             tb = tb_find_pc(pc);
589             if (tb) {
590                 /* the PC is inside the translated code. It means that we have
591                    a virtual CPU fault */
592                 cpu_restore_state(tb, env, pc, NULL);
593             }
594         }
595         do_raise_exception_err(env->exception_index, env->error_code);
596     }
597     env = saved_env;
598 }
599
600 #endif
601
602 /* Complex FPU operations which may need stack space. */
603
604 /* convert MIPS rounding mode in FCR31 to IEEE library */
605 unsigned int ieee_rm[] = {
606     float_round_nearest_even,
607     float_round_to_zero,
608     float_round_up,
609     float_round_down
610 };
611
612 #define RESTORE_ROUNDING_MODE \
613     set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status)
614
615 void do_ctc1 (void)
616 {
617     switch(T1) {
618     case 25:
619         if (T0 & 0xffffff00)
620             return;
621         env->fcr31 = (env->fcr31 & 0x017fffff) | ((T0 & 0xfe) << 24) |
622                      ((T0 & 0x1) << 23);
623         break;
624     case 26:
625         if (T0 & 0x007c0000)
626             return;
627         env->fcr31 = (env->fcr31 & 0xfffc0f83) | (T0 & 0x0003f07c);
628         break;
629     case 28:
630         if (T0 & 0x007c0000)
631             return;
632         env->fcr31 = (env->fcr31 & 0xfefff07c) | (T0 & 0x00000f83) |
633                      ((T0 & 0x4) << 22);
634         break;
635     case 31:
636         if (T0 & 0x007c0000)
637             return;
638         env->fcr31 = T0;
639         break;
640     default:
641         return;
642     }
643     /* set rounding mode */
644     RESTORE_ROUNDING_MODE;
645     set_float_exception_flags(0, &env->fp_status);
646     if ((GET_FP_ENABLE(env->fcr31) | 0x20) & GET_FP_CAUSE(env->fcr31))
647         do_raise_exception(EXCP_FPE);
648 }
649
650 inline char ieee_ex_to_mips(char xcpt)
651 {
652     return (xcpt & float_flag_inexact) >> 5 |
653            (xcpt & float_flag_underflow) >> 3 |
654            (xcpt & float_flag_overflow) >> 1 |
655            (xcpt & float_flag_divbyzero) << 1 |
656            (xcpt & float_flag_invalid) << 4;
657 }
658
659 inline char mips_ex_to_ieee(char xcpt)
660 {
661     return (xcpt & FP_INEXACT) << 5 |
662            (xcpt & FP_UNDERFLOW) << 3 |
663            (xcpt & FP_OVERFLOW) << 1 |
664            (xcpt & FP_DIV0) >> 1 |
665            (xcpt & FP_INVALID) >> 4;
666 }
667
668 inline void update_fcr31(void)
669 {
670     int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->fp_status));
671
672     SET_FP_CAUSE(env->fcr31, tmp);
673     if (GET_FP_ENABLE(env->fcr31) & tmp)
674         do_raise_exception(EXCP_FPE);
675     else
676         UPDATE_FP_FLAGS(env->fcr31, tmp);
677 }
678
679 #define FLOAT_OP(name, p) void do_float_##name##_##p(void)
680
681 FLOAT_OP(cvtd, s)
682 {
683     set_float_exception_flags(0, &env->fp_status);
684     FDT2 = float32_to_float64(FST0, &env->fp_status);
685     update_fcr31();
686 }
687 FLOAT_OP(cvtd, w)
688 {
689     set_float_exception_flags(0, &env->fp_status);
690     FDT2 = int32_to_float64(WT0, &env->fp_status);
691     update_fcr31();
692 }
693 FLOAT_OP(cvtd, l)
694 {
695     set_float_exception_flags(0, &env->fp_status);
696     FDT2 = int64_to_float64(DT0, &env->fp_status);
697     update_fcr31();
698 }
699 FLOAT_OP(cvtl, d)
700 {
701     set_float_exception_flags(0, &env->fp_status);
702     DT2 = float64_to_int64(FDT0, &env->fp_status);
703     update_fcr31();
704     if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
705         DT2 = 0x7fffffffffffffffULL;
706 }
707 FLOAT_OP(cvtl, s)
708 {
709     set_float_exception_flags(0, &env->fp_status);
710     DT2 = float32_to_int64(FST0, &env->fp_status);
711     update_fcr31();
712     if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
713         DT2 = 0x7fffffffffffffffULL;
714 }
715
716 FLOAT_OP(cvtps, pw)
717 {
718     set_float_exception_flags(0, &env->fp_status);
719     FST2 = int32_to_float32(WT0, &env->fp_status);
720     FSTH2 = int32_to_float32(WTH0, &env->fp_status);
721     update_fcr31();
722 }
723 FLOAT_OP(cvtpw, ps)
724 {
725     set_float_exception_flags(0, &env->fp_status);
726     WT2 = float32_to_int32(FST0, &env->fp_status);
727     WTH2 = float32_to_int32(FSTH0, &env->fp_status);
728     update_fcr31();
729     if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
730         WT2 = 0x7fffffff;
731 }
732 FLOAT_OP(cvts, d)
733 {
734     set_float_exception_flags(0, &env->fp_status);
735     FST2 = float64_to_float32(FDT0, &env->fp_status);
736     update_fcr31();
737 }
738 FLOAT_OP(cvts, w)
739 {
740     set_float_exception_flags(0, &env->fp_status);
741     FST2 = int32_to_float32(WT0, &env->fp_status);
742     update_fcr31();
743 }
744 FLOAT_OP(cvts, l)
745 {
746     set_float_exception_flags(0, &env->fp_status);
747     FST2 = int64_to_float32(DT0, &env->fp_status);
748     update_fcr31();
749 }
750 FLOAT_OP(cvts, pl)
751 {
752     set_float_exception_flags(0, &env->fp_status);
753     WT2 = WT0;
754     update_fcr31();
755 }
756 FLOAT_OP(cvts, pu)
757 {
758     set_float_exception_flags(0, &env->fp_status);
759     WT2 = WTH0;
760     update_fcr31();
761 }
762 FLOAT_OP(cvtw, s)
763 {
764     set_float_exception_flags(0, &env->fp_status);
765     WT2 = float32_to_int32(FST0, &env->fp_status);
766     update_fcr31();
767     if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
768         WT2 = 0x7fffffff;
769 }
770 FLOAT_OP(cvtw, d)
771 {
772     set_float_exception_flags(0, &env->fp_status);
773     WT2 = float64_to_int32(FDT0, &env->fp_status);
774     update_fcr31();
775     if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
776         WT2 = 0x7fffffff;
777 }
778
779 FLOAT_OP(roundl, d)
780 {
781     set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
782     DT2 = float64_round_to_int(FDT0, &env->fp_status);
783     RESTORE_ROUNDING_MODE;
784     update_fcr31();
785     if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
786         DT2 = 0x7fffffffffffffffULL;
787 }
788 FLOAT_OP(roundl, s)
789 {
790     set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
791     DT2 = float32_round_to_int(FST0, &env->fp_status);
792     RESTORE_ROUNDING_MODE;
793     update_fcr31();
794     if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
795         DT2 = 0x7fffffffffffffffULL;
796 }
797 FLOAT_OP(roundw, d)
798 {
799     set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
800     WT2 = float64_round_to_int(FDT0, &env->fp_status);
801     RESTORE_ROUNDING_MODE;
802     update_fcr31();
803     if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
804         WT2 = 0x7fffffff;
805 }
806 FLOAT_OP(roundw, s)
807 {
808     set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
809     WT2 = float32_round_to_int(FST0, &env->fp_status);
810     RESTORE_ROUNDING_MODE;
811     update_fcr31();
812     if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
813         WT2 = 0x7fffffff;
814 }
815
816 FLOAT_OP(truncl, d)
817 {
818     DT2 = float64_to_int64_round_to_zero(FDT0, &env->fp_status);
819     update_fcr31();
820     if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
821         DT2 = 0x7fffffffffffffffULL;
822 }
823 FLOAT_OP(truncl, s)
824 {
825     DT2 = float32_to_int64_round_to_zero(FST0, &env->fp_status);
826     update_fcr31();
827     if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
828         DT2 = 0x7fffffffffffffffULL;
829 }
830 FLOAT_OP(truncw, d)
831 {
832     WT2 = float64_to_int32_round_to_zero(FDT0, &env->fp_status);
833     update_fcr31();
834     if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
835         WT2 = 0x7fffffff;
836 }
837 FLOAT_OP(truncw, s)
838 {
839     WT2 = float32_to_int32_round_to_zero(FST0, &env->fp_status);
840     update_fcr31();
841     if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
842         WT2 = 0x7fffffff;
843 }
844
845 FLOAT_OP(ceill, d)
846 {
847     set_float_rounding_mode(float_round_up, &env->fp_status);
848     DT2 = float64_round_to_int(FDT0, &env->fp_status);
849     RESTORE_ROUNDING_MODE;
850     update_fcr31();
851     if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
852         DT2 = 0x7fffffffffffffffULL;
853 }
854 FLOAT_OP(ceill, s)
855 {
856     set_float_rounding_mode(float_round_up, &env->fp_status);
857     DT2 = float32_round_to_int(FST0, &env->fp_status);
858     RESTORE_ROUNDING_MODE;
859     update_fcr31();
860     if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
861         DT2 = 0x7fffffffffffffffULL;
862 }
863 FLOAT_OP(ceilw, d)
864 {
865     set_float_rounding_mode(float_round_up, &env->fp_status);
866     WT2 = float64_round_to_int(FDT0, &env->fp_status);
867     RESTORE_ROUNDING_MODE;
868     update_fcr31();
869     if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
870         WT2 = 0x7fffffff;
871 }
872 FLOAT_OP(ceilw, s)
873 {
874     set_float_rounding_mode(float_round_up, &env->fp_status);
875     WT2 = float32_round_to_int(FST0, &env->fp_status);
876     RESTORE_ROUNDING_MODE;
877     update_fcr31();
878     if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
879         WT2 = 0x7fffffff;
880 }
881
882 FLOAT_OP(floorl, d)
883 {
884     set_float_rounding_mode(float_round_down, &env->fp_status);
885     DT2 = float64_round_to_int(FDT0, &env->fp_status);
886     RESTORE_ROUNDING_MODE;
887     update_fcr31();
888     if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
889         DT2 = 0x7fffffffffffffffULL;
890 }
891 FLOAT_OP(floorl, s)
892 {
893     set_float_rounding_mode(float_round_down, &env->fp_status);
894     DT2 = float32_round_to_int(FST0, &env->fp_status);
895     RESTORE_ROUNDING_MODE;
896     update_fcr31();
897     if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
898         DT2 = 0x7fffffffffffffffULL;
899 }
900 FLOAT_OP(floorw, d)
901 {
902     set_float_rounding_mode(float_round_down, &env->fp_status);
903     WT2 = float64_round_to_int(FDT0, &env->fp_status);
904     RESTORE_ROUNDING_MODE;
905     update_fcr31();
906     if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
907         WT2 = 0x7fffffff;
908 }
909 FLOAT_OP(floorw, s)
910 {
911     set_float_rounding_mode(float_round_down, &env->fp_status);
912     WT2 = float32_round_to_int(FST0, &env->fp_status);
913     RESTORE_ROUNDING_MODE;
914     update_fcr31();
915     if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
916         WT2 = 0x7fffffff;
917 }
918
919 /* unary operations, MIPS specific, s and d */
920 #define FLOAT_UNOP(name)  \
921 FLOAT_OP(name, d)         \
922 {                         \
923     set_float_exception_flags(0, &env->fp_status);            \
924 /* XXX: not implemented */ \
925 /*    FDT2 = float64_ ## name (FDT0, &env->fp_status);*/          \
926 do_raise_exception(EXCP_RI); \
927     update_fcr31();       \
928 }                         \
929 FLOAT_OP(name, s)         \
930 {                         \
931     set_float_exception_flags(0, &env->fp_status);            \
932 /* XXX: not implemented */ \
933 /*    FST2 = float32_ ## name (FST0, &env->fp_status);*/          \
934 do_raise_exception(EXCP_RI); \
935     update_fcr31();       \
936 }
937 FLOAT_UNOP(rsqrt)
938 FLOAT_UNOP(recip)
939 #undef FLOAT_UNOP
940
941 /* unary operations, MIPS specific, s, d and ps */
942 #define FLOAT_UNOP(name)  \
943 FLOAT_OP(name, d)         \
944 {                         \
945     set_float_exception_flags(0, &env->fp_status);            \
946 /* XXX: not implemented */ \
947 /*    FDT2 = float64_ ## name (FDT0, &env->fp_status);*/          \
948 do_raise_exception(EXCP_RI); \
949     update_fcr31();       \
950 }                         \
951 FLOAT_OP(name, s)         \
952 {                         \
953     set_float_exception_flags(0, &env->fp_status);            \
954 /* XXX: not implemented */ \
955 /*    FST2 = float32_ ## name (FST0, &env->fp_status);*/          \
956 do_raise_exception(EXCP_RI); \
957     update_fcr31();       \
958 }                         \
959 FLOAT_OP(name, ps)        \
960 {                         \
961     set_float_exception_flags(0, &env->fp_status);            \
962 /* XXX: not implemented */ \
963 /*    FST2 = float32_ ## name (FST0, &env->fp_status);*/          \
964 /*    FSTH2 = float32_ ## name (FSTH0, &env->fp_status);*/        \
965 do_raise_exception(EXCP_RI); \
966     update_fcr31();       \
967 }
968 FLOAT_UNOP(rsqrt1)
969 FLOAT_UNOP(recip1)
970 #undef FLOAT_UNOP
971
972 /* binary operations */
973 #define FLOAT_BINOP(name) \
974 FLOAT_OP(name, d)         \
975 {                         \
976     set_float_exception_flags(0, &env->fp_status);            \
977     FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status);    \
978     update_fcr31();                                           \
979     if (GET_FP_CAUSE(env->fcr31) & FP_INVALID)                \
980         FDT2 = 0x7ff7ffffffffffffULL;                         \
981     else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) {       \
982         if ((env->fcr31 & 0x3) == 0)                          \
983             FDT2 &= 0x8000000000000000ULL;                    \
984     }                     \
985 }                         \
986 FLOAT_OP(name, s)         \
987 {                         \
988     set_float_exception_flags(0, &env->fp_status);            \
989     FST2 = float32_ ## name (FST0, FST1, &env->fp_status);    \
990     update_fcr31();                                           \
991     if (GET_FP_CAUSE(env->fcr31) & FP_INVALID)                \
992         FST2 = 0x7fbfffff;                                    \
993     else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) {       \
994         if ((env->fcr31 & 0x3) == 0)                          \
995             FST2 &= 0x80000000ULL;                            \
996     }                     \
997 }                         \
998 FLOAT_OP(name, ps)        \
999 {                         \
1000     set_float_exception_flags(0, &env->fp_status);            \
1001     FST2 = float32_ ## name (FST0, FST1, &env->fp_status);    \
1002     FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fp_status); \
1003     update_fcr31();       \
1004     if (GET_FP_CAUSE(env->fcr31) & FP_INVALID) {              \
1005         FST2 = 0x7fbfffff;                                    \
1006         FSTH2 = 0x7fbfffff;                                   \
1007     } else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) {     \
1008         if ((env->fcr31 & 0x3) == 0) {                        \
1009             FST2 &= 0x80000000ULL;                            \
1010             FSTH2 &= 0x80000000ULL;                           \
1011         }                 \
1012     }                     \
1013 }
1014 FLOAT_BINOP(add)
1015 FLOAT_BINOP(sub)
1016 FLOAT_BINOP(mul)
1017 FLOAT_BINOP(div)
1018 #undef FLOAT_BINOP
1019
1020 /* binary operations, MIPS specific */
1021 #define FLOAT_BINOP(name) \
1022 FLOAT_OP(name, d)         \
1023 {                         \
1024     set_float_exception_flags(0, &env->fp_status);            \
1025 /* XXX: not implemented */ \
1026 /*    FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status);*/    \
1027 do_raise_exception(EXCP_RI); \
1028     update_fcr31();       \
1029 }                         \
1030 FLOAT_OP(name, s)         \
1031 {                         \
1032     set_float_exception_flags(0, &env->fp_status);            \
1033 /* XXX: not implemented */ \
1034 /*    FST2 = float32_ ## name (FST0, FST1, &env->fp_status);*/    \
1035 do_raise_exception(EXCP_RI); \
1036     update_fcr31();       \
1037 }                         \
1038 FLOAT_OP(name, ps)        \
1039 {                         \
1040     set_float_exception_flags(0, &env->fp_status);            \
1041 /* XXX: not implemented */ \
1042 /*    FST2 = float32_ ## name (FST0, FST1, &env->fp_status);*/    \
1043 /*    FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fp_status);*/ \
1044 do_raise_exception(EXCP_RI); \
1045     update_fcr31();       \
1046 }
1047 FLOAT_BINOP(rsqrt2)
1048 FLOAT_BINOP(recip2)
1049 #undef FLOAT_BINOP
1050
1051 FLOAT_OP(addr, ps)
1052 {
1053     set_float_exception_flags(0, &env->fp_status);
1054     FST2 = float32_add (FST0, FSTH0, &env->fp_status);
1055     FSTH2 = float32_add (FST1, FSTH1, &env->fp_status);
1056     update_fcr31();
1057 }
1058
1059 FLOAT_OP(mulr, ps)
1060 {
1061     set_float_exception_flags(0, &env->fp_status);
1062     FST2 = float32_mul (FST0, FSTH0, &env->fp_status);
1063     FSTH2 = float32_mul (FST1, FSTH1, &env->fp_status);
1064     update_fcr31();
1065 }
1066
1067 #define FOP_COND_D(op, cond)                   \
1068 void do_cmp_d_ ## op (long cc)                 \
1069 {                                              \
1070     int c = cond;                              \
1071     update_fcr31();                            \
1072     if (c)                                     \
1073         SET_FP_COND(cc, env);                  \
1074     else                                       \
1075         CLEAR_FP_COND(cc, env);                \
1076 }                                              \
1077 void do_cmpabs_d_ ## op (long cc)              \
1078 {                                              \
1079     int c;                                     \
1080     FDT0 &= ~(1ULL << 63);                     \
1081     FDT1 &= ~(1ULL << 63);                     \
1082     c = cond;                                  \
1083     update_fcr31();                            \
1084     if (c)                                     \
1085         SET_FP_COND(cc, env);                  \
1086     else                                       \
1087         CLEAR_FP_COND(cc, env);                \
1088 }
1089
1090 int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM)
1091 {
1092     if (float64_is_signaling_nan(a) ||
1093         float64_is_signaling_nan(b) ||
1094         (sig && (float64_is_nan(a) || float64_is_nan(b)))) {
1095         float_raise(float_flag_invalid, status);
1096         return 1;
1097     } else if (float64_is_nan(a) || float64_is_nan(b)) {
1098         return 1;
1099     } else {
1100         return 0;
1101     }
1102 }
1103
1104 /* NOTE: the comma operator will make "cond" to eval to false,
1105  * but float*_is_unordered() is still called. */
1106 FOP_COND_D(f,   (float64_is_unordered(0, FDT1, FDT0, &env->fp_status), 0))
1107 FOP_COND_D(un,  float64_is_unordered(0, FDT1, FDT0, &env->fp_status))
1108 FOP_COND_D(eq,  !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status))
1109 FOP_COND_D(ueq, float64_is_unordered(0, FDT1, FDT0, &env->fp_status)  || float64_eq(FDT0, FDT1, &env->fp_status))
1110 FOP_COND_D(olt, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status))
1111 FOP_COND_D(ult, float64_is_unordered(0, FDT1, FDT0, &env->fp_status)  || float64_lt(FDT0, FDT1, &env->fp_status))
1112 FOP_COND_D(ole, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status))
1113 FOP_COND_D(ule, float64_is_unordered(0, FDT1, FDT0, &env->fp_status)  || float64_le(FDT0, FDT1, &env->fp_status))
1114 /* NOTE: the comma operator will make "cond" to eval to false,
1115  * but float*_is_unordered() is still called. */
1116 FOP_COND_D(sf,  (float64_is_unordered(1, FDT1, FDT0, &env->fp_status), 0))
1117 FOP_COND_D(ngle,float64_is_unordered(1, FDT1, FDT0, &env->fp_status))
1118 FOP_COND_D(seq, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status))
1119 FOP_COND_D(ngl, float64_is_unordered(1, FDT1, FDT0, &env->fp_status)  || float64_eq(FDT0, FDT1, &env->fp_status))
1120 FOP_COND_D(lt,  !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status))
1121 FOP_COND_D(nge, float64_is_unordered(1, FDT1, FDT0, &env->fp_status)  || float64_lt(FDT0, FDT1, &env->fp_status))
1122 FOP_COND_D(le,  !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status))
1123 FOP_COND_D(ngt, float64_is_unordered(1, FDT1, FDT0, &env->fp_status)  || float64_le(FDT0, FDT1, &env->fp_status))
1124
1125 #define FOP_COND_S(op, cond)                   \
1126 void do_cmp_s_ ## op (long cc)                 \
1127 {                                              \
1128     int c = cond;                              \
1129     update_fcr31();                            \
1130     if (c)                                     \
1131         SET_FP_COND(cc, env);                  \
1132     else                                       \
1133         CLEAR_FP_COND(cc, env);                \
1134 }                                              \
1135 void do_cmpabs_s_ ## op (long cc)              \
1136 {                                              \
1137     int c;                                     \
1138     FST0 &= ~(1 << 31);                        \
1139     FST1 &= ~(1 << 31);                        \
1140     c = cond;                                  \
1141     update_fcr31();                            \
1142     if (c)                                     \
1143         SET_FP_COND(cc, env);                  \
1144     else                                       \
1145         CLEAR_FP_COND(cc, env);                \
1146 }
1147
1148 flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM)
1149 {
1150     extern flag float32_is_nan(float32 a);
1151     if (float32_is_signaling_nan(a) ||
1152         float32_is_signaling_nan(b) ||
1153         (sig && (float32_is_nan(a) || float32_is_nan(b)))) {
1154         float_raise(float_flag_invalid, status);
1155         return 1;
1156     } else if (float32_is_nan(a) || float32_is_nan(b)) {
1157         return 1;
1158     } else {
1159         return 0;
1160     }
1161 }
1162
1163 /* NOTE: the comma operator will make "cond" to eval to false,
1164  * but float*_is_unordered() is still called. */
1165 FOP_COND_S(f,   (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0))
1166 FOP_COND_S(un,  float32_is_unordered(0, FST1, FST0, &env->fp_status))
1167 FOP_COND_S(eq,  !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status))
1168 FOP_COND_S(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status)  || float32_eq(FST0, FST1, &env->fp_status))
1169 FOP_COND_S(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status))
1170 FOP_COND_S(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status)  || float32_lt(FST0, FST1, &env->fp_status))
1171 FOP_COND_S(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status))
1172 FOP_COND_S(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status)  || float32_le(FST0, FST1, &env->fp_status))
1173 /* NOTE: the comma operator will make "cond" to eval to false,
1174  * but float*_is_unordered() is still called. */
1175 FOP_COND_S(sf,  (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0))
1176 FOP_COND_S(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status))
1177 FOP_COND_S(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status))
1178 FOP_COND_S(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status)  || float32_eq(FST0, FST1, &env->fp_status))
1179 FOP_COND_S(lt,  !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status))
1180 FOP_COND_S(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status)  || float32_lt(FST0, FST1, &env->fp_status))
1181 FOP_COND_S(le,  !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status))
1182 FOP_COND_S(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status)  || float32_le(FST0, FST1, &env->fp_status))
1183
1184 #define FOP_COND_PS(op, condl, condh)          \
1185 void do_cmp_ps_ ## op (long cc)                \
1186 {                                              \
1187     int cl = condl;                            \
1188     int ch = condh;                            \
1189     update_fcr31();                            \
1190     if (cl)                                    \
1191         SET_FP_COND(cc, env);                  \
1192     else                                       \
1193         CLEAR_FP_COND(cc, env);                \
1194     if (ch)                                    \
1195         SET_FP_COND(cc + 1, env);              \
1196     else                                       \
1197         CLEAR_FP_COND(cc + 1, env);            \
1198 }                                              \
1199 void do_cmpabs_ps_ ## op (long cc)             \
1200 {                                              \
1201     int cl, ch;                                \
1202     FST0 &= ~(1 << 31);                        \
1203     FSTH0 &= ~(1 << 31);                       \
1204     FST1 &= ~(1 << 31);                        \
1205     FSTH1 &= ~(1 << 31);                       \
1206     cl = condl;                                \
1207     ch = condh;                                \
1208     update_fcr31();                            \
1209     if (cl)                                    \
1210         SET_FP_COND(cc, env);                  \
1211     else                                       \
1212         CLEAR_FP_COND(cc, env);                \
1213     if (ch)                                    \
1214         SET_FP_COND(cc + 1, env);              \
1215     else                                       \
1216         CLEAR_FP_COND(cc + 1, env);            \
1217 }
1218
1219 /* NOTE: the comma operator will make "cond" to eval to false,
1220  * but float*_is_unordered() is still called. */
1221 FOP_COND_PS(f,   (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0),
1222                  (float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status), 0))
1223 FOP_COND_PS(un,  float32_is_unordered(0, FST1, FST0, &env->fp_status),
1224                  float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status))
1225 FOP_COND_PS(eq,  !float32_is_unordered(0, FST1, FST0, &env->fp_status)   && float32_eq(FST0, FST1, &env->fp_status),
1226                  !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status))
1227 FOP_COND_PS(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status)    || float32_eq(FST0, FST1, &env->fp_status),
1228                  float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status)  || float32_eq(FSTH0, FSTH1, &env->fp_status))
1229 FOP_COND_PS(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status)   && float32_lt(FST0, FST1, &env->fp_status),
1230                  !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status))
1231 FOP_COND_PS(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status)    || float32_lt(FST0, FST1, &env->fp_status),
1232                  float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status)  || float32_lt(FSTH0, FSTH1, &env->fp_status))
1233 FOP_COND_PS(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status)   && float32_le(FST0, FST1, &env->fp_status),
1234                  !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status))
1235 FOP_COND_PS(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status)    || float32_le(FST0, FST1, &env->fp_status),
1236                  float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status)  || float32_le(FSTH0, FSTH1, &env->fp_status))
1237 /* NOTE: the comma operator will make "cond" to eval to false,
1238  * but float*_is_unordered() is still called. */
1239 FOP_COND_PS(sf,  (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0),
1240                  (float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status), 0))
1241 FOP_COND_PS(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status),
1242                  float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status))
1243 FOP_COND_PS(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status)   && float32_eq(FST0, FST1, &env->fp_status),
1244                  !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status))
1245 FOP_COND_PS(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status)    || float32_eq(FST0, FST1, &env->fp_status),
1246                  float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status)  || float32_eq(FSTH0, FSTH1, &env->fp_status))
1247 FOP_COND_PS(lt,  !float32_is_unordered(1, FST1, FST0, &env->fp_status)   && float32_lt(FST0, FST1, &env->fp_status),
1248                  !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status))
1249 FOP_COND_PS(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status)    || float32_lt(FST0, FST1, &env->fp_status),
1250                  float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status)  || float32_lt(FSTH0, FSTH1, &env->fp_status))
1251 FOP_COND_PS(le,  !float32_is_unordered(1, FST1, FST0, &env->fp_status)   && float32_le(FST0, FST1, &env->fp_status),
1252                  !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status))
1253 FOP_COND_PS(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status)    || float32_le(FST0, FST1, &env->fp_status),
1254                  float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status)  || float32_le(FSTH0, FSTH1, &env->fp_status))