Statistics
| Branch: | Revision:

root / target-mips / op_helper.c @ 95af5ce5

History | View | Annotate | Download (44.4 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
#ifdef __s390__
26
# define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL))
27
#else
28
# define GETPC() (__builtin_return_address(0))
29
#endif
30

    
31
/*****************************************************************************/
32
/* Exceptions processing helpers */
33

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

    
46
void do_raise_exception (uint32_t exception)
47
{
48
    do_raise_exception_err(exception, 0);
49
}
50

    
51
void do_interrupt_restart (void)
52
{
53
    if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
54
        !(env->CP0_Status & (1 << CP0St_ERL)) &&
55
        !(env->hflags & MIPS_HFLAG_DM) &&
56
        (env->CP0_Status & (1 << CP0St_IE)) &&
57
        (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask)) {
58
        env->CP0_Cause &= ~(0x1f << CP0Ca_EC);
59
        do_raise_exception(EXCP_EXT_INTERRUPT);
60
    }
61
}
62

    
63
void do_restore_state (void *pc_ptr)
64
{
65
    TranslationBlock *tb;
66
    unsigned long pc = (unsigned long) pc_ptr;
67
    
68
    tb = tb_find_pc (pc);
69
    if (tb) {
70
        cpu_restore_state (tb, env, pc, NULL);
71
    }
72
}
73

    
74
void do_clo (void)
75
{
76
    T0 = clo32(T0);
77
}
78

    
79
void do_clz (void)
80
{
81
    T0 = clz32(T0);
82
}
83

    
84
#if defined(TARGET_MIPS64)
85
#if TARGET_LONG_BITS > HOST_LONG_BITS
86
/* Those might call libgcc functions.  */
87
void do_dsll (void)
88
{
89
    T0 = T0 << T1;
90
}
91

    
92
void do_dsll32 (void)
93
{
94
    T0 = T0 << (T1 + 32);
95
}
96

    
97
void do_dsra (void)
98
{
99
    T0 = (int64_t)T0 >> T1;
100
}
101

    
102
void do_dsra32 (void)
103
{
104
    T0 = (int64_t)T0 >> (T1 + 32);
105
}
106

    
107
void do_dsrl (void)
108
{
109
    T0 = T0 >> T1;
110
}
111

    
112
void do_dsrl32 (void)
113
{
114
    T0 = T0 >> (T1 + 32);
115
}
116

    
117
void do_drotr (void)
118
{
119
    target_ulong tmp;
120

    
121
    if (T1) {
122
        tmp = T0 << (0x40 - T1);
123
        T0 = (T0 >> T1) | tmp;
124
    }
125
}
126

    
127
void do_drotr32 (void)
128
{
129
    target_ulong tmp;
130

    
131
    tmp = T0 << (0x40 - (32 + T1));
132
    T0 = (T0 >> (32 + T1)) | tmp;
133
}
134

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

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

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

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

    
154
    T0 &= 0x3F;
155
    if (T0) {
156
        tmp = T1 << (0x40 - T0);
157
        T0 = (T1 >> T0) | tmp;
158
    } else
159
        T0 = T1;
160
}
161

    
162
#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */
163

    
164
void do_dclo (void)
165
{
166
    T0 = clo64(T0);
167
}
168

    
169
void do_dclz (void)
170
{
171
    T0 = clz64(T0);
172
}
173

    
174
#endif /* TARGET_MIPS64 */
175

    
176
/* 64 bits arithmetic for 32 bits hosts */
177
#if TARGET_LONG_BITS > HOST_LONG_BITS
178
static always_inline uint64_t get_HILO (void)
179
{
180
    return (env->HI[env->current_tc][0] << 32) | (uint32_t)env->LO[env->current_tc][0];
181
}
182

    
183
static always_inline void set_HILO (uint64_t HILO)
184
{
185
    env->LO[env->current_tc][0] = (int32_t)HILO;
186
    env->HI[env->current_tc][0] = (int32_t)(HILO >> 32);
187
}
188

    
189
static always_inline void set_HIT0_LO (uint64_t HILO)
190
{
191
    env->LO[env->current_tc][0] = (int32_t)(HILO & 0xFFFFFFFF);
192
    T0 = env->HI[env->current_tc][0] = (int32_t)(HILO >> 32);
193
}
194

    
195
static always_inline void set_HI_LOT0 (uint64_t HILO)
196
{
197
    T0 = env->LO[env->current_tc][0] = (int32_t)(HILO & 0xFFFFFFFF);
198
    env->HI[env->current_tc][0] = (int32_t)(HILO >> 32);
199
}
200

    
201
void do_mult (void)
202
{
203
    set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
204
}
205

    
206
void do_multu (void)
207
{
208
    set_HILO((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
209
}
210

    
211
void do_madd (void)
212
{
213
    int64_t tmp;
214

    
215
    tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
216
    set_HILO((int64_t)get_HILO() + tmp);
217
}
218

    
219
void do_maddu (void)
220
{
221
    uint64_t tmp;
222

    
223
    tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
224
    set_HILO(get_HILO() + tmp);
225
}
226

    
227
void do_msub (void)
228
{
229
    int64_t tmp;
230

    
231
    tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
232
    set_HILO((int64_t)get_HILO() - tmp);
233
}
234

    
235
void do_msubu (void)
236
{
237
    uint64_t tmp;
238

    
239
    tmp = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
240
    set_HILO(get_HILO() - tmp);
241
}
242

    
243
/* Multiplication variants of the vr54xx. */
244
void do_muls (void)
245
{
246
    set_HI_LOT0(0 - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
247
}
248

    
249
void do_mulsu (void)
250
{
251
    set_HI_LOT0(0 - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
252
}
253

    
254
void do_macc (void)
255
{
256
    set_HI_LOT0(((int64_t)get_HILO()) + ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
257
}
258

    
259
void do_macchi (void)
260
{
261
    set_HIT0_LO(((int64_t)get_HILO()) + ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
262
}
263

    
264
void do_maccu (void)
265
{
266
    set_HI_LOT0(((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
267
}
268

    
269
void do_macchiu (void)
270
{
271
    set_HIT0_LO(((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
272
}
273

    
274
void do_msac (void)
275
{
276
    set_HI_LOT0(((int64_t)get_HILO()) - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
277
}
278

    
279
void do_msachi (void)
280
{
281
    set_HIT0_LO(((int64_t)get_HILO()) - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
282
}
283

    
284
void do_msacu (void)
285
{
286
    set_HI_LOT0(((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
287
}
288

    
289
void do_msachiu (void)
290
{
291
    set_HIT0_LO(((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
292
}
293

    
294
void do_mulhi (void)
295
{
296
    set_HIT0_LO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
297
}
298

    
299
void do_mulhiu (void)
300
{
301
    set_HIT0_LO((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1);
302
}
303

    
304
void do_mulshi (void)
305
{
306
    set_HIT0_LO(0 - ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1));
307
}
308

    
309
void do_mulshiu (void)
310
{
311
    set_HIT0_LO(0 - ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1));
312
}
313
#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */
314

    
315
#if defined(CONFIG_USER_ONLY)
316
void do_mfc0_random (void)
317
{
318
    cpu_abort(env, "mfc0 random\n");
319
}
320

    
321
void do_mfc0_count (void)
322
{
323
    cpu_abort(env, "mfc0 count\n");
324
}
325

    
326
void cpu_mips_store_count(CPUState *env, uint32_t value)
327
{
328
    cpu_abort(env, "mtc0 count\n");
329
}
330

    
331
void cpu_mips_store_compare(CPUState *env, uint32_t value)
332
{
333
    cpu_abort(env, "mtc0 compare\n");
334
}
335

    
336
void cpu_mips_start_count(CPUState *env)
337
{
338
    cpu_abort(env, "start count\n");
339
}
340

    
341
void cpu_mips_stop_count(CPUState *env)
342
{
343
    cpu_abort(env, "stop count\n");
344
}
345

    
346
void cpu_mips_update_irq(CPUState *env)
347
{
348
    cpu_abort(env, "mtc0 status / mtc0 cause\n");
349
}
350

    
351
void do_mtc0_status_debug(uint32_t old, uint32_t val)
352
{
353
    cpu_abort(env, "mtc0 status debug\n");
354
}
355

    
356
void do_mtc0_status_irqraise_debug (void)
357
{
358
    cpu_abort(env, "mtc0 status irqraise debug\n");
359
}
360

    
361
void cpu_mips_tlb_flush (CPUState *env, int flush_global)
362
{
363
    cpu_abort(env, "mips_tlb_flush\n");
364
}
365

    
366
#else
367

    
368
/* CP0 helpers */
369
void do_mfc0_random (void)
370
{
371
    T0 = (int32_t)cpu_mips_get_random(env);
372
}
373

    
374
void do_mfc0_count (void)
375
{
376
    T0 = (int32_t)cpu_mips_get_count(env);
377
}
378

    
379
void do_mtc0_status_debug(uint32_t old, uint32_t val)
380
{
381
    fprintf(logfile, "Status %08x (%08x) => %08x (%08x) Cause %08x",
382
            old, old & env->CP0_Cause & CP0Ca_IP_mask,
383
            val, val & env->CP0_Cause & CP0Ca_IP_mask,
384
            env->CP0_Cause);
385
    switch (env->hflags & MIPS_HFLAG_KSU) {
386
    case MIPS_HFLAG_UM: fputs(", UM\n", logfile); break;
387
    case MIPS_HFLAG_SM: fputs(", SM\n", logfile); break;
388
    case MIPS_HFLAG_KM: fputs("\n", logfile); break;
389
    default: cpu_abort(env, "Invalid MMU mode!\n"); break;
390
    }
391
}
392

    
393
void do_mtc0_status_irqraise_debug(void)
394
{
395
    fprintf(logfile, "Raise pending IRQs\n");
396
}
397

    
398
void fpu_handle_exception(void)
399
{
400
#ifdef CONFIG_SOFTFLOAT
401
    int flags = get_float_exception_flags(&env->fpu->fp_status);
402
    unsigned int cpuflags = 0, enable, cause = 0;
403

    
404
    enable = GET_FP_ENABLE(env->fpu->fcr31);
405

    
406
    /* determine current flags */
407
    if (flags & float_flag_invalid) {
408
        cpuflags |= FP_INVALID;
409
        cause |= FP_INVALID & enable;
410
    }
411
    if (flags & float_flag_divbyzero) {
412
        cpuflags |= FP_DIV0;
413
        cause |= FP_DIV0 & enable;
414
    }
415
    if (flags & float_flag_overflow) {
416
        cpuflags |= FP_OVERFLOW;
417
        cause |= FP_OVERFLOW & enable;
418
    }
419
    if (flags & float_flag_underflow) {
420
        cpuflags |= FP_UNDERFLOW;
421
        cause |= FP_UNDERFLOW & enable;
422
    }
423
    if (flags & float_flag_inexact) {
424
        cpuflags |= FP_INEXACT;
425
        cause |= FP_INEXACT & enable;
426
    }
427
    SET_FP_FLAGS(env->fpu->fcr31, cpuflags);
428
    SET_FP_CAUSE(env->fpu->fcr31, cause);
429
#else
430
    SET_FP_FLAGS(env->fpu->fcr31, 0);
431
    SET_FP_CAUSE(env->fpu->fcr31, 0);
432
#endif
433
}
434

    
435
/* TLB management */
436
void cpu_mips_tlb_flush (CPUState *env, int flush_global)
437
{
438
    /* Flush qemu's TLB and discard all shadowed entries.  */
439
    tlb_flush (env, flush_global);
440
    env->tlb->tlb_in_use = env->tlb->nb_tlb;
441
}
442

    
443
static void r4k_mips_tlb_flush_extra (CPUState *env, int first)
444
{
445
    /* Discard entries from env->tlb[first] onwards.  */
446
    while (env->tlb->tlb_in_use > first) {
447
        r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
448
    }
449
}
450

    
451
static void r4k_fill_tlb (int idx)
452
{
453
    r4k_tlb_t *tlb;
454

    
455
    /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
456
    tlb = &env->tlb->mmu.r4k.tlb[idx];
457
    tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
458
#if defined(TARGET_MIPS64)
459
    tlb->VPN &= env->SEGMask;
460
#endif
461
    tlb->ASID = env->CP0_EntryHi & 0xFF;
462
    tlb->PageMask = env->CP0_PageMask;
463
    tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
464
    tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
465
    tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
466
    tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
467
    tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
468
    tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
469
    tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
470
    tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
471
    tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
472
}
473

    
474
void r4k_do_tlbwi (void)
475
{
476
    /* Discard cached TLB entries.  We could avoid doing this if the
477
       tlbwi is just upgrading access permissions on the current entry;
478
       that might be a further win.  */
479
    r4k_mips_tlb_flush_extra (env, env->tlb->nb_tlb);
480

    
481
    r4k_invalidate_tlb(env, env->CP0_Index % env->tlb->nb_tlb, 0);
482
    r4k_fill_tlb(env->CP0_Index % env->tlb->nb_tlb);
483
}
484

    
485
void r4k_do_tlbwr (void)
486
{
487
    int r = cpu_mips_get_random(env);
488

    
489
    r4k_invalidate_tlb(env, r, 1);
490
    r4k_fill_tlb(r);
491
}
492

    
493
void r4k_do_tlbp (void)
494
{
495
    r4k_tlb_t *tlb;
496
    target_ulong mask;
497
    target_ulong tag;
498
    target_ulong VPN;
499
    uint8_t ASID;
500
    int i;
501

    
502
    ASID = env->CP0_EntryHi & 0xFF;
503
    for (i = 0; i < env->tlb->nb_tlb; i++) {
504
        tlb = &env->tlb->mmu.r4k.tlb[i];
505
        /* 1k pages are not supported. */
506
        mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
507
        tag = env->CP0_EntryHi & ~mask;
508
        VPN = tlb->VPN & ~mask;
509
        /* Check ASID, virtual page number & size */
510
        if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
511
            /* TLB match */
512
            env->CP0_Index = i;
513
            break;
514
        }
515
    }
516
    if (i == env->tlb->nb_tlb) {
517
        /* No match.  Discard any shadow entries, if any of them match.  */
518
        for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
519
            tlb = &env->tlb->mmu.r4k.tlb[i];
520
            /* 1k pages are not supported. */
521
            mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
522
            tag = env->CP0_EntryHi & ~mask;
523
            VPN = tlb->VPN & ~mask;
524
            /* Check ASID, virtual page number & size */
525
            if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
526
                r4k_mips_tlb_flush_extra (env, i);
527
                break;
528
            }
529
        }
530

    
531
        env->CP0_Index |= 0x80000000;
532
    }
533
}
534

    
535
void r4k_do_tlbr (void)
536
{
537
    r4k_tlb_t *tlb;
538
    uint8_t ASID;
539

    
540
    ASID = env->CP0_EntryHi & 0xFF;
541
    tlb = &env->tlb->mmu.r4k.tlb[env->CP0_Index % env->tlb->nb_tlb];
542

    
543
    /* If this will change the current ASID, flush qemu's TLB.  */
544
    if (ASID != tlb->ASID)
545
        cpu_mips_tlb_flush (env, 1);
546

    
547
    r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
548

    
549
    env->CP0_EntryHi = tlb->VPN | tlb->ASID;
550
    env->CP0_PageMask = tlb->PageMask;
551
    env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
552
                        (tlb->C0 << 3) | (tlb->PFN[0] >> 6);
553
    env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
554
                        (tlb->C1 << 3) | (tlb->PFN[1] >> 6);
555
}
556

    
557
#endif /* !CONFIG_USER_ONLY */
558

    
559
void dump_ldst (const unsigned char *func)
560
{
561
    if (loglevel)
562
        fprintf(logfile, "%s => " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__, T0, T1);
563
}
564

    
565
void dump_sc (void)
566
{
567
    if (loglevel) {
568
        fprintf(logfile, "%s " TARGET_FMT_lx " at " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", __func__,
569
                T1, T0, env->CP0_LLAddr);
570
    }
571
}
572

    
573
void debug_pre_eret (void)
574
{
575
    fprintf(logfile, "ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
576
            env->PC[env->current_tc], env->CP0_EPC);
577
    if (env->CP0_Status & (1 << CP0St_ERL))
578
        fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
579
    if (env->hflags & MIPS_HFLAG_DM)
580
        fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC);
581
    fputs("\n", logfile);
582
}
583

    
584
void debug_post_eret (void)
585
{
586
    fprintf(logfile, "  =>  PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
587
            env->PC[env->current_tc], env->CP0_EPC);
588
    if (env->CP0_Status & (1 << CP0St_ERL))
589
        fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
590
    if (env->hflags & MIPS_HFLAG_DM)
591
        fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC);
592
    switch (env->hflags & MIPS_HFLAG_KSU) {
593
    case MIPS_HFLAG_UM: fputs(", UM\n", logfile); break;
594
    case MIPS_HFLAG_SM: fputs(", SM\n", logfile); break;
595
    case MIPS_HFLAG_KM: fputs("\n", logfile); break;
596
    default: cpu_abort(env, "Invalid MMU mode!\n"); break;
597
    }
598
}
599

    
600
void do_pmon (int function)
601
{
602
    function /= 2;
603
    switch (function) {
604
    case 2: /* TODO: char inbyte(int waitflag); */
605
        if (env->gpr[env->current_tc][4] == 0)
606
            env->gpr[env->current_tc][2] = -1;
607
        /* Fall through */
608
    case 11: /* TODO: char inbyte (void); */
609
        env->gpr[env->current_tc][2] = -1;
610
        break;
611
    case 3:
612
    case 12:
613
        printf("%c", (char)(env->gpr[env->current_tc][4] & 0xFF));
614
        break;
615
    case 17:
616
        break;
617
    case 158:
618
        {
619
            unsigned char *fmt = (void *)(unsigned long)env->gpr[env->current_tc][4];
620
            printf("%s", fmt);
621
        }
622
        break;
623
    }
624
}
625

    
626
#if !defined(CONFIG_USER_ONLY)
627

    
628
static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr);
629

    
630
#define MMUSUFFIX _mmu
631
#define ALIGNED_ONLY
632

    
633
#define SHIFT 0
634
#include "softmmu_template.h"
635

    
636
#define SHIFT 1
637
#include "softmmu_template.h"
638

    
639
#define SHIFT 2
640
#include "softmmu_template.h"
641

    
642
#define SHIFT 3
643
#include "softmmu_template.h"
644

    
645
static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr)
646
{
647
    env->CP0_BadVAddr = addr;
648
    do_restore_state (retaddr);
649
    do_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL);
650
}
651

    
652
void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
653
{
654
    TranslationBlock *tb;
655
    CPUState *saved_env;
656
    unsigned long pc;
657
    int ret;
658

    
659
    /* XXX: hack to restore env in all cases, even if not called from
660
       generated code */
661
    saved_env = env;
662
    env = cpu_single_env;
663
    ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
664
    if (ret) {
665
        if (retaddr) {
666
            /* now we have a real cpu fault */
667
            pc = (unsigned long)retaddr;
668
            tb = tb_find_pc(pc);
669
            if (tb) {
670
                /* the PC is inside the translated code. It means that we have
671
                   a virtual CPU fault */
672
                cpu_restore_state(tb, env, pc, NULL);
673
            }
674
        }
675
        do_raise_exception_err(env->exception_index, env->error_code);
676
    }
677
    env = saved_env;
678
}
679

    
680
void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
681
                          int unused)
682
{
683
    if (is_exec)
684
        do_raise_exception(EXCP_IBE);
685
    else
686
        do_raise_exception(EXCP_DBE);
687
}
688
#endif
689

    
690
/* Complex FPU operations which may need stack space. */
691

    
692
#define FLOAT_ONE32 make_float32(0x3f8 << 20)
693
#define FLOAT_ONE64 make_float64(0x3ffULL << 52)
694
#define FLOAT_TWO32 make_float32(1 << 30)
695
#define FLOAT_TWO64 make_float64(1ULL << 62)
696
#define FLOAT_QNAN32 0x7fbfffff
697
#define FLOAT_QNAN64 0x7ff7ffffffffffffULL
698
#define FLOAT_SNAN32 0x7fffffff
699
#define FLOAT_SNAN64 0x7fffffffffffffffULL
700

    
701
/* convert MIPS rounding mode in FCR31 to IEEE library */
702
unsigned int ieee_rm[] = {
703
    float_round_nearest_even,
704
    float_round_to_zero,
705
    float_round_up,
706
    float_round_down
707
};
708

    
709
#define RESTORE_ROUNDING_MODE \
710
    set_float_rounding_mode(ieee_rm[env->fpu->fcr31 & 3], &env->fpu->fp_status)
711

    
712
void do_cfc1 (int reg)
713
{
714
    switch (reg) {
715
    case 0:
716
        T0 = (int32_t)env->fpu->fcr0;
717
        break;
718
    case 25:
719
        T0 = ((env->fpu->fcr31 >> 24) & 0xfe) | ((env->fpu->fcr31 >> 23) & 0x1);
720
        break;
721
    case 26:
722
        T0 = env->fpu->fcr31 & 0x0003f07c;
723
        break;
724
    case 28:
725
        T0 = (env->fpu->fcr31 & 0x00000f83) | ((env->fpu->fcr31 >> 22) & 0x4);
726
        break;
727
    default:
728
        T0 = (int32_t)env->fpu->fcr31;
729
        break;
730
    }
731
}
732

    
733
void do_ctc1 (int reg)
734
{
735
    switch(reg) {
736
    case 25:
737
        if (T0 & 0xffffff00)
738
            return;
739
        env->fpu->fcr31 = (env->fpu->fcr31 & 0x017fffff) | ((T0 & 0xfe) << 24) |
740
                     ((T0 & 0x1) << 23);
741
        break;
742
    case 26:
743
        if (T0 & 0x007c0000)
744
            return;
745
        env->fpu->fcr31 = (env->fpu->fcr31 & 0xfffc0f83) | (T0 & 0x0003f07c);
746
        break;
747
    case 28:
748
        if (T0 & 0x007c0000)
749
            return;
750
        env->fpu->fcr31 = (env->fpu->fcr31 & 0xfefff07c) | (T0 & 0x00000f83) |
751
                     ((T0 & 0x4) << 22);
752
        break;
753
    case 31:
754
        if (T0 & 0x007c0000)
755
            return;
756
        env->fpu->fcr31 = T0;
757
        break;
758
    default:
759
        return;
760
    }
761
    /* set rounding mode */
762
    RESTORE_ROUNDING_MODE;
763
    set_float_exception_flags(0, &env->fpu->fp_status);
764
    if ((GET_FP_ENABLE(env->fpu->fcr31) | 0x20) & GET_FP_CAUSE(env->fpu->fcr31))
765
        do_raise_exception(EXCP_FPE);
766
}
767

    
768
static always_inline char ieee_ex_to_mips(char xcpt)
769
{
770
    return (xcpt & float_flag_inexact) >> 5 |
771
           (xcpt & float_flag_underflow) >> 3 |
772
           (xcpt & float_flag_overflow) >> 1 |
773
           (xcpt & float_flag_divbyzero) << 1 |
774
           (xcpt & float_flag_invalid) << 4;
775
}
776

    
777
static always_inline char mips_ex_to_ieee(char xcpt)
778
{
779
    return (xcpt & FP_INEXACT) << 5 |
780
           (xcpt & FP_UNDERFLOW) << 3 |
781
           (xcpt & FP_OVERFLOW) << 1 |
782
           (xcpt & FP_DIV0) >> 1 |
783
           (xcpt & FP_INVALID) >> 4;
784
}
785

    
786
static always_inline void update_fcr31(void)
787
{
788
    int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->fpu->fp_status));
789

    
790
    SET_FP_CAUSE(env->fpu->fcr31, tmp);
791
    if (GET_FP_ENABLE(env->fpu->fcr31) & tmp)
792
        do_raise_exception(EXCP_FPE);
793
    else
794
        UPDATE_FP_FLAGS(env->fpu->fcr31, tmp);
795
}
796

    
797
#define FLOAT_OP(name, p) void do_float_##name##_##p(void)
798

    
799
FLOAT_OP(cvtd, s)
800
{
801
    set_float_exception_flags(0, &env->fpu->fp_status);
802
    FDT2 = float32_to_float64(FST0, &env->fpu->fp_status);
803
    update_fcr31();
804
}
805
FLOAT_OP(cvtd, w)
806
{
807
    set_float_exception_flags(0, &env->fpu->fp_status);
808
    FDT2 = int32_to_float64(WT0, &env->fpu->fp_status);
809
    update_fcr31();
810
}
811
FLOAT_OP(cvtd, l)
812
{
813
    set_float_exception_flags(0, &env->fpu->fp_status);
814
    FDT2 = int64_to_float64(DT0, &env->fpu->fp_status);
815
    update_fcr31();
816
}
817
FLOAT_OP(cvtl, d)
818
{
819
    set_float_exception_flags(0, &env->fpu->fp_status);
820
    DT2 = float64_to_int64(FDT0, &env->fpu->fp_status);
821
    update_fcr31();
822
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
823
        DT2 = FLOAT_SNAN64;
824
}
825
FLOAT_OP(cvtl, s)
826
{
827
    set_float_exception_flags(0, &env->fpu->fp_status);
828
    DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
829
    update_fcr31();
830
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
831
        DT2 = FLOAT_SNAN64;
832
}
833

    
834
FLOAT_OP(cvtps, pw)
835
{
836
    set_float_exception_flags(0, &env->fpu->fp_status);
837
    FST2 = int32_to_float32(WT0, &env->fpu->fp_status);
838
    FSTH2 = int32_to_float32(WTH0, &env->fpu->fp_status);
839
    update_fcr31();
840
}
841
FLOAT_OP(cvtpw, ps)
842
{
843
    set_float_exception_flags(0, &env->fpu->fp_status);
844
    WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
845
    WTH2 = float32_to_int32(FSTH0, &env->fpu->fp_status);
846
    update_fcr31();
847
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
848
        WT2 = FLOAT_SNAN32;
849
}
850
FLOAT_OP(cvts, d)
851
{
852
    set_float_exception_flags(0, &env->fpu->fp_status);
853
    FST2 = float64_to_float32(FDT0, &env->fpu->fp_status);
854
    update_fcr31();
855
}
856
FLOAT_OP(cvts, w)
857
{
858
    set_float_exception_flags(0, &env->fpu->fp_status);
859
    FST2 = int32_to_float32(WT0, &env->fpu->fp_status);
860
    update_fcr31();
861
}
862
FLOAT_OP(cvts, l)
863
{
864
    set_float_exception_flags(0, &env->fpu->fp_status);
865
    FST2 = int64_to_float32(DT0, &env->fpu->fp_status);
866
    update_fcr31();
867
}
868
FLOAT_OP(cvts, pl)
869
{
870
    set_float_exception_flags(0, &env->fpu->fp_status);
871
    WT2 = WT0;
872
    update_fcr31();
873
}
874
FLOAT_OP(cvts, pu)
875
{
876
    set_float_exception_flags(0, &env->fpu->fp_status);
877
    WT2 = WTH0;
878
    update_fcr31();
879
}
880
FLOAT_OP(cvtw, s)
881
{
882
    set_float_exception_flags(0, &env->fpu->fp_status);
883
    WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
884
    update_fcr31();
885
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
886
        WT2 = FLOAT_SNAN32;
887
}
888
FLOAT_OP(cvtw, d)
889
{
890
    set_float_exception_flags(0, &env->fpu->fp_status);
891
    WT2 = float64_to_int32(FDT0, &env->fpu->fp_status);
892
    update_fcr31();
893
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
894
        WT2 = FLOAT_SNAN32;
895
}
896

    
897
FLOAT_OP(roundl, d)
898
{
899
    set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
900
    DT2 = float64_to_int64(FDT0, &env->fpu->fp_status);
901
    RESTORE_ROUNDING_MODE;
902
    update_fcr31();
903
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
904
        DT2 = FLOAT_SNAN64;
905
}
906
FLOAT_OP(roundl, s)
907
{
908
    set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
909
    DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
910
    RESTORE_ROUNDING_MODE;
911
    update_fcr31();
912
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
913
        DT2 = FLOAT_SNAN64;
914
}
915
FLOAT_OP(roundw, d)
916
{
917
    set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
918
    WT2 = float64_to_int32(FDT0, &env->fpu->fp_status);
919
    RESTORE_ROUNDING_MODE;
920
    update_fcr31();
921
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
922
        WT2 = FLOAT_SNAN32;
923
}
924
FLOAT_OP(roundw, s)
925
{
926
    set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
927
    WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
928
    RESTORE_ROUNDING_MODE;
929
    update_fcr31();
930
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
931
        WT2 = FLOAT_SNAN32;
932
}
933

    
934
FLOAT_OP(truncl, d)
935
{
936
    DT2 = float64_to_int64_round_to_zero(FDT0, &env->fpu->fp_status);
937
    update_fcr31();
938
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
939
        DT2 = FLOAT_SNAN64;
940
}
941
FLOAT_OP(truncl, s)
942
{
943
    DT2 = float32_to_int64_round_to_zero(FST0, &env->fpu->fp_status);
944
    update_fcr31();
945
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
946
        DT2 = FLOAT_SNAN64;
947
}
948
FLOAT_OP(truncw, d)
949
{
950
    WT2 = float64_to_int32_round_to_zero(FDT0, &env->fpu->fp_status);
951
    update_fcr31();
952
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
953
        WT2 = FLOAT_SNAN32;
954
}
955
FLOAT_OP(truncw, s)
956
{
957
    WT2 = float32_to_int32_round_to_zero(FST0, &env->fpu->fp_status);
958
    update_fcr31();
959
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
960
        WT2 = FLOAT_SNAN32;
961
}
962

    
963
FLOAT_OP(ceill, d)
964
{
965
    set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
966
    DT2 = float64_to_int64(FDT0, &env->fpu->fp_status);
967
    RESTORE_ROUNDING_MODE;
968
    update_fcr31();
969
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
970
        DT2 = FLOAT_SNAN64;
971
}
972
FLOAT_OP(ceill, s)
973
{
974
    set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
975
    DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
976
    RESTORE_ROUNDING_MODE;
977
    update_fcr31();
978
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
979
        DT2 = FLOAT_SNAN64;
980
}
981
FLOAT_OP(ceilw, d)
982
{
983
    set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
984
    WT2 = float64_to_int32(FDT0, &env->fpu->fp_status);
985
    RESTORE_ROUNDING_MODE;
986
    update_fcr31();
987
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
988
        WT2 = FLOAT_SNAN32;
989
}
990
FLOAT_OP(ceilw, s)
991
{
992
    set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
993
    WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
994
    RESTORE_ROUNDING_MODE;
995
    update_fcr31();
996
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
997
        WT2 = FLOAT_SNAN32;
998
}
999

    
1000
FLOAT_OP(floorl, d)
1001
{
1002
    set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
1003
    DT2 = float64_to_int64(FDT0, &env->fpu->fp_status);
1004
    RESTORE_ROUNDING_MODE;
1005
    update_fcr31();
1006
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
1007
        DT2 = FLOAT_SNAN64;
1008
}
1009
FLOAT_OP(floorl, s)
1010
{
1011
    set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
1012
    DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
1013
    RESTORE_ROUNDING_MODE;
1014
    update_fcr31();
1015
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
1016
        DT2 = FLOAT_SNAN64;
1017
}
1018
FLOAT_OP(floorw, d)
1019
{
1020
    set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
1021
    WT2 = float64_to_int32(FDT0, &env->fpu->fp_status);
1022
    RESTORE_ROUNDING_MODE;
1023
    update_fcr31();
1024
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
1025
        WT2 = FLOAT_SNAN32;
1026
}
1027
FLOAT_OP(floorw, s)
1028
{
1029
    set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
1030
    WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
1031
    RESTORE_ROUNDING_MODE;
1032
    update_fcr31();
1033
    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
1034
        WT2 = FLOAT_SNAN32;
1035
}
1036

    
1037
/* MIPS specific unary operations */
1038
FLOAT_OP(recip, d)
1039
{
1040
    set_float_exception_flags(0, &env->fpu->fp_status);
1041
    FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fpu->fp_status);
1042
    update_fcr31();
1043
}
1044
FLOAT_OP(recip, s)
1045
{
1046
    set_float_exception_flags(0, &env->fpu->fp_status);
1047
    FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status);
1048
    update_fcr31();
1049
}
1050

    
1051
FLOAT_OP(rsqrt, d)
1052
{
1053
    set_float_exception_flags(0, &env->fpu->fp_status);
1054
    FDT2 = float64_sqrt(FDT0, &env->fpu->fp_status);
1055
    FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fpu->fp_status);
1056
    update_fcr31();
1057
}
1058
FLOAT_OP(rsqrt, s)
1059
{
1060
    set_float_exception_flags(0, &env->fpu->fp_status);
1061
    FST2 = float32_sqrt(FST0, &env->fpu->fp_status);
1062
    FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status);
1063
    update_fcr31();
1064
}
1065

    
1066
FLOAT_OP(recip1, d)
1067
{
1068
    set_float_exception_flags(0, &env->fpu->fp_status);
1069
    FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fpu->fp_status);
1070
    update_fcr31();
1071
}
1072
FLOAT_OP(recip1, s)
1073
{
1074
    set_float_exception_flags(0, &env->fpu->fp_status);
1075
    FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status);
1076
    update_fcr31();
1077
}
1078
FLOAT_OP(recip1, ps)
1079
{
1080
    set_float_exception_flags(0, &env->fpu->fp_status);
1081
    FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status);
1082
    FSTH2 = float32_div(FLOAT_ONE32, FSTH0, &env->fpu->fp_status);
1083
    update_fcr31();
1084
}
1085

    
1086
FLOAT_OP(rsqrt1, d)
1087
{
1088
    set_float_exception_flags(0, &env->fpu->fp_status);
1089
    FDT2 = float64_sqrt(FDT0, &env->fpu->fp_status);
1090
    FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fpu->fp_status);
1091
    update_fcr31();
1092
}
1093
FLOAT_OP(rsqrt1, s)
1094
{
1095
    set_float_exception_flags(0, &env->fpu->fp_status);
1096
    FST2 = float32_sqrt(FST0, &env->fpu->fp_status);
1097
    FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status);
1098
    update_fcr31();
1099
}
1100
FLOAT_OP(rsqrt1, ps)
1101
{
1102
    set_float_exception_flags(0, &env->fpu->fp_status);
1103
    FST2 = float32_sqrt(FST0, &env->fpu->fp_status);
1104
    FSTH2 = float32_sqrt(FSTH0, &env->fpu->fp_status);
1105
    FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status);
1106
    FSTH2 = float32_div(FLOAT_ONE32, FSTH2, &env->fpu->fp_status);
1107
    update_fcr31();
1108
}
1109

    
1110
/* binary operations */
1111
#define FLOAT_BINOP(name) \
1112
FLOAT_OP(name, d)         \
1113
{                         \
1114
    set_float_exception_flags(0, &env->fpu->fp_status);            \
1115
    FDT2 = float64_ ## name (FDT0, FDT1, &env->fpu->fp_status);    \
1116
    update_fcr31();                                                \
1117
    if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID)                \
1118
        DT2 = FLOAT_QNAN64;                                        \
1119
}                         \
1120
FLOAT_OP(name, s)         \
1121
{                         \
1122
    set_float_exception_flags(0, &env->fpu->fp_status);            \
1123
    FST2 = float32_ ## name (FST0, FST1, &env->fpu->fp_status);    \
1124
    update_fcr31();                                                \
1125
    if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID)                \
1126
        WT2 = FLOAT_QNAN32;                                        \
1127
}                         \
1128
FLOAT_OP(name, ps)        \
1129
{                         \
1130
    set_float_exception_flags(0, &env->fpu->fp_status);            \
1131
    FST2 = float32_ ## name (FST0, FST1, &env->fpu->fp_status);    \
1132
    FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fpu->fp_status); \
1133
    update_fcr31();       \
1134
    if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) {              \
1135
        WT2 = FLOAT_QNAN32;                                        \
1136
        WTH2 = FLOAT_QNAN32;                                       \
1137
    }                     \
1138
}
1139
FLOAT_BINOP(add)
1140
FLOAT_BINOP(sub)
1141
FLOAT_BINOP(mul)
1142
FLOAT_BINOP(div)
1143
#undef FLOAT_BINOP
1144

    
1145
/* MIPS specific binary operations */
1146
FLOAT_OP(recip2, d)
1147
{
1148
    set_float_exception_flags(0, &env->fpu->fp_status);
1149
    FDT2 = float64_mul(FDT0, FDT2, &env->fpu->fp_status);
1150
    FDT2 = float64_chs(float64_sub(FDT2, FLOAT_ONE64, &env->fpu->fp_status));
1151
    update_fcr31();
1152
}
1153
FLOAT_OP(recip2, s)
1154
{
1155
    set_float_exception_flags(0, &env->fpu->fp_status);
1156
    FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
1157
    FST2 = float32_chs(float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status));
1158
    update_fcr31();
1159
}
1160
FLOAT_OP(recip2, ps)
1161
{
1162
    set_float_exception_flags(0, &env->fpu->fp_status);
1163
    FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
1164
    FSTH2 = float32_mul(FSTH0, FSTH2, &env->fpu->fp_status);
1165
    FST2 = float32_chs(float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status));
1166
    FSTH2 = float32_chs(float32_sub(FSTH2, FLOAT_ONE32, &env->fpu->fp_status));
1167
    update_fcr31();
1168
}
1169

    
1170
FLOAT_OP(rsqrt2, d)
1171
{
1172
    set_float_exception_flags(0, &env->fpu->fp_status);
1173
    FDT2 = float64_mul(FDT0, FDT2, &env->fpu->fp_status);
1174
    FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fpu->fp_status);
1175
    FDT2 = float64_chs(float64_div(FDT2, FLOAT_TWO64, &env->fpu->fp_status));
1176
    update_fcr31();
1177
}
1178
FLOAT_OP(rsqrt2, s)
1179
{
1180
    set_float_exception_flags(0, &env->fpu->fp_status);
1181
    FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
1182
    FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status);
1183
    FST2 = float32_chs(float32_div(FST2, FLOAT_TWO32, &env->fpu->fp_status));
1184
    update_fcr31();
1185
}
1186
FLOAT_OP(rsqrt2, ps)
1187
{
1188
    set_float_exception_flags(0, &env->fpu->fp_status);
1189
    FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
1190
    FSTH2 = float32_mul(FSTH0, FSTH2, &env->fpu->fp_status);
1191
    FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status);
1192
    FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fpu->fp_status);
1193
    FST2 = float32_chs(float32_div(FST2, FLOAT_TWO32, &env->fpu->fp_status));
1194
    FSTH2 = float32_chs(float32_div(FSTH2, FLOAT_TWO32, &env->fpu->fp_status));
1195
    update_fcr31();
1196
}
1197

    
1198
FLOAT_OP(addr, ps)
1199
{
1200
    set_float_exception_flags(0, &env->fpu->fp_status);
1201
    FST2 = float32_add (FST0, FSTH0, &env->fpu->fp_status);
1202
    FSTH2 = float32_add (FST1, FSTH1, &env->fpu->fp_status);
1203
    update_fcr31();
1204
}
1205

    
1206
FLOAT_OP(mulr, ps)
1207
{
1208
    set_float_exception_flags(0, &env->fpu->fp_status);
1209
    FST2 = float32_mul (FST0, FSTH0, &env->fpu->fp_status);
1210
    FSTH2 = float32_mul (FST1, FSTH1, &env->fpu->fp_status);
1211
    update_fcr31();
1212
}
1213

    
1214
/* compare operations */
1215
#define FOP_COND_D(op, cond)                   \
1216
void do_cmp_d_ ## op (long cc)                 \
1217
{                                              \
1218
    int c = cond;                              \
1219
    update_fcr31();                            \
1220
    if (c)                                     \
1221
        SET_FP_COND(cc, env->fpu);             \
1222
    else                                       \
1223
        CLEAR_FP_COND(cc, env->fpu);           \
1224
}                                              \
1225
void do_cmpabs_d_ ## op (long cc)              \
1226
{                                              \
1227
    int c;                                     \
1228
    FDT0 = float64_abs(FDT0);                  \
1229
    FDT1 = float64_abs(FDT1);                  \
1230
    c = cond;                                  \
1231
    update_fcr31();                            \
1232
    if (c)                                     \
1233
        SET_FP_COND(cc, env->fpu);             \
1234
    else                                       \
1235
        CLEAR_FP_COND(cc, env->fpu);           \
1236
}
1237

    
1238
int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM)
1239
{
1240
    if (float64_is_signaling_nan(a) ||
1241
        float64_is_signaling_nan(b) ||
1242
        (sig && (float64_is_nan(a) || float64_is_nan(b)))) {
1243
        float_raise(float_flag_invalid, status);
1244
        return 1;
1245
    } else if (float64_is_nan(a) || float64_is_nan(b)) {
1246
        return 1;
1247
    } else {
1248
        return 0;
1249
    }
1250
}
1251

    
1252
/* NOTE: the comma operator will make "cond" to eval to false,
1253
 * but float*_is_unordered() is still called. */
1254
FOP_COND_D(f,   (float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status), 0))
1255
FOP_COND_D(un,  float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status))
1256
FOP_COND_D(eq,  !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_eq(FDT0, FDT1, &env->fpu->fp_status))
1257
FOP_COND_D(ueq, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status)  || float64_eq(FDT0, FDT1, &env->fpu->fp_status))
1258
FOP_COND_D(olt, !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_lt(FDT0, FDT1, &env->fpu->fp_status))
1259
FOP_COND_D(ult, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status)  || float64_lt(FDT0, FDT1, &env->fpu->fp_status))
1260
FOP_COND_D(ole, !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_le(FDT0, FDT1, &env->fpu->fp_status))
1261
FOP_COND_D(ule, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status)  || float64_le(FDT0, FDT1, &env->fpu->fp_status))
1262
/* NOTE: the comma operator will make "cond" to eval to false,
1263
 * but float*_is_unordered() is still called. */
1264
FOP_COND_D(sf,  (float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status), 0))
1265
FOP_COND_D(ngle,float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status))
1266
FOP_COND_D(seq, !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_eq(FDT0, FDT1, &env->fpu->fp_status))
1267
FOP_COND_D(ngl, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status)  || float64_eq(FDT0, FDT1, &env->fpu->fp_status))
1268
FOP_COND_D(lt,  !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_lt(FDT0, FDT1, &env->fpu->fp_status))
1269
FOP_COND_D(nge, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status)  || float64_lt(FDT0, FDT1, &env->fpu->fp_status))
1270
FOP_COND_D(le,  !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_le(FDT0, FDT1, &env->fpu->fp_status))
1271
FOP_COND_D(ngt, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status)  || float64_le(FDT0, FDT1, &env->fpu->fp_status))
1272

    
1273
#define FOP_COND_S(op, cond)                   \
1274
void do_cmp_s_ ## op (long cc)                 \
1275
{                                              \
1276
    int c = cond;                              \
1277
    update_fcr31();                            \
1278
    if (c)                                     \
1279
        SET_FP_COND(cc, env->fpu);             \
1280
    else                                       \
1281
        CLEAR_FP_COND(cc, env->fpu);           \
1282
}                                              \
1283
void do_cmpabs_s_ ## op (long cc)              \
1284
{                                              \
1285
    int c;                                     \
1286
    FST0 = float32_abs(FST0);                  \
1287
    FST1 = float32_abs(FST1);                  \
1288
    c = cond;                                  \
1289
    update_fcr31();                            \
1290
    if (c)                                     \
1291
        SET_FP_COND(cc, env->fpu);             \
1292
    else                                       \
1293
        CLEAR_FP_COND(cc, env->fpu);           \
1294
}
1295

    
1296
flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM)
1297
{
1298
    if (float32_is_signaling_nan(a) ||
1299
        float32_is_signaling_nan(b) ||
1300
        (sig && (float32_is_nan(a) || float32_is_nan(b)))) {
1301
        float_raise(float_flag_invalid, status);
1302
        return 1;
1303
    } else if (float32_is_nan(a) || float32_is_nan(b)) {
1304
        return 1;
1305
    } else {
1306
        return 0;
1307
    }
1308
}
1309

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

    
1331
#define FOP_COND_PS(op, condl, condh)          \
1332
void do_cmp_ps_ ## op (long cc)                \
1333
{                                              \
1334
    int cl = condl;                            \
1335
    int ch = condh;                            \
1336
    update_fcr31();                            \
1337
    if (cl)                                    \
1338
        SET_FP_COND(cc, env->fpu);             \
1339
    else                                       \
1340
        CLEAR_FP_COND(cc, env->fpu);           \
1341
    if (ch)                                    \
1342
        SET_FP_COND(cc + 1, env->fpu);         \
1343
    else                                       \
1344
        CLEAR_FP_COND(cc + 1, env->fpu);       \
1345
}                                              \
1346
void do_cmpabs_ps_ ## op (long cc)             \
1347
{                                              \
1348
    int cl, ch;                                \
1349
    FST0 = float32_abs(FST0);                  \
1350
    FSTH0 = float32_abs(FSTH0);                \
1351
    FST1 = float32_abs(FST1);                  \
1352
    FSTH1 = float32_abs(FSTH1);                \
1353
    cl = condl;                                \
1354
    ch = condh;                                \
1355
    update_fcr31();                            \
1356
    if (cl)                                    \
1357
        SET_FP_COND(cc, env->fpu);             \
1358
    else                                       \
1359
        CLEAR_FP_COND(cc, env->fpu);           \
1360
    if (ch)                                    \
1361
        SET_FP_COND(cc + 1, env->fpu);         \
1362
    else                                       \
1363
        CLEAR_FP_COND(cc + 1, env->fpu);       \
1364
}
1365

    
1366
/* NOTE: the comma operator will make "cond" to eval to false,
1367
 * but float*_is_unordered() is still called. */
1368
FOP_COND_PS(f,   (float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status), 0),
1369
                 (float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status), 0))
1370
FOP_COND_PS(un,  float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status),
1371
                 float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status))
1372
FOP_COND_PS(eq,  !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)   && float32_eq(FST0, FST1, &env->fpu->fp_status),
1373
                 !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
1374
FOP_COND_PS(ueq, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)    || float32_eq(FST0, FST1, &env->fpu->fp_status),
1375
                 float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
1376
FOP_COND_PS(olt, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)   && float32_lt(FST0, FST1, &env->fpu->fp_status),
1377
                 !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
1378
FOP_COND_PS(ult, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)    || float32_lt(FST0, FST1, &env->fpu->fp_status),
1379
                 float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
1380
FOP_COND_PS(ole, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)   && float32_le(FST0, FST1, &env->fpu->fp_status),
1381
                 !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_le(FSTH0, FSTH1, &env->fpu->fp_status))
1382
FOP_COND_PS(ule, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)    || float32_le(FST0, FST1, &env->fpu->fp_status),
1383
                 float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_le(FSTH0, FSTH1, &env->fpu->fp_status))
1384
/* NOTE: the comma operator will make "cond" to eval to false,
1385
 * but float*_is_unordered() is still called. */
1386
FOP_COND_PS(sf,  (float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status), 0),
1387
                 (float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status), 0))
1388
FOP_COND_PS(ngle,float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status),
1389
                 float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status))
1390
FOP_COND_PS(seq, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)   && float32_eq(FST0, FST1, &env->fpu->fp_status),
1391
                 !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
1392
FOP_COND_PS(ngl, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)    || float32_eq(FST0, FST1, &env->fpu->fp_status),
1393
                 float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
1394
FOP_COND_PS(lt,  !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)   && float32_lt(FST0, FST1, &env->fpu->fp_status),
1395
                 !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
1396
FOP_COND_PS(nge, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)    || float32_lt(FST0, FST1, &env->fpu->fp_status),
1397
                 float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
1398
FOP_COND_PS(le,  !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)   && float32_le(FST0, FST1, &env->fpu->fp_status),
1399
                 !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_le(FSTH0, FSTH1, &env->fpu->fp_status))
1400
FOP_COND_PS(ngt, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)    || float32_le(FST0, FST1, &env->fpu->fp_status),
1401
                 float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_le(FSTH0, FSTH1, &env->fpu->fp_status))