Statistics
| Branch: | Revision:

root / target-ppc / op_helper.c @ 7872c51c

History | View | Annotate | Download (84.3 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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
562
    u.d = d;
563

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

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

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

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

    
701
static always_inline void float_zero_divide_excp (void)
702
{
703
    env->fpscr |= 1 << FPSCR_ZX;
704
    env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
705
    /* Update the floating-point exception summary */
706
    env->fpscr |= 1 << FPSCR_FX;
707
    if (fpscr_ze != 0) {
708
        /* Update the floating-point enabled exception summary */
709
        env->fpscr |= 1 << FPSCR_FEX;
710
        if (msr_fe0 != 0 || msr_fe1 != 0) {
711
            helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
712
                                       POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
713
        }
714
    }
715
}
716

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

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

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

    
764
static always_inline void fpscr_set_rounding_mode (void)
765
{
766
    int rnd_type;
767

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

    
791
void helper_fpscr_clrbit (uint32_t bit)
792
{
793
    int prev;
794

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

    
809
void helper_fpscr_setbit (uint32_t bit)
810
{
811
    int prev;
812

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

    
924
void helper_store_fpscr (uint64_t arg, uint32_t mask)
925
{
926
    /*
927
     * We use only the 32 LSB of the incoming fpr
928
     */
929
    uint32_t prev, new;
930
    int i;
931

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

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

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

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

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

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

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

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

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

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

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

    
1099
/* fabs */
1100
uint64_t helper_fabs (uint64_t arg)
1101
{
1102
    CPU_DoubleU farg;
1103

    
1104
    farg.ll = arg;
1105
    farg.d = float64_abs(farg.d);
1106
    return farg.ll;
1107
}
1108

    
1109
/* fnabs */
1110
uint64_t helper_fnabs (uint64_t arg)
1111
{
1112
    CPU_DoubleU farg;
1113

    
1114
    farg.ll = arg;
1115
    farg.d = float64_abs(farg.d);
1116
    farg.d = float64_chs(farg.d);
1117
    return farg.ll;
1118
}
1119

    
1120
/* fneg */
1121
uint64_t helper_fneg (uint64_t arg)
1122
{
1123
    CPU_DoubleU farg;
1124

    
1125
    farg.ll = arg;
1126
    farg.d = float64_chs(farg.d);
1127
    return farg.ll;
1128
}
1129

    
1130
/* fctiw - fctiw. */
1131
uint64_t helper_fctiw (uint64_t arg)
1132
{
1133
    CPU_DoubleU farg;
1134
    farg.ll = arg;
1135

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

    
1154
/* fctiwz - fctiwz. */
1155
uint64_t helper_fctiwz (uint64_t arg)
1156
{
1157
    CPU_DoubleU farg;
1158
    farg.ll = arg;
1159

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

    
1178
#if defined(TARGET_PPC64)
1179
/* fcfid - fcfid. */
1180
uint64_t helper_fcfid (uint64_t arg)
1181
{
1182
    CPU_DoubleU farg;
1183
    farg.d = int64_to_float64(arg, &env->fp_status);
1184
    return farg.ll;
1185
}
1186

    
1187
/* fctid - fctid. */
1188
uint64_t helper_fctid (uint64_t arg)
1189
{
1190
    CPU_DoubleU farg;
1191
    farg.ll = arg;
1192

    
1193
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1194
        /* sNaN conversion */
1195
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1196
    } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
1197
        /* qNan / infinity conversion */
1198
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1199
    } else {
1200
        farg.ll = float64_to_int64(farg.d, &env->fp_status);
1201
    }
1202
    return farg.ll;
1203
}
1204

    
1205
/* fctidz - fctidz. */
1206
uint64_t helper_fctidz (uint64_t arg)
1207
{
1208
    CPU_DoubleU farg;
1209
    farg.ll = arg;
1210

    
1211
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1212
        /* sNaN conversion */
1213
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1214
    } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
1215
        /* qNan / infinity conversion */
1216
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1217
    } else {
1218
        farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status);
1219
    }
1220
    return farg.ll;
1221
}
1222

    
1223
#endif
1224

    
1225
static always_inline uint64_t do_fri (uint64_t arg, int rounding_mode)
1226
{
1227
    CPU_DoubleU farg;
1228
    farg.ll = arg;
1229

    
1230
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1231
        /* sNaN round */
1232
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1233
    } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
1234
        /* qNan / infinity round */
1235
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1236
    } else {
1237
        set_float_rounding_mode(rounding_mode, &env->fp_status);
1238
        farg.ll = float64_round_to_int(farg.d, &env->fp_status);
1239
        /* Restore rounding mode from FPSCR */
1240
        fpscr_set_rounding_mode();
1241
    }
1242
    return farg.ll;
1243
}
1244

    
1245
uint64_t helper_frin (uint64_t arg)
1246
{
1247
    return do_fri(arg, float_round_nearest_even);
1248
}
1249

    
1250
uint64_t helper_friz (uint64_t arg)
1251
{
1252
    return do_fri(arg, float_round_to_zero);
1253
}
1254

    
1255
uint64_t helper_frip (uint64_t arg)
1256
{
1257
    return do_fri(arg, float_round_up);
1258
}
1259

    
1260
uint64_t helper_frim (uint64_t arg)
1261
{
1262
    return do_fri(arg, float_round_down);
1263
}
1264

    
1265
/* fmadd - fmadd. */
1266
uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1267
{
1268
    CPU_DoubleU farg1, farg2, farg3;
1269

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

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

    
1312
/* fmsub - fmsub. */
1313
uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1314
{
1315
    CPU_DoubleU farg1, farg2, farg3;
1316

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

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

    
1359
/* fnmadd - fnmadd. */
1360
uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1361
{
1362
    CPU_DoubleU farg1, farg2, farg3;
1363

    
1364
    farg1.ll = arg1;
1365
    farg2.ll = arg2;
1366
    farg3.ll = arg3;
1367

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

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

    
1409
/* fnmsub - fnmsub. */
1410
uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1411
{
1412
    CPU_DoubleU farg1, farg2, farg3;
1413

    
1414
    farg1.ll = arg1;
1415
    farg2.ll = arg2;
1416
    farg3.ll = arg3;
1417

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

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

    
1459
/* frsp - frsp. */
1460
uint64_t helper_frsp (uint64_t arg)
1461
{
1462
    CPU_DoubleU farg;
1463
    float32 f32;
1464
    farg.ll = arg;
1465

    
1466
#if USE_PRECISE_EMULATION
1467
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1468
        /* sNaN square root */
1469
       farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1470
    } else {
1471
       f32 = float64_to_float32(farg.d, &env->fp_status);
1472
       farg.d = float32_to_float64(f32, &env->fp_status);
1473
    }
1474
#else
1475
    f32 = float64_to_float32(farg.d, &env->fp_status);
1476
    farg.d = float32_to_float64(f32, &env->fp_status);
1477
#endif
1478
    return farg.ll;
1479
}
1480

    
1481
/* fsqrt - fsqrt. */
1482
uint64_t helper_fsqrt (uint64_t arg)
1483
{
1484
    CPU_DoubleU farg;
1485
    farg.ll = arg;
1486

    
1487
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1488
        /* sNaN square root */
1489
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1490
    } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
1491
        /* Square root of a negative nonzero number */
1492
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
1493
    } else {
1494
        farg.d = float64_sqrt(farg.d, &env->fp_status);
1495
    }
1496
    return farg.ll;
1497
}
1498

    
1499
/* fre - fre. */
1500
uint64_t helper_fre (uint64_t arg)
1501
{
1502
    CPU_DoubleU fone, farg;
1503
    fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
1504
    farg.ll = arg;
1505

    
1506
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1507
        /* sNaN reciprocal */
1508
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1509
    } else {
1510
        farg.d = float64_div(fone.d, farg.d, &env->fp_status);
1511
    }
1512
    return farg.d;
1513
}
1514

    
1515
/* fres - fres. */
1516
uint64_t helper_fres (uint64_t arg)
1517
{
1518
    CPU_DoubleU fone, farg;
1519
    float32 f32;
1520
    fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
1521
    farg.ll = arg;
1522

    
1523
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1524
        /* sNaN reciprocal */
1525
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1526
    } else {
1527
        farg.d = float64_div(fone.d, farg.d, &env->fp_status);
1528
        f32 = float64_to_float32(farg.d, &env->fp_status);
1529
        farg.d = float32_to_float64(f32, &env->fp_status);
1530
    }
1531
    return farg.ll;
1532
}
1533

    
1534
/* frsqrte  - frsqrte. */
1535
uint64_t helper_frsqrte (uint64_t arg)
1536
{
1537
    CPU_DoubleU fone, farg;
1538
    float32 f32;
1539
    fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
1540
    farg.ll = arg;
1541

    
1542
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1543
        /* sNaN reciprocal square root */
1544
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1545
    } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
1546
        /* Reciprocal square root of a negative nonzero number */
1547
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
1548
    } else {
1549
        farg.d = float64_sqrt(farg.d, &env->fp_status);
1550
        farg.d = float64_div(fone.d, farg.d, &env->fp_status);
1551
        f32 = float64_to_float32(farg.d, &env->fp_status);
1552
        farg.d = float32_to_float64(f32, &env->fp_status);
1553
    }
1554
    return farg.ll;
1555
}
1556

    
1557
/* fsel - fsel. */
1558
uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1559
{
1560
    CPU_DoubleU farg1;
1561

    
1562
    farg1.ll = arg1;
1563

    
1564
    if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_nan(farg1.d))
1565
        return arg2;
1566
    else
1567
        return arg3;
1568
}
1569

    
1570
void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD)
1571
{
1572
    CPU_DoubleU farg1, farg2;
1573
    uint32_t ret = 0;
1574
    farg1.ll = arg1;
1575
    farg2.ll = arg2;
1576

    
1577
    if (unlikely(float64_is_nan(farg1.d) ||
1578
                 float64_is_nan(farg2.d))) {
1579
        ret = 0x01UL;
1580
    } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1581
        ret = 0x08UL;
1582
    } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1583
        ret = 0x04UL;
1584
    } else {
1585
        ret = 0x02UL;
1586
    }
1587

    
1588
    env->fpscr &= ~(0x0F << FPSCR_FPRF);
1589
    env->fpscr |= ret << FPSCR_FPRF;
1590
    env->crf[crfD] = ret;
1591
    if (unlikely(ret == 0x01UL
1592
                 && (float64_is_signaling_nan(farg1.d) ||
1593
                     float64_is_signaling_nan(farg2.d)))) {
1594
        /* sNaN comparison */
1595
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1596
    }
1597
}
1598

    
1599
void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD)
1600
{
1601
    CPU_DoubleU farg1, farg2;
1602
    uint32_t ret = 0;
1603
    farg1.ll = arg1;
1604
    farg2.ll = arg2;
1605

    
1606
    if (unlikely(float64_is_nan(farg1.d) ||
1607
                 float64_is_nan(farg2.d))) {
1608
        ret = 0x01UL;
1609
    } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1610
        ret = 0x08UL;
1611
    } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1612
        ret = 0x04UL;
1613
    } else {
1614
        ret = 0x02UL;
1615
    }
1616

    
1617
    env->fpscr &= ~(0x0F << FPSCR_FPRF);
1618
    env->fpscr |= ret << FPSCR_FPRF;
1619
    env->crf[crfD] = ret;
1620
    if (unlikely (ret == 0x01UL)) {
1621
        if (float64_is_signaling_nan(farg1.d) ||
1622
            float64_is_signaling_nan(farg2.d)) {
1623
            /* sNaN comparison */
1624
            fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
1625
                                  POWERPC_EXCP_FP_VXVC);
1626
        } else {
1627
            /* qNaN comparison */
1628
            fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
1629
        }
1630
    }
1631
}
1632

    
1633
#if !defined (CONFIG_USER_ONLY)
1634
void helper_store_msr (target_ulong val)
1635
{
1636
    val = hreg_store_msr(env, val, 0);
1637
    if (val != 0) {
1638
        env->interrupt_request |= CPU_INTERRUPT_EXITTB;
1639
        helper_raise_exception(val);
1640
    }
1641
}
1642

    
1643
static always_inline void do_rfi (target_ulong nip, target_ulong msr,
1644
                                    target_ulong msrm, int keep_msrh)
1645
{
1646
#if defined(TARGET_PPC64)
1647
    if (msr & (1ULL << MSR_SF)) {
1648
        nip = (uint64_t)nip;
1649
        msr &= (uint64_t)msrm;
1650
    } else {
1651
        nip = (uint32_t)nip;
1652
        msr = (uint32_t)(msr & msrm);
1653
        if (keep_msrh)
1654
            msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
1655
    }
1656
#else
1657
    nip = (uint32_t)nip;
1658
    msr &= (uint32_t)msrm;
1659
#endif
1660
    /* XXX: beware: this is false if VLE is supported */
1661
    env->nip = nip & ~((target_ulong)0x00000003);
1662
    hreg_store_msr(env, msr, 1);
1663
#if defined (DEBUG_OP)
1664
    cpu_dump_rfi(env->nip, env->msr);
1665
#endif
1666
    /* No need to raise an exception here,
1667
     * as rfi is always the last insn of a TB
1668
     */
1669
    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
1670
}
1671

    
1672
void helper_rfi (void)
1673
{
1674
    do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1675
           ~((target_ulong)0xFFFF0000), 1);
1676
}
1677

    
1678
#if defined(TARGET_PPC64)
1679
void helper_rfid (void)
1680
{
1681
    do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1682
           ~((target_ulong)0xFFFF0000), 0);
1683
}
1684

    
1685
void helper_hrfid (void)
1686
{
1687
    do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
1688
           ~((target_ulong)0xFFFF0000), 0);
1689
}
1690
#endif
1691
#endif
1692

    
1693
void helper_tw (target_ulong arg1, target_ulong arg2, uint32_t flags)
1694
{
1695
    if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
1696
                  ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
1697
                  ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
1698
                  ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
1699
                  ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
1700
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
1701
    }
1702
}
1703

    
1704
#if defined(TARGET_PPC64)
1705
void helper_td (target_ulong arg1, target_ulong arg2, uint32_t flags)
1706
{
1707
    if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
1708
                  ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
1709
                  ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
1710
                  ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
1711
                  ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01)))))
1712
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
1713
}
1714
#endif
1715

    
1716
/*****************************************************************************/
1717
/* PowerPC 601 specific instructions (POWER bridge) */
1718

    
1719
target_ulong helper_clcs (uint32_t arg)
1720
{
1721
    switch (arg) {
1722
    case 0x0CUL:
1723
        /* Instruction cache line size */
1724
        return env->icache_line_size;
1725
        break;
1726
    case 0x0DUL:
1727
        /* Data cache line size */
1728
        return env->dcache_line_size;
1729
        break;
1730
    case 0x0EUL:
1731
        /* Minimum cache line size */
1732
        return (env->icache_line_size < env->dcache_line_size) ?
1733
                env->icache_line_size : env->dcache_line_size;
1734
        break;
1735
    case 0x0FUL:
1736
        /* Maximum cache line size */
1737
        return (env->icache_line_size > env->dcache_line_size) ?
1738
                env->icache_line_size : env->dcache_line_size;
1739
        break;
1740
    default:
1741
        /* Undefined */
1742
        return 0;
1743
        break;
1744
    }
1745
}
1746

    
1747
target_ulong helper_div (target_ulong arg1, target_ulong arg2)
1748
{
1749
    uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
1750

    
1751
    if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1752
        (int32_t)arg2 == 0) {
1753
        env->spr[SPR_MQ] = 0;
1754
        return INT32_MIN;
1755
    } else {
1756
        env->spr[SPR_MQ] = tmp % arg2;
1757
        return  tmp / (int32_t)arg2;
1758
    }
1759
}
1760

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

    
1765
    if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1766
        (int32_t)arg2 == 0) {
1767
        env->xer |= (1 << XER_OV) | (1 << XER_SO);
1768
        env->spr[SPR_MQ] = 0;
1769
        return INT32_MIN;
1770
    } else {
1771
        env->spr[SPR_MQ] = tmp % arg2;
1772
        tmp /= (int32_t)arg2;
1773
        if ((int32_t)tmp != tmp) {
1774
            env->xer |= (1 << XER_OV) | (1 << XER_SO);
1775
        } else {
1776
            env->xer &= ~(1 << XER_OV);
1777
        }
1778
        return tmp;
1779
    }
1780
}
1781

    
1782
target_ulong helper_divs (target_ulong arg1, target_ulong arg2)
1783
{
1784
    if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1785
        (int32_t)arg2 == 0) {
1786
        env->spr[SPR_MQ] = 0;
1787
        return INT32_MIN;
1788
    } else {
1789
        env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1790
        return (int32_t)arg1 / (int32_t)arg2;
1791
    }
1792
}
1793

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

    
1808
#if !defined (CONFIG_USER_ONLY)
1809
target_ulong helper_rac (target_ulong addr)
1810
{
1811
    mmu_ctx_t ctx;
1812
    int nb_BATs;
1813
    target_ulong ret = 0;
1814

    
1815
    /* We don't have to generate many instances of this instruction,
1816
     * as rac is supervisor only.
1817
     */
1818
    /* XXX: FIX THIS: Pretend we have no BAT */
1819
    nb_BATs = env->nb_BATs;
1820
    env->nb_BATs = 0;
1821
    if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0)
1822
        ret = ctx.raddr;
1823
    env->nb_BATs = nb_BATs;
1824
    return ret;
1825
}
1826

    
1827
void helper_rfsvc (void)
1828
{
1829
    do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
1830
}
1831
#endif
1832

    
1833
/*****************************************************************************/
1834
/* 602 specific instructions */
1835
/* mfrom is the most crazy instruction ever seen, imho ! */
1836
/* Real implementation uses a ROM table. Do the same */
1837
/* Extremly decomposed:
1838
 *                      -arg / 256
1839
 * return 256 * log10(10           + 1.0) + 0.5
1840
 */
1841
#if !defined (CONFIG_USER_ONLY)
1842
target_ulong helper_602_mfrom (target_ulong arg)
1843
{
1844
    if (likely(arg < 602)) {
1845
#include "mfrom_table.c"
1846
        return mfrom_ROM_table[arg];
1847
    } else {
1848
        return 0;
1849
    }
1850
}
1851
#endif
1852

    
1853
/*****************************************************************************/
1854
/* Embedded PowerPC specific helpers */
1855

    
1856
/* XXX: to be improved to check access rights when in user-mode */
1857
target_ulong helper_load_dcr (target_ulong dcrn)
1858
{
1859
    target_ulong val = 0;
1860

    
1861
    if (unlikely(env->dcr_env == NULL)) {
1862
        if (loglevel != 0) {
1863
            fprintf(logfile, "No DCR environment\n");
1864
        }
1865
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1866
                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
1867
    } else if (unlikely(ppc_dcr_read(env->dcr_env, dcrn, &val) != 0)) {
1868
        if (loglevel != 0) {
1869
            fprintf(logfile, "DCR read error %d %03x\n", (int)dcrn, (int)dcrn);
1870
        }
1871
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1872
                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1873
    }
1874
    return val;
1875
}
1876

    
1877
void helper_store_dcr (target_ulong dcrn, target_ulong val)
1878
{
1879
    if (unlikely(env->dcr_env == NULL)) {
1880
        if (loglevel != 0) {
1881
            fprintf(logfile, "No DCR environment\n");
1882
        }
1883
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1884
                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
1885
    } else if (unlikely(ppc_dcr_write(env->dcr_env, dcrn, val) != 0)) {
1886
        if (loglevel != 0) {
1887
            fprintf(logfile, "DCR write error %d %03x\n", (int)dcrn, (int)dcrn);
1888
        }
1889
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1890
                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1891
    }
1892
}
1893

    
1894
#if !defined(CONFIG_USER_ONLY)
1895
void helper_40x_rfci (void)
1896
{
1897
    do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
1898
           ~((target_ulong)0xFFFF0000), 0);
1899
}
1900

    
1901
void helper_rfci (void)
1902
{
1903
    do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
1904
           ~((target_ulong)0x3FFF0000), 0);
1905
}
1906

    
1907
void helper_rfdi (void)
1908
{
1909
    do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
1910
           ~((target_ulong)0x3FFF0000), 0);
1911
}
1912

    
1913
void helper_rfmci (void)
1914
{
1915
    do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
1916
           ~((target_ulong)0x3FFF0000), 0);
1917
}
1918
#endif
1919

    
1920
/* 440 specific */
1921
target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_Rc)
1922
{
1923
    target_ulong mask;
1924
    int i;
1925

    
1926
    i = 1;
1927
    for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1928
        if ((high & mask) == 0) {
1929
            if (update_Rc) {
1930
                env->crf[0] = 0x4;
1931
            }
1932
            goto done;
1933
        }
1934
        i++;
1935
    }
1936
    for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1937
        if ((low & mask) == 0) {
1938
            if (update_Rc) {
1939
                env->crf[0] = 0x8;
1940
            }
1941
            goto done;
1942
        }
1943
        i++;
1944
    }
1945
    if (update_Rc) {
1946
        env->crf[0] = 0x2;
1947
    }
1948
 done:
1949
    env->xer = (env->xer & ~0x7F) | i;
1950
    if (update_Rc) {
1951
        env->crf[0] |= xer_so;
1952
    }
1953
    return i;
1954
}
1955

    
1956
/*****************************************************************************/
1957
/* Altivec extension helpers */
1958
#if defined(WORDS_BIGENDIAN)
1959
#define HI_IDX 0
1960
#define LO_IDX 1
1961
#else
1962
#define HI_IDX 1
1963
#define LO_IDX 0
1964
#endif
1965

    
1966
#if defined(WORDS_BIGENDIAN)
1967
#define VECTOR_FOR_INORDER_I(index, element)            \
1968
    for (index = 0; index < ARRAY_SIZE(r->element); index++)
1969
#else
1970
#define VECTOR_FOR_INORDER_I(index, element)            \
1971
  for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
1972
#endif
1973

    
1974
#define VARITH_DO(name, op, element)        \
1975
void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)          \
1976
{                                                                       \
1977
    int i;                                                              \
1978
    for (i = 0; i < ARRAY_SIZE(r->element); i++) {                      \
1979
        r->element[i] = a->element[i] op b->element[i];                 \
1980
    }                                                                   \
1981
}
1982
#define VARITH(suffix, element)                  \
1983
  VARITH_DO(add##suffix, +, element)             \
1984
  VARITH_DO(sub##suffix, -, element)
1985
VARITH(ubm, u8)
1986
VARITH(uhm, u16)
1987
VARITH(uwm, u32)
1988
#undef VARITH_DO
1989
#undef VARITH
1990

    
1991
#undef VECTOR_FOR_INORDER_I
1992
#undef HI_IDX
1993
#undef LO_IDX
1994

    
1995
/*****************************************************************************/
1996
/* SPE extension helpers */
1997
/* Use a table to make this quicker */
1998
static uint8_t hbrev[16] = {
1999
    0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
2000
    0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
2001
};
2002

    
2003
static always_inline uint8_t byte_reverse (uint8_t val)
2004
{
2005
    return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
2006
}
2007

    
2008
static always_inline uint32_t word_reverse (uint32_t val)
2009
{
2010
    return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
2011
        (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
2012
}
2013

    
2014
#define MASKBITS 16 // Random value - to be fixed (implementation dependant)
2015
target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
2016
{
2017
    uint32_t a, b, d, mask;
2018

    
2019
    mask = UINT32_MAX >> (32 - MASKBITS);
2020
    a = arg1 & mask;
2021
    b = arg2 & mask;
2022
    d = word_reverse(1 + word_reverse(a | ~b));
2023
    return (arg1 & ~mask) | (d & b);
2024
}
2025

    
2026
uint32_t helper_cntlsw32 (uint32_t val)
2027
{
2028
    if (val & 0x80000000)
2029
        return clz32(~val);
2030
    else
2031
        return clz32(val);
2032
}
2033

    
2034
uint32_t helper_cntlzw32 (uint32_t val)
2035
{
2036
    return clz32(val);
2037
}
2038

    
2039
/* Single-precision floating-point conversions */
2040
static always_inline uint32_t efscfsi (uint32_t val)
2041
{
2042
    CPU_FloatU u;
2043

    
2044
    u.f = int32_to_float32(val, &env->spe_status);
2045

    
2046
    return u.l;
2047
}
2048

    
2049
static always_inline uint32_t efscfui (uint32_t val)
2050
{
2051
    CPU_FloatU u;
2052

    
2053
    u.f = uint32_to_float32(val, &env->spe_status);
2054

    
2055
    return u.l;
2056
}
2057

    
2058
static always_inline int32_t efsctsi (uint32_t val)
2059
{
2060
    CPU_FloatU u;
2061

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

    
2067
    return float32_to_int32(u.f, &env->spe_status);
2068
}
2069

    
2070
static always_inline uint32_t efsctui (uint32_t val)
2071
{
2072
    CPU_FloatU u;
2073

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

    
2079
    return float32_to_uint32(u.f, &env->spe_status);
2080
}
2081

    
2082
static always_inline uint32_t efsctsiz (uint32_t val)
2083
{
2084
    CPU_FloatU u;
2085

    
2086
    u.l = val;
2087
    /* NaN are not treated the same way IEEE 754 does */
2088
    if (unlikely(float32_is_nan(u.f)))
2089
        return 0;
2090

    
2091
    return float32_to_int32_round_to_zero(u.f, &env->spe_status);
2092
}
2093

    
2094
static always_inline uint32_t efsctuiz (uint32_t val)
2095
{
2096
    CPU_FloatU u;
2097

    
2098
    u.l = val;
2099
    /* NaN are not treated the same way IEEE 754 does */
2100
    if (unlikely(float32_is_nan(u.f)))
2101
        return 0;
2102

    
2103
    return float32_to_uint32_round_to_zero(u.f, &env->spe_status);
2104
}
2105

    
2106
static always_inline uint32_t efscfsf (uint32_t val)
2107
{
2108
    CPU_FloatU u;
2109
    float32 tmp;
2110

    
2111
    u.f = int32_to_float32(val, &env->spe_status);
2112
    tmp = int64_to_float32(1ULL << 32, &env->spe_status);
2113
    u.f = float32_div(u.f, tmp, &env->spe_status);
2114

    
2115
    return u.l;
2116
}
2117

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

    
2123
    u.f = uint32_to_float32(val, &env->spe_status);
2124
    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2125
    u.f = float32_div(u.f, tmp, &env->spe_status);
2126

    
2127
    return u.l;
2128
}
2129

    
2130
static always_inline uint32_t efsctsf (uint32_t val)
2131
{
2132
    CPU_FloatU u;
2133
    float32 tmp;
2134

    
2135
    u.l = val;
2136
    /* NaN are not treated the same way IEEE 754 does */
2137
    if (unlikely(float32_is_nan(u.f)))
2138
        return 0;
2139
    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2140
    u.f = float32_mul(u.f, tmp, &env->spe_status);
2141

    
2142
    return float32_to_int32(u.f, &env->spe_status);
2143
}
2144

    
2145
static always_inline uint32_t efsctuf (uint32_t val)
2146
{
2147
    CPU_FloatU u;
2148
    float32 tmp;
2149

    
2150
    u.l = val;
2151
    /* NaN are not treated the same way IEEE 754 does */
2152
    if (unlikely(float32_is_nan(u.f)))
2153
        return 0;
2154
    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2155
    u.f = float32_mul(u.f, tmp, &env->spe_status);
2156

    
2157
    return float32_to_uint32(u.f, &env->spe_status);
2158
}
2159

    
2160
#define HELPER_SPE_SINGLE_CONV(name)                                          \
2161
uint32_t helper_e##name (uint32_t val)                                        \
2162
{                                                                             \
2163
    return e##name(val);                                                      \
2164
}
2165
/* efscfsi */
2166
HELPER_SPE_SINGLE_CONV(fscfsi);
2167
/* efscfui */
2168
HELPER_SPE_SINGLE_CONV(fscfui);
2169
/* efscfuf */
2170
HELPER_SPE_SINGLE_CONV(fscfuf);
2171
/* efscfsf */
2172
HELPER_SPE_SINGLE_CONV(fscfsf);
2173
/* efsctsi */
2174
HELPER_SPE_SINGLE_CONV(fsctsi);
2175
/* efsctui */
2176
HELPER_SPE_SINGLE_CONV(fsctui);
2177
/* efsctsiz */
2178
HELPER_SPE_SINGLE_CONV(fsctsiz);
2179
/* efsctuiz */
2180
HELPER_SPE_SINGLE_CONV(fsctuiz);
2181
/* efsctsf */
2182
HELPER_SPE_SINGLE_CONV(fsctsf);
2183
/* efsctuf */
2184
HELPER_SPE_SINGLE_CONV(fsctuf);
2185

    
2186
#define HELPER_SPE_VECTOR_CONV(name)                                          \
2187
uint64_t helper_ev##name (uint64_t val)                                       \
2188
{                                                                             \
2189
    return ((uint64_t)e##name(val >> 32) << 32) |                             \
2190
            (uint64_t)e##name(val);                                           \
2191
}
2192
/* evfscfsi */
2193
HELPER_SPE_VECTOR_CONV(fscfsi);
2194
/* evfscfui */
2195
HELPER_SPE_VECTOR_CONV(fscfui);
2196
/* evfscfuf */
2197
HELPER_SPE_VECTOR_CONV(fscfuf);
2198
/* evfscfsf */
2199
HELPER_SPE_VECTOR_CONV(fscfsf);
2200
/* evfsctsi */
2201
HELPER_SPE_VECTOR_CONV(fsctsi);
2202
/* evfsctui */
2203
HELPER_SPE_VECTOR_CONV(fsctui);
2204
/* evfsctsiz */
2205
HELPER_SPE_VECTOR_CONV(fsctsiz);
2206
/* evfsctuiz */
2207
HELPER_SPE_VECTOR_CONV(fsctuiz);
2208
/* evfsctsf */
2209
HELPER_SPE_VECTOR_CONV(fsctsf);
2210
/* evfsctuf */
2211
HELPER_SPE_VECTOR_CONV(fsctuf);
2212

    
2213
/* Single-precision floating-point arithmetic */
2214
static always_inline uint32_t efsadd (uint32_t op1, uint32_t op2)
2215
{
2216
    CPU_FloatU u1, u2;
2217
    u1.l = op1;
2218
    u2.l = op2;
2219
    u1.f = float32_add(u1.f, u2.f, &env->spe_status);
2220
    return u1.l;
2221
}
2222

    
2223
static always_inline uint32_t efssub (uint32_t op1, uint32_t op2)
2224
{
2225
    CPU_FloatU u1, u2;
2226
    u1.l = op1;
2227
    u2.l = op2;
2228
    u1.f = float32_sub(u1.f, u2.f, &env->spe_status);
2229
    return u1.l;
2230
}
2231

    
2232
static always_inline uint32_t efsmul (uint32_t op1, uint32_t op2)
2233
{
2234
    CPU_FloatU u1, u2;
2235
    u1.l = op1;
2236
    u2.l = op2;
2237
    u1.f = float32_mul(u1.f, u2.f, &env->spe_status);
2238
    return u1.l;
2239
}
2240

    
2241
static always_inline uint32_t efsdiv (uint32_t op1, uint32_t op2)
2242
{
2243
    CPU_FloatU u1, u2;
2244
    u1.l = op1;
2245
    u2.l = op2;
2246
    u1.f = float32_div(u1.f, u2.f, &env->spe_status);
2247
    return u1.l;
2248
}
2249

    
2250
#define HELPER_SPE_SINGLE_ARITH(name)                                         \
2251
uint32_t helper_e##name (uint32_t op1, uint32_t op2)                          \
2252
{                                                                             \
2253
    return e##name(op1, op2);                                                 \
2254
}
2255
/* efsadd */
2256
HELPER_SPE_SINGLE_ARITH(fsadd);
2257
/* efssub */
2258
HELPER_SPE_SINGLE_ARITH(fssub);
2259
/* efsmul */
2260
HELPER_SPE_SINGLE_ARITH(fsmul);
2261
/* efsdiv */
2262
HELPER_SPE_SINGLE_ARITH(fsdiv);
2263

    
2264
#define HELPER_SPE_VECTOR_ARITH(name)                                         \
2265
uint64_t helper_ev##name (uint64_t op1, uint64_t op2)                         \
2266
{                                                                             \
2267
    return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) |                  \
2268
            (uint64_t)e##name(op1, op2);                                      \
2269
}
2270
/* evfsadd */
2271
HELPER_SPE_VECTOR_ARITH(fsadd);
2272
/* evfssub */
2273
HELPER_SPE_VECTOR_ARITH(fssub);
2274
/* evfsmul */
2275
HELPER_SPE_VECTOR_ARITH(fsmul);
2276
/* evfsdiv */
2277
HELPER_SPE_VECTOR_ARITH(fsdiv);
2278

    
2279
/* Single-precision floating-point comparisons */
2280
static always_inline uint32_t efststlt (uint32_t op1, uint32_t op2)
2281
{
2282
    CPU_FloatU u1, u2;
2283
    u1.l = op1;
2284
    u2.l = op2;
2285
    return float32_lt(u1.f, u2.f, &env->spe_status) ? 4 : 0;
2286
}
2287

    
2288
static always_inline uint32_t efststgt (uint32_t op1, uint32_t op2)
2289
{
2290
    CPU_FloatU u1, u2;
2291
    u1.l = op1;
2292
    u2.l = op2;
2293
    return float32_le(u1.f, u2.f, &env->spe_status) ? 0 : 4;
2294
}
2295

    
2296
static always_inline uint32_t efststeq (uint32_t op1, uint32_t op2)
2297
{
2298
    CPU_FloatU u1, u2;
2299
    u1.l = op1;
2300
    u2.l = op2;
2301
    return float32_eq(u1.f, u2.f, &env->spe_status) ? 4 : 0;
2302
}
2303

    
2304
static always_inline uint32_t efscmplt (uint32_t op1, uint32_t op2)
2305
{
2306
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2307
    return efststlt(op1, op2);
2308
}
2309

    
2310
static always_inline uint32_t efscmpgt (uint32_t op1, uint32_t op2)
2311
{
2312
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2313
    return efststgt(op1, op2);
2314
}
2315

    
2316
static always_inline uint32_t efscmpeq (uint32_t op1, uint32_t op2)
2317
{
2318
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2319
    return efststeq(op1, op2);
2320
}
2321

    
2322
#define HELPER_SINGLE_SPE_CMP(name)                                           \
2323
uint32_t helper_e##name (uint32_t op1, uint32_t op2)                          \
2324
{                                                                             \
2325
    return e##name(op1, op2) << 2;                                            \
2326
}
2327
/* efststlt */
2328
HELPER_SINGLE_SPE_CMP(fststlt);
2329
/* efststgt */
2330
HELPER_SINGLE_SPE_CMP(fststgt);
2331
/* efststeq */
2332
HELPER_SINGLE_SPE_CMP(fststeq);
2333
/* efscmplt */
2334
HELPER_SINGLE_SPE_CMP(fscmplt);
2335
/* efscmpgt */
2336
HELPER_SINGLE_SPE_CMP(fscmpgt);
2337
/* efscmpeq */
2338
HELPER_SINGLE_SPE_CMP(fscmpeq);
2339

    
2340
static always_inline uint32_t evcmp_merge (int t0, int t1)
2341
{
2342
    return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
2343
}
2344

    
2345
#define HELPER_VECTOR_SPE_CMP(name)                                           \
2346
uint32_t helper_ev##name (uint64_t op1, uint64_t op2)                         \
2347
{                                                                             \
2348
    return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2));     \
2349
}
2350
/* evfststlt */
2351
HELPER_VECTOR_SPE_CMP(fststlt);
2352
/* evfststgt */
2353
HELPER_VECTOR_SPE_CMP(fststgt);
2354
/* evfststeq */
2355
HELPER_VECTOR_SPE_CMP(fststeq);
2356
/* evfscmplt */
2357
HELPER_VECTOR_SPE_CMP(fscmplt);
2358
/* evfscmpgt */
2359
HELPER_VECTOR_SPE_CMP(fscmpgt);
2360
/* evfscmpeq */
2361
HELPER_VECTOR_SPE_CMP(fscmpeq);
2362

    
2363
/* Double-precision floating-point conversion */
2364
uint64_t helper_efdcfsi (uint32_t val)
2365
{
2366
    CPU_DoubleU u;
2367

    
2368
    u.d = int32_to_float64(val, &env->spe_status);
2369

    
2370
    return u.ll;
2371
}
2372

    
2373
uint64_t helper_efdcfsid (uint64_t val)
2374
{
2375
    CPU_DoubleU u;
2376

    
2377
    u.d = int64_to_float64(val, &env->spe_status);
2378

    
2379
    return u.ll;
2380
}
2381

    
2382
uint64_t helper_efdcfui (uint32_t val)
2383
{
2384
    CPU_DoubleU u;
2385

    
2386
    u.d = uint32_to_float64(val, &env->spe_status);
2387

    
2388
    return u.ll;
2389
}
2390

    
2391
uint64_t helper_efdcfuid (uint64_t val)
2392
{
2393
    CPU_DoubleU u;
2394

    
2395
    u.d = uint64_to_float64(val, &env->spe_status);
2396

    
2397
    return u.ll;
2398
}
2399

    
2400
uint32_t helper_efdctsi (uint64_t val)
2401
{
2402
    CPU_DoubleU u;
2403

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

    
2409
    return float64_to_int32(u.d, &env->spe_status);
2410
}
2411

    
2412
uint32_t helper_efdctui (uint64_t val)
2413
{
2414
    CPU_DoubleU u;
2415

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

    
2421
    return float64_to_uint32(u.d, &env->spe_status);
2422
}
2423

    
2424
uint32_t helper_efdctsiz (uint64_t val)
2425
{
2426
    CPU_DoubleU u;
2427

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

    
2433
    return float64_to_int32_round_to_zero(u.d, &env->spe_status);
2434
}
2435

    
2436
uint64_t helper_efdctsidz (uint64_t val)
2437
{
2438
    CPU_DoubleU u;
2439

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

    
2445
    return float64_to_int64_round_to_zero(u.d, &env->spe_status);
2446
}
2447

    
2448
uint32_t helper_efdctuiz (uint64_t val)
2449
{
2450
    CPU_DoubleU u;
2451

    
2452
    u.ll = val;
2453
    /* NaN are not treated the same way IEEE 754 does */
2454
    if (unlikely(float64_is_nan(u.d)))
2455
        return 0;
2456

    
2457
    return float64_to_uint32_round_to_zero(u.d, &env->spe_status);
2458
}
2459

    
2460
uint64_t helper_efdctuidz (uint64_t val)
2461
{
2462
    CPU_DoubleU u;
2463

    
2464
    u.ll = val;
2465
    /* NaN are not treated the same way IEEE 754 does */
2466
    if (unlikely(float64_is_nan(u.d)))
2467
        return 0;
2468

    
2469
    return float64_to_uint64_round_to_zero(u.d, &env->spe_status);
2470
}
2471

    
2472
uint64_t helper_efdcfsf (uint32_t val)
2473
{
2474
    CPU_DoubleU u;
2475
    float64 tmp;
2476

    
2477
    u.d = int32_to_float64(val, &env->spe_status);
2478
    tmp = int64_to_float64(1ULL << 32, &env->spe_status);
2479
    u.d = float64_div(u.d, tmp, &env->spe_status);
2480

    
2481
    return u.ll;
2482
}
2483

    
2484
uint64_t helper_efdcfuf (uint32_t val)
2485
{
2486
    CPU_DoubleU u;
2487
    float64 tmp;
2488

    
2489
    u.d = uint32_to_float64(val, &env->spe_status);
2490
    tmp = int64_to_float64(1ULL << 32, &env->spe_status);
2491
    u.d = float64_div(u.d, tmp, &env->spe_status);
2492

    
2493
    return u.ll;
2494
}
2495

    
2496
uint32_t helper_efdctsf (uint64_t val)
2497
{
2498
    CPU_DoubleU u;
2499
    float64 tmp;
2500

    
2501
    u.ll = val;
2502
    /* NaN are not treated the same way IEEE 754 does */
2503
    if (unlikely(float64_is_nan(u.d)))
2504
        return 0;
2505
    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
2506
    u.d = float64_mul(u.d, tmp, &env->spe_status);
2507

    
2508
    return float64_to_int32(u.d, &env->spe_status);
2509
}
2510

    
2511
uint32_t helper_efdctuf (uint64_t val)
2512
{
2513
    CPU_DoubleU u;
2514
    float64 tmp;
2515

    
2516
    u.ll = val;
2517
    /* NaN are not treated the same way IEEE 754 does */
2518
    if (unlikely(float64_is_nan(u.d)))
2519
        return 0;
2520
    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
2521
    u.d = float64_mul(u.d, tmp, &env->spe_status);
2522

    
2523
    return float64_to_uint32(u.d, &env->spe_status);
2524
}
2525

    
2526
uint32_t helper_efscfd (uint64_t val)
2527
{
2528
    CPU_DoubleU u1;
2529
    CPU_FloatU u2;
2530

    
2531
    u1.ll = val;
2532
    u2.f = float64_to_float32(u1.d, &env->spe_status);
2533

    
2534
    return u2.l;
2535
}
2536

    
2537
uint64_t helper_efdcfs (uint32_t val)
2538
{
2539
    CPU_DoubleU u2;
2540
    CPU_FloatU u1;
2541

    
2542
    u1.l = val;
2543
    u2.d = float32_to_float64(u1.f, &env->spe_status);
2544

    
2545
    return u2.ll;
2546
}
2547

    
2548
/* Double precision fixed-point arithmetic */
2549
uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
2550
{
2551
    CPU_DoubleU u1, u2;
2552
    u1.ll = op1;
2553
    u2.ll = op2;
2554
    u1.d = float64_add(u1.d, u2.d, &env->spe_status);
2555
    return u1.ll;
2556
}
2557

    
2558
uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
2559
{
2560
    CPU_DoubleU u1, u2;
2561
    u1.ll = op1;
2562
    u2.ll = op2;
2563
    u1.d = float64_sub(u1.d, u2.d, &env->spe_status);
2564
    return u1.ll;
2565
}
2566

    
2567
uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
2568
{
2569
    CPU_DoubleU u1, u2;
2570
    u1.ll = op1;
2571
    u2.ll = op2;
2572
    u1.d = float64_mul(u1.d, u2.d, &env->spe_status);
2573
    return u1.ll;
2574
}
2575

    
2576
uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
2577
{
2578
    CPU_DoubleU u1, u2;
2579
    u1.ll = op1;
2580
    u2.ll = op2;
2581
    u1.d = float64_div(u1.d, u2.d, &env->spe_status);
2582
    return u1.ll;
2583
}
2584

    
2585
/* Double precision floating point helpers */
2586
uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
2587
{
2588
    CPU_DoubleU u1, u2;
2589
    u1.ll = op1;
2590
    u2.ll = op2;
2591
    return float64_lt(u1.d, u2.d, &env->spe_status) ? 4 : 0;
2592
}
2593

    
2594
uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
2595
{
2596
    CPU_DoubleU u1, u2;
2597
    u1.ll = op1;
2598
    u2.ll = op2;
2599
    return float64_le(u1.d, u2.d, &env->spe_status) ? 0 : 4;
2600
}
2601

    
2602
uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
2603
{
2604
    CPU_DoubleU u1, u2;
2605
    u1.ll = op1;
2606
    u2.ll = op2;
2607
    return float64_eq(u1.d, u2.d, &env->spe_status) ? 4 : 0;
2608
}
2609

    
2610
uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
2611
{
2612
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2613
    return helper_efdtstlt(op1, op2);
2614
}
2615

    
2616
uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
2617
{
2618
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2619
    return helper_efdtstgt(op1, op2);
2620
}
2621

    
2622
uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
2623
{
2624
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2625
    return helper_efdtsteq(op1, op2);
2626
}
2627

    
2628
/*****************************************************************************/
2629
/* Softmmu support */
2630
#if !defined (CONFIG_USER_ONLY)
2631

    
2632
#define MMUSUFFIX _mmu
2633

    
2634
#define SHIFT 0
2635
#include "softmmu_template.h"
2636

    
2637
#define SHIFT 1
2638
#include "softmmu_template.h"
2639

    
2640
#define SHIFT 2
2641
#include "softmmu_template.h"
2642

    
2643
#define SHIFT 3
2644
#include "softmmu_template.h"
2645

    
2646
/* try to fill the TLB and return an exception if error. If retaddr is
2647
   NULL, it means that the function was called in C code (i.e. not
2648
   from generated code or from helper.c) */
2649
/* XXX: fix it to restore all registers */
2650
void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
2651
{
2652
    TranslationBlock *tb;
2653
    CPUState *saved_env;
2654
    unsigned long pc;
2655
    int ret;
2656

    
2657
    /* XXX: hack to restore env in all cases, even if not called from
2658
       generated code */
2659
    saved_env = env;
2660
    env = cpu_single_env;
2661
    ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
2662
    if (unlikely(ret != 0)) {
2663
        if (likely(retaddr)) {
2664
            /* now we have a real cpu fault */
2665
            pc = (unsigned long)retaddr;
2666
            tb = tb_find_pc(pc);
2667
            if (likely(tb)) {
2668
                /* the PC is inside the translated code. It means that we have
2669
                   a virtual CPU fault */
2670
                cpu_restore_state(tb, env, pc, NULL);
2671
            }
2672
        }
2673
        helper_raise_exception_err(env->exception_index, env->error_code);
2674
    }
2675
    env = saved_env;
2676
}
2677

    
2678
/* Segment registers load and store */
2679
target_ulong helper_load_sr (target_ulong sr_num)
2680
{
2681
    return env->sr[sr_num];
2682
}
2683

    
2684
void helper_store_sr (target_ulong sr_num, target_ulong val)
2685
{
2686
    ppc_store_sr(env, sr_num, val);
2687
}
2688

    
2689
/* SLB management */
2690
#if defined(TARGET_PPC64)
2691
target_ulong helper_load_slb (target_ulong slb_nr)
2692
{
2693
    return ppc_load_slb(env, slb_nr);
2694
}
2695

    
2696
void helper_store_slb (target_ulong slb_nr, target_ulong rs)
2697
{
2698
    ppc_store_slb(env, slb_nr, rs);
2699
}
2700

    
2701
void helper_slbia (void)
2702
{
2703
    ppc_slb_invalidate_all(env);
2704
}
2705

    
2706
void helper_slbie (target_ulong addr)
2707
{
2708
    ppc_slb_invalidate_one(env, addr);
2709
}
2710

    
2711
#endif /* defined(TARGET_PPC64) */
2712

    
2713
/* TLB management */
2714
void helper_tlbia (void)
2715
{
2716
    ppc_tlb_invalidate_all(env);
2717
}
2718

    
2719
void helper_tlbie (target_ulong addr)
2720
{
2721
    ppc_tlb_invalidate_one(env, addr);
2722
}
2723

    
2724
/* Software driven TLBs management */
2725
/* PowerPC 602/603 software TLB load instructions helpers */
2726
static void do_6xx_tlb (target_ulong new_EPN, int is_code)
2727
{
2728
    target_ulong RPN, CMP, EPN;
2729
    int way;
2730

    
2731
    RPN = env->spr[SPR_RPA];
2732
    if (is_code) {
2733
        CMP = env->spr[SPR_ICMP];
2734
        EPN = env->spr[SPR_IMISS];
2735
    } else {
2736
        CMP = env->spr[SPR_DCMP];
2737
        EPN = env->spr[SPR_DMISS];
2738
    }
2739
    way = (env->spr[SPR_SRR1] >> 17) & 1;
2740
#if defined (DEBUG_SOFTWARE_TLB)
2741
    if (loglevel != 0) {
2742
        fprintf(logfile, "%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
2743
                " PTE1 " ADDRX " way %d\n",
2744
                __func__, new_EPN, EPN, CMP, RPN, way);
2745
    }
2746
#endif
2747
    /* Store this TLB */
2748
    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2749
                     way, is_code, CMP, RPN);
2750
}
2751

    
2752
void helper_6xx_tlbd (target_ulong EPN)
2753
{
2754
    do_6xx_tlb(EPN, 0);
2755
}
2756

    
2757
void helper_6xx_tlbi (target_ulong EPN)
2758
{
2759
    do_6xx_tlb(EPN, 1);
2760
}
2761

    
2762
/* PowerPC 74xx software TLB load instructions helpers */
2763
static void do_74xx_tlb (target_ulong new_EPN, int is_code)
2764
{
2765
    target_ulong RPN, CMP, EPN;
2766
    int way;
2767

    
2768
    RPN = env->spr[SPR_PTELO];
2769
    CMP = env->spr[SPR_PTEHI];
2770
    EPN = env->spr[SPR_TLBMISS] & ~0x3;
2771
    way = env->spr[SPR_TLBMISS] & 0x3;
2772
#if defined (DEBUG_SOFTWARE_TLB)
2773
    if (loglevel != 0) {
2774
        fprintf(logfile, "%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
2775
                " PTE1 " ADDRX " way %d\n",
2776
                __func__, new_EPN, EPN, CMP, RPN, way);
2777
    }
2778
#endif
2779
    /* Store this TLB */
2780
    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2781
                     way, is_code, CMP, RPN);
2782
}
2783

    
2784
void helper_74xx_tlbd (target_ulong EPN)
2785
{
2786
    do_74xx_tlb(EPN, 0);
2787
}
2788

    
2789
void helper_74xx_tlbi (target_ulong EPN)
2790
{
2791
    do_74xx_tlb(EPN, 1);
2792
}
2793

    
2794
static always_inline target_ulong booke_tlb_to_page_size (int size)
2795
{
2796
    return 1024 << (2 * size);
2797
}
2798

    
2799
static always_inline int booke_page_size_to_tlb (target_ulong page_size)
2800
{
2801
    int size;
2802

    
2803
    switch (page_size) {
2804
    case 0x00000400UL:
2805
        size = 0x0;
2806
        break;
2807
    case 0x00001000UL:
2808
        size = 0x1;
2809
        break;
2810
    case 0x00004000UL:
2811
        size = 0x2;
2812
        break;
2813
    case 0x00010000UL:
2814
        size = 0x3;
2815
        break;
2816
    case 0x00040000UL:
2817
        size = 0x4;
2818
        break;
2819
    case 0x00100000UL:
2820
        size = 0x5;
2821
        break;
2822
    case 0x00400000UL:
2823
        size = 0x6;
2824
        break;
2825
    case 0x01000000UL:
2826
        size = 0x7;
2827
        break;
2828
    case 0x04000000UL:
2829
        size = 0x8;
2830
        break;
2831
    case 0x10000000UL:
2832
        size = 0x9;
2833
        break;
2834
    case 0x40000000UL:
2835
        size = 0xA;
2836
        break;
2837
#if defined (TARGET_PPC64)
2838
    case 0x000100000000ULL:
2839
        size = 0xB;
2840
        break;
2841
    case 0x000400000000ULL:
2842
        size = 0xC;
2843
        break;
2844
    case 0x001000000000ULL:
2845
        size = 0xD;
2846
        break;
2847
    case 0x004000000000ULL:
2848
        size = 0xE;
2849
        break;
2850
    case 0x010000000000ULL:
2851
        size = 0xF;
2852
        break;
2853
#endif
2854
    default:
2855
        size = -1;
2856
        break;
2857
    }
2858

    
2859
    return size;
2860
}
2861

    
2862
/* Helpers for 4xx TLB management */
2863
target_ulong helper_4xx_tlbre_lo (target_ulong entry)
2864
{
2865
    ppcemb_tlb_t *tlb;
2866
    target_ulong ret;
2867
    int size;
2868

    
2869
    entry &= 0x3F;
2870
    tlb = &env->tlb[entry].tlbe;
2871
    ret = tlb->EPN;
2872
    if (tlb->prot & PAGE_VALID)
2873
        ret |= 0x400;
2874
    size = booke_page_size_to_tlb(tlb->size);
2875
    if (size < 0 || size > 0x7)
2876
        size = 1;
2877
    ret |= size << 7;
2878
    env->spr[SPR_40x_PID] = tlb->PID;
2879
    return ret;
2880
}
2881

    
2882
target_ulong helper_4xx_tlbre_hi (target_ulong entry)
2883
{
2884
    ppcemb_tlb_t *tlb;
2885
    target_ulong ret;
2886

    
2887
    entry &= 0x3F;
2888
    tlb = &env->tlb[entry].tlbe;
2889
    ret = tlb->RPN;
2890
    if (tlb->prot & PAGE_EXEC)
2891
        ret |= 0x200;
2892
    if (tlb->prot & PAGE_WRITE)
2893
        ret |= 0x100;
2894
    return ret;
2895
}
2896

    
2897
void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
2898
{
2899
    ppcemb_tlb_t *tlb;
2900
    target_ulong page, end;
2901

    
2902
#if defined (DEBUG_SOFTWARE_TLB)
2903
    if (loglevel != 0) {
2904
        fprintf(logfile, "%s entry %d val " ADDRX "\n", __func__, (int)entry, val);
2905
    }
2906
#endif
2907
    entry &= 0x3F;
2908
    tlb = &env->tlb[entry].tlbe;
2909
    /* Invalidate previous TLB (if it's valid) */
2910
    if (tlb->prot & PAGE_VALID) {
2911
        end = tlb->EPN + tlb->size;
2912
#if defined (DEBUG_SOFTWARE_TLB)
2913
        if (loglevel != 0) {
2914
            fprintf(logfile, "%s: invalidate old TLB %d start " ADDRX
2915
                    " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
2916
        }
2917
#endif
2918
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
2919
            tlb_flush_page(env, page);
2920
    }
2921
    tlb->size = booke_tlb_to_page_size((val >> 7) & 0x7);
2922
    /* We cannot handle TLB size < TARGET_PAGE_SIZE.
2923
     * If this ever occurs, one should use the ppcemb target instead
2924
     * of the ppc or ppc64 one
2925
     */
2926
    if ((val & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
2927
        cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
2928
                  "are not supported (%d)\n",
2929
                  tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
2930
    }
2931
    tlb->EPN = val & ~(tlb->size - 1);
2932
    if (val & 0x40)
2933
        tlb->prot |= PAGE_VALID;
2934
    else
2935
        tlb->prot &= ~PAGE_VALID;
2936
    if (val & 0x20) {
2937
        /* XXX: TO BE FIXED */
2938
        cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
2939
    }
2940
    tlb->PID = env->spr[SPR_40x_PID]; /* PID */
2941
    tlb->attr = val & 0xFF;
2942
#if defined (DEBUG_SOFTWARE_TLB)
2943
    if (loglevel != 0) {
2944
        fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
2945
                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
2946
                (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2947
                tlb->prot & PAGE_READ ? 'r' : '-',
2948
                tlb->prot & PAGE_WRITE ? 'w' : '-',
2949
                tlb->prot & PAGE_EXEC ? 'x' : '-',
2950
                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2951
    }
2952
#endif
2953
    /* Invalidate new TLB (if valid) */
2954
    if (tlb->prot & PAGE_VALID) {
2955
        end = tlb->EPN + tlb->size;
2956
#if defined (DEBUG_SOFTWARE_TLB)
2957
        if (loglevel != 0) {
2958
            fprintf(logfile, "%s: invalidate TLB %d start " ADDRX
2959
                    " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
2960
        }
2961
#endif
2962
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
2963
            tlb_flush_page(env, page);
2964
    }
2965
}
2966

    
2967
void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
2968
{
2969
    ppcemb_tlb_t *tlb;
2970

    
2971
#if defined (DEBUG_SOFTWARE_TLB)
2972
    if (loglevel != 0) {
2973
        fprintf(logfile, "%s entry %i val " ADDRX "\n", __func__, (int)entry, val);
2974
    }
2975
#endif
2976
    entry &= 0x3F;
2977
    tlb = &env->tlb[entry].tlbe;
2978
    tlb->RPN = val & 0xFFFFFC00;
2979
    tlb->prot = PAGE_READ;
2980
    if (val & 0x200)
2981
        tlb->prot |= PAGE_EXEC;
2982
    if (val & 0x100)
2983
        tlb->prot |= PAGE_WRITE;
2984
#if defined (DEBUG_SOFTWARE_TLB)
2985
    if (loglevel != 0) {
2986
        fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
2987
                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
2988
                (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2989
                tlb->prot & PAGE_READ ? 'r' : '-',
2990
                tlb->prot & PAGE_WRITE ? 'w' : '-',
2991
                tlb->prot & PAGE_EXEC ? 'x' : '-',
2992
                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2993
    }
2994
#endif
2995
}
2996

    
2997
target_ulong helper_4xx_tlbsx (target_ulong address)
2998
{
2999
    return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
3000
}
3001

    
3002
/* PowerPC 440 TLB management */
3003
void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
3004
{
3005
    ppcemb_tlb_t *tlb;
3006
    target_ulong EPN, RPN, size;
3007
    int do_flush_tlbs;
3008

    
3009
#if defined (DEBUG_SOFTWARE_TLB)
3010
    if (loglevel != 0) {
3011
        fprintf(logfile, "%s word %d entry %d value " ADDRX "\n",
3012
                __func__, word, (int)entry, value);
3013
    }
3014
#endif
3015
    do_flush_tlbs = 0;
3016
    entry &= 0x3F;
3017
    tlb = &env->tlb[entry].tlbe;
3018
    switch (word) {
3019
    default:
3020
        /* Just here to please gcc */
3021
    case 0:
3022
        EPN = value & 0xFFFFFC00;
3023
        if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
3024
            do_flush_tlbs = 1;
3025
        tlb->EPN = EPN;
3026
        size = booke_tlb_to_page_size((value >> 4) & 0xF);
3027
        if ((tlb->prot & PAGE_VALID) && tlb->size < size)
3028
            do_flush_tlbs = 1;
3029
        tlb->size = size;
3030
        tlb->attr &= ~0x1;
3031
        tlb->attr |= (value >> 8) & 1;
3032
        if (value & 0x200) {
3033
            tlb->prot |= PAGE_VALID;
3034
        } else {
3035
            if (tlb->prot & PAGE_VALID) {
3036
                tlb->prot &= ~PAGE_VALID;
3037
                do_flush_tlbs = 1;
3038
            }
3039
        }
3040
        tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
3041
        if (do_flush_tlbs)
3042
            tlb_flush(env, 1);
3043
        break;
3044
    case 1:
3045
        RPN = value & 0xFFFFFC0F;
3046
        if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
3047
            tlb_flush(env, 1);
3048
        tlb->RPN = RPN;
3049
        break;
3050
    case 2:
3051
        tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
3052
        tlb->prot = tlb->prot & PAGE_VALID;
3053
        if (value & 0x1)
3054
            tlb->prot |= PAGE_READ << 4;
3055
        if (value & 0x2)
3056
            tlb->prot |= PAGE_WRITE << 4;
3057
        if (value & 0x4)
3058
            tlb->prot |= PAGE_EXEC << 4;
3059
        if (value & 0x8)
3060
            tlb->prot |= PAGE_READ;
3061
        if (value & 0x10)
3062
            tlb->prot |= PAGE_WRITE;
3063
        if (value & 0x20)
3064
            tlb->prot |= PAGE_EXEC;
3065
        break;
3066
    }
3067
}
3068

    
3069
target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
3070
{
3071
    ppcemb_tlb_t *tlb;
3072
    target_ulong ret;
3073
    int size;
3074

    
3075
    entry &= 0x3F;
3076
    tlb = &env->tlb[entry].tlbe;
3077
    switch (word) {
3078
    default:
3079
        /* Just here to please gcc */
3080
    case 0:
3081
        ret = tlb->EPN;
3082
        size = booke_page_size_to_tlb(tlb->size);
3083
        if (size < 0 || size > 0xF)
3084
            size = 1;
3085
        ret |= size << 4;
3086
        if (tlb->attr & 0x1)
3087
            ret |= 0x100;
3088
        if (tlb->prot & PAGE_VALID)
3089
            ret |= 0x200;
3090
        env->spr[SPR_440_MMUCR] &= ~0x000000FF;
3091
        env->spr[SPR_440_MMUCR] |= tlb->PID;
3092
        break;
3093
    case 1:
3094
        ret = tlb->RPN;
3095
        break;
3096
    case 2:
3097
        ret = tlb->attr & ~0x1;
3098
        if (tlb->prot & (PAGE_READ << 4))
3099
            ret |= 0x1;
3100
        if (tlb->prot & (PAGE_WRITE << 4))
3101
            ret |= 0x2;
3102
        if (tlb->prot & (PAGE_EXEC << 4))
3103
            ret |= 0x4;
3104
        if (tlb->prot & PAGE_READ)
3105
            ret |= 0x8;
3106
        if (tlb->prot & PAGE_WRITE)
3107
            ret |= 0x10;
3108
        if (tlb->prot & PAGE_EXEC)
3109
            ret |= 0x20;
3110
        break;
3111
    }
3112
    return ret;
3113
}
3114

    
3115
target_ulong helper_440_tlbsx (target_ulong address)
3116
{
3117
    return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
3118
}
3119

    
3120
#endif /* !CONFIG_USER_ONLY */