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