Statistics
| Branch: | Revision:

root / target-ppc / op_helper.c @ f6b19645

History | View | Annotate | Download (115.1 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 <string.h>
21
#include "exec.h"
22
#include "host-utils.h"
23
#include "helper.h"
24

    
25
#include "helper_regs.h"
26

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

    
31
#ifdef DEBUG_SOFTWARE_TLB
32
#  define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
33
#else
34
#  define LOG_SWTLB(...) do { } while (0)
35
#endif
36

    
37

    
38
/*****************************************************************************/
39
/* Exceptions processing helpers */
40

    
41
void helper_raise_exception_err (uint32_t exception, uint32_t error_code)
42
{
43
#if 0
44
    printf("Raise exception %3x code : %d\n", exception, error_code);
45
#endif
46
    env->exception_index = exception;
47
    env->error_code = error_code;
48
    cpu_loop_exit();
49
}
50

    
51
void helper_raise_exception (uint32_t exception)
52
{
53
    helper_raise_exception_err(exception, 0);
54
}
55

    
56
/*****************************************************************************/
57
/* Registers load and stores */
58
target_ulong helper_load_cr (void)
59
{
60
    return (env->crf[0] << 28) |
61
           (env->crf[1] << 24) |
62
           (env->crf[2] << 20) |
63
           (env->crf[3] << 16) |
64
           (env->crf[4] << 12) |
65
           (env->crf[5] << 8) |
66
           (env->crf[6] << 4) |
67
           (env->crf[7] << 0);
68
}
69

    
70
void helper_store_cr (target_ulong val, uint32_t mask)
71
{
72
    int i, sh;
73

    
74
    for (i = 0, sh = 7; i < 8; i++, sh--) {
75
        if (mask & (1 << sh))
76
            env->crf[i] = (val >> (sh * 4)) & 0xFUL;
77
    }
78
}
79

    
80
/*****************************************************************************/
81
/* SPR accesses */
82
void helper_load_dump_spr (uint32_t sprn)
83
{
84
    qemu_log("Read SPR %d %03x => " ADDRX "\n",
85
                sprn, sprn, env->spr[sprn]);
86
}
87

    
88
void helper_store_dump_spr (uint32_t sprn)
89
{
90
    qemu_log("Write SPR %d %03x <= " ADDRX "\n",
91
                sprn, sprn, env->spr[sprn]);
92
}
93

    
94
target_ulong helper_load_tbl (void)
95
{
96
    return cpu_ppc_load_tbl(env);
97
}
98

    
99
target_ulong helper_load_tbu (void)
100
{
101
    return cpu_ppc_load_tbu(env);
102
}
103

    
104
target_ulong helper_load_atbl (void)
105
{
106
    return cpu_ppc_load_atbl(env);
107
}
108

    
109
target_ulong helper_load_atbu (void)
110
{
111
    return cpu_ppc_load_atbu(env);
112
}
113

    
114
target_ulong helper_load_601_rtcl (void)
115
{
116
    return cpu_ppc601_load_rtcl(env);
117
}
118

    
119
target_ulong helper_load_601_rtcu (void)
120
{
121
    return cpu_ppc601_load_rtcu(env);
122
}
123

    
124
#if !defined(CONFIG_USER_ONLY)
125
#if defined (TARGET_PPC64)
126
void helper_store_asr (target_ulong val)
127
{
128
    ppc_store_asr(env, val);
129
}
130
#endif
131

    
132
void helper_store_sdr1 (target_ulong val)
133
{
134
    ppc_store_sdr1(env, val);
135
}
136

    
137
void helper_store_tbl (target_ulong val)
138
{
139
    cpu_ppc_store_tbl(env, val);
140
}
141

    
142
void helper_store_tbu (target_ulong val)
143
{
144
    cpu_ppc_store_tbu(env, val);
145
}
146

    
147
void helper_store_atbl (target_ulong val)
148
{
149
    cpu_ppc_store_atbl(env, val);
150
}
151

    
152
void helper_store_atbu (target_ulong val)
153
{
154
    cpu_ppc_store_atbu(env, val);
155
}
156

    
157
void helper_store_601_rtcl (target_ulong val)
158
{
159
    cpu_ppc601_store_rtcl(env, val);
160
}
161

    
162
void helper_store_601_rtcu (target_ulong val)
163
{
164
    cpu_ppc601_store_rtcu(env, val);
165
}
166

    
167
target_ulong helper_load_decr (void)
168
{
169
    return cpu_ppc_load_decr(env);
170
}
171

    
172
void helper_store_decr (target_ulong val)
173
{
174
    cpu_ppc_store_decr(env, val);
175
}
176

    
177
void helper_store_hid0_601 (target_ulong val)
178
{
179
    target_ulong hid0;
180

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

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

    
203
target_ulong helper_load_40x_pit (void)
204
{
205
    return load_40x_pit(env);
206
}
207

    
208
void helper_store_40x_pit (target_ulong val)
209
{
210
    store_40x_pit(env, val);
211
}
212

    
213
void helper_store_40x_dbcr0 (target_ulong val)
214
{
215
    store_40x_dbcr0(env, val);
216
}
217

    
218
void helper_store_40x_sler (target_ulong val)
219
{
220
    store_40x_sler(env, val);
221
}
222

    
223
void helper_store_booke_tcr (target_ulong val)
224
{
225
    store_booke_tcr(env, val);
226
}
227

    
228
void helper_store_booke_tsr (target_ulong val)
229
{
230
    store_booke_tsr(env, val);
231
}
232

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

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

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

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

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

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

    
264
/*****************************************************************************/
265
/* Memory load and stores */
266

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

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

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

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

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

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

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

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

    
374
void helper_icbi(target_ulong addr)
375
{
376
    uint32_t tmp;
377

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

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

    
413
/*****************************************************************************/
414
/* Fixed point operations helpers */
415
#if defined(TARGET_PPC64)
416

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

    
422
    muls64(&tl, &th, arg1, arg2);
423
    return th;
424
}
425

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

    
431
    mulu64(&tl, &th, arg1, arg2);
432
    return th;
433
}
434

    
435
uint64_t helper_mulldo (uint64_t arg1, uint64_t arg2)
436
{
437
    int64_t th;
438
    uint64_t tl;
439

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

    
451
target_ulong helper_cntlzw (target_ulong t)
452
{
453
    return clz32(t);
454
}
455

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

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

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

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

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

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

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

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

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

    
560
static always_inline int isden (float64 d)
561
{
562
    CPU_DoubleU u;
563

    
564
    u.d = d;
565

    
566
    return ((u.ll >> 52) & 0x7FF) == 0;
567
}
568

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

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

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

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

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

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

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

    
766
static always_inline void fpscr_set_rounding_mode (void)
767
{
768
    int rnd_type;
769

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

    
793
void helper_fpscr_clrbit (uint32_t bit)
794
{
795
    int prev;
796

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

    
811
void helper_fpscr_setbit (uint32_t bit)
812
{
813
    int prev;
814

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1101
/* fabs */
1102
uint64_t helper_fabs (uint64_t arg)
1103
{
1104
    CPU_DoubleU farg;
1105

    
1106
    farg.ll = arg;
1107
    farg.d = float64_abs(farg.d);
1108
    return farg.ll;
1109
}
1110

    
1111
/* fnabs */
1112
uint64_t helper_fnabs (uint64_t arg)
1113
{
1114
    CPU_DoubleU farg;
1115

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

    
1122
/* fneg */
1123
uint64_t helper_fneg (uint64_t arg)
1124
{
1125
    CPU_DoubleU farg;
1126

    
1127
    farg.ll = arg;
1128
    farg.d = float64_chs(farg.d);
1129
    return farg.ll;
1130
}
1131

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

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

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

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

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

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

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

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

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

    
1225
#endif
1226

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

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

    
1247
uint64_t helper_frin (uint64_t arg)
1248
{
1249
    return do_fri(arg, float_round_nearest_even);
1250
}
1251

    
1252
uint64_t helper_friz (uint64_t arg)
1253
{
1254
    return do_fri(arg, float_round_to_zero);
1255
}
1256

    
1257
uint64_t helper_frip (uint64_t arg)
1258
{
1259
    return do_fri(arg, float_round_up);
1260
}
1261

    
1262
uint64_t helper_frim (uint64_t arg)
1263
{
1264
    return do_fri(arg, float_round_down);
1265
}
1266

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

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

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

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

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

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

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

    
1366
    farg1.ll = arg1;
1367
    farg2.ll = arg2;
1368
    farg3.ll = arg3;
1369

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

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

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

    
1416
    farg1.ll = arg1;
1417
    farg2.ll = arg2;
1418
    farg3.ll = arg3;
1419

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1564
    farg1.ll = arg1;
1565

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1718
/*****************************************************************************/
1719
/* PowerPC 601 specific instructions (POWER bridge) */
1720

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

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

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

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

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

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

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

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

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

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

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

    
1855
/*****************************************************************************/
1856
/* Embedded PowerPC specific helpers */
1857

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

    
1863
    if (unlikely(env->dcr_env == NULL)) {
1864
        qemu_log("No DCR environment\n");
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
        qemu_log("DCR read error %d %03x\n", (int)dcrn, (int)dcrn);
1869
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1870
                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1871
    }
1872
    return val;
1873
}
1874

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

    
1888
#if !defined(CONFIG_USER_ONLY)
1889
void helper_40x_rfci (void)
1890
{
1891
    do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
1892
           ~((target_ulong)0xFFFF0000), 0);
1893
}
1894

    
1895
void helper_rfci (void)
1896
{
1897
    do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
1898
           ~((target_ulong)0x3FFF0000), 0);
1899
}
1900

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

    
1907
void helper_rfmci (void)
1908
{
1909
    do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
1910
           ~((target_ulong)0x3FFF0000), 0);
1911
}
1912
#endif
1913

    
1914
/* 440 specific */
1915
target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_Rc)
1916
{
1917
    target_ulong mask;
1918
    int i;
1919

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

    
1950
/*****************************************************************************/
1951
/* Altivec extension helpers */
1952
#if defined(WORDS_BIGENDIAN)
1953
#define HI_IDX 0
1954
#define LO_IDX 1
1955
#else
1956
#define HI_IDX 1
1957
#define LO_IDX 0
1958
#endif
1959

    
1960
#if defined(WORDS_BIGENDIAN)
1961
#define VECTOR_FOR_INORDER_I(index, element)            \
1962
    for (index = 0; index < ARRAY_SIZE(r->element); index++)
1963
#else
1964
#define VECTOR_FOR_INORDER_I(index, element)            \
1965
  for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
1966
#endif
1967

    
1968
/* If X is a NaN, store the corresponding QNaN into RESULT.  Otherwise,
1969
 * execute the following block.  */
1970
#define DO_HANDLE_NAN(result, x)                \
1971
    if (float32_is_nan(x) || float32_is_signaling_nan(x)) {     \
1972
        CPU_FloatU __f;                                         \
1973
        __f.f = x;                                              \
1974
        __f.l = __f.l | (1 << 22);  /* Set QNaN bit. */         \
1975
        result = __f.f;                                         \
1976
    } else
1977

    
1978
#define HANDLE_NAN1(result, x)                  \
1979
    DO_HANDLE_NAN(result, x)
1980
#define HANDLE_NAN2(result, x, y)               \
1981
    DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y)
1982
#define HANDLE_NAN3(result, x, y, z)            \
1983
    DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) DO_HANDLE_NAN(result, z)
1984

    
1985
/* Saturating arithmetic helpers.  */
1986
#define SATCVT(from, to, from_type, to_type, min, max, use_min, use_max) \
1987
    static always_inline to_type cvt##from##to (from_type x, int *sat)  \
1988
    {                                                                   \
1989
        to_type r;                                                      \
1990
        if (use_min && x < min) {                                       \
1991
            r = min;                                                    \
1992
            *sat = 1;                                                   \
1993
        } else if (use_max && x > max) {                                \
1994
            r = max;                                                    \
1995
            *sat = 1;                                                   \
1996
        } else {                                                        \
1997
            r = x;                                                      \
1998
        }                                                               \
1999
        return r;                                                       \
2000
    }
2001
SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX, 1, 1)
2002
SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX, 1, 1)
2003
SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX, 1, 1)
2004
SATCVT(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX, 0, 1)
2005
SATCVT(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX, 0, 1)
2006
SATCVT(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX, 0, 1)
2007
SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX, 1, 1)
2008
SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX, 1, 1)
2009
SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX, 1, 1)
2010
#undef SATCVT
2011

    
2012
#define LVE(name, access, swap, element)                        \
2013
    void helper_##name (ppc_avr_t *r, target_ulong addr)        \
2014
    {                                                           \
2015
        size_t n_elems = ARRAY_SIZE(r->element);                \
2016
        int adjust = HI_IDX*(n_elems-1);                        \
2017
        int sh = sizeof(r->element[0]) >> 1;                    \
2018
        int index = (addr & 0xf) >> sh;                         \
2019
        if(msr_le) {                                            \
2020
            r->element[LO_IDX ? index : (adjust - index)] = swap(access(addr)); \
2021
        } else {                                                        \
2022
            r->element[LO_IDX ? index : (adjust - index)] = access(addr); \
2023
        }                                                               \
2024
    }
2025
#define I(x) (x)
2026
LVE(lvebx, ldub, I, u8)
2027
LVE(lvehx, lduw, bswap16, u16)
2028
LVE(lvewx, ldl, bswap32, u32)
2029
#undef I
2030
#undef LVE
2031

    
2032
void helper_lvsl (ppc_avr_t *r, target_ulong sh)
2033
{
2034
    int i, j = (sh & 0xf);
2035

    
2036
    VECTOR_FOR_INORDER_I (i, u8) {
2037
        r->u8[i] = j++;
2038
    }
2039
}
2040

    
2041
void helper_lvsr (ppc_avr_t *r, target_ulong sh)
2042
{
2043
    int i, j = 0x10 - (sh & 0xf);
2044

    
2045
    VECTOR_FOR_INORDER_I (i, u8) {
2046
        r->u8[i] = j++;
2047
    }
2048
}
2049

    
2050
#define STVE(name, access, swap, element)                       \
2051
    void helper_##name (ppc_avr_t *r, target_ulong addr)        \
2052
    {                                                           \
2053
        size_t n_elems = ARRAY_SIZE(r->element);                \
2054
        int adjust = HI_IDX*(n_elems-1);                        \
2055
        int sh = sizeof(r->element[0]) >> 1;                    \
2056
        int index = (addr & 0xf) >> sh;                         \
2057
        if(msr_le) {                                            \
2058
            access(addr, swap(r->element[LO_IDX ? index : (adjust - index)])); \
2059
        } else {                                                        \
2060
            access(addr, r->element[LO_IDX ? index : (adjust - index)]); \
2061
        }                                                               \
2062
    }
2063
#define I(x) (x)
2064
STVE(stvebx, stb, I, u8)
2065
STVE(stvehx, stw, bswap16, u16)
2066
STVE(stvewx, stl, bswap32, u32)
2067
#undef I
2068
#undef LVE
2069

    
2070
void helper_mtvscr (ppc_avr_t *r)
2071
{
2072
#if defined(WORDS_BIGENDIAN)
2073
    env->vscr = r->u32[3];
2074
#else
2075
    env->vscr = r->u32[0];
2076
#endif
2077
    set_flush_to_zero(vscr_nj, &env->vec_status);
2078
}
2079

    
2080
void helper_vaddcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2081
{
2082
    int i;
2083
    for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2084
        r->u32[i] = ~a->u32[i] < b->u32[i];
2085
    }
2086
}
2087

    
2088
#define VARITH_DO(name, op, element)        \
2089
void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)          \
2090
{                                                                       \
2091
    int i;                                                              \
2092
    for (i = 0; i < ARRAY_SIZE(r->element); i++) {                      \
2093
        r->element[i] = a->element[i] op b->element[i];                 \
2094
    }                                                                   \
2095
}
2096
#define VARITH(suffix, element)                  \
2097
  VARITH_DO(add##suffix, +, element)             \
2098
  VARITH_DO(sub##suffix, -, element)
2099
VARITH(ubm, u8)
2100
VARITH(uhm, u16)
2101
VARITH(uwm, u32)
2102
#undef VARITH_DO
2103
#undef VARITH
2104

    
2105
#define VARITHSAT_CASE(type, op, cvt, element)                          \
2106
    {                                                                   \
2107
        type result = (type)a->element[i] op (type)b->element[i];       \
2108
        r->element[i] = cvt(result, &sat);                              \
2109
    }
2110

    
2111
#define VARITHSAT_DO(name, op, optype, cvt, element)                    \
2112
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
2113
    {                                                                   \
2114
        int sat = 0;                                                    \
2115
        int i;                                                          \
2116
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2117
            switch (sizeof(r->element[0])) {                            \
2118
            case 1: VARITHSAT_CASE(optype, op, cvt, element); break;    \
2119
            case 2: VARITHSAT_CASE(optype, op, cvt, element); break;    \
2120
            case 4: VARITHSAT_CASE(optype, op, cvt, element); break;    \
2121
            }                                                           \
2122
        }                                                               \
2123
        if (sat) {                                                      \
2124
            env->vscr |= (1 << VSCR_SAT);                               \
2125
        }                                                               \
2126
    }
2127
#define VARITHSAT_SIGNED(suffix, element, optype, cvt)        \
2128
    VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element)    \
2129
    VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element)
2130
#define VARITHSAT_UNSIGNED(suffix, element, optype, cvt)       \
2131
    VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element)     \
2132
    VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element)
2133
VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb)
2134
VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh)
2135
VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw)
2136
VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub)
2137
VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh)
2138
VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw)
2139
#undef VARITHSAT_CASE
2140
#undef VARITHSAT_DO
2141
#undef VARITHSAT_SIGNED
2142
#undef VARITHSAT_UNSIGNED
2143

    
2144
#define VAVG_DO(name, element, etype)                                   \
2145
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
2146
    {                                                                   \
2147
        int i;                                                          \
2148
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2149
            etype x = (etype)a->element[i] + (etype)b->element[i] + 1;  \
2150
            r->element[i] = x >> 1;                                     \
2151
        }                                                               \
2152
    }
2153

    
2154
#define VAVG(type, signed_element, signed_type, unsigned_element, unsigned_type) \
2155
    VAVG_DO(avgs##type, signed_element, signed_type)                    \
2156
    VAVG_DO(avgu##type, unsigned_element, unsigned_type)
2157
VAVG(b, s8, int16_t, u8, uint16_t)
2158
VAVG(h, s16, int32_t, u16, uint32_t)
2159
VAVG(w, s32, int64_t, u32, uint64_t)
2160
#undef VAVG_DO
2161
#undef VAVG
2162

    
2163
#define VCMP_DO(suffix, compare, element, record)                       \
2164
    void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2165
    {                                                                   \
2166
        uint32_t ones = (uint32_t)-1;                                   \
2167
        uint32_t all = ones;                                            \
2168
        uint32_t none = 0;                                              \
2169
        int i;                                                          \
2170
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2171
            uint32_t result = (a->element[i] compare b->element[i] ? ones : 0x0); \
2172
            switch (sizeof (a->element[0])) {                           \
2173
            case 4: r->u32[i] = result; break;                          \
2174
            case 2: r->u16[i] = result; break;                          \
2175
            case 1: r->u8[i] = result; break;                           \
2176
            }                                                           \
2177
            all &= result;                                              \
2178
            none |= result;                                             \
2179
        }                                                               \
2180
        if (record) {                                                   \
2181
            env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1);       \
2182
        }                                                               \
2183
    }
2184
#define VCMP(suffix, compare, element)          \
2185
    VCMP_DO(suffix, compare, element, 0)        \
2186
    VCMP_DO(suffix##_dot, compare, element, 1)
2187
VCMP(equb, ==, u8)
2188
VCMP(equh, ==, u16)
2189
VCMP(equw, ==, u32)
2190
VCMP(gtub, >, u8)
2191
VCMP(gtuh, >, u16)
2192
VCMP(gtuw, >, u32)
2193
VCMP(gtsb, >, s8)
2194
VCMP(gtsh, >, s16)
2195
VCMP(gtsw, >, s32)
2196
#undef VCMP_DO
2197
#undef VCMP
2198

    
2199
void helper_vmhaddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2200
{
2201
    int sat = 0;
2202
    int i;
2203

    
2204
    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2205
        int32_t prod = a->s16[i] * b->s16[i];
2206
        int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2207
        r->s16[i] = cvtswsh (t, &sat);
2208
    }
2209

    
2210
    if (sat) {
2211
        env->vscr |= (1 << VSCR_SAT);
2212
    }
2213
}
2214

    
2215
void helper_vmhraddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2216
{
2217
    int sat = 0;
2218
    int i;
2219

    
2220
    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2221
        int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
2222
        int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2223
        r->s16[i] = cvtswsh (t, &sat);
2224
    }
2225

    
2226
    if (sat) {
2227
        env->vscr |= (1 << VSCR_SAT);
2228
    }
2229
}
2230

    
2231
#define VMINMAX_DO(name, compare, element)                              \
2232
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
2233
    {                                                                   \
2234
        int i;                                                          \
2235
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2236
            if (a->element[i] compare b->element[i]) {                  \
2237
                r->element[i] = b->element[i];                          \
2238
            } else {                                                    \
2239
                r->element[i] = a->element[i];                          \
2240
            }                                                           \
2241
        }                                                               \
2242
    }
2243
#define VMINMAX(suffix, element)                \
2244
  VMINMAX_DO(min##suffix, >, element)           \
2245
  VMINMAX_DO(max##suffix, <, element)
2246
VMINMAX(sb, s8)
2247
VMINMAX(sh, s16)
2248
VMINMAX(sw, s32)
2249
VMINMAX(ub, u8)
2250
VMINMAX(uh, u16)
2251
VMINMAX(uw, u32)
2252
#undef VMINMAX_DO
2253
#undef VMINMAX
2254

    
2255
void helper_vmladduhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2256
{
2257
    int i;
2258
    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2259
        int32_t prod = a->s16[i] * b->s16[i];
2260
        r->s16[i] = (int16_t) (prod + c->s16[i]);
2261
    }
2262
}
2263

    
2264
#define VMRG_DO(name, element, highp)                                   \
2265
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
2266
    {                                                                   \
2267
        ppc_avr_t result;                                               \
2268
        int i;                                                          \
2269
        size_t n_elems = ARRAY_SIZE(r->element);                        \
2270
        for (i = 0; i < n_elems/2; i++) {                               \
2271
            if (highp) {                                                \
2272
                result.element[i*2+HI_IDX] = a->element[i];             \
2273
                result.element[i*2+LO_IDX] = b->element[i];             \
2274
            } else {                                                    \
2275
                result.element[n_elems - i*2 - (1+HI_IDX)] = b->element[n_elems - i - 1]; \
2276
                result.element[n_elems - i*2 - (1+LO_IDX)] = a->element[n_elems - i - 1]; \
2277
            }                                                           \
2278
        }                                                               \
2279
        *r = result;                                                    \
2280
    }
2281
#if defined(WORDS_BIGENDIAN)
2282
#define MRGHI 0
2283
#define MRGLO 1
2284
#else
2285
#define MRGHI 1
2286
#define MRGLO 0
2287
#endif
2288
#define VMRG(suffix, element)                   \
2289
  VMRG_DO(mrgl##suffix, element, MRGHI)         \
2290
  VMRG_DO(mrgh##suffix, element, MRGLO)
2291
VMRG(b, u8)
2292
VMRG(h, u16)
2293
VMRG(w, u32)
2294
#undef VMRG_DO
2295
#undef VMRG
2296
#undef MRGHI
2297
#undef MRGLO
2298

    
2299
void helper_vmsummbm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2300
{
2301
    int32_t prod[16];
2302
    int i;
2303

    
2304
    for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
2305
        prod[i] = (int32_t)a->s8[i] * b->u8[i];
2306
    }
2307

    
2308
    VECTOR_FOR_INORDER_I(i, s32) {
2309
        r->s32[i] = c->s32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2310
    }
2311
}
2312

    
2313
void helper_vmsumshm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2314
{
2315
    int32_t prod[8];
2316
    int i;
2317

    
2318
    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2319
        prod[i] = a->s16[i] * b->s16[i];
2320
    }
2321

    
2322
    VECTOR_FOR_INORDER_I(i, s32) {
2323
        r->s32[i] = c->s32[i] + prod[2*i] + prod[2*i+1];
2324
    }
2325
}
2326

    
2327
void helper_vmsumshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2328
{
2329
    int32_t prod[8];
2330
    int i;
2331
    int sat = 0;
2332

    
2333
    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2334
        prod[i] = (int32_t)a->s16[i] * b->s16[i];
2335
    }
2336

    
2337
    VECTOR_FOR_INORDER_I (i, s32) {
2338
        int64_t t = (int64_t)c->s32[i] + prod[2*i] + prod[2*i+1];
2339
        r->u32[i] = cvtsdsw(t, &sat);
2340
    }
2341

    
2342
    if (sat) {
2343
        env->vscr |= (1 << VSCR_SAT);
2344
    }
2345
}
2346

    
2347
void helper_vmsumubm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2348
{
2349
    uint16_t prod[16];
2350
    int i;
2351

    
2352
    for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2353
        prod[i] = a->u8[i] * b->u8[i];
2354
    }
2355

    
2356
    VECTOR_FOR_INORDER_I(i, u32) {
2357
        r->u32[i] = c->u32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2358
    }
2359
}
2360

    
2361
void helper_vmsumuhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2362
{
2363
    uint32_t prod[8];
2364
    int i;
2365

    
2366
    for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2367
        prod[i] = a->u16[i] * b->u16[i];
2368
    }
2369

    
2370
    VECTOR_FOR_INORDER_I(i, u32) {
2371
        r->u32[i] = c->u32[i] + prod[2*i] + prod[2*i+1];
2372
    }
2373
}
2374

    
2375
void helper_vmsumuhs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2376
{
2377
    uint32_t prod[8];
2378
    int i;
2379
    int sat = 0;
2380

    
2381
    for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2382
        prod[i] = a->u16[i] * b->u16[i];
2383
    }
2384

    
2385
    VECTOR_FOR_INORDER_I (i, s32) {
2386
        uint64_t t = (uint64_t)c->u32[i] + prod[2*i] + prod[2*i+1];
2387
        r->u32[i] = cvtuduw(t, &sat);
2388
    }
2389

    
2390
    if (sat) {
2391
        env->vscr |= (1 << VSCR_SAT);
2392
    }
2393
}
2394

    
2395
#define VMUL_DO(name, mul_element, prod_element, evenp)                 \
2396
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
2397
    {                                                                   \
2398
        int i;                                                          \
2399
        VECTOR_FOR_INORDER_I(i, prod_element) {                         \
2400
            if (evenp) {                                                \
2401
                r->prod_element[i] = a->mul_element[i*2+HI_IDX] * b->mul_element[i*2+HI_IDX]; \
2402
            } else {                                                    \
2403
                r->prod_element[i] = a->mul_element[i*2+LO_IDX] * b->mul_element[i*2+LO_IDX]; \
2404
            }                                                           \
2405
        }                                                               \
2406
    }
2407
#define VMUL(suffix, mul_element, prod_element) \
2408
  VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
2409
  VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
2410
VMUL(sb, s8, s16)
2411
VMUL(sh, s16, s32)
2412
VMUL(ub, u8, u16)
2413
VMUL(uh, u16, u32)
2414
#undef VMUL_DO
2415
#undef VMUL
2416

    
2417
void helper_vperm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2418
{
2419
    ppc_avr_t result;
2420
    int i;
2421
    VECTOR_FOR_INORDER_I (i, u8) {
2422
        int s = c->u8[i] & 0x1f;
2423
#if defined(WORDS_BIGENDIAN)
2424
        int index = s & 0xf;
2425
#else
2426
        int index = 15 - (s & 0xf);
2427
#endif
2428
        if (s & 0x10) {
2429
            result.u8[i] = b->u8[index];
2430
        } else {
2431
            result.u8[i] = a->u8[index];
2432
        }
2433
    }
2434
    *r = result;
2435
}
2436

    
2437
#if defined(WORDS_BIGENDIAN)
2438
#define PKBIG 1
2439
#else
2440
#define PKBIG 0
2441
#endif
2442
void helper_vpkpx (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2443
{
2444
    int i, j;
2445
    ppc_avr_t result;
2446
#if defined(WORDS_BIGENDIAN)
2447
    const ppc_avr_t *x[2] = { a, b };
2448
#else
2449
    const ppc_avr_t *x[2] = { b, a };
2450
#endif
2451

    
2452
    VECTOR_FOR_INORDER_I (i, u64) {
2453
        VECTOR_FOR_INORDER_I (j, u32){
2454
            uint32_t e = x[i]->u32[j];
2455
            result.u16[4*i+j] = (((e >> 9) & 0xfc00) |
2456
                                 ((e >> 6) & 0x3e0) |
2457
                                 ((e >> 3) & 0x1f));
2458
        }
2459
    }
2460
    *r = result;
2461
}
2462

    
2463
#define VPK(suffix, from, to, cvt, dosat)       \
2464
    void helper_vpk##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
2465
    {                                                                   \
2466
        int i;                                                          \
2467
        int sat = 0;                                                    \
2468
        ppc_avr_t result;                                               \
2469
        ppc_avr_t *a0 = PKBIG ? a : b;                                  \
2470
        ppc_avr_t *a1 = PKBIG ? b : a;                                  \
2471
        VECTOR_FOR_INORDER_I (i, from) {                                \
2472
            result.to[i] = cvt(a0->from[i], &sat);                      \
2473
            result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat);  \
2474
        }                                                               \
2475
        *r = result;                                                    \
2476
        if (dosat && sat) {                                             \
2477
            env->vscr |= (1 << VSCR_SAT);                               \
2478
        }                                                               \
2479
    }
2480
#define I(x, y) (x)
2481
VPK(shss, s16, s8, cvtshsb, 1)
2482
VPK(shus, s16, u8, cvtshub, 1)
2483
VPK(swss, s32, s16, cvtswsh, 1)
2484
VPK(swus, s32, u16, cvtswuh, 1)
2485
VPK(uhus, u16, u8, cvtuhub, 1)
2486
VPK(uwus, u32, u16, cvtuwuh, 1)
2487
VPK(uhum, u16, u8, I, 0)
2488
VPK(uwum, u32, u16, I, 0)
2489
#undef I
2490
#undef VPK
2491
#undef PKBIG
2492

    
2493
#define VRFI(suffix, rounding)                                          \
2494
    void helper_vrfi##suffix (ppc_avr_t *r, ppc_avr_t *b)               \
2495
    {                                                                   \
2496
        int i;                                                          \
2497
        float_status s = env->vec_status;                               \
2498
        set_float_rounding_mode(rounding, &s);                          \
2499
        for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
2500
            HANDLE_NAN1(r->f[i], b->f[i]) {                             \
2501
                r->f[i] = float32_round_to_int (b->f[i], &s);           \
2502
            }                                                           \
2503
        }                                                               \
2504
    }
2505
VRFI(n, float_round_nearest_even)
2506
VRFI(m, float_round_down)
2507
VRFI(p, float_round_up)
2508
VRFI(z, float_round_to_zero)
2509
#undef VRFI
2510

    
2511
#define VROTATE(suffix, element)                                        \
2512
    void helper_vrl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
2513
    {                                                                   \
2514
        int i;                                                          \
2515
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2516
            unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2517
            unsigned int shift = b->element[i] & mask;                  \
2518
            r->element[i] = (a->element[i] << shift) | (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
2519
        }                                                               \
2520
    }
2521
VROTATE(b, u8)
2522
VROTATE(h, u16)
2523
VROTATE(w, u32)
2524
#undef VROTATE
2525

    
2526
void helper_vsel (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2527
{
2528
    r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
2529
    r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
2530
}
2531

    
2532
#if defined(WORDS_BIGENDIAN)
2533
#define LEFT 0
2534
#define RIGHT 1
2535
#else
2536
#define LEFT 1
2537
#define RIGHT 0
2538
#endif
2539
/* The specification says that the results are undefined if all of the
2540
 * shift counts are not identical.  We check to make sure that they are
2541
 * to conform to what real hardware appears to do.  */
2542
#define VSHIFT(suffix, leftp)                                           \
2543
    void helper_vs##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)   \
2544
    {                                                                   \
2545
        int shift = b->u8[LO_IDX*0x15] & 0x7;                           \
2546
        int doit = 1;                                                   \
2547
        int i;                                                          \
2548
        for (i = 0; i < ARRAY_SIZE(r->u8); i++) {                       \
2549
            doit = doit && ((b->u8[i] & 0x7) == shift);                 \
2550
        }                                                               \
2551
        if (doit) {                                                     \
2552
            if (shift == 0) {                                           \
2553
                *r = *a;                                                \
2554
            } else if (leftp) {                                         \
2555
                uint64_t carry = a->u64[LO_IDX] >> (64 - shift);        \
2556
                r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry;     \
2557
                r->u64[LO_IDX] = a->u64[LO_IDX] << shift;               \
2558
            } else {                                                    \
2559
                uint64_t carry = a->u64[HI_IDX] << (64 - shift);        \
2560
                r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry;     \
2561
                r->u64[HI_IDX] = a->u64[HI_IDX] >> shift;               \
2562
            }                                                           \
2563
        }                                                               \
2564
    }
2565
VSHIFT(l, LEFT)
2566
VSHIFT(r, RIGHT)
2567
#undef VSHIFT
2568
#undef LEFT
2569
#undef RIGHT
2570

    
2571
#define VSL(suffix, element)                                            \
2572
    void helper_vsl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
2573
    {                                                                   \
2574
        int i;                                                          \
2575
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2576
            unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2577
            unsigned int shift = b->element[i] & mask;                  \
2578
            r->element[i] = a->element[i] << shift;                     \
2579
        }                                                               \
2580
    }
2581
VSL(b, u8)
2582
VSL(h, u16)
2583
VSL(w, u32)
2584
#undef VSL
2585

    
2586
void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
2587
{
2588
    int sh = shift & 0xf;
2589
    int i;
2590
    ppc_avr_t result;
2591

    
2592
#if defined(WORDS_BIGENDIAN)
2593
    for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2594
        int index = sh + i;
2595
        if (index > 0xf) {
2596
            result.u8[i] = b->u8[index-0x10];
2597
        } else {
2598
            result.u8[i] = a->u8[index];
2599
        }
2600
    }
2601
#else
2602
    for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2603
        int index = (16 - sh) + i;
2604
        if (index > 0xf) {
2605
            result.u8[i] = a->u8[index-0x10];
2606
        } else {
2607
            result.u8[i] = b->u8[index];
2608
        }
2609
    }
2610
#endif
2611
    *r = result;
2612
}
2613

    
2614
void helper_vslo (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2615
{
2616
  int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2617

    
2618
#if defined (WORDS_BIGENDIAN)
2619
  memmove (&r->u8[0], &a->u8[sh], 16-sh);
2620
  memset (&r->u8[16-sh], 0, sh);
2621
#else
2622
  memmove (&r->u8[sh], &a->u8[0], 16-sh);
2623
  memset (&r->u8[0], 0, sh);
2624
#endif
2625
}
2626

    
2627
/* Experimental testing shows that hardware masks the immediate.  */
2628
#define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
2629
#if defined(WORDS_BIGENDIAN)
2630
#define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
2631
#else
2632
#define SPLAT_ELEMENT(element) (ARRAY_SIZE(r->element)-1 - _SPLAT_MASKED(element))
2633
#endif
2634
#define VSPLT(suffix, element)                                          \
2635
    void helper_vsplt##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
2636
    {                                                                   \
2637
        uint32_t s = b->element[SPLAT_ELEMENT(element)];                \
2638
        int i;                                                          \
2639
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2640
            r->element[i] = s;                                          \
2641
        }                                                               \
2642
    }
2643
VSPLT(b, u8)
2644
VSPLT(h, u16)
2645
VSPLT(w, u32)
2646
#undef VSPLT
2647
#undef SPLAT_ELEMENT
2648
#undef _SPLAT_MASKED
2649

    
2650
#define VSPLTI(suffix, element, splat_type)                     \
2651
    void helper_vspltis##suffix (ppc_avr_t *r, uint32_t splat)  \
2652
    {                                                           \
2653
        splat_type x = (int8_t)(splat << 3) >> 3;               \
2654
        int i;                                                  \
2655
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {          \
2656
            r->element[i] = x;                                  \
2657
        }                                                       \
2658
    }
2659
VSPLTI(b, s8, int8_t)
2660
VSPLTI(h, s16, int16_t)
2661
VSPLTI(w, s32, int32_t)
2662
#undef VSPLTI
2663

    
2664
#define VSR(suffix, element)                                            \
2665
    void helper_vsr##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
2666
    {                                                                   \
2667
        int i;                                                          \
2668
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2669
            unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2670
            unsigned int shift = b->element[i] & mask;                  \
2671
            r->element[i] = a->element[i] >> shift;                     \
2672
        }                                                               \
2673
    }
2674
VSR(ab, s8)
2675
VSR(ah, s16)
2676
VSR(aw, s32)
2677
VSR(b, u8)
2678
VSR(h, u16)
2679
VSR(w, u32)
2680
#undef VSR
2681

    
2682
void helper_vsro (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2683
{
2684
  int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2685

    
2686
#if defined (WORDS_BIGENDIAN)
2687
  memmove (&r->u8[sh], &a->u8[0], 16-sh);
2688
  memset (&r->u8[0], 0, sh);
2689
#else
2690
  memmove (&r->u8[0], &a->u8[sh], 16-sh);
2691
  memset (&r->u8[16-sh], 0, sh);
2692
#endif
2693
}
2694

    
2695
void helper_vsubcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2696
{
2697
    int i;
2698
    for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2699
        r->u32[i] = a->u32[i] >= b->u32[i];
2700
    }
2701
}
2702

    
2703
void helper_vsumsws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2704
{
2705
    int64_t t;
2706
    int i, upper;
2707
    ppc_avr_t result;
2708
    int sat = 0;
2709

    
2710
#if defined(WORDS_BIGENDIAN)
2711
    upper = ARRAY_SIZE(r->s32)-1;
2712
#else
2713
    upper = 0;
2714
#endif
2715
    t = (int64_t)b->s32[upper];
2716
    for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2717
        t += a->s32[i];
2718
        result.s32[i] = 0;
2719
    }
2720
    result.s32[upper] = cvtsdsw(t, &sat);
2721
    *r = result;
2722

    
2723
    if (sat) {
2724
        env->vscr |= (1 << VSCR_SAT);
2725
    }
2726
}
2727

    
2728
void helper_vsum2sws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2729
{
2730
    int i, j, upper;
2731
    ppc_avr_t result;
2732
    int sat = 0;
2733

    
2734
#if defined(WORDS_BIGENDIAN)
2735
    upper = 1;
2736
#else
2737
    upper = 0;
2738
#endif
2739
    for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
2740
        int64_t t = (int64_t)b->s32[upper+i*2];
2741
        result.u64[i] = 0;
2742
        for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
2743
            t += a->s32[2*i+j];
2744
        }
2745
        result.s32[upper+i*2] = cvtsdsw(t, &sat);
2746
    }
2747

    
2748
    *r = result;
2749
    if (sat) {
2750
        env->vscr |= (1 << VSCR_SAT);
2751
    }
2752
}
2753

    
2754
void helper_vsum4sbs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2755
{
2756
    int i, j;
2757
    int sat = 0;
2758

    
2759
    for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2760
        int64_t t = (int64_t)b->s32[i];
2761
        for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
2762
            t += a->s8[4*i+j];
2763
        }
2764
        r->s32[i] = cvtsdsw(t, &sat);
2765
    }
2766

    
2767
    if (sat) {
2768
        env->vscr |= (1 << VSCR_SAT);
2769
    }
2770
}
2771

    
2772
void helper_vsum4shs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2773
{
2774
    int sat = 0;
2775
    int i;
2776

    
2777
    for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2778
        int64_t t = (int64_t)b->s32[i];
2779
        t += a->s16[2*i] + a->s16[2*i+1];
2780
        r->s32[i] = cvtsdsw(t, &sat);
2781
    }
2782

    
2783
    if (sat) {
2784
        env->vscr |= (1 << VSCR_SAT);
2785
    }
2786
}
2787

    
2788
void helper_vsum4ubs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2789
{
2790
    int i, j;
2791
    int sat = 0;
2792

    
2793
    for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2794
        uint64_t t = (uint64_t)b->u32[i];
2795
        for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
2796
            t += a->u8[4*i+j];
2797
        }
2798
        r->u32[i] = cvtuduw(t, &sat);
2799
    }
2800

    
2801
    if (sat) {
2802
        env->vscr |= (1 << VSCR_SAT);
2803
    }
2804
}
2805

    
2806
#if defined(WORDS_BIGENDIAN)
2807
#define UPKHI 1
2808
#define UPKLO 0
2809
#else
2810
#define UPKHI 0
2811
#define UPKLO 1
2812
#endif
2813
#define VUPKPX(suffix, hi)                                      \
2814
    void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b)       \
2815
    {                                                           \
2816
        int i;                                                  \
2817
        ppc_avr_t result;                                       \
2818
        for (i = 0; i < ARRAY_SIZE(r->u32); i++) {              \
2819
            uint16_t e = b->u16[hi ? i : i+4];                  \
2820
            uint8_t a = (e >> 15) ? 0xff : 0;                   \
2821
            uint8_t r = (e >> 10) & 0x1f;                       \
2822
            uint8_t g = (e >> 5) & 0x1f;                        \
2823
            uint8_t b = e & 0x1f;                               \
2824
            result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b;       \
2825
        }                                                               \
2826
        *r = result;                                                    \
2827
    }
2828
VUPKPX(lpx, UPKLO)
2829
VUPKPX(hpx, UPKHI)
2830
#undef VUPKPX
2831

    
2832
#define VUPK(suffix, unpacked, packee, hi)                              \
2833
    void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b)               \
2834
    {                                                                   \
2835
        int i;                                                          \
2836
        ppc_avr_t result;                                               \
2837
        if (hi) {                                                       \
2838
            for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) {             \
2839
                result.unpacked[i] = b->packee[i];                      \
2840
            }                                                           \
2841
        } else {                                                        \
2842
            for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); i++) { \
2843
                result.unpacked[i-ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
2844
            }                                                           \
2845
        }                                                               \
2846
        *r = result;                                                    \
2847
    }
2848
VUPK(hsb, s16, s8, UPKHI)
2849
VUPK(hsh, s32, s16, UPKHI)
2850
VUPK(lsb, s16, s8, UPKLO)
2851
VUPK(lsh, s32, s16, UPKLO)
2852
#undef VUPK
2853
#undef UPKHI
2854
#undef UPKLO
2855

    
2856
#undef DO_HANDLE_NAN
2857
#undef HANDLE_NAN1
2858
#undef HANDLE_NAN2
2859
#undef HANDLE_NAN3
2860
#undef VECTOR_FOR_INORDER_I
2861
#undef HI_IDX
2862
#undef LO_IDX
2863

    
2864
/*****************************************************************************/
2865
/* SPE extension helpers */
2866
/* Use a table to make this quicker */
2867
static uint8_t hbrev[16] = {
2868
    0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
2869
    0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
2870
};
2871

    
2872
static always_inline uint8_t byte_reverse (uint8_t val)
2873
{
2874
    return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
2875
}
2876

    
2877
static always_inline uint32_t word_reverse (uint32_t val)
2878
{
2879
    return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
2880
        (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
2881
}
2882

    
2883
#define MASKBITS 16 // Random value - to be fixed (implementation dependant)
2884
target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
2885
{
2886
    uint32_t a, b, d, mask;
2887

    
2888
    mask = UINT32_MAX >> (32 - MASKBITS);
2889
    a = arg1 & mask;
2890
    b = arg2 & mask;
2891
    d = word_reverse(1 + word_reverse(a | ~b));
2892
    return (arg1 & ~mask) | (d & b);
2893
}
2894

    
2895
uint32_t helper_cntlsw32 (uint32_t val)
2896
{
2897
    if (val & 0x80000000)
2898
        return clz32(~val);
2899
    else
2900
        return clz32(val);
2901
}
2902

    
2903
uint32_t helper_cntlzw32 (uint32_t val)
2904
{
2905
    return clz32(val);
2906
}
2907

    
2908
/* Single-precision floating-point conversions */
2909
static always_inline uint32_t efscfsi (uint32_t val)
2910
{
2911
    CPU_FloatU u;
2912

    
2913
    u.f = int32_to_float32(val, &env->vec_status);
2914

    
2915
    return u.l;
2916
}
2917

    
2918
static always_inline uint32_t efscfui (uint32_t val)
2919
{
2920
    CPU_FloatU u;
2921

    
2922
    u.f = uint32_to_float32(val, &env->vec_status);
2923

    
2924
    return u.l;
2925
}
2926

    
2927
static always_inline int32_t efsctsi (uint32_t val)
2928
{
2929
    CPU_FloatU u;
2930

    
2931
    u.l = val;
2932
    /* NaN are not treated the same way IEEE 754 does */
2933
    if (unlikely(float32_is_nan(u.f)))
2934
        return 0;
2935

    
2936
    return float32_to_int32(u.f, &env->vec_status);
2937
}
2938

    
2939
static always_inline uint32_t efsctui (uint32_t val)
2940
{
2941
    CPU_FloatU u;
2942

    
2943
    u.l = val;
2944
    /* NaN are not treated the same way IEEE 754 does */
2945
    if (unlikely(float32_is_nan(u.f)))
2946
        return 0;
2947

    
2948
    return float32_to_uint32(u.f, &env->vec_status);
2949
}
2950

    
2951
static always_inline uint32_t efsctsiz (uint32_t val)
2952
{
2953
    CPU_FloatU u;
2954

    
2955
    u.l = val;
2956
    /* NaN are not treated the same way IEEE 754 does */
2957
    if (unlikely(float32_is_nan(u.f)))
2958
        return 0;
2959

    
2960
    return float32_to_int32_round_to_zero(u.f, &env->vec_status);
2961
}
2962

    
2963
static always_inline uint32_t efsctuiz (uint32_t val)
2964
{
2965
    CPU_FloatU u;
2966

    
2967
    u.l = val;
2968
    /* NaN are not treated the same way IEEE 754 does */
2969
    if (unlikely(float32_is_nan(u.f)))
2970
        return 0;
2971

    
2972
    return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
2973
}
2974

    
2975
static always_inline uint32_t efscfsf (uint32_t val)
2976
{
2977
    CPU_FloatU u;
2978
    float32 tmp;
2979

    
2980
    u.f = int32_to_float32(val, &env->vec_status);
2981
    tmp = int64_to_float32(1ULL << 32, &env->vec_status);
2982
    u.f = float32_div(u.f, tmp, &env->vec_status);
2983

    
2984
    return u.l;
2985
}
2986

    
2987
static always_inline uint32_t efscfuf (uint32_t val)
2988
{
2989
    CPU_FloatU u;
2990
    float32 tmp;
2991

    
2992
    u.f = uint32_to_float32(val, &env->vec_status);
2993
    tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
2994
    u.f = float32_div(u.f, tmp, &env->vec_status);
2995

    
2996
    return u.l;
2997
}
2998

    
2999
static always_inline uint32_t efsctsf (uint32_t val)
3000
{
3001
    CPU_FloatU u;
3002
    float32 tmp;
3003

    
3004
    u.l = val;
3005
    /* NaN are not treated the same way IEEE 754 does */
3006
    if (unlikely(float32_is_nan(u.f)))
3007
        return 0;
3008
    tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3009
    u.f = float32_mul(u.f, tmp, &env->vec_status);
3010

    
3011
    return float32_to_int32(u.f, &env->vec_status);
3012
}
3013

    
3014
static always_inline uint32_t efsctuf (uint32_t val)
3015
{
3016
    CPU_FloatU u;
3017
    float32 tmp;
3018

    
3019
    u.l = val;
3020
    /* NaN are not treated the same way IEEE 754 does */
3021
    if (unlikely(float32_is_nan(u.f)))
3022
        return 0;
3023
    tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3024
    u.f = float32_mul(u.f, tmp, &env->vec_status);
3025

    
3026
    return float32_to_uint32(u.f, &env->vec_status);
3027
}
3028

    
3029
#define HELPER_SPE_SINGLE_CONV(name)                                          \
3030
uint32_t helper_e##name (uint32_t val)                                        \
3031
{                                                                             \
3032
    return e##name(val);                                                      \
3033
}
3034
/* efscfsi */
3035
HELPER_SPE_SINGLE_CONV(fscfsi);
3036
/* efscfui */
3037
HELPER_SPE_SINGLE_CONV(fscfui);
3038
/* efscfuf */
3039
HELPER_SPE_SINGLE_CONV(fscfuf);
3040
/* efscfsf */
3041
HELPER_SPE_SINGLE_CONV(fscfsf);
3042
/* efsctsi */
3043
HELPER_SPE_SINGLE_CONV(fsctsi);
3044
/* efsctui */
3045
HELPER_SPE_SINGLE_CONV(fsctui);
3046
/* efsctsiz */
3047
HELPER_SPE_SINGLE_CONV(fsctsiz);
3048
/* efsctuiz */
3049
HELPER_SPE_SINGLE_CONV(fsctuiz);
3050
/* efsctsf */
3051
HELPER_SPE_SINGLE_CONV(fsctsf);
3052
/* efsctuf */
3053
HELPER_SPE_SINGLE_CONV(fsctuf);
3054

    
3055
#define HELPER_SPE_VECTOR_CONV(name)                                          \
3056
uint64_t helper_ev##name (uint64_t val)                                       \
3057
{                                                                             \
3058
    return ((uint64_t)e##name(val >> 32) << 32) |                             \
3059
            (uint64_t)e##name(val);                                           \
3060
}
3061
/* evfscfsi */
3062
HELPER_SPE_VECTOR_CONV(fscfsi);
3063
/* evfscfui */
3064
HELPER_SPE_VECTOR_CONV(fscfui);
3065
/* evfscfuf */
3066
HELPER_SPE_VECTOR_CONV(fscfuf);
3067
/* evfscfsf */
3068
HELPER_SPE_VECTOR_CONV(fscfsf);
3069
/* evfsctsi */
3070
HELPER_SPE_VECTOR_CONV(fsctsi);
3071
/* evfsctui */
3072
HELPER_SPE_VECTOR_CONV(fsctui);
3073
/* evfsctsiz */
3074
HELPER_SPE_VECTOR_CONV(fsctsiz);
3075
/* evfsctuiz */
3076
HELPER_SPE_VECTOR_CONV(fsctuiz);
3077
/* evfsctsf */
3078
HELPER_SPE_VECTOR_CONV(fsctsf);
3079
/* evfsctuf */
3080
HELPER_SPE_VECTOR_CONV(fsctuf);
3081

    
3082
/* Single-precision floating-point arithmetic */
3083
static always_inline uint32_t efsadd (uint32_t op1, uint32_t op2)
3084
{
3085
    CPU_FloatU u1, u2;
3086
    u1.l = op1;
3087
    u2.l = op2;
3088
    u1.f = float32_add(u1.f, u2.f, &env->vec_status);
3089
    return u1.l;
3090
}
3091

    
3092
static always_inline uint32_t efssub (uint32_t op1, uint32_t op2)
3093
{
3094
    CPU_FloatU u1, u2;
3095
    u1.l = op1;
3096
    u2.l = op2;
3097
    u1.f = float32_sub(u1.f, u2.f, &env->vec_status);
3098
    return u1.l;
3099
}
3100

    
3101
static always_inline uint32_t efsmul (uint32_t op1, uint32_t op2)
3102
{
3103
    CPU_FloatU u1, u2;
3104
    u1.l = op1;
3105
    u2.l = op2;
3106
    u1.f = float32_mul(u1.f, u2.f, &env->vec_status);
3107
    return u1.l;
3108
}
3109

    
3110
static always_inline uint32_t efsdiv (uint32_t op1, uint32_t op2)
3111
{
3112
    CPU_FloatU u1, u2;
3113
    u1.l = op1;
3114
    u2.l = op2;
3115
    u1.f = float32_div(u1.f, u2.f, &env->vec_status);
3116
    return u1.l;
3117
}
3118

    
3119
#define HELPER_SPE_SINGLE_ARITH(name)                                         \
3120
uint32_t helper_e##name (uint32_t op1, uint32_t op2)                          \
3121
{                                                                             \
3122
    return e##name(op1, op2);                                                 \
3123
}
3124
/* efsadd */
3125
HELPER_SPE_SINGLE_ARITH(fsadd);
3126
/* efssub */
3127
HELPER_SPE_SINGLE_ARITH(fssub);
3128
/* efsmul */
3129
HELPER_SPE_SINGLE_ARITH(fsmul);
3130
/* efsdiv */
3131
HELPER_SPE_SINGLE_ARITH(fsdiv);
3132

    
3133
#define HELPER_SPE_VECTOR_ARITH(name)                                         \
3134
uint64_t helper_ev##name (uint64_t op1, uint64_t op2)                         \
3135
{                                                                             \
3136
    return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) |                  \
3137
            (uint64_t)e##name(op1, op2);                                      \
3138
}
3139
/* evfsadd */
3140
HELPER_SPE_VECTOR_ARITH(fsadd);
3141
/* evfssub */
3142
HELPER_SPE_VECTOR_ARITH(fssub);
3143
/* evfsmul */
3144
HELPER_SPE_VECTOR_ARITH(fsmul);
3145
/* evfsdiv */
3146
HELPER_SPE_VECTOR_ARITH(fsdiv);
3147

    
3148
/* Single-precision floating-point comparisons */
3149
static always_inline uint32_t efststlt (uint32_t op1, uint32_t op2)
3150
{
3151
    CPU_FloatU u1, u2;
3152
    u1.l = op1;
3153
    u2.l = op2;
3154
    return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0;
3155
}
3156

    
3157
static always_inline uint32_t efststgt (uint32_t op1, uint32_t op2)
3158
{
3159
    CPU_FloatU u1, u2;
3160
    u1.l = op1;
3161
    u2.l = op2;
3162
    return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4;
3163
}
3164

    
3165
static always_inline uint32_t efststeq (uint32_t op1, uint32_t op2)
3166
{
3167
    CPU_FloatU u1, u2;
3168
    u1.l = op1;
3169
    u2.l = op2;
3170
    return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0;
3171
}
3172

    
3173
static always_inline uint32_t efscmplt (uint32_t op1, uint32_t op2)
3174
{
3175
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3176
    return efststlt(op1, op2);
3177
}
3178

    
3179
static always_inline uint32_t efscmpgt (uint32_t op1, uint32_t op2)
3180
{
3181
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3182
    return efststgt(op1, op2);
3183
}
3184

    
3185
static always_inline uint32_t efscmpeq (uint32_t op1, uint32_t op2)
3186
{
3187
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3188
    return efststeq(op1, op2);
3189
}
3190

    
3191
#define HELPER_SINGLE_SPE_CMP(name)                                           \
3192
uint32_t helper_e##name (uint32_t op1, uint32_t op2)                          \
3193
{                                                                             \
3194
    return e##name(op1, op2) << 2;                                            \
3195
}
3196
/* efststlt */
3197
HELPER_SINGLE_SPE_CMP(fststlt);
3198
/* efststgt */
3199
HELPER_SINGLE_SPE_CMP(fststgt);
3200
/* efststeq */
3201
HELPER_SINGLE_SPE_CMP(fststeq);
3202
/* efscmplt */
3203
HELPER_SINGLE_SPE_CMP(fscmplt);
3204
/* efscmpgt */
3205
HELPER_SINGLE_SPE_CMP(fscmpgt);
3206
/* efscmpeq */
3207
HELPER_SINGLE_SPE_CMP(fscmpeq);
3208

    
3209
static always_inline uint32_t evcmp_merge (int t0, int t1)
3210
{
3211
    return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
3212
}
3213

    
3214
#define HELPER_VECTOR_SPE_CMP(name)                                           \
3215
uint32_t helper_ev##name (uint64_t op1, uint64_t op2)                         \
3216
{                                                                             \
3217
    return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2));     \
3218
}
3219
/* evfststlt */
3220
HELPER_VECTOR_SPE_CMP(fststlt);
3221
/* evfststgt */
3222
HELPER_VECTOR_SPE_CMP(fststgt);
3223
/* evfststeq */
3224
HELPER_VECTOR_SPE_CMP(fststeq);
3225
/* evfscmplt */
3226
HELPER_VECTOR_SPE_CMP(fscmplt);
3227
/* evfscmpgt */
3228
HELPER_VECTOR_SPE_CMP(fscmpgt);
3229
/* evfscmpeq */
3230
HELPER_VECTOR_SPE_CMP(fscmpeq);
3231

    
3232
/* Double-precision floating-point conversion */
3233
uint64_t helper_efdcfsi (uint32_t val)
3234
{
3235
    CPU_DoubleU u;
3236

    
3237
    u.d = int32_to_float64(val, &env->vec_status);
3238

    
3239
    return u.ll;
3240
}
3241

    
3242
uint64_t helper_efdcfsid (uint64_t val)
3243
{
3244
    CPU_DoubleU u;
3245

    
3246
    u.d = int64_to_float64(val, &env->vec_status);
3247

    
3248
    return u.ll;
3249
}
3250

    
3251
uint64_t helper_efdcfui (uint32_t val)
3252
{
3253
    CPU_DoubleU u;
3254

    
3255
    u.d = uint32_to_float64(val, &env->vec_status);
3256

    
3257
    return u.ll;
3258
}
3259

    
3260
uint64_t helper_efdcfuid (uint64_t val)
3261
{
3262
    CPU_DoubleU u;
3263

    
3264
    u.d = uint64_to_float64(val, &env->vec_status);
3265

    
3266
    return u.ll;
3267
}
3268

    
3269
uint32_t helper_efdctsi (uint64_t val)
3270
{
3271
    CPU_DoubleU u;
3272

    
3273
    u.ll = val;
3274
    /* NaN are not treated the same way IEEE 754 does */
3275
    if (unlikely(float64_is_nan(u.d)))
3276
        return 0;
3277

    
3278
    return float64_to_int32(u.d, &env->vec_status);
3279
}
3280

    
3281
uint32_t helper_efdctui (uint64_t val)
3282
{
3283
    CPU_DoubleU u;
3284

    
3285
    u.ll = val;
3286
    /* NaN are not treated the same way IEEE 754 does */
3287
    if (unlikely(float64_is_nan(u.d)))
3288
        return 0;
3289

    
3290
    return float64_to_uint32(u.d, &env->vec_status);
3291
}
3292

    
3293
uint32_t helper_efdctsiz (uint64_t val)
3294
{
3295
    CPU_DoubleU u;
3296

    
3297
    u.ll = val;
3298
    /* NaN are not treated the same way IEEE 754 does */
3299
    if (unlikely(float64_is_nan(u.d)))
3300
        return 0;
3301

    
3302
    return float64_to_int32_round_to_zero(u.d, &env->vec_status);
3303
}
3304

    
3305
uint64_t helper_efdctsidz (uint64_t val)
3306
{
3307
    CPU_DoubleU u;
3308

    
3309
    u.ll = val;
3310
    /* NaN are not treated the same way IEEE 754 does */
3311
    if (unlikely(float64_is_nan(u.d)))
3312
        return 0;
3313

    
3314
    return float64_to_int64_round_to_zero(u.d, &env->vec_status);
3315
}
3316

    
3317
uint32_t helper_efdctuiz (uint64_t val)
3318
{
3319
    CPU_DoubleU u;
3320

    
3321
    u.ll = val;
3322
    /* NaN are not treated the same way IEEE 754 does */
3323
    if (unlikely(float64_is_nan(u.d)))
3324
        return 0;
3325

    
3326
    return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
3327
}
3328

    
3329
uint64_t helper_efdctuidz (uint64_t val)
3330
{
3331
    CPU_DoubleU u;
3332

    
3333
    u.ll = val;
3334
    /* NaN are not treated the same way IEEE 754 does */
3335
    if (unlikely(float64_is_nan(u.d)))
3336
        return 0;
3337

    
3338
    return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
3339
}
3340

    
3341
uint64_t helper_efdcfsf (uint32_t val)
3342
{
3343
    CPU_DoubleU u;
3344
    float64 tmp;
3345

    
3346
    u.d = int32_to_float64(val, &env->vec_status);
3347
    tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3348
    u.d = float64_div(u.d, tmp, &env->vec_status);
3349

    
3350
    return u.ll;
3351
}
3352

    
3353
uint64_t helper_efdcfuf (uint32_t val)
3354
{
3355
    CPU_DoubleU u;
3356
    float64 tmp;
3357

    
3358
    u.d = uint32_to_float64(val, &env->vec_status);
3359
    tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3360
    u.d = float64_div(u.d, tmp, &env->vec_status);
3361

    
3362
    return u.ll;
3363
}
3364

    
3365
uint32_t helper_efdctsf (uint64_t val)
3366
{
3367
    CPU_DoubleU u;
3368
    float64 tmp;
3369

    
3370
    u.ll = val;
3371
    /* NaN are not treated the same way IEEE 754 does */
3372
    if (unlikely(float64_is_nan(u.d)))
3373
        return 0;
3374
    tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3375
    u.d = float64_mul(u.d, tmp, &env->vec_status);
3376

    
3377
    return float64_to_int32(u.d, &env->vec_status);
3378
}
3379

    
3380
uint32_t helper_efdctuf (uint64_t val)
3381
{
3382
    CPU_DoubleU u;
3383
    float64 tmp;
3384

    
3385
    u.ll = val;
3386
    /* NaN are not treated the same way IEEE 754 does */
3387
    if (unlikely(float64_is_nan(u.d)))
3388
        return 0;
3389
    tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3390
    u.d = float64_mul(u.d, tmp, &env->vec_status);
3391

    
3392
    return float64_to_uint32(u.d, &env->vec_status);
3393
}
3394

    
3395
uint32_t helper_efscfd (uint64_t val)
3396
{
3397
    CPU_DoubleU u1;
3398
    CPU_FloatU u2;
3399

    
3400
    u1.ll = val;
3401
    u2.f = float64_to_float32(u1.d, &env->vec_status);
3402

    
3403
    return u2.l;
3404
}
3405

    
3406
uint64_t helper_efdcfs (uint32_t val)
3407
{
3408
    CPU_DoubleU u2;
3409
    CPU_FloatU u1;
3410

    
3411
    u1.l = val;
3412
    u2.d = float32_to_float64(u1.f, &env->vec_status);
3413

    
3414
    return u2.ll;
3415
}
3416

    
3417
/* Double precision fixed-point arithmetic */
3418
uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
3419
{
3420
    CPU_DoubleU u1, u2;
3421
    u1.ll = op1;
3422
    u2.ll = op2;
3423
    u1.d = float64_add(u1.d, u2.d, &env->vec_status);
3424
    return u1.ll;
3425
}
3426

    
3427
uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
3428
{
3429
    CPU_DoubleU u1, u2;
3430
    u1.ll = op1;
3431
    u2.ll = op2;
3432
    u1.d = float64_sub(u1.d, u2.d, &env->vec_status);
3433
    return u1.ll;
3434
}
3435

    
3436
uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
3437
{
3438
    CPU_DoubleU u1, u2;
3439
    u1.ll = op1;
3440
    u2.ll = op2;
3441
    u1.d = float64_mul(u1.d, u2.d, &env->vec_status);
3442
    return u1.ll;
3443
}
3444

    
3445
uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
3446
{
3447
    CPU_DoubleU u1, u2;
3448
    u1.ll = op1;
3449
    u2.ll = op2;
3450
    u1.d = float64_div(u1.d, u2.d, &env->vec_status);
3451
    return u1.ll;
3452
}
3453

    
3454
/* Double precision floating point helpers */
3455
uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
3456
{
3457
    CPU_DoubleU u1, u2;
3458
    u1.ll = op1;
3459
    u2.ll = op2;
3460
    return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0;
3461
}
3462

    
3463
uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
3464
{
3465
    CPU_DoubleU u1, u2;
3466
    u1.ll = op1;
3467
    u2.ll = op2;
3468
    return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4;
3469
}
3470

    
3471
uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
3472
{
3473
    CPU_DoubleU u1, u2;
3474
    u1.ll = op1;
3475
    u2.ll = op2;
3476
    return float64_eq(u1.d, u2.d, &env->vec_status) ? 4 : 0;
3477
}
3478

    
3479
uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
3480
{
3481
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3482
    return helper_efdtstlt(op1, op2);
3483
}
3484

    
3485
uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
3486
{
3487
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3488
    return helper_efdtstgt(op1, op2);
3489
}
3490

    
3491
uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
3492
{
3493
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3494
    return helper_efdtsteq(op1, op2);
3495
}
3496

    
3497
/*****************************************************************************/
3498
/* Softmmu support */
3499
#if !defined (CONFIG_USER_ONLY)
3500

    
3501
#define MMUSUFFIX _mmu
3502

    
3503
#define SHIFT 0
3504
#include "softmmu_template.h"
3505

    
3506
#define SHIFT 1
3507
#include "softmmu_template.h"
3508

    
3509
#define SHIFT 2
3510
#include "softmmu_template.h"
3511

    
3512
#define SHIFT 3
3513
#include "softmmu_template.h"
3514

    
3515
/* try to fill the TLB and return an exception if error. If retaddr is
3516
   NULL, it means that the function was called in C code (i.e. not
3517
   from generated code or from helper.c) */
3518
/* XXX: fix it to restore all registers */
3519
void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
3520
{
3521
    TranslationBlock *tb;
3522
    CPUState *saved_env;
3523
    unsigned long pc;
3524
    int ret;
3525

    
3526
    /* XXX: hack to restore env in all cases, even if not called from
3527
       generated code */
3528
    saved_env = env;
3529
    env = cpu_single_env;
3530
    ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
3531
    if (unlikely(ret != 0)) {
3532
        if (likely(retaddr)) {
3533
            /* now we have a real cpu fault */
3534
            pc = (unsigned long)retaddr;
3535
            tb = tb_find_pc(pc);
3536
            if (likely(tb)) {
3537
                /* the PC is inside the translated code. It means that we have
3538
                   a virtual CPU fault */
3539
                cpu_restore_state(tb, env, pc, NULL);
3540
            }
3541
        }
3542
        helper_raise_exception_err(env->exception_index, env->error_code);
3543
    }
3544
    env = saved_env;
3545
}
3546

    
3547
/* Segment registers load and store */
3548
target_ulong helper_load_sr (target_ulong sr_num)
3549
{
3550
    return env->sr[sr_num];
3551
}
3552

    
3553
void helper_store_sr (target_ulong sr_num, target_ulong val)
3554
{
3555
    ppc_store_sr(env, sr_num, val);
3556
}
3557

    
3558
/* SLB management */
3559
#if defined(TARGET_PPC64)
3560
target_ulong helper_load_slb (target_ulong slb_nr)
3561
{
3562
    return ppc_load_slb(env, slb_nr);
3563
}
3564

    
3565
void helper_store_slb (target_ulong slb_nr, target_ulong rs)
3566
{
3567
    ppc_store_slb(env, slb_nr, rs);
3568
}
3569

    
3570
void helper_slbia (void)
3571
{
3572
    ppc_slb_invalidate_all(env);
3573
}
3574

    
3575
void helper_slbie (target_ulong addr)
3576
{
3577
    ppc_slb_invalidate_one(env, addr);
3578
}
3579

    
3580
#endif /* defined(TARGET_PPC64) */
3581

    
3582
/* TLB management */
3583
void helper_tlbia (void)
3584
{
3585
    ppc_tlb_invalidate_all(env);
3586
}
3587

    
3588
void helper_tlbie (target_ulong addr)
3589
{
3590
    ppc_tlb_invalidate_one(env, addr);
3591
}
3592

    
3593
/* Software driven TLBs management */
3594
/* PowerPC 602/603 software TLB load instructions helpers */
3595
static void do_6xx_tlb (target_ulong new_EPN, int is_code)
3596
{
3597
    target_ulong RPN, CMP, EPN;
3598
    int way;
3599

    
3600
    RPN = env->spr[SPR_RPA];
3601
    if (is_code) {
3602
        CMP = env->spr[SPR_ICMP];
3603
        EPN = env->spr[SPR_IMISS];
3604
    } else {
3605
        CMP = env->spr[SPR_DCMP];
3606
        EPN = env->spr[SPR_DMISS];
3607
    }
3608
    way = (env->spr[SPR_SRR1] >> 17) & 1;
3609
    LOG_SWTLB("%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
3610
                " PTE1 " ADDRX " way %d\n",
3611
                __func__, new_EPN, EPN, CMP, RPN, way);
3612
    /* Store this TLB */
3613
    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3614
                     way, is_code, CMP, RPN);
3615
}
3616

    
3617
void helper_6xx_tlbd (target_ulong EPN)
3618
{
3619
    do_6xx_tlb(EPN, 0);
3620
}
3621

    
3622
void helper_6xx_tlbi (target_ulong EPN)
3623
{
3624
    do_6xx_tlb(EPN, 1);
3625
}
3626

    
3627
/* PowerPC 74xx software TLB load instructions helpers */
3628
static void do_74xx_tlb (target_ulong new_EPN, int is_code)
3629
{
3630
    target_ulong RPN, CMP, EPN;
3631
    int way;
3632

    
3633
    RPN = env->spr[SPR_PTELO];
3634
    CMP = env->spr[SPR_PTEHI];
3635
    EPN = env->spr[SPR_TLBMISS] & ~0x3;
3636
    way = env->spr[SPR_TLBMISS] & 0x3;
3637
    LOG_SWTLB("%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
3638
                " PTE1 " ADDRX " way %d\n",
3639
                __func__, new_EPN, EPN, CMP, RPN, way);
3640
    /* Store this TLB */
3641
    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3642
                     way, is_code, CMP, RPN);
3643
}
3644

    
3645
void helper_74xx_tlbd (target_ulong EPN)
3646
{
3647
    do_74xx_tlb(EPN, 0);
3648
}
3649

    
3650
void helper_74xx_tlbi (target_ulong EPN)
3651
{
3652
    do_74xx_tlb(EPN, 1);
3653
}
3654

    
3655
static always_inline target_ulong booke_tlb_to_page_size (int size)
3656
{
3657
    return 1024 << (2 * size);
3658
}
3659

    
3660
static always_inline int booke_page_size_to_tlb (target_ulong page_size)
3661
{
3662
    int size;
3663

    
3664
    switch (page_size) {
3665
    case 0x00000400UL:
3666
        size = 0x0;
3667
        break;
3668
    case 0x00001000UL:
3669
        size = 0x1;
3670
        break;
3671
    case 0x00004000UL:
3672
        size = 0x2;
3673
        break;
3674
    case 0x00010000UL:
3675
        size = 0x3;
3676
        break;
3677
    case 0x00040000UL:
3678
        size = 0x4;
3679
        break;
3680
    case 0x00100000UL:
3681
        size = 0x5;
3682
        break;
3683
    case 0x00400000UL:
3684
        size = 0x6;
3685
        break;
3686
    case 0x01000000UL:
3687
        size = 0x7;
3688
        break;
3689
    case 0x04000000UL:
3690
        size = 0x8;
3691
        break;
3692
    case 0x10000000UL:
3693
        size = 0x9;
3694
        break;
3695
    case 0x40000000UL:
3696
        size = 0xA;
3697
        break;
3698
#if defined (TARGET_PPC64)
3699
    case 0x000100000000ULL:
3700
        size = 0xB;
3701
        break;
3702
    case 0x000400000000ULL:
3703
        size = 0xC;
3704
        break;
3705
    case 0x001000000000ULL:
3706
        size = 0xD;
3707
        break;
3708
    case 0x004000000000ULL:
3709
        size = 0xE;
3710
        break;
3711
    case 0x010000000000ULL:
3712
        size = 0xF;
3713
        break;
3714
#endif
3715
    default:
3716
        size = -1;
3717
        break;
3718
    }
3719

    
3720
    return size;
3721
}
3722

    
3723
/* Helpers for 4xx TLB management */
3724
target_ulong helper_4xx_tlbre_lo (target_ulong entry)
3725
{
3726
    ppcemb_tlb_t *tlb;
3727
    target_ulong ret;
3728
    int size;
3729

    
3730
    entry &= 0x3F;
3731
    tlb = &env->tlb[entry].tlbe;
3732
    ret = tlb->EPN;
3733
    if (tlb->prot & PAGE_VALID)
3734
        ret |= 0x400;
3735
    size = booke_page_size_to_tlb(tlb->size);
3736
    if (size < 0 || size > 0x7)
3737
        size = 1;
3738
    ret |= size << 7;
3739
    env->spr[SPR_40x_PID] = tlb->PID;
3740
    return ret;
3741
}
3742

    
3743
target_ulong helper_4xx_tlbre_hi (target_ulong entry)
3744
{
3745
    ppcemb_tlb_t *tlb;
3746
    target_ulong ret;
3747

    
3748
    entry &= 0x3F;
3749
    tlb = &env->tlb[entry].tlbe;
3750
    ret = tlb->RPN;
3751
    if (tlb->prot & PAGE_EXEC)
3752
        ret |= 0x200;
3753
    if (tlb->prot & PAGE_WRITE)
3754
        ret |= 0x100;
3755
    return ret;
3756
}
3757

    
3758
void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
3759
{
3760
    ppcemb_tlb_t *tlb;
3761
    target_ulong page, end;
3762

    
3763
    LOG_SWTLB("%s entry %d val " ADDRX "\n", __func__, (int)entry, val);
3764
    entry &= 0x3F;
3765
    tlb = &env->tlb[entry].tlbe;
3766
    /* Invalidate previous TLB (if it's valid) */
3767
    if (tlb->prot & PAGE_VALID) {
3768
        end = tlb->EPN + tlb->size;
3769
        LOG_SWTLB("%s: invalidate old TLB %d start " ADDRX
3770
                    " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
3771
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3772
            tlb_flush_page(env, page);
3773
    }
3774
    tlb->size = booke_tlb_to_page_size((val >> 7) & 0x7);
3775
    /* We cannot handle TLB size < TARGET_PAGE_SIZE.
3776
     * If this ever occurs, one should use the ppcemb target instead
3777
     * of the ppc or ppc64 one
3778
     */
3779
    if ((val & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
3780
        cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
3781
                  "are not supported (%d)\n",
3782
                  tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
3783
    }
3784
    tlb->EPN = val & ~(tlb->size - 1);
3785
    if (val & 0x40)
3786
        tlb->prot |= PAGE_VALID;
3787
    else
3788
        tlb->prot &= ~PAGE_VALID;
3789
    if (val & 0x20) {
3790
        /* XXX: TO BE FIXED */
3791
        cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
3792
    }
3793
    tlb->PID = env->spr[SPR_40x_PID]; /* PID */
3794
    tlb->attr = val & 0xFF;
3795
    LOG_SWTLB("%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
3796
                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
3797
                (int)entry, tlb->RPN, tlb->EPN, tlb->size,
3798
                tlb->prot & PAGE_READ ? 'r' : '-',
3799
                tlb->prot & PAGE_WRITE ? 'w' : '-',
3800
                tlb->prot & PAGE_EXEC ? 'x' : '-',
3801
                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
3802
    /* Invalidate new TLB (if valid) */
3803
    if (tlb->prot & PAGE_VALID) {
3804
        end = tlb->EPN + tlb->size;
3805
        LOG_SWTLB("%s: invalidate TLB %d start " ADDRX
3806
                    " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
3807
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3808
            tlb_flush_page(env, page);
3809
    }
3810
}
3811

    
3812
void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
3813
{
3814
    ppcemb_tlb_t *tlb;
3815

    
3816
    LOG_SWTLB("%s entry %i val " ADDRX "\n", __func__, (int)entry, val);
3817
    entry &= 0x3F;
3818
    tlb = &env->tlb[entry].tlbe;
3819
    tlb->RPN = val & 0xFFFFFC00;
3820
    tlb->prot = PAGE_READ;
3821
    if (val & 0x200)
3822
        tlb->prot |= PAGE_EXEC;
3823
    if (val & 0x100)
3824
        tlb->prot |= PAGE_WRITE;
3825
    LOG_SWTLB("%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
3826
                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
3827
                (int)entry, tlb->RPN, tlb->EPN, tlb->size,
3828
                tlb->prot & PAGE_READ ? 'r' : '-',
3829
                tlb->prot & PAGE_WRITE ? 'w' : '-',
3830
                tlb->prot & PAGE_EXEC ? 'x' : '-',
3831
                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
3832
}
3833

    
3834
target_ulong helper_4xx_tlbsx (target_ulong address)
3835
{
3836
    return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
3837
}
3838

    
3839
/* PowerPC 440 TLB management */
3840
void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
3841
{
3842
    ppcemb_tlb_t *tlb;
3843
    target_ulong EPN, RPN, size;
3844
    int do_flush_tlbs;
3845

    
3846
    LOG_SWTLB("%s word %d entry %d value " ADDRX "\n",
3847
                __func__, word, (int)entry, value);
3848
    do_flush_tlbs = 0;
3849
    entry &= 0x3F;
3850
    tlb = &env->tlb[entry].tlbe;
3851
    switch (word) {
3852
    default:
3853
        /* Just here to please gcc */
3854
    case 0:
3855
        EPN = value & 0xFFFFFC00;
3856
        if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
3857
            do_flush_tlbs = 1;
3858
        tlb->EPN = EPN;
3859
        size = booke_tlb_to_page_size((value >> 4) & 0xF);
3860
        if ((tlb->prot & PAGE_VALID) && tlb->size < size)
3861
            do_flush_tlbs = 1;
3862
        tlb->size = size;
3863
        tlb->attr &= ~0x1;
3864
        tlb->attr |= (value >> 8) & 1;
3865
        if (value & 0x200) {
3866
            tlb->prot |= PAGE_VALID;
3867
        } else {
3868
            if (tlb->prot & PAGE_VALID) {
3869
                tlb->prot &= ~PAGE_VALID;
3870
                do_flush_tlbs = 1;
3871
            }
3872
        }
3873
        tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
3874
        if (do_flush_tlbs)
3875
            tlb_flush(env, 1);
3876
        break;
3877
    case 1:
3878
        RPN = value & 0xFFFFFC0F;
3879
        if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
3880
            tlb_flush(env, 1);
3881
        tlb->RPN = RPN;
3882
        break;
3883
    case 2:
3884
        tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
3885
        tlb->prot = tlb->prot & PAGE_VALID;
3886
        if (value & 0x1)
3887
            tlb->prot |= PAGE_READ << 4;
3888
        if (value & 0x2)
3889
            tlb->prot |= PAGE_WRITE << 4;
3890
        if (value & 0x4)
3891
            tlb->prot |= PAGE_EXEC << 4;
3892
        if (value & 0x8)
3893
            tlb->prot |= PAGE_READ;
3894
        if (value & 0x10)
3895
            tlb->prot |= PAGE_WRITE;
3896
        if (value & 0x20)
3897
            tlb->prot |= PAGE_EXEC;
3898
        break;
3899
    }
3900
}
3901

    
3902
target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
3903
{
3904
    ppcemb_tlb_t *tlb;
3905
    target_ulong ret;
3906
    int size;
3907

    
3908
    entry &= 0x3F;
3909
    tlb = &env->tlb[entry].tlbe;
3910
    switch (word) {
3911
    default:
3912
        /* Just here to please gcc */
3913
    case 0:
3914
        ret = tlb->EPN;
3915
        size = booke_page_size_to_tlb(tlb->size);
3916
        if (size < 0 || size > 0xF)
3917
            size = 1;
3918
        ret |= size << 4;
3919
        if (tlb->attr & 0x1)
3920
            ret |= 0x100;
3921
        if (tlb->prot & PAGE_VALID)
3922
            ret |= 0x200;
3923
        env->spr[SPR_440_MMUCR] &= ~0x000000FF;
3924
        env->spr[SPR_440_MMUCR] |= tlb->PID;
3925
        break;
3926
    case 1:
3927
        ret = tlb->RPN;
3928
        break;
3929
    case 2:
3930
        ret = tlb->attr & ~0x1;
3931
        if (tlb->prot & (PAGE_READ << 4))
3932
            ret |= 0x1;
3933
        if (tlb->prot & (PAGE_WRITE << 4))
3934
            ret |= 0x2;
3935
        if (tlb->prot & (PAGE_EXEC << 4))
3936
            ret |= 0x4;
3937
        if (tlb->prot & PAGE_READ)
3938
            ret |= 0x8;
3939
        if (tlb->prot & PAGE_WRITE)
3940
            ret |= 0x10;
3941
        if (tlb->prot & PAGE_EXEC)
3942
            ret |= 0x20;
3943
        break;
3944
    }
3945
    return ret;
3946
}
3947

    
3948
target_ulong helper_440_tlbsx (target_ulong address)
3949
{
3950
    return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
3951
}
3952

    
3953
#endif /* !CONFIG_USER_ONLY */