Statistics
| Branch: | Revision:

root / target-mips / op_helper.c @ 924b2c07

History | View | Annotate | Download (39.6 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
#define GETPC() (__builtin_return_address(0))
24

    
25
/*****************************************************************************/
26
/* Exceptions processing helpers */
27
void cpu_loop_exit(void)
28
{
29
    longjmp(env->jmp_env, 1);
30
}
31

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

    
44
void do_raise_exception (uint32_t exception)
45
{
46
    do_raise_exception_err(exception, 0);
47
}
48

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

    
54
  tb = tb_find_pc (pc);
55
  cpu_restore_state (tb, env, pc, NULL);
56
}
57

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

    
64
void do_raise_exception_direct (uint32_t exception)
65
{
66
    do_raise_exception_direct_err (exception, 0);
67
}
68

    
69
#define MEMSUFFIX _raw
70
#include "op_helper_mem.c"
71
#undef MEMSUFFIX
72
#if !defined(CONFIG_USER_ONLY)
73
#define MEMSUFFIX _user
74
#include "op_helper_mem.c"
75
#undef MEMSUFFIX
76
#define MEMSUFFIX _kernel
77
#include "op_helper_mem.c"
78
#undef MEMSUFFIX
79
#endif
80

    
81
#ifdef TARGET_MIPS64
82
#if TARGET_LONG_BITS > HOST_LONG_BITS
83
/* Those might call libgcc functions.  */
84
void do_dsll (void)
85
{
86
    T0 = T0 << T1;
87
}
88

    
89
void do_dsll32 (void)
90
{
91
    T0 = T0 << (T1 + 32);
92
}
93

    
94
void do_dsra (void)
95
{
96
    T0 = (int64_t)T0 >> T1;
97
}
98

    
99
void do_dsra32 (void)
100
{
101
    T0 = (int64_t)T0 >> (T1 + 32);
102
}
103

    
104
void do_dsrl (void)
105
{
106
    T0 = T0 >> T1;
107
}
108

    
109
void do_dsrl32 (void)
110
{
111
    T0 = T0 >> (T1 + 32);
112
}
113

    
114
void do_drotr (void)
115
{
116
    target_ulong tmp;
117

    
118
    if (T1) {
119
       tmp = T0 << (0x40 - T1);
120
       T0 = (T0 >> T1) | tmp;
121
    }
122
}
123

    
124
void do_drotr32 (void)
125
{
126
    target_ulong tmp;
127

    
128
    if (T1) {
129
       tmp = T0 << (0x40 - (32 + T1));
130
       T0 = (T0 >> (32 + T1)) | tmp;
131
    }
132
}
133

    
134
void do_dsllv (void)
135
{
136
    T0 = T1 << (T0 & 0x3F);
137
}
138

    
139
void do_dsrav (void)
140
{
141
    T0 = (int64_t)T1 >> (T0 & 0x3F);
142
}
143

    
144
void do_dsrlv (void)
145
{
146
    T0 = T1 >> (T0 & 0x3F);
147
}
148

    
149
void do_drotrv (void)
150
{
151
    target_ulong tmp;
152

    
153
    T0 &= 0x3F;
154
    if (T0) {
155
       tmp = T1 << (0x40 - T0);
156
       T0 = (T1 >> T0) | tmp;
157
    } else
158
       T0 = T1;
159
}
160
#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */
161
#endif /* TARGET_MIPS64 */
162

    
163
/* 64 bits arithmetic for 32 bits hosts */
164
#if TARGET_LONG_BITS > HOST_LONG_BITS
165
static inline uint64_t get_HILO (void)
166
{
167
    return (env->HI << 32) | (uint32_t)env->LO;
168
}
169

    
170
static inline void set_HILO (uint64_t HILO)
171
{
172
    env->LO = (int32_t)HILO;
173
    env->HI = (int32_t)(HILO >> 32);
174
}
175

    
176
void do_mult (void)
177
{
178
    set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
179
}
180

    
181
void do_multu (void)
182
{
183
    set_HILO((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
184
}
185

    
186
void do_madd (void)
187
{
188
    int64_t tmp;
189

    
190
    tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
191
    set_HILO((int64_t)get_HILO() + tmp);
192
}
193

    
194
void do_maddu (void)
195
{
196
    uint64_t tmp;
197

    
198
    tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
199
    set_HILO(get_HILO() + tmp);
200
}
201

    
202
void do_msub (void)
203
{
204
    int64_t tmp;
205

    
206
    tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
207
    set_HILO((int64_t)get_HILO() - tmp);
208
}
209

    
210
void do_msubu (void)
211
{
212
    uint64_t tmp;
213

    
214
    tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
215
    set_HILO(get_HILO() - tmp);
216
}
217
#endif
218

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

    
230
#ifdef TARGET_MIPS64
231
void do_ddiv (void)
232
{
233
    if (T1 != 0) {
234
        lldiv_t res = lldiv((int64_t)T0, (int64_t)T1);
235
        env->LO = res.quot;
236
        env->HI = res.rem;
237
    }
238
}
239

    
240
#if TARGET_LONG_BITS > HOST_LONG_BITS
241
void do_ddivu (void)
242
{
243
    if (T1 != 0) {
244
        env->LO = T0 / T1;
245
        env->HI = T0 % T1;
246
    }
247
}
248
#endif
249
#endif /* TARGET_MIPS64 */
250

    
251
#if defined(CONFIG_USER_ONLY) 
252
void do_mfc0_random (void)
253
{
254
    cpu_abort(env, "mfc0 random\n");
255
}
256

    
257
void do_mfc0_count (void)
258
{
259
    cpu_abort(env, "mfc0 count\n");
260
}
261

    
262
void cpu_mips_store_count(CPUState *env, uint32_t value)
263
{
264
    cpu_abort(env, "mtc0 count\n");
265
}
266

    
267
void cpu_mips_store_compare(CPUState *env, uint32_t value)
268
{
269
    cpu_abort(env, "mtc0 compare\n");
270
}
271

    
272
void cpu_mips_update_irq(CPUState *env)
273
{
274
    cpu_abort(env, "mtc0 status / mtc0 cause\n");
275
}
276

    
277
void do_mtc0_status_debug(uint32_t old, uint32_t val)
278
{
279
    cpu_abort(env, "mtc0 status debug\n");
280
}
281

    
282
void do_mtc0_status_irqraise_debug (void)
283
{
284
    cpu_abort(env, "mtc0 status irqraise debug\n");
285
}
286

    
287
void cpu_mips_tlb_flush (CPUState *env, int flush_global)
288
{
289
    cpu_abort(env, "mips_tlb_flush\n");
290
}
291

    
292
#else
293

    
294
/* CP0 helpers */
295
void do_mfc0_random (void)
296
{
297
    T0 = (int32_t)cpu_mips_get_random(env);
298
}
299

    
300
void do_mfc0_count (void)
301
{
302
    T0 = (int32_t)cpu_mips_get_count(env);
303
}
304

    
305
void do_mtc0_status_debug(uint32_t old, uint32_t val)
306
{
307
    fprintf(logfile, "Status %08x (%08x) => %08x (%08x) Cause %08x",
308
            old, old & env->CP0_Cause & CP0Ca_IP_mask,
309
            val, val & env->CP0_Cause & CP0Ca_IP_mask,
310
            env->CP0_Cause);
311
    (env->hflags & MIPS_HFLAG_UM) ? fputs(", UM\n", logfile)
312
                                  : fputs("\n", logfile);
313
}
314

    
315
void do_mtc0_status_irqraise_debug(void)
316
{
317
    fprintf(logfile, "Raise pending IRQs\n");
318
}
319

    
320
void fpu_handle_exception(void)
321
{
322
#ifdef CONFIG_SOFTFLOAT
323
    int flags = get_float_exception_flags(&env->fp_status);
324
    unsigned int cpuflags = 0, enable, cause = 0;
325

    
326
    enable = GET_FP_ENABLE(env->fcr31);
327

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

    
357
/* TLB management */
358
void cpu_mips_tlb_flush (CPUState *env, int flush_global)
359
{
360
    /* Flush qemu's TLB and discard all shadowed entries.  */
361
    tlb_flush (env, flush_global);
362
    env->tlb_in_use = env->nb_tlb;
363
}
364

    
365
static void r4k_mips_tlb_flush_extra (CPUState *env, int first)
366
{
367
    /* Discard entries from env->tlb[first] onwards.  */
368
    while (env->tlb_in_use > first) {
369
        r4k_invalidate_tlb(env, --env->tlb_in_use, 0);
370
    }
371
}
372

    
373
static void r4k_fill_tlb (int idx)
374
{
375
    r4k_tlb_t *tlb;
376

    
377
    /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
378
    tlb = &env->mmu.r4k.tlb[idx];
379
    tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
380
#ifdef TARGET_MIPS64
381
    tlb->VPN &= 0xC00000FFFFFFFFFFULL;
382
#endif
383
    tlb->ASID = env->CP0_EntryHi & 0xFF;
384
    tlb->PageMask = env->CP0_PageMask;
385
    tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
386
    tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
387
    tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
388
    tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
389
    tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
390
    tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
391
    tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
392
    tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
393
    tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
394
}
395

    
396
void r4k_do_tlbwi (void)
397
{
398
    /* Discard cached TLB entries.  We could avoid doing this if the
399
       tlbwi is just upgrading access permissions on the current entry;
400
       that might be a further win.  */
401
    r4k_mips_tlb_flush_extra (env, env->nb_tlb);
402

    
403
    r4k_invalidate_tlb(env, env->CP0_Index % env->nb_tlb, 0);
404
    r4k_fill_tlb(env->CP0_Index % env->nb_tlb);
405
}
406

    
407
void r4k_do_tlbwr (void)
408
{
409
    int r = cpu_mips_get_random(env);
410

    
411
    r4k_invalidate_tlb(env, r, 1);
412
    r4k_fill_tlb(r);
413
}
414

    
415
void r4k_do_tlbp (void)
416
{
417
    r4k_tlb_t *tlb;
418
    target_ulong mask;
419
    target_ulong tag;
420
    target_ulong VPN;
421
    uint8_t ASID;
422
    int i;
423

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

    
453
        env->CP0_Index |= 0x80000000;
454
    }
455
}
456

    
457
void r4k_do_tlbr (void)
458
{
459
    r4k_tlb_t *tlb;
460
    uint8_t ASID;
461

    
462
    ASID = env->CP0_EntryHi & 0xFF;
463
    tlb = &env->mmu.r4k.tlb[env->CP0_Index % env->nb_tlb];
464

    
465
    /* If this will change the current ASID, flush qemu's TLB.  */
466
    if (ASID != tlb->ASID)
467
        cpu_mips_tlb_flush (env, 1);
468

    
469
    r4k_mips_tlb_flush_extra(env, env->nb_tlb);
470

    
471
    env->CP0_EntryHi = tlb->VPN | tlb->ASID;
472
    env->CP0_PageMask = tlb->PageMask;
473
    env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
474
                        (tlb->C0 << 3) | (tlb->PFN[0] >> 6);
475
    env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
476
                        (tlb->C1 << 3) | (tlb->PFN[1] >> 6);
477
}
478

    
479
#endif /* !CONFIG_USER_ONLY */
480

    
481
void dump_ldst (const unsigned char *func)
482
{
483
    if (loglevel)
484
        fprintf(logfile, "%s => " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__, T0, T1);
485
}
486

    
487
void dump_sc (void)
488
{
489
    if (loglevel) {
490
        fprintf(logfile, "%s " TARGET_FMT_lx " at " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", __func__,
491
                T1, T0, env->CP0_LLAddr);
492
    }
493
}
494

    
495
void debug_pre_eret (void)
496
{
497
    fprintf(logfile, "ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
498
            env->PC, env->CP0_EPC);
499
    if (env->CP0_Status & (1 << CP0St_ERL))
500
        fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
501
    if (env->hflags & MIPS_HFLAG_DM)
502
        fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC);
503
    fputs("\n", logfile);
504
}
505

    
506
void debug_post_eret (void)
507
{
508
    fprintf(logfile, "  =>  PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
509
            env->PC, env->CP0_EPC);
510
    if (env->CP0_Status & (1 << CP0St_ERL))
511
        fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
512
    if (env->hflags & MIPS_HFLAG_DM)
513
        fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC);
514
    if (env->hflags & MIPS_HFLAG_UM)
515
        fputs(", UM\n", logfile);
516
    else
517
        fputs("\n", logfile);
518
}
519

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

    
546
#if !defined(CONFIG_USER_ONLY) 
547

    
548
static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr);
549

    
550
#define MMUSUFFIX _mmu
551
#define ALIGNED_ONLY
552

    
553
#define SHIFT 0
554
#include "softmmu_template.h"
555

    
556
#define SHIFT 1
557
#include "softmmu_template.h"
558

    
559
#define SHIFT 2
560
#include "softmmu_template.h"
561

    
562
#define SHIFT 3
563
#include "softmmu_template.h"
564

    
565
static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr)
566
{
567
    env->CP0_BadVAddr = addr;
568
    do_restore_state (retaddr);
569
    do_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL);
570
}
571

    
572
void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
573
{
574
    TranslationBlock *tb;
575
    CPUState *saved_env;
576
    unsigned long pc;
577
    int ret;
578

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

    
600
#endif
601

    
602
/* Complex FPU operations which may need stack space. */
603

    
604
/* convert MIPS rounding mode in FCR31 to IEEE library */
605
unsigned int ieee_rm[] = {
606
    float_round_nearest_even,
607
    float_round_to_zero,
608
    float_round_up,
609
    float_round_down
610
};
611

    
612
#define RESTORE_ROUNDING_MODE \
613
    set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status)
614

    
615
void do_ctc1 (void)
616
{
617
    switch(T1) {
618
    case 25:
619
        if (T0 & 0xffffff00)
620
            return;
621
        env->fcr31 = (env->fcr31 & 0x017fffff) | ((T0 & 0xfe) << 24) |
622
                     ((T0 & 0x1) << 23);
623
        break;
624
    case 26:
625
        if (T0 & 0x007c0000)
626
            return;
627
        env->fcr31 = (env->fcr31 & 0xfffc0f83) | (T0 & 0x0003f07c);
628
        break;
629
    case 28:
630
        if (T0 & 0x007c0000)
631
            return;
632
        env->fcr31 = (env->fcr31 & 0xfefff07c) | (T0 & 0x00000f83) |
633
                     ((T0 & 0x4) << 22);
634
        break;
635
    case 31:
636
        if (T0 & 0x007c0000)
637
            return;
638
        env->fcr31 = T0;
639
        break;
640
    default:
641
        return;
642
    }
643
    /* set rounding mode */
644
    RESTORE_ROUNDING_MODE;
645
    set_float_exception_flags(0, &env->fp_status);
646
    if ((GET_FP_ENABLE(env->fcr31) | 0x20) & GET_FP_CAUSE(env->fcr31))
647
        do_raise_exception(EXCP_FPE);
648
}
649

    
650
inline char ieee_ex_to_mips(char xcpt)
651
{
652
    return (xcpt & float_flag_inexact) >> 5 |
653
           (xcpt & float_flag_underflow) >> 3 |
654
           (xcpt & float_flag_overflow) >> 1 |
655
           (xcpt & float_flag_divbyzero) << 1 |
656
           (xcpt & float_flag_invalid) << 4;
657
}
658

    
659
inline char mips_ex_to_ieee(char xcpt)
660
{
661
    return (xcpt & FP_INEXACT) << 5 |
662
           (xcpt & FP_UNDERFLOW) << 3 |
663
           (xcpt & FP_OVERFLOW) << 1 |
664
           (xcpt & FP_DIV0) >> 1 |
665
           (xcpt & FP_INVALID) >> 4;
666
}
667

    
668
inline void update_fcr31(void)
669
{
670
    int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->fp_status));
671

    
672
    SET_FP_CAUSE(env->fcr31, tmp);
673
    if (GET_FP_ENABLE(env->fcr31) & tmp)
674
        do_raise_exception(EXCP_FPE);
675
    else
676
        UPDATE_FP_FLAGS(env->fcr31, tmp);
677
}
678

    
679
#define FLOAT_OP(name, p) void do_float_##name##_##p(void)
680

    
681
FLOAT_OP(cvtd, s)
682
{
683
    set_float_exception_flags(0, &env->fp_status);
684
    FDT2 = float32_to_float64(FST0, &env->fp_status);
685
    update_fcr31();
686
}
687
FLOAT_OP(cvtd, w)
688
{
689
    set_float_exception_flags(0, &env->fp_status);
690
    FDT2 = int32_to_float64(WT0, &env->fp_status);
691
    update_fcr31();
692
}
693
FLOAT_OP(cvtd, l)
694
{
695
    set_float_exception_flags(0, &env->fp_status);
696
    FDT2 = int64_to_float64(DT0, &env->fp_status);
697
    update_fcr31();
698
}
699
FLOAT_OP(cvtl, d)
700
{
701
    set_float_exception_flags(0, &env->fp_status);
702
    DT2 = float64_to_int64(FDT0, &env->fp_status);
703
    update_fcr31();
704
    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
705
        DT2 = 0x7fffffffffffffffULL;
706
}
707
FLOAT_OP(cvtl, s)
708
{
709
    set_float_exception_flags(0, &env->fp_status);
710
    DT2 = float32_to_int64(FST0, &env->fp_status);
711
    update_fcr31();
712
    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
713
        DT2 = 0x7fffffffffffffffULL;
714
}
715

    
716
FLOAT_OP(cvtps, pw)
717
{
718
    set_float_exception_flags(0, &env->fp_status);
719
    FST2 = int32_to_float32(WT0, &env->fp_status);
720
    FSTH2 = int32_to_float32(WTH0, &env->fp_status);
721
    update_fcr31();
722
}
723
FLOAT_OP(cvtpw, ps)
724
{
725
    set_float_exception_flags(0, &env->fp_status);
726
    WT2 = float32_to_int32(FST0, &env->fp_status);
727
    WTH2 = float32_to_int32(FSTH0, &env->fp_status);
728
    update_fcr31();
729
    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
730
        WT2 = 0x7fffffff;
731
}
732
FLOAT_OP(cvts, d)
733
{
734
    set_float_exception_flags(0, &env->fp_status);
735
    FST2 = float64_to_float32(FDT0, &env->fp_status);
736
    update_fcr31();
737
}
738
FLOAT_OP(cvts, w)
739
{
740
    set_float_exception_flags(0, &env->fp_status);
741
    FST2 = int32_to_float32(WT0, &env->fp_status);
742
    update_fcr31();
743
}
744
FLOAT_OP(cvts, l)
745
{
746
    set_float_exception_flags(0, &env->fp_status);
747
    FST2 = int64_to_float32(DT0, &env->fp_status);
748
    update_fcr31();
749
}
750
FLOAT_OP(cvts, pl)
751
{
752
    set_float_exception_flags(0, &env->fp_status);
753
    WT2 = WT0;
754
    update_fcr31();
755
}
756
FLOAT_OP(cvts, pu)
757
{
758
    set_float_exception_flags(0, &env->fp_status);
759
    WT2 = WTH0;
760
    update_fcr31();
761
}
762
FLOAT_OP(cvtw, s)
763
{
764
    set_float_exception_flags(0, &env->fp_status);
765
    WT2 = float32_to_int32(FST0, &env->fp_status);
766
    update_fcr31();
767
    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
768
        WT2 = 0x7fffffff;
769
}
770
FLOAT_OP(cvtw, d)
771
{
772
    set_float_exception_flags(0, &env->fp_status);
773
    WT2 = float64_to_int32(FDT0, &env->fp_status);
774
    update_fcr31();
775
    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
776
        WT2 = 0x7fffffff;
777
}
778

    
779
FLOAT_OP(roundl, d)
780
{
781
    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
782
    DT2 = float64_round_to_int(FDT0, &env->fp_status);
783
    RESTORE_ROUNDING_MODE;
784
    update_fcr31();
785
    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
786
        DT2 = 0x7fffffffffffffffULL;
787
}
788
FLOAT_OP(roundl, s)
789
{
790
    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
791
    DT2 = float32_round_to_int(FST0, &env->fp_status);
792
    RESTORE_ROUNDING_MODE;
793
    update_fcr31();
794
    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
795
        DT2 = 0x7fffffffffffffffULL;
796
}
797
FLOAT_OP(roundw, d)
798
{
799
    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
800
    WT2 = float64_round_to_int(FDT0, &env->fp_status);
801
    RESTORE_ROUNDING_MODE;
802
    update_fcr31();
803
    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
804
        WT2 = 0x7fffffff;
805
}
806
FLOAT_OP(roundw, s)
807
{
808
    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
809
    WT2 = float32_round_to_int(FST0, &env->fp_status);
810
    RESTORE_ROUNDING_MODE;
811
    update_fcr31();
812
    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
813
        WT2 = 0x7fffffff;
814
}
815

    
816
FLOAT_OP(truncl, d)
817
{
818
    DT2 = float64_to_int64_round_to_zero(FDT0, &env->fp_status);
819
    update_fcr31();
820
    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
821
        DT2 = 0x7fffffffffffffffULL;
822
}
823
FLOAT_OP(truncl, s)
824
{
825
    DT2 = float32_to_int64_round_to_zero(FST0, &env->fp_status);
826
    update_fcr31();
827
    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
828
        DT2 = 0x7fffffffffffffffULL;
829
}
830
FLOAT_OP(truncw, d)
831
{
832
    WT2 = float64_to_int32_round_to_zero(FDT0, &env->fp_status);
833
    update_fcr31();
834
    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
835
        WT2 = 0x7fffffff;
836
}
837
FLOAT_OP(truncw, s)
838
{
839
    WT2 = float32_to_int32_round_to_zero(FST0, &env->fp_status);
840
    update_fcr31();
841
    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
842
        WT2 = 0x7fffffff;
843
}
844

    
845
FLOAT_OP(ceill, d)
846
{
847
    set_float_rounding_mode(float_round_up, &env->fp_status);
848
    DT2 = float64_round_to_int(FDT0, &env->fp_status);
849
    RESTORE_ROUNDING_MODE;
850
    update_fcr31();
851
    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
852
        DT2 = 0x7fffffffffffffffULL;
853
}
854
FLOAT_OP(ceill, s)
855
{
856
    set_float_rounding_mode(float_round_up, &env->fp_status);
857
    DT2 = float32_round_to_int(FST0, &env->fp_status);
858
    RESTORE_ROUNDING_MODE;
859
    update_fcr31();
860
    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
861
        DT2 = 0x7fffffffffffffffULL;
862
}
863
FLOAT_OP(ceilw, d)
864
{
865
    set_float_rounding_mode(float_round_up, &env->fp_status);
866
    WT2 = float64_round_to_int(FDT0, &env->fp_status);
867
    RESTORE_ROUNDING_MODE;
868
    update_fcr31();
869
    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
870
        WT2 = 0x7fffffff;
871
}
872
FLOAT_OP(ceilw, s)
873
{
874
    set_float_rounding_mode(float_round_up, &env->fp_status);
875
    WT2 = float32_round_to_int(FST0, &env->fp_status);
876
    RESTORE_ROUNDING_MODE;
877
    update_fcr31();
878
    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
879
        WT2 = 0x7fffffff;
880
}
881

    
882
FLOAT_OP(floorl, d)
883
{
884
    set_float_rounding_mode(float_round_down, &env->fp_status);
885
    DT2 = float64_round_to_int(FDT0, &env->fp_status);
886
    RESTORE_ROUNDING_MODE;
887
    update_fcr31();
888
    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
889
        DT2 = 0x7fffffffffffffffULL;
890
}
891
FLOAT_OP(floorl, s)
892
{
893
    set_float_rounding_mode(float_round_down, &env->fp_status);
894
    DT2 = float32_round_to_int(FST0, &env->fp_status);
895
    RESTORE_ROUNDING_MODE;
896
    update_fcr31();
897
    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
898
        DT2 = 0x7fffffffffffffffULL;
899
}
900
FLOAT_OP(floorw, d)
901
{
902
    set_float_rounding_mode(float_round_down, &env->fp_status);
903
    WT2 = float64_round_to_int(FDT0, &env->fp_status);
904
    RESTORE_ROUNDING_MODE;
905
    update_fcr31();
906
    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
907
        WT2 = 0x7fffffff;
908
}
909
FLOAT_OP(floorw, s)
910
{
911
    set_float_rounding_mode(float_round_down, &env->fp_status);
912
    WT2 = float32_round_to_int(FST0, &env->fp_status);
913
    RESTORE_ROUNDING_MODE;
914
    update_fcr31();
915
    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
916
        WT2 = 0x7fffffff;
917
}
918

    
919
/* unary operations, MIPS specific, s and d */
920
#define FLOAT_UNOP(name)  \
921
FLOAT_OP(name, d)         \
922
{                         \
923
    set_float_exception_flags(0, &env->fp_status);            \
924
/* XXX: not implemented */ \
925
/*    FDT2 = float64_ ## name (FDT0, &env->fp_status);*/          \
926
do_raise_exception(EXCP_RI); \
927
    update_fcr31();       \
928
}                         \
929
FLOAT_OP(name, s)         \
930
{                         \
931
    set_float_exception_flags(0, &env->fp_status);            \
932
/* XXX: not implemented */ \
933
/*    FST2 = float32_ ## name (FST0, &env->fp_status);*/          \
934
do_raise_exception(EXCP_RI); \
935
    update_fcr31();       \
936
}
937
FLOAT_UNOP(rsqrt)
938
FLOAT_UNOP(recip)
939
#undef FLOAT_UNOP
940

    
941
/* unary operations, MIPS specific, s, d and ps */
942
#define FLOAT_UNOP(name)  \
943
FLOAT_OP(name, d)         \
944
{                         \
945
    set_float_exception_flags(0, &env->fp_status);            \
946
/* XXX: not implemented */ \
947
/*    FDT2 = float64_ ## name (FDT0, &env->fp_status);*/          \
948
do_raise_exception(EXCP_RI); \
949
    update_fcr31();       \
950
}                         \
951
FLOAT_OP(name, s)         \
952
{                         \
953
    set_float_exception_flags(0, &env->fp_status);            \
954
/* XXX: not implemented */ \
955
/*    FST2 = float32_ ## name (FST0, &env->fp_status);*/          \
956
do_raise_exception(EXCP_RI); \
957
    update_fcr31();       \
958
}                         \
959
FLOAT_OP(name, ps)        \
960
{                         \
961
    set_float_exception_flags(0, &env->fp_status);            \
962
/* XXX: not implemented */ \
963
/*    FST2 = float32_ ## name (FST0, &env->fp_status);*/          \
964
/*    FSTH2 = float32_ ## name (FSTH0, &env->fp_status);*/        \
965
do_raise_exception(EXCP_RI); \
966
    update_fcr31();       \
967
}
968
FLOAT_UNOP(rsqrt1)
969
FLOAT_UNOP(recip1)
970
#undef FLOAT_UNOP
971

    
972
/* binary operations */
973
#define FLOAT_BINOP(name) \
974
FLOAT_OP(name, d)         \
975
{                         \
976
    set_float_exception_flags(0, &env->fp_status);            \
977
    FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status);    \
978
    update_fcr31();                                           \
979
    if (GET_FP_CAUSE(env->fcr31) & FP_INVALID)                \
980
        FDT2 = 0x7ff7ffffffffffffULL;                         \
981
    else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) {       \
982
        if ((env->fcr31 & 0x3) == 0)                          \
983
            FDT2 &= 0x8000000000000000ULL;                    \
984
    }                     \
985
}                         \
986
FLOAT_OP(name, s)         \
987
{                         \
988
    set_float_exception_flags(0, &env->fp_status);            \
989
    FST2 = float32_ ## name (FST0, FST1, &env->fp_status);    \
990
    update_fcr31();                                           \
991
    if (GET_FP_CAUSE(env->fcr31) & FP_INVALID)                \
992
        FST2 = 0x7fbfffff;                                    \
993
    else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) {       \
994
        if ((env->fcr31 & 0x3) == 0)                          \
995
            FST2 &= 0x80000000ULL;                            \
996
    }                     \
997
}                         \
998
FLOAT_OP(name, ps)        \
999
{                         \
1000
    set_float_exception_flags(0, &env->fp_status);            \
1001
    FST2 = float32_ ## name (FST0, FST1, &env->fp_status);    \
1002
    FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fp_status); \
1003
    update_fcr31();       \
1004
    if (GET_FP_CAUSE(env->fcr31) & FP_INVALID) {              \
1005
        FST2 = 0x7fbfffff;                                    \
1006
        FSTH2 = 0x7fbfffff;                                   \
1007
    } else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) {     \
1008
        if ((env->fcr31 & 0x3) == 0) {                        \
1009
            FST2 &= 0x80000000ULL;                            \
1010
            FSTH2 &= 0x80000000ULL;                           \
1011
        }                 \
1012
    }                     \
1013
}
1014
FLOAT_BINOP(add)
1015
FLOAT_BINOP(sub)
1016
FLOAT_BINOP(mul)
1017
FLOAT_BINOP(div)
1018
#undef FLOAT_BINOP
1019

    
1020
/* binary operations, MIPS specific */
1021
#define FLOAT_BINOP(name) \
1022
FLOAT_OP(name, d)         \
1023
{                         \
1024
    set_float_exception_flags(0, &env->fp_status);            \
1025
/* XXX: not implemented */ \
1026
/*    FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status);*/    \
1027
do_raise_exception(EXCP_RI); \
1028
    update_fcr31();       \
1029
}                         \
1030
FLOAT_OP(name, s)         \
1031
{                         \
1032
    set_float_exception_flags(0, &env->fp_status);            \
1033
/* XXX: not implemented */ \
1034
/*    FST2 = float32_ ## name (FST0, FST1, &env->fp_status);*/    \
1035
do_raise_exception(EXCP_RI); \
1036
    update_fcr31();       \
1037
}                         \
1038
FLOAT_OP(name, ps)        \
1039
{                         \
1040
    set_float_exception_flags(0, &env->fp_status);            \
1041
/* XXX: not implemented */ \
1042
/*    FST2 = float32_ ## name (FST0, FST1, &env->fp_status);*/    \
1043
/*    FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fp_status);*/ \
1044
do_raise_exception(EXCP_RI); \
1045
    update_fcr31();       \
1046
}
1047
FLOAT_BINOP(rsqrt2)
1048
FLOAT_BINOP(recip2)
1049
#undef FLOAT_BINOP
1050

    
1051
FLOAT_OP(addr, ps)
1052
{
1053
    set_float_exception_flags(0, &env->fp_status);
1054
    FST2 = float32_add (FST0, FSTH0, &env->fp_status);
1055
    FSTH2 = float32_add (FST1, FSTH1, &env->fp_status);
1056
    update_fcr31();
1057
}
1058

    
1059
FLOAT_OP(mulr, ps)
1060
{
1061
    set_float_exception_flags(0, &env->fp_status);
1062
    FST2 = float32_mul (FST0, FSTH0, &env->fp_status);
1063
    FSTH2 = float32_mul (FST1, FSTH1, &env->fp_status);
1064
    update_fcr31();
1065
}
1066

    
1067
#define FOP_COND_D(op, cond)                   \
1068
void do_cmp_d_ ## op (long cc)                 \
1069
{                                              \
1070
    int c = cond;                              \
1071
    update_fcr31();                            \
1072
    if (c)                                     \
1073
        SET_FP_COND(cc, env);                  \
1074
    else                                       \
1075
        CLEAR_FP_COND(cc, env);                \
1076
}                                              \
1077
void do_cmpabs_d_ ## op (long cc)              \
1078
{                                              \
1079
    int c;                                     \
1080
    FDT0 &= ~(1ULL << 63);                     \
1081
    FDT1 &= ~(1ULL << 63);                     \
1082
    c = cond;                                  \
1083
    update_fcr31();                            \
1084
    if (c)                                     \
1085
        SET_FP_COND(cc, env);                  \
1086
    else                                       \
1087
        CLEAR_FP_COND(cc, env);                \
1088
}
1089

    
1090
int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM)
1091
{
1092
    if (float64_is_signaling_nan(a) ||
1093
        float64_is_signaling_nan(b) ||
1094
        (sig && (float64_is_nan(a) || float64_is_nan(b)))) {
1095
        float_raise(float_flag_invalid, status);
1096
        return 1;
1097
    } else if (float64_is_nan(a) || float64_is_nan(b)) {
1098
        return 1;
1099
    } else {
1100
        return 0;
1101
    }
1102
}
1103

    
1104
/* NOTE: the comma operator will make "cond" to eval to false,
1105
 * but float*_is_unordered() is still called. */
1106
FOP_COND_D(f,   (float64_is_unordered(0, FDT1, FDT0, &env->fp_status), 0))
1107
FOP_COND_D(un,  float64_is_unordered(0, FDT1, FDT0, &env->fp_status))
1108
FOP_COND_D(eq,  !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status))
1109
FOP_COND_D(ueq, float64_is_unordered(0, FDT1, FDT0, &env->fp_status)  || float64_eq(FDT0, FDT1, &env->fp_status))
1110
FOP_COND_D(olt, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status))
1111
FOP_COND_D(ult, float64_is_unordered(0, FDT1, FDT0, &env->fp_status)  || float64_lt(FDT0, FDT1, &env->fp_status))
1112
FOP_COND_D(ole, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status))
1113
FOP_COND_D(ule, float64_is_unordered(0, FDT1, FDT0, &env->fp_status)  || float64_le(FDT0, FDT1, &env->fp_status))
1114
/* NOTE: the comma operator will make "cond" to eval to false,
1115
 * but float*_is_unordered() is still called. */
1116
FOP_COND_D(sf,  (float64_is_unordered(1, FDT1, FDT0, &env->fp_status), 0))
1117
FOP_COND_D(ngle,float64_is_unordered(1, FDT1, FDT0, &env->fp_status))
1118
FOP_COND_D(seq, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status))
1119
FOP_COND_D(ngl, float64_is_unordered(1, FDT1, FDT0, &env->fp_status)  || float64_eq(FDT0, FDT1, &env->fp_status))
1120
FOP_COND_D(lt,  !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status))
1121
FOP_COND_D(nge, float64_is_unordered(1, FDT1, FDT0, &env->fp_status)  || float64_lt(FDT0, FDT1, &env->fp_status))
1122
FOP_COND_D(le,  !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status))
1123
FOP_COND_D(ngt, float64_is_unordered(1, FDT1, FDT0, &env->fp_status)  || float64_le(FDT0, FDT1, &env->fp_status))
1124

    
1125
#define FOP_COND_S(op, cond)                   \
1126
void do_cmp_s_ ## op (long cc)                 \
1127
{                                              \
1128
    int c = cond;                              \
1129
    update_fcr31();                            \
1130
    if (c)                                     \
1131
        SET_FP_COND(cc, env);                  \
1132
    else                                       \
1133
        CLEAR_FP_COND(cc, env);                \
1134
}                                              \
1135
void do_cmpabs_s_ ## op (long cc)              \
1136
{                                              \
1137
    int c;                                     \
1138
    FST0 &= ~(1 << 31);                        \
1139
    FST1 &= ~(1 << 31);                        \
1140
    c = cond;                                  \
1141
    update_fcr31();                            \
1142
    if (c)                                     \
1143
        SET_FP_COND(cc, env);                  \
1144
    else                                       \
1145
        CLEAR_FP_COND(cc, env);                \
1146
}
1147

    
1148
flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM)
1149
{
1150
    if (float32_is_signaling_nan(a) ||
1151
        float32_is_signaling_nan(b) ||
1152
        (sig && (float32_is_nan(a) || float32_is_nan(b)))) {
1153
        float_raise(float_flag_invalid, status);
1154
        return 1;
1155
    } else if (float32_is_nan(a) || float32_is_nan(b)) {
1156
        return 1;
1157
    } else {
1158
        return 0;
1159
    }
1160
}
1161

    
1162
/* NOTE: the comma operator will make "cond" to eval to false,
1163
 * but float*_is_unordered() is still called. */
1164
FOP_COND_S(f,   (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0))
1165
FOP_COND_S(un,  float32_is_unordered(0, FST1, FST0, &env->fp_status))
1166
FOP_COND_S(eq,  !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status))
1167
FOP_COND_S(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status)  || float32_eq(FST0, FST1, &env->fp_status))
1168
FOP_COND_S(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status))
1169
FOP_COND_S(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status)  || float32_lt(FST0, FST1, &env->fp_status))
1170
FOP_COND_S(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status))
1171
FOP_COND_S(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status)  || float32_le(FST0, FST1, &env->fp_status))
1172
/* NOTE: the comma operator will make "cond" to eval to false,
1173
 * but float*_is_unordered() is still called. */
1174
FOP_COND_S(sf,  (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0))
1175
FOP_COND_S(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status))
1176
FOP_COND_S(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status))
1177
FOP_COND_S(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status)  || float32_eq(FST0, FST1, &env->fp_status))
1178
FOP_COND_S(lt,  !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status))
1179
FOP_COND_S(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status)  || float32_lt(FST0, FST1, &env->fp_status))
1180
FOP_COND_S(le,  !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status))
1181
FOP_COND_S(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status)  || float32_le(FST0, FST1, &env->fp_status))
1182

    
1183
#define FOP_COND_PS(op, condl, condh)          \
1184
void do_cmp_ps_ ## op (long cc)                \
1185
{                                              \
1186
    int cl = condl;                            \
1187
    int ch = condh;                            \
1188
    update_fcr31();                            \
1189
    if (cl)                                    \
1190
        SET_FP_COND(cc, env);                  \
1191
    else                                       \
1192
        CLEAR_FP_COND(cc, env);                \
1193
    if (ch)                                    \
1194
        SET_FP_COND(cc + 1, env);              \
1195
    else                                       \
1196
        CLEAR_FP_COND(cc + 1, env);            \
1197
}                                              \
1198
void do_cmpabs_ps_ ## op (long cc)             \
1199
{                                              \
1200
    int cl, ch;                                \
1201
    FST0 &= ~(1 << 31);                        \
1202
    FSTH0 &= ~(1 << 31);                       \
1203
    FST1 &= ~(1 << 31);                        \
1204
    FSTH1 &= ~(1 << 31);                       \
1205
    cl = condl;                                \
1206
    ch = condh;                                \
1207
    update_fcr31();                            \
1208
    if (cl)                                    \
1209
        SET_FP_COND(cc, env);                  \
1210
    else                                       \
1211
        CLEAR_FP_COND(cc, env);                \
1212
    if (ch)                                    \
1213
        SET_FP_COND(cc + 1, env);              \
1214
    else                                       \
1215
        CLEAR_FP_COND(cc + 1, env);            \
1216
}
1217

    
1218
/* NOTE: the comma operator will make "cond" to eval to false,
1219
 * but float*_is_unordered() is still called. */
1220
FOP_COND_PS(f,   (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0),
1221
                 (float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status), 0))
1222
FOP_COND_PS(un,  float32_is_unordered(0, FST1, FST0, &env->fp_status),
1223
                 float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status))
1224
FOP_COND_PS(eq,  !float32_is_unordered(0, FST1, FST0, &env->fp_status)   && float32_eq(FST0, FST1, &env->fp_status),
1225
                 !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status))
1226
FOP_COND_PS(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status)    || float32_eq(FST0, FST1, &env->fp_status),
1227
                 float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status)  || float32_eq(FSTH0, FSTH1, &env->fp_status))
1228
FOP_COND_PS(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status)   && float32_lt(FST0, FST1, &env->fp_status),
1229
                 !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status))
1230
FOP_COND_PS(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status)    || float32_lt(FST0, FST1, &env->fp_status),
1231
                 float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status)  || float32_lt(FSTH0, FSTH1, &env->fp_status))
1232
FOP_COND_PS(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status)   && float32_le(FST0, FST1, &env->fp_status),
1233
                 !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status))
1234
FOP_COND_PS(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status)    || float32_le(FST0, FST1, &env->fp_status),
1235
                 float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status)  || float32_le(FSTH0, FSTH1, &env->fp_status))
1236
/* NOTE: the comma operator will make "cond" to eval to false,
1237
 * but float*_is_unordered() is still called. */
1238
FOP_COND_PS(sf,  (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0),
1239
                 (float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status), 0))
1240
FOP_COND_PS(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status),
1241
                 float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status))
1242
FOP_COND_PS(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status)   && float32_eq(FST0, FST1, &env->fp_status),
1243
                 !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status))
1244
FOP_COND_PS(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status)    || float32_eq(FST0, FST1, &env->fp_status),
1245
                 float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status)  || float32_eq(FSTH0, FSTH1, &env->fp_status))
1246
FOP_COND_PS(lt,  !float32_is_unordered(1, FST1, FST0, &env->fp_status)   && float32_lt(FST0, FST1, &env->fp_status),
1247
                 !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status))
1248
FOP_COND_PS(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status)    || float32_lt(FST0, FST1, &env->fp_status),
1249
                 float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status)  || float32_lt(FSTH0, FSTH1, &env->fp_status))
1250
FOP_COND_PS(le,  !float32_is_unordered(1, FST1, FST0, &env->fp_status)   && float32_le(FST0, FST1, &env->fp_status),
1251
                 !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status))
1252
FOP_COND_PS(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status)    || float32_le(FST0, FST1, &env->fp_status),
1253
                 float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status)  || float32_le(FSTH0, FSTH1, &env->fp_status))