Statistics
| Branch: | Revision:

root / target-ppc / op_helper.c @ 875b31db

History | View | Annotate | Download (123.8 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 farg;
1505
    farg.ll = arg;
1506

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

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

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

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

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

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

    
1561
    farg1.ll = arg1;
1562

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1911
/* 440 specific */
1912
target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_Rc)
1913
{
1914
    target_ulong mask;
1915
    int i;
1916

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

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

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

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

    
1975
#define HANDLE_NAN1(result, x)                  \
1976
    DO_HANDLE_NAN(result, x)
1977
#define HANDLE_NAN2(result, x, y)               \
1978
    DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y)
1979
#define HANDLE_NAN3(result, x, y, z)            \
1980
    DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) DO_HANDLE_NAN(result, z)
1981

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

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

    
2029
void helper_lvsl (ppc_avr_t *r, target_ulong sh)
2030
{
2031
    int i, j = (sh & 0xf);
2032

    
2033
    VECTOR_FOR_INORDER_I (i, u8) {
2034
        r->u8[i] = j++;
2035
    }
2036
}
2037

    
2038
void helper_lvsr (ppc_avr_t *r, target_ulong sh)
2039
{
2040
    int i, j = 0x10 - (sh & 0xf);
2041

    
2042
    VECTOR_FOR_INORDER_I (i, u8) {
2043
        r->u8[i] = j++;
2044
    }
2045
}
2046

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

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

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

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

    
2102
#define VARITHFP(suffix, func)                                          \
2103
    void helper_v##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)    \
2104
    {                                                                   \
2105
        int i;                                                          \
2106
        for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
2107
            HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) {                    \
2108
                r->f[i] = func(a->f[i], b->f[i], &env->vec_status);     \
2109
            }                                                           \
2110
        }                                                               \
2111
    }
2112
VARITHFP(addfp, float32_add)
2113
VARITHFP(subfp, float32_sub)
2114
#undef VARITHFP
2115

    
2116
#define VARITHSAT_CASE(type, op, cvt, element)                          \
2117
    {                                                                   \
2118
        type result = (type)a->element[i] op (type)b->element[i];       \
2119
        r->element[i] = cvt(result, &sat);                              \
2120
    }
2121

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

    
2155
#define VAVG_DO(name, element, etype)                                   \
2156
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
2157
    {                                                                   \
2158
        int i;                                                          \
2159
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2160
            etype x = (etype)a->element[i] + (etype)b->element[i] + 1;  \
2161
            r->element[i] = x >> 1;                                     \
2162
        }                                                               \
2163
    }
2164

    
2165
#define VAVG(type, signed_element, signed_type, unsigned_element, unsigned_type) \
2166
    VAVG_DO(avgs##type, signed_element, signed_type)                    \
2167
    VAVG_DO(avgu##type, unsigned_element, unsigned_type)
2168
VAVG(b, s8, int16_t, u8, uint16_t)
2169
VAVG(h, s16, int32_t, u16, uint32_t)
2170
VAVG(w, s32, int64_t, u32, uint64_t)
2171
#undef VAVG_DO
2172
#undef VAVG
2173

    
2174
#define VCF(suffix, cvt, element)                                       \
2175
    void helper_vcf##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t uim)  \
2176
    {                                                                   \
2177
        int i;                                                          \
2178
        for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
2179
            float32 t = cvt(b->element[i], &env->vec_status);           \
2180
            r->f[i] = float32_scalbn (t, -uim, &env->vec_status);       \
2181
        }                                                               \
2182
    }
2183
VCF(ux, uint32_to_float32, u32)
2184
VCF(sx, int32_to_float32, s32)
2185
#undef VCF
2186

    
2187
#define VCMP_DO(suffix, compare, element, record)                       \
2188
    void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2189
    {                                                                   \
2190
        uint32_t ones = (uint32_t)-1;                                   \
2191
        uint32_t all = ones;                                            \
2192
        uint32_t none = 0;                                              \
2193
        int i;                                                          \
2194
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2195
            uint32_t result = (a->element[i] compare b->element[i] ? ones : 0x0); \
2196
            switch (sizeof (a->element[0])) {                           \
2197
            case 4: r->u32[i] = result; break;                          \
2198
            case 2: r->u16[i] = result; break;                          \
2199
            case 1: r->u8[i] = result; break;                           \
2200
            }                                                           \
2201
            all &= result;                                              \
2202
            none |= result;                                             \
2203
        }                                                               \
2204
        if (record) {                                                   \
2205
            env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1);       \
2206
        }                                                               \
2207
    }
2208
#define VCMP(suffix, compare, element)          \
2209
    VCMP_DO(suffix, compare, element, 0)        \
2210
    VCMP_DO(suffix##_dot, compare, element, 1)
2211
VCMP(equb, ==, u8)
2212
VCMP(equh, ==, u16)
2213
VCMP(equw, ==, u32)
2214
VCMP(gtub, >, u8)
2215
VCMP(gtuh, >, u16)
2216
VCMP(gtuw, >, u32)
2217
VCMP(gtsb, >, s8)
2218
VCMP(gtsh, >, s16)
2219
VCMP(gtsw, >, s32)
2220
#undef VCMP_DO
2221
#undef VCMP
2222

    
2223
#define VCMPFP_DO(suffix, compare, order, record)                       \
2224
    void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2225
    {                                                                   \
2226
        uint32_t ones = (uint32_t)-1;                                   \
2227
        uint32_t all = ones;                                            \
2228
        uint32_t none = 0;                                              \
2229
        int i;                                                          \
2230
        for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
2231
            uint32_t result;                                            \
2232
            int rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status); \
2233
            if (rel == float_relation_unordered) {                      \
2234
                result = 0;                                             \
2235
            } else if (rel compare order) {                             \
2236
                result = ones;                                          \
2237
            } else {                                                    \
2238
                result = 0;                                             \
2239
            }                                                           \
2240
            r->u32[i] = result;                                         \
2241
            all &= result;                                              \
2242
            none |= result;                                             \
2243
        }                                                               \
2244
        if (record) {                                                   \
2245
            env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1);       \
2246
        }                                                               \
2247
    }
2248
#define VCMPFP(suffix, compare, order)           \
2249
    VCMPFP_DO(suffix, compare, order, 0)         \
2250
    VCMPFP_DO(suffix##_dot, compare, order, 1)
2251
VCMPFP(eqfp, ==, float_relation_equal)
2252
VCMPFP(gefp, !=, float_relation_less)
2253
VCMPFP(gtfp, ==, float_relation_greater)
2254
#undef VCMPFP_DO
2255
#undef VCMPFP
2256

    
2257
static always_inline void vcmpbfp_internal (ppc_avr_t *r, ppc_avr_t *a,
2258
                                            ppc_avr_t *b, int record)
2259
{
2260
    int i;
2261
    int all_in = 0;
2262
    for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2263
        int le_rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status);
2264
        if (le_rel == float_relation_unordered) {
2265
            r->u32[i] = 0xc0000000;
2266
            /* ALL_IN does not need to be updated here.  */
2267
        } else {
2268
            float32 bneg = float32_chs(b->f[i]);
2269
            int ge_rel = float32_compare_quiet(a->f[i], bneg, &env->vec_status);
2270
            int le = le_rel != float_relation_greater;
2271
            int ge = ge_rel != float_relation_less;
2272
            r->u32[i] = ((!le) << 31) | ((!ge) << 30);
2273
            all_in |= (!le | !ge);
2274
        }
2275
    }
2276
    if (record) {
2277
        env->crf[6] = (all_in == 0) << 1;
2278
    }
2279
}
2280

    
2281
void helper_vcmpbfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2282
{
2283
    vcmpbfp_internal(r, a, b, 0);
2284
}
2285

    
2286
void helper_vcmpbfp_dot (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2287
{
2288
    vcmpbfp_internal(r, a, b, 1);
2289
}
2290

    
2291
#define VCT(suffix, satcvt, element)                                    \
2292
    void helper_vct##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t uim)  \
2293
    {                                                                   \
2294
        int i;                                                          \
2295
        int sat = 0;                                                    \
2296
        float_status s = env->vec_status;                               \
2297
        set_float_rounding_mode(float_round_to_zero, &s);               \
2298
        for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
2299
            if (float32_is_nan(b->f[i]) ||                              \
2300
                float32_is_signaling_nan(b->f[i])) {                    \
2301
                r->element[i] = 0;                                      \
2302
            } else {                                                    \
2303
                float64 t = float32_to_float64(b->f[i], &s);            \
2304
                int64_t j;                                              \
2305
                t = float64_scalbn(t, uim, &s);                         \
2306
                j = float64_to_int64(t, &s);                            \
2307
                r->element[i] = satcvt(j, &sat);                        \
2308
            }                                                           \
2309
        }                                                               \
2310
        if (sat) {                                                      \
2311
            env->vscr |= (1 << VSCR_SAT);                               \
2312
        }                                                               \
2313
    }
2314
VCT(uxs, cvtsduw, u32)
2315
VCT(sxs, cvtsdsw, s32)
2316
#undef VCT
2317

    
2318
void helper_vmaddfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2319
{
2320
    int i;
2321
    for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2322
        HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
2323
            /* Need to do the computation in higher precision and round
2324
             * once at the end.  */
2325
            float64 af, bf, cf, t;
2326
            af = float32_to_float64(a->f[i], &env->vec_status);
2327
            bf = float32_to_float64(b->f[i], &env->vec_status);
2328
            cf = float32_to_float64(c->f[i], &env->vec_status);
2329
            t = float64_mul(af, cf, &env->vec_status);
2330
            t = float64_add(t, bf, &env->vec_status);
2331
            r->f[i] = float64_to_float32(t, &env->vec_status);
2332
        }
2333
    }
2334
}
2335

    
2336
void helper_vmhaddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2337
{
2338
    int sat = 0;
2339
    int i;
2340

    
2341
    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2342
        int32_t prod = a->s16[i] * b->s16[i];
2343
        int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2344
        r->s16[i] = cvtswsh (t, &sat);
2345
    }
2346

    
2347
    if (sat) {
2348
        env->vscr |= (1 << VSCR_SAT);
2349
    }
2350
}
2351

    
2352
void helper_vmhraddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2353
{
2354
    int sat = 0;
2355
    int i;
2356

    
2357
    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2358
        int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
2359
        int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2360
        r->s16[i] = cvtswsh (t, &sat);
2361
    }
2362

    
2363
    if (sat) {
2364
        env->vscr |= (1 << VSCR_SAT);
2365
    }
2366
}
2367

    
2368
#define VMINMAX_DO(name, compare, element)                              \
2369
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
2370
    {                                                                   \
2371
        int i;                                                          \
2372
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2373
            if (a->element[i] compare b->element[i]) {                  \
2374
                r->element[i] = b->element[i];                          \
2375
            } else {                                                    \
2376
                r->element[i] = a->element[i];                          \
2377
            }                                                           \
2378
        }                                                               \
2379
    }
2380
#define VMINMAX(suffix, element)                \
2381
  VMINMAX_DO(min##suffix, >, element)           \
2382
  VMINMAX_DO(max##suffix, <, element)
2383
VMINMAX(sb, s8)
2384
VMINMAX(sh, s16)
2385
VMINMAX(sw, s32)
2386
VMINMAX(ub, u8)
2387
VMINMAX(uh, u16)
2388
VMINMAX(uw, u32)
2389
#undef VMINMAX_DO
2390
#undef VMINMAX
2391

    
2392
#define VMINMAXFP(suffix, rT, rF)                                       \
2393
    void helper_v##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)    \
2394
    {                                                                   \
2395
        int i;                                                          \
2396
        for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
2397
            HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) {                    \
2398
                if (float32_lt_quiet(a->f[i], b->f[i], &env->vec_status)) { \
2399
                    r->f[i] = rT->f[i];                                 \
2400
                } else {                                                \
2401
                    r->f[i] = rF->f[i];                                 \
2402
                }                                                       \
2403
            }                                                           \
2404
        }                                                               \
2405
    }
2406
VMINMAXFP(minfp, a, b)
2407
VMINMAXFP(maxfp, b, a)
2408
#undef VMINMAXFP
2409

    
2410
void helper_vmladduhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2411
{
2412
    int i;
2413
    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2414
        int32_t prod = a->s16[i] * b->s16[i];
2415
        r->s16[i] = (int16_t) (prod + c->s16[i]);
2416
    }
2417
}
2418

    
2419
#define VMRG_DO(name, element, highp)                                   \
2420
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
2421
    {                                                                   \
2422
        ppc_avr_t result;                                               \
2423
        int i;                                                          \
2424
        size_t n_elems = ARRAY_SIZE(r->element);                        \
2425
        for (i = 0; i < n_elems/2; i++) {                               \
2426
            if (highp) {                                                \
2427
                result.element[i*2+HI_IDX] = a->element[i];             \
2428
                result.element[i*2+LO_IDX] = b->element[i];             \
2429
            } else {                                                    \
2430
                result.element[n_elems - i*2 - (1+HI_IDX)] = b->element[n_elems - i - 1]; \
2431
                result.element[n_elems - i*2 - (1+LO_IDX)] = a->element[n_elems - i - 1]; \
2432
            }                                                           \
2433
        }                                                               \
2434
        *r = result;                                                    \
2435
    }
2436
#if defined(WORDS_BIGENDIAN)
2437
#define MRGHI 0
2438
#define MRGLO 1
2439
#else
2440
#define MRGHI 1
2441
#define MRGLO 0
2442
#endif
2443
#define VMRG(suffix, element)                   \
2444
  VMRG_DO(mrgl##suffix, element, MRGHI)         \
2445
  VMRG_DO(mrgh##suffix, element, MRGLO)
2446
VMRG(b, u8)
2447
VMRG(h, u16)
2448
VMRG(w, u32)
2449
#undef VMRG_DO
2450
#undef VMRG
2451
#undef MRGHI
2452
#undef MRGLO
2453

    
2454
void helper_vmsummbm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2455
{
2456
    int32_t prod[16];
2457
    int i;
2458

    
2459
    for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
2460
        prod[i] = (int32_t)a->s8[i] * b->u8[i];
2461
    }
2462

    
2463
    VECTOR_FOR_INORDER_I(i, s32) {
2464
        r->s32[i] = c->s32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2465
    }
2466
}
2467

    
2468
void helper_vmsumshm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2469
{
2470
    int32_t prod[8];
2471
    int i;
2472

    
2473
    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2474
        prod[i] = a->s16[i] * b->s16[i];
2475
    }
2476

    
2477
    VECTOR_FOR_INORDER_I(i, s32) {
2478
        r->s32[i] = c->s32[i] + prod[2*i] + prod[2*i+1];
2479
    }
2480
}
2481

    
2482
void helper_vmsumshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2483
{
2484
    int32_t prod[8];
2485
    int i;
2486
    int sat = 0;
2487

    
2488
    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2489
        prod[i] = (int32_t)a->s16[i] * b->s16[i];
2490
    }
2491

    
2492
    VECTOR_FOR_INORDER_I (i, s32) {
2493
        int64_t t = (int64_t)c->s32[i] + prod[2*i] + prod[2*i+1];
2494
        r->u32[i] = cvtsdsw(t, &sat);
2495
    }
2496

    
2497
    if (sat) {
2498
        env->vscr |= (1 << VSCR_SAT);
2499
    }
2500
}
2501

    
2502
void helper_vmsumubm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2503
{
2504
    uint16_t prod[16];
2505
    int i;
2506

    
2507
    for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2508
        prod[i] = a->u8[i] * b->u8[i];
2509
    }
2510

    
2511
    VECTOR_FOR_INORDER_I(i, u32) {
2512
        r->u32[i] = c->u32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2513
    }
2514
}
2515

    
2516
void helper_vmsumuhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2517
{
2518
    uint32_t prod[8];
2519
    int i;
2520

    
2521
    for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2522
        prod[i] = a->u16[i] * b->u16[i];
2523
    }
2524

    
2525
    VECTOR_FOR_INORDER_I(i, u32) {
2526
        r->u32[i] = c->u32[i] + prod[2*i] + prod[2*i+1];
2527
    }
2528
}
2529

    
2530
void helper_vmsumuhs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2531
{
2532
    uint32_t prod[8];
2533
    int i;
2534
    int sat = 0;
2535

    
2536
    for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2537
        prod[i] = a->u16[i] * b->u16[i];
2538
    }
2539

    
2540
    VECTOR_FOR_INORDER_I (i, s32) {
2541
        uint64_t t = (uint64_t)c->u32[i] + prod[2*i] + prod[2*i+1];
2542
        r->u32[i] = cvtuduw(t, &sat);
2543
    }
2544

    
2545
    if (sat) {
2546
        env->vscr |= (1 << VSCR_SAT);
2547
    }
2548
}
2549

    
2550
#define VMUL_DO(name, mul_element, prod_element, evenp)                 \
2551
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
2552
    {                                                                   \
2553
        int i;                                                          \
2554
        VECTOR_FOR_INORDER_I(i, prod_element) {                         \
2555
            if (evenp) {                                                \
2556
                r->prod_element[i] = a->mul_element[i*2+HI_IDX] * b->mul_element[i*2+HI_IDX]; \
2557
            } else {                                                    \
2558
                r->prod_element[i] = a->mul_element[i*2+LO_IDX] * b->mul_element[i*2+LO_IDX]; \
2559
            }                                                           \
2560
        }                                                               \
2561
    }
2562
#define VMUL(suffix, mul_element, prod_element) \
2563
  VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
2564
  VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
2565
VMUL(sb, s8, s16)
2566
VMUL(sh, s16, s32)
2567
VMUL(ub, u8, u16)
2568
VMUL(uh, u16, u32)
2569
#undef VMUL_DO
2570
#undef VMUL
2571

    
2572
void helper_vnmsubfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2573
{
2574
    int i;
2575
    for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2576
        HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
2577
            /* Need to do the computation is higher precision and round
2578
             * once at the end.  */
2579
            float64 af, bf, cf, t;
2580
            af = float32_to_float64(a->f[i], &env->vec_status);
2581
            bf = float32_to_float64(b->f[i], &env->vec_status);
2582
            cf = float32_to_float64(c->f[i], &env->vec_status);
2583
            t = float64_mul(af, cf, &env->vec_status);
2584
            t = float64_sub(t, bf, &env->vec_status);
2585
            t = float64_chs(t);
2586
            r->f[i] = float64_to_float32(t, &env->vec_status);
2587
        }
2588
    }
2589
}
2590

    
2591
void helper_vperm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2592
{
2593
    ppc_avr_t result;
2594
    int i;
2595
    VECTOR_FOR_INORDER_I (i, u8) {
2596
        int s = c->u8[i] & 0x1f;
2597
#if defined(WORDS_BIGENDIAN)
2598
        int index = s & 0xf;
2599
#else
2600
        int index = 15 - (s & 0xf);
2601
#endif
2602
        if (s & 0x10) {
2603
            result.u8[i] = b->u8[index];
2604
        } else {
2605
            result.u8[i] = a->u8[index];
2606
        }
2607
    }
2608
    *r = result;
2609
}
2610

    
2611
#if defined(WORDS_BIGENDIAN)
2612
#define PKBIG 1
2613
#else
2614
#define PKBIG 0
2615
#endif
2616
void helper_vpkpx (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2617
{
2618
    int i, j;
2619
    ppc_avr_t result;
2620
#if defined(WORDS_BIGENDIAN)
2621
    const ppc_avr_t *x[2] = { a, b };
2622
#else
2623
    const ppc_avr_t *x[2] = { b, a };
2624
#endif
2625

    
2626
    VECTOR_FOR_INORDER_I (i, u64) {
2627
        VECTOR_FOR_INORDER_I (j, u32){
2628
            uint32_t e = x[i]->u32[j];
2629
            result.u16[4*i+j] = (((e >> 9) & 0xfc00) |
2630
                                 ((e >> 6) & 0x3e0) |
2631
                                 ((e >> 3) & 0x1f));
2632
        }
2633
    }
2634
    *r = result;
2635
}
2636

    
2637
#define VPK(suffix, from, to, cvt, dosat)       \
2638
    void helper_vpk##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
2639
    {                                                                   \
2640
        int i;                                                          \
2641
        int sat = 0;                                                    \
2642
        ppc_avr_t result;                                               \
2643
        ppc_avr_t *a0 = PKBIG ? a : b;                                  \
2644
        ppc_avr_t *a1 = PKBIG ? b : a;                                  \
2645
        VECTOR_FOR_INORDER_I (i, from) {                                \
2646
            result.to[i] = cvt(a0->from[i], &sat);                      \
2647
            result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat);  \
2648
        }                                                               \
2649
        *r = result;                                                    \
2650
        if (dosat && sat) {                                             \
2651
            env->vscr |= (1 << VSCR_SAT);                               \
2652
        }                                                               \
2653
    }
2654
#define I(x, y) (x)
2655
VPK(shss, s16, s8, cvtshsb, 1)
2656
VPK(shus, s16, u8, cvtshub, 1)
2657
VPK(swss, s32, s16, cvtswsh, 1)
2658
VPK(swus, s32, u16, cvtswuh, 1)
2659
VPK(uhus, u16, u8, cvtuhub, 1)
2660
VPK(uwus, u32, u16, cvtuwuh, 1)
2661
VPK(uhum, u16, u8, I, 0)
2662
VPK(uwum, u32, u16, I, 0)
2663
#undef I
2664
#undef VPK
2665
#undef PKBIG
2666

    
2667
#define VRFI(suffix, rounding)                                          \
2668
    void helper_vrfi##suffix (ppc_avr_t *r, ppc_avr_t *b)               \
2669
    {                                                                   \
2670
        int i;                                                          \
2671
        float_status s = env->vec_status;                               \
2672
        set_float_rounding_mode(rounding, &s);                          \
2673
        for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
2674
            HANDLE_NAN1(r->f[i], b->f[i]) {                             \
2675
                r->f[i] = float32_round_to_int (b->f[i], &s);           \
2676
            }                                                           \
2677
        }                                                               \
2678
    }
2679
VRFI(n, float_round_nearest_even)
2680
VRFI(m, float_round_down)
2681
VRFI(p, float_round_up)
2682
VRFI(z, float_round_to_zero)
2683
#undef VRFI
2684

    
2685
#define VROTATE(suffix, element)                                        \
2686
    void helper_vrl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
2687
    {                                                                   \
2688
        int i;                                                          \
2689
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2690
            unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2691
            unsigned int shift = b->element[i] & mask;                  \
2692
            r->element[i] = (a->element[i] << shift) | (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
2693
        }                                                               \
2694
    }
2695
VROTATE(b, u8)
2696
VROTATE(h, u16)
2697
VROTATE(w, u32)
2698
#undef VROTATE
2699

    
2700
void helper_vsel (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2701
{
2702
    r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
2703
    r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
2704
}
2705

    
2706
void helper_vlogefp (ppc_avr_t *r, ppc_avr_t *b)
2707
{
2708
    int i;
2709
    for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2710
        HANDLE_NAN1(r->f[i], b->f[i]) {
2711
            r->f[i] = float32_log2(b->f[i], &env->vec_status);
2712
        }
2713
    }
2714
}
2715

    
2716
#if defined(WORDS_BIGENDIAN)
2717
#define LEFT 0
2718
#define RIGHT 1
2719
#else
2720
#define LEFT 1
2721
#define RIGHT 0
2722
#endif
2723
/* The specification says that the results are undefined if all of the
2724
 * shift counts are not identical.  We check to make sure that they are
2725
 * to conform to what real hardware appears to do.  */
2726
#define VSHIFT(suffix, leftp)                                           \
2727
    void helper_vs##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)   \
2728
    {                                                                   \
2729
        int shift = b->u8[LO_IDX*0x15] & 0x7;                           \
2730
        int doit = 1;                                                   \
2731
        int i;                                                          \
2732
        for (i = 0; i < ARRAY_SIZE(r->u8); i++) {                       \
2733
            doit = doit && ((b->u8[i] & 0x7) == shift);                 \
2734
        }                                                               \
2735
        if (doit) {                                                     \
2736
            if (shift == 0) {                                           \
2737
                *r = *a;                                                \
2738
            } else if (leftp) {                                         \
2739
                uint64_t carry = a->u64[LO_IDX] >> (64 - shift);        \
2740
                r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry;     \
2741
                r->u64[LO_IDX] = a->u64[LO_IDX] << shift;               \
2742
            } else {                                                    \
2743
                uint64_t carry = a->u64[HI_IDX] << (64 - shift);        \
2744
                r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry;     \
2745
                r->u64[HI_IDX] = a->u64[HI_IDX] >> shift;               \
2746
            }                                                           \
2747
        }                                                               \
2748
    }
2749
VSHIFT(l, LEFT)
2750
VSHIFT(r, RIGHT)
2751
#undef VSHIFT
2752
#undef LEFT
2753
#undef RIGHT
2754

    
2755
#define VSL(suffix, element)                                            \
2756
    void helper_vsl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
2757
    {                                                                   \
2758
        int i;                                                          \
2759
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2760
            unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2761
            unsigned int shift = b->element[i] & mask;                  \
2762
            r->element[i] = a->element[i] << shift;                     \
2763
        }                                                               \
2764
    }
2765
VSL(b, u8)
2766
VSL(h, u16)
2767
VSL(w, u32)
2768
#undef VSL
2769

    
2770
void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
2771
{
2772
    int sh = shift & 0xf;
2773
    int i;
2774
    ppc_avr_t result;
2775

    
2776
#if defined(WORDS_BIGENDIAN)
2777
    for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2778
        int index = sh + i;
2779
        if (index > 0xf) {
2780
            result.u8[i] = b->u8[index-0x10];
2781
        } else {
2782
            result.u8[i] = a->u8[index];
2783
        }
2784
    }
2785
#else
2786
    for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2787
        int index = (16 - sh) + i;
2788
        if (index > 0xf) {
2789
            result.u8[i] = a->u8[index-0x10];
2790
        } else {
2791
            result.u8[i] = b->u8[index];
2792
        }
2793
    }
2794
#endif
2795
    *r = result;
2796
}
2797

    
2798
void helper_vslo (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2799
{
2800
  int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2801

    
2802
#if defined (WORDS_BIGENDIAN)
2803
  memmove (&r->u8[0], &a->u8[sh], 16-sh);
2804
  memset (&r->u8[16-sh], 0, sh);
2805
#else
2806
  memmove (&r->u8[sh], &a->u8[0], 16-sh);
2807
  memset (&r->u8[0], 0, sh);
2808
#endif
2809
}
2810

    
2811
/* Experimental testing shows that hardware masks the immediate.  */
2812
#define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
2813
#if defined(WORDS_BIGENDIAN)
2814
#define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
2815
#else
2816
#define SPLAT_ELEMENT(element) (ARRAY_SIZE(r->element)-1 - _SPLAT_MASKED(element))
2817
#endif
2818
#define VSPLT(suffix, element)                                          \
2819
    void helper_vsplt##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
2820
    {                                                                   \
2821
        uint32_t s = b->element[SPLAT_ELEMENT(element)];                \
2822
        int i;                                                          \
2823
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2824
            r->element[i] = s;                                          \
2825
        }                                                               \
2826
    }
2827
VSPLT(b, u8)
2828
VSPLT(h, u16)
2829
VSPLT(w, u32)
2830
#undef VSPLT
2831
#undef SPLAT_ELEMENT
2832
#undef _SPLAT_MASKED
2833

    
2834
#define VSPLTI(suffix, element, splat_type)                     \
2835
    void helper_vspltis##suffix (ppc_avr_t *r, uint32_t splat)  \
2836
    {                                                           \
2837
        splat_type x = (int8_t)(splat << 3) >> 3;               \
2838
        int i;                                                  \
2839
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {          \
2840
            r->element[i] = x;                                  \
2841
        }                                                       \
2842
    }
2843
VSPLTI(b, s8, int8_t)
2844
VSPLTI(h, s16, int16_t)
2845
VSPLTI(w, s32, int32_t)
2846
#undef VSPLTI
2847

    
2848
#define VSR(suffix, element)                                            \
2849
    void helper_vsr##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
2850
    {                                                                   \
2851
        int i;                                                          \
2852
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2853
            unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2854
            unsigned int shift = b->element[i] & mask;                  \
2855
            r->element[i] = a->element[i] >> shift;                     \
2856
        }                                                               \
2857
    }
2858
VSR(ab, s8)
2859
VSR(ah, s16)
2860
VSR(aw, s32)
2861
VSR(b, u8)
2862
VSR(h, u16)
2863
VSR(w, u32)
2864
#undef VSR
2865

    
2866
void helper_vsro (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2867
{
2868
  int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2869

    
2870
#if defined (WORDS_BIGENDIAN)
2871
  memmove (&r->u8[sh], &a->u8[0], 16-sh);
2872
  memset (&r->u8[0], 0, sh);
2873
#else
2874
  memmove (&r->u8[0], &a->u8[sh], 16-sh);
2875
  memset (&r->u8[16-sh], 0, sh);
2876
#endif
2877
}
2878

    
2879
void helper_vsubcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2880
{
2881
    int i;
2882
    for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2883
        r->u32[i] = a->u32[i] >= b->u32[i];
2884
    }
2885
}
2886

    
2887
void helper_vsumsws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2888
{
2889
    int64_t t;
2890
    int i, upper;
2891
    ppc_avr_t result;
2892
    int sat = 0;
2893

    
2894
#if defined(WORDS_BIGENDIAN)
2895
    upper = ARRAY_SIZE(r->s32)-1;
2896
#else
2897
    upper = 0;
2898
#endif
2899
    t = (int64_t)b->s32[upper];
2900
    for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2901
        t += a->s32[i];
2902
        result.s32[i] = 0;
2903
    }
2904
    result.s32[upper] = cvtsdsw(t, &sat);
2905
    *r = result;
2906

    
2907
    if (sat) {
2908
        env->vscr |= (1 << VSCR_SAT);
2909
    }
2910
}
2911

    
2912
void helper_vsum2sws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2913
{
2914
    int i, j, upper;
2915
    ppc_avr_t result;
2916
    int sat = 0;
2917

    
2918
#if defined(WORDS_BIGENDIAN)
2919
    upper = 1;
2920
#else
2921
    upper = 0;
2922
#endif
2923
    for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
2924
        int64_t t = (int64_t)b->s32[upper+i*2];
2925
        result.u64[i] = 0;
2926
        for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
2927
            t += a->s32[2*i+j];
2928
        }
2929
        result.s32[upper+i*2] = cvtsdsw(t, &sat);
2930
    }
2931

    
2932
    *r = result;
2933
    if (sat) {
2934
        env->vscr |= (1 << VSCR_SAT);
2935
    }
2936
}
2937

    
2938
void helper_vsum4sbs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2939
{
2940
    int i, j;
2941
    int sat = 0;
2942

    
2943
    for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2944
        int64_t t = (int64_t)b->s32[i];
2945
        for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
2946
            t += a->s8[4*i+j];
2947
        }
2948
        r->s32[i] = cvtsdsw(t, &sat);
2949
    }
2950

    
2951
    if (sat) {
2952
        env->vscr |= (1 << VSCR_SAT);
2953
    }
2954
}
2955

    
2956
void helper_vsum4shs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2957
{
2958
    int sat = 0;
2959
    int i;
2960

    
2961
    for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2962
        int64_t t = (int64_t)b->s32[i];
2963
        t += a->s16[2*i] + a->s16[2*i+1];
2964
        r->s32[i] = cvtsdsw(t, &sat);
2965
    }
2966

    
2967
    if (sat) {
2968
        env->vscr |= (1 << VSCR_SAT);
2969
    }
2970
}
2971

    
2972
void helper_vsum4ubs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2973
{
2974
    int i, j;
2975
    int sat = 0;
2976

    
2977
    for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2978
        uint64_t t = (uint64_t)b->u32[i];
2979
        for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
2980
            t += a->u8[4*i+j];
2981
        }
2982
        r->u32[i] = cvtuduw(t, &sat);
2983
    }
2984

    
2985
    if (sat) {
2986
        env->vscr |= (1 << VSCR_SAT);
2987
    }
2988
}
2989

    
2990
#if defined(WORDS_BIGENDIAN)
2991
#define UPKHI 1
2992
#define UPKLO 0
2993
#else
2994
#define UPKHI 0
2995
#define UPKLO 1
2996
#endif
2997
#define VUPKPX(suffix, hi)                                      \
2998
    void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b)       \
2999
    {                                                           \
3000
        int i;                                                  \
3001
        ppc_avr_t result;                                       \
3002
        for (i = 0; i < ARRAY_SIZE(r->u32); i++) {              \
3003
            uint16_t e = b->u16[hi ? i : i+4];                  \
3004
            uint8_t a = (e >> 15) ? 0xff : 0;                   \
3005
            uint8_t r = (e >> 10) & 0x1f;                       \
3006
            uint8_t g = (e >> 5) & 0x1f;                        \
3007
            uint8_t b = e & 0x1f;                               \
3008
            result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b;       \
3009
        }                                                               \
3010
        *r = result;                                                    \
3011
    }
3012
VUPKPX(lpx, UPKLO)
3013
VUPKPX(hpx, UPKHI)
3014
#undef VUPKPX
3015

    
3016
#define VUPK(suffix, unpacked, packee, hi)                              \
3017
    void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b)               \
3018
    {                                                                   \
3019
        int i;                                                          \
3020
        ppc_avr_t result;                                               \
3021
        if (hi) {                                                       \
3022
            for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) {             \
3023
                result.unpacked[i] = b->packee[i];                      \
3024
            }                                                           \
3025
        } else {                                                        \
3026
            for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); i++) { \
3027
                result.unpacked[i-ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
3028
            }                                                           \
3029
        }                                                               \
3030
        *r = result;                                                    \
3031
    }
3032
VUPK(hsb, s16, s8, UPKHI)
3033
VUPK(hsh, s32, s16, UPKHI)
3034
VUPK(lsb, s16, s8, UPKLO)
3035
VUPK(lsh, s32, s16, UPKLO)
3036
#undef VUPK
3037
#undef UPKHI
3038
#undef UPKLO
3039

    
3040
#undef DO_HANDLE_NAN
3041
#undef HANDLE_NAN1
3042
#undef HANDLE_NAN2
3043
#undef HANDLE_NAN3
3044
#undef VECTOR_FOR_INORDER_I
3045
#undef HI_IDX
3046
#undef LO_IDX
3047

    
3048
/*****************************************************************************/
3049
/* SPE extension helpers */
3050
/* Use a table to make this quicker */
3051
static uint8_t hbrev[16] = {
3052
    0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
3053
    0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
3054
};
3055

    
3056
static always_inline uint8_t byte_reverse (uint8_t val)
3057
{
3058
    return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
3059
}
3060

    
3061
static always_inline uint32_t word_reverse (uint32_t val)
3062
{
3063
    return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
3064
        (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
3065
}
3066

    
3067
#define MASKBITS 16 // Random value - to be fixed (implementation dependant)
3068
target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
3069
{
3070
    uint32_t a, b, d, mask;
3071

    
3072
    mask = UINT32_MAX >> (32 - MASKBITS);
3073
    a = arg1 & mask;
3074
    b = arg2 & mask;
3075
    d = word_reverse(1 + word_reverse(a | ~b));
3076
    return (arg1 & ~mask) | (d & b);
3077
}
3078

    
3079
uint32_t helper_cntlsw32 (uint32_t val)
3080
{
3081
    if (val & 0x80000000)
3082
        return clz32(~val);
3083
    else
3084
        return clz32(val);
3085
}
3086

    
3087
uint32_t helper_cntlzw32 (uint32_t val)
3088
{
3089
    return clz32(val);
3090
}
3091

    
3092
/* Single-precision floating-point conversions */
3093
static always_inline uint32_t efscfsi (uint32_t val)
3094
{
3095
    CPU_FloatU u;
3096

    
3097
    u.f = int32_to_float32(val, &env->vec_status);
3098

    
3099
    return u.l;
3100
}
3101

    
3102
static always_inline uint32_t efscfui (uint32_t val)
3103
{
3104
    CPU_FloatU u;
3105

    
3106
    u.f = uint32_to_float32(val, &env->vec_status);
3107

    
3108
    return u.l;
3109
}
3110

    
3111
static always_inline int32_t efsctsi (uint32_t val)
3112
{
3113
    CPU_FloatU u;
3114

    
3115
    u.l = val;
3116
    /* NaN are not treated the same way IEEE 754 does */
3117
    if (unlikely(float32_is_nan(u.f)))
3118
        return 0;
3119

    
3120
    return float32_to_int32(u.f, &env->vec_status);
3121
}
3122

    
3123
static always_inline uint32_t efsctui (uint32_t val)
3124
{
3125
    CPU_FloatU u;
3126

    
3127
    u.l = val;
3128
    /* NaN are not treated the same way IEEE 754 does */
3129
    if (unlikely(float32_is_nan(u.f)))
3130
        return 0;
3131

    
3132
    return float32_to_uint32(u.f, &env->vec_status);
3133
}
3134

    
3135
static always_inline uint32_t efsctsiz (uint32_t val)
3136
{
3137
    CPU_FloatU u;
3138

    
3139
    u.l = val;
3140
    /* NaN are not treated the same way IEEE 754 does */
3141
    if (unlikely(float32_is_nan(u.f)))
3142
        return 0;
3143

    
3144
    return float32_to_int32_round_to_zero(u.f, &env->vec_status);
3145
}
3146

    
3147
static always_inline uint32_t efsctuiz (uint32_t val)
3148
{
3149
    CPU_FloatU u;
3150

    
3151
    u.l = val;
3152
    /* NaN are not treated the same way IEEE 754 does */
3153
    if (unlikely(float32_is_nan(u.f)))
3154
        return 0;
3155

    
3156
    return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
3157
}
3158

    
3159
static always_inline uint32_t efscfsf (uint32_t val)
3160
{
3161
    CPU_FloatU u;
3162
    float32 tmp;
3163

    
3164
    u.f = int32_to_float32(val, &env->vec_status);
3165
    tmp = int64_to_float32(1ULL << 32, &env->vec_status);
3166
    u.f = float32_div(u.f, tmp, &env->vec_status);
3167

    
3168
    return u.l;
3169
}
3170

    
3171
static always_inline uint32_t efscfuf (uint32_t val)
3172
{
3173
    CPU_FloatU u;
3174
    float32 tmp;
3175

    
3176
    u.f = uint32_to_float32(val, &env->vec_status);
3177
    tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3178
    u.f = float32_div(u.f, tmp, &env->vec_status);
3179

    
3180
    return u.l;
3181
}
3182

    
3183
static always_inline uint32_t efsctsf (uint32_t val)
3184
{
3185
    CPU_FloatU u;
3186
    float32 tmp;
3187

    
3188
    u.l = val;
3189
    /* NaN are not treated the same way IEEE 754 does */
3190
    if (unlikely(float32_is_nan(u.f)))
3191
        return 0;
3192
    tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3193
    u.f = float32_mul(u.f, tmp, &env->vec_status);
3194

    
3195
    return float32_to_int32(u.f, &env->vec_status);
3196
}
3197

    
3198
static always_inline uint32_t efsctuf (uint32_t val)
3199
{
3200
    CPU_FloatU u;
3201
    float32 tmp;
3202

    
3203
    u.l = val;
3204
    /* NaN are not treated the same way IEEE 754 does */
3205
    if (unlikely(float32_is_nan(u.f)))
3206
        return 0;
3207
    tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3208
    u.f = float32_mul(u.f, tmp, &env->vec_status);
3209

    
3210
    return float32_to_uint32(u.f, &env->vec_status);
3211
}
3212

    
3213
#define HELPER_SPE_SINGLE_CONV(name)                                          \
3214
uint32_t helper_e##name (uint32_t val)                                        \
3215
{                                                                             \
3216
    return e##name(val);                                                      \
3217
}
3218
/* efscfsi */
3219
HELPER_SPE_SINGLE_CONV(fscfsi);
3220
/* efscfui */
3221
HELPER_SPE_SINGLE_CONV(fscfui);
3222
/* efscfuf */
3223
HELPER_SPE_SINGLE_CONV(fscfuf);
3224
/* efscfsf */
3225
HELPER_SPE_SINGLE_CONV(fscfsf);
3226
/* efsctsi */
3227
HELPER_SPE_SINGLE_CONV(fsctsi);
3228
/* efsctui */
3229
HELPER_SPE_SINGLE_CONV(fsctui);
3230
/* efsctsiz */
3231
HELPER_SPE_SINGLE_CONV(fsctsiz);
3232
/* efsctuiz */
3233
HELPER_SPE_SINGLE_CONV(fsctuiz);
3234
/* efsctsf */
3235
HELPER_SPE_SINGLE_CONV(fsctsf);
3236
/* efsctuf */
3237
HELPER_SPE_SINGLE_CONV(fsctuf);
3238

    
3239
#define HELPER_SPE_VECTOR_CONV(name)                                          \
3240
uint64_t helper_ev##name (uint64_t val)                                       \
3241
{                                                                             \
3242
    return ((uint64_t)e##name(val >> 32) << 32) |                             \
3243
            (uint64_t)e##name(val);                                           \
3244
}
3245
/* evfscfsi */
3246
HELPER_SPE_VECTOR_CONV(fscfsi);
3247
/* evfscfui */
3248
HELPER_SPE_VECTOR_CONV(fscfui);
3249
/* evfscfuf */
3250
HELPER_SPE_VECTOR_CONV(fscfuf);
3251
/* evfscfsf */
3252
HELPER_SPE_VECTOR_CONV(fscfsf);
3253
/* evfsctsi */
3254
HELPER_SPE_VECTOR_CONV(fsctsi);
3255
/* evfsctui */
3256
HELPER_SPE_VECTOR_CONV(fsctui);
3257
/* evfsctsiz */
3258
HELPER_SPE_VECTOR_CONV(fsctsiz);
3259
/* evfsctuiz */
3260
HELPER_SPE_VECTOR_CONV(fsctuiz);
3261
/* evfsctsf */
3262
HELPER_SPE_VECTOR_CONV(fsctsf);
3263
/* evfsctuf */
3264
HELPER_SPE_VECTOR_CONV(fsctuf);
3265

    
3266
/* Single-precision floating-point arithmetic */
3267
static always_inline uint32_t efsadd (uint32_t op1, uint32_t op2)
3268
{
3269
    CPU_FloatU u1, u2;
3270
    u1.l = op1;
3271
    u2.l = op2;
3272
    u1.f = float32_add(u1.f, u2.f, &env->vec_status);
3273
    return u1.l;
3274
}
3275

    
3276
static always_inline uint32_t efssub (uint32_t op1, uint32_t op2)
3277
{
3278
    CPU_FloatU u1, u2;
3279
    u1.l = op1;
3280
    u2.l = op2;
3281
    u1.f = float32_sub(u1.f, u2.f, &env->vec_status);
3282
    return u1.l;
3283
}
3284

    
3285
static always_inline uint32_t efsmul (uint32_t op1, uint32_t op2)
3286
{
3287
    CPU_FloatU u1, u2;
3288
    u1.l = op1;
3289
    u2.l = op2;
3290
    u1.f = float32_mul(u1.f, u2.f, &env->vec_status);
3291
    return u1.l;
3292
}
3293

    
3294
static always_inline uint32_t efsdiv (uint32_t op1, uint32_t op2)
3295
{
3296
    CPU_FloatU u1, u2;
3297
    u1.l = op1;
3298
    u2.l = op2;
3299
    u1.f = float32_div(u1.f, u2.f, &env->vec_status);
3300
    return u1.l;
3301
}
3302

    
3303
#define HELPER_SPE_SINGLE_ARITH(name)                                         \
3304
uint32_t helper_e##name (uint32_t op1, uint32_t op2)                          \
3305
{                                                                             \
3306
    return e##name(op1, op2);                                                 \
3307
}
3308
/* efsadd */
3309
HELPER_SPE_SINGLE_ARITH(fsadd);
3310
/* efssub */
3311
HELPER_SPE_SINGLE_ARITH(fssub);
3312
/* efsmul */
3313
HELPER_SPE_SINGLE_ARITH(fsmul);
3314
/* efsdiv */
3315
HELPER_SPE_SINGLE_ARITH(fsdiv);
3316

    
3317
#define HELPER_SPE_VECTOR_ARITH(name)                                         \
3318
uint64_t helper_ev##name (uint64_t op1, uint64_t op2)                         \
3319
{                                                                             \
3320
    return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) |                  \
3321
            (uint64_t)e##name(op1, op2);                                      \
3322
}
3323
/* evfsadd */
3324
HELPER_SPE_VECTOR_ARITH(fsadd);
3325
/* evfssub */
3326
HELPER_SPE_VECTOR_ARITH(fssub);
3327
/* evfsmul */
3328
HELPER_SPE_VECTOR_ARITH(fsmul);
3329
/* evfsdiv */
3330
HELPER_SPE_VECTOR_ARITH(fsdiv);
3331

    
3332
/* Single-precision floating-point comparisons */
3333
static always_inline uint32_t efststlt (uint32_t op1, uint32_t op2)
3334
{
3335
    CPU_FloatU u1, u2;
3336
    u1.l = op1;
3337
    u2.l = op2;
3338
    return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0;
3339
}
3340

    
3341
static always_inline uint32_t efststgt (uint32_t op1, uint32_t op2)
3342
{
3343
    CPU_FloatU u1, u2;
3344
    u1.l = op1;
3345
    u2.l = op2;
3346
    return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4;
3347
}
3348

    
3349
static always_inline uint32_t efststeq (uint32_t op1, uint32_t op2)
3350
{
3351
    CPU_FloatU u1, u2;
3352
    u1.l = op1;
3353
    u2.l = op2;
3354
    return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0;
3355
}
3356

    
3357
static always_inline uint32_t efscmplt (uint32_t op1, uint32_t op2)
3358
{
3359
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3360
    return efststlt(op1, op2);
3361
}
3362

    
3363
static always_inline uint32_t efscmpgt (uint32_t op1, uint32_t op2)
3364
{
3365
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3366
    return efststgt(op1, op2);
3367
}
3368

    
3369
static always_inline uint32_t efscmpeq (uint32_t op1, uint32_t op2)
3370
{
3371
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3372
    return efststeq(op1, op2);
3373
}
3374

    
3375
#define HELPER_SINGLE_SPE_CMP(name)                                           \
3376
uint32_t helper_e##name (uint32_t op1, uint32_t op2)                          \
3377
{                                                                             \
3378
    return e##name(op1, op2) << 2;                                            \
3379
}
3380
/* efststlt */
3381
HELPER_SINGLE_SPE_CMP(fststlt);
3382
/* efststgt */
3383
HELPER_SINGLE_SPE_CMP(fststgt);
3384
/* efststeq */
3385
HELPER_SINGLE_SPE_CMP(fststeq);
3386
/* efscmplt */
3387
HELPER_SINGLE_SPE_CMP(fscmplt);
3388
/* efscmpgt */
3389
HELPER_SINGLE_SPE_CMP(fscmpgt);
3390
/* efscmpeq */
3391
HELPER_SINGLE_SPE_CMP(fscmpeq);
3392

    
3393
static always_inline uint32_t evcmp_merge (int t0, int t1)
3394
{
3395
    return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
3396
}
3397

    
3398
#define HELPER_VECTOR_SPE_CMP(name)                                           \
3399
uint32_t helper_ev##name (uint64_t op1, uint64_t op2)                         \
3400
{                                                                             \
3401
    return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2));     \
3402
}
3403
/* evfststlt */
3404
HELPER_VECTOR_SPE_CMP(fststlt);
3405
/* evfststgt */
3406
HELPER_VECTOR_SPE_CMP(fststgt);
3407
/* evfststeq */
3408
HELPER_VECTOR_SPE_CMP(fststeq);
3409
/* evfscmplt */
3410
HELPER_VECTOR_SPE_CMP(fscmplt);
3411
/* evfscmpgt */
3412
HELPER_VECTOR_SPE_CMP(fscmpgt);
3413
/* evfscmpeq */
3414
HELPER_VECTOR_SPE_CMP(fscmpeq);
3415

    
3416
/* Double-precision floating-point conversion */
3417
uint64_t helper_efdcfsi (uint32_t val)
3418
{
3419
    CPU_DoubleU u;
3420

    
3421
    u.d = int32_to_float64(val, &env->vec_status);
3422

    
3423
    return u.ll;
3424
}
3425

    
3426
uint64_t helper_efdcfsid (uint64_t val)
3427
{
3428
    CPU_DoubleU u;
3429

    
3430
    u.d = int64_to_float64(val, &env->vec_status);
3431

    
3432
    return u.ll;
3433
}
3434

    
3435
uint64_t helper_efdcfui (uint32_t val)
3436
{
3437
    CPU_DoubleU u;
3438

    
3439
    u.d = uint32_to_float64(val, &env->vec_status);
3440

    
3441
    return u.ll;
3442
}
3443

    
3444
uint64_t helper_efdcfuid (uint64_t val)
3445
{
3446
    CPU_DoubleU u;
3447

    
3448
    u.d = uint64_to_float64(val, &env->vec_status);
3449

    
3450
    return u.ll;
3451
}
3452

    
3453
uint32_t helper_efdctsi (uint64_t val)
3454
{
3455
    CPU_DoubleU u;
3456

    
3457
    u.ll = val;
3458
    /* NaN are not treated the same way IEEE 754 does */
3459
    if (unlikely(float64_is_nan(u.d)))
3460
        return 0;
3461

    
3462
    return float64_to_int32(u.d, &env->vec_status);
3463
}
3464

    
3465
uint32_t helper_efdctui (uint64_t val)
3466
{
3467
    CPU_DoubleU u;
3468

    
3469
    u.ll = val;
3470
    /* NaN are not treated the same way IEEE 754 does */
3471
    if (unlikely(float64_is_nan(u.d)))
3472
        return 0;
3473

    
3474
    return float64_to_uint32(u.d, &env->vec_status);
3475
}
3476

    
3477
uint32_t helper_efdctsiz (uint64_t val)
3478
{
3479
    CPU_DoubleU u;
3480

    
3481
    u.ll = val;
3482
    /* NaN are not treated the same way IEEE 754 does */
3483
    if (unlikely(float64_is_nan(u.d)))
3484
        return 0;
3485

    
3486
    return float64_to_int32_round_to_zero(u.d, &env->vec_status);
3487
}
3488

    
3489
uint64_t helper_efdctsidz (uint64_t val)
3490
{
3491
    CPU_DoubleU u;
3492

    
3493
    u.ll = val;
3494
    /* NaN are not treated the same way IEEE 754 does */
3495
    if (unlikely(float64_is_nan(u.d)))
3496
        return 0;
3497

    
3498
    return float64_to_int64_round_to_zero(u.d, &env->vec_status);
3499
}
3500

    
3501
uint32_t helper_efdctuiz (uint64_t val)
3502
{
3503
    CPU_DoubleU u;
3504

    
3505
    u.ll = val;
3506
    /* NaN are not treated the same way IEEE 754 does */
3507
    if (unlikely(float64_is_nan(u.d)))
3508
        return 0;
3509

    
3510
    return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
3511
}
3512

    
3513
uint64_t helper_efdctuidz (uint64_t val)
3514
{
3515
    CPU_DoubleU u;
3516

    
3517
    u.ll = val;
3518
    /* NaN are not treated the same way IEEE 754 does */
3519
    if (unlikely(float64_is_nan(u.d)))
3520
        return 0;
3521

    
3522
    return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
3523
}
3524

    
3525
uint64_t helper_efdcfsf (uint32_t val)
3526
{
3527
    CPU_DoubleU u;
3528
    float64 tmp;
3529

    
3530
    u.d = int32_to_float64(val, &env->vec_status);
3531
    tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3532
    u.d = float64_div(u.d, tmp, &env->vec_status);
3533

    
3534
    return u.ll;
3535
}
3536

    
3537
uint64_t helper_efdcfuf (uint32_t val)
3538
{
3539
    CPU_DoubleU u;
3540
    float64 tmp;
3541

    
3542
    u.d = uint32_to_float64(val, &env->vec_status);
3543
    tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3544
    u.d = float64_div(u.d, tmp, &env->vec_status);
3545

    
3546
    return u.ll;
3547
}
3548

    
3549
uint32_t helper_efdctsf (uint64_t val)
3550
{
3551
    CPU_DoubleU u;
3552
    float64 tmp;
3553

    
3554
    u.ll = val;
3555
    /* NaN are not treated the same way IEEE 754 does */
3556
    if (unlikely(float64_is_nan(u.d)))
3557
        return 0;
3558
    tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3559
    u.d = float64_mul(u.d, tmp, &env->vec_status);
3560

    
3561
    return float64_to_int32(u.d, &env->vec_status);
3562
}
3563

    
3564
uint32_t helper_efdctuf (uint64_t val)
3565
{
3566
    CPU_DoubleU u;
3567
    float64 tmp;
3568

    
3569
    u.ll = val;
3570
    /* NaN are not treated the same way IEEE 754 does */
3571
    if (unlikely(float64_is_nan(u.d)))
3572
        return 0;
3573
    tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3574
    u.d = float64_mul(u.d, tmp, &env->vec_status);
3575

    
3576
    return float64_to_uint32(u.d, &env->vec_status);
3577
}
3578

    
3579
uint32_t helper_efscfd (uint64_t val)
3580
{
3581
    CPU_DoubleU u1;
3582
    CPU_FloatU u2;
3583

    
3584
    u1.ll = val;
3585
    u2.f = float64_to_float32(u1.d, &env->vec_status);
3586

    
3587
    return u2.l;
3588
}
3589

    
3590
uint64_t helper_efdcfs (uint32_t val)
3591
{
3592
    CPU_DoubleU u2;
3593
    CPU_FloatU u1;
3594

    
3595
    u1.l = val;
3596
    u2.d = float32_to_float64(u1.f, &env->vec_status);
3597

    
3598
    return u2.ll;
3599
}
3600

    
3601
/* Double precision fixed-point arithmetic */
3602
uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
3603
{
3604
    CPU_DoubleU u1, u2;
3605
    u1.ll = op1;
3606
    u2.ll = op2;
3607
    u1.d = float64_add(u1.d, u2.d, &env->vec_status);
3608
    return u1.ll;
3609
}
3610

    
3611
uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
3612
{
3613
    CPU_DoubleU u1, u2;
3614
    u1.ll = op1;
3615
    u2.ll = op2;
3616
    u1.d = float64_sub(u1.d, u2.d, &env->vec_status);
3617
    return u1.ll;
3618
}
3619

    
3620
uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
3621
{
3622
    CPU_DoubleU u1, u2;
3623
    u1.ll = op1;
3624
    u2.ll = op2;
3625
    u1.d = float64_mul(u1.d, u2.d, &env->vec_status);
3626
    return u1.ll;
3627
}
3628

    
3629
uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
3630
{
3631
    CPU_DoubleU u1, u2;
3632
    u1.ll = op1;
3633
    u2.ll = op2;
3634
    u1.d = float64_div(u1.d, u2.d, &env->vec_status);
3635
    return u1.ll;
3636
}
3637

    
3638
/* Double precision floating point helpers */
3639
uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
3640
{
3641
    CPU_DoubleU u1, u2;
3642
    u1.ll = op1;
3643
    u2.ll = op2;
3644
    return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0;
3645
}
3646

    
3647
uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
3648
{
3649
    CPU_DoubleU u1, u2;
3650
    u1.ll = op1;
3651
    u2.ll = op2;
3652
    return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4;
3653
}
3654

    
3655
uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
3656
{
3657
    CPU_DoubleU u1, u2;
3658
    u1.ll = op1;
3659
    u2.ll = op2;
3660
    return float64_eq(u1.d, u2.d, &env->vec_status) ? 4 : 0;
3661
}
3662

    
3663
uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
3664
{
3665
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3666
    return helper_efdtstlt(op1, op2);
3667
}
3668

    
3669
uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
3670
{
3671
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3672
    return helper_efdtstgt(op1, op2);
3673
}
3674

    
3675
uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
3676
{
3677
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3678
    return helper_efdtsteq(op1, op2);
3679
}
3680

    
3681
/*****************************************************************************/
3682
/* Softmmu support */
3683
#if !defined (CONFIG_USER_ONLY)
3684

    
3685
#define MMUSUFFIX _mmu
3686

    
3687
#define SHIFT 0
3688
#include "softmmu_template.h"
3689

    
3690
#define SHIFT 1
3691
#include "softmmu_template.h"
3692

    
3693
#define SHIFT 2
3694
#include "softmmu_template.h"
3695

    
3696
#define SHIFT 3
3697
#include "softmmu_template.h"
3698

    
3699
/* try to fill the TLB and return an exception if error. If retaddr is
3700
   NULL, it means that the function was called in C code (i.e. not
3701
   from generated code or from helper.c) */
3702
/* XXX: fix it to restore all registers */
3703
void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
3704
{
3705
    TranslationBlock *tb;
3706
    CPUState *saved_env;
3707
    unsigned long pc;
3708
    int ret;
3709

    
3710
    /* XXX: hack to restore env in all cases, even if not called from
3711
       generated code */
3712
    saved_env = env;
3713
    env = cpu_single_env;
3714
    ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
3715
    if (unlikely(ret != 0)) {
3716
        if (likely(retaddr)) {
3717
            /* now we have a real cpu fault */
3718
            pc = (unsigned long)retaddr;
3719
            tb = tb_find_pc(pc);
3720
            if (likely(tb)) {
3721
                /* the PC is inside the translated code. It means that we have
3722
                   a virtual CPU fault */
3723
                cpu_restore_state(tb, env, pc, NULL);
3724
            }
3725
        }
3726
        helper_raise_exception_err(env->exception_index, env->error_code);
3727
    }
3728
    env = saved_env;
3729
}
3730

    
3731
/* Segment registers load and store */
3732
target_ulong helper_load_sr (target_ulong sr_num)
3733
{
3734
    return env->sr[sr_num];
3735
}
3736

    
3737
void helper_store_sr (target_ulong sr_num, target_ulong val)
3738
{
3739
    ppc_store_sr(env, sr_num, val);
3740
}
3741

    
3742
/* SLB management */
3743
#if defined(TARGET_PPC64)
3744
target_ulong helper_load_slb (target_ulong slb_nr)
3745
{
3746
    return ppc_load_slb(env, slb_nr);
3747
}
3748

    
3749
void helper_store_slb (target_ulong slb_nr, target_ulong rs)
3750
{
3751
    ppc_store_slb(env, slb_nr, rs);
3752
}
3753

    
3754
void helper_slbia (void)
3755
{
3756
    ppc_slb_invalidate_all(env);
3757
}
3758

    
3759
void helper_slbie (target_ulong addr)
3760
{
3761
    ppc_slb_invalidate_one(env, addr);
3762
}
3763

    
3764
#endif /* defined(TARGET_PPC64) */
3765

    
3766
/* TLB management */
3767
void helper_tlbia (void)
3768
{
3769
    ppc_tlb_invalidate_all(env);
3770
}
3771

    
3772
void helper_tlbie (target_ulong addr)
3773
{
3774
    ppc_tlb_invalidate_one(env, addr);
3775
}
3776

    
3777
/* Software driven TLBs management */
3778
/* PowerPC 602/603 software TLB load instructions helpers */
3779
static void do_6xx_tlb (target_ulong new_EPN, int is_code)
3780
{
3781
    target_ulong RPN, CMP, EPN;
3782
    int way;
3783

    
3784
    RPN = env->spr[SPR_RPA];
3785
    if (is_code) {
3786
        CMP = env->spr[SPR_ICMP];
3787
        EPN = env->spr[SPR_IMISS];
3788
    } else {
3789
        CMP = env->spr[SPR_DCMP];
3790
        EPN = env->spr[SPR_DMISS];
3791
    }
3792
    way = (env->spr[SPR_SRR1] >> 17) & 1;
3793
    LOG_SWTLB("%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
3794
                " PTE1 " ADDRX " way %d\n",
3795
                __func__, new_EPN, EPN, CMP, RPN, way);
3796
    /* Store this TLB */
3797
    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3798
                     way, is_code, CMP, RPN);
3799
}
3800

    
3801
void helper_6xx_tlbd (target_ulong EPN)
3802
{
3803
    do_6xx_tlb(EPN, 0);
3804
}
3805

    
3806
void helper_6xx_tlbi (target_ulong EPN)
3807
{
3808
    do_6xx_tlb(EPN, 1);
3809
}
3810

    
3811
/* PowerPC 74xx software TLB load instructions helpers */
3812
static void do_74xx_tlb (target_ulong new_EPN, int is_code)
3813
{
3814
    target_ulong RPN, CMP, EPN;
3815
    int way;
3816

    
3817
    RPN = env->spr[SPR_PTELO];
3818
    CMP = env->spr[SPR_PTEHI];
3819
    EPN = env->spr[SPR_TLBMISS] & ~0x3;
3820
    way = env->spr[SPR_TLBMISS] & 0x3;
3821
    LOG_SWTLB("%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
3822
                " PTE1 " ADDRX " way %d\n",
3823
                __func__, new_EPN, EPN, CMP, RPN, way);
3824
    /* Store this TLB */
3825
    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3826
                     way, is_code, CMP, RPN);
3827
}
3828

    
3829
void helper_74xx_tlbd (target_ulong EPN)
3830
{
3831
    do_74xx_tlb(EPN, 0);
3832
}
3833

    
3834
void helper_74xx_tlbi (target_ulong EPN)
3835
{
3836
    do_74xx_tlb(EPN, 1);
3837
}
3838

    
3839
static always_inline target_ulong booke_tlb_to_page_size (int size)
3840
{
3841
    return 1024 << (2 * size);
3842
}
3843

    
3844
static always_inline int booke_page_size_to_tlb (target_ulong page_size)
3845
{
3846
    int size;
3847

    
3848
    switch (page_size) {
3849
    case 0x00000400UL:
3850
        size = 0x0;
3851
        break;
3852
    case 0x00001000UL:
3853
        size = 0x1;
3854
        break;
3855
    case 0x00004000UL:
3856
        size = 0x2;
3857
        break;
3858
    case 0x00010000UL:
3859
        size = 0x3;
3860
        break;
3861
    case 0x00040000UL:
3862
        size = 0x4;
3863
        break;
3864
    case 0x00100000UL:
3865
        size = 0x5;
3866
        break;
3867
    case 0x00400000UL:
3868
        size = 0x6;
3869
        break;
3870
    case 0x01000000UL:
3871
        size = 0x7;
3872
        break;
3873
    case 0x04000000UL:
3874
        size = 0x8;
3875
        break;
3876
    case 0x10000000UL:
3877
        size = 0x9;
3878
        break;
3879
    case 0x40000000UL:
3880
        size = 0xA;
3881
        break;
3882
#if defined (TARGET_PPC64)
3883
    case 0x000100000000ULL:
3884
        size = 0xB;
3885
        break;
3886
    case 0x000400000000ULL:
3887
        size = 0xC;
3888
        break;
3889
    case 0x001000000000ULL:
3890
        size = 0xD;
3891
        break;
3892
    case 0x004000000000ULL:
3893
        size = 0xE;
3894
        break;
3895
    case 0x010000000000ULL:
3896
        size = 0xF;
3897
        break;
3898
#endif
3899
    default:
3900
        size = -1;
3901
        break;
3902
    }
3903

    
3904
    return size;
3905
}
3906

    
3907
/* Helpers for 4xx TLB management */
3908
target_ulong helper_4xx_tlbre_lo (target_ulong entry)
3909
{
3910
    ppcemb_tlb_t *tlb;
3911
    target_ulong ret;
3912
    int size;
3913

    
3914
    entry &= 0x3F;
3915
    tlb = &env->tlb[entry].tlbe;
3916
    ret = tlb->EPN;
3917
    if (tlb->prot & PAGE_VALID)
3918
        ret |= 0x400;
3919
    size = booke_page_size_to_tlb(tlb->size);
3920
    if (size < 0 || size > 0x7)
3921
        size = 1;
3922
    ret |= size << 7;
3923
    env->spr[SPR_40x_PID] = tlb->PID;
3924
    return ret;
3925
}
3926

    
3927
target_ulong helper_4xx_tlbre_hi (target_ulong entry)
3928
{
3929
    ppcemb_tlb_t *tlb;
3930
    target_ulong ret;
3931

    
3932
    entry &= 0x3F;
3933
    tlb = &env->tlb[entry].tlbe;
3934
    ret = tlb->RPN;
3935
    if (tlb->prot & PAGE_EXEC)
3936
        ret |= 0x200;
3937
    if (tlb->prot & PAGE_WRITE)
3938
        ret |= 0x100;
3939
    return ret;
3940
}
3941

    
3942
void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
3943
{
3944
    ppcemb_tlb_t *tlb;
3945
    target_ulong page, end;
3946

    
3947
    LOG_SWTLB("%s entry %d val " ADDRX "\n", __func__, (int)entry, val);
3948
    entry &= 0x3F;
3949
    tlb = &env->tlb[entry].tlbe;
3950
    /* Invalidate previous TLB (if it's valid) */
3951
    if (tlb->prot & PAGE_VALID) {
3952
        end = tlb->EPN + tlb->size;
3953
        LOG_SWTLB("%s: invalidate old TLB %d start " ADDRX
3954
                    " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
3955
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3956
            tlb_flush_page(env, page);
3957
    }
3958
    tlb->size = booke_tlb_to_page_size((val >> 7) & 0x7);
3959
    /* We cannot handle TLB size < TARGET_PAGE_SIZE.
3960
     * If this ever occurs, one should use the ppcemb target instead
3961
     * of the ppc or ppc64 one
3962
     */
3963
    if ((val & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
3964
        cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
3965
                  "are not supported (%d)\n",
3966
                  tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
3967
    }
3968
    tlb->EPN = val & ~(tlb->size - 1);
3969
    if (val & 0x40)
3970
        tlb->prot |= PAGE_VALID;
3971
    else
3972
        tlb->prot &= ~PAGE_VALID;
3973
    if (val & 0x20) {
3974
        /* XXX: TO BE FIXED */
3975
        cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
3976
    }
3977
    tlb->PID = env->spr[SPR_40x_PID]; /* PID */
3978
    tlb->attr = val & 0xFF;
3979
    LOG_SWTLB("%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
3980
                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
3981
                (int)entry, tlb->RPN, tlb->EPN, tlb->size,
3982
                tlb->prot & PAGE_READ ? 'r' : '-',
3983
                tlb->prot & PAGE_WRITE ? 'w' : '-',
3984
                tlb->prot & PAGE_EXEC ? 'x' : '-',
3985
                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
3986
    /* Invalidate new TLB (if valid) */
3987
    if (tlb->prot & PAGE_VALID) {
3988
        end = tlb->EPN + tlb->size;
3989
        LOG_SWTLB("%s: invalidate TLB %d start " ADDRX
3990
                    " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
3991
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3992
            tlb_flush_page(env, page);
3993
    }
3994
}
3995

    
3996
void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
3997
{
3998
    ppcemb_tlb_t *tlb;
3999

    
4000
    LOG_SWTLB("%s entry %i val " ADDRX "\n", __func__, (int)entry, val);
4001
    entry &= 0x3F;
4002
    tlb = &env->tlb[entry].tlbe;
4003
    tlb->RPN = val & 0xFFFFFC00;
4004
    tlb->prot = PAGE_READ;
4005
    if (val & 0x200)
4006
        tlb->prot |= PAGE_EXEC;
4007
    if (val & 0x100)
4008
        tlb->prot |= PAGE_WRITE;
4009
    LOG_SWTLB("%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
4010
                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
4011
                (int)entry, tlb->RPN, tlb->EPN, tlb->size,
4012
                tlb->prot & PAGE_READ ? 'r' : '-',
4013
                tlb->prot & PAGE_WRITE ? 'w' : '-',
4014
                tlb->prot & PAGE_EXEC ? 'x' : '-',
4015
                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
4016
}
4017

    
4018
target_ulong helper_4xx_tlbsx (target_ulong address)
4019
{
4020
    return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
4021
}
4022

    
4023
/* PowerPC 440 TLB management */
4024
void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
4025
{
4026
    ppcemb_tlb_t *tlb;
4027
    target_ulong EPN, RPN, size;
4028
    int do_flush_tlbs;
4029

    
4030
    LOG_SWTLB("%s word %d entry %d value " ADDRX "\n",
4031
                __func__, word, (int)entry, value);
4032
    do_flush_tlbs = 0;
4033
    entry &= 0x3F;
4034
    tlb = &env->tlb[entry].tlbe;
4035
    switch (word) {
4036
    default:
4037
        /* Just here to please gcc */
4038
    case 0:
4039
        EPN = value & 0xFFFFFC00;
4040
        if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
4041
            do_flush_tlbs = 1;
4042
        tlb->EPN = EPN;
4043
        size = booke_tlb_to_page_size((value >> 4) & 0xF);
4044
        if ((tlb->prot & PAGE_VALID) && tlb->size < size)
4045
            do_flush_tlbs = 1;
4046
        tlb->size = size;
4047
        tlb->attr &= ~0x1;
4048
        tlb->attr |= (value >> 8) & 1;
4049
        if (value & 0x200) {
4050
            tlb->prot |= PAGE_VALID;
4051
        } else {
4052
            if (tlb->prot & PAGE_VALID) {
4053
                tlb->prot &= ~PAGE_VALID;
4054
                do_flush_tlbs = 1;
4055
            }
4056
        }
4057
        tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
4058
        if (do_flush_tlbs)
4059
            tlb_flush(env, 1);
4060
        break;
4061
    case 1:
4062
        RPN = value & 0xFFFFFC0F;
4063
        if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
4064
            tlb_flush(env, 1);
4065
        tlb->RPN = RPN;
4066
        break;
4067
    case 2:
4068
        tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
4069
        tlb->prot = tlb->prot & PAGE_VALID;
4070
        if (value & 0x1)
4071
            tlb->prot |= PAGE_READ << 4;
4072
        if (value & 0x2)
4073
            tlb->prot |= PAGE_WRITE << 4;
4074
        if (value & 0x4)
4075
            tlb->prot |= PAGE_EXEC << 4;
4076
        if (value & 0x8)
4077
            tlb->prot |= PAGE_READ;
4078
        if (value & 0x10)
4079
            tlb->prot |= PAGE_WRITE;
4080
        if (value & 0x20)
4081
            tlb->prot |= PAGE_EXEC;
4082
        break;
4083
    }
4084
}
4085

    
4086
target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
4087
{
4088
    ppcemb_tlb_t *tlb;
4089
    target_ulong ret;
4090
    int size;
4091

    
4092
    entry &= 0x3F;
4093
    tlb = &env->tlb[entry].tlbe;
4094
    switch (word) {
4095
    default:
4096
        /* Just here to please gcc */
4097
    case 0:
4098
        ret = tlb->EPN;
4099
        size = booke_page_size_to_tlb(tlb->size);
4100
        if (size < 0 || size > 0xF)
4101
            size = 1;
4102
        ret |= size << 4;
4103
        if (tlb->attr & 0x1)
4104
            ret |= 0x100;
4105
        if (tlb->prot & PAGE_VALID)
4106
            ret |= 0x200;
4107
        env->spr[SPR_440_MMUCR] &= ~0x000000FF;
4108
        env->spr[SPR_440_MMUCR] |= tlb->PID;
4109
        break;
4110
    case 1:
4111
        ret = tlb->RPN;
4112
        break;
4113
    case 2:
4114
        ret = tlb->attr & ~0x1;
4115
        if (tlb->prot & (PAGE_READ << 4))
4116
            ret |= 0x1;
4117
        if (tlb->prot & (PAGE_WRITE << 4))
4118
            ret |= 0x2;
4119
        if (tlb->prot & (PAGE_EXEC << 4))
4120
            ret |= 0x4;
4121
        if (tlb->prot & PAGE_READ)
4122
            ret |= 0x8;
4123
        if (tlb->prot & PAGE_WRITE)
4124
            ret |= 0x10;
4125
        if (tlb->prot & PAGE_EXEC)
4126
            ret |= 0x20;
4127
        break;
4128
    }
4129
    return ret;
4130
}
4131

    
4132
target_ulong helper_440_tlbsx (target_ulong address)
4133
{
4134
    return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
4135
}
4136

    
4137
#endif /* !CONFIG_USER_ONLY */