Statistics
| Branch: | Revision:

root / target-ppc / op_helper.c @ d79f0809

History | View | Annotate | Download (90.4 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
#define VMRG_DO(name, element, highp)                                   \
2035
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
2036
    {                                                                   \
2037
        ppc_avr_t result;                                               \
2038
        int i;                                                          \
2039
        size_t n_elems = ARRAY_SIZE(r->element);                        \
2040
        for (i = 0; i < n_elems/2; i++) {                               \
2041
            if (highp) {                                                \
2042
                result.element[i*2+HI_IDX] = a->element[i];             \
2043
                result.element[i*2+LO_IDX] = b->element[i];             \
2044
            } else {                                                    \
2045
                result.element[n_elems - i*2 - (1+HI_IDX)] = b->element[n_elems - i - 1]; \
2046
                result.element[n_elems - i*2 - (1+LO_IDX)] = a->element[n_elems - i - 1]; \
2047
            }                                                           \
2048
        }                                                               \
2049
        *r = result;                                                    \
2050
    }
2051
#if defined(WORDS_BIGENDIAN)
2052
#define MRGHI 0
2053
#define MRGL0 1
2054
#else
2055
#define MRGHI 1
2056
#define MRGLO 0
2057
#endif
2058
#define VMRG(suffix, element)                   \
2059
  VMRG_DO(mrgl##suffix, element, MRGHI)         \
2060
  VMRG_DO(mrgh##suffix, element, MRGLO)
2061
VMRG(b, u8)
2062
VMRG(h, u16)
2063
VMRG(w, u32)
2064
#undef VMRG_DO
2065
#undef VMRG
2066
#undef MRGHI
2067
#undef MRGLO
2068

    
2069
#define VMUL_DO(name, mul_element, prod_element, evenp)                 \
2070
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
2071
    {                                                                   \
2072
        int i;                                                          \
2073
        VECTOR_FOR_INORDER_I(i, prod_element) {                         \
2074
            if (evenp) {                                                \
2075
                r->prod_element[i] = a->mul_element[i*2+HI_IDX] * b->mul_element[i*2+HI_IDX]; \
2076
            } else {                                                    \
2077
                r->prod_element[i] = a->mul_element[i*2+LO_IDX] * b->mul_element[i*2+LO_IDX]; \
2078
            }                                                           \
2079
        }                                                               \
2080
    }
2081
#define VMUL(suffix, mul_element, prod_element) \
2082
  VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
2083
  VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
2084
VMUL(sb, s8, s16)
2085
VMUL(sh, s16, s32)
2086
VMUL(ub, u8, u16)
2087
VMUL(uh, u16, u32)
2088
#undef VMUL_DO
2089
#undef VMUL
2090

    
2091
#define VSL(suffix, element)                                            \
2092
    void helper_vsl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
2093
    {                                                                   \
2094
        int i;                                                          \
2095
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2096
            unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2097
            unsigned int shift = b->element[i] & mask;                  \
2098
            r->element[i] = a->element[i] << shift;                     \
2099
        }                                                               \
2100
    }
2101
VSL(b, u8)
2102
VSL(h, u16)
2103
VSL(w, u32)
2104
#undef VSL
2105

    
2106
#define VSR(suffix, element)                                            \
2107
    void helper_vsr##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
2108
    {                                                                   \
2109
        int i;                                                          \
2110
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2111
            unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2112
            unsigned int shift = b->element[i] & mask;                  \
2113
            r->element[i] = a->element[i] >> shift;                     \
2114
        }                                                               \
2115
    }
2116
VSR(ab, s8)
2117
VSR(ah, s16)
2118
VSR(aw, s32)
2119
VSR(b, u8)
2120
VSR(h, u16)
2121
VSR(w, u32)
2122
#undef VSR
2123

    
2124
#undef VECTOR_FOR_INORDER_I
2125
#undef HI_IDX
2126
#undef LO_IDX
2127

    
2128
/*****************************************************************************/
2129
/* SPE extension helpers */
2130
/* Use a table to make this quicker */
2131
static uint8_t hbrev[16] = {
2132
    0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
2133
    0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
2134
};
2135

    
2136
static always_inline uint8_t byte_reverse (uint8_t val)
2137
{
2138
    return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
2139
}
2140

    
2141
static always_inline uint32_t word_reverse (uint32_t val)
2142
{
2143
    return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
2144
        (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
2145
}
2146

    
2147
#define MASKBITS 16 // Random value - to be fixed (implementation dependant)
2148
target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
2149
{
2150
    uint32_t a, b, d, mask;
2151

    
2152
    mask = UINT32_MAX >> (32 - MASKBITS);
2153
    a = arg1 & mask;
2154
    b = arg2 & mask;
2155
    d = word_reverse(1 + word_reverse(a | ~b));
2156
    return (arg1 & ~mask) | (d & b);
2157
}
2158

    
2159
uint32_t helper_cntlsw32 (uint32_t val)
2160
{
2161
    if (val & 0x80000000)
2162
        return clz32(~val);
2163
    else
2164
        return clz32(val);
2165
}
2166

    
2167
uint32_t helper_cntlzw32 (uint32_t val)
2168
{
2169
    return clz32(val);
2170
}
2171

    
2172
/* Single-precision floating-point conversions */
2173
static always_inline uint32_t efscfsi (uint32_t val)
2174
{
2175
    CPU_FloatU u;
2176

    
2177
    u.f = int32_to_float32(val, &env->spe_status);
2178

    
2179
    return u.l;
2180
}
2181

    
2182
static always_inline uint32_t efscfui (uint32_t val)
2183
{
2184
    CPU_FloatU u;
2185

    
2186
    u.f = uint32_to_float32(val, &env->spe_status);
2187

    
2188
    return u.l;
2189
}
2190

    
2191
static always_inline int32_t efsctsi (uint32_t val)
2192
{
2193
    CPU_FloatU u;
2194

    
2195
    u.l = val;
2196
    /* NaN are not treated the same way IEEE 754 does */
2197
    if (unlikely(float32_is_nan(u.f)))
2198
        return 0;
2199

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

    
2203
static always_inline uint32_t efsctui (uint32_t val)
2204
{
2205
    CPU_FloatU u;
2206

    
2207
    u.l = val;
2208
    /* NaN are not treated the same way IEEE 754 does */
2209
    if (unlikely(float32_is_nan(u.f)))
2210
        return 0;
2211

    
2212
    return float32_to_uint32(u.f, &env->spe_status);
2213
}
2214

    
2215
static always_inline uint32_t efsctsiz (uint32_t val)
2216
{
2217
    CPU_FloatU u;
2218

    
2219
    u.l = val;
2220
    /* NaN are not treated the same way IEEE 754 does */
2221
    if (unlikely(float32_is_nan(u.f)))
2222
        return 0;
2223

    
2224
    return float32_to_int32_round_to_zero(u.f, &env->spe_status);
2225
}
2226

    
2227
static always_inline uint32_t efsctuiz (uint32_t val)
2228
{
2229
    CPU_FloatU u;
2230

    
2231
    u.l = val;
2232
    /* NaN are not treated the same way IEEE 754 does */
2233
    if (unlikely(float32_is_nan(u.f)))
2234
        return 0;
2235

    
2236
    return float32_to_uint32_round_to_zero(u.f, &env->spe_status);
2237
}
2238

    
2239
static always_inline uint32_t efscfsf (uint32_t val)
2240
{
2241
    CPU_FloatU u;
2242
    float32 tmp;
2243

    
2244
    u.f = int32_to_float32(val, &env->spe_status);
2245
    tmp = int64_to_float32(1ULL << 32, &env->spe_status);
2246
    u.f = float32_div(u.f, tmp, &env->spe_status);
2247

    
2248
    return u.l;
2249
}
2250

    
2251
static always_inline uint32_t efscfuf (uint32_t val)
2252
{
2253
    CPU_FloatU u;
2254
    float32 tmp;
2255

    
2256
    u.f = uint32_to_float32(val, &env->spe_status);
2257
    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2258
    u.f = float32_div(u.f, tmp, &env->spe_status);
2259

    
2260
    return u.l;
2261
}
2262

    
2263
static always_inline uint32_t efsctsf (uint32_t val)
2264
{
2265
    CPU_FloatU u;
2266
    float32 tmp;
2267

    
2268
    u.l = val;
2269
    /* NaN are not treated the same way IEEE 754 does */
2270
    if (unlikely(float32_is_nan(u.f)))
2271
        return 0;
2272
    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2273
    u.f = float32_mul(u.f, tmp, &env->spe_status);
2274

    
2275
    return float32_to_int32(u.f, &env->spe_status);
2276
}
2277

    
2278
static always_inline uint32_t efsctuf (uint32_t val)
2279
{
2280
    CPU_FloatU u;
2281
    float32 tmp;
2282

    
2283
    u.l = val;
2284
    /* NaN are not treated the same way IEEE 754 does */
2285
    if (unlikely(float32_is_nan(u.f)))
2286
        return 0;
2287
    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2288
    u.f = float32_mul(u.f, tmp, &env->spe_status);
2289

    
2290
    return float32_to_uint32(u.f, &env->spe_status);
2291
}
2292

    
2293
#define HELPER_SPE_SINGLE_CONV(name)                                          \
2294
uint32_t helper_e##name (uint32_t val)                                        \
2295
{                                                                             \
2296
    return e##name(val);                                                      \
2297
}
2298
/* efscfsi */
2299
HELPER_SPE_SINGLE_CONV(fscfsi);
2300
/* efscfui */
2301
HELPER_SPE_SINGLE_CONV(fscfui);
2302
/* efscfuf */
2303
HELPER_SPE_SINGLE_CONV(fscfuf);
2304
/* efscfsf */
2305
HELPER_SPE_SINGLE_CONV(fscfsf);
2306
/* efsctsi */
2307
HELPER_SPE_SINGLE_CONV(fsctsi);
2308
/* efsctui */
2309
HELPER_SPE_SINGLE_CONV(fsctui);
2310
/* efsctsiz */
2311
HELPER_SPE_SINGLE_CONV(fsctsiz);
2312
/* efsctuiz */
2313
HELPER_SPE_SINGLE_CONV(fsctuiz);
2314
/* efsctsf */
2315
HELPER_SPE_SINGLE_CONV(fsctsf);
2316
/* efsctuf */
2317
HELPER_SPE_SINGLE_CONV(fsctuf);
2318

    
2319
#define HELPER_SPE_VECTOR_CONV(name)                                          \
2320
uint64_t helper_ev##name (uint64_t val)                                       \
2321
{                                                                             \
2322
    return ((uint64_t)e##name(val >> 32) << 32) |                             \
2323
            (uint64_t)e##name(val);                                           \
2324
}
2325
/* evfscfsi */
2326
HELPER_SPE_VECTOR_CONV(fscfsi);
2327
/* evfscfui */
2328
HELPER_SPE_VECTOR_CONV(fscfui);
2329
/* evfscfuf */
2330
HELPER_SPE_VECTOR_CONV(fscfuf);
2331
/* evfscfsf */
2332
HELPER_SPE_VECTOR_CONV(fscfsf);
2333
/* evfsctsi */
2334
HELPER_SPE_VECTOR_CONV(fsctsi);
2335
/* evfsctui */
2336
HELPER_SPE_VECTOR_CONV(fsctui);
2337
/* evfsctsiz */
2338
HELPER_SPE_VECTOR_CONV(fsctsiz);
2339
/* evfsctuiz */
2340
HELPER_SPE_VECTOR_CONV(fsctuiz);
2341
/* evfsctsf */
2342
HELPER_SPE_VECTOR_CONV(fsctsf);
2343
/* evfsctuf */
2344
HELPER_SPE_VECTOR_CONV(fsctuf);
2345

    
2346
/* Single-precision floating-point arithmetic */
2347
static always_inline uint32_t efsadd (uint32_t op1, uint32_t op2)
2348
{
2349
    CPU_FloatU u1, u2;
2350
    u1.l = op1;
2351
    u2.l = op2;
2352
    u1.f = float32_add(u1.f, u2.f, &env->spe_status);
2353
    return u1.l;
2354
}
2355

    
2356
static always_inline uint32_t efssub (uint32_t op1, uint32_t op2)
2357
{
2358
    CPU_FloatU u1, u2;
2359
    u1.l = op1;
2360
    u2.l = op2;
2361
    u1.f = float32_sub(u1.f, u2.f, &env->spe_status);
2362
    return u1.l;
2363
}
2364

    
2365
static always_inline uint32_t efsmul (uint32_t op1, uint32_t op2)
2366
{
2367
    CPU_FloatU u1, u2;
2368
    u1.l = op1;
2369
    u2.l = op2;
2370
    u1.f = float32_mul(u1.f, u2.f, &env->spe_status);
2371
    return u1.l;
2372
}
2373

    
2374
static always_inline uint32_t efsdiv (uint32_t op1, uint32_t op2)
2375
{
2376
    CPU_FloatU u1, u2;
2377
    u1.l = op1;
2378
    u2.l = op2;
2379
    u1.f = float32_div(u1.f, u2.f, &env->spe_status);
2380
    return u1.l;
2381
}
2382

    
2383
#define HELPER_SPE_SINGLE_ARITH(name)                                         \
2384
uint32_t helper_e##name (uint32_t op1, uint32_t op2)                          \
2385
{                                                                             \
2386
    return e##name(op1, op2);                                                 \
2387
}
2388
/* efsadd */
2389
HELPER_SPE_SINGLE_ARITH(fsadd);
2390
/* efssub */
2391
HELPER_SPE_SINGLE_ARITH(fssub);
2392
/* efsmul */
2393
HELPER_SPE_SINGLE_ARITH(fsmul);
2394
/* efsdiv */
2395
HELPER_SPE_SINGLE_ARITH(fsdiv);
2396

    
2397
#define HELPER_SPE_VECTOR_ARITH(name)                                         \
2398
uint64_t helper_ev##name (uint64_t op1, uint64_t op2)                         \
2399
{                                                                             \
2400
    return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) |                  \
2401
            (uint64_t)e##name(op1, op2);                                      \
2402
}
2403
/* evfsadd */
2404
HELPER_SPE_VECTOR_ARITH(fsadd);
2405
/* evfssub */
2406
HELPER_SPE_VECTOR_ARITH(fssub);
2407
/* evfsmul */
2408
HELPER_SPE_VECTOR_ARITH(fsmul);
2409
/* evfsdiv */
2410
HELPER_SPE_VECTOR_ARITH(fsdiv);
2411

    
2412
/* Single-precision floating-point comparisons */
2413
static always_inline uint32_t efststlt (uint32_t op1, uint32_t op2)
2414
{
2415
    CPU_FloatU u1, u2;
2416
    u1.l = op1;
2417
    u2.l = op2;
2418
    return float32_lt(u1.f, u2.f, &env->spe_status) ? 4 : 0;
2419
}
2420

    
2421
static always_inline uint32_t efststgt (uint32_t op1, uint32_t op2)
2422
{
2423
    CPU_FloatU u1, u2;
2424
    u1.l = op1;
2425
    u2.l = op2;
2426
    return float32_le(u1.f, u2.f, &env->spe_status) ? 0 : 4;
2427
}
2428

    
2429
static always_inline uint32_t efststeq (uint32_t op1, uint32_t op2)
2430
{
2431
    CPU_FloatU u1, u2;
2432
    u1.l = op1;
2433
    u2.l = op2;
2434
    return float32_eq(u1.f, u2.f, &env->spe_status) ? 4 : 0;
2435
}
2436

    
2437
static always_inline uint32_t efscmplt (uint32_t op1, uint32_t op2)
2438
{
2439
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2440
    return efststlt(op1, op2);
2441
}
2442

    
2443
static always_inline uint32_t efscmpgt (uint32_t op1, uint32_t op2)
2444
{
2445
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2446
    return efststgt(op1, op2);
2447
}
2448

    
2449
static always_inline uint32_t efscmpeq (uint32_t op1, uint32_t op2)
2450
{
2451
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2452
    return efststeq(op1, op2);
2453
}
2454

    
2455
#define HELPER_SINGLE_SPE_CMP(name)                                           \
2456
uint32_t helper_e##name (uint32_t op1, uint32_t op2)                          \
2457
{                                                                             \
2458
    return e##name(op1, op2) << 2;                                            \
2459
}
2460
/* efststlt */
2461
HELPER_SINGLE_SPE_CMP(fststlt);
2462
/* efststgt */
2463
HELPER_SINGLE_SPE_CMP(fststgt);
2464
/* efststeq */
2465
HELPER_SINGLE_SPE_CMP(fststeq);
2466
/* efscmplt */
2467
HELPER_SINGLE_SPE_CMP(fscmplt);
2468
/* efscmpgt */
2469
HELPER_SINGLE_SPE_CMP(fscmpgt);
2470
/* efscmpeq */
2471
HELPER_SINGLE_SPE_CMP(fscmpeq);
2472

    
2473
static always_inline uint32_t evcmp_merge (int t0, int t1)
2474
{
2475
    return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
2476
}
2477

    
2478
#define HELPER_VECTOR_SPE_CMP(name)                                           \
2479
uint32_t helper_ev##name (uint64_t op1, uint64_t op2)                         \
2480
{                                                                             \
2481
    return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2));     \
2482
}
2483
/* evfststlt */
2484
HELPER_VECTOR_SPE_CMP(fststlt);
2485
/* evfststgt */
2486
HELPER_VECTOR_SPE_CMP(fststgt);
2487
/* evfststeq */
2488
HELPER_VECTOR_SPE_CMP(fststeq);
2489
/* evfscmplt */
2490
HELPER_VECTOR_SPE_CMP(fscmplt);
2491
/* evfscmpgt */
2492
HELPER_VECTOR_SPE_CMP(fscmpgt);
2493
/* evfscmpeq */
2494
HELPER_VECTOR_SPE_CMP(fscmpeq);
2495

    
2496
/* Double-precision floating-point conversion */
2497
uint64_t helper_efdcfsi (uint32_t val)
2498
{
2499
    CPU_DoubleU u;
2500

    
2501
    u.d = int32_to_float64(val, &env->spe_status);
2502

    
2503
    return u.ll;
2504
}
2505

    
2506
uint64_t helper_efdcfsid (uint64_t val)
2507
{
2508
    CPU_DoubleU u;
2509

    
2510
    u.d = int64_to_float64(val, &env->spe_status);
2511

    
2512
    return u.ll;
2513
}
2514

    
2515
uint64_t helper_efdcfui (uint32_t val)
2516
{
2517
    CPU_DoubleU u;
2518

    
2519
    u.d = uint32_to_float64(val, &env->spe_status);
2520

    
2521
    return u.ll;
2522
}
2523

    
2524
uint64_t helper_efdcfuid (uint64_t val)
2525
{
2526
    CPU_DoubleU u;
2527

    
2528
    u.d = uint64_to_float64(val, &env->spe_status);
2529

    
2530
    return u.ll;
2531
}
2532

    
2533
uint32_t helper_efdctsi (uint64_t val)
2534
{
2535
    CPU_DoubleU u;
2536

    
2537
    u.ll = val;
2538
    /* NaN are not treated the same way IEEE 754 does */
2539
    if (unlikely(float64_is_nan(u.d)))
2540
        return 0;
2541

    
2542
    return float64_to_int32(u.d, &env->spe_status);
2543
}
2544

    
2545
uint32_t helper_efdctui (uint64_t val)
2546
{
2547
    CPU_DoubleU u;
2548

    
2549
    u.ll = val;
2550
    /* NaN are not treated the same way IEEE 754 does */
2551
    if (unlikely(float64_is_nan(u.d)))
2552
        return 0;
2553

    
2554
    return float64_to_uint32(u.d, &env->spe_status);
2555
}
2556

    
2557
uint32_t helper_efdctsiz (uint64_t val)
2558
{
2559
    CPU_DoubleU u;
2560

    
2561
    u.ll = val;
2562
    /* NaN are not treated the same way IEEE 754 does */
2563
    if (unlikely(float64_is_nan(u.d)))
2564
        return 0;
2565

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

    
2569
uint64_t helper_efdctsidz (uint64_t val)
2570
{
2571
    CPU_DoubleU u;
2572

    
2573
    u.ll = val;
2574
    /* NaN are not treated the same way IEEE 754 does */
2575
    if (unlikely(float64_is_nan(u.d)))
2576
        return 0;
2577

    
2578
    return float64_to_int64_round_to_zero(u.d, &env->spe_status);
2579
}
2580

    
2581
uint32_t helper_efdctuiz (uint64_t val)
2582
{
2583
    CPU_DoubleU u;
2584

    
2585
    u.ll = val;
2586
    /* NaN are not treated the same way IEEE 754 does */
2587
    if (unlikely(float64_is_nan(u.d)))
2588
        return 0;
2589

    
2590
    return float64_to_uint32_round_to_zero(u.d, &env->spe_status);
2591
}
2592

    
2593
uint64_t helper_efdctuidz (uint64_t val)
2594
{
2595
    CPU_DoubleU u;
2596

    
2597
    u.ll = val;
2598
    /* NaN are not treated the same way IEEE 754 does */
2599
    if (unlikely(float64_is_nan(u.d)))
2600
        return 0;
2601

    
2602
    return float64_to_uint64_round_to_zero(u.d, &env->spe_status);
2603
}
2604

    
2605
uint64_t helper_efdcfsf (uint32_t val)
2606
{
2607
    CPU_DoubleU u;
2608
    float64 tmp;
2609

    
2610
    u.d = int32_to_float64(val, &env->spe_status);
2611
    tmp = int64_to_float64(1ULL << 32, &env->spe_status);
2612
    u.d = float64_div(u.d, tmp, &env->spe_status);
2613

    
2614
    return u.ll;
2615
}
2616

    
2617
uint64_t helper_efdcfuf (uint32_t val)
2618
{
2619
    CPU_DoubleU u;
2620
    float64 tmp;
2621

    
2622
    u.d = uint32_to_float64(val, &env->spe_status);
2623
    tmp = int64_to_float64(1ULL << 32, &env->spe_status);
2624
    u.d = float64_div(u.d, tmp, &env->spe_status);
2625

    
2626
    return u.ll;
2627
}
2628

    
2629
uint32_t helper_efdctsf (uint64_t val)
2630
{
2631
    CPU_DoubleU u;
2632
    float64 tmp;
2633

    
2634
    u.ll = val;
2635
    /* NaN are not treated the same way IEEE 754 does */
2636
    if (unlikely(float64_is_nan(u.d)))
2637
        return 0;
2638
    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
2639
    u.d = float64_mul(u.d, tmp, &env->spe_status);
2640

    
2641
    return float64_to_int32(u.d, &env->spe_status);
2642
}
2643

    
2644
uint32_t helper_efdctuf (uint64_t val)
2645
{
2646
    CPU_DoubleU u;
2647
    float64 tmp;
2648

    
2649
    u.ll = val;
2650
    /* NaN are not treated the same way IEEE 754 does */
2651
    if (unlikely(float64_is_nan(u.d)))
2652
        return 0;
2653
    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
2654
    u.d = float64_mul(u.d, tmp, &env->spe_status);
2655

    
2656
    return float64_to_uint32(u.d, &env->spe_status);
2657
}
2658

    
2659
uint32_t helper_efscfd (uint64_t val)
2660
{
2661
    CPU_DoubleU u1;
2662
    CPU_FloatU u2;
2663

    
2664
    u1.ll = val;
2665
    u2.f = float64_to_float32(u1.d, &env->spe_status);
2666

    
2667
    return u2.l;
2668
}
2669

    
2670
uint64_t helper_efdcfs (uint32_t val)
2671
{
2672
    CPU_DoubleU u2;
2673
    CPU_FloatU u1;
2674

    
2675
    u1.l = val;
2676
    u2.d = float32_to_float64(u1.f, &env->spe_status);
2677

    
2678
    return u2.ll;
2679
}
2680

    
2681
/* Double precision fixed-point arithmetic */
2682
uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
2683
{
2684
    CPU_DoubleU u1, u2;
2685
    u1.ll = op1;
2686
    u2.ll = op2;
2687
    u1.d = float64_add(u1.d, u2.d, &env->spe_status);
2688
    return u1.ll;
2689
}
2690

    
2691
uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
2692
{
2693
    CPU_DoubleU u1, u2;
2694
    u1.ll = op1;
2695
    u2.ll = op2;
2696
    u1.d = float64_sub(u1.d, u2.d, &env->spe_status);
2697
    return u1.ll;
2698
}
2699

    
2700
uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
2701
{
2702
    CPU_DoubleU u1, u2;
2703
    u1.ll = op1;
2704
    u2.ll = op2;
2705
    u1.d = float64_mul(u1.d, u2.d, &env->spe_status);
2706
    return u1.ll;
2707
}
2708

    
2709
uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
2710
{
2711
    CPU_DoubleU u1, u2;
2712
    u1.ll = op1;
2713
    u2.ll = op2;
2714
    u1.d = float64_div(u1.d, u2.d, &env->spe_status);
2715
    return u1.ll;
2716
}
2717

    
2718
/* Double precision floating point helpers */
2719
uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
2720
{
2721
    CPU_DoubleU u1, u2;
2722
    u1.ll = op1;
2723
    u2.ll = op2;
2724
    return float64_lt(u1.d, u2.d, &env->spe_status) ? 4 : 0;
2725
}
2726

    
2727
uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
2728
{
2729
    CPU_DoubleU u1, u2;
2730
    u1.ll = op1;
2731
    u2.ll = op2;
2732
    return float64_le(u1.d, u2.d, &env->spe_status) ? 0 : 4;
2733
}
2734

    
2735
uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
2736
{
2737
    CPU_DoubleU u1, u2;
2738
    u1.ll = op1;
2739
    u2.ll = op2;
2740
    return float64_eq(u1.d, u2.d, &env->spe_status) ? 4 : 0;
2741
}
2742

    
2743
uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
2744
{
2745
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2746
    return helper_efdtstlt(op1, op2);
2747
}
2748

    
2749
uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
2750
{
2751
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2752
    return helper_efdtstgt(op1, op2);
2753
}
2754

    
2755
uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
2756
{
2757
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2758
    return helper_efdtsteq(op1, op2);
2759
}
2760

    
2761
/*****************************************************************************/
2762
/* Softmmu support */
2763
#if !defined (CONFIG_USER_ONLY)
2764

    
2765
#define MMUSUFFIX _mmu
2766

    
2767
#define SHIFT 0
2768
#include "softmmu_template.h"
2769

    
2770
#define SHIFT 1
2771
#include "softmmu_template.h"
2772

    
2773
#define SHIFT 2
2774
#include "softmmu_template.h"
2775

    
2776
#define SHIFT 3
2777
#include "softmmu_template.h"
2778

    
2779
/* try to fill the TLB and return an exception if error. If retaddr is
2780
   NULL, it means that the function was called in C code (i.e. not
2781
   from generated code or from helper.c) */
2782
/* XXX: fix it to restore all registers */
2783
void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
2784
{
2785
    TranslationBlock *tb;
2786
    CPUState *saved_env;
2787
    unsigned long pc;
2788
    int ret;
2789

    
2790
    /* XXX: hack to restore env in all cases, even if not called from
2791
       generated code */
2792
    saved_env = env;
2793
    env = cpu_single_env;
2794
    ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
2795
    if (unlikely(ret != 0)) {
2796
        if (likely(retaddr)) {
2797
            /* now we have a real cpu fault */
2798
            pc = (unsigned long)retaddr;
2799
            tb = tb_find_pc(pc);
2800
            if (likely(tb)) {
2801
                /* the PC is inside the translated code. It means that we have
2802
                   a virtual CPU fault */
2803
                cpu_restore_state(tb, env, pc, NULL);
2804
            }
2805
        }
2806
        helper_raise_exception_err(env->exception_index, env->error_code);
2807
    }
2808
    env = saved_env;
2809
}
2810

    
2811
/* Segment registers load and store */
2812
target_ulong helper_load_sr (target_ulong sr_num)
2813
{
2814
    return env->sr[sr_num];
2815
}
2816

    
2817
void helper_store_sr (target_ulong sr_num, target_ulong val)
2818
{
2819
    ppc_store_sr(env, sr_num, val);
2820
}
2821

    
2822
/* SLB management */
2823
#if defined(TARGET_PPC64)
2824
target_ulong helper_load_slb (target_ulong slb_nr)
2825
{
2826
    return ppc_load_slb(env, slb_nr);
2827
}
2828

    
2829
void helper_store_slb (target_ulong slb_nr, target_ulong rs)
2830
{
2831
    ppc_store_slb(env, slb_nr, rs);
2832
}
2833

    
2834
void helper_slbia (void)
2835
{
2836
    ppc_slb_invalidate_all(env);
2837
}
2838

    
2839
void helper_slbie (target_ulong addr)
2840
{
2841
    ppc_slb_invalidate_one(env, addr);
2842
}
2843

    
2844
#endif /* defined(TARGET_PPC64) */
2845

    
2846
/* TLB management */
2847
void helper_tlbia (void)
2848
{
2849
    ppc_tlb_invalidate_all(env);
2850
}
2851

    
2852
void helper_tlbie (target_ulong addr)
2853
{
2854
    ppc_tlb_invalidate_one(env, addr);
2855
}
2856

    
2857
/* Software driven TLBs management */
2858
/* PowerPC 602/603 software TLB load instructions helpers */
2859
static void do_6xx_tlb (target_ulong new_EPN, int is_code)
2860
{
2861
    target_ulong RPN, CMP, EPN;
2862
    int way;
2863

    
2864
    RPN = env->spr[SPR_RPA];
2865
    if (is_code) {
2866
        CMP = env->spr[SPR_ICMP];
2867
        EPN = env->spr[SPR_IMISS];
2868
    } else {
2869
        CMP = env->spr[SPR_DCMP];
2870
        EPN = env->spr[SPR_DMISS];
2871
    }
2872
    way = (env->spr[SPR_SRR1] >> 17) & 1;
2873
#if defined (DEBUG_SOFTWARE_TLB)
2874
    if (loglevel != 0) {
2875
        fprintf(logfile, "%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
2876
                " PTE1 " ADDRX " way %d\n",
2877
                __func__, new_EPN, EPN, CMP, RPN, way);
2878
    }
2879
#endif
2880
    /* Store this TLB */
2881
    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2882
                     way, is_code, CMP, RPN);
2883
}
2884

    
2885
void helper_6xx_tlbd (target_ulong EPN)
2886
{
2887
    do_6xx_tlb(EPN, 0);
2888
}
2889

    
2890
void helper_6xx_tlbi (target_ulong EPN)
2891
{
2892
    do_6xx_tlb(EPN, 1);
2893
}
2894

    
2895
/* PowerPC 74xx software TLB load instructions helpers */
2896
static void do_74xx_tlb (target_ulong new_EPN, int is_code)
2897
{
2898
    target_ulong RPN, CMP, EPN;
2899
    int way;
2900

    
2901
    RPN = env->spr[SPR_PTELO];
2902
    CMP = env->spr[SPR_PTEHI];
2903
    EPN = env->spr[SPR_TLBMISS] & ~0x3;
2904
    way = env->spr[SPR_TLBMISS] & 0x3;
2905
#if defined (DEBUG_SOFTWARE_TLB)
2906
    if (loglevel != 0) {
2907
        fprintf(logfile, "%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
2908
                " PTE1 " ADDRX " way %d\n",
2909
                __func__, new_EPN, EPN, CMP, RPN, way);
2910
    }
2911
#endif
2912
    /* Store this TLB */
2913
    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2914
                     way, is_code, CMP, RPN);
2915
}
2916

    
2917
void helper_74xx_tlbd (target_ulong EPN)
2918
{
2919
    do_74xx_tlb(EPN, 0);
2920
}
2921

    
2922
void helper_74xx_tlbi (target_ulong EPN)
2923
{
2924
    do_74xx_tlb(EPN, 1);
2925
}
2926

    
2927
static always_inline target_ulong booke_tlb_to_page_size (int size)
2928
{
2929
    return 1024 << (2 * size);
2930
}
2931

    
2932
static always_inline int booke_page_size_to_tlb (target_ulong page_size)
2933
{
2934
    int size;
2935

    
2936
    switch (page_size) {
2937
    case 0x00000400UL:
2938
        size = 0x0;
2939
        break;
2940
    case 0x00001000UL:
2941
        size = 0x1;
2942
        break;
2943
    case 0x00004000UL:
2944
        size = 0x2;
2945
        break;
2946
    case 0x00010000UL:
2947
        size = 0x3;
2948
        break;
2949
    case 0x00040000UL:
2950
        size = 0x4;
2951
        break;
2952
    case 0x00100000UL:
2953
        size = 0x5;
2954
        break;
2955
    case 0x00400000UL:
2956
        size = 0x6;
2957
        break;
2958
    case 0x01000000UL:
2959
        size = 0x7;
2960
        break;
2961
    case 0x04000000UL:
2962
        size = 0x8;
2963
        break;
2964
    case 0x10000000UL:
2965
        size = 0x9;
2966
        break;
2967
    case 0x40000000UL:
2968
        size = 0xA;
2969
        break;
2970
#if defined (TARGET_PPC64)
2971
    case 0x000100000000ULL:
2972
        size = 0xB;
2973
        break;
2974
    case 0x000400000000ULL:
2975
        size = 0xC;
2976
        break;
2977
    case 0x001000000000ULL:
2978
        size = 0xD;
2979
        break;
2980
    case 0x004000000000ULL:
2981
        size = 0xE;
2982
        break;
2983
    case 0x010000000000ULL:
2984
        size = 0xF;
2985
        break;
2986
#endif
2987
    default:
2988
        size = -1;
2989
        break;
2990
    }
2991

    
2992
    return size;
2993
}
2994

    
2995
/* Helpers for 4xx TLB management */
2996
target_ulong helper_4xx_tlbre_lo (target_ulong entry)
2997
{
2998
    ppcemb_tlb_t *tlb;
2999
    target_ulong ret;
3000
    int size;
3001

    
3002
    entry &= 0x3F;
3003
    tlb = &env->tlb[entry].tlbe;
3004
    ret = tlb->EPN;
3005
    if (tlb->prot & PAGE_VALID)
3006
        ret |= 0x400;
3007
    size = booke_page_size_to_tlb(tlb->size);
3008
    if (size < 0 || size > 0x7)
3009
        size = 1;
3010
    ret |= size << 7;
3011
    env->spr[SPR_40x_PID] = tlb->PID;
3012
    return ret;
3013
}
3014

    
3015
target_ulong helper_4xx_tlbre_hi (target_ulong entry)
3016
{
3017
    ppcemb_tlb_t *tlb;
3018
    target_ulong ret;
3019

    
3020
    entry &= 0x3F;
3021
    tlb = &env->tlb[entry].tlbe;
3022
    ret = tlb->RPN;
3023
    if (tlb->prot & PAGE_EXEC)
3024
        ret |= 0x200;
3025
    if (tlb->prot & PAGE_WRITE)
3026
        ret |= 0x100;
3027
    return ret;
3028
}
3029

    
3030
void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
3031
{
3032
    ppcemb_tlb_t *tlb;
3033
    target_ulong page, end;
3034

    
3035
#if defined (DEBUG_SOFTWARE_TLB)
3036
    if (loglevel != 0) {
3037
        fprintf(logfile, "%s entry %d val " ADDRX "\n", __func__, (int)entry, val);
3038
    }
3039
#endif
3040
    entry &= 0x3F;
3041
    tlb = &env->tlb[entry].tlbe;
3042
    /* Invalidate previous TLB (if it's valid) */
3043
    if (tlb->prot & PAGE_VALID) {
3044
        end = tlb->EPN + tlb->size;
3045
#if defined (DEBUG_SOFTWARE_TLB)
3046
        if (loglevel != 0) {
3047
            fprintf(logfile, "%s: invalidate old TLB %d start " ADDRX
3048
                    " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
3049
        }
3050
#endif
3051
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3052
            tlb_flush_page(env, page);
3053
    }
3054
    tlb->size = booke_tlb_to_page_size((val >> 7) & 0x7);
3055
    /* We cannot handle TLB size < TARGET_PAGE_SIZE.
3056
     * If this ever occurs, one should use the ppcemb target instead
3057
     * of the ppc or ppc64 one
3058
     */
3059
    if ((val & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
3060
        cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
3061
                  "are not supported (%d)\n",
3062
                  tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
3063
    }
3064
    tlb->EPN = val & ~(tlb->size - 1);
3065
    if (val & 0x40)
3066
        tlb->prot |= PAGE_VALID;
3067
    else
3068
        tlb->prot &= ~PAGE_VALID;
3069
    if (val & 0x20) {
3070
        /* XXX: TO BE FIXED */
3071
        cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
3072
    }
3073
    tlb->PID = env->spr[SPR_40x_PID]; /* PID */
3074
    tlb->attr = val & 0xFF;
3075
#if defined (DEBUG_SOFTWARE_TLB)
3076
    if (loglevel != 0) {
3077
        fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
3078
                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
3079
                (int)entry, tlb->RPN, tlb->EPN, tlb->size,
3080
                tlb->prot & PAGE_READ ? 'r' : '-',
3081
                tlb->prot & PAGE_WRITE ? 'w' : '-',
3082
                tlb->prot & PAGE_EXEC ? 'x' : '-',
3083
                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
3084
    }
3085
#endif
3086
    /* Invalidate new TLB (if valid) */
3087
    if (tlb->prot & PAGE_VALID) {
3088
        end = tlb->EPN + tlb->size;
3089
#if defined (DEBUG_SOFTWARE_TLB)
3090
        if (loglevel != 0) {
3091
            fprintf(logfile, "%s: invalidate TLB %d start " ADDRX
3092
                    " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
3093
        }
3094
#endif
3095
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3096
            tlb_flush_page(env, page);
3097
    }
3098
}
3099

    
3100
void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
3101
{
3102
    ppcemb_tlb_t *tlb;
3103

    
3104
#if defined (DEBUG_SOFTWARE_TLB)
3105
    if (loglevel != 0) {
3106
        fprintf(logfile, "%s entry %i val " ADDRX "\n", __func__, (int)entry, val);
3107
    }
3108
#endif
3109
    entry &= 0x3F;
3110
    tlb = &env->tlb[entry].tlbe;
3111
    tlb->RPN = val & 0xFFFFFC00;
3112
    tlb->prot = PAGE_READ;
3113
    if (val & 0x200)
3114
        tlb->prot |= PAGE_EXEC;
3115
    if (val & 0x100)
3116
        tlb->prot |= PAGE_WRITE;
3117
#if defined (DEBUG_SOFTWARE_TLB)
3118
    if (loglevel != 0) {
3119
        fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
3120
                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
3121
                (int)entry, tlb->RPN, tlb->EPN, tlb->size,
3122
                tlb->prot & PAGE_READ ? 'r' : '-',
3123
                tlb->prot & PAGE_WRITE ? 'w' : '-',
3124
                tlb->prot & PAGE_EXEC ? 'x' : '-',
3125
                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
3126
    }
3127
#endif
3128
}
3129

    
3130
target_ulong helper_4xx_tlbsx (target_ulong address)
3131
{
3132
    return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
3133
}
3134

    
3135
/* PowerPC 440 TLB management */
3136
void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
3137
{
3138
    ppcemb_tlb_t *tlb;
3139
    target_ulong EPN, RPN, size;
3140
    int do_flush_tlbs;
3141

    
3142
#if defined (DEBUG_SOFTWARE_TLB)
3143
    if (loglevel != 0) {
3144
        fprintf(logfile, "%s word %d entry %d value " ADDRX "\n",
3145
                __func__, word, (int)entry, value);
3146
    }
3147
#endif
3148
    do_flush_tlbs = 0;
3149
    entry &= 0x3F;
3150
    tlb = &env->tlb[entry].tlbe;
3151
    switch (word) {
3152
    default:
3153
        /* Just here to please gcc */
3154
    case 0:
3155
        EPN = value & 0xFFFFFC00;
3156
        if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
3157
            do_flush_tlbs = 1;
3158
        tlb->EPN = EPN;
3159
        size = booke_tlb_to_page_size((value >> 4) & 0xF);
3160
        if ((tlb->prot & PAGE_VALID) && tlb->size < size)
3161
            do_flush_tlbs = 1;
3162
        tlb->size = size;
3163
        tlb->attr &= ~0x1;
3164
        tlb->attr |= (value >> 8) & 1;
3165
        if (value & 0x200) {
3166
            tlb->prot |= PAGE_VALID;
3167
        } else {
3168
            if (tlb->prot & PAGE_VALID) {
3169
                tlb->prot &= ~PAGE_VALID;
3170
                do_flush_tlbs = 1;
3171
            }
3172
        }
3173
        tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
3174
        if (do_flush_tlbs)
3175
            tlb_flush(env, 1);
3176
        break;
3177
    case 1:
3178
        RPN = value & 0xFFFFFC0F;
3179
        if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
3180
            tlb_flush(env, 1);
3181
        tlb->RPN = RPN;
3182
        break;
3183
    case 2:
3184
        tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
3185
        tlb->prot = tlb->prot & PAGE_VALID;
3186
        if (value & 0x1)
3187
            tlb->prot |= PAGE_READ << 4;
3188
        if (value & 0x2)
3189
            tlb->prot |= PAGE_WRITE << 4;
3190
        if (value & 0x4)
3191
            tlb->prot |= PAGE_EXEC << 4;
3192
        if (value & 0x8)
3193
            tlb->prot |= PAGE_READ;
3194
        if (value & 0x10)
3195
            tlb->prot |= PAGE_WRITE;
3196
        if (value & 0x20)
3197
            tlb->prot |= PAGE_EXEC;
3198
        break;
3199
    }
3200
}
3201

    
3202
target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
3203
{
3204
    ppcemb_tlb_t *tlb;
3205
    target_ulong ret;
3206
    int size;
3207

    
3208
    entry &= 0x3F;
3209
    tlb = &env->tlb[entry].tlbe;
3210
    switch (word) {
3211
    default:
3212
        /* Just here to please gcc */
3213
    case 0:
3214
        ret = tlb->EPN;
3215
        size = booke_page_size_to_tlb(tlb->size);
3216
        if (size < 0 || size > 0xF)
3217
            size = 1;
3218
        ret |= size << 4;
3219
        if (tlb->attr & 0x1)
3220
            ret |= 0x100;
3221
        if (tlb->prot & PAGE_VALID)
3222
            ret |= 0x200;
3223
        env->spr[SPR_440_MMUCR] &= ~0x000000FF;
3224
        env->spr[SPR_440_MMUCR] |= tlb->PID;
3225
        break;
3226
    case 1:
3227
        ret = tlb->RPN;
3228
        break;
3229
    case 2:
3230
        ret = tlb->attr & ~0x1;
3231
        if (tlb->prot & (PAGE_READ << 4))
3232
            ret |= 0x1;
3233
        if (tlb->prot & (PAGE_WRITE << 4))
3234
            ret |= 0x2;
3235
        if (tlb->prot & (PAGE_EXEC << 4))
3236
            ret |= 0x4;
3237
        if (tlb->prot & PAGE_READ)
3238
            ret |= 0x8;
3239
        if (tlb->prot & PAGE_WRITE)
3240
            ret |= 0x10;
3241
        if (tlb->prot & PAGE_EXEC)
3242
            ret |= 0x20;
3243
        break;
3244
    }
3245
    return ret;
3246
}
3247

    
3248
target_ulong helper_440_tlbsx (target_ulong address)
3249
{
3250
    return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
3251
}
3252

    
3253
#endif /* !CONFIG_USER_ONLY */