Statistics
| Branch: | Revision:

root / target-ppc / op_helper.c @ f6b868fc

History | View | Annotate | Download (124.4 kB)

1
/*
2
 *  PowerPC emulation helpers for qemu.
3
 *
4
 *  Copyright (c) 2003-2007 Jocelyn Mayer
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
19
 */
20
#include <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
void helper_vrefp (ppc_avr_t *r, ppc_avr_t *b)
2668
{
2669
    int i;
2670
    for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2671
        HANDLE_NAN1(r->f[i], b->f[i]) {
2672
            r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status);
2673
        }
2674
    }
2675
}
2676

    
2677
#define VRFI(suffix, rounding)                                          \
2678
    void helper_vrfi##suffix (ppc_avr_t *r, ppc_avr_t *b)               \
2679
    {                                                                   \
2680
        int i;                                                          \
2681
        float_status s = env->vec_status;                               \
2682
        set_float_rounding_mode(rounding, &s);                          \
2683
        for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
2684
            HANDLE_NAN1(r->f[i], b->f[i]) {                             \
2685
                r->f[i] = float32_round_to_int (b->f[i], &s);           \
2686
            }                                                           \
2687
        }                                                               \
2688
    }
2689
VRFI(n, float_round_nearest_even)
2690
VRFI(m, float_round_down)
2691
VRFI(p, float_round_up)
2692
VRFI(z, float_round_to_zero)
2693
#undef VRFI
2694

    
2695
#define VROTATE(suffix, element)                                        \
2696
    void helper_vrl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
2697
    {                                                                   \
2698
        int i;                                                          \
2699
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2700
            unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2701
            unsigned int shift = b->element[i] & mask;                  \
2702
            r->element[i] = (a->element[i] << shift) | (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
2703
        }                                                               \
2704
    }
2705
VROTATE(b, u8)
2706
VROTATE(h, u16)
2707
VROTATE(w, u32)
2708
#undef VROTATE
2709

    
2710
void helper_vrsqrtefp (ppc_avr_t *r, ppc_avr_t *b)
2711
{
2712
    int i;
2713
    for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2714
        HANDLE_NAN1(r->f[i], b->f[i]) {
2715
            float32 t = float32_sqrt(b->f[i], &env->vec_status);
2716
            r->f[i] = float32_div(float32_one, t, &env->vec_status);
2717
        }
2718
    }
2719
}
2720

    
2721
void helper_vsel (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2722
{
2723
    r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
2724
    r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
2725
}
2726

    
2727
void helper_vlogefp (ppc_avr_t *r, ppc_avr_t *b)
2728
{
2729
    int i;
2730
    for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2731
        HANDLE_NAN1(r->f[i], b->f[i]) {
2732
            r->f[i] = float32_log2(b->f[i], &env->vec_status);
2733
        }
2734
    }
2735
}
2736

    
2737
#if defined(WORDS_BIGENDIAN)
2738
#define LEFT 0
2739
#define RIGHT 1
2740
#else
2741
#define LEFT 1
2742
#define RIGHT 0
2743
#endif
2744
/* The specification says that the results are undefined if all of the
2745
 * shift counts are not identical.  We check to make sure that they are
2746
 * to conform to what real hardware appears to do.  */
2747
#define VSHIFT(suffix, leftp)                                           \
2748
    void helper_vs##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)   \
2749
    {                                                                   \
2750
        int shift = b->u8[LO_IDX*0x15] & 0x7;                           \
2751
        int doit = 1;                                                   \
2752
        int i;                                                          \
2753
        for (i = 0; i < ARRAY_SIZE(r->u8); i++) {                       \
2754
            doit = doit && ((b->u8[i] & 0x7) == shift);                 \
2755
        }                                                               \
2756
        if (doit) {                                                     \
2757
            if (shift == 0) {                                           \
2758
                *r = *a;                                                \
2759
            } else if (leftp) {                                         \
2760
                uint64_t carry = a->u64[LO_IDX] >> (64 - shift);        \
2761
                r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry;     \
2762
                r->u64[LO_IDX] = a->u64[LO_IDX] << shift;               \
2763
            } else {                                                    \
2764
                uint64_t carry = a->u64[HI_IDX] << (64 - shift);        \
2765
                r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry;     \
2766
                r->u64[HI_IDX] = a->u64[HI_IDX] >> shift;               \
2767
            }                                                           \
2768
        }                                                               \
2769
    }
2770
VSHIFT(l, LEFT)
2771
VSHIFT(r, RIGHT)
2772
#undef VSHIFT
2773
#undef LEFT
2774
#undef RIGHT
2775

    
2776
#define VSL(suffix, element)                                            \
2777
    void helper_vsl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
2778
    {                                                                   \
2779
        int i;                                                          \
2780
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2781
            unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2782
            unsigned int shift = b->element[i] & mask;                  \
2783
            r->element[i] = a->element[i] << shift;                     \
2784
        }                                                               \
2785
    }
2786
VSL(b, u8)
2787
VSL(h, u16)
2788
VSL(w, u32)
2789
#undef VSL
2790

    
2791
void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
2792
{
2793
    int sh = shift & 0xf;
2794
    int i;
2795
    ppc_avr_t result;
2796

    
2797
#if defined(WORDS_BIGENDIAN)
2798
    for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2799
        int index = sh + i;
2800
        if (index > 0xf) {
2801
            result.u8[i] = b->u8[index-0x10];
2802
        } else {
2803
            result.u8[i] = a->u8[index];
2804
        }
2805
    }
2806
#else
2807
    for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2808
        int index = (16 - sh) + i;
2809
        if (index > 0xf) {
2810
            result.u8[i] = a->u8[index-0x10];
2811
        } else {
2812
            result.u8[i] = b->u8[index];
2813
        }
2814
    }
2815
#endif
2816
    *r = result;
2817
}
2818

    
2819
void helper_vslo (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2820
{
2821
  int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2822

    
2823
#if defined (WORDS_BIGENDIAN)
2824
  memmove (&r->u8[0], &a->u8[sh], 16-sh);
2825
  memset (&r->u8[16-sh], 0, sh);
2826
#else
2827
  memmove (&r->u8[sh], &a->u8[0], 16-sh);
2828
  memset (&r->u8[0], 0, sh);
2829
#endif
2830
}
2831

    
2832
/* Experimental testing shows that hardware masks the immediate.  */
2833
#define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
2834
#if defined(WORDS_BIGENDIAN)
2835
#define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
2836
#else
2837
#define SPLAT_ELEMENT(element) (ARRAY_SIZE(r->element)-1 - _SPLAT_MASKED(element))
2838
#endif
2839
#define VSPLT(suffix, element)                                          \
2840
    void helper_vsplt##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
2841
    {                                                                   \
2842
        uint32_t s = b->element[SPLAT_ELEMENT(element)];                \
2843
        int i;                                                          \
2844
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2845
            r->element[i] = s;                                          \
2846
        }                                                               \
2847
    }
2848
VSPLT(b, u8)
2849
VSPLT(h, u16)
2850
VSPLT(w, u32)
2851
#undef VSPLT
2852
#undef SPLAT_ELEMENT
2853
#undef _SPLAT_MASKED
2854

    
2855
#define VSPLTI(suffix, element, splat_type)                     \
2856
    void helper_vspltis##suffix (ppc_avr_t *r, uint32_t splat)  \
2857
    {                                                           \
2858
        splat_type x = (int8_t)(splat << 3) >> 3;               \
2859
        int i;                                                  \
2860
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {          \
2861
            r->element[i] = x;                                  \
2862
        }                                                       \
2863
    }
2864
VSPLTI(b, s8, int8_t)
2865
VSPLTI(h, s16, int16_t)
2866
VSPLTI(w, s32, int32_t)
2867
#undef VSPLTI
2868

    
2869
#define VSR(suffix, element)                                            \
2870
    void helper_vsr##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
2871
    {                                                                   \
2872
        int i;                                                          \
2873
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2874
            unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2875
            unsigned int shift = b->element[i] & mask;                  \
2876
            r->element[i] = a->element[i] >> shift;                     \
2877
        }                                                               \
2878
    }
2879
VSR(ab, s8)
2880
VSR(ah, s16)
2881
VSR(aw, s32)
2882
VSR(b, u8)
2883
VSR(h, u16)
2884
VSR(w, u32)
2885
#undef VSR
2886

    
2887
void helper_vsro (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2888
{
2889
  int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2890

    
2891
#if defined (WORDS_BIGENDIAN)
2892
  memmove (&r->u8[sh], &a->u8[0], 16-sh);
2893
  memset (&r->u8[0], 0, sh);
2894
#else
2895
  memmove (&r->u8[0], &a->u8[sh], 16-sh);
2896
  memset (&r->u8[16-sh], 0, sh);
2897
#endif
2898
}
2899

    
2900
void helper_vsubcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2901
{
2902
    int i;
2903
    for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2904
        r->u32[i] = a->u32[i] >= b->u32[i];
2905
    }
2906
}
2907

    
2908
void helper_vsumsws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2909
{
2910
    int64_t t;
2911
    int i, upper;
2912
    ppc_avr_t result;
2913
    int sat = 0;
2914

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

    
2928
    if (sat) {
2929
        env->vscr |= (1 << VSCR_SAT);
2930
    }
2931
}
2932

    
2933
void helper_vsum2sws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2934
{
2935
    int i, j, upper;
2936
    ppc_avr_t result;
2937
    int sat = 0;
2938

    
2939
#if defined(WORDS_BIGENDIAN)
2940
    upper = 1;
2941
#else
2942
    upper = 0;
2943
#endif
2944
    for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
2945
        int64_t t = (int64_t)b->s32[upper+i*2];
2946
        result.u64[i] = 0;
2947
        for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
2948
            t += a->s32[2*i+j];
2949
        }
2950
        result.s32[upper+i*2] = cvtsdsw(t, &sat);
2951
    }
2952

    
2953
    *r = result;
2954
    if (sat) {
2955
        env->vscr |= (1 << VSCR_SAT);
2956
    }
2957
}
2958

    
2959
void helper_vsum4sbs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2960
{
2961
    int i, j;
2962
    int sat = 0;
2963

    
2964
    for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2965
        int64_t t = (int64_t)b->s32[i];
2966
        for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
2967
            t += a->s8[4*i+j];
2968
        }
2969
        r->s32[i] = cvtsdsw(t, &sat);
2970
    }
2971

    
2972
    if (sat) {
2973
        env->vscr |= (1 << VSCR_SAT);
2974
    }
2975
}
2976

    
2977
void helper_vsum4shs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2978
{
2979
    int sat = 0;
2980
    int i;
2981

    
2982
    for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2983
        int64_t t = (int64_t)b->s32[i];
2984
        t += a->s16[2*i] + a->s16[2*i+1];
2985
        r->s32[i] = cvtsdsw(t, &sat);
2986
    }
2987

    
2988
    if (sat) {
2989
        env->vscr |= (1 << VSCR_SAT);
2990
    }
2991
}
2992

    
2993
void helper_vsum4ubs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2994
{
2995
    int i, j;
2996
    int sat = 0;
2997

    
2998
    for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2999
        uint64_t t = (uint64_t)b->u32[i];
3000
        for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
3001
            t += a->u8[4*i+j];
3002
        }
3003
        r->u32[i] = cvtuduw(t, &sat);
3004
    }
3005

    
3006
    if (sat) {
3007
        env->vscr |= (1 << VSCR_SAT);
3008
    }
3009
}
3010

    
3011
#if defined(WORDS_BIGENDIAN)
3012
#define UPKHI 1
3013
#define UPKLO 0
3014
#else
3015
#define UPKHI 0
3016
#define UPKLO 1
3017
#endif
3018
#define VUPKPX(suffix, hi)                                      \
3019
    void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b)       \
3020
    {                                                           \
3021
        int i;                                                  \
3022
        ppc_avr_t result;                                       \
3023
        for (i = 0; i < ARRAY_SIZE(r->u32); i++) {              \
3024
            uint16_t e = b->u16[hi ? i : i+4];                  \
3025
            uint8_t a = (e >> 15) ? 0xff : 0;                   \
3026
            uint8_t r = (e >> 10) & 0x1f;                       \
3027
            uint8_t g = (e >> 5) & 0x1f;                        \
3028
            uint8_t b = e & 0x1f;                               \
3029
            result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b;       \
3030
        }                                                               \
3031
        *r = result;                                                    \
3032
    }
3033
VUPKPX(lpx, UPKLO)
3034
VUPKPX(hpx, UPKHI)
3035
#undef VUPKPX
3036

    
3037
#define VUPK(suffix, unpacked, packee, hi)                              \
3038
    void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b)               \
3039
    {                                                                   \
3040
        int i;                                                          \
3041
        ppc_avr_t result;                                               \
3042
        if (hi) {                                                       \
3043
            for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) {             \
3044
                result.unpacked[i] = b->packee[i];                      \
3045
            }                                                           \
3046
        } else {                                                        \
3047
            for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); i++) { \
3048
                result.unpacked[i-ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
3049
            }                                                           \
3050
        }                                                               \
3051
        *r = result;                                                    \
3052
    }
3053
VUPK(hsb, s16, s8, UPKHI)
3054
VUPK(hsh, s32, s16, UPKHI)
3055
VUPK(lsb, s16, s8, UPKLO)
3056
VUPK(lsh, s32, s16, UPKLO)
3057
#undef VUPK
3058
#undef UPKHI
3059
#undef UPKLO
3060

    
3061
#undef DO_HANDLE_NAN
3062
#undef HANDLE_NAN1
3063
#undef HANDLE_NAN2
3064
#undef HANDLE_NAN3
3065
#undef VECTOR_FOR_INORDER_I
3066
#undef HI_IDX
3067
#undef LO_IDX
3068

    
3069
/*****************************************************************************/
3070
/* SPE extension helpers */
3071
/* Use a table to make this quicker */
3072
static uint8_t hbrev[16] = {
3073
    0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
3074
    0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
3075
};
3076

    
3077
static always_inline uint8_t byte_reverse (uint8_t val)
3078
{
3079
    return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
3080
}
3081

    
3082
static always_inline uint32_t word_reverse (uint32_t val)
3083
{
3084
    return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
3085
        (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
3086
}
3087

    
3088
#define MASKBITS 16 // Random value - to be fixed (implementation dependant)
3089
target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
3090
{
3091
    uint32_t a, b, d, mask;
3092

    
3093
    mask = UINT32_MAX >> (32 - MASKBITS);
3094
    a = arg1 & mask;
3095
    b = arg2 & mask;
3096
    d = word_reverse(1 + word_reverse(a | ~b));
3097
    return (arg1 & ~mask) | (d & b);
3098
}
3099

    
3100
uint32_t helper_cntlsw32 (uint32_t val)
3101
{
3102
    if (val & 0x80000000)
3103
        return clz32(~val);
3104
    else
3105
        return clz32(val);
3106
}
3107

    
3108
uint32_t helper_cntlzw32 (uint32_t val)
3109
{
3110
    return clz32(val);
3111
}
3112

    
3113
/* Single-precision floating-point conversions */
3114
static always_inline uint32_t efscfsi (uint32_t val)
3115
{
3116
    CPU_FloatU u;
3117

    
3118
    u.f = int32_to_float32(val, &env->vec_status);
3119

    
3120
    return u.l;
3121
}
3122

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

    
3127
    u.f = uint32_to_float32(val, &env->vec_status);
3128

    
3129
    return u.l;
3130
}
3131

    
3132
static always_inline int32_t efsctsi (uint32_t val)
3133
{
3134
    CPU_FloatU u;
3135

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

    
3141
    return float32_to_int32(u.f, &env->vec_status);
3142
}
3143

    
3144
static always_inline uint32_t efsctui (uint32_t val)
3145
{
3146
    CPU_FloatU u;
3147

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

    
3153
    return float32_to_uint32(u.f, &env->vec_status);
3154
}
3155

    
3156
static always_inline uint32_t efsctsiz (uint32_t val)
3157
{
3158
    CPU_FloatU u;
3159

    
3160
    u.l = val;
3161
    /* NaN are not treated the same way IEEE 754 does */
3162
    if (unlikely(float32_is_nan(u.f)))
3163
        return 0;
3164

    
3165
    return float32_to_int32_round_to_zero(u.f, &env->vec_status);
3166
}
3167

    
3168
static always_inline uint32_t efsctuiz (uint32_t val)
3169
{
3170
    CPU_FloatU u;
3171

    
3172
    u.l = val;
3173
    /* NaN are not treated the same way IEEE 754 does */
3174
    if (unlikely(float32_is_nan(u.f)))
3175
        return 0;
3176

    
3177
    return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
3178
}
3179

    
3180
static always_inline uint32_t efscfsf (uint32_t val)
3181
{
3182
    CPU_FloatU u;
3183
    float32 tmp;
3184

    
3185
    u.f = int32_to_float32(val, &env->vec_status);
3186
    tmp = int64_to_float32(1ULL << 32, &env->vec_status);
3187
    u.f = float32_div(u.f, tmp, &env->vec_status);
3188

    
3189
    return u.l;
3190
}
3191

    
3192
static always_inline uint32_t efscfuf (uint32_t val)
3193
{
3194
    CPU_FloatU u;
3195
    float32 tmp;
3196

    
3197
    u.f = uint32_to_float32(val, &env->vec_status);
3198
    tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3199
    u.f = float32_div(u.f, tmp, &env->vec_status);
3200

    
3201
    return u.l;
3202
}
3203

    
3204
static always_inline uint32_t efsctsf (uint32_t val)
3205
{
3206
    CPU_FloatU u;
3207
    float32 tmp;
3208

    
3209
    u.l = val;
3210
    /* NaN are not treated the same way IEEE 754 does */
3211
    if (unlikely(float32_is_nan(u.f)))
3212
        return 0;
3213
    tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3214
    u.f = float32_mul(u.f, tmp, &env->vec_status);
3215

    
3216
    return float32_to_int32(u.f, &env->vec_status);
3217
}
3218

    
3219
static always_inline uint32_t efsctuf (uint32_t val)
3220
{
3221
    CPU_FloatU u;
3222
    float32 tmp;
3223

    
3224
    u.l = val;
3225
    /* NaN are not treated the same way IEEE 754 does */
3226
    if (unlikely(float32_is_nan(u.f)))
3227
        return 0;
3228
    tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3229
    u.f = float32_mul(u.f, tmp, &env->vec_status);
3230

    
3231
    return float32_to_uint32(u.f, &env->vec_status);
3232
}
3233

    
3234
#define HELPER_SPE_SINGLE_CONV(name)                                          \
3235
uint32_t helper_e##name (uint32_t val)                                        \
3236
{                                                                             \
3237
    return e##name(val);                                                      \
3238
}
3239
/* efscfsi */
3240
HELPER_SPE_SINGLE_CONV(fscfsi);
3241
/* efscfui */
3242
HELPER_SPE_SINGLE_CONV(fscfui);
3243
/* efscfuf */
3244
HELPER_SPE_SINGLE_CONV(fscfuf);
3245
/* efscfsf */
3246
HELPER_SPE_SINGLE_CONV(fscfsf);
3247
/* efsctsi */
3248
HELPER_SPE_SINGLE_CONV(fsctsi);
3249
/* efsctui */
3250
HELPER_SPE_SINGLE_CONV(fsctui);
3251
/* efsctsiz */
3252
HELPER_SPE_SINGLE_CONV(fsctsiz);
3253
/* efsctuiz */
3254
HELPER_SPE_SINGLE_CONV(fsctuiz);
3255
/* efsctsf */
3256
HELPER_SPE_SINGLE_CONV(fsctsf);
3257
/* efsctuf */
3258
HELPER_SPE_SINGLE_CONV(fsctuf);
3259

    
3260
#define HELPER_SPE_VECTOR_CONV(name)                                          \
3261
uint64_t helper_ev##name (uint64_t val)                                       \
3262
{                                                                             \
3263
    return ((uint64_t)e##name(val >> 32) << 32) |                             \
3264
            (uint64_t)e##name(val);                                           \
3265
}
3266
/* evfscfsi */
3267
HELPER_SPE_VECTOR_CONV(fscfsi);
3268
/* evfscfui */
3269
HELPER_SPE_VECTOR_CONV(fscfui);
3270
/* evfscfuf */
3271
HELPER_SPE_VECTOR_CONV(fscfuf);
3272
/* evfscfsf */
3273
HELPER_SPE_VECTOR_CONV(fscfsf);
3274
/* evfsctsi */
3275
HELPER_SPE_VECTOR_CONV(fsctsi);
3276
/* evfsctui */
3277
HELPER_SPE_VECTOR_CONV(fsctui);
3278
/* evfsctsiz */
3279
HELPER_SPE_VECTOR_CONV(fsctsiz);
3280
/* evfsctuiz */
3281
HELPER_SPE_VECTOR_CONV(fsctuiz);
3282
/* evfsctsf */
3283
HELPER_SPE_VECTOR_CONV(fsctsf);
3284
/* evfsctuf */
3285
HELPER_SPE_VECTOR_CONV(fsctuf);
3286

    
3287
/* Single-precision floating-point arithmetic */
3288
static always_inline uint32_t efsadd (uint32_t op1, uint32_t op2)
3289
{
3290
    CPU_FloatU u1, u2;
3291
    u1.l = op1;
3292
    u2.l = op2;
3293
    u1.f = float32_add(u1.f, u2.f, &env->vec_status);
3294
    return u1.l;
3295
}
3296

    
3297
static always_inline uint32_t efssub (uint32_t op1, uint32_t op2)
3298
{
3299
    CPU_FloatU u1, u2;
3300
    u1.l = op1;
3301
    u2.l = op2;
3302
    u1.f = float32_sub(u1.f, u2.f, &env->vec_status);
3303
    return u1.l;
3304
}
3305

    
3306
static always_inline uint32_t efsmul (uint32_t op1, uint32_t op2)
3307
{
3308
    CPU_FloatU u1, u2;
3309
    u1.l = op1;
3310
    u2.l = op2;
3311
    u1.f = float32_mul(u1.f, u2.f, &env->vec_status);
3312
    return u1.l;
3313
}
3314

    
3315
static always_inline uint32_t efsdiv (uint32_t op1, uint32_t op2)
3316
{
3317
    CPU_FloatU u1, u2;
3318
    u1.l = op1;
3319
    u2.l = op2;
3320
    u1.f = float32_div(u1.f, u2.f, &env->vec_status);
3321
    return u1.l;
3322
}
3323

    
3324
#define HELPER_SPE_SINGLE_ARITH(name)                                         \
3325
uint32_t helper_e##name (uint32_t op1, uint32_t op2)                          \
3326
{                                                                             \
3327
    return e##name(op1, op2);                                                 \
3328
}
3329
/* efsadd */
3330
HELPER_SPE_SINGLE_ARITH(fsadd);
3331
/* efssub */
3332
HELPER_SPE_SINGLE_ARITH(fssub);
3333
/* efsmul */
3334
HELPER_SPE_SINGLE_ARITH(fsmul);
3335
/* efsdiv */
3336
HELPER_SPE_SINGLE_ARITH(fsdiv);
3337

    
3338
#define HELPER_SPE_VECTOR_ARITH(name)                                         \
3339
uint64_t helper_ev##name (uint64_t op1, uint64_t op2)                         \
3340
{                                                                             \
3341
    return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) |                  \
3342
            (uint64_t)e##name(op1, op2);                                      \
3343
}
3344
/* evfsadd */
3345
HELPER_SPE_VECTOR_ARITH(fsadd);
3346
/* evfssub */
3347
HELPER_SPE_VECTOR_ARITH(fssub);
3348
/* evfsmul */
3349
HELPER_SPE_VECTOR_ARITH(fsmul);
3350
/* evfsdiv */
3351
HELPER_SPE_VECTOR_ARITH(fsdiv);
3352

    
3353
/* Single-precision floating-point comparisons */
3354
static always_inline uint32_t efststlt (uint32_t op1, uint32_t op2)
3355
{
3356
    CPU_FloatU u1, u2;
3357
    u1.l = op1;
3358
    u2.l = op2;
3359
    return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0;
3360
}
3361

    
3362
static always_inline uint32_t efststgt (uint32_t op1, uint32_t op2)
3363
{
3364
    CPU_FloatU u1, u2;
3365
    u1.l = op1;
3366
    u2.l = op2;
3367
    return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4;
3368
}
3369

    
3370
static always_inline uint32_t efststeq (uint32_t op1, uint32_t op2)
3371
{
3372
    CPU_FloatU u1, u2;
3373
    u1.l = op1;
3374
    u2.l = op2;
3375
    return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0;
3376
}
3377

    
3378
static always_inline uint32_t efscmplt (uint32_t op1, uint32_t op2)
3379
{
3380
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3381
    return efststlt(op1, op2);
3382
}
3383

    
3384
static always_inline uint32_t efscmpgt (uint32_t op1, uint32_t op2)
3385
{
3386
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3387
    return efststgt(op1, op2);
3388
}
3389

    
3390
static always_inline uint32_t efscmpeq (uint32_t op1, uint32_t op2)
3391
{
3392
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3393
    return efststeq(op1, op2);
3394
}
3395

    
3396
#define HELPER_SINGLE_SPE_CMP(name)                                           \
3397
uint32_t helper_e##name (uint32_t op1, uint32_t op2)                          \
3398
{                                                                             \
3399
    return e##name(op1, op2) << 2;                                            \
3400
}
3401
/* efststlt */
3402
HELPER_SINGLE_SPE_CMP(fststlt);
3403
/* efststgt */
3404
HELPER_SINGLE_SPE_CMP(fststgt);
3405
/* efststeq */
3406
HELPER_SINGLE_SPE_CMP(fststeq);
3407
/* efscmplt */
3408
HELPER_SINGLE_SPE_CMP(fscmplt);
3409
/* efscmpgt */
3410
HELPER_SINGLE_SPE_CMP(fscmpgt);
3411
/* efscmpeq */
3412
HELPER_SINGLE_SPE_CMP(fscmpeq);
3413

    
3414
static always_inline uint32_t evcmp_merge (int t0, int t1)
3415
{
3416
    return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
3417
}
3418

    
3419
#define HELPER_VECTOR_SPE_CMP(name)                                           \
3420
uint32_t helper_ev##name (uint64_t op1, uint64_t op2)                         \
3421
{                                                                             \
3422
    return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2));     \
3423
}
3424
/* evfststlt */
3425
HELPER_VECTOR_SPE_CMP(fststlt);
3426
/* evfststgt */
3427
HELPER_VECTOR_SPE_CMP(fststgt);
3428
/* evfststeq */
3429
HELPER_VECTOR_SPE_CMP(fststeq);
3430
/* evfscmplt */
3431
HELPER_VECTOR_SPE_CMP(fscmplt);
3432
/* evfscmpgt */
3433
HELPER_VECTOR_SPE_CMP(fscmpgt);
3434
/* evfscmpeq */
3435
HELPER_VECTOR_SPE_CMP(fscmpeq);
3436

    
3437
/* Double-precision floating-point conversion */
3438
uint64_t helper_efdcfsi (uint32_t val)
3439
{
3440
    CPU_DoubleU u;
3441

    
3442
    u.d = int32_to_float64(val, &env->vec_status);
3443

    
3444
    return u.ll;
3445
}
3446

    
3447
uint64_t helper_efdcfsid (uint64_t val)
3448
{
3449
    CPU_DoubleU u;
3450

    
3451
    u.d = int64_to_float64(val, &env->vec_status);
3452

    
3453
    return u.ll;
3454
}
3455

    
3456
uint64_t helper_efdcfui (uint32_t val)
3457
{
3458
    CPU_DoubleU u;
3459

    
3460
    u.d = uint32_to_float64(val, &env->vec_status);
3461

    
3462
    return u.ll;
3463
}
3464

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

    
3469
    u.d = uint64_to_float64(val, &env->vec_status);
3470

    
3471
    return u.ll;
3472
}
3473

    
3474
uint32_t helper_efdctsi (uint64_t val)
3475
{
3476
    CPU_DoubleU u;
3477

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

    
3483
    return float64_to_int32(u.d, &env->vec_status);
3484
}
3485

    
3486
uint32_t helper_efdctui (uint64_t val)
3487
{
3488
    CPU_DoubleU u;
3489

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

    
3495
    return float64_to_uint32(u.d, &env->vec_status);
3496
}
3497

    
3498
uint32_t helper_efdctsiz (uint64_t val)
3499
{
3500
    CPU_DoubleU u;
3501

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

    
3507
    return float64_to_int32_round_to_zero(u.d, &env->vec_status);
3508
}
3509

    
3510
uint64_t helper_efdctsidz (uint64_t val)
3511
{
3512
    CPU_DoubleU u;
3513

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

    
3519
    return float64_to_int64_round_to_zero(u.d, &env->vec_status);
3520
}
3521

    
3522
uint32_t helper_efdctuiz (uint64_t val)
3523
{
3524
    CPU_DoubleU u;
3525

    
3526
    u.ll = val;
3527
    /* NaN are not treated the same way IEEE 754 does */
3528
    if (unlikely(float64_is_nan(u.d)))
3529
        return 0;
3530

    
3531
    return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
3532
}
3533

    
3534
uint64_t helper_efdctuidz (uint64_t val)
3535
{
3536
    CPU_DoubleU u;
3537

    
3538
    u.ll = val;
3539
    /* NaN are not treated the same way IEEE 754 does */
3540
    if (unlikely(float64_is_nan(u.d)))
3541
        return 0;
3542

    
3543
    return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
3544
}
3545

    
3546
uint64_t helper_efdcfsf (uint32_t val)
3547
{
3548
    CPU_DoubleU u;
3549
    float64 tmp;
3550

    
3551
    u.d = int32_to_float64(val, &env->vec_status);
3552
    tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3553
    u.d = float64_div(u.d, tmp, &env->vec_status);
3554

    
3555
    return u.ll;
3556
}
3557

    
3558
uint64_t helper_efdcfuf (uint32_t val)
3559
{
3560
    CPU_DoubleU u;
3561
    float64 tmp;
3562

    
3563
    u.d = uint32_to_float64(val, &env->vec_status);
3564
    tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3565
    u.d = float64_div(u.d, tmp, &env->vec_status);
3566

    
3567
    return u.ll;
3568
}
3569

    
3570
uint32_t helper_efdctsf (uint64_t val)
3571
{
3572
    CPU_DoubleU u;
3573
    float64 tmp;
3574

    
3575
    u.ll = val;
3576
    /* NaN are not treated the same way IEEE 754 does */
3577
    if (unlikely(float64_is_nan(u.d)))
3578
        return 0;
3579
    tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3580
    u.d = float64_mul(u.d, tmp, &env->vec_status);
3581

    
3582
    return float64_to_int32(u.d, &env->vec_status);
3583
}
3584

    
3585
uint32_t helper_efdctuf (uint64_t val)
3586
{
3587
    CPU_DoubleU u;
3588
    float64 tmp;
3589

    
3590
    u.ll = val;
3591
    /* NaN are not treated the same way IEEE 754 does */
3592
    if (unlikely(float64_is_nan(u.d)))
3593
        return 0;
3594
    tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3595
    u.d = float64_mul(u.d, tmp, &env->vec_status);
3596

    
3597
    return float64_to_uint32(u.d, &env->vec_status);
3598
}
3599

    
3600
uint32_t helper_efscfd (uint64_t val)
3601
{
3602
    CPU_DoubleU u1;
3603
    CPU_FloatU u2;
3604

    
3605
    u1.ll = val;
3606
    u2.f = float64_to_float32(u1.d, &env->vec_status);
3607

    
3608
    return u2.l;
3609
}
3610

    
3611
uint64_t helper_efdcfs (uint32_t val)
3612
{
3613
    CPU_DoubleU u2;
3614
    CPU_FloatU u1;
3615

    
3616
    u1.l = val;
3617
    u2.d = float32_to_float64(u1.f, &env->vec_status);
3618

    
3619
    return u2.ll;
3620
}
3621

    
3622
/* Double precision fixed-point arithmetic */
3623
uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
3624
{
3625
    CPU_DoubleU u1, u2;
3626
    u1.ll = op1;
3627
    u2.ll = op2;
3628
    u1.d = float64_add(u1.d, u2.d, &env->vec_status);
3629
    return u1.ll;
3630
}
3631

    
3632
uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
3633
{
3634
    CPU_DoubleU u1, u2;
3635
    u1.ll = op1;
3636
    u2.ll = op2;
3637
    u1.d = float64_sub(u1.d, u2.d, &env->vec_status);
3638
    return u1.ll;
3639
}
3640

    
3641
uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
3642
{
3643
    CPU_DoubleU u1, u2;
3644
    u1.ll = op1;
3645
    u2.ll = op2;
3646
    u1.d = float64_mul(u1.d, u2.d, &env->vec_status);
3647
    return u1.ll;
3648
}
3649

    
3650
uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
3651
{
3652
    CPU_DoubleU u1, u2;
3653
    u1.ll = op1;
3654
    u2.ll = op2;
3655
    u1.d = float64_div(u1.d, u2.d, &env->vec_status);
3656
    return u1.ll;
3657
}
3658

    
3659
/* Double precision floating point helpers */
3660
uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
3661
{
3662
    CPU_DoubleU u1, u2;
3663
    u1.ll = op1;
3664
    u2.ll = op2;
3665
    return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0;
3666
}
3667

    
3668
uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
3669
{
3670
    CPU_DoubleU u1, u2;
3671
    u1.ll = op1;
3672
    u2.ll = op2;
3673
    return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4;
3674
}
3675

    
3676
uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
3677
{
3678
    CPU_DoubleU u1, u2;
3679
    u1.ll = op1;
3680
    u2.ll = op2;
3681
    return float64_eq(u1.d, u2.d, &env->vec_status) ? 4 : 0;
3682
}
3683

    
3684
uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
3685
{
3686
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3687
    return helper_efdtstlt(op1, op2);
3688
}
3689

    
3690
uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
3691
{
3692
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3693
    return helper_efdtstgt(op1, op2);
3694
}
3695

    
3696
uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
3697
{
3698
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3699
    return helper_efdtsteq(op1, op2);
3700
}
3701

    
3702
/*****************************************************************************/
3703
/* Softmmu support */
3704
#if !defined (CONFIG_USER_ONLY)
3705

    
3706
#define MMUSUFFIX _mmu
3707

    
3708
#define SHIFT 0
3709
#include "softmmu_template.h"
3710

    
3711
#define SHIFT 1
3712
#include "softmmu_template.h"
3713

    
3714
#define SHIFT 2
3715
#include "softmmu_template.h"
3716

    
3717
#define SHIFT 3
3718
#include "softmmu_template.h"
3719

    
3720
/* try to fill the TLB and return an exception if error. If retaddr is
3721
   NULL, it means that the function was called in C code (i.e. not
3722
   from generated code or from helper.c) */
3723
/* XXX: fix it to restore all registers */
3724
void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
3725
{
3726
    TranslationBlock *tb;
3727
    CPUState *saved_env;
3728
    unsigned long pc;
3729
    int ret;
3730

    
3731
    /* XXX: hack to restore env in all cases, even if not called from
3732
       generated code */
3733
    saved_env = env;
3734
    env = cpu_single_env;
3735
    ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
3736
    if (unlikely(ret != 0)) {
3737
        if (likely(retaddr)) {
3738
            /* now we have a real cpu fault */
3739
            pc = (unsigned long)retaddr;
3740
            tb = tb_find_pc(pc);
3741
            if (likely(tb)) {
3742
                /* the PC is inside the translated code. It means that we have
3743
                   a virtual CPU fault */
3744
                cpu_restore_state(tb, env, pc, NULL);
3745
            }
3746
        }
3747
        helper_raise_exception_err(env->exception_index, env->error_code);
3748
    }
3749
    env = saved_env;
3750
}
3751

    
3752
/* Segment registers load and store */
3753
target_ulong helper_load_sr (target_ulong sr_num)
3754
{
3755
#if defined(TARGET_PPC64)
3756
    if (env->mmu_model & POWERPC_MMU_64)
3757
        return ppc_load_sr(env, sr_num);
3758
#endif
3759
    return env->sr[sr_num];
3760
}
3761

    
3762
void helper_store_sr (target_ulong sr_num, target_ulong val)
3763
{
3764
    ppc_store_sr(env, sr_num, val);
3765
}
3766

    
3767
/* SLB management */
3768
#if defined(TARGET_PPC64)
3769
target_ulong helper_load_slb (target_ulong slb_nr)
3770
{
3771
    return ppc_load_slb(env, slb_nr);
3772
}
3773

    
3774
void helper_store_slb (target_ulong rb, target_ulong rs)
3775
{
3776
    ppc_store_slb(env, rb, rs);
3777
}
3778

    
3779
void helper_slbia (void)
3780
{
3781
    ppc_slb_invalidate_all(env);
3782
}
3783

    
3784
void helper_slbie (target_ulong addr)
3785
{
3786
    ppc_slb_invalidate_one(env, addr);
3787
}
3788

    
3789
#endif /* defined(TARGET_PPC64) */
3790

    
3791
/* TLB management */
3792
void helper_tlbia (void)
3793
{
3794
    ppc_tlb_invalidate_all(env);
3795
}
3796

    
3797
void helper_tlbie (target_ulong addr)
3798
{
3799
    ppc_tlb_invalidate_one(env, addr);
3800
}
3801

    
3802
/* Software driven TLBs management */
3803
/* PowerPC 602/603 software TLB load instructions helpers */
3804
static void do_6xx_tlb (target_ulong new_EPN, int is_code)
3805
{
3806
    target_ulong RPN, CMP, EPN;
3807
    int way;
3808

    
3809
    RPN = env->spr[SPR_RPA];
3810
    if (is_code) {
3811
        CMP = env->spr[SPR_ICMP];
3812
        EPN = env->spr[SPR_IMISS];
3813
    } else {
3814
        CMP = env->spr[SPR_DCMP];
3815
        EPN = env->spr[SPR_DMISS];
3816
    }
3817
    way = (env->spr[SPR_SRR1] >> 17) & 1;
3818
    LOG_SWTLB("%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
3819
                " PTE1 " ADDRX " way %d\n",
3820
                __func__, new_EPN, EPN, CMP, RPN, way);
3821
    /* Store this TLB */
3822
    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3823
                     way, is_code, CMP, RPN);
3824
}
3825

    
3826
void helper_6xx_tlbd (target_ulong EPN)
3827
{
3828
    do_6xx_tlb(EPN, 0);
3829
}
3830

    
3831
void helper_6xx_tlbi (target_ulong EPN)
3832
{
3833
    do_6xx_tlb(EPN, 1);
3834
}
3835

    
3836
/* PowerPC 74xx software TLB load instructions helpers */
3837
static void do_74xx_tlb (target_ulong new_EPN, int is_code)
3838
{
3839
    target_ulong RPN, CMP, EPN;
3840
    int way;
3841

    
3842
    RPN = env->spr[SPR_PTELO];
3843
    CMP = env->spr[SPR_PTEHI];
3844
    EPN = env->spr[SPR_TLBMISS] & ~0x3;
3845
    way = env->spr[SPR_TLBMISS] & 0x3;
3846
    LOG_SWTLB("%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
3847
                " PTE1 " ADDRX " way %d\n",
3848
                __func__, new_EPN, EPN, CMP, RPN, way);
3849
    /* Store this TLB */
3850
    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3851
                     way, is_code, CMP, RPN);
3852
}
3853

    
3854
void helper_74xx_tlbd (target_ulong EPN)
3855
{
3856
    do_74xx_tlb(EPN, 0);
3857
}
3858

    
3859
void helper_74xx_tlbi (target_ulong EPN)
3860
{
3861
    do_74xx_tlb(EPN, 1);
3862
}
3863

    
3864
static always_inline target_ulong booke_tlb_to_page_size (int size)
3865
{
3866
    return 1024 << (2 * size);
3867
}
3868

    
3869
static always_inline int booke_page_size_to_tlb (target_ulong page_size)
3870
{
3871
    int size;
3872

    
3873
    switch (page_size) {
3874
    case 0x00000400UL:
3875
        size = 0x0;
3876
        break;
3877
    case 0x00001000UL:
3878
        size = 0x1;
3879
        break;
3880
    case 0x00004000UL:
3881
        size = 0x2;
3882
        break;
3883
    case 0x00010000UL:
3884
        size = 0x3;
3885
        break;
3886
    case 0x00040000UL:
3887
        size = 0x4;
3888
        break;
3889
    case 0x00100000UL:
3890
        size = 0x5;
3891
        break;
3892
    case 0x00400000UL:
3893
        size = 0x6;
3894
        break;
3895
    case 0x01000000UL:
3896
        size = 0x7;
3897
        break;
3898
    case 0x04000000UL:
3899
        size = 0x8;
3900
        break;
3901
    case 0x10000000UL:
3902
        size = 0x9;
3903
        break;
3904
    case 0x40000000UL:
3905
        size = 0xA;
3906
        break;
3907
#if defined (TARGET_PPC64)
3908
    case 0x000100000000ULL:
3909
        size = 0xB;
3910
        break;
3911
    case 0x000400000000ULL:
3912
        size = 0xC;
3913
        break;
3914
    case 0x001000000000ULL:
3915
        size = 0xD;
3916
        break;
3917
    case 0x004000000000ULL:
3918
        size = 0xE;
3919
        break;
3920
    case 0x010000000000ULL:
3921
        size = 0xF;
3922
        break;
3923
#endif
3924
    default:
3925
        size = -1;
3926
        break;
3927
    }
3928

    
3929
    return size;
3930
}
3931

    
3932
/* Helpers for 4xx TLB management */
3933
target_ulong helper_4xx_tlbre_lo (target_ulong entry)
3934
{
3935
    ppcemb_tlb_t *tlb;
3936
    target_ulong ret;
3937
    int size;
3938

    
3939
    entry &= 0x3F;
3940
    tlb = &env->tlb[entry].tlbe;
3941
    ret = tlb->EPN;
3942
    if (tlb->prot & PAGE_VALID)
3943
        ret |= 0x400;
3944
    size = booke_page_size_to_tlb(tlb->size);
3945
    if (size < 0 || size > 0x7)
3946
        size = 1;
3947
    ret |= size << 7;
3948
    env->spr[SPR_40x_PID] = tlb->PID;
3949
    return ret;
3950
}
3951

    
3952
target_ulong helper_4xx_tlbre_hi (target_ulong entry)
3953
{
3954
    ppcemb_tlb_t *tlb;
3955
    target_ulong ret;
3956

    
3957
    entry &= 0x3F;
3958
    tlb = &env->tlb[entry].tlbe;
3959
    ret = tlb->RPN;
3960
    if (tlb->prot & PAGE_EXEC)
3961
        ret |= 0x200;
3962
    if (tlb->prot & PAGE_WRITE)
3963
        ret |= 0x100;
3964
    return ret;
3965
}
3966

    
3967
void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
3968
{
3969
    ppcemb_tlb_t *tlb;
3970
    target_ulong page, end;
3971

    
3972
    LOG_SWTLB("%s entry %d val " ADDRX "\n", __func__, (int)entry, val);
3973
    entry &= 0x3F;
3974
    tlb = &env->tlb[entry].tlbe;
3975
    /* Invalidate previous TLB (if it's valid) */
3976
    if (tlb->prot & PAGE_VALID) {
3977
        end = tlb->EPN + tlb->size;
3978
        LOG_SWTLB("%s: invalidate old TLB %d start " ADDRX
3979
                    " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
3980
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3981
            tlb_flush_page(env, page);
3982
    }
3983
    tlb->size = booke_tlb_to_page_size((val >> 7) & 0x7);
3984
    /* We cannot handle TLB size < TARGET_PAGE_SIZE.
3985
     * If this ever occurs, one should use the ppcemb target instead
3986
     * of the ppc or ppc64 one
3987
     */
3988
    if ((val & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
3989
        cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
3990
                  "are not supported (%d)\n",
3991
                  tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
3992
    }
3993
    tlb->EPN = val & ~(tlb->size - 1);
3994
    if (val & 0x40)
3995
        tlb->prot |= PAGE_VALID;
3996
    else
3997
        tlb->prot &= ~PAGE_VALID;
3998
    if (val & 0x20) {
3999
        /* XXX: TO BE FIXED */
4000
        cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
4001
    }
4002
    tlb->PID = env->spr[SPR_40x_PID]; /* PID */
4003
    tlb->attr = val & 0xFF;
4004
    LOG_SWTLB("%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
4005
                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
4006
                (int)entry, tlb->RPN, tlb->EPN, tlb->size,
4007
                tlb->prot & PAGE_READ ? 'r' : '-',
4008
                tlb->prot & PAGE_WRITE ? 'w' : '-',
4009
                tlb->prot & PAGE_EXEC ? 'x' : '-',
4010
                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
4011
    /* Invalidate new TLB (if valid) */
4012
    if (tlb->prot & PAGE_VALID) {
4013
        end = tlb->EPN + tlb->size;
4014
        LOG_SWTLB("%s: invalidate TLB %d start " ADDRX
4015
                    " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
4016
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
4017
            tlb_flush_page(env, page);
4018
    }
4019
}
4020

    
4021
void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
4022
{
4023
    ppcemb_tlb_t *tlb;
4024

    
4025
    LOG_SWTLB("%s entry %i val " ADDRX "\n", __func__, (int)entry, val);
4026
    entry &= 0x3F;
4027
    tlb = &env->tlb[entry].tlbe;
4028
    tlb->RPN = val & 0xFFFFFC00;
4029
    tlb->prot = PAGE_READ;
4030
    if (val & 0x200)
4031
        tlb->prot |= PAGE_EXEC;
4032
    if (val & 0x100)
4033
        tlb->prot |= PAGE_WRITE;
4034
    LOG_SWTLB("%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
4035
                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
4036
                (int)entry, tlb->RPN, tlb->EPN, tlb->size,
4037
                tlb->prot & PAGE_READ ? 'r' : '-',
4038
                tlb->prot & PAGE_WRITE ? 'w' : '-',
4039
                tlb->prot & PAGE_EXEC ? 'x' : '-',
4040
                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
4041
}
4042

    
4043
target_ulong helper_4xx_tlbsx (target_ulong address)
4044
{
4045
    return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
4046
}
4047

    
4048
/* PowerPC 440 TLB management */
4049
void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
4050
{
4051
    ppcemb_tlb_t *tlb;
4052
    target_ulong EPN, RPN, size;
4053
    int do_flush_tlbs;
4054

    
4055
    LOG_SWTLB("%s word %d entry %d value " ADDRX "\n",
4056
                __func__, word, (int)entry, value);
4057
    do_flush_tlbs = 0;
4058
    entry &= 0x3F;
4059
    tlb = &env->tlb[entry].tlbe;
4060
    switch (word) {
4061
    default:
4062
        /* Just here to please gcc */
4063
    case 0:
4064
        EPN = value & 0xFFFFFC00;
4065
        if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
4066
            do_flush_tlbs = 1;
4067
        tlb->EPN = EPN;
4068
        size = booke_tlb_to_page_size((value >> 4) & 0xF);
4069
        if ((tlb->prot & PAGE_VALID) && tlb->size < size)
4070
            do_flush_tlbs = 1;
4071
        tlb->size = size;
4072
        tlb->attr &= ~0x1;
4073
        tlb->attr |= (value >> 8) & 1;
4074
        if (value & 0x200) {
4075
            tlb->prot |= PAGE_VALID;
4076
        } else {
4077
            if (tlb->prot & PAGE_VALID) {
4078
                tlb->prot &= ~PAGE_VALID;
4079
                do_flush_tlbs = 1;
4080
            }
4081
        }
4082
        tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
4083
        if (do_flush_tlbs)
4084
            tlb_flush(env, 1);
4085
        break;
4086
    case 1:
4087
        RPN = value & 0xFFFFFC0F;
4088
        if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
4089
            tlb_flush(env, 1);
4090
        tlb->RPN = RPN;
4091
        break;
4092
    case 2:
4093
        tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
4094
        tlb->prot = tlb->prot & PAGE_VALID;
4095
        if (value & 0x1)
4096
            tlb->prot |= PAGE_READ << 4;
4097
        if (value & 0x2)
4098
            tlb->prot |= PAGE_WRITE << 4;
4099
        if (value & 0x4)
4100
            tlb->prot |= PAGE_EXEC << 4;
4101
        if (value & 0x8)
4102
            tlb->prot |= PAGE_READ;
4103
        if (value & 0x10)
4104
            tlb->prot |= PAGE_WRITE;
4105
        if (value & 0x20)
4106
            tlb->prot |= PAGE_EXEC;
4107
        break;
4108
    }
4109
}
4110

    
4111
target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
4112
{
4113
    ppcemb_tlb_t *tlb;
4114
    target_ulong ret;
4115
    int size;
4116

    
4117
    entry &= 0x3F;
4118
    tlb = &env->tlb[entry].tlbe;
4119
    switch (word) {
4120
    default:
4121
        /* Just here to please gcc */
4122
    case 0:
4123
        ret = tlb->EPN;
4124
        size = booke_page_size_to_tlb(tlb->size);
4125
        if (size < 0 || size > 0xF)
4126
            size = 1;
4127
        ret |= size << 4;
4128
        if (tlb->attr & 0x1)
4129
            ret |= 0x100;
4130
        if (tlb->prot & PAGE_VALID)
4131
            ret |= 0x200;
4132
        env->spr[SPR_440_MMUCR] &= ~0x000000FF;
4133
        env->spr[SPR_440_MMUCR] |= tlb->PID;
4134
        break;
4135
    case 1:
4136
        ret = tlb->RPN;
4137
        break;
4138
    case 2:
4139
        ret = tlb->attr & ~0x1;
4140
        if (tlb->prot & (PAGE_READ << 4))
4141
            ret |= 0x1;
4142
        if (tlb->prot & (PAGE_WRITE << 4))
4143
            ret |= 0x2;
4144
        if (tlb->prot & (PAGE_EXEC << 4))
4145
            ret |= 0x4;
4146
        if (tlb->prot & PAGE_READ)
4147
            ret |= 0x8;
4148
        if (tlb->prot & PAGE_WRITE)
4149
            ret |= 0x10;
4150
        if (tlb->prot & PAGE_EXEC)
4151
            ret |= 0x20;
4152
        break;
4153
    }
4154
    return ret;
4155
}
4156

    
4157
target_ulong helper_440_tlbsx (target_ulong address)
4158
{
4159
    return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
4160
}
4161

    
4162
#endif /* !CONFIG_USER_ONLY */