Statistics
| Branch: | Revision:

root / target-ppc / op_helper.c @ 6c01bf6c

History | View | Annotate | Download (83.5 kB)

1
/*
2
 *  PowerPC emulation helpers for qemu.
3
 *
4
 *  Copyright (c) 2003-2007 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 "exec.h"
21
#include "host-utils.h"
22
#include "helper.h"
23

    
24
#include "helper_regs.h"
25

    
26
//#define DEBUG_OP
27
//#define DEBUG_EXCEPTIONS
28
//#define DEBUG_SOFTWARE_TLB
29

    
30
/*****************************************************************************/
31
/* Exceptions processing helpers */
32

    
33
void helper_raise_exception_err (uint32_t exception, uint32_t error_code)
34
{
35
#if 0
36
    printf("Raise exception %3x code : %d\n", exception, error_code);
37
#endif
38
    env->exception_index = exception;
39
    env->error_code = error_code;
40
    cpu_loop_exit();
41
}
42

    
43
void helper_raise_exception (uint32_t exception)
44
{
45
    helper_raise_exception_err(exception, 0);
46
}
47

    
48
/*****************************************************************************/
49
/* Registers load and stores */
50
target_ulong helper_load_cr (void)
51
{
52
    return (env->crf[0] << 28) |
53
           (env->crf[1] << 24) |
54
           (env->crf[2] << 20) |
55
           (env->crf[3] << 16) |
56
           (env->crf[4] << 12) |
57
           (env->crf[5] << 8) |
58
           (env->crf[6] << 4) |
59
           (env->crf[7] << 0);
60
}
61

    
62
void helper_store_cr (target_ulong val, uint32_t mask)
63
{
64
    int i, sh;
65

    
66
    for (i = 0, sh = 7; i < 8; i++, sh--) {
67
        if (mask & (1 << sh))
68
            env->crf[i] = (val >> (sh * 4)) & 0xFUL;
69
    }
70
}
71

    
72
/*****************************************************************************/
73
/* SPR accesses */
74
void helper_load_dump_spr (uint32_t sprn)
75
{
76
    if (loglevel != 0) {
77
        fprintf(logfile, "Read SPR %d %03x => " ADDRX "\n",
78
                sprn, sprn, env->spr[sprn]);
79
    }
80
}
81

    
82
void helper_store_dump_spr (uint32_t sprn)
83
{
84
    if (loglevel != 0) {
85
        fprintf(logfile, "Write SPR %d %03x <= " ADDRX "\n",
86
                sprn, sprn, env->spr[sprn]);
87
    }
88
}
89

    
90
target_ulong helper_load_tbl (void)
91
{
92
    return cpu_ppc_load_tbl(env);
93
}
94

    
95
target_ulong helper_load_tbu (void)
96
{
97
    return cpu_ppc_load_tbu(env);
98
}
99

    
100
target_ulong helper_load_atbl (void)
101
{
102
    return cpu_ppc_load_atbl(env);
103
}
104

    
105
target_ulong helper_load_atbu (void)
106
{
107
    return cpu_ppc_load_atbu(env);
108
}
109

    
110
target_ulong helper_load_601_rtcl (void)
111
{
112
    return cpu_ppc601_load_rtcl(env);
113
}
114

    
115
target_ulong helper_load_601_rtcu (void)
116
{
117
    return cpu_ppc601_load_rtcu(env);
118
}
119

    
120
#if !defined(CONFIG_USER_ONLY)
121
#if defined (TARGET_PPC64)
122
void helper_store_asr (target_ulong val)
123
{
124
    ppc_store_asr(env, val);
125
}
126
#endif
127

    
128
void helper_store_sdr1 (target_ulong val)
129
{
130
    ppc_store_sdr1(env, val);
131
}
132

    
133
void helper_store_tbl (target_ulong val)
134
{
135
    cpu_ppc_store_tbl(env, val);
136
}
137

    
138
void helper_store_tbu (target_ulong val)
139
{
140
    cpu_ppc_store_tbu(env, val);
141
}
142

    
143
void helper_store_atbl (target_ulong val)
144
{
145
    cpu_ppc_store_atbl(env, val);
146
}
147

    
148
void helper_store_atbu (target_ulong val)
149
{
150
    cpu_ppc_store_atbu(env, val);
151
}
152

    
153
void helper_store_601_rtcl (target_ulong val)
154
{
155
    cpu_ppc601_store_rtcl(env, val);
156
}
157

    
158
void helper_store_601_rtcu (target_ulong val)
159
{
160
    cpu_ppc601_store_rtcu(env, val);
161
}
162

    
163
target_ulong helper_load_decr (void)
164
{
165
    return cpu_ppc_load_decr(env);
166
}
167

    
168
void helper_store_decr (target_ulong val)
169
{
170
    cpu_ppc_store_decr(env, val);
171
}
172

    
173
void helper_store_hid0_601 (target_ulong val)
174
{
175
    target_ulong hid0;
176

    
177
    hid0 = env->spr[SPR_HID0];
178
    if ((val ^ hid0) & 0x00000008) {
179
        /* Change current endianness */
180
        env->hflags &= ~(1 << MSR_LE);
181
        env->hflags_nmsr &= ~(1 << MSR_LE);
182
        env->hflags_nmsr |= (1 << MSR_LE) & (((val >> 3) & 1) << MSR_LE);
183
        env->hflags |= env->hflags_nmsr;
184
        if (loglevel != 0) {
185
            fprintf(logfile, "%s: set endianness to %c => " ADDRX "\n",
186
                    __func__, val & 0x8 ? 'l' : 'b', env->hflags);
187
        }
188
    }
189
    env->spr[SPR_HID0] = (uint32_t)val;
190
}
191

    
192
void helper_store_403_pbr (uint32_t num, target_ulong value)
193
{
194
    if (likely(env->pb[num] != value)) {
195
        env->pb[num] = value;
196
        /* Should be optimized */
197
        tlb_flush(env, 1);
198
    }
199
}
200

    
201
target_ulong helper_load_40x_pit (void)
202
{
203
    return load_40x_pit(env);
204
}
205

    
206
void helper_store_40x_pit (target_ulong val)
207
{
208
    store_40x_pit(env, val);
209
}
210

    
211
void helper_store_40x_dbcr0 (target_ulong val)
212
{
213
    store_40x_dbcr0(env, val);
214
}
215

    
216
void helper_store_40x_sler (target_ulong val)
217
{
218
    store_40x_sler(env, val);
219
}
220

    
221
void helper_store_booke_tcr (target_ulong val)
222
{
223
    store_booke_tcr(env, val);
224
}
225

    
226
void helper_store_booke_tsr (target_ulong val)
227
{
228
    store_booke_tsr(env, val);
229
}
230

    
231
void helper_store_ibatu (uint32_t nr, target_ulong val)
232
{
233
    ppc_store_ibatu(env, nr, val);
234
}
235

    
236
void helper_store_ibatl (uint32_t nr, target_ulong val)
237
{
238
    ppc_store_ibatl(env, nr, val);
239
}
240

    
241
void helper_store_dbatu (uint32_t nr, target_ulong val)
242
{
243
    ppc_store_dbatu(env, nr, val);
244
}
245

    
246
void helper_store_dbatl (uint32_t nr, target_ulong val)
247
{
248
    ppc_store_dbatl(env, nr, val);
249
}
250

    
251
void helper_store_601_batl (uint32_t nr, target_ulong val)
252
{
253
    ppc_store_ibatl_601(env, nr, val);
254
}
255

    
256
void helper_store_601_batu (uint32_t nr, target_ulong val)
257
{
258
    ppc_store_ibatu_601(env, nr, val);
259
}
260
#endif
261

    
262
/*****************************************************************************/
263
/* Memory load and stores */
264

    
265
static always_inline target_ulong addr_add(target_ulong addr, target_long arg)
266
{
267
#if defined(TARGET_PPC64)
268
        if (!msr_sf)
269
            return (uint32_t)(addr + arg);
270
        else
271
#endif
272
            return addr + arg;
273
}
274

    
275
void helper_lmw (target_ulong addr, uint32_t reg)
276
{
277
    for (; reg < 32; reg++) {
278
        if (msr_le)
279
            env->gpr[reg] = bswap32(ldl(addr));
280
        else
281
            env->gpr[reg] = ldl(addr);
282
        addr = addr_add(addr, 4);
283
    }
284
}
285

    
286
void helper_stmw (target_ulong addr, uint32_t reg)
287
{
288
    for (; reg < 32; reg++) {
289
        if (msr_le)
290
            stl(addr, bswap32((uint32_t)env->gpr[reg]));
291
        else
292
            stl(addr, (uint32_t)env->gpr[reg]);
293
        addr = addr_add(addr, 4);
294
    }
295
}
296

    
297
void helper_lsw(target_ulong addr, uint32_t nb, uint32_t reg)
298
{
299
    int sh;
300
    for (; nb > 3; nb -= 4) {
301
        env->gpr[reg] = ldl(addr);
302
        reg = (reg + 1) % 32;
303
        addr = addr_add(addr, 4);
304
    }
305
    if (unlikely(nb > 0)) {
306
        env->gpr[reg] = 0;
307
        for (sh = 24; nb > 0; nb--, sh -= 8) {
308
            env->gpr[reg] |= ldub(addr) << sh;
309
            addr = addr_add(addr, 1);
310
        }
311
    }
312
}
313
/* PPC32 specification says we must generate an exception if
314
 * rA is in the range of registers to be loaded.
315
 * In an other hand, IBM says this is valid, but rA won't be loaded.
316
 * For now, I'll follow the spec...
317
 */
318
void helper_lswx(target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
319
{
320
    if (likely(xer_bc != 0)) {
321
        if (unlikely((ra != 0 && reg < ra && (reg + xer_bc) > ra) ||
322
                     (reg < rb && (reg + xer_bc) > rb))) {
323
            helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
324
                                       POWERPC_EXCP_INVAL |
325
                                       POWERPC_EXCP_INVAL_LSWX);
326
        } else {
327
            helper_lsw(addr, xer_bc, reg);
328
        }
329
    }
330
}
331

    
332
void helper_stsw(target_ulong addr, uint32_t nb, uint32_t reg)
333
{
334
    int sh;
335
    for (; nb > 3; nb -= 4) {
336
        stl(addr, env->gpr[reg]);
337
        reg = (reg + 1) % 32;
338
        addr = addr_add(addr, 4);
339
    }
340
    if (unlikely(nb > 0)) {
341
        for (sh = 24; nb > 0; nb--, sh -= 8)
342
            stb(addr, (env->gpr[reg] >> sh) & 0xFF);
343
            addr = addr_add(addr, 1);
344
    }
345
}
346

    
347
static void do_dcbz(target_ulong addr, int dcache_line_size)
348
{
349
    addr &= ~(dcache_line_size - 1);
350
    int i;
351
    for (i = 0 ; i < dcache_line_size ; i += 4) {
352
        stl(addr + i , 0);
353
    }
354
    if (env->reserve == addr)
355
        env->reserve = (target_ulong)-1ULL;
356
}
357

    
358
void helper_dcbz(target_ulong addr)
359
{
360
    do_dcbz(addr, env->dcache_line_size);
361
}
362

    
363
void helper_dcbz_970(target_ulong addr)
364
{
365
    if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1)
366
        do_dcbz(addr, 32);
367
    else
368
        do_dcbz(addr, env->dcache_line_size);
369
}
370

    
371
void helper_icbi(target_ulong addr)
372
{
373
    uint32_t tmp;
374

    
375
    addr &= ~(env->dcache_line_size - 1);
376
    /* Invalidate one cache line :
377
     * PowerPC specification says this is to be treated like a load
378
     * (not a fetch) by the MMU. To be sure it will be so,
379
     * do the load "by hand".
380
     */
381
    tmp = ldl(addr);
382
    tb_invalidate_page_range(addr, addr + env->icache_line_size);
383
}
384

    
385
// XXX: to be tested
386
target_ulong helper_lscbx (target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
387
{
388
    int i, c, d;
389
    d = 24;
390
    for (i = 0; i < xer_bc; i++) {
391
        c = ldub(addr);
392
        addr = addr_add(addr, 1);
393
        /* ra (if not 0) and rb are never modified */
394
        if (likely(reg != rb && (ra == 0 || reg != ra))) {
395
            env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d);
396
        }
397
        if (unlikely(c == xer_cmp))
398
            break;
399
        if (likely(d != 0)) {
400
            d -= 8;
401
        } else {
402
            d = 24;
403
            reg++;
404
            reg = reg & 0x1F;
405
        }
406
    }
407
    return i;
408
}
409

    
410
/*****************************************************************************/
411
/* Fixed point operations helpers */
412
#if defined(TARGET_PPC64)
413

    
414
/* multiply high word */
415
uint64_t helper_mulhd (uint64_t arg1, uint64_t arg2)
416
{
417
    uint64_t tl, th;
418

    
419
    muls64(&tl, &th, arg1, arg2);
420
    return th;
421
}
422

    
423
/* multiply high word unsigned */
424
uint64_t helper_mulhdu (uint64_t arg1, uint64_t arg2)
425
{
426
    uint64_t tl, th;
427

    
428
    mulu64(&tl, &th, arg1, arg2);
429
    return th;
430
}
431

    
432
uint64_t helper_mulldo (uint64_t arg1, uint64_t arg2)
433
{
434
    int64_t th;
435
    uint64_t tl;
436

    
437
    muls64(&tl, (uint64_t *)&th, arg1, arg2);
438
    /* If th != 0 && th != -1, then we had an overflow */
439
    if (likely((uint64_t)(th + 1) <= 1)) {
440
        env->xer &= ~(1 << XER_OV);
441
    } else {
442
        env->xer |= (1 << XER_OV) | (1 << XER_SO);
443
    }
444
    return (int64_t)tl;
445
}
446
#endif
447

    
448
target_ulong helper_cntlzw (target_ulong t)
449
{
450
    return clz32(t);
451
}
452

    
453
#if defined(TARGET_PPC64)
454
target_ulong helper_cntlzd (target_ulong t)
455
{
456
    return clz64(t);
457
}
458
#endif
459

    
460
/* shift right arithmetic helper */
461
target_ulong helper_sraw (target_ulong value, target_ulong shift)
462
{
463
    int32_t ret;
464

    
465
    if (likely(!(shift & 0x20))) {
466
        if (likely((uint32_t)shift != 0)) {
467
            shift &= 0x1f;
468
            ret = (int32_t)value >> shift;
469
            if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
470
                env->xer &= ~(1 << XER_CA);
471
            } else {
472
                env->xer |= (1 << XER_CA);
473
            }
474
        } else {
475
            ret = (int32_t)value;
476
            env->xer &= ~(1 << XER_CA);
477
        }
478
    } else {
479
        ret = (int32_t)value >> 31;
480
        if (ret) {
481
            env->xer |= (1 << XER_CA);
482
        } else {
483
            env->xer &= ~(1 << XER_CA);
484
        }
485
    }
486
    return (target_long)ret;
487
}
488

    
489
#if defined(TARGET_PPC64)
490
target_ulong helper_srad (target_ulong value, target_ulong shift)
491
{
492
    int64_t ret;
493

    
494
    if (likely(!(shift & 0x40))) {
495
        if (likely((uint64_t)shift != 0)) {
496
            shift &= 0x3f;
497
            ret = (int64_t)value >> shift;
498
            if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
499
                env->xer &= ~(1 << XER_CA);
500
            } else {
501
                env->xer |= (1 << XER_CA);
502
            }
503
        } else {
504
            ret = (int64_t)value;
505
            env->xer &= ~(1 << XER_CA);
506
        }
507
    } else {
508
        ret = (int64_t)value >> 63;
509
        if (ret) {
510
            env->xer |= (1 << XER_CA);
511
        } else {
512
            env->xer &= ~(1 << XER_CA);
513
        }
514
    }
515
    return ret;
516
}
517
#endif
518

    
519
target_ulong helper_popcntb (target_ulong val)
520
{
521
    val = (val & 0x55555555) + ((val >>  1) & 0x55555555);
522
    val = (val & 0x33333333) + ((val >>  2) & 0x33333333);
523
    val = (val & 0x0f0f0f0f) + ((val >>  4) & 0x0f0f0f0f);
524
    return val;
525
}
526

    
527
#if defined(TARGET_PPC64)
528
target_ulong helper_popcntb_64 (target_ulong val)
529
{
530
    val = (val & 0x5555555555555555ULL) + ((val >>  1) & 0x5555555555555555ULL);
531
    val = (val & 0x3333333333333333ULL) + ((val >>  2) & 0x3333333333333333ULL);
532
    val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >>  4) & 0x0f0f0f0f0f0f0f0fULL);
533
    return val;
534
}
535
#endif
536

    
537
/*****************************************************************************/
538
/* Floating point operations helpers */
539
uint64_t helper_float32_to_float64(uint32_t arg)
540
{
541
    CPU_FloatU f;
542
    CPU_DoubleU d;
543
    f.l = arg;
544
    d.d = float32_to_float64(f.f, &env->fp_status);
545
    return d.ll;
546
}
547

    
548
uint32_t helper_float64_to_float32(uint64_t arg)
549
{
550
    CPU_FloatU f;
551
    CPU_DoubleU d;
552
    d.ll = arg;
553
    f.f = float64_to_float32(d.d, &env->fp_status);
554
    return f.l;
555
}
556

    
557
static always_inline int isden (float64 d)
558
{
559
    CPU_DoubleU u;
560

    
561
    u.d = d;
562

    
563
    return ((u.ll >> 52) & 0x7FF) == 0;
564
}
565

    
566
uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf)
567
{
568
    CPU_DoubleU farg;
569
    int isneg;
570
    int ret;
571
    farg.ll = arg;
572
    isneg = float64_is_neg(farg.d);
573
    if (unlikely(float64_is_nan(farg.d))) {
574
        if (float64_is_signaling_nan(farg.d)) {
575
            /* Signaling NaN: flags are undefined */
576
            ret = 0x00;
577
        } else {
578
            /* Quiet NaN */
579
            ret = 0x11;
580
        }
581
    } else if (unlikely(float64_is_infinity(farg.d))) {
582
        /* +/- infinity */
583
        if (isneg)
584
            ret = 0x09;
585
        else
586
            ret = 0x05;
587
    } else {
588
        if (float64_is_zero(farg.d)) {
589
            /* +/- zero */
590
            if (isneg)
591
                ret = 0x12;
592
            else
593
                ret = 0x02;
594
        } else {
595
            if (isden(farg.d)) {
596
                /* Denormalized numbers */
597
                ret = 0x10;
598
            } else {
599
                /* Normalized numbers */
600
                ret = 0x00;
601
            }
602
            if (isneg) {
603
                ret |= 0x08;
604
            } else {
605
                ret |= 0x04;
606
            }
607
        }
608
    }
609
    if (set_fprf) {
610
        /* We update FPSCR_FPRF */
611
        env->fpscr &= ~(0x1F << FPSCR_FPRF);
612
        env->fpscr |= ret << FPSCR_FPRF;
613
    }
614
    /* We just need fpcc to update Rc1 */
615
    return ret & 0xF;
616
}
617

    
618
/* Floating-point invalid operations exception */
619
static always_inline uint64_t fload_invalid_op_excp (int op)
620
{
621
    uint64_t ret = 0;
622
    int ve;
623

    
624
    ve = fpscr_ve;
625
    switch (op) {
626
    case POWERPC_EXCP_FP_VXSNAN:
627
        env->fpscr |= 1 << FPSCR_VXSNAN;
628
        break;
629
    case POWERPC_EXCP_FP_VXSOFT:
630
        env->fpscr |= 1 << FPSCR_VXSOFT;
631
        break;
632
    case POWERPC_EXCP_FP_VXISI:
633
        /* Magnitude subtraction of infinities */
634
        env->fpscr |= 1 << FPSCR_VXISI;
635
        goto update_arith;
636
    case POWERPC_EXCP_FP_VXIDI:
637
        /* Division of infinity by infinity */
638
        env->fpscr |= 1 << FPSCR_VXIDI;
639
        goto update_arith;
640
    case POWERPC_EXCP_FP_VXZDZ:
641
        /* Division of zero by zero */
642
        env->fpscr |= 1 << FPSCR_VXZDZ;
643
        goto update_arith;
644
    case POWERPC_EXCP_FP_VXIMZ:
645
        /* Multiplication of zero by infinity */
646
        env->fpscr |= 1 << FPSCR_VXIMZ;
647
        goto update_arith;
648
    case POWERPC_EXCP_FP_VXVC:
649
        /* Ordered comparison of NaN */
650
        env->fpscr |= 1 << FPSCR_VXVC;
651
        env->fpscr &= ~(0xF << FPSCR_FPCC);
652
        env->fpscr |= 0x11 << FPSCR_FPCC;
653
        /* We must update the target FPR before raising the exception */
654
        if (ve != 0) {
655
            env->exception_index = POWERPC_EXCP_PROGRAM;
656
            env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
657
            /* Update the floating-point enabled exception summary */
658
            env->fpscr |= 1 << FPSCR_FEX;
659
            /* Exception is differed */
660
            ve = 0;
661
        }
662
        break;
663
    case POWERPC_EXCP_FP_VXSQRT:
664
        /* Square root of a negative number */
665
        env->fpscr |= 1 << FPSCR_VXSQRT;
666
    update_arith:
667
        env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
668
        if (ve == 0) {
669
            /* Set the result to quiet NaN */
670
            ret = 0xFFF8000000000000ULL;
671
            env->fpscr &= ~(0xF << FPSCR_FPCC);
672
            env->fpscr |= 0x11 << FPSCR_FPCC;
673
        }
674
        break;
675
    case POWERPC_EXCP_FP_VXCVI:
676
        /* Invalid conversion */
677
        env->fpscr |= 1 << FPSCR_VXCVI;
678
        env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
679
        if (ve == 0) {
680
            /* Set the result to quiet NaN */
681
            ret = 0xFFF8000000000000ULL;
682
            env->fpscr &= ~(0xF << FPSCR_FPCC);
683
            env->fpscr |= 0x11 << FPSCR_FPCC;
684
        }
685
        break;
686
    }
687
    /* Update the floating-point invalid operation summary */
688
    env->fpscr |= 1 << FPSCR_VX;
689
    /* Update the floating-point exception summary */
690
    env->fpscr |= 1 << FPSCR_FX;
691
    if (ve != 0) {
692
        /* Update the floating-point enabled exception summary */
693
        env->fpscr |= 1 << FPSCR_FEX;
694
        if (msr_fe0 != 0 || msr_fe1 != 0)
695
            helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | op);
696
    }
697
    return ret;
698
}
699

    
700
static always_inline uint64_t float_zero_divide_excp (uint64_t arg1, uint64_t arg2)
701
{
702
    env->fpscr |= 1 << FPSCR_ZX;
703
    env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
704
    /* Update the floating-point exception summary */
705
    env->fpscr |= 1 << FPSCR_FX;
706
    if (fpscr_ze != 0) {
707
        /* Update the floating-point enabled exception summary */
708
        env->fpscr |= 1 << FPSCR_FEX;
709
        if (msr_fe0 != 0 || msr_fe1 != 0) {
710
            helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
711
                                       POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
712
        }
713
    } else {
714
        /* Set the result to infinity */
715
        arg1 = ((arg1 ^ arg2) & 0x8000000000000000ULL);
716
        arg1 |= 0x7FFULL << 52;
717
    }
718
    return arg1;
719
}
720

    
721
static always_inline void float_overflow_excp (void)
722
{
723
    env->fpscr |= 1 << FPSCR_OX;
724
    /* Update the floating-point exception summary */
725
    env->fpscr |= 1 << FPSCR_FX;
726
    if (fpscr_oe != 0) {
727
        /* XXX: should adjust the result */
728
        /* Update the floating-point enabled exception summary */
729
        env->fpscr |= 1 << FPSCR_FEX;
730
        /* We must update the target FPR before raising the exception */
731
        env->exception_index = POWERPC_EXCP_PROGRAM;
732
        env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
733
    } else {
734
        env->fpscr |= 1 << FPSCR_XX;
735
        env->fpscr |= 1 << FPSCR_FI;
736
    }
737
}
738

    
739
static always_inline void float_underflow_excp (void)
740
{
741
    env->fpscr |= 1 << FPSCR_UX;
742
    /* Update the floating-point exception summary */
743
    env->fpscr |= 1 << FPSCR_FX;
744
    if (fpscr_ue != 0) {
745
        /* XXX: should adjust the result */
746
        /* Update the floating-point enabled exception summary */
747
        env->fpscr |= 1 << FPSCR_FEX;
748
        /* We must update the target FPR before raising the exception */
749
        env->exception_index = POWERPC_EXCP_PROGRAM;
750
        env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
751
    }
752
}
753

    
754
static always_inline void float_inexact_excp (void)
755
{
756
    env->fpscr |= 1 << FPSCR_XX;
757
    /* Update the floating-point exception summary */
758
    env->fpscr |= 1 << FPSCR_FX;
759
    if (fpscr_xe != 0) {
760
        /* Update the floating-point enabled exception summary */
761
        env->fpscr |= 1 << FPSCR_FEX;
762
        /* We must update the target FPR before raising the exception */
763
        env->exception_index = POWERPC_EXCP_PROGRAM;
764
        env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
765
    }
766
}
767

    
768
static always_inline void fpscr_set_rounding_mode (void)
769
{
770
    int rnd_type;
771

    
772
    /* Set rounding mode */
773
    switch (fpscr_rn) {
774
    case 0:
775
        /* Best approximation (round to nearest) */
776
        rnd_type = float_round_nearest_even;
777
        break;
778
    case 1:
779
        /* Smaller magnitude (round toward zero) */
780
        rnd_type = float_round_to_zero;
781
        break;
782
    case 2:
783
        /* Round toward +infinite */
784
        rnd_type = float_round_up;
785
        break;
786
    default:
787
    case 3:
788
        /* Round toward -infinite */
789
        rnd_type = float_round_down;
790
        break;
791
    }
792
    set_float_rounding_mode(rnd_type, &env->fp_status);
793
}
794

    
795
void helper_fpscr_clrbit (uint32_t bit)
796
{
797
    int prev;
798

    
799
    prev = (env->fpscr >> bit) & 1;
800
    env->fpscr &= ~(1 << bit);
801
    if (prev == 1) {
802
        switch (bit) {
803
        case FPSCR_RN1:
804
        case FPSCR_RN:
805
            fpscr_set_rounding_mode();
806
            break;
807
        default:
808
            break;
809
        }
810
    }
811
}
812

    
813
void helper_fpscr_setbit (uint32_t bit)
814
{
815
    int prev;
816

    
817
    prev = (env->fpscr >> bit) & 1;
818
    env->fpscr |= 1 << bit;
819
    if (prev == 0) {
820
        switch (bit) {
821
        case FPSCR_VX:
822
            env->fpscr |= 1 << FPSCR_FX;
823
            if (fpscr_ve)
824
                goto raise_ve;
825
        case FPSCR_OX:
826
            env->fpscr |= 1 << FPSCR_FX;
827
            if (fpscr_oe)
828
                goto raise_oe;
829
            break;
830
        case FPSCR_UX:
831
            env->fpscr |= 1 << FPSCR_FX;
832
            if (fpscr_ue)
833
                goto raise_ue;
834
            break;
835
        case FPSCR_ZX:
836
            env->fpscr |= 1 << FPSCR_FX;
837
            if (fpscr_ze)
838
                goto raise_ze;
839
            break;
840
        case FPSCR_XX:
841
            env->fpscr |= 1 << FPSCR_FX;
842
            if (fpscr_xe)
843
                goto raise_xe;
844
            break;
845
        case FPSCR_VXSNAN:
846
        case FPSCR_VXISI:
847
        case FPSCR_VXIDI:
848
        case FPSCR_VXZDZ:
849
        case FPSCR_VXIMZ:
850
        case FPSCR_VXVC:
851
        case FPSCR_VXSOFT:
852
        case FPSCR_VXSQRT:
853
        case FPSCR_VXCVI:
854
            env->fpscr |= 1 << FPSCR_VX;
855
            env->fpscr |= 1 << FPSCR_FX;
856
            if (fpscr_ve != 0)
857
                goto raise_ve;
858
            break;
859
        case FPSCR_VE:
860
            if (fpscr_vx != 0) {
861
            raise_ve:
862
                env->error_code = POWERPC_EXCP_FP;
863
                if (fpscr_vxsnan)
864
                    env->error_code |= POWERPC_EXCP_FP_VXSNAN;
865
                if (fpscr_vxisi)
866
                    env->error_code |= POWERPC_EXCP_FP_VXISI;
867
                if (fpscr_vxidi)
868
                    env->error_code |= POWERPC_EXCP_FP_VXIDI;
869
                if (fpscr_vxzdz)
870
                    env->error_code |= POWERPC_EXCP_FP_VXZDZ;
871
                if (fpscr_vximz)
872
                    env->error_code |= POWERPC_EXCP_FP_VXIMZ;
873
                if (fpscr_vxvc)
874
                    env->error_code |= POWERPC_EXCP_FP_VXVC;
875
                if (fpscr_vxsoft)
876
                    env->error_code |= POWERPC_EXCP_FP_VXSOFT;
877
                if (fpscr_vxsqrt)
878
                    env->error_code |= POWERPC_EXCP_FP_VXSQRT;
879
                if (fpscr_vxcvi)
880
                    env->error_code |= POWERPC_EXCP_FP_VXCVI;
881
                goto raise_excp;
882
            }
883
            break;
884
        case FPSCR_OE:
885
            if (fpscr_ox != 0) {
886
            raise_oe:
887
                env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
888
                goto raise_excp;
889
            }
890
            break;
891
        case FPSCR_UE:
892
            if (fpscr_ux != 0) {
893
            raise_ue:
894
                env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
895
                goto raise_excp;
896
            }
897
            break;
898
        case FPSCR_ZE:
899
            if (fpscr_zx != 0) {
900
            raise_ze:
901
                env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX;
902
                goto raise_excp;
903
            }
904
            break;
905
        case FPSCR_XE:
906
            if (fpscr_xx != 0) {
907
            raise_xe:
908
                env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
909
                goto raise_excp;
910
            }
911
            break;
912
        case FPSCR_RN1:
913
        case FPSCR_RN:
914
            fpscr_set_rounding_mode();
915
            break;
916
        default:
917
            break;
918
        raise_excp:
919
            /* Update the floating-point enabled exception summary */
920
            env->fpscr |= 1 << FPSCR_FEX;
921
                /* We have to update Rc1 before raising the exception */
922
            env->exception_index = POWERPC_EXCP_PROGRAM;
923
            break;
924
        }
925
    }
926
}
927

    
928
void helper_store_fpscr (uint64_t arg, uint32_t mask)
929
{
930
    /*
931
     * We use only the 32 LSB of the incoming fpr
932
     */
933
    uint32_t prev, new;
934
    int i;
935

    
936
    prev = env->fpscr;
937
    new = (uint32_t)arg;
938
    new &= ~0x60000000;
939
    new |= prev & 0x60000000;
940
    for (i = 0; i < 8; i++) {
941
        if (mask & (1 << i)) {
942
            env->fpscr &= ~(0xF << (4 * i));
943
            env->fpscr |= new & (0xF << (4 * i));
944
        }
945
    }
946
    /* Update VX and FEX */
947
    if (fpscr_ix != 0)
948
        env->fpscr |= 1 << FPSCR_VX;
949
    else
950
        env->fpscr &= ~(1 << FPSCR_VX);
951
    if ((fpscr_ex & fpscr_eex) != 0) {
952
        env->fpscr |= 1 << FPSCR_FEX;
953
        env->exception_index = POWERPC_EXCP_PROGRAM;
954
        /* XXX: we should compute it properly */
955
        env->error_code = POWERPC_EXCP_FP;
956
    }
957
    else
958
        env->fpscr &= ~(1 << FPSCR_FEX);
959
    fpscr_set_rounding_mode();
960
}
961

    
962
void helper_float_check_status (void)
963
{
964
#ifdef CONFIG_SOFTFLOAT
965
    if (env->exception_index == POWERPC_EXCP_PROGRAM &&
966
        (env->error_code & POWERPC_EXCP_FP)) {
967
        /* Differred floating-point exception after target FPR update */
968
        if (msr_fe0 != 0 || msr_fe1 != 0)
969
            helper_raise_exception_err(env->exception_index, env->error_code);
970
    } else {
971
        int status = get_float_exception_flags(&env->fp_status);
972
        if (status & float_flag_overflow) {
973
            float_overflow_excp();
974
        } else if (status & float_flag_underflow) {
975
            float_underflow_excp();
976
        } else if (status & float_flag_inexact) {
977
            float_inexact_excp();
978
        }
979
    }
980
#else
981
    if (env->exception_index == POWERPC_EXCP_PROGRAM &&
982
        (env->error_code & POWERPC_EXCP_FP)) {
983
        /* Differred floating-point exception after target FPR update */
984
        if (msr_fe0 != 0 || msr_fe1 != 0)
985
            helper_raise_exception_err(env->exception_index, env->error_code);
986
    }
987
#endif
988
}
989

    
990
#ifdef CONFIG_SOFTFLOAT
991
void helper_reset_fpstatus (void)
992
{
993
    set_float_exception_flags(0, &env->fp_status);
994
}
995
#endif
996

    
997
/* fadd - fadd. */
998
uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
999
{
1000
    CPU_DoubleU farg1, farg2;
1001

    
1002
    farg1.ll = arg1;
1003
    farg2.ll = arg2;
1004
#if USE_PRECISE_EMULATION
1005
    if (unlikely(float64_is_signaling_nan(farg1.d) ||
1006
                 float64_is_signaling_nan(farg2.d))) {
1007
        /* sNaN addition */
1008
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1009
    } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
1010
                      float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
1011
        /* Magnitude subtraction of infinities */
1012
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1013
    } else {
1014
        farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
1015
    }
1016
#else
1017
    farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
1018
#endif
1019
    return farg1.ll;
1020
}
1021

    
1022
/* fsub - fsub. */
1023
uint64_t helper_fsub (uint64_t arg1, uint64_t arg2)
1024
{
1025
    CPU_DoubleU farg1, farg2;
1026

    
1027
    farg1.ll = arg1;
1028
    farg2.ll = arg2;
1029
#if USE_PRECISE_EMULATION
1030
{
1031
    if (unlikely(float64_is_signaling_nan(farg1.d) ||
1032
                 float64_is_signaling_nan(farg2.d))) {
1033
        /* sNaN subtraction */
1034
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1035
    } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
1036
                      float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
1037
        /* Magnitude subtraction of infinities */
1038
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1039
    } else {
1040
        farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
1041
    }
1042
}
1043
#else
1044
    farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
1045
#endif
1046
    return farg1.ll;
1047
}
1048

    
1049
/* fmul - fmul. */
1050
uint64_t helper_fmul (uint64_t arg1, uint64_t arg2)
1051
{
1052
    CPU_DoubleU farg1, farg2;
1053

    
1054
    farg1.ll = arg1;
1055
    farg2.ll = arg2;
1056
#if USE_PRECISE_EMULATION
1057
    if (unlikely(float64_is_signaling_nan(farg1.d) ||
1058
                 float64_is_signaling_nan(farg2.d))) {
1059
        /* sNaN multiplication */
1060
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1061
    } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1062
                        (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1063
        /* Multiplication of zero by infinity */
1064
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1065
    } else {
1066
        farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1067
    }
1068
#else
1069
    farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1070
#endif
1071
    return farg1.ll;
1072
}
1073

    
1074
/* fdiv - fdiv. */
1075
uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2)
1076
{
1077
    CPU_DoubleU farg1, farg2;
1078

    
1079
    farg1.ll = arg1;
1080
    farg2.ll = arg2;
1081
#if USE_PRECISE_EMULATION
1082
    if (unlikely(float64_is_signaling_nan(farg1.d) ||
1083
                 float64_is_signaling_nan(farg2.d))) {
1084
        /* sNaN division */
1085
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1086
    } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d))) {
1087
        /* Division of infinity by infinity */
1088
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
1089
    } else if (unlikely(!float64_is_nan(farg1.d) && float64_is_zero(farg2.d))) {
1090
        if (float64_is_zero(farg1.d)) {
1091
            /* Division of zero by zero */
1092
            farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
1093
        } else {
1094
            /* Division by zero */
1095
            farg1.ll = float_zero_divide_excp(farg1.d, farg2.d);
1096
        }
1097
    } else {
1098
        farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
1099
    }
1100
#else
1101
    farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
1102
#endif
1103
    return farg1.ll;
1104
}
1105

    
1106
/* fabs */
1107
uint64_t helper_fabs (uint64_t arg)
1108
{
1109
    CPU_DoubleU farg;
1110

    
1111
    farg.ll = arg;
1112
    farg.d = float64_abs(farg.d);
1113
    return farg.ll;
1114
}
1115

    
1116
/* fnabs */
1117
uint64_t helper_fnabs (uint64_t arg)
1118
{
1119
    CPU_DoubleU farg;
1120

    
1121
    farg.ll = arg;
1122
    farg.d = float64_abs(farg.d);
1123
    farg.d = float64_chs(farg.d);
1124
    return farg.ll;
1125
}
1126

    
1127
/* fneg */
1128
uint64_t helper_fneg (uint64_t arg)
1129
{
1130
    CPU_DoubleU farg;
1131

    
1132
    farg.ll = arg;
1133
    farg.d = float64_chs(farg.d);
1134
    return farg.ll;
1135
}
1136

    
1137
/* fctiw - fctiw. */
1138
uint64_t helper_fctiw (uint64_t arg)
1139
{
1140
    CPU_DoubleU farg;
1141
    farg.ll = arg;
1142

    
1143
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1144
        /* sNaN conversion */
1145
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1146
    } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
1147
        /* qNan / infinity conversion */
1148
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1149
    } else {
1150
        farg.ll = float64_to_int32(farg.d, &env->fp_status);
1151
#if USE_PRECISE_EMULATION
1152
        /* XXX: higher bits are not supposed to be significant.
1153
         *     to make tests easier, return the same as a real PowerPC 750
1154
         */
1155
        farg.ll |= 0xFFF80000ULL << 32;
1156
#endif
1157
    }
1158
    return farg.ll;
1159
}
1160

    
1161
/* fctiwz - fctiwz. */
1162
uint64_t helper_fctiwz (uint64_t arg)
1163
{
1164
    CPU_DoubleU farg;
1165
    farg.ll = arg;
1166

    
1167
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1168
        /* sNaN conversion */
1169
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1170
    } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
1171
        /* qNan / infinity conversion */
1172
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1173
    } else {
1174
        farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status);
1175
#if USE_PRECISE_EMULATION
1176
        /* XXX: higher bits are not supposed to be significant.
1177
         *     to make tests easier, return the same as a real PowerPC 750
1178
         */
1179
        farg.ll |= 0xFFF80000ULL << 32;
1180
#endif
1181
    }
1182
    return farg.ll;
1183
}
1184

    
1185
#if defined(TARGET_PPC64)
1186
/* fcfid - fcfid. */
1187
uint64_t helper_fcfid (uint64_t arg)
1188
{
1189
    CPU_DoubleU farg;
1190
    farg.d = int64_to_float64(arg, &env->fp_status);
1191
    return farg.ll;
1192
}
1193

    
1194
/* fctid - fctid. */
1195
uint64_t helper_fctid (uint64_t arg)
1196
{
1197
    CPU_DoubleU farg;
1198
    farg.ll = arg;
1199

    
1200
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1201
        /* sNaN conversion */
1202
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1203
    } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
1204
        /* qNan / infinity conversion */
1205
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1206
    } else {
1207
        farg.ll = float64_to_int64(farg.d, &env->fp_status);
1208
    }
1209
    return farg.ll;
1210
}
1211

    
1212
/* fctidz - fctidz. */
1213
uint64_t helper_fctidz (uint64_t arg)
1214
{
1215
    CPU_DoubleU farg;
1216
    farg.ll = arg;
1217

    
1218
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1219
        /* sNaN conversion */
1220
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1221
    } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
1222
        /* qNan / infinity conversion */
1223
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1224
    } else {
1225
        farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status);
1226
    }
1227
    return farg.ll;
1228
}
1229

    
1230
#endif
1231

    
1232
static always_inline uint64_t do_fri (uint64_t arg, int rounding_mode)
1233
{
1234
    CPU_DoubleU farg;
1235
    farg.ll = arg;
1236

    
1237
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1238
        /* sNaN round */
1239
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1240
    } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
1241
        /* qNan / infinity round */
1242
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1243
    } else {
1244
        set_float_rounding_mode(rounding_mode, &env->fp_status);
1245
        farg.ll = float64_round_to_int(farg.d, &env->fp_status);
1246
        /* Restore rounding mode from FPSCR */
1247
        fpscr_set_rounding_mode();
1248
    }
1249
    return farg.ll;
1250
}
1251

    
1252
uint64_t helper_frin (uint64_t arg)
1253
{
1254
    return do_fri(arg, float_round_nearest_even);
1255
}
1256

    
1257
uint64_t helper_friz (uint64_t arg)
1258
{
1259
    return do_fri(arg, float_round_to_zero);
1260
}
1261

    
1262
uint64_t helper_frip (uint64_t arg)
1263
{
1264
    return do_fri(arg, float_round_up);
1265
}
1266

    
1267
uint64_t helper_frim (uint64_t arg)
1268
{
1269
    return do_fri(arg, float_round_down);
1270
}
1271

    
1272
/* fmadd - fmadd. */
1273
uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1274
{
1275
    CPU_DoubleU farg1, farg2, farg3;
1276

    
1277
    farg1.ll = arg1;
1278
    farg2.ll = arg2;
1279
    farg3.ll = arg3;
1280
#if USE_PRECISE_EMULATION
1281
    if (unlikely(float64_is_signaling_nan(farg1.d) ||
1282
                 float64_is_signaling_nan(farg2.d) ||
1283
                 float64_is_signaling_nan(farg3.d))) {
1284
        /* sNaN operation */
1285
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1286
    } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1287
                        (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1288
        /* Multiplication of zero by infinity */
1289
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1290
    } else {
1291
#ifdef FLOAT128
1292
        /* This is the way the PowerPC specification defines it */
1293
        float128 ft0_128, ft1_128;
1294

    
1295
        ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1296
        ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1297
        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1298
        if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1299
                     float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1300
            /* Magnitude subtraction of infinities */
1301
            farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1302
        } else {
1303
            ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1304
            ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1305
            farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1306
        }
1307
#else
1308
        /* This is OK on x86 hosts */
1309
        farg1.d = (farg1.d * farg2.d) + farg3.d;
1310
#endif
1311
    }
1312
#else
1313
    farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1314
    farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status);
1315
#endif
1316
    return farg1.ll;
1317
}
1318

    
1319
/* fmsub - fmsub. */
1320
uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1321
{
1322
    CPU_DoubleU farg1, farg2, farg3;
1323

    
1324
    farg1.ll = arg1;
1325
    farg2.ll = arg2;
1326
    farg3.ll = arg3;
1327
#if USE_PRECISE_EMULATION
1328
    if (unlikely(float64_is_signaling_nan(farg1.d) ||
1329
                 float64_is_signaling_nan(farg2.d) ||
1330
                 float64_is_signaling_nan(farg3.d))) {
1331
        /* sNaN operation */
1332
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1333
    } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1334
                        (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1335
        /* Multiplication of zero by infinity */
1336
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1337
    } else {
1338
#ifdef FLOAT128
1339
        /* This is the way the PowerPC specification defines it */
1340
        float128 ft0_128, ft1_128;
1341

    
1342
        ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1343
        ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1344
        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1345
        if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1346
                     float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1347
            /* Magnitude subtraction of infinities */
1348
            farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1349
        } else {
1350
            ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1351
            ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1352
            farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1353
        }
1354
#else
1355
        /* This is OK on x86 hosts */
1356
        farg1.d = (farg1.d * farg2.d) - farg3.d;
1357
#endif
1358
    }
1359
#else
1360
    farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1361
    farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status);
1362
#endif
1363
    return farg1.ll;
1364
}
1365

    
1366
/* fnmadd - fnmadd. */
1367
uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1368
{
1369
    CPU_DoubleU farg1, farg2, farg3;
1370

    
1371
    farg1.ll = arg1;
1372
    farg2.ll = arg2;
1373
    farg3.ll = arg3;
1374

    
1375
    if (unlikely(float64_is_signaling_nan(farg1.d) ||
1376
                 float64_is_signaling_nan(farg2.d) ||
1377
                 float64_is_signaling_nan(farg3.d))) {
1378
        /* sNaN operation */
1379
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1380
    } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1381
                        (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1382
        /* Multiplication of zero by infinity */
1383
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1384
    } else {
1385
#if USE_PRECISE_EMULATION
1386
#ifdef FLOAT128
1387
        /* This is the way the PowerPC specification defines it */
1388
        float128 ft0_128, ft1_128;
1389

    
1390
        ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1391
        ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1392
        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1393
        if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1394
                     float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1395
            /* Magnitude subtraction of infinities */
1396
            farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1397
        } else {
1398
            ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1399
            ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1400
            farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1401
        }
1402
#else
1403
        /* This is OK on x86 hosts */
1404
        farg1.d = (farg1.d * farg2.d) + farg3.d;
1405
#endif
1406
#else
1407
        farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1408
        farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status);
1409
#endif
1410
        if (likely(!float64_is_nan(farg1.d)))
1411
            farg1.d = float64_chs(farg1.d);
1412
    }
1413
    return farg1.ll;
1414
}
1415

    
1416
/* fnmsub - fnmsub. */
1417
uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1418
{
1419
    CPU_DoubleU farg1, farg2, farg3;
1420

    
1421
    farg1.ll = arg1;
1422
    farg2.ll = arg2;
1423
    farg3.ll = arg3;
1424

    
1425
    if (unlikely(float64_is_signaling_nan(farg1.d) ||
1426
                 float64_is_signaling_nan(farg2.d) ||
1427
                 float64_is_signaling_nan(farg3.d))) {
1428
        /* sNaN operation */
1429
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1430
    } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1431
                        (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1432
        /* Multiplication of zero by infinity */
1433
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1434
    } else {
1435
#if USE_PRECISE_EMULATION
1436
#ifdef FLOAT128
1437
        /* This is the way the PowerPC specification defines it */
1438
        float128 ft0_128, ft1_128;
1439

    
1440
        ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1441
        ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1442
        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1443
        if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1444
                     float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1445
            /* Magnitude subtraction of infinities */
1446
            farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1447
        } else {
1448
            ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1449
            ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1450
            farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1451
        }
1452
#else
1453
        /* This is OK on x86 hosts */
1454
        farg1.d = (farg1.d * farg2.d) - farg3.d;
1455
#endif
1456
#else
1457
        farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1458
        farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status);
1459
#endif
1460
        if (likely(!float64_is_nan(farg1.d)))
1461
            farg1.d = float64_chs(farg1.d);
1462
    }
1463
    return farg1.ll;
1464
}
1465

    
1466
/* frsp - frsp. */
1467
uint64_t helper_frsp (uint64_t arg)
1468
{
1469
    CPU_DoubleU farg;
1470
    float32 f32;
1471
    farg.ll = arg;
1472

    
1473
#if USE_PRECISE_EMULATION
1474
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1475
        /* sNaN square root */
1476
       farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1477
    } else {
1478
       f32 = float64_to_float32(farg.d, &env->fp_status);
1479
       farg.d = float32_to_float64(f32, &env->fp_status);
1480
    }
1481
#else
1482
    f32 = float64_to_float32(farg.d, &env->fp_status);
1483
    farg.d = float32_to_float64(f32, &env->fp_status);
1484
#endif
1485
    return farg.ll;
1486
}
1487

    
1488
/* fsqrt - fsqrt. */
1489
uint64_t helper_fsqrt (uint64_t arg)
1490
{
1491
    CPU_DoubleU farg;
1492
    farg.ll = arg;
1493

    
1494
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1495
        /* sNaN square root */
1496
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1497
    } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
1498
        /* Square root of a negative nonzero number */
1499
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
1500
    } else {
1501
        farg.d = float64_sqrt(farg.d, &env->fp_status);
1502
    }
1503
    return farg.ll;
1504
}
1505

    
1506
/* fre - fre. */
1507
uint64_t helper_fre (uint64_t arg)
1508
{
1509
    CPU_DoubleU fone, farg;
1510
    fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
1511
    farg.ll = arg;
1512

    
1513
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1514
        /* sNaN reciprocal */
1515
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1516
    } else if (unlikely(float64_is_zero(farg.d))) {
1517
        /* Zero reciprocal */
1518
        farg.ll = float_zero_divide_excp(fone.d, farg.d);
1519
    } else {
1520
        farg.d = float64_div(fone.d, farg.d, &env->fp_status);
1521
    }
1522
    return farg.d;
1523
}
1524

    
1525
/* fres - fres. */
1526
uint64_t helper_fres (uint64_t arg)
1527
{
1528
    CPU_DoubleU fone, farg;
1529
    float32 f32;
1530
    fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
1531
    farg.ll = arg;
1532

    
1533
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1534
        /* sNaN reciprocal */
1535
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1536
    } else if (unlikely(float64_is_zero(farg.d))) {
1537
        /* Zero reciprocal */
1538
        farg.ll = float_zero_divide_excp(fone.d, farg.d);
1539
    } else {
1540
        farg.d = float64_div(fone.d, farg.d, &env->fp_status);
1541
        f32 = float64_to_float32(farg.d, &env->fp_status);
1542
        farg.d = float32_to_float64(f32, &env->fp_status);
1543
    }
1544
    return farg.ll;
1545
}
1546

    
1547
/* frsqrte  - frsqrte. */
1548
uint64_t helper_frsqrte (uint64_t arg)
1549
{
1550
    CPU_DoubleU fone, farg;
1551
    float32 f32;
1552
    fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
1553
    farg.ll = arg;
1554

    
1555
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1556
        /* sNaN reciprocal square root */
1557
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1558
    } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
1559
        /* Reciprocal square root of a negative nonzero number */
1560
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
1561
    } else {
1562
        farg.d = float64_sqrt(farg.d, &env->fp_status);
1563
        farg.d = float64_div(fone.d, farg.d, &env->fp_status);
1564
        f32 = float64_to_float32(farg.d, &env->fp_status);
1565
        farg.d = float32_to_float64(f32, &env->fp_status);
1566
    }
1567
    return farg.ll;
1568
}
1569

    
1570
/* fsel - fsel. */
1571
uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1572
{
1573
    CPU_DoubleU farg1;
1574

    
1575
    farg1.ll = arg1;
1576

    
1577
    if (!float64_is_neg(farg1.d) || float64_is_zero(farg1.d))
1578
        return arg2;
1579
    else
1580
        return arg3;
1581
}
1582

    
1583
void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD)
1584
{
1585
    CPU_DoubleU farg1, farg2;
1586
    uint32_t ret = 0;
1587
    farg1.ll = arg1;
1588
    farg2.ll = arg2;
1589

    
1590
    if (unlikely(float64_is_nan(farg1.d) ||
1591
                 float64_is_nan(farg2.d))) {
1592
        ret = 0x01UL;
1593
    } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1594
        ret = 0x08UL;
1595
    } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1596
        ret = 0x04UL;
1597
    } else {
1598
        ret = 0x02UL;
1599
    }
1600

    
1601
    env->fpscr &= ~(0x0F << FPSCR_FPRF);
1602
    env->fpscr |= ret << FPSCR_FPRF;
1603
    env->crf[crfD] = ret;
1604
    if (unlikely(ret == 0x01UL
1605
                 && (float64_is_signaling_nan(farg1.d) ||
1606
                     float64_is_signaling_nan(farg2.d)))) {
1607
        /* sNaN comparison */
1608
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1609
    }
1610
}
1611

    
1612
void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD)
1613
{
1614
    CPU_DoubleU farg1, farg2;
1615
    uint32_t ret = 0;
1616
    farg1.ll = arg1;
1617
    farg2.ll = arg2;
1618

    
1619
    if (unlikely(float64_is_nan(farg1.d) ||
1620
                 float64_is_nan(farg2.d))) {
1621
        ret = 0x01UL;
1622
    } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1623
        ret = 0x08UL;
1624
    } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1625
        ret = 0x04UL;
1626
    } else {
1627
        ret = 0x02UL;
1628
    }
1629

    
1630
    env->fpscr &= ~(0x0F << FPSCR_FPRF);
1631
    env->fpscr |= ret << FPSCR_FPRF;
1632
    env->crf[crfD] = ret;
1633
    if (unlikely (ret == 0x01UL)) {
1634
        if (float64_is_signaling_nan(farg1.d) ||
1635
            float64_is_signaling_nan(farg2.d)) {
1636
            /* sNaN comparison */
1637
            fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
1638
                                  POWERPC_EXCP_FP_VXVC);
1639
        } else {
1640
            /* qNaN comparison */
1641
            fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
1642
        }
1643
    }
1644
}
1645

    
1646
#if !defined (CONFIG_USER_ONLY)
1647
void helper_store_msr (target_ulong val)
1648
{
1649
    val = hreg_store_msr(env, val, 0);
1650
    if (val != 0) {
1651
        env->interrupt_request |= CPU_INTERRUPT_EXITTB;
1652
        helper_raise_exception(val);
1653
    }
1654
}
1655

    
1656
static always_inline void do_rfi (target_ulong nip, target_ulong msr,
1657
                                    target_ulong msrm, int keep_msrh)
1658
{
1659
#if defined(TARGET_PPC64)
1660
    if (msr & (1ULL << MSR_SF)) {
1661
        nip = (uint64_t)nip;
1662
        msr &= (uint64_t)msrm;
1663
    } else {
1664
        nip = (uint32_t)nip;
1665
        msr = (uint32_t)(msr & msrm);
1666
        if (keep_msrh)
1667
            msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
1668
    }
1669
#else
1670
    nip = (uint32_t)nip;
1671
    msr &= (uint32_t)msrm;
1672
#endif
1673
    /* XXX: beware: this is false if VLE is supported */
1674
    env->nip = nip & ~((target_ulong)0x00000003);
1675
    hreg_store_msr(env, msr, 1);
1676
#if defined (DEBUG_OP)
1677
    cpu_dump_rfi(env->nip, env->msr);
1678
#endif
1679
    /* No need to raise an exception here,
1680
     * as rfi is always the last insn of a TB
1681
     */
1682
    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
1683
}
1684

    
1685
void helper_rfi (void)
1686
{
1687
    do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1688
           ~((target_ulong)0xFFFF0000), 1);
1689
}
1690

    
1691
#if defined(TARGET_PPC64)
1692
void helper_rfid (void)
1693
{
1694
    do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1695
           ~((target_ulong)0xFFFF0000), 0);
1696
}
1697

    
1698
void helper_hrfid (void)
1699
{
1700
    do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
1701
           ~((target_ulong)0xFFFF0000), 0);
1702
}
1703
#endif
1704
#endif
1705

    
1706
void helper_tw (target_ulong arg1, target_ulong arg2, uint32_t flags)
1707
{
1708
    if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
1709
                  ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
1710
                  ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
1711
                  ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
1712
                  ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
1713
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
1714
    }
1715
}
1716

    
1717
#if defined(TARGET_PPC64)
1718
void helper_td (target_ulong arg1, target_ulong arg2, uint32_t flags)
1719
{
1720
    if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
1721
                  ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
1722
                  ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
1723
                  ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
1724
                  ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01)))))
1725
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
1726
}
1727
#endif
1728

    
1729
/*****************************************************************************/
1730
/* PowerPC 601 specific instructions (POWER bridge) */
1731

    
1732
target_ulong helper_clcs (uint32_t arg)
1733
{
1734
    switch (arg) {
1735
    case 0x0CUL:
1736
        /* Instruction cache line size */
1737
        return env->icache_line_size;
1738
        break;
1739
    case 0x0DUL:
1740
        /* Data cache line size */
1741
        return env->dcache_line_size;
1742
        break;
1743
    case 0x0EUL:
1744
        /* Minimum cache line size */
1745
        return (env->icache_line_size < env->dcache_line_size) ?
1746
                env->icache_line_size : env->dcache_line_size;
1747
        break;
1748
    case 0x0FUL:
1749
        /* Maximum cache line size */
1750
        return (env->icache_line_size > env->dcache_line_size) ?
1751
                env->icache_line_size : env->dcache_line_size;
1752
        break;
1753
    default:
1754
        /* Undefined */
1755
        return 0;
1756
        break;
1757
    }
1758
}
1759

    
1760
target_ulong helper_div (target_ulong arg1, target_ulong arg2)
1761
{
1762
    uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
1763

    
1764
    if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1765
        (int32_t)arg2 == 0) {
1766
        env->spr[SPR_MQ] = 0;
1767
        return INT32_MIN;
1768
    } else {
1769
        env->spr[SPR_MQ] = tmp % arg2;
1770
        return  tmp / (int32_t)arg2;
1771
    }
1772
}
1773

    
1774
target_ulong helper_divo (target_ulong arg1, target_ulong arg2)
1775
{
1776
    uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
1777

    
1778
    if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1779
        (int32_t)arg2 == 0) {
1780
        env->xer |= (1 << XER_OV) | (1 << XER_SO);
1781
        env->spr[SPR_MQ] = 0;
1782
        return INT32_MIN;
1783
    } else {
1784
        env->spr[SPR_MQ] = tmp % arg2;
1785
        tmp /= (int32_t)arg2;
1786
        if ((int32_t)tmp != tmp) {
1787
            env->xer |= (1 << XER_OV) | (1 << XER_SO);
1788
        } else {
1789
            env->xer &= ~(1 << XER_OV);
1790
        }
1791
        return tmp;
1792
    }
1793
}
1794

    
1795
target_ulong helper_divs (target_ulong arg1, target_ulong arg2)
1796
{
1797
    if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1798
        (int32_t)arg2 == 0) {
1799
        env->spr[SPR_MQ] = 0;
1800
        return INT32_MIN;
1801
    } else {
1802
        env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1803
        return (int32_t)arg1 / (int32_t)arg2;
1804
    }
1805
}
1806

    
1807
target_ulong helper_divso (target_ulong arg1, target_ulong arg2)
1808
{
1809
    if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1810
        (int32_t)arg2 == 0) {
1811
        env->xer |= (1 << XER_OV) | (1 << XER_SO);
1812
        env->spr[SPR_MQ] = 0;
1813
        return INT32_MIN;
1814
    } else {
1815
        env->xer &= ~(1 << XER_OV);
1816
        env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1817
        return (int32_t)arg1 / (int32_t)arg2;
1818
    }
1819
}
1820

    
1821
#if !defined (CONFIG_USER_ONLY)
1822
target_ulong helper_rac (target_ulong addr)
1823
{
1824
    mmu_ctx_t ctx;
1825
    int nb_BATs;
1826
    target_ulong ret = 0;
1827

    
1828
    /* We don't have to generate many instances of this instruction,
1829
     * as rac is supervisor only.
1830
     */
1831
    /* XXX: FIX THIS: Pretend we have no BAT */
1832
    nb_BATs = env->nb_BATs;
1833
    env->nb_BATs = 0;
1834
    if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0)
1835
        ret = ctx.raddr;
1836
    env->nb_BATs = nb_BATs;
1837
    return ret;
1838
}
1839

    
1840
void helper_rfsvc (void)
1841
{
1842
    do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
1843
}
1844
#endif
1845

    
1846
/*****************************************************************************/
1847
/* 602 specific instructions */
1848
/* mfrom is the most crazy instruction ever seen, imho ! */
1849
/* Real implementation uses a ROM table. Do the same */
1850
/* Extremly decomposed:
1851
 *                      -arg / 256
1852
 * return 256 * log10(10           + 1.0) + 0.5
1853
 */
1854
#if !defined (CONFIG_USER_ONLY)
1855
target_ulong helper_602_mfrom (target_ulong arg)
1856
{
1857
    if (likely(arg < 602)) {
1858
#include "mfrom_table.c"
1859
        return mfrom_ROM_table[arg];
1860
    } else {
1861
        return 0;
1862
    }
1863
}
1864
#endif
1865

    
1866
/*****************************************************************************/
1867
/* Embedded PowerPC specific helpers */
1868

    
1869
/* XXX: to be improved to check access rights when in user-mode */
1870
target_ulong helper_load_dcr (target_ulong dcrn)
1871
{
1872
    target_ulong val = 0;
1873

    
1874
    if (unlikely(env->dcr_env == NULL)) {
1875
        if (loglevel != 0) {
1876
            fprintf(logfile, "No DCR environment\n");
1877
        }
1878
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1879
                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
1880
    } else if (unlikely(ppc_dcr_read(env->dcr_env, dcrn, &val) != 0)) {
1881
        if (loglevel != 0) {
1882
            fprintf(logfile, "DCR read error %d %03x\n", (int)dcrn, (int)dcrn);
1883
        }
1884
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1885
                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1886
    }
1887
    return val;
1888
}
1889

    
1890
void helper_store_dcr (target_ulong dcrn, target_ulong val)
1891
{
1892
    if (unlikely(env->dcr_env == NULL)) {
1893
        if (loglevel != 0) {
1894
            fprintf(logfile, "No DCR environment\n");
1895
        }
1896
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1897
                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
1898
    } else if (unlikely(ppc_dcr_write(env->dcr_env, dcrn, val) != 0)) {
1899
        if (loglevel != 0) {
1900
            fprintf(logfile, "DCR write error %d %03x\n", (int)dcrn, (int)dcrn);
1901
        }
1902
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1903
                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1904
    }
1905
}
1906

    
1907
#if !defined(CONFIG_USER_ONLY)
1908
void helper_40x_rfci (void)
1909
{
1910
    do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
1911
           ~((target_ulong)0xFFFF0000), 0);
1912
}
1913

    
1914
void helper_rfci (void)
1915
{
1916
    do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
1917
           ~((target_ulong)0x3FFF0000), 0);
1918
}
1919

    
1920
void helper_rfdi (void)
1921
{
1922
    do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
1923
           ~((target_ulong)0x3FFF0000), 0);
1924
}
1925

    
1926
void helper_rfmci (void)
1927
{
1928
    do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
1929
           ~((target_ulong)0x3FFF0000), 0);
1930
}
1931
#endif
1932

    
1933
/* 440 specific */
1934
target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_Rc)
1935
{
1936
    target_ulong mask;
1937
    int i;
1938

    
1939
    i = 1;
1940
    for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1941
        if ((high & mask) == 0) {
1942
            if (update_Rc) {
1943
                env->crf[0] = 0x4;
1944
            }
1945
            goto done;
1946
        }
1947
        i++;
1948
    }
1949
    for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1950
        if ((low & mask) == 0) {
1951
            if (update_Rc) {
1952
                env->crf[0] = 0x8;
1953
            }
1954
            goto done;
1955
        }
1956
        i++;
1957
    }
1958
    if (update_Rc) {
1959
        env->crf[0] = 0x2;
1960
    }
1961
 done:
1962
    env->xer = (env->xer & ~0x7F) | i;
1963
    if (update_Rc) {
1964
        env->crf[0] |= xer_so;
1965
    }
1966
    return i;
1967
}
1968

    
1969
/*****************************************************************************/
1970
/* SPE extension helpers */
1971
/* Use a table to make this quicker */
1972
static uint8_t hbrev[16] = {
1973
    0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
1974
    0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
1975
};
1976

    
1977
static always_inline uint8_t byte_reverse (uint8_t val)
1978
{
1979
    return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
1980
}
1981

    
1982
static always_inline uint32_t word_reverse (uint32_t val)
1983
{
1984
    return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
1985
        (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
1986
}
1987

    
1988
#define MASKBITS 16 // Random value - to be fixed (implementation dependant)
1989
target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
1990
{
1991
    uint32_t a, b, d, mask;
1992

    
1993
    mask = UINT32_MAX >> (32 - MASKBITS);
1994
    a = arg1 & mask;
1995
    b = arg2 & mask;
1996
    d = word_reverse(1 + word_reverse(a | ~b));
1997
    return (arg1 & ~mask) | (d & b);
1998
}
1999

    
2000
uint32_t helper_cntlsw32 (uint32_t val)
2001
{
2002
    if (val & 0x80000000)
2003
        return clz32(~val);
2004
    else
2005
        return clz32(val);
2006
}
2007

    
2008
uint32_t helper_cntlzw32 (uint32_t val)
2009
{
2010
    return clz32(val);
2011
}
2012

    
2013
/* Single-precision floating-point conversions */
2014
static always_inline uint32_t efscfsi (uint32_t val)
2015
{
2016
    CPU_FloatU u;
2017

    
2018
    u.f = int32_to_float32(val, &env->spe_status);
2019

    
2020
    return u.l;
2021
}
2022

    
2023
static always_inline uint32_t efscfui (uint32_t val)
2024
{
2025
    CPU_FloatU u;
2026

    
2027
    u.f = uint32_to_float32(val, &env->spe_status);
2028

    
2029
    return u.l;
2030
}
2031

    
2032
static always_inline int32_t efsctsi (uint32_t val)
2033
{
2034
    CPU_FloatU u;
2035

    
2036
    u.l = val;
2037
    /* NaN are not treated the same way IEEE 754 does */
2038
    if (unlikely(float32_is_nan(u.f)))
2039
        return 0;
2040

    
2041
    return float32_to_int32(u.f, &env->spe_status);
2042
}
2043

    
2044
static always_inline uint32_t efsctui (uint32_t val)
2045
{
2046
    CPU_FloatU u;
2047

    
2048
    u.l = val;
2049
    /* NaN are not treated the same way IEEE 754 does */
2050
    if (unlikely(float32_is_nan(u.f)))
2051
        return 0;
2052

    
2053
    return float32_to_uint32(u.f, &env->spe_status);
2054
}
2055

    
2056
static always_inline uint32_t efsctsiz (uint32_t val)
2057
{
2058
    CPU_FloatU u;
2059

    
2060
    u.l = val;
2061
    /* NaN are not treated the same way IEEE 754 does */
2062
    if (unlikely(float32_is_nan(u.f)))
2063
        return 0;
2064

    
2065
    return float32_to_int32_round_to_zero(u.f, &env->spe_status);
2066
}
2067

    
2068
static always_inline uint32_t efsctuiz (uint32_t val)
2069
{
2070
    CPU_FloatU u;
2071

    
2072
    u.l = val;
2073
    /* NaN are not treated the same way IEEE 754 does */
2074
    if (unlikely(float32_is_nan(u.f)))
2075
        return 0;
2076

    
2077
    return float32_to_uint32_round_to_zero(u.f, &env->spe_status);
2078
}
2079

    
2080
static always_inline uint32_t efscfsf (uint32_t val)
2081
{
2082
    CPU_FloatU u;
2083
    float32 tmp;
2084

    
2085
    u.f = int32_to_float32(val, &env->spe_status);
2086
    tmp = int64_to_float32(1ULL << 32, &env->spe_status);
2087
    u.f = float32_div(u.f, tmp, &env->spe_status);
2088

    
2089
    return u.l;
2090
}
2091

    
2092
static always_inline uint32_t efscfuf (uint32_t val)
2093
{
2094
    CPU_FloatU u;
2095
    float32 tmp;
2096

    
2097
    u.f = uint32_to_float32(val, &env->spe_status);
2098
    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2099
    u.f = float32_div(u.f, tmp, &env->spe_status);
2100

    
2101
    return u.l;
2102
}
2103

    
2104
static always_inline uint32_t efsctsf (uint32_t val)
2105
{
2106
    CPU_FloatU u;
2107
    float32 tmp;
2108

    
2109
    u.l = val;
2110
    /* NaN are not treated the same way IEEE 754 does */
2111
    if (unlikely(float32_is_nan(u.f)))
2112
        return 0;
2113
    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2114
    u.f = float32_mul(u.f, tmp, &env->spe_status);
2115

    
2116
    return float32_to_int32(u.f, &env->spe_status);
2117
}
2118

    
2119
static always_inline uint32_t efsctuf (uint32_t val)
2120
{
2121
    CPU_FloatU u;
2122
    float32 tmp;
2123

    
2124
    u.l = val;
2125
    /* NaN are not treated the same way IEEE 754 does */
2126
    if (unlikely(float32_is_nan(u.f)))
2127
        return 0;
2128
    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2129
    u.f = float32_mul(u.f, tmp, &env->spe_status);
2130

    
2131
    return float32_to_uint32(u.f, &env->spe_status);
2132
}
2133

    
2134
#define HELPER_SPE_SINGLE_CONV(name)                                          \
2135
uint32_t helper_e##name (uint32_t val)                                        \
2136
{                                                                             \
2137
    return e##name(val);                                                      \
2138
}
2139
/* efscfsi */
2140
HELPER_SPE_SINGLE_CONV(fscfsi);
2141
/* efscfui */
2142
HELPER_SPE_SINGLE_CONV(fscfui);
2143
/* efscfuf */
2144
HELPER_SPE_SINGLE_CONV(fscfuf);
2145
/* efscfsf */
2146
HELPER_SPE_SINGLE_CONV(fscfsf);
2147
/* efsctsi */
2148
HELPER_SPE_SINGLE_CONV(fsctsi);
2149
/* efsctui */
2150
HELPER_SPE_SINGLE_CONV(fsctui);
2151
/* efsctsiz */
2152
HELPER_SPE_SINGLE_CONV(fsctsiz);
2153
/* efsctuiz */
2154
HELPER_SPE_SINGLE_CONV(fsctuiz);
2155
/* efsctsf */
2156
HELPER_SPE_SINGLE_CONV(fsctsf);
2157
/* efsctuf */
2158
HELPER_SPE_SINGLE_CONV(fsctuf);
2159

    
2160
#define HELPER_SPE_VECTOR_CONV(name)                                          \
2161
uint64_t helper_ev##name (uint64_t val)                                       \
2162
{                                                                             \
2163
    return ((uint64_t)e##name(val >> 32) << 32) |                             \
2164
            (uint64_t)e##name(val);                                           \
2165
}
2166
/* evfscfsi */
2167
HELPER_SPE_VECTOR_CONV(fscfsi);
2168
/* evfscfui */
2169
HELPER_SPE_VECTOR_CONV(fscfui);
2170
/* evfscfuf */
2171
HELPER_SPE_VECTOR_CONV(fscfuf);
2172
/* evfscfsf */
2173
HELPER_SPE_VECTOR_CONV(fscfsf);
2174
/* evfsctsi */
2175
HELPER_SPE_VECTOR_CONV(fsctsi);
2176
/* evfsctui */
2177
HELPER_SPE_VECTOR_CONV(fsctui);
2178
/* evfsctsiz */
2179
HELPER_SPE_VECTOR_CONV(fsctsiz);
2180
/* evfsctuiz */
2181
HELPER_SPE_VECTOR_CONV(fsctuiz);
2182
/* evfsctsf */
2183
HELPER_SPE_VECTOR_CONV(fsctsf);
2184
/* evfsctuf */
2185
HELPER_SPE_VECTOR_CONV(fsctuf);
2186

    
2187
/* Single-precision floating-point arithmetic */
2188
static always_inline uint32_t efsadd (uint32_t op1, uint32_t op2)
2189
{
2190
    CPU_FloatU u1, u2;
2191
    u1.l = op1;
2192
    u2.l = op2;
2193
    u1.f = float32_add(u1.f, u2.f, &env->spe_status);
2194
    return u1.l;
2195
}
2196

    
2197
static always_inline uint32_t efssub (uint32_t op1, uint32_t op2)
2198
{
2199
    CPU_FloatU u1, u2;
2200
    u1.l = op1;
2201
    u2.l = op2;
2202
    u1.f = float32_sub(u1.f, u2.f, &env->spe_status);
2203
    return u1.l;
2204
}
2205

    
2206
static always_inline uint32_t efsmul (uint32_t op1, uint32_t op2)
2207
{
2208
    CPU_FloatU u1, u2;
2209
    u1.l = op1;
2210
    u2.l = op2;
2211
    u1.f = float32_mul(u1.f, u2.f, &env->spe_status);
2212
    return u1.l;
2213
}
2214

    
2215
static always_inline uint32_t efsdiv (uint32_t op1, uint32_t op2)
2216
{
2217
    CPU_FloatU u1, u2;
2218
    u1.l = op1;
2219
    u2.l = op2;
2220
    u1.f = float32_div(u1.f, u2.f, &env->spe_status);
2221
    return u1.l;
2222
}
2223

    
2224
#define HELPER_SPE_SINGLE_ARITH(name)                                         \
2225
uint32_t helper_e##name (uint32_t op1, uint32_t op2)                          \
2226
{                                                                             \
2227
    return e##name(op1, op2);                                                 \
2228
}
2229
/* efsadd */
2230
HELPER_SPE_SINGLE_ARITH(fsadd);
2231
/* efssub */
2232
HELPER_SPE_SINGLE_ARITH(fssub);
2233
/* efsmul */
2234
HELPER_SPE_SINGLE_ARITH(fsmul);
2235
/* efsdiv */
2236
HELPER_SPE_SINGLE_ARITH(fsdiv);
2237

    
2238
#define HELPER_SPE_VECTOR_ARITH(name)                                         \
2239
uint64_t helper_ev##name (uint64_t op1, uint64_t op2)                         \
2240
{                                                                             \
2241
    return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) |                  \
2242
            (uint64_t)e##name(op1, op2);                                      \
2243
}
2244
/* evfsadd */
2245
HELPER_SPE_VECTOR_ARITH(fsadd);
2246
/* evfssub */
2247
HELPER_SPE_VECTOR_ARITH(fssub);
2248
/* evfsmul */
2249
HELPER_SPE_VECTOR_ARITH(fsmul);
2250
/* evfsdiv */
2251
HELPER_SPE_VECTOR_ARITH(fsdiv);
2252

    
2253
/* Single-precision floating-point comparisons */
2254
static always_inline uint32_t efststlt (uint32_t op1, uint32_t op2)
2255
{
2256
    CPU_FloatU u1, u2;
2257
    u1.l = op1;
2258
    u2.l = op2;
2259
    return float32_lt(u1.f, u2.f, &env->spe_status) ? 4 : 0;
2260
}
2261

    
2262
static always_inline uint32_t efststgt (uint32_t op1, uint32_t op2)
2263
{
2264
    CPU_FloatU u1, u2;
2265
    u1.l = op1;
2266
    u2.l = op2;
2267
    return float32_le(u1.f, u2.f, &env->spe_status) ? 0 : 4;
2268
}
2269

    
2270
static always_inline uint32_t efststeq (uint32_t op1, uint32_t op2)
2271
{
2272
    CPU_FloatU u1, u2;
2273
    u1.l = op1;
2274
    u2.l = op2;
2275
    return float32_eq(u1.f, u2.f, &env->spe_status) ? 4 : 0;
2276
}
2277

    
2278
static always_inline uint32_t efscmplt (uint32_t op1, uint32_t op2)
2279
{
2280
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2281
    return efststlt(op1, op2);
2282
}
2283

    
2284
static always_inline uint32_t efscmpgt (uint32_t op1, uint32_t op2)
2285
{
2286
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2287
    return efststgt(op1, op2);
2288
}
2289

    
2290
static always_inline uint32_t efscmpeq (uint32_t op1, uint32_t op2)
2291
{
2292
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2293
    return efststeq(op1, op2);
2294
}
2295

    
2296
#define HELPER_SINGLE_SPE_CMP(name)                                           \
2297
uint32_t helper_e##name (uint32_t op1, uint32_t op2)                          \
2298
{                                                                             \
2299
    return e##name(op1, op2) << 2;                                            \
2300
}
2301
/* efststlt */
2302
HELPER_SINGLE_SPE_CMP(fststlt);
2303
/* efststgt */
2304
HELPER_SINGLE_SPE_CMP(fststgt);
2305
/* efststeq */
2306
HELPER_SINGLE_SPE_CMP(fststeq);
2307
/* efscmplt */
2308
HELPER_SINGLE_SPE_CMP(fscmplt);
2309
/* efscmpgt */
2310
HELPER_SINGLE_SPE_CMP(fscmpgt);
2311
/* efscmpeq */
2312
HELPER_SINGLE_SPE_CMP(fscmpeq);
2313

    
2314
static always_inline uint32_t evcmp_merge (int t0, int t1)
2315
{
2316
    return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
2317
}
2318

    
2319
#define HELPER_VECTOR_SPE_CMP(name)                                           \
2320
uint32_t helper_ev##name (uint64_t op1, uint64_t op2)                         \
2321
{                                                                             \
2322
    return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2));     \
2323
}
2324
/* evfststlt */
2325
HELPER_VECTOR_SPE_CMP(fststlt);
2326
/* evfststgt */
2327
HELPER_VECTOR_SPE_CMP(fststgt);
2328
/* evfststeq */
2329
HELPER_VECTOR_SPE_CMP(fststeq);
2330
/* evfscmplt */
2331
HELPER_VECTOR_SPE_CMP(fscmplt);
2332
/* evfscmpgt */
2333
HELPER_VECTOR_SPE_CMP(fscmpgt);
2334
/* evfscmpeq */
2335
HELPER_VECTOR_SPE_CMP(fscmpeq);
2336

    
2337
/* Double-precision floating-point conversion */
2338
uint64_t helper_efdcfsi (uint32_t val)
2339
{
2340
    CPU_DoubleU u;
2341

    
2342
    u.d = int32_to_float64(val, &env->spe_status);
2343

    
2344
    return u.ll;
2345
}
2346

    
2347
uint64_t helper_efdcfsid (uint64_t val)
2348
{
2349
    CPU_DoubleU u;
2350

    
2351
    u.d = int64_to_float64(val, &env->spe_status);
2352

    
2353
    return u.ll;
2354
}
2355

    
2356
uint64_t helper_efdcfui (uint32_t val)
2357
{
2358
    CPU_DoubleU u;
2359

    
2360
    u.d = uint32_to_float64(val, &env->spe_status);
2361

    
2362
    return u.ll;
2363
}
2364

    
2365
uint64_t helper_efdcfuid (uint64_t val)
2366
{
2367
    CPU_DoubleU u;
2368

    
2369
    u.d = uint64_to_float64(val, &env->spe_status);
2370

    
2371
    return u.ll;
2372
}
2373

    
2374
uint32_t helper_efdctsi (uint64_t val)
2375
{
2376
    CPU_DoubleU u;
2377

    
2378
    u.ll = val;
2379
    /* NaN are not treated the same way IEEE 754 does */
2380
    if (unlikely(float64_is_nan(u.d)))
2381
        return 0;
2382

    
2383
    return float64_to_int32(u.d, &env->spe_status);
2384
}
2385

    
2386
uint32_t helper_efdctui (uint64_t val)
2387
{
2388
    CPU_DoubleU u;
2389

    
2390
    u.ll = val;
2391
    /* NaN are not treated the same way IEEE 754 does */
2392
    if (unlikely(float64_is_nan(u.d)))
2393
        return 0;
2394

    
2395
    return float64_to_uint32(u.d, &env->spe_status);
2396
}
2397

    
2398
uint32_t helper_efdctsiz (uint64_t val)
2399
{
2400
    CPU_DoubleU u;
2401

    
2402
    u.ll = val;
2403
    /* NaN are not treated the same way IEEE 754 does */
2404
    if (unlikely(float64_is_nan(u.d)))
2405
        return 0;
2406

    
2407
    return float64_to_int32_round_to_zero(u.d, &env->spe_status);
2408
}
2409

    
2410
uint64_t helper_efdctsidz (uint64_t val)
2411
{
2412
    CPU_DoubleU u;
2413

    
2414
    u.ll = val;
2415
    /* NaN are not treated the same way IEEE 754 does */
2416
    if (unlikely(float64_is_nan(u.d)))
2417
        return 0;
2418

    
2419
    return float64_to_int64_round_to_zero(u.d, &env->spe_status);
2420
}
2421

    
2422
uint32_t helper_efdctuiz (uint64_t val)
2423
{
2424
    CPU_DoubleU u;
2425

    
2426
    u.ll = val;
2427
    /* NaN are not treated the same way IEEE 754 does */
2428
    if (unlikely(float64_is_nan(u.d)))
2429
        return 0;
2430

    
2431
    return float64_to_uint32_round_to_zero(u.d, &env->spe_status);
2432
}
2433

    
2434
uint64_t helper_efdctuidz (uint64_t val)
2435
{
2436
    CPU_DoubleU u;
2437

    
2438
    u.ll = val;
2439
    /* NaN are not treated the same way IEEE 754 does */
2440
    if (unlikely(float64_is_nan(u.d)))
2441
        return 0;
2442

    
2443
    return float64_to_uint64_round_to_zero(u.d, &env->spe_status);
2444
}
2445

    
2446
uint64_t helper_efdcfsf (uint32_t val)
2447
{
2448
    CPU_DoubleU u;
2449
    float64 tmp;
2450

    
2451
    u.d = int32_to_float64(val, &env->spe_status);
2452
    tmp = int64_to_float64(1ULL << 32, &env->spe_status);
2453
    u.d = float64_div(u.d, tmp, &env->spe_status);
2454

    
2455
    return u.ll;
2456
}
2457

    
2458
uint64_t helper_efdcfuf (uint32_t val)
2459
{
2460
    CPU_DoubleU u;
2461
    float64 tmp;
2462

    
2463
    u.d = uint32_to_float64(val, &env->spe_status);
2464
    tmp = int64_to_float64(1ULL << 32, &env->spe_status);
2465
    u.d = float64_div(u.d, tmp, &env->spe_status);
2466

    
2467
    return u.ll;
2468
}
2469

    
2470
uint32_t helper_efdctsf (uint64_t val)
2471
{
2472
    CPU_DoubleU u;
2473
    float64 tmp;
2474

    
2475
    u.ll = val;
2476
    /* NaN are not treated the same way IEEE 754 does */
2477
    if (unlikely(float64_is_nan(u.d)))
2478
        return 0;
2479
    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
2480
    u.d = float64_mul(u.d, tmp, &env->spe_status);
2481

    
2482
    return float64_to_int32(u.d, &env->spe_status);
2483
}
2484

    
2485
uint32_t helper_efdctuf (uint64_t val)
2486
{
2487
    CPU_DoubleU u;
2488
    float64 tmp;
2489

    
2490
    u.ll = val;
2491
    /* NaN are not treated the same way IEEE 754 does */
2492
    if (unlikely(float64_is_nan(u.d)))
2493
        return 0;
2494
    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
2495
    u.d = float64_mul(u.d, tmp, &env->spe_status);
2496

    
2497
    return float64_to_uint32(u.d, &env->spe_status);
2498
}
2499

    
2500
uint32_t helper_efscfd (uint64_t val)
2501
{
2502
    CPU_DoubleU u1;
2503
    CPU_FloatU u2;
2504

    
2505
    u1.ll = val;
2506
    u2.f = float64_to_float32(u1.d, &env->spe_status);
2507

    
2508
    return u2.l;
2509
}
2510

    
2511
uint64_t helper_efdcfs (uint32_t val)
2512
{
2513
    CPU_DoubleU u2;
2514
    CPU_FloatU u1;
2515

    
2516
    u1.l = val;
2517
    u2.d = float32_to_float64(u1.f, &env->spe_status);
2518

    
2519
    return u2.ll;
2520
}
2521

    
2522
/* Double precision fixed-point arithmetic */
2523
uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
2524
{
2525
    CPU_DoubleU u1, u2;
2526
    u1.ll = op1;
2527
    u2.ll = op2;
2528
    u1.d = float64_add(u1.d, u2.d, &env->spe_status);
2529
    return u1.ll;
2530
}
2531

    
2532
uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
2533
{
2534
    CPU_DoubleU u1, u2;
2535
    u1.ll = op1;
2536
    u2.ll = op2;
2537
    u1.d = float64_sub(u1.d, u2.d, &env->spe_status);
2538
    return u1.ll;
2539
}
2540

    
2541
uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
2542
{
2543
    CPU_DoubleU u1, u2;
2544
    u1.ll = op1;
2545
    u2.ll = op2;
2546
    u1.d = float64_mul(u1.d, u2.d, &env->spe_status);
2547
    return u1.ll;
2548
}
2549

    
2550
uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
2551
{
2552
    CPU_DoubleU u1, u2;
2553
    u1.ll = op1;
2554
    u2.ll = op2;
2555
    u1.d = float64_div(u1.d, u2.d, &env->spe_status);
2556
    return u1.ll;
2557
}
2558

    
2559
/* Double precision floating point helpers */
2560
uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
2561
{
2562
    CPU_DoubleU u1, u2;
2563
    u1.ll = op1;
2564
    u2.ll = op2;
2565
    return float64_lt(u1.d, u2.d, &env->spe_status) ? 4 : 0;
2566
}
2567

    
2568
uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
2569
{
2570
    CPU_DoubleU u1, u2;
2571
    u1.ll = op1;
2572
    u2.ll = op2;
2573
    return float64_le(u1.d, u2.d, &env->spe_status) ? 0 : 4;
2574
}
2575

    
2576
uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
2577
{
2578
    CPU_DoubleU u1, u2;
2579
    u1.ll = op1;
2580
    u2.ll = op2;
2581
    return float64_eq(u1.d, u2.d, &env->spe_status) ? 4 : 0;
2582
}
2583

    
2584
uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
2585
{
2586
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2587
    return helper_efdtstlt(op1, op2);
2588
}
2589

    
2590
uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
2591
{
2592
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2593
    return helper_efdtstgt(op1, op2);
2594
}
2595

    
2596
uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
2597
{
2598
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2599
    return helper_efdtsteq(op1, op2);
2600
}
2601

    
2602
/*****************************************************************************/
2603
/* Softmmu support */
2604
#if !defined (CONFIG_USER_ONLY)
2605

    
2606
#define MMUSUFFIX _mmu
2607

    
2608
#define SHIFT 0
2609
#include "softmmu_template.h"
2610

    
2611
#define SHIFT 1
2612
#include "softmmu_template.h"
2613

    
2614
#define SHIFT 2
2615
#include "softmmu_template.h"
2616

    
2617
#define SHIFT 3
2618
#include "softmmu_template.h"
2619

    
2620
/* try to fill the TLB and return an exception if error. If retaddr is
2621
   NULL, it means that the function was called in C code (i.e. not
2622
   from generated code or from helper.c) */
2623
/* XXX: fix it to restore all registers */
2624
void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
2625
{
2626
    TranslationBlock *tb;
2627
    CPUState *saved_env;
2628
    unsigned long pc;
2629
    int ret;
2630

    
2631
    /* XXX: hack to restore env in all cases, even if not called from
2632
       generated code */
2633
    saved_env = env;
2634
    env = cpu_single_env;
2635
    ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
2636
    if (unlikely(ret != 0)) {
2637
        if (likely(retaddr)) {
2638
            /* now we have a real cpu fault */
2639
            pc = (unsigned long)retaddr;
2640
            tb = tb_find_pc(pc);
2641
            if (likely(tb)) {
2642
                /* the PC is inside the translated code. It means that we have
2643
                   a virtual CPU fault */
2644
                cpu_restore_state(tb, env, pc, NULL);
2645
            }
2646
        }
2647
        helper_raise_exception_err(env->exception_index, env->error_code);
2648
    }
2649
    env = saved_env;
2650
}
2651

    
2652
/* Segment registers load and store */
2653
target_ulong helper_load_sr (target_ulong sr_num)
2654
{
2655
    return env->sr[sr_num];
2656
}
2657

    
2658
void helper_store_sr (target_ulong sr_num, target_ulong val)
2659
{
2660
    ppc_store_sr(env, sr_num, val);
2661
}
2662

    
2663
/* SLB management */
2664
#if defined(TARGET_PPC64)
2665
target_ulong helper_load_slb (target_ulong slb_nr)
2666
{
2667
    return ppc_load_slb(env, slb_nr);
2668
}
2669

    
2670
void helper_store_slb (target_ulong slb_nr, target_ulong rs)
2671
{
2672
    ppc_store_slb(env, slb_nr, rs);
2673
}
2674

    
2675
void helper_slbia (void)
2676
{
2677
    ppc_slb_invalidate_all(env);
2678
}
2679

    
2680
void helper_slbie (target_ulong addr)
2681
{
2682
    ppc_slb_invalidate_one(env, addr);
2683
}
2684

    
2685
#endif /* defined(TARGET_PPC64) */
2686

    
2687
/* TLB management */
2688
void helper_tlbia (void)
2689
{
2690
    ppc_tlb_invalidate_all(env);
2691
}
2692

    
2693
void helper_tlbie (target_ulong addr)
2694
{
2695
    ppc_tlb_invalidate_one(env, addr);
2696
}
2697

    
2698
/* Software driven TLBs management */
2699
/* PowerPC 602/603 software TLB load instructions helpers */
2700
static void do_6xx_tlb (target_ulong new_EPN, int is_code)
2701
{
2702
    target_ulong RPN, CMP, EPN;
2703
    int way;
2704

    
2705
    RPN = env->spr[SPR_RPA];
2706
    if (is_code) {
2707
        CMP = env->spr[SPR_ICMP];
2708
        EPN = env->spr[SPR_IMISS];
2709
    } else {
2710
        CMP = env->spr[SPR_DCMP];
2711
        EPN = env->spr[SPR_DMISS];
2712
    }
2713
    way = (env->spr[SPR_SRR1] >> 17) & 1;
2714
#if defined (DEBUG_SOFTWARE_TLB)
2715
    if (loglevel != 0) {
2716
        fprintf(logfile, "%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
2717
                " PTE1 " ADDRX " way %d\n",
2718
                __func__, new_EPN, EPN, CMP, RPN, way);
2719
    }
2720
#endif
2721
    /* Store this TLB */
2722
    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2723
                     way, is_code, CMP, RPN);
2724
}
2725

    
2726
void helper_6xx_tlbd (target_ulong EPN)
2727
{
2728
    do_6xx_tlb(EPN, 0);
2729
}
2730

    
2731
void helper_6xx_tlbi (target_ulong EPN)
2732
{
2733
    do_6xx_tlb(EPN, 1);
2734
}
2735

    
2736
/* PowerPC 74xx software TLB load instructions helpers */
2737
static void do_74xx_tlb (target_ulong new_EPN, int is_code)
2738
{
2739
    target_ulong RPN, CMP, EPN;
2740
    int way;
2741

    
2742
    RPN = env->spr[SPR_PTELO];
2743
    CMP = env->spr[SPR_PTEHI];
2744
    EPN = env->spr[SPR_TLBMISS] & ~0x3;
2745
    way = env->spr[SPR_TLBMISS] & 0x3;
2746
#if defined (DEBUG_SOFTWARE_TLB)
2747
    if (loglevel != 0) {
2748
        fprintf(logfile, "%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
2749
                " PTE1 " ADDRX " way %d\n",
2750
                __func__, new_EPN, EPN, CMP, RPN, way);
2751
    }
2752
#endif
2753
    /* Store this TLB */
2754
    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2755
                     way, is_code, CMP, RPN);
2756
}
2757

    
2758
void helper_74xx_tlbd (target_ulong EPN)
2759
{
2760
    do_74xx_tlb(EPN, 0);
2761
}
2762

    
2763
void helper_74xx_tlbi (target_ulong EPN)
2764
{
2765
    do_74xx_tlb(EPN, 1);
2766
}
2767

    
2768
static always_inline target_ulong booke_tlb_to_page_size (int size)
2769
{
2770
    return 1024 << (2 * size);
2771
}
2772

    
2773
static always_inline int booke_page_size_to_tlb (target_ulong page_size)
2774
{
2775
    int size;
2776

    
2777
    switch (page_size) {
2778
    case 0x00000400UL:
2779
        size = 0x0;
2780
        break;
2781
    case 0x00001000UL:
2782
        size = 0x1;
2783
        break;
2784
    case 0x00004000UL:
2785
        size = 0x2;
2786
        break;
2787
    case 0x00010000UL:
2788
        size = 0x3;
2789
        break;
2790
    case 0x00040000UL:
2791
        size = 0x4;
2792
        break;
2793
    case 0x00100000UL:
2794
        size = 0x5;
2795
        break;
2796
    case 0x00400000UL:
2797
        size = 0x6;
2798
        break;
2799
    case 0x01000000UL:
2800
        size = 0x7;
2801
        break;
2802
    case 0x04000000UL:
2803
        size = 0x8;
2804
        break;
2805
    case 0x10000000UL:
2806
        size = 0x9;
2807
        break;
2808
    case 0x40000000UL:
2809
        size = 0xA;
2810
        break;
2811
#if defined (TARGET_PPC64)
2812
    case 0x000100000000ULL:
2813
        size = 0xB;
2814
        break;
2815
    case 0x000400000000ULL:
2816
        size = 0xC;
2817
        break;
2818
    case 0x001000000000ULL:
2819
        size = 0xD;
2820
        break;
2821
    case 0x004000000000ULL:
2822
        size = 0xE;
2823
        break;
2824
    case 0x010000000000ULL:
2825
        size = 0xF;
2826
        break;
2827
#endif
2828
    default:
2829
        size = -1;
2830
        break;
2831
    }
2832

    
2833
    return size;
2834
}
2835

    
2836
/* Helpers for 4xx TLB management */
2837
target_ulong helper_4xx_tlbre_lo (target_ulong entry)
2838
{
2839
    ppcemb_tlb_t *tlb;
2840
    target_ulong ret;
2841
    int size;
2842

    
2843
    entry &= 0x3F;
2844
    tlb = &env->tlb[entry].tlbe;
2845
    ret = tlb->EPN;
2846
    if (tlb->prot & PAGE_VALID)
2847
        ret |= 0x400;
2848
    size = booke_page_size_to_tlb(tlb->size);
2849
    if (size < 0 || size > 0x7)
2850
        size = 1;
2851
    ret |= size << 7;
2852
    env->spr[SPR_40x_PID] = tlb->PID;
2853
    return ret;
2854
}
2855

    
2856
target_ulong helper_4xx_tlbre_hi (target_ulong entry)
2857
{
2858
    ppcemb_tlb_t *tlb;
2859
    target_ulong ret;
2860

    
2861
    entry &= 0x3F;
2862
    tlb = &env->tlb[entry].tlbe;
2863
    ret = tlb->RPN;
2864
    if (tlb->prot & PAGE_EXEC)
2865
        ret |= 0x200;
2866
    if (tlb->prot & PAGE_WRITE)
2867
        ret |= 0x100;
2868
    return ret;
2869
}
2870

    
2871
void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
2872
{
2873
    ppcemb_tlb_t *tlb;
2874
    target_ulong page, end;
2875

    
2876
#if defined (DEBUG_SOFTWARE_TLB)
2877
    if (loglevel != 0) {
2878
        fprintf(logfile, "%s entry %d val " ADDRX "\n", __func__, (int)entry, val);
2879
    }
2880
#endif
2881
    entry &= 0x3F;
2882
    tlb = &env->tlb[entry].tlbe;
2883
    /* Invalidate previous TLB (if it's valid) */
2884
    if (tlb->prot & PAGE_VALID) {
2885
        end = tlb->EPN + tlb->size;
2886
#if defined (DEBUG_SOFTWARE_TLB)
2887
        if (loglevel != 0) {
2888
            fprintf(logfile, "%s: invalidate old TLB %d start " ADDRX
2889
                    " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
2890
        }
2891
#endif
2892
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
2893
            tlb_flush_page(env, page);
2894
    }
2895
    tlb->size = booke_tlb_to_page_size((val >> 7) & 0x7);
2896
    /* We cannot handle TLB size < TARGET_PAGE_SIZE.
2897
     * If this ever occurs, one should use the ppcemb target instead
2898
     * of the ppc or ppc64 one
2899
     */
2900
    if ((val & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
2901
        cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
2902
                  "are not supported (%d)\n",
2903
                  tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
2904
    }
2905
    tlb->EPN = val & ~(tlb->size - 1);
2906
    if (val & 0x40)
2907
        tlb->prot |= PAGE_VALID;
2908
    else
2909
        tlb->prot &= ~PAGE_VALID;
2910
    if (val & 0x20) {
2911
        /* XXX: TO BE FIXED */
2912
        cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
2913
    }
2914
    tlb->PID = env->spr[SPR_40x_PID]; /* PID */
2915
    tlb->attr = val & 0xFF;
2916
#if defined (DEBUG_SOFTWARE_TLB)
2917
    if (loglevel != 0) {
2918
        fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
2919
                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
2920
                (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2921
                tlb->prot & PAGE_READ ? 'r' : '-',
2922
                tlb->prot & PAGE_WRITE ? 'w' : '-',
2923
                tlb->prot & PAGE_EXEC ? 'x' : '-',
2924
                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2925
    }
2926
#endif
2927
    /* Invalidate new TLB (if valid) */
2928
    if (tlb->prot & PAGE_VALID) {
2929
        end = tlb->EPN + tlb->size;
2930
#if defined (DEBUG_SOFTWARE_TLB)
2931
        if (loglevel != 0) {
2932
            fprintf(logfile, "%s: invalidate TLB %d start " ADDRX
2933
                    " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
2934
        }
2935
#endif
2936
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
2937
            tlb_flush_page(env, page);
2938
    }
2939
}
2940

    
2941
void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
2942
{
2943
    ppcemb_tlb_t *tlb;
2944

    
2945
#if defined (DEBUG_SOFTWARE_TLB)
2946
    if (loglevel != 0) {
2947
        fprintf(logfile, "%s entry %i val " ADDRX "\n", __func__, (int)entry, val);
2948
    }
2949
#endif
2950
    entry &= 0x3F;
2951
    tlb = &env->tlb[entry].tlbe;
2952
    tlb->RPN = val & 0xFFFFFC00;
2953
    tlb->prot = PAGE_READ;
2954
    if (val & 0x200)
2955
        tlb->prot |= PAGE_EXEC;
2956
    if (val & 0x100)
2957
        tlb->prot |= PAGE_WRITE;
2958
#if defined (DEBUG_SOFTWARE_TLB)
2959
    if (loglevel != 0) {
2960
        fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
2961
                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
2962
                (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2963
                tlb->prot & PAGE_READ ? 'r' : '-',
2964
                tlb->prot & PAGE_WRITE ? 'w' : '-',
2965
                tlb->prot & PAGE_EXEC ? 'x' : '-',
2966
                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2967
    }
2968
#endif
2969
}
2970

    
2971
target_ulong helper_4xx_tlbsx (target_ulong address)
2972
{
2973
    return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
2974
}
2975

    
2976
/* PowerPC 440 TLB management */
2977
void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
2978
{
2979
    ppcemb_tlb_t *tlb;
2980
    target_ulong EPN, RPN, size;
2981
    int do_flush_tlbs;
2982

    
2983
#if defined (DEBUG_SOFTWARE_TLB)
2984
    if (loglevel != 0) {
2985
        fprintf(logfile, "%s word %d entry %d value " ADDRX "\n",
2986
                __func__, word, (int)entry, value);
2987
    }
2988
#endif
2989
    do_flush_tlbs = 0;
2990
    entry &= 0x3F;
2991
    tlb = &env->tlb[entry].tlbe;
2992
    switch (word) {
2993
    default:
2994
        /* Just here to please gcc */
2995
    case 0:
2996
        EPN = value & 0xFFFFFC00;
2997
        if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
2998
            do_flush_tlbs = 1;
2999
        tlb->EPN = EPN;
3000
        size = booke_tlb_to_page_size((value >> 4) & 0xF);
3001
        if ((tlb->prot & PAGE_VALID) && tlb->size < size)
3002
            do_flush_tlbs = 1;
3003
        tlb->size = size;
3004
        tlb->attr &= ~0x1;
3005
        tlb->attr |= (value >> 8) & 1;
3006
        if (value & 0x200) {
3007
            tlb->prot |= PAGE_VALID;
3008
        } else {
3009
            if (tlb->prot & PAGE_VALID) {
3010
                tlb->prot &= ~PAGE_VALID;
3011
                do_flush_tlbs = 1;
3012
            }
3013
        }
3014
        tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
3015
        if (do_flush_tlbs)
3016
            tlb_flush(env, 1);
3017
        break;
3018
    case 1:
3019
        RPN = value & 0xFFFFFC0F;
3020
        if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
3021
            tlb_flush(env, 1);
3022
        tlb->RPN = RPN;
3023
        break;
3024
    case 2:
3025
        tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
3026
        tlb->prot = tlb->prot & PAGE_VALID;
3027
        if (value & 0x1)
3028
            tlb->prot |= PAGE_READ << 4;
3029
        if (value & 0x2)
3030
            tlb->prot |= PAGE_WRITE << 4;
3031
        if (value & 0x4)
3032
            tlb->prot |= PAGE_EXEC << 4;
3033
        if (value & 0x8)
3034
            tlb->prot |= PAGE_READ;
3035
        if (value & 0x10)
3036
            tlb->prot |= PAGE_WRITE;
3037
        if (value & 0x20)
3038
            tlb->prot |= PAGE_EXEC;
3039
        break;
3040
    }
3041
}
3042

    
3043
target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
3044
{
3045
    ppcemb_tlb_t *tlb;
3046
    target_ulong ret;
3047
    int size;
3048

    
3049
    entry &= 0x3F;
3050
    tlb = &env->tlb[entry].tlbe;
3051
    switch (word) {
3052
    default:
3053
        /* Just here to please gcc */
3054
    case 0:
3055
        ret = tlb->EPN;
3056
        size = booke_page_size_to_tlb(tlb->size);
3057
        if (size < 0 || size > 0xF)
3058
            size = 1;
3059
        ret |= size << 4;
3060
        if (tlb->attr & 0x1)
3061
            ret |= 0x100;
3062
        if (tlb->prot & PAGE_VALID)
3063
            ret |= 0x200;
3064
        env->spr[SPR_440_MMUCR] &= ~0x000000FF;
3065
        env->spr[SPR_440_MMUCR] |= tlb->PID;
3066
        break;
3067
    case 1:
3068
        ret = tlb->RPN;
3069
        break;
3070
    case 2:
3071
        ret = tlb->attr & ~0x1;
3072
        if (tlb->prot & (PAGE_READ << 4))
3073
            ret |= 0x1;
3074
        if (tlb->prot & (PAGE_WRITE << 4))
3075
            ret |= 0x2;
3076
        if (tlb->prot & (PAGE_EXEC << 4))
3077
            ret |= 0x4;
3078
        if (tlb->prot & PAGE_READ)
3079
            ret |= 0x8;
3080
        if (tlb->prot & PAGE_WRITE)
3081
            ret |= 0x10;
3082
        if (tlb->prot & PAGE_EXEC)
3083
            ret |= 0x20;
3084
        break;
3085
    }
3086
    return ret;
3087
}
3088

    
3089
target_ulong helper_440_tlbsx (target_ulong address)
3090
{
3091
    return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
3092
}
3093

    
3094
#endif /* !CONFIG_USER_ONLY */