Statistics
| Branch: | Revision:

root / target-mips / op_helper.c @ 05f778c8

History | View | Annotate | Download (42.7 kB)

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
#include "host-utils.h"
24

    
25
#define GETPC() (__builtin_return_address(0))
26

    
27
/*****************************************************************************/
28
/* Exceptions processing helpers */
29

    
30
void do_raise_exception_err (uint32_t exception, int error_code)
31
{
32
#if 1
33
    if (logfile && exception < 0x100)
34
        fprintf(logfile, "%s: %d %d\n", __func__, exception, error_code);
35
#endif
36
    env->exception_index = exception;
37
    env->error_code = error_code;
38
    T0 = 0;
39
    cpu_loop_exit();
40
}
41

    
42
void do_raise_exception (uint32_t exception)
43
{
44
    do_raise_exception_err(exception, 0);
45
}
46

    
47
void do_restore_state (void *pc_ptr)
48
{
49
  TranslationBlock *tb;
50
  unsigned long pc = (unsigned long) pc_ptr;
51

    
52
  tb = tb_find_pc (pc);
53
  cpu_restore_state (tb, env, pc, NULL);
54
}
55

    
56
void do_raise_exception_direct_err (uint32_t exception, int error_code)
57
{
58
    do_restore_state (GETPC ());
59
    do_raise_exception_err (exception, error_code);
60
}
61

    
62
void do_raise_exception_direct (uint32_t exception)
63
{
64
    do_raise_exception_direct_err (exception, 0);
65
}
66

    
67
#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
68
#if TARGET_LONG_BITS > HOST_LONG_BITS
69
/* Those might call libgcc functions.  */
70
void do_dsll (void)
71
{
72
    T0 = T0 << T1;
73
}
74

    
75
void do_dsll32 (void)
76
{
77
    T0 = T0 << (T1 + 32);
78
}
79

    
80
void do_dsra (void)
81
{
82
    T0 = (int64_t)T0 >> T1;
83
}
84

    
85
void do_dsra32 (void)
86
{
87
    T0 = (int64_t)T0 >> (T1 + 32);
88
}
89

    
90
void do_dsrl (void)
91
{
92
    T0 = T0 >> T1;
93
}
94

    
95
void do_dsrl32 (void)
96
{
97
    T0 = T0 >> (T1 + 32);
98
}
99

    
100
void do_drotr (void)
101
{
102
    target_ulong tmp;
103

    
104
    if (T1) {
105
       tmp = T0 << (0x40 - T1);
106
       T0 = (T0 >> T1) | tmp;
107
    }
108
}
109

    
110
void do_drotr32 (void)
111
{
112
    target_ulong tmp;
113

    
114
    if (T1) {
115
       tmp = T0 << (0x40 - (32 + T1));
116
       T0 = (T0 >> (32 + T1)) | tmp;
117
    }
118
}
119

    
120
void do_dsllv (void)
121
{
122
    T0 = T1 << (T0 & 0x3F);
123
}
124

    
125
void do_dsrav (void)
126
{
127
    T0 = (int64_t)T1 >> (T0 & 0x3F);
128
}
129

    
130
void do_dsrlv (void)
131
{
132
    T0 = T1 >> (T0 & 0x3F);
133
}
134

    
135
void do_drotrv (void)
136
{
137
    target_ulong tmp;
138

    
139
    T0 &= 0x3F;
140
    if (T0) {
141
       tmp = T1 << (0x40 - T0);
142
       T0 = (T1 >> T0) | tmp;
143
    } else
144
       T0 = T1;
145
}
146

    
147
void do_dclo (void)
148
{
149
    T0 = clo64(T0);
150
}
151

    
152
void do_dclz (void)
153
{
154
    T0 = clz64(T0);
155
}
156

    
157
#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */
158
#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */
159

    
160
/* 64 bits arithmetic for 32 bits hosts */
161
#if TARGET_LONG_BITS > HOST_LONG_BITS
162
static always_inline uint64_t get_HILO (void)
163
{
164
    return (env->HI[0][env->current_tc] << 32) | (uint32_t)env->LO[0][env->current_tc];
165
}
166

    
167
static always_inline void set_HILO (uint64_t HILO)
168
{
169
    env->LO[0][env->current_tc] = (int32_t)HILO;
170
    env->HI[0][env->current_tc] = (int32_t)(HILO >> 32);
171
}
172

    
173
void do_mult (void)
174
{
175
    set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
176
}
177

    
178
void do_multu (void)
179
{
180
    set_HILO((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
181
}
182

    
183
void do_madd (void)
184
{
185
    int64_t tmp;
186

    
187
    tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
188
    set_HILO((int64_t)get_HILO() + tmp);
189
}
190

    
191
void do_maddu (void)
192
{
193
    uint64_t tmp;
194

    
195
    tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
196
    set_HILO(get_HILO() + tmp);
197
}
198

    
199
void do_msub (void)
200
{
201
    int64_t tmp;
202

    
203
    tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
204
    set_HILO((int64_t)get_HILO() - tmp);
205
}
206

    
207
void do_msubu (void)
208
{
209
    uint64_t tmp;
210

    
211
    tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
212
    set_HILO(get_HILO() - tmp);
213
}
214
#endif
215

    
216
#if HOST_LONG_BITS < 64
217
void do_div (void)
218
{
219
    /* 64bit datatypes because we may see overflow/underflow. */
220
    if (T1 != 0) {
221
        env->LO[0][env->current_tc] = (int32_t)((int64_t)(int32_t)T0 / (int32_t)T1);
222
        env->HI[0][env->current_tc] = (int32_t)((int64_t)(int32_t)T0 % (int32_t)T1);
223
    }
224
}
225
#endif
226

    
227
#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
228
void do_ddiv (void)
229
{
230
    if (T1 != 0) {
231
        lldiv_t res = lldiv((int64_t)T0, (int64_t)T1);
232
        env->LO[0][env->current_tc] = res.quot;
233
        env->HI[0][env->current_tc] = res.rem;
234
    }
235
}
236

    
237
#if TARGET_LONG_BITS > HOST_LONG_BITS
238
void do_ddivu (void)
239
{
240
    if (T1 != 0) {
241
        env->LO[0][env->current_tc] = T0 / T1;
242
        env->HI[0][env->current_tc] = T0 % T1;
243
    }
244
}
245
#endif
246
#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */
247

    
248
#if defined(CONFIG_USER_ONLY)
249
void do_mfc0_random (void)
250
{
251
    cpu_abort(env, "mfc0 random\n");
252
}
253

    
254
void do_mfc0_count (void)
255
{
256
    cpu_abort(env, "mfc0 count\n");
257
}
258

    
259
void cpu_mips_store_count(CPUState *env, uint32_t value)
260
{
261
    cpu_abort(env, "mtc0 count\n");
262
}
263

    
264
void cpu_mips_store_compare(CPUState *env, uint32_t value)
265
{
266
    cpu_abort(env, "mtc0 compare\n");
267
}
268

    
269
void cpu_mips_start_count(CPUState *env)
270
{
271
    cpu_abort(env, "start count\n");
272
}
273

    
274
void cpu_mips_stop_count(CPUState *env)
275
{
276
    cpu_abort(env, "stop count\n");
277
}
278

    
279
void cpu_mips_update_irq(CPUState *env)
280
{
281
    cpu_abort(env, "mtc0 status / mtc0 cause\n");
282
}
283

    
284
void do_mtc0_status_debug(uint32_t old, uint32_t val)
285
{
286
    cpu_abort(env, "mtc0 status debug\n");
287
}
288

    
289
void do_mtc0_status_irqraise_debug (void)
290
{
291
    cpu_abort(env, "mtc0 status irqraise debug\n");
292
}
293

    
294
void cpu_mips_tlb_flush (CPUState *env, int flush_global)
295
{
296
    cpu_abort(env, "mips_tlb_flush\n");
297
}
298

    
299
#else
300

    
301
/* CP0 helpers */
302
void do_mfc0_random (void)
303
{
304
    T0 = (int32_t)cpu_mips_get_random(env);
305
}
306

    
307
void do_mfc0_count (void)
308
{
309
    T0 = (int32_t)cpu_mips_get_count(env);
310
}
311

    
312
void do_mtc0_status_debug(uint32_t old, uint32_t val)
313
{
314
    fprintf(logfile, "Status %08x (%08x) => %08x (%08x) Cause %08x",
315
            old, old & env->CP0_Cause & CP0Ca_IP_mask,
316
            val, val & env->CP0_Cause & CP0Ca_IP_mask,
317
            env->CP0_Cause);
318
    (env->hflags & MIPS_HFLAG_UM) ? fputs(", UM\n", logfile)
319
                                  : fputs("\n", logfile);
320
}
321

    
322
void do_mtc0_status_irqraise_debug(void)
323
{
324
    fprintf(logfile, "Raise pending IRQs\n");
325
}
326

    
327
void fpu_handle_exception(void)
328
{
329
#ifdef CONFIG_SOFTFLOAT
330
    int flags = get_float_exception_flags(&env->fpu->fp_status);
331
    unsigned int cpuflags = 0, enable, cause = 0;
332

    
333
    enable = GET_FP_ENABLE(env->fpu->fcr31);
334

    
335
    /* determine current flags */
336
    if (flags & float_flag_invalid) {
337
        cpuflags |= FP_INVALID;
338
        cause |= FP_INVALID & enable;
339
    }
340
    if (flags & float_flag_divbyzero) {
341
        cpuflags |= FP_DIV0;
342
        cause |= FP_DIV0 & enable;
343
    }
344
    if (flags & float_flag_overflow) {
345
        cpuflags |= FP_OVERFLOW;
346
        cause |= FP_OVERFLOW & enable;
347
    }
348
    if (flags & float_flag_underflow) {
349
        cpuflags |= FP_UNDERFLOW;
350
        cause |= FP_UNDERFLOW & enable;
351
    }
352
    if (flags & float_flag_inexact) {
353
        cpuflags |= FP_INEXACT;
354
        cause |= FP_INEXACT & enable;
355
    }
356
    SET_FP_FLAGS(env->fpu->fcr31, cpuflags);
357
    SET_FP_CAUSE(env->fpu->fcr31, cause);
358
#else
359
    SET_FP_FLAGS(env->fpu->fcr31, 0);
360
    SET_FP_CAUSE(env->fpu->fcr31, 0);
361
#endif
362
}
363

    
364
/* TLB management */
365
void cpu_mips_tlb_flush (CPUState *env, int flush_global)
366
{
367
    /* Flush qemu's TLB and discard all shadowed entries.  */
368
    tlb_flush (env, flush_global);
369
    env->tlb->tlb_in_use = env->tlb->nb_tlb;
370
}
371

    
372
static void r4k_mips_tlb_flush_extra (CPUState *env, int first)
373
{
374
    /* Discard entries from env->tlb[first] onwards.  */
375
    while (env->tlb->tlb_in_use > first) {
376
        r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
377
    }
378
}
379

    
380
static void r4k_fill_tlb (int idx)
381
{
382
    r4k_tlb_t *tlb;
383

    
384
    /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
385
    tlb = &env->tlb->mmu.r4k.tlb[idx];
386
    tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
387
#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
388
    tlb->VPN &= env->SEGMask;
389
#endif
390
    tlb->ASID = env->CP0_EntryHi & 0xFF;
391
    tlb->PageMask = env->CP0_PageMask;
392
    tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
393
    tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
394
    tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
395
    tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
396
    tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
397
    tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
398
    tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
399
    tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
400
    tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
401
}
402

    
403
void r4k_do_tlbwi (void)
404
{
405
    /* Discard cached TLB entries.  We could avoid doing this if the
406
       tlbwi is just upgrading access permissions on the current entry;
407
       that might be a further win.  */
408
    r4k_mips_tlb_flush_extra (env, env->tlb->nb_tlb);
409

    
410
    r4k_invalidate_tlb(env, env->CP0_Index % env->tlb->nb_tlb, 0);
411
    r4k_fill_tlb(env->CP0_Index % env->tlb->nb_tlb);
412
}
413

    
414
void r4k_do_tlbwr (void)
415
{
416
    int r = cpu_mips_get_random(env);
417

    
418
    r4k_invalidate_tlb(env, r, 1);
419
    r4k_fill_tlb(r);
420
}
421

    
422
void r4k_do_tlbp (void)
423
{
424
    r4k_tlb_t *tlb;
425
    target_ulong mask;
426
    target_ulong tag;
427
    target_ulong VPN;
428
    uint8_t ASID;
429
    int i;
430

    
431
    ASID = env->CP0_EntryHi & 0xFF;
432
    for (i = 0; i < env->tlb->nb_tlb; i++) {
433
        tlb = &env->tlb->mmu.r4k.tlb[i];
434
        /* 1k pages are not supported. */
435
        mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
436
        tag = env->CP0_EntryHi & ~mask;
437
        VPN = tlb->VPN & ~mask;
438
        /* Check ASID, virtual page number & size */
439
        if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
440
            /* TLB match */
441
            env->CP0_Index = i;
442
            break;
443
        }
444
    }
445
    if (i == env->tlb->nb_tlb) {
446
        /* No match.  Discard any shadow entries, if any of them match.  */
447
        for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
448
            tlb = &env->tlb->mmu.r4k.tlb[i];
449
            /* 1k pages are not supported. */
450
            mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
451
            tag = env->CP0_EntryHi & ~mask;
452
            VPN = tlb->VPN & ~mask;
453
            /* Check ASID, virtual page number & size */
454
            if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
455
                r4k_mips_tlb_flush_extra (env, i);
456
                break;
457
            }
458
        }
459

    
460
        env->CP0_Index |= 0x80000000;
461
    }
462
}
463

    
464
void r4k_do_tlbr (void)
465
{
466
    r4k_tlb_t *tlb;
467
    uint8_t ASID;
468

    
469
    ASID = env->CP0_EntryHi & 0xFF;
470
    tlb = &env->tlb->mmu.r4k.tlb[env->CP0_Index % env->tlb->nb_tlb];
471

    
472
    /* If this will change the current ASID, flush qemu's TLB.  */
473
    if (ASID != tlb->ASID)
474
        cpu_mips_tlb_flush (env, 1);
475

    
476
    r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
477

    
478
    env->CP0_EntryHi = tlb->VPN | tlb->ASID;
479
    env->CP0_PageMask = tlb->PageMask;
480
    env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
481
                        (tlb->C0 << 3) | (tlb->PFN[0] >> 6);
482
    env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
483
                        (tlb->C1 << 3) | (tlb->PFN[1] >> 6);
484
}
485

    
486
#endif /* !CONFIG_USER_ONLY */
487

    
488
void dump_ldst (const unsigned char *func)
489
{
490
    if (loglevel)
491
        fprintf(logfile, "%s => " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__, T0, T1);
492
}
493

    
494
void dump_sc (void)
495
{
496
    if (loglevel) {
497
        fprintf(logfile, "%s " TARGET_FMT_lx " at " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", __func__,
498
                T1, T0, env->CP0_LLAddr);
499
    }
500
}
501

    
502
void debug_pre_eret (void)
503
{
504
    fprintf(logfile, "ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
505
            env->PC[env->current_tc], env->CP0_EPC);
506
    if (env->CP0_Status & (1 << CP0St_ERL))
507
        fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
508
    if (env->hflags & MIPS_HFLAG_DM)
509
        fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC);
510
    fputs("\n", logfile);
511
}
512

    
513
void debug_post_eret (void)
514
{
515
    fprintf(logfile, "  =>  PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
516
            env->PC[env->current_tc], env->CP0_EPC);
517
    if (env->CP0_Status & (1 << CP0St_ERL))
518
        fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
519
    if (env->hflags & MIPS_HFLAG_DM)
520
        fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC);
521
    if (env->hflags & MIPS_HFLAG_UM)
522
        fputs(", UM\n", logfile);
523
    else
524
        fputs("\n", logfile);
525
}
526

    
527
void do_pmon (int function)
528
{
529
    function /= 2;
530
    switch (function) {
531
    case 2: /* TODO: char inbyte(int waitflag); */
532
        if (env->gpr[4][env->current_tc] == 0)
533
            env->gpr[2][env->current_tc] = -1;
534
        /* Fall through */
535
    case 11: /* TODO: char inbyte (void); */
536
        env->gpr[2][env->current_tc] = -1;
537
        break;
538
    case 3:
539
    case 12:
540
        printf("%c", (char)(env->gpr[4][env->current_tc] & 0xFF));
541
        break;
542
    case 17:
543
        break;
544
    case 158:
545
        {
546
            unsigned char *fmt = (void *)(unsigned long)env->gpr[4][env->current_tc];
547
            printf("%s", fmt);
548
        }
549
        break;
550
    }
551
}
552

    
553
#if !defined(CONFIG_USER_ONLY)
554

    
555
static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr);
556

    
557
#define MMUSUFFIX _mmu
558
#define ALIGNED_ONLY
559

    
560
#define SHIFT 0
561
#include "softmmu_template.h"
562

    
563
#define SHIFT 1
564
#include "softmmu_template.h"
565

    
566
#define SHIFT 2
567
#include "softmmu_template.h"
568

    
569
#define SHIFT 3
570
#include "softmmu_template.h"
571

    
572
static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr)
573
{
574
    env->CP0_BadVAddr = addr;
575
    do_restore_state (retaddr);
576
    do_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL);
577
}
578

    
579
void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
580
{
581
    TranslationBlock *tb;
582
    CPUState *saved_env;
583
    unsigned long pc;
584
    int ret;
585

    
586
    /* XXX: hack to restore env in all cases, even if not called from
587
       generated code */
588
    saved_env = env;
589
    env = cpu_single_env;
590
    ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
591
    if (ret) {
592
        if (retaddr) {
593
            /* now we have a real cpu fault */
594
            pc = (unsigned long)retaddr;
595
            tb = tb_find_pc(pc);
596
            if (tb) {
597
                /* the PC is inside the translated code. It means that we have
598
                   a virtual CPU fault */
599
                cpu_restore_state(tb, env, pc, NULL);
600
            }
601
        }
602
        do_raise_exception_err(env->exception_index, env->error_code);
603
    }
604
    env = saved_env;
605
}
606

    
607
void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
608
                          int unused)
609
{
610
    if (is_exec)
611
        do_raise_exception(EXCP_IBE);
612
    else
613
        do_raise_exception(EXCP_DBE);
614
}
615
#endif
616

    
617
/* Complex FPU operations which may need stack space. */
618

    
619
#define FLOAT_SIGN32 (1 << 31)
620
#define FLOAT_SIGN64 (1ULL << 63)
621
#define FLOAT_ONE32 (0x3f8 << 20)
622
#define FLOAT_ONE64 (0x3ffULL << 52)
623
#define FLOAT_TWO32 (1 << 30)
624
#define FLOAT_TWO64 (1ULL << 62)
625
#define FLOAT_QNAN32 0x7fbfffff
626
#define FLOAT_QNAN64 0x7ff7ffffffffffffULL
627
#define FLOAT_SNAN32 0x7fffffff
628
#define FLOAT_SNAN64 0x7fffffffffffffffULL
629

    
630
/* convert MIPS rounding mode in FCR31 to IEEE library */
631
unsigned int ieee_rm[] = {
632
    float_round_nearest_even,
633
    float_round_to_zero,
634
    float_round_up,
635
    float_round_down
636
};
637

    
638
#define RESTORE_ROUNDING_MODE \
639
    set_float_rounding_mode(ieee_rm[env->fpu->fcr31 & 3], &env->fpu->fp_status)
640

    
641
void do_cfc1 (int reg)
642
{
643
    switch (reg) {
644
    case 0:
645
        T0 = (int32_t)env->fpu->fcr0;
646
        break;
647
    case 25:
648
        T0 = ((env->fpu->fcr31 >> 24) & 0xfe) | ((env->fpu->fcr31 >> 23) & 0x1);
649
        break;
650
    case 26:
651
        T0 = env->fpu->fcr31 & 0x0003f07c;
652
        break;
653
    case 28:
654
        T0 = (env->fpu->fcr31 & 0x00000f83) | ((env->fpu->fcr31 >> 22) & 0x4);
655
        break;
656
    default:
657
        T0 = (int32_t)env->fpu->fcr31;
658
        break;
659
    }
660
}
661

    
662
void do_ctc1 (int reg)
663
{
664
    switch(reg) {
665
    case 25:
666
        if (T0 & 0xffffff00)
667
            return;
668
        env->fpu->fcr31 = (env->fpu->fcr31 & 0x017fffff) | ((T0 & 0xfe) << 24) |
669
                     ((T0 & 0x1) << 23);
670
        break;
671
    case 26:
672
        if (T0 & 0x007c0000)
673
            return;
674
        env->fpu->fcr31 = (env->fpu->fcr31 & 0xfffc0f83) | (T0 & 0x0003f07c);
675
        break;
676
    case 28:
677
        if (T0 & 0x007c0000)
678
            return;
679
        env->fpu->fcr31 = (env->fpu->fcr31 & 0xfefff07c) | (T0 & 0x00000f83) |
680
                     ((T0 & 0x4) << 22);
681
        break;
682
    case 31:
683
        if (T0 & 0x007c0000)
684
            return;
685
        env->fpu->fcr31 = T0;
686
        break;
687
    default:
688
        return;
689
    }
690
    /* set rounding mode */
691
    RESTORE_ROUNDING_MODE;
692
    set_float_exception_flags(0, &env->fpu->fp_status);
693
    if ((GET_FP_ENABLE(env->fpu->fcr31) | 0x20) & GET_FP_CAUSE(env->fpu->fcr31))
694
        do_raise_exception(EXCP_FPE);
695
}
696

    
697
static always_inline char ieee_ex_to_mips(char xcpt)
698
{
699
    return (xcpt & float_flag_inexact) >> 5 |
700
           (xcpt & float_flag_underflow) >> 3 |
701
           (xcpt & float_flag_overflow) >> 1 |
702
           (xcpt & float_flag_divbyzero) << 1 |
703
           (xcpt & float_flag_invalid) << 4;
704
}
705

    
706
static always_inline char mips_ex_to_ieee(char xcpt)
707
{
708
    return (xcpt & FP_INEXACT) << 5 |
709
           (xcpt & FP_UNDERFLOW) << 3 |
710
           (xcpt & FP_OVERFLOW) << 1 |
711
           (xcpt & FP_DIV0) >> 1 |
712
           (xcpt & FP_INVALID) >> 4;
713
}
714

    
715
static always_inline void update_fcr31(void)
716
{
717
    int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->fpu->fp_status));
718

    
719
    SET_FP_CAUSE(env->fpu->fcr31, tmp);
720
    if (GET_FP_ENABLE(env->fpu->fcr31) & tmp)
721
        do_raise_exception(EXCP_FPE);
722
    else
723
        UPDATE_FP_FLAGS(env->fpu->fcr31, tmp);
724
}
725

    
726
#define FLOAT_OP(name, p) void do_float_##name##_##p(void)
727

    
728
FLOAT_OP(cvtd, s)
729
{
730
    set_float_exception_flags(0, &env->fpu->fp_status);
731
    FDT2 = float32_to_float64(FST0, &env->fpu->fp_status);
732
    update_fcr31();
733
}
734
FLOAT_OP(cvtd, w)
735
{
736
    set_float_exception_flags(0, &env->fpu->fp_status);
737
    FDT2 = int32_to_float64(WT0, &env->fpu->fp_status);
738
    update_fcr31();
739
}
740
FLOAT_OP(cvtd, l)
741
{
742
    set_float_exception_flags(0, &env->fpu->fp_status);
743
    FDT2 = int64_to_float64(DT0, &env->fpu->fp_status);
744
    update_fcr31();
745
}
746
FLOAT_OP(cvtl, d)
747
{
748
    set_float_exception_flags(0, &env->fpu->fp_status);
749
    DT2 = float64_to_int64(FDT0, &env->fpu->fp_status);
750
    update_fcr31();
751
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
752
        DT2 = FLOAT_SNAN64;
753
}
754
FLOAT_OP(cvtl, s)
755
{
756
    set_float_exception_flags(0, &env->fpu->fp_status);
757
    DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
758
    update_fcr31();
759
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
760
        DT2 = FLOAT_SNAN64;
761
}
762

    
763
FLOAT_OP(cvtps, pw)
764
{
765
    set_float_exception_flags(0, &env->fpu->fp_status);
766
    FST2 = int32_to_float32(WT0, &env->fpu->fp_status);
767
    FSTH2 = int32_to_float32(WTH0, &env->fpu->fp_status);
768
    update_fcr31();
769
}
770
FLOAT_OP(cvtpw, ps)
771
{
772
    set_float_exception_flags(0, &env->fpu->fp_status);
773
    WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
774
    WTH2 = float32_to_int32(FSTH0, &env->fpu->fp_status);
775
    update_fcr31();
776
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
777
        WT2 = FLOAT_SNAN32;
778
}
779
FLOAT_OP(cvts, d)
780
{
781
    set_float_exception_flags(0, &env->fpu->fp_status);
782
    FST2 = float64_to_float32(FDT0, &env->fpu->fp_status);
783
    update_fcr31();
784
}
785
FLOAT_OP(cvts, w)
786
{
787
    set_float_exception_flags(0, &env->fpu->fp_status);
788
    FST2 = int32_to_float32(WT0, &env->fpu->fp_status);
789
    update_fcr31();
790
}
791
FLOAT_OP(cvts, l)
792
{
793
    set_float_exception_flags(0, &env->fpu->fp_status);
794
    FST2 = int64_to_float32(DT0, &env->fpu->fp_status);
795
    update_fcr31();
796
}
797
FLOAT_OP(cvts, pl)
798
{
799
    set_float_exception_flags(0, &env->fpu->fp_status);
800
    WT2 = WT0;
801
    update_fcr31();
802
}
803
FLOAT_OP(cvts, pu)
804
{
805
    set_float_exception_flags(0, &env->fpu->fp_status);
806
    WT2 = WTH0;
807
    update_fcr31();
808
}
809
FLOAT_OP(cvtw, s)
810
{
811
    set_float_exception_flags(0, &env->fpu->fp_status);
812
    WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
813
    update_fcr31();
814
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
815
        WT2 = FLOAT_SNAN32;
816
}
817
FLOAT_OP(cvtw, d)
818
{
819
    set_float_exception_flags(0, &env->fpu->fp_status);
820
    WT2 = float64_to_int32(FDT0, &env->fpu->fp_status);
821
    update_fcr31();
822
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
823
        WT2 = FLOAT_SNAN32;
824
}
825

    
826
FLOAT_OP(roundl, d)
827
{
828
    set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
829
    DT2 = float64_to_int64(FDT0, &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(roundl, s)
836
{
837
    set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
838
    DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
839
    RESTORE_ROUNDING_MODE;
840
    update_fcr31();
841
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
842
        DT2 = FLOAT_SNAN64;
843
}
844
FLOAT_OP(roundw, d)
845
{
846
    set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
847
    WT2 = float64_to_int32(FDT0, &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
FLOAT_OP(roundw, s)
854
{
855
    set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
856
    WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
857
    RESTORE_ROUNDING_MODE;
858
    update_fcr31();
859
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
860
        WT2 = FLOAT_SNAN32;
861
}
862

    
863
FLOAT_OP(truncl, d)
864
{
865
    DT2 = float64_to_int64_round_to_zero(FDT0, &env->fpu->fp_status);
866
    update_fcr31();
867
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
868
        DT2 = FLOAT_SNAN64;
869
}
870
FLOAT_OP(truncl, s)
871
{
872
    DT2 = float32_to_int64_round_to_zero(FST0, &env->fpu->fp_status);
873
    update_fcr31();
874
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
875
        DT2 = FLOAT_SNAN64;
876
}
877
FLOAT_OP(truncw, d)
878
{
879
    WT2 = float64_to_int32_round_to_zero(FDT0, &env->fpu->fp_status);
880
    update_fcr31();
881
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
882
        WT2 = FLOAT_SNAN32;
883
}
884
FLOAT_OP(truncw, s)
885
{
886
    WT2 = float32_to_int32_round_to_zero(FST0, &env->fpu->fp_status);
887
    update_fcr31();
888
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
889
        WT2 = FLOAT_SNAN32;
890
}
891

    
892
FLOAT_OP(ceill, d)
893
{
894
    set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
895
    DT2 = float64_to_int64(FDT0, &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(ceill, s)
902
{
903
    set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
904
    DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
905
    RESTORE_ROUNDING_MODE;
906
    update_fcr31();
907
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
908
        DT2 = FLOAT_SNAN64;
909
}
910
FLOAT_OP(ceilw, d)
911
{
912
    set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
913
    WT2 = float64_to_int32(FDT0, &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
FLOAT_OP(ceilw, s)
920
{
921
    set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
922
    WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
923
    RESTORE_ROUNDING_MODE;
924
    update_fcr31();
925
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
926
        WT2 = FLOAT_SNAN32;
927
}
928

    
929
FLOAT_OP(floorl, d)
930
{
931
    set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
932
    DT2 = float64_to_int64(FDT0, &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(floorl, s)
939
{
940
    set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
941
    DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
942
    RESTORE_ROUNDING_MODE;
943
    update_fcr31();
944
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
945
        DT2 = FLOAT_SNAN64;
946
}
947
FLOAT_OP(floorw, d)
948
{
949
    set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
950
    WT2 = float64_to_int32(FDT0, &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
FLOAT_OP(floorw, s)
957
{
958
    set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
959
    WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
960
    RESTORE_ROUNDING_MODE;
961
    update_fcr31();
962
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
963
        WT2 = FLOAT_SNAN32;
964
}
965

    
966
/* MIPS specific unary operations */
967
FLOAT_OP(recip, d)
968
{
969
    set_float_exception_flags(0, &env->fpu->fp_status);
970
    FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fpu->fp_status);
971
    update_fcr31();
972
}
973
FLOAT_OP(recip, s)
974
{
975
    set_float_exception_flags(0, &env->fpu->fp_status);
976
    FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status);
977
    update_fcr31();
978
}
979

    
980
FLOAT_OP(rsqrt, d)
981
{
982
    set_float_exception_flags(0, &env->fpu->fp_status);
983
    FDT2 = float64_sqrt(FDT0, &env->fpu->fp_status);
984
    FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fpu->fp_status);
985
    update_fcr31();
986
}
987
FLOAT_OP(rsqrt, s)
988
{
989
    set_float_exception_flags(0, &env->fpu->fp_status);
990
    FST2 = float32_sqrt(FST0, &env->fpu->fp_status);
991
    FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status);
992
    update_fcr31();
993
}
994

    
995
FLOAT_OP(recip1, d)
996
{
997
    set_float_exception_flags(0, &env->fpu->fp_status);
998
    FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fpu->fp_status);
999
    update_fcr31();
1000
}
1001
FLOAT_OP(recip1, s)
1002
{
1003
    set_float_exception_flags(0, &env->fpu->fp_status);
1004
    FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status);
1005
    update_fcr31();
1006
}
1007
FLOAT_OP(recip1, ps)
1008
{
1009
    set_float_exception_flags(0, &env->fpu->fp_status);
1010
    FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status);
1011
    FSTH2 = float32_div(FLOAT_ONE32, FSTH0, &env->fpu->fp_status);
1012
    update_fcr31();
1013
}
1014

    
1015
FLOAT_OP(rsqrt1, d)
1016
{
1017
    set_float_exception_flags(0, &env->fpu->fp_status);
1018
    FDT2 = float64_sqrt(FDT0, &env->fpu->fp_status);
1019
    FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fpu->fp_status);
1020
    update_fcr31();
1021
}
1022
FLOAT_OP(rsqrt1, s)
1023
{
1024
    set_float_exception_flags(0, &env->fpu->fp_status);
1025
    FST2 = float32_sqrt(FST0, &env->fpu->fp_status);
1026
    FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status);
1027
    update_fcr31();
1028
}
1029
FLOAT_OP(rsqrt1, ps)
1030
{
1031
    set_float_exception_flags(0, &env->fpu->fp_status);
1032
    FST2 = float32_sqrt(FST0, &env->fpu->fp_status);
1033
    FSTH2 = float32_sqrt(FSTH0, &env->fpu->fp_status);
1034
    FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status);
1035
    FSTH2 = float32_div(FLOAT_ONE32, FSTH2, &env->fpu->fp_status);
1036
    update_fcr31();
1037
}
1038

    
1039
/* binary operations */
1040
#define FLOAT_BINOP(name) \
1041
FLOAT_OP(name, d)         \
1042
{                         \
1043
    set_float_exception_flags(0, &env->fpu->fp_status);            \
1044
    FDT2 = float64_ ## name (FDT0, FDT1, &env->fpu->fp_status);    \
1045
    update_fcr31();                                                \
1046
    if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID)                \
1047
        FDT2 = FLOAT_QNAN64;                                       \
1048
}                         \
1049
FLOAT_OP(name, s)         \
1050
{                         \
1051
    set_float_exception_flags(0, &env->fpu->fp_status);            \
1052
    FST2 = float32_ ## name (FST0, FST1, &env->fpu->fp_status);    \
1053
    update_fcr31();                                                \
1054
    if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID)                \
1055
        FST2 = FLOAT_QNAN32;                                       \
1056
}                         \
1057
FLOAT_OP(name, ps)        \
1058
{                         \
1059
    set_float_exception_flags(0, &env->fpu->fp_status);            \
1060
    FST2 = float32_ ## name (FST0, FST1, &env->fpu->fp_status);    \
1061
    FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fpu->fp_status); \
1062
    update_fcr31();       \
1063
    if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) {              \
1064
        FST2 = FLOAT_QNAN32;                                       \
1065
        FSTH2 = FLOAT_QNAN32;                                      \
1066
    }                     \
1067
}
1068
FLOAT_BINOP(add)
1069
FLOAT_BINOP(sub)
1070
FLOAT_BINOP(mul)
1071
FLOAT_BINOP(div)
1072
#undef FLOAT_BINOP
1073

    
1074
/* MIPS specific binary operations */
1075
FLOAT_OP(recip2, d)
1076
{
1077
    set_float_exception_flags(0, &env->fpu->fp_status);
1078
    FDT2 = float64_mul(FDT0, FDT2, &env->fpu->fp_status);
1079
    FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fpu->fp_status) ^ FLOAT_SIGN64;
1080
    update_fcr31();
1081
}
1082
FLOAT_OP(recip2, s)
1083
{
1084
    set_float_exception_flags(0, &env->fpu->fp_status);
1085
    FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
1086
    FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status) ^ FLOAT_SIGN32;
1087
    update_fcr31();
1088
}
1089
FLOAT_OP(recip2, ps)
1090
{
1091
    set_float_exception_flags(0, &env->fpu->fp_status);
1092
    FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
1093
    FSTH2 = float32_mul(FSTH0, FSTH2, &env->fpu->fp_status);
1094
    FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status) ^ FLOAT_SIGN32;
1095
    FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fpu->fp_status) ^ FLOAT_SIGN32;
1096
    update_fcr31();
1097
}
1098

    
1099
FLOAT_OP(rsqrt2, d)
1100
{
1101
    set_float_exception_flags(0, &env->fpu->fp_status);
1102
    FDT2 = float64_mul(FDT0, FDT2, &env->fpu->fp_status);
1103
    FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fpu->fp_status);
1104
    FDT2 = float64_div(FDT2, FLOAT_TWO64, &env->fpu->fp_status) ^ FLOAT_SIGN64;
1105
    update_fcr31();
1106
}
1107
FLOAT_OP(rsqrt2, s)
1108
{
1109
    set_float_exception_flags(0, &env->fpu->fp_status);
1110
    FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
1111
    FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status);
1112
    FST2 = float32_div(FST2, FLOAT_TWO32, &env->fpu->fp_status) ^ FLOAT_SIGN32;
1113
    update_fcr31();
1114
}
1115
FLOAT_OP(rsqrt2, ps)
1116
{
1117
    set_float_exception_flags(0, &env->fpu->fp_status);
1118
    FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
1119
    FSTH2 = float32_mul(FSTH0, FSTH2, &env->fpu->fp_status);
1120
    FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status);
1121
    FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fpu->fp_status);
1122
    FST2 = float32_div(FST2, FLOAT_TWO32, &env->fpu->fp_status) ^ FLOAT_SIGN32;
1123
    FSTH2 = float32_div(FSTH2, FLOAT_TWO32, &env->fpu->fp_status) ^ FLOAT_SIGN32;
1124
    update_fcr31();
1125
}
1126

    
1127
FLOAT_OP(addr, ps)
1128
{
1129
    set_float_exception_flags(0, &env->fpu->fp_status);
1130
    FST2 = float32_add (FST0, FSTH0, &env->fpu->fp_status);
1131
    FSTH2 = float32_add (FST1, FSTH1, &env->fpu->fp_status);
1132
    update_fcr31();
1133
}
1134

    
1135
FLOAT_OP(mulr, ps)
1136
{
1137
    set_float_exception_flags(0, &env->fpu->fp_status);
1138
    FST2 = float32_mul (FST0, FSTH0, &env->fpu->fp_status);
1139
    FSTH2 = float32_mul (FST1, FSTH1, &env->fpu->fp_status);
1140
    update_fcr31();
1141
}
1142

    
1143
/* compare operations */
1144
#define FOP_COND_D(op, cond)                   \
1145
void do_cmp_d_ ## op (long cc)                 \
1146
{                                              \
1147
    int c = cond;                              \
1148
    update_fcr31();                            \
1149
    if (c)                                     \
1150
        SET_FP_COND(cc, env->fpu);             \
1151
    else                                       \
1152
        CLEAR_FP_COND(cc, env->fpu);           \
1153
}                                              \
1154
void do_cmpabs_d_ ## op (long cc)              \
1155
{                                              \
1156
    int c;                                     \
1157
    FDT0 &= ~FLOAT_SIGN64;                     \
1158
    FDT1 &= ~FLOAT_SIGN64;                     \
1159
    c = cond;                                  \
1160
    update_fcr31();                            \
1161
    if (c)                                     \
1162
        SET_FP_COND(cc, env->fpu);             \
1163
    else                                       \
1164
        CLEAR_FP_COND(cc, env->fpu);           \
1165
}
1166

    
1167
int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM)
1168
{
1169
    if (float64_is_signaling_nan(a) ||
1170
        float64_is_signaling_nan(b) ||
1171
        (sig && (float64_is_nan(a) || float64_is_nan(b)))) {
1172
        float_raise(float_flag_invalid, status);
1173
        return 1;
1174
    } else if (float64_is_nan(a) || float64_is_nan(b)) {
1175
        return 1;
1176
    } else {
1177
        return 0;
1178
    }
1179
}
1180

    
1181
/* NOTE: the comma operator will make "cond" to eval to false,
1182
 * but float*_is_unordered() is still called. */
1183
FOP_COND_D(f,   (float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status), 0))
1184
FOP_COND_D(un,  float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status))
1185
FOP_COND_D(eq,  !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_eq(FDT0, FDT1, &env->fpu->fp_status))
1186
FOP_COND_D(ueq, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status)  || float64_eq(FDT0, FDT1, &env->fpu->fp_status))
1187
FOP_COND_D(olt, !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_lt(FDT0, FDT1, &env->fpu->fp_status))
1188
FOP_COND_D(ult, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status)  || float64_lt(FDT0, FDT1, &env->fpu->fp_status))
1189
FOP_COND_D(ole, !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_le(FDT0, FDT1, &env->fpu->fp_status))
1190
FOP_COND_D(ule, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status)  || float64_le(FDT0, FDT1, &env->fpu->fp_status))
1191
/* NOTE: the comma operator will make "cond" to eval to false,
1192
 * but float*_is_unordered() is still called. */
1193
FOP_COND_D(sf,  (float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status), 0))
1194
FOP_COND_D(ngle,float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status))
1195
FOP_COND_D(seq, !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_eq(FDT0, FDT1, &env->fpu->fp_status))
1196
FOP_COND_D(ngl, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status)  || float64_eq(FDT0, FDT1, &env->fpu->fp_status))
1197
FOP_COND_D(lt,  !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_lt(FDT0, FDT1, &env->fpu->fp_status))
1198
FOP_COND_D(nge, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status)  || float64_lt(FDT0, FDT1, &env->fpu->fp_status))
1199
FOP_COND_D(le,  !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_le(FDT0, FDT1, &env->fpu->fp_status))
1200
FOP_COND_D(ngt, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status)  || float64_le(FDT0, FDT1, &env->fpu->fp_status))
1201

    
1202
#define FOP_COND_S(op, cond)                   \
1203
void do_cmp_s_ ## op (long cc)                 \
1204
{                                              \
1205
    int c = cond;                              \
1206
    update_fcr31();                            \
1207
    if (c)                                     \
1208
        SET_FP_COND(cc, env->fpu);             \
1209
    else                                       \
1210
        CLEAR_FP_COND(cc, env->fpu);           \
1211
}                                              \
1212
void do_cmpabs_s_ ## op (long cc)              \
1213
{                                              \
1214
    int c;                                     \
1215
    FST0 &= ~FLOAT_SIGN32;                     \
1216
    FST1 &= ~FLOAT_SIGN32;                     \
1217
    c = cond;                                  \
1218
    update_fcr31();                            \
1219
    if (c)                                     \
1220
        SET_FP_COND(cc, env->fpu);             \
1221
    else                                       \
1222
        CLEAR_FP_COND(cc, env->fpu);           \
1223
}
1224

    
1225
flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM)
1226
{
1227
    if (float32_is_signaling_nan(a) ||
1228
        float32_is_signaling_nan(b) ||
1229
        (sig && (float32_is_nan(a) || float32_is_nan(b)))) {
1230
        float_raise(float_flag_invalid, status);
1231
        return 1;
1232
    } else if (float32_is_nan(a) || float32_is_nan(b)) {
1233
        return 1;
1234
    } else {
1235
        return 0;
1236
    }
1237
}
1238

    
1239
/* NOTE: the comma operator will make "cond" to eval to false,
1240
 * but float*_is_unordered() is still called. */
1241
FOP_COND_S(f,   (float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status), 0))
1242
FOP_COND_S(un,  float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status))
1243
FOP_COND_S(eq,  !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status))
1244
FOP_COND_S(ueq, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)  || float32_eq(FST0, FST1, &env->fpu->fp_status))
1245
FOP_COND_S(olt, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status))
1246
FOP_COND_S(ult, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)  || float32_lt(FST0, FST1, &env->fpu->fp_status))
1247
FOP_COND_S(ole, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status))
1248
FOP_COND_S(ule, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)  || float32_le(FST0, FST1, &env->fpu->fp_status))
1249
/* NOTE: the comma operator will make "cond" to eval to false,
1250
 * but float*_is_unordered() is still called. */
1251
FOP_COND_S(sf,  (float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status), 0))
1252
FOP_COND_S(ngle,float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status))
1253
FOP_COND_S(seq, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status))
1254
FOP_COND_S(ngl, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)  || float32_eq(FST0, FST1, &env->fpu->fp_status))
1255
FOP_COND_S(lt,  !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status))
1256
FOP_COND_S(nge, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)  || float32_lt(FST0, FST1, &env->fpu->fp_status))
1257
FOP_COND_S(le,  !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status))
1258
FOP_COND_S(ngt, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)  || float32_le(FST0, FST1, &env->fpu->fp_status))
1259

    
1260
#define FOP_COND_PS(op, condl, condh)          \
1261
void do_cmp_ps_ ## op (long cc)                \
1262
{                                              \
1263
    int cl = condl;                            \
1264
    int ch = condh;                            \
1265
    update_fcr31();                            \
1266
    if (cl)                                    \
1267
        SET_FP_COND(cc, env->fpu);             \
1268
    else                                       \
1269
        CLEAR_FP_COND(cc, env->fpu);           \
1270
    if (ch)                                    \
1271
        SET_FP_COND(cc + 1, env->fpu);         \
1272
    else                                       \
1273
        CLEAR_FP_COND(cc + 1, env->fpu);       \
1274
}                                              \
1275
void do_cmpabs_ps_ ## op (long cc)             \
1276
{                                              \
1277
    int cl, ch;                                \
1278
    FST0 &= ~FLOAT_SIGN32;                     \
1279
    FSTH0 &= ~FLOAT_SIGN32;                    \
1280
    FST1 &= ~FLOAT_SIGN32;                     \
1281
    FSTH1 &= ~FLOAT_SIGN32;                    \
1282
    cl = condl;                                \
1283
    ch = condh;                                \
1284
    update_fcr31();                            \
1285
    if (cl)                                    \
1286
        SET_FP_COND(cc, env->fpu);             \
1287
    else                                       \
1288
        CLEAR_FP_COND(cc, env->fpu);           \
1289
    if (ch)                                    \
1290
        SET_FP_COND(cc + 1, env->fpu);         \
1291
    else                                       \
1292
        CLEAR_FP_COND(cc + 1, env->fpu);       \
1293
}
1294

    
1295
/* NOTE: the comma operator will make "cond" to eval to false,
1296
 * but float*_is_unordered() is still called. */
1297
FOP_COND_PS(f,   (float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status), 0),
1298
                 (float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status), 0))
1299
FOP_COND_PS(un,  float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status),
1300
                 float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status))
1301
FOP_COND_PS(eq,  !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)   && float32_eq(FST0, FST1, &env->fpu->fp_status),
1302
                 !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
1303
FOP_COND_PS(ueq, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)    || float32_eq(FST0, FST1, &env->fpu->fp_status),
1304
                 float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
1305
FOP_COND_PS(olt, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)   && float32_lt(FST0, FST1, &env->fpu->fp_status),
1306
                 !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
1307
FOP_COND_PS(ult, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)    || float32_lt(FST0, FST1, &env->fpu->fp_status),
1308
                 float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
1309
FOP_COND_PS(ole, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)   && float32_le(FST0, FST1, &env->fpu->fp_status),
1310
                 !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_le(FSTH0, FSTH1, &env->fpu->fp_status))
1311
FOP_COND_PS(ule, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)    || float32_le(FST0, FST1, &env->fpu->fp_status),
1312
                 float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_le(FSTH0, FSTH1, &env->fpu->fp_status))
1313
/* NOTE: the comma operator will make "cond" to eval to false,
1314
 * but float*_is_unordered() is still called. */
1315
FOP_COND_PS(sf,  (float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status), 0),
1316
                 (float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status), 0))
1317
FOP_COND_PS(ngle,float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status),
1318
                 float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status))
1319
FOP_COND_PS(seq, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)   && float32_eq(FST0, FST1, &env->fpu->fp_status),
1320
                 !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
1321
FOP_COND_PS(ngl, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)    || float32_eq(FST0, FST1, &env->fpu->fp_status),
1322
                 float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
1323
FOP_COND_PS(lt,  !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)   && float32_lt(FST0, FST1, &env->fpu->fp_status),
1324
                 !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
1325
FOP_COND_PS(nge, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)    || float32_lt(FST0, FST1, &env->fpu->fp_status),
1326
                 float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
1327
FOP_COND_PS(le,  !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)   && float32_le(FST0, FST1, &env->fpu->fp_status),
1328
                 !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_le(FSTH0, FSTH1, &env->fpu->fp_status))
1329
FOP_COND_PS(ngt, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)    || float32_le(FST0, FST1, &env->fpu->fp_status),
1330
                 float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_le(FSTH0, FSTH1, &env->fpu->fp_status))