Statistics
| Branch: | Revision:

root / target-ppc / op_helper.c @ fad6cb1a

History | View | Annotate | Download (86.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., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 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
#define VAVG_DO(name, element, etype)                                   \
1992
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
1993
    {                                                                   \
1994
        int i;                                                          \
1995
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
1996
            etype x = (etype)a->element[i] + (etype)b->element[i] + 1;  \
1997
            r->element[i] = x >> 1;                                     \
1998
        }                                                               \
1999
    }
2000

    
2001
#define VAVG(type, signed_element, signed_type, unsigned_element, unsigned_type) \
2002
    VAVG_DO(avgs##type, signed_element, signed_type)                    \
2003
    VAVG_DO(avgu##type, unsigned_element, unsigned_type)
2004
VAVG(b, s8, int16_t, u8, uint16_t)
2005
VAVG(h, s16, int32_t, u16, uint32_t)
2006
VAVG(w, s32, int64_t, u32, uint64_t)
2007
#undef VAVG_DO
2008
#undef VAVG
2009

    
2010
#define VMINMAX_DO(name, compare, element)                              \
2011
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
2012
    {                                                                   \
2013
        int i;                                                          \
2014
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2015
            if (a->element[i] compare b->element[i]) {                  \
2016
                r->element[i] = b->element[i];                          \
2017
            } else {                                                    \
2018
                r->element[i] = a->element[i];                          \
2019
            }                                                           \
2020
        }                                                               \
2021
    }
2022
#define VMINMAX(suffix, element)                \
2023
  VMINMAX_DO(min##suffix, >, element)           \
2024
  VMINMAX_DO(max##suffix, <, element)
2025
VMINMAX(sb, s8)
2026
VMINMAX(sh, s16)
2027
VMINMAX(sw, s32)
2028
VMINMAX(ub, u8)
2029
VMINMAX(uh, u16)
2030
VMINMAX(uw, u32)
2031
#undef VMINMAX_DO
2032
#undef VMINMAX
2033

    
2034
#undef VECTOR_FOR_INORDER_I
2035
#undef HI_IDX
2036
#undef LO_IDX
2037

    
2038
/*****************************************************************************/
2039
/* SPE extension helpers */
2040
/* Use a table to make this quicker */
2041
static uint8_t hbrev[16] = {
2042
    0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
2043
    0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
2044
};
2045

    
2046
static always_inline uint8_t byte_reverse (uint8_t val)
2047
{
2048
    return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
2049
}
2050

    
2051
static always_inline uint32_t word_reverse (uint32_t val)
2052
{
2053
    return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
2054
        (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
2055
}
2056

    
2057
#define MASKBITS 16 // Random value - to be fixed (implementation dependant)
2058
target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
2059
{
2060
    uint32_t a, b, d, mask;
2061

    
2062
    mask = UINT32_MAX >> (32 - MASKBITS);
2063
    a = arg1 & mask;
2064
    b = arg2 & mask;
2065
    d = word_reverse(1 + word_reverse(a | ~b));
2066
    return (arg1 & ~mask) | (d & b);
2067
}
2068

    
2069
uint32_t helper_cntlsw32 (uint32_t val)
2070
{
2071
    if (val & 0x80000000)
2072
        return clz32(~val);
2073
    else
2074
        return clz32(val);
2075
}
2076

    
2077
uint32_t helper_cntlzw32 (uint32_t val)
2078
{
2079
    return clz32(val);
2080
}
2081

    
2082
/* Single-precision floating-point conversions */
2083
static always_inline uint32_t efscfsi (uint32_t val)
2084
{
2085
    CPU_FloatU u;
2086

    
2087
    u.f = int32_to_float32(val, &env->spe_status);
2088

    
2089
    return u.l;
2090
}
2091

    
2092
static always_inline uint32_t efscfui (uint32_t val)
2093
{
2094
    CPU_FloatU u;
2095

    
2096
    u.f = uint32_to_float32(val, &env->spe_status);
2097

    
2098
    return u.l;
2099
}
2100

    
2101
static always_inline int32_t efsctsi (uint32_t val)
2102
{
2103
    CPU_FloatU u;
2104

    
2105
    u.l = val;
2106
    /* NaN are not treated the same way IEEE 754 does */
2107
    if (unlikely(float32_is_nan(u.f)))
2108
        return 0;
2109

    
2110
    return float32_to_int32(u.f, &env->spe_status);
2111
}
2112

    
2113
static always_inline uint32_t efsctui (uint32_t val)
2114
{
2115
    CPU_FloatU u;
2116

    
2117
    u.l = val;
2118
    /* NaN are not treated the same way IEEE 754 does */
2119
    if (unlikely(float32_is_nan(u.f)))
2120
        return 0;
2121

    
2122
    return float32_to_uint32(u.f, &env->spe_status);
2123
}
2124

    
2125
static always_inline uint32_t efsctsiz (uint32_t val)
2126
{
2127
    CPU_FloatU u;
2128

    
2129
    u.l = val;
2130
    /* NaN are not treated the same way IEEE 754 does */
2131
    if (unlikely(float32_is_nan(u.f)))
2132
        return 0;
2133

    
2134
    return float32_to_int32_round_to_zero(u.f, &env->spe_status);
2135
}
2136

    
2137
static always_inline uint32_t efsctuiz (uint32_t val)
2138
{
2139
    CPU_FloatU u;
2140

    
2141
    u.l = val;
2142
    /* NaN are not treated the same way IEEE 754 does */
2143
    if (unlikely(float32_is_nan(u.f)))
2144
        return 0;
2145

    
2146
    return float32_to_uint32_round_to_zero(u.f, &env->spe_status);
2147
}
2148

    
2149
static always_inline uint32_t efscfsf (uint32_t val)
2150
{
2151
    CPU_FloatU u;
2152
    float32 tmp;
2153

    
2154
    u.f = int32_to_float32(val, &env->spe_status);
2155
    tmp = int64_to_float32(1ULL << 32, &env->spe_status);
2156
    u.f = float32_div(u.f, tmp, &env->spe_status);
2157

    
2158
    return u.l;
2159
}
2160

    
2161
static always_inline uint32_t efscfuf (uint32_t val)
2162
{
2163
    CPU_FloatU u;
2164
    float32 tmp;
2165

    
2166
    u.f = uint32_to_float32(val, &env->spe_status);
2167
    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2168
    u.f = float32_div(u.f, tmp, &env->spe_status);
2169

    
2170
    return u.l;
2171
}
2172

    
2173
static always_inline uint32_t efsctsf (uint32_t val)
2174
{
2175
    CPU_FloatU u;
2176
    float32 tmp;
2177

    
2178
    u.l = val;
2179
    /* NaN are not treated the same way IEEE 754 does */
2180
    if (unlikely(float32_is_nan(u.f)))
2181
        return 0;
2182
    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2183
    u.f = float32_mul(u.f, tmp, &env->spe_status);
2184

    
2185
    return float32_to_int32(u.f, &env->spe_status);
2186
}
2187

    
2188
static always_inline uint32_t efsctuf (uint32_t val)
2189
{
2190
    CPU_FloatU u;
2191
    float32 tmp;
2192

    
2193
    u.l = val;
2194
    /* NaN are not treated the same way IEEE 754 does */
2195
    if (unlikely(float32_is_nan(u.f)))
2196
        return 0;
2197
    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2198
    u.f = float32_mul(u.f, tmp, &env->spe_status);
2199

    
2200
    return float32_to_uint32(u.f, &env->spe_status);
2201
}
2202

    
2203
#define HELPER_SPE_SINGLE_CONV(name)                                          \
2204
uint32_t helper_e##name (uint32_t val)                                        \
2205
{                                                                             \
2206
    return e##name(val);                                                      \
2207
}
2208
/* efscfsi */
2209
HELPER_SPE_SINGLE_CONV(fscfsi);
2210
/* efscfui */
2211
HELPER_SPE_SINGLE_CONV(fscfui);
2212
/* efscfuf */
2213
HELPER_SPE_SINGLE_CONV(fscfuf);
2214
/* efscfsf */
2215
HELPER_SPE_SINGLE_CONV(fscfsf);
2216
/* efsctsi */
2217
HELPER_SPE_SINGLE_CONV(fsctsi);
2218
/* efsctui */
2219
HELPER_SPE_SINGLE_CONV(fsctui);
2220
/* efsctsiz */
2221
HELPER_SPE_SINGLE_CONV(fsctsiz);
2222
/* efsctuiz */
2223
HELPER_SPE_SINGLE_CONV(fsctuiz);
2224
/* efsctsf */
2225
HELPER_SPE_SINGLE_CONV(fsctsf);
2226
/* efsctuf */
2227
HELPER_SPE_SINGLE_CONV(fsctuf);
2228

    
2229
#define HELPER_SPE_VECTOR_CONV(name)                                          \
2230
uint64_t helper_ev##name (uint64_t val)                                       \
2231
{                                                                             \
2232
    return ((uint64_t)e##name(val >> 32) << 32) |                             \
2233
            (uint64_t)e##name(val);                                           \
2234
}
2235
/* evfscfsi */
2236
HELPER_SPE_VECTOR_CONV(fscfsi);
2237
/* evfscfui */
2238
HELPER_SPE_VECTOR_CONV(fscfui);
2239
/* evfscfuf */
2240
HELPER_SPE_VECTOR_CONV(fscfuf);
2241
/* evfscfsf */
2242
HELPER_SPE_VECTOR_CONV(fscfsf);
2243
/* evfsctsi */
2244
HELPER_SPE_VECTOR_CONV(fsctsi);
2245
/* evfsctui */
2246
HELPER_SPE_VECTOR_CONV(fsctui);
2247
/* evfsctsiz */
2248
HELPER_SPE_VECTOR_CONV(fsctsiz);
2249
/* evfsctuiz */
2250
HELPER_SPE_VECTOR_CONV(fsctuiz);
2251
/* evfsctsf */
2252
HELPER_SPE_VECTOR_CONV(fsctsf);
2253
/* evfsctuf */
2254
HELPER_SPE_VECTOR_CONV(fsctuf);
2255

    
2256
/* Single-precision floating-point arithmetic */
2257
static always_inline uint32_t efsadd (uint32_t op1, uint32_t op2)
2258
{
2259
    CPU_FloatU u1, u2;
2260
    u1.l = op1;
2261
    u2.l = op2;
2262
    u1.f = float32_add(u1.f, u2.f, &env->spe_status);
2263
    return u1.l;
2264
}
2265

    
2266
static always_inline uint32_t efssub (uint32_t op1, uint32_t op2)
2267
{
2268
    CPU_FloatU u1, u2;
2269
    u1.l = op1;
2270
    u2.l = op2;
2271
    u1.f = float32_sub(u1.f, u2.f, &env->spe_status);
2272
    return u1.l;
2273
}
2274

    
2275
static always_inline uint32_t efsmul (uint32_t op1, uint32_t op2)
2276
{
2277
    CPU_FloatU u1, u2;
2278
    u1.l = op1;
2279
    u2.l = op2;
2280
    u1.f = float32_mul(u1.f, u2.f, &env->spe_status);
2281
    return u1.l;
2282
}
2283

    
2284
static always_inline uint32_t efsdiv (uint32_t op1, uint32_t op2)
2285
{
2286
    CPU_FloatU u1, u2;
2287
    u1.l = op1;
2288
    u2.l = op2;
2289
    u1.f = float32_div(u1.f, u2.f, &env->spe_status);
2290
    return u1.l;
2291
}
2292

    
2293
#define HELPER_SPE_SINGLE_ARITH(name)                                         \
2294
uint32_t helper_e##name (uint32_t op1, uint32_t op2)                          \
2295
{                                                                             \
2296
    return e##name(op1, op2);                                                 \
2297
}
2298
/* efsadd */
2299
HELPER_SPE_SINGLE_ARITH(fsadd);
2300
/* efssub */
2301
HELPER_SPE_SINGLE_ARITH(fssub);
2302
/* efsmul */
2303
HELPER_SPE_SINGLE_ARITH(fsmul);
2304
/* efsdiv */
2305
HELPER_SPE_SINGLE_ARITH(fsdiv);
2306

    
2307
#define HELPER_SPE_VECTOR_ARITH(name)                                         \
2308
uint64_t helper_ev##name (uint64_t op1, uint64_t op2)                         \
2309
{                                                                             \
2310
    return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) |                  \
2311
            (uint64_t)e##name(op1, op2);                                      \
2312
}
2313
/* evfsadd */
2314
HELPER_SPE_VECTOR_ARITH(fsadd);
2315
/* evfssub */
2316
HELPER_SPE_VECTOR_ARITH(fssub);
2317
/* evfsmul */
2318
HELPER_SPE_VECTOR_ARITH(fsmul);
2319
/* evfsdiv */
2320
HELPER_SPE_VECTOR_ARITH(fsdiv);
2321

    
2322
/* Single-precision floating-point comparisons */
2323
static always_inline uint32_t efststlt (uint32_t op1, uint32_t op2)
2324
{
2325
    CPU_FloatU u1, u2;
2326
    u1.l = op1;
2327
    u2.l = op2;
2328
    return float32_lt(u1.f, u2.f, &env->spe_status) ? 4 : 0;
2329
}
2330

    
2331
static always_inline uint32_t efststgt (uint32_t op1, uint32_t op2)
2332
{
2333
    CPU_FloatU u1, u2;
2334
    u1.l = op1;
2335
    u2.l = op2;
2336
    return float32_le(u1.f, u2.f, &env->spe_status) ? 0 : 4;
2337
}
2338

    
2339
static always_inline uint32_t efststeq (uint32_t op1, uint32_t op2)
2340
{
2341
    CPU_FloatU u1, u2;
2342
    u1.l = op1;
2343
    u2.l = op2;
2344
    return float32_eq(u1.f, u2.f, &env->spe_status) ? 4 : 0;
2345
}
2346

    
2347
static always_inline uint32_t efscmplt (uint32_t op1, uint32_t op2)
2348
{
2349
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2350
    return efststlt(op1, op2);
2351
}
2352

    
2353
static always_inline uint32_t efscmpgt (uint32_t op1, uint32_t op2)
2354
{
2355
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2356
    return efststgt(op1, op2);
2357
}
2358

    
2359
static always_inline uint32_t efscmpeq (uint32_t op1, uint32_t op2)
2360
{
2361
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2362
    return efststeq(op1, op2);
2363
}
2364

    
2365
#define HELPER_SINGLE_SPE_CMP(name)                                           \
2366
uint32_t helper_e##name (uint32_t op1, uint32_t op2)                          \
2367
{                                                                             \
2368
    return e##name(op1, op2) << 2;                                            \
2369
}
2370
/* efststlt */
2371
HELPER_SINGLE_SPE_CMP(fststlt);
2372
/* efststgt */
2373
HELPER_SINGLE_SPE_CMP(fststgt);
2374
/* efststeq */
2375
HELPER_SINGLE_SPE_CMP(fststeq);
2376
/* efscmplt */
2377
HELPER_SINGLE_SPE_CMP(fscmplt);
2378
/* efscmpgt */
2379
HELPER_SINGLE_SPE_CMP(fscmpgt);
2380
/* efscmpeq */
2381
HELPER_SINGLE_SPE_CMP(fscmpeq);
2382

    
2383
static always_inline uint32_t evcmp_merge (int t0, int t1)
2384
{
2385
    return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
2386
}
2387

    
2388
#define HELPER_VECTOR_SPE_CMP(name)                                           \
2389
uint32_t helper_ev##name (uint64_t op1, uint64_t op2)                         \
2390
{                                                                             \
2391
    return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2));     \
2392
}
2393
/* evfststlt */
2394
HELPER_VECTOR_SPE_CMP(fststlt);
2395
/* evfststgt */
2396
HELPER_VECTOR_SPE_CMP(fststgt);
2397
/* evfststeq */
2398
HELPER_VECTOR_SPE_CMP(fststeq);
2399
/* evfscmplt */
2400
HELPER_VECTOR_SPE_CMP(fscmplt);
2401
/* evfscmpgt */
2402
HELPER_VECTOR_SPE_CMP(fscmpgt);
2403
/* evfscmpeq */
2404
HELPER_VECTOR_SPE_CMP(fscmpeq);
2405

    
2406
/* Double-precision floating-point conversion */
2407
uint64_t helper_efdcfsi (uint32_t val)
2408
{
2409
    CPU_DoubleU u;
2410

    
2411
    u.d = int32_to_float64(val, &env->spe_status);
2412

    
2413
    return u.ll;
2414
}
2415

    
2416
uint64_t helper_efdcfsid (uint64_t val)
2417
{
2418
    CPU_DoubleU u;
2419

    
2420
    u.d = int64_to_float64(val, &env->spe_status);
2421

    
2422
    return u.ll;
2423
}
2424

    
2425
uint64_t helper_efdcfui (uint32_t val)
2426
{
2427
    CPU_DoubleU u;
2428

    
2429
    u.d = uint32_to_float64(val, &env->spe_status);
2430

    
2431
    return u.ll;
2432
}
2433

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

    
2438
    u.d = uint64_to_float64(val, &env->spe_status);
2439

    
2440
    return u.ll;
2441
}
2442

    
2443
uint32_t helper_efdctsi (uint64_t val)
2444
{
2445
    CPU_DoubleU u;
2446

    
2447
    u.ll = val;
2448
    /* NaN are not treated the same way IEEE 754 does */
2449
    if (unlikely(float64_is_nan(u.d)))
2450
        return 0;
2451

    
2452
    return float64_to_int32(u.d, &env->spe_status);
2453
}
2454

    
2455
uint32_t helper_efdctui (uint64_t val)
2456
{
2457
    CPU_DoubleU u;
2458

    
2459
    u.ll = val;
2460
    /* NaN are not treated the same way IEEE 754 does */
2461
    if (unlikely(float64_is_nan(u.d)))
2462
        return 0;
2463

    
2464
    return float64_to_uint32(u.d, &env->spe_status);
2465
}
2466

    
2467
uint32_t helper_efdctsiz (uint64_t val)
2468
{
2469
    CPU_DoubleU u;
2470

    
2471
    u.ll = val;
2472
    /* NaN are not treated the same way IEEE 754 does */
2473
    if (unlikely(float64_is_nan(u.d)))
2474
        return 0;
2475

    
2476
    return float64_to_int32_round_to_zero(u.d, &env->spe_status);
2477
}
2478

    
2479
uint64_t helper_efdctsidz (uint64_t val)
2480
{
2481
    CPU_DoubleU u;
2482

    
2483
    u.ll = val;
2484
    /* NaN are not treated the same way IEEE 754 does */
2485
    if (unlikely(float64_is_nan(u.d)))
2486
        return 0;
2487

    
2488
    return float64_to_int64_round_to_zero(u.d, &env->spe_status);
2489
}
2490

    
2491
uint32_t helper_efdctuiz (uint64_t val)
2492
{
2493
    CPU_DoubleU u;
2494

    
2495
    u.ll = val;
2496
    /* NaN are not treated the same way IEEE 754 does */
2497
    if (unlikely(float64_is_nan(u.d)))
2498
        return 0;
2499

    
2500
    return float64_to_uint32_round_to_zero(u.d, &env->spe_status);
2501
}
2502

    
2503
uint64_t helper_efdctuidz (uint64_t val)
2504
{
2505
    CPU_DoubleU u;
2506

    
2507
    u.ll = val;
2508
    /* NaN are not treated the same way IEEE 754 does */
2509
    if (unlikely(float64_is_nan(u.d)))
2510
        return 0;
2511

    
2512
    return float64_to_uint64_round_to_zero(u.d, &env->spe_status);
2513
}
2514

    
2515
uint64_t helper_efdcfsf (uint32_t val)
2516
{
2517
    CPU_DoubleU u;
2518
    float64 tmp;
2519

    
2520
    u.d = int32_to_float64(val, &env->spe_status);
2521
    tmp = int64_to_float64(1ULL << 32, &env->spe_status);
2522
    u.d = float64_div(u.d, tmp, &env->spe_status);
2523

    
2524
    return u.ll;
2525
}
2526

    
2527
uint64_t helper_efdcfuf (uint32_t val)
2528
{
2529
    CPU_DoubleU u;
2530
    float64 tmp;
2531

    
2532
    u.d = uint32_to_float64(val, &env->spe_status);
2533
    tmp = int64_to_float64(1ULL << 32, &env->spe_status);
2534
    u.d = float64_div(u.d, tmp, &env->spe_status);
2535

    
2536
    return u.ll;
2537
}
2538

    
2539
uint32_t helper_efdctsf (uint64_t val)
2540
{
2541
    CPU_DoubleU u;
2542
    float64 tmp;
2543

    
2544
    u.ll = val;
2545
    /* NaN are not treated the same way IEEE 754 does */
2546
    if (unlikely(float64_is_nan(u.d)))
2547
        return 0;
2548
    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
2549
    u.d = float64_mul(u.d, tmp, &env->spe_status);
2550

    
2551
    return float64_to_int32(u.d, &env->spe_status);
2552
}
2553

    
2554
uint32_t helper_efdctuf (uint64_t val)
2555
{
2556
    CPU_DoubleU u;
2557
    float64 tmp;
2558

    
2559
    u.ll = val;
2560
    /* NaN are not treated the same way IEEE 754 does */
2561
    if (unlikely(float64_is_nan(u.d)))
2562
        return 0;
2563
    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
2564
    u.d = float64_mul(u.d, tmp, &env->spe_status);
2565

    
2566
    return float64_to_uint32(u.d, &env->spe_status);
2567
}
2568

    
2569
uint32_t helper_efscfd (uint64_t val)
2570
{
2571
    CPU_DoubleU u1;
2572
    CPU_FloatU u2;
2573

    
2574
    u1.ll = val;
2575
    u2.f = float64_to_float32(u1.d, &env->spe_status);
2576

    
2577
    return u2.l;
2578
}
2579

    
2580
uint64_t helper_efdcfs (uint32_t val)
2581
{
2582
    CPU_DoubleU u2;
2583
    CPU_FloatU u1;
2584

    
2585
    u1.l = val;
2586
    u2.d = float32_to_float64(u1.f, &env->spe_status);
2587

    
2588
    return u2.ll;
2589
}
2590

    
2591
/* Double precision fixed-point arithmetic */
2592
uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
2593
{
2594
    CPU_DoubleU u1, u2;
2595
    u1.ll = op1;
2596
    u2.ll = op2;
2597
    u1.d = float64_add(u1.d, u2.d, &env->spe_status);
2598
    return u1.ll;
2599
}
2600

    
2601
uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
2602
{
2603
    CPU_DoubleU u1, u2;
2604
    u1.ll = op1;
2605
    u2.ll = op2;
2606
    u1.d = float64_sub(u1.d, u2.d, &env->spe_status);
2607
    return u1.ll;
2608
}
2609

    
2610
uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
2611
{
2612
    CPU_DoubleU u1, u2;
2613
    u1.ll = op1;
2614
    u2.ll = op2;
2615
    u1.d = float64_mul(u1.d, u2.d, &env->spe_status);
2616
    return u1.ll;
2617
}
2618

    
2619
uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
2620
{
2621
    CPU_DoubleU u1, u2;
2622
    u1.ll = op1;
2623
    u2.ll = op2;
2624
    u1.d = float64_div(u1.d, u2.d, &env->spe_status);
2625
    return u1.ll;
2626
}
2627

    
2628
/* Double precision floating point helpers */
2629
uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
2630
{
2631
    CPU_DoubleU u1, u2;
2632
    u1.ll = op1;
2633
    u2.ll = op2;
2634
    return float64_lt(u1.d, u2.d, &env->spe_status) ? 4 : 0;
2635
}
2636

    
2637
uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
2638
{
2639
    CPU_DoubleU u1, u2;
2640
    u1.ll = op1;
2641
    u2.ll = op2;
2642
    return float64_le(u1.d, u2.d, &env->spe_status) ? 0 : 4;
2643
}
2644

    
2645
uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
2646
{
2647
    CPU_DoubleU u1, u2;
2648
    u1.ll = op1;
2649
    u2.ll = op2;
2650
    return float64_eq(u1.d, u2.d, &env->spe_status) ? 4 : 0;
2651
}
2652

    
2653
uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
2654
{
2655
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2656
    return helper_efdtstlt(op1, op2);
2657
}
2658

    
2659
uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
2660
{
2661
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2662
    return helper_efdtstgt(op1, op2);
2663
}
2664

    
2665
uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
2666
{
2667
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2668
    return helper_efdtsteq(op1, op2);
2669
}
2670

    
2671
/*****************************************************************************/
2672
/* Softmmu support */
2673
#if !defined (CONFIG_USER_ONLY)
2674

    
2675
#define MMUSUFFIX _mmu
2676

    
2677
#define SHIFT 0
2678
#include "softmmu_template.h"
2679

    
2680
#define SHIFT 1
2681
#include "softmmu_template.h"
2682

    
2683
#define SHIFT 2
2684
#include "softmmu_template.h"
2685

    
2686
#define SHIFT 3
2687
#include "softmmu_template.h"
2688

    
2689
/* try to fill the TLB and return an exception if error. If retaddr is
2690
   NULL, it means that the function was called in C code (i.e. not
2691
   from generated code or from helper.c) */
2692
/* XXX: fix it to restore all registers */
2693
void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
2694
{
2695
    TranslationBlock *tb;
2696
    CPUState *saved_env;
2697
    unsigned long pc;
2698
    int ret;
2699

    
2700
    /* XXX: hack to restore env in all cases, even if not called from
2701
       generated code */
2702
    saved_env = env;
2703
    env = cpu_single_env;
2704
    ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
2705
    if (unlikely(ret != 0)) {
2706
        if (likely(retaddr)) {
2707
            /* now we have a real cpu fault */
2708
            pc = (unsigned long)retaddr;
2709
            tb = tb_find_pc(pc);
2710
            if (likely(tb)) {
2711
                /* the PC is inside the translated code. It means that we have
2712
                   a virtual CPU fault */
2713
                cpu_restore_state(tb, env, pc, NULL);
2714
            }
2715
        }
2716
        helper_raise_exception_err(env->exception_index, env->error_code);
2717
    }
2718
    env = saved_env;
2719
}
2720

    
2721
/* Segment registers load and store */
2722
target_ulong helper_load_sr (target_ulong sr_num)
2723
{
2724
    return env->sr[sr_num];
2725
}
2726

    
2727
void helper_store_sr (target_ulong sr_num, target_ulong val)
2728
{
2729
    ppc_store_sr(env, sr_num, val);
2730
}
2731

    
2732
/* SLB management */
2733
#if defined(TARGET_PPC64)
2734
target_ulong helper_load_slb (target_ulong slb_nr)
2735
{
2736
    return ppc_load_slb(env, slb_nr);
2737
}
2738

    
2739
void helper_store_slb (target_ulong slb_nr, target_ulong rs)
2740
{
2741
    ppc_store_slb(env, slb_nr, rs);
2742
}
2743

    
2744
void helper_slbia (void)
2745
{
2746
    ppc_slb_invalidate_all(env);
2747
}
2748

    
2749
void helper_slbie (target_ulong addr)
2750
{
2751
    ppc_slb_invalidate_one(env, addr);
2752
}
2753

    
2754
#endif /* defined(TARGET_PPC64) */
2755

    
2756
/* TLB management */
2757
void helper_tlbia (void)
2758
{
2759
    ppc_tlb_invalidate_all(env);
2760
}
2761

    
2762
void helper_tlbie (target_ulong addr)
2763
{
2764
    ppc_tlb_invalidate_one(env, addr);
2765
}
2766

    
2767
/* Software driven TLBs management */
2768
/* PowerPC 602/603 software TLB load instructions helpers */
2769
static void do_6xx_tlb (target_ulong new_EPN, int is_code)
2770
{
2771
    target_ulong RPN, CMP, EPN;
2772
    int way;
2773

    
2774
    RPN = env->spr[SPR_RPA];
2775
    if (is_code) {
2776
        CMP = env->spr[SPR_ICMP];
2777
        EPN = env->spr[SPR_IMISS];
2778
    } else {
2779
        CMP = env->spr[SPR_DCMP];
2780
        EPN = env->spr[SPR_DMISS];
2781
    }
2782
    way = (env->spr[SPR_SRR1] >> 17) & 1;
2783
#if defined (DEBUG_SOFTWARE_TLB)
2784
    if (loglevel != 0) {
2785
        fprintf(logfile, "%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
2786
                " PTE1 " ADDRX " way %d\n",
2787
                __func__, new_EPN, EPN, CMP, RPN, way);
2788
    }
2789
#endif
2790
    /* Store this TLB */
2791
    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2792
                     way, is_code, CMP, RPN);
2793
}
2794

    
2795
void helper_6xx_tlbd (target_ulong EPN)
2796
{
2797
    do_6xx_tlb(EPN, 0);
2798
}
2799

    
2800
void helper_6xx_tlbi (target_ulong EPN)
2801
{
2802
    do_6xx_tlb(EPN, 1);
2803
}
2804

    
2805
/* PowerPC 74xx software TLB load instructions helpers */
2806
static void do_74xx_tlb (target_ulong new_EPN, int is_code)
2807
{
2808
    target_ulong RPN, CMP, EPN;
2809
    int way;
2810

    
2811
    RPN = env->spr[SPR_PTELO];
2812
    CMP = env->spr[SPR_PTEHI];
2813
    EPN = env->spr[SPR_TLBMISS] & ~0x3;
2814
    way = env->spr[SPR_TLBMISS] & 0x3;
2815
#if defined (DEBUG_SOFTWARE_TLB)
2816
    if (loglevel != 0) {
2817
        fprintf(logfile, "%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
2818
                " PTE1 " ADDRX " way %d\n",
2819
                __func__, new_EPN, EPN, CMP, RPN, way);
2820
    }
2821
#endif
2822
    /* Store this TLB */
2823
    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2824
                     way, is_code, CMP, RPN);
2825
}
2826

    
2827
void helper_74xx_tlbd (target_ulong EPN)
2828
{
2829
    do_74xx_tlb(EPN, 0);
2830
}
2831

    
2832
void helper_74xx_tlbi (target_ulong EPN)
2833
{
2834
    do_74xx_tlb(EPN, 1);
2835
}
2836

    
2837
static always_inline target_ulong booke_tlb_to_page_size (int size)
2838
{
2839
    return 1024 << (2 * size);
2840
}
2841

    
2842
static always_inline int booke_page_size_to_tlb (target_ulong page_size)
2843
{
2844
    int size;
2845

    
2846
    switch (page_size) {
2847
    case 0x00000400UL:
2848
        size = 0x0;
2849
        break;
2850
    case 0x00001000UL:
2851
        size = 0x1;
2852
        break;
2853
    case 0x00004000UL:
2854
        size = 0x2;
2855
        break;
2856
    case 0x00010000UL:
2857
        size = 0x3;
2858
        break;
2859
    case 0x00040000UL:
2860
        size = 0x4;
2861
        break;
2862
    case 0x00100000UL:
2863
        size = 0x5;
2864
        break;
2865
    case 0x00400000UL:
2866
        size = 0x6;
2867
        break;
2868
    case 0x01000000UL:
2869
        size = 0x7;
2870
        break;
2871
    case 0x04000000UL:
2872
        size = 0x8;
2873
        break;
2874
    case 0x10000000UL:
2875
        size = 0x9;
2876
        break;
2877
    case 0x40000000UL:
2878
        size = 0xA;
2879
        break;
2880
#if defined (TARGET_PPC64)
2881
    case 0x000100000000ULL:
2882
        size = 0xB;
2883
        break;
2884
    case 0x000400000000ULL:
2885
        size = 0xC;
2886
        break;
2887
    case 0x001000000000ULL:
2888
        size = 0xD;
2889
        break;
2890
    case 0x004000000000ULL:
2891
        size = 0xE;
2892
        break;
2893
    case 0x010000000000ULL:
2894
        size = 0xF;
2895
        break;
2896
#endif
2897
    default:
2898
        size = -1;
2899
        break;
2900
    }
2901

    
2902
    return size;
2903
}
2904

    
2905
/* Helpers for 4xx TLB management */
2906
target_ulong helper_4xx_tlbre_lo (target_ulong entry)
2907
{
2908
    ppcemb_tlb_t *tlb;
2909
    target_ulong ret;
2910
    int size;
2911

    
2912
    entry &= 0x3F;
2913
    tlb = &env->tlb[entry].tlbe;
2914
    ret = tlb->EPN;
2915
    if (tlb->prot & PAGE_VALID)
2916
        ret |= 0x400;
2917
    size = booke_page_size_to_tlb(tlb->size);
2918
    if (size < 0 || size > 0x7)
2919
        size = 1;
2920
    ret |= size << 7;
2921
    env->spr[SPR_40x_PID] = tlb->PID;
2922
    return ret;
2923
}
2924

    
2925
target_ulong helper_4xx_tlbre_hi (target_ulong entry)
2926
{
2927
    ppcemb_tlb_t *tlb;
2928
    target_ulong ret;
2929

    
2930
    entry &= 0x3F;
2931
    tlb = &env->tlb[entry].tlbe;
2932
    ret = tlb->RPN;
2933
    if (tlb->prot & PAGE_EXEC)
2934
        ret |= 0x200;
2935
    if (tlb->prot & PAGE_WRITE)
2936
        ret |= 0x100;
2937
    return ret;
2938
}
2939

    
2940
void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
2941
{
2942
    ppcemb_tlb_t *tlb;
2943
    target_ulong page, end;
2944

    
2945
#if defined (DEBUG_SOFTWARE_TLB)
2946
    if (loglevel != 0) {
2947
        fprintf(logfile, "%s entry %d val " ADDRX "\n", __func__, (int)entry, val);
2948
    }
2949
#endif
2950
    entry &= 0x3F;
2951
    tlb = &env->tlb[entry].tlbe;
2952
    /* Invalidate previous TLB (if it's valid) */
2953
    if (tlb->prot & PAGE_VALID) {
2954
        end = tlb->EPN + tlb->size;
2955
#if defined (DEBUG_SOFTWARE_TLB)
2956
        if (loglevel != 0) {
2957
            fprintf(logfile, "%s: invalidate old TLB %d start " ADDRX
2958
                    " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
2959
        }
2960
#endif
2961
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
2962
            tlb_flush_page(env, page);
2963
    }
2964
    tlb->size = booke_tlb_to_page_size((val >> 7) & 0x7);
2965
    /* We cannot handle TLB size < TARGET_PAGE_SIZE.
2966
     * If this ever occurs, one should use the ppcemb target instead
2967
     * of the ppc or ppc64 one
2968
     */
2969
    if ((val & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
2970
        cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
2971
                  "are not supported (%d)\n",
2972
                  tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
2973
    }
2974
    tlb->EPN = val & ~(tlb->size - 1);
2975
    if (val & 0x40)
2976
        tlb->prot |= PAGE_VALID;
2977
    else
2978
        tlb->prot &= ~PAGE_VALID;
2979
    if (val & 0x20) {
2980
        /* XXX: TO BE FIXED */
2981
        cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
2982
    }
2983
    tlb->PID = env->spr[SPR_40x_PID]; /* PID */
2984
    tlb->attr = val & 0xFF;
2985
#if defined (DEBUG_SOFTWARE_TLB)
2986
    if (loglevel != 0) {
2987
        fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
2988
                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
2989
                (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2990
                tlb->prot & PAGE_READ ? 'r' : '-',
2991
                tlb->prot & PAGE_WRITE ? 'w' : '-',
2992
                tlb->prot & PAGE_EXEC ? 'x' : '-',
2993
                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2994
    }
2995
#endif
2996
    /* Invalidate new TLB (if valid) */
2997
    if (tlb->prot & PAGE_VALID) {
2998
        end = tlb->EPN + tlb->size;
2999
#if defined (DEBUG_SOFTWARE_TLB)
3000
        if (loglevel != 0) {
3001
            fprintf(logfile, "%s: invalidate TLB %d start " ADDRX
3002
                    " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
3003
        }
3004
#endif
3005
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3006
            tlb_flush_page(env, page);
3007
    }
3008
}
3009

    
3010
void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
3011
{
3012
    ppcemb_tlb_t *tlb;
3013

    
3014
#if defined (DEBUG_SOFTWARE_TLB)
3015
    if (loglevel != 0) {
3016
        fprintf(logfile, "%s entry %i val " ADDRX "\n", __func__, (int)entry, val);
3017
    }
3018
#endif
3019
    entry &= 0x3F;
3020
    tlb = &env->tlb[entry].tlbe;
3021
    tlb->RPN = val & 0xFFFFFC00;
3022
    tlb->prot = PAGE_READ;
3023
    if (val & 0x200)
3024
        tlb->prot |= PAGE_EXEC;
3025
    if (val & 0x100)
3026
        tlb->prot |= PAGE_WRITE;
3027
#if defined (DEBUG_SOFTWARE_TLB)
3028
    if (loglevel != 0) {
3029
        fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
3030
                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
3031
                (int)entry, tlb->RPN, tlb->EPN, tlb->size,
3032
                tlb->prot & PAGE_READ ? 'r' : '-',
3033
                tlb->prot & PAGE_WRITE ? 'w' : '-',
3034
                tlb->prot & PAGE_EXEC ? 'x' : '-',
3035
                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
3036
    }
3037
#endif
3038
}
3039

    
3040
target_ulong helper_4xx_tlbsx (target_ulong address)
3041
{
3042
    return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
3043
}
3044

    
3045
/* PowerPC 440 TLB management */
3046
void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
3047
{
3048
    ppcemb_tlb_t *tlb;
3049
    target_ulong EPN, RPN, size;
3050
    int do_flush_tlbs;
3051

    
3052
#if defined (DEBUG_SOFTWARE_TLB)
3053
    if (loglevel != 0) {
3054
        fprintf(logfile, "%s word %d entry %d value " ADDRX "\n",
3055
                __func__, word, (int)entry, value);
3056
    }
3057
#endif
3058
    do_flush_tlbs = 0;
3059
    entry &= 0x3F;
3060
    tlb = &env->tlb[entry].tlbe;
3061
    switch (word) {
3062
    default:
3063
        /* Just here to please gcc */
3064
    case 0:
3065
        EPN = value & 0xFFFFFC00;
3066
        if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
3067
            do_flush_tlbs = 1;
3068
        tlb->EPN = EPN;
3069
        size = booke_tlb_to_page_size((value >> 4) & 0xF);
3070
        if ((tlb->prot & PAGE_VALID) && tlb->size < size)
3071
            do_flush_tlbs = 1;
3072
        tlb->size = size;
3073
        tlb->attr &= ~0x1;
3074
        tlb->attr |= (value >> 8) & 1;
3075
        if (value & 0x200) {
3076
            tlb->prot |= PAGE_VALID;
3077
        } else {
3078
            if (tlb->prot & PAGE_VALID) {
3079
                tlb->prot &= ~PAGE_VALID;
3080
                do_flush_tlbs = 1;
3081
            }
3082
        }
3083
        tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
3084
        if (do_flush_tlbs)
3085
            tlb_flush(env, 1);
3086
        break;
3087
    case 1:
3088
        RPN = value & 0xFFFFFC0F;
3089
        if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
3090
            tlb_flush(env, 1);
3091
        tlb->RPN = RPN;
3092
        break;
3093
    case 2:
3094
        tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
3095
        tlb->prot = tlb->prot & PAGE_VALID;
3096
        if (value & 0x1)
3097
            tlb->prot |= PAGE_READ << 4;
3098
        if (value & 0x2)
3099
            tlb->prot |= PAGE_WRITE << 4;
3100
        if (value & 0x4)
3101
            tlb->prot |= PAGE_EXEC << 4;
3102
        if (value & 0x8)
3103
            tlb->prot |= PAGE_READ;
3104
        if (value & 0x10)
3105
            tlb->prot |= PAGE_WRITE;
3106
        if (value & 0x20)
3107
            tlb->prot |= PAGE_EXEC;
3108
        break;
3109
    }
3110
}
3111

    
3112
target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
3113
{
3114
    ppcemb_tlb_t *tlb;
3115
    target_ulong ret;
3116
    int size;
3117

    
3118
    entry &= 0x3F;
3119
    tlb = &env->tlb[entry].tlbe;
3120
    switch (word) {
3121
    default:
3122
        /* Just here to please gcc */
3123
    case 0:
3124
        ret = tlb->EPN;
3125
        size = booke_page_size_to_tlb(tlb->size);
3126
        if (size < 0 || size > 0xF)
3127
            size = 1;
3128
        ret |= size << 4;
3129
        if (tlb->attr & 0x1)
3130
            ret |= 0x100;
3131
        if (tlb->prot & PAGE_VALID)
3132
            ret |= 0x200;
3133
        env->spr[SPR_440_MMUCR] &= ~0x000000FF;
3134
        env->spr[SPR_440_MMUCR] |= tlb->PID;
3135
        break;
3136
    case 1:
3137
        ret = tlb->RPN;
3138
        break;
3139
    case 2:
3140
        ret = tlb->attr & ~0x1;
3141
        if (tlb->prot & (PAGE_READ << 4))
3142
            ret |= 0x1;
3143
        if (tlb->prot & (PAGE_WRITE << 4))
3144
            ret |= 0x2;
3145
        if (tlb->prot & (PAGE_EXEC << 4))
3146
            ret |= 0x4;
3147
        if (tlb->prot & PAGE_READ)
3148
            ret |= 0x8;
3149
        if (tlb->prot & PAGE_WRITE)
3150
            ret |= 0x10;
3151
        if (tlb->prot & PAGE_EXEC)
3152
            ret |= 0x20;
3153
        break;
3154
    }
3155
    return ret;
3156
}
3157

    
3158
target_ulong helper_440_tlbsx (target_ulong address)
3159
{
3160
    return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
3161
}
3162

    
3163
#endif /* !CONFIG_USER_ONLY */