Statistics
| Branch: | Revision:

root / target-ppc / op_helper.c @ f586ce09

History | View | Annotate | Download (115.9 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 VARITHSAT_CASE(type, op, cvt, element)                          \
2103
    {                                                                   \
2104
        type result = (type)a->element[i] op (type)b->element[i];       \
2105
        r->element[i] = cvt(result, &sat);                              \
2106
    }
2107

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

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

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

    
2160
#define VCF(suffix, cvt, element)                                       \
2161
    void helper_vcf##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t uim)  \
2162
    {                                                                   \
2163
        int i;                                                          \
2164
        for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
2165
            float32 t = cvt(b->element[i], &env->vec_status);           \
2166
            r->f[i] = float32_scalbn (t, -uim, &env->vec_status);       \
2167
        }                                                               \
2168
    }
2169
VCF(ux, uint32_to_float32, u32)
2170
VCF(sx, int32_to_float32, s32)
2171
#undef VCF
2172

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

    
2209
void helper_vmhaddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2210
{
2211
    int sat = 0;
2212
    int i;
2213

    
2214
    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2215
        int32_t prod = a->s16[i] * b->s16[i];
2216
        int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2217
        r->s16[i] = cvtswsh (t, &sat);
2218
    }
2219

    
2220
    if (sat) {
2221
        env->vscr |= (1 << VSCR_SAT);
2222
    }
2223
}
2224

    
2225
void helper_vmhraddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2226
{
2227
    int sat = 0;
2228
    int i;
2229

    
2230
    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2231
        int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
2232
        int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2233
        r->s16[i] = cvtswsh (t, &sat);
2234
    }
2235

    
2236
    if (sat) {
2237
        env->vscr |= (1 << VSCR_SAT);
2238
    }
2239
}
2240

    
2241
#define VMINMAX_DO(name, compare, element)                              \
2242
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
2243
    {                                                                   \
2244
        int i;                                                          \
2245
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2246
            if (a->element[i] compare b->element[i]) {                  \
2247
                r->element[i] = b->element[i];                          \
2248
            } else {                                                    \
2249
                r->element[i] = a->element[i];                          \
2250
            }                                                           \
2251
        }                                                               \
2252
    }
2253
#define VMINMAX(suffix, element)                \
2254
  VMINMAX_DO(min##suffix, >, element)           \
2255
  VMINMAX_DO(max##suffix, <, element)
2256
VMINMAX(sb, s8)
2257
VMINMAX(sh, s16)
2258
VMINMAX(sw, s32)
2259
VMINMAX(ub, u8)
2260
VMINMAX(uh, u16)
2261
VMINMAX(uw, u32)
2262
#undef VMINMAX_DO
2263
#undef VMINMAX
2264

    
2265
void helper_vmladduhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2266
{
2267
    int i;
2268
    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2269
        int32_t prod = a->s16[i] * b->s16[i];
2270
        r->s16[i] = (int16_t) (prod + c->s16[i]);
2271
    }
2272
}
2273

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

    
2309
void helper_vmsummbm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2310
{
2311
    int32_t prod[16];
2312
    int i;
2313

    
2314
    for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
2315
        prod[i] = (int32_t)a->s8[i] * b->u8[i];
2316
    }
2317

    
2318
    VECTOR_FOR_INORDER_I(i, s32) {
2319
        r->s32[i] = c->s32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2320
    }
2321
}
2322

    
2323
void helper_vmsumshm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2324
{
2325
    int32_t prod[8];
2326
    int i;
2327

    
2328
    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2329
        prod[i] = a->s16[i] * b->s16[i];
2330
    }
2331

    
2332
    VECTOR_FOR_INORDER_I(i, s32) {
2333
        r->s32[i] = c->s32[i] + prod[2*i] + prod[2*i+1];
2334
    }
2335
}
2336

    
2337
void helper_vmsumshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2338
{
2339
    int32_t prod[8];
2340
    int i;
2341
    int sat = 0;
2342

    
2343
    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2344
        prod[i] = (int32_t)a->s16[i] * b->s16[i];
2345
    }
2346

    
2347
    VECTOR_FOR_INORDER_I (i, s32) {
2348
        int64_t t = (int64_t)c->s32[i] + prod[2*i] + prod[2*i+1];
2349
        r->u32[i] = cvtsdsw(t, &sat);
2350
    }
2351

    
2352
    if (sat) {
2353
        env->vscr |= (1 << VSCR_SAT);
2354
    }
2355
}
2356

    
2357
void helper_vmsumubm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2358
{
2359
    uint16_t prod[16];
2360
    int i;
2361

    
2362
    for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2363
        prod[i] = a->u8[i] * b->u8[i];
2364
    }
2365

    
2366
    VECTOR_FOR_INORDER_I(i, u32) {
2367
        r->u32[i] = c->u32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2368
    }
2369
}
2370

    
2371
void helper_vmsumuhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2372
{
2373
    uint32_t prod[8];
2374
    int i;
2375

    
2376
    for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2377
        prod[i] = a->u16[i] * b->u16[i];
2378
    }
2379

    
2380
    VECTOR_FOR_INORDER_I(i, u32) {
2381
        r->u32[i] = c->u32[i] + prod[2*i] + prod[2*i+1];
2382
    }
2383
}
2384

    
2385
void helper_vmsumuhs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2386
{
2387
    uint32_t prod[8];
2388
    int i;
2389
    int sat = 0;
2390

    
2391
    for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2392
        prod[i] = a->u16[i] * b->u16[i];
2393
    }
2394

    
2395
    VECTOR_FOR_INORDER_I (i, s32) {
2396
        uint64_t t = (uint64_t)c->u32[i] + prod[2*i] + prod[2*i+1];
2397
        r->u32[i] = cvtuduw(t, &sat);
2398
    }
2399

    
2400
    if (sat) {
2401
        env->vscr |= (1 << VSCR_SAT);
2402
    }
2403
}
2404

    
2405
#define VMUL_DO(name, mul_element, prod_element, evenp)                 \
2406
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
2407
    {                                                                   \
2408
        int i;                                                          \
2409
        VECTOR_FOR_INORDER_I(i, prod_element) {                         \
2410
            if (evenp) {                                                \
2411
                r->prod_element[i] = a->mul_element[i*2+HI_IDX] * b->mul_element[i*2+HI_IDX]; \
2412
            } else {                                                    \
2413
                r->prod_element[i] = a->mul_element[i*2+LO_IDX] * b->mul_element[i*2+LO_IDX]; \
2414
            }                                                           \
2415
        }                                                               \
2416
    }
2417
#define VMUL(suffix, mul_element, prod_element) \
2418
  VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
2419
  VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
2420
VMUL(sb, s8, s16)
2421
VMUL(sh, s16, s32)
2422
VMUL(ub, u8, u16)
2423
VMUL(uh, u16, u32)
2424
#undef VMUL_DO
2425
#undef VMUL
2426

    
2427
void helper_vperm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2428
{
2429
    ppc_avr_t result;
2430
    int i;
2431
    VECTOR_FOR_INORDER_I (i, u8) {
2432
        int s = c->u8[i] & 0x1f;
2433
#if defined(WORDS_BIGENDIAN)
2434
        int index = s & 0xf;
2435
#else
2436
        int index = 15 - (s & 0xf);
2437
#endif
2438
        if (s & 0x10) {
2439
            result.u8[i] = b->u8[index];
2440
        } else {
2441
            result.u8[i] = a->u8[index];
2442
        }
2443
    }
2444
    *r = result;
2445
}
2446

    
2447
#if defined(WORDS_BIGENDIAN)
2448
#define PKBIG 1
2449
#else
2450
#define PKBIG 0
2451
#endif
2452
void helper_vpkpx (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2453
{
2454
    int i, j;
2455
    ppc_avr_t result;
2456
#if defined(WORDS_BIGENDIAN)
2457
    const ppc_avr_t *x[2] = { a, b };
2458
#else
2459
    const ppc_avr_t *x[2] = { b, a };
2460
#endif
2461

    
2462
    VECTOR_FOR_INORDER_I (i, u64) {
2463
        VECTOR_FOR_INORDER_I (j, u32){
2464
            uint32_t e = x[i]->u32[j];
2465
            result.u16[4*i+j] = (((e >> 9) & 0xfc00) |
2466
                                 ((e >> 6) & 0x3e0) |
2467
                                 ((e >> 3) & 0x1f));
2468
        }
2469
    }
2470
    *r = result;
2471
}
2472

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

    
2503
#define VRFI(suffix, rounding)                                          \
2504
    void helper_vrfi##suffix (ppc_avr_t *r, ppc_avr_t *b)               \
2505
    {                                                                   \
2506
        int i;                                                          \
2507
        float_status s = env->vec_status;                               \
2508
        set_float_rounding_mode(rounding, &s);                          \
2509
        for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
2510
            HANDLE_NAN1(r->f[i], b->f[i]) {                             \
2511
                r->f[i] = float32_round_to_int (b->f[i], &s);           \
2512
            }                                                           \
2513
        }                                                               \
2514
    }
2515
VRFI(n, float_round_nearest_even)
2516
VRFI(m, float_round_down)
2517
VRFI(p, float_round_up)
2518
VRFI(z, float_round_to_zero)
2519
#undef VRFI
2520

    
2521
#define VROTATE(suffix, element)                                        \
2522
    void helper_vrl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
2523
    {                                                                   \
2524
        int i;                                                          \
2525
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2526
            unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2527
            unsigned int shift = b->element[i] & mask;                  \
2528
            r->element[i] = (a->element[i] << shift) | (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
2529
        }                                                               \
2530
    }
2531
VROTATE(b, u8)
2532
VROTATE(h, u16)
2533
VROTATE(w, u32)
2534
#undef VROTATE
2535

    
2536
void helper_vsel (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2537
{
2538
    r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
2539
    r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
2540
}
2541

    
2542
void helper_vrlogefp (ppc_avr_t *r, ppc_avr_t *b)
2543
{
2544
    int i;
2545
    for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2546
        HANDLE_NAN1(r->f[i], b->f[i]) {
2547
            r->f[i] = float32_log2(b->f[i], &env->vec_status);
2548
        }
2549
    }
2550
}
2551

    
2552
#if defined(WORDS_BIGENDIAN)
2553
#define LEFT 0
2554
#define RIGHT 1
2555
#else
2556
#define LEFT 1
2557
#define RIGHT 0
2558
#endif
2559
/* The specification says that the results are undefined if all of the
2560
 * shift counts are not identical.  We check to make sure that they are
2561
 * to conform to what real hardware appears to do.  */
2562
#define VSHIFT(suffix, leftp)                                           \
2563
    void helper_vs##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)   \
2564
    {                                                                   \
2565
        int shift = b->u8[LO_IDX*0x15] & 0x7;                           \
2566
        int doit = 1;                                                   \
2567
        int i;                                                          \
2568
        for (i = 0; i < ARRAY_SIZE(r->u8); i++) {                       \
2569
            doit = doit && ((b->u8[i] & 0x7) == shift);                 \
2570
        }                                                               \
2571
        if (doit) {                                                     \
2572
            if (shift == 0) {                                           \
2573
                *r = *a;                                                \
2574
            } else if (leftp) {                                         \
2575
                uint64_t carry = a->u64[LO_IDX] >> (64 - shift);        \
2576
                r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry;     \
2577
                r->u64[LO_IDX] = a->u64[LO_IDX] << shift;               \
2578
            } else {                                                    \
2579
                uint64_t carry = a->u64[HI_IDX] << (64 - shift);        \
2580
                r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry;     \
2581
                r->u64[HI_IDX] = a->u64[HI_IDX] >> shift;               \
2582
            }                                                           \
2583
        }                                                               \
2584
    }
2585
VSHIFT(l, LEFT)
2586
VSHIFT(r, RIGHT)
2587
#undef VSHIFT
2588
#undef LEFT
2589
#undef RIGHT
2590

    
2591
#define VSL(suffix, element)                                            \
2592
    void helper_vsl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
2593
    {                                                                   \
2594
        int i;                                                          \
2595
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2596
            unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2597
            unsigned int shift = b->element[i] & mask;                  \
2598
            r->element[i] = a->element[i] << shift;                     \
2599
        }                                                               \
2600
    }
2601
VSL(b, u8)
2602
VSL(h, u16)
2603
VSL(w, u32)
2604
#undef VSL
2605

    
2606
void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
2607
{
2608
    int sh = shift & 0xf;
2609
    int i;
2610
    ppc_avr_t result;
2611

    
2612
#if defined(WORDS_BIGENDIAN)
2613
    for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2614
        int index = sh + i;
2615
        if (index > 0xf) {
2616
            result.u8[i] = b->u8[index-0x10];
2617
        } else {
2618
            result.u8[i] = a->u8[index];
2619
        }
2620
    }
2621
#else
2622
    for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2623
        int index = (16 - sh) + i;
2624
        if (index > 0xf) {
2625
            result.u8[i] = a->u8[index-0x10];
2626
        } else {
2627
            result.u8[i] = b->u8[index];
2628
        }
2629
    }
2630
#endif
2631
    *r = result;
2632
}
2633

    
2634
void helper_vslo (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2635
{
2636
  int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2637

    
2638
#if defined (WORDS_BIGENDIAN)
2639
  memmove (&r->u8[0], &a->u8[sh], 16-sh);
2640
  memset (&r->u8[16-sh], 0, sh);
2641
#else
2642
  memmove (&r->u8[sh], &a->u8[0], 16-sh);
2643
  memset (&r->u8[0], 0, sh);
2644
#endif
2645
}
2646

    
2647
/* Experimental testing shows that hardware masks the immediate.  */
2648
#define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
2649
#if defined(WORDS_BIGENDIAN)
2650
#define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
2651
#else
2652
#define SPLAT_ELEMENT(element) (ARRAY_SIZE(r->element)-1 - _SPLAT_MASKED(element))
2653
#endif
2654
#define VSPLT(suffix, element)                                          \
2655
    void helper_vsplt##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
2656
    {                                                                   \
2657
        uint32_t s = b->element[SPLAT_ELEMENT(element)];                \
2658
        int i;                                                          \
2659
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2660
            r->element[i] = s;                                          \
2661
        }                                                               \
2662
    }
2663
VSPLT(b, u8)
2664
VSPLT(h, u16)
2665
VSPLT(w, u32)
2666
#undef VSPLT
2667
#undef SPLAT_ELEMENT
2668
#undef _SPLAT_MASKED
2669

    
2670
#define VSPLTI(suffix, element, splat_type)                     \
2671
    void helper_vspltis##suffix (ppc_avr_t *r, uint32_t splat)  \
2672
    {                                                           \
2673
        splat_type x = (int8_t)(splat << 3) >> 3;               \
2674
        int i;                                                  \
2675
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {          \
2676
            r->element[i] = x;                                  \
2677
        }                                                       \
2678
    }
2679
VSPLTI(b, s8, int8_t)
2680
VSPLTI(h, s16, int16_t)
2681
VSPLTI(w, s32, int32_t)
2682
#undef VSPLTI
2683

    
2684
#define VSR(suffix, element)                                            \
2685
    void helper_vsr##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
2686
    {                                                                   \
2687
        int i;                                                          \
2688
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2689
            unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2690
            unsigned int shift = b->element[i] & mask;                  \
2691
            r->element[i] = a->element[i] >> shift;                     \
2692
        }                                                               \
2693
    }
2694
VSR(ab, s8)
2695
VSR(ah, s16)
2696
VSR(aw, s32)
2697
VSR(b, u8)
2698
VSR(h, u16)
2699
VSR(w, u32)
2700
#undef VSR
2701

    
2702
void helper_vsro (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2703
{
2704
  int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2705

    
2706
#if defined (WORDS_BIGENDIAN)
2707
  memmove (&r->u8[sh], &a->u8[0], 16-sh);
2708
  memset (&r->u8[0], 0, sh);
2709
#else
2710
  memmove (&r->u8[0], &a->u8[sh], 16-sh);
2711
  memset (&r->u8[16-sh], 0, sh);
2712
#endif
2713
}
2714

    
2715
void helper_vsubcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2716
{
2717
    int i;
2718
    for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2719
        r->u32[i] = a->u32[i] >= b->u32[i];
2720
    }
2721
}
2722

    
2723
void helper_vsumsws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2724
{
2725
    int64_t t;
2726
    int i, upper;
2727
    ppc_avr_t result;
2728
    int sat = 0;
2729

    
2730
#if defined(WORDS_BIGENDIAN)
2731
    upper = ARRAY_SIZE(r->s32)-1;
2732
#else
2733
    upper = 0;
2734
#endif
2735
    t = (int64_t)b->s32[upper];
2736
    for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2737
        t += a->s32[i];
2738
        result.s32[i] = 0;
2739
    }
2740
    result.s32[upper] = cvtsdsw(t, &sat);
2741
    *r = result;
2742

    
2743
    if (sat) {
2744
        env->vscr |= (1 << VSCR_SAT);
2745
    }
2746
}
2747

    
2748
void helper_vsum2sws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2749
{
2750
    int i, j, upper;
2751
    ppc_avr_t result;
2752
    int sat = 0;
2753

    
2754
#if defined(WORDS_BIGENDIAN)
2755
    upper = 1;
2756
#else
2757
    upper = 0;
2758
#endif
2759
    for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
2760
        int64_t t = (int64_t)b->s32[upper+i*2];
2761
        result.u64[i] = 0;
2762
        for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
2763
            t += a->s32[2*i+j];
2764
        }
2765
        result.s32[upper+i*2] = cvtsdsw(t, &sat);
2766
    }
2767

    
2768
    *r = result;
2769
    if (sat) {
2770
        env->vscr |= (1 << VSCR_SAT);
2771
    }
2772
}
2773

    
2774
void helper_vsum4sbs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2775
{
2776
    int i, j;
2777
    int sat = 0;
2778

    
2779
    for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2780
        int64_t t = (int64_t)b->s32[i];
2781
        for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
2782
            t += a->s8[4*i+j];
2783
        }
2784
        r->s32[i] = cvtsdsw(t, &sat);
2785
    }
2786

    
2787
    if (sat) {
2788
        env->vscr |= (1 << VSCR_SAT);
2789
    }
2790
}
2791

    
2792
void helper_vsum4shs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2793
{
2794
    int sat = 0;
2795
    int i;
2796

    
2797
    for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2798
        int64_t t = (int64_t)b->s32[i];
2799
        t += a->s16[2*i] + a->s16[2*i+1];
2800
        r->s32[i] = cvtsdsw(t, &sat);
2801
    }
2802

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

    
2808
void helper_vsum4ubs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2809
{
2810
    int i, j;
2811
    int sat = 0;
2812

    
2813
    for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2814
        uint64_t t = (uint64_t)b->u32[i];
2815
        for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
2816
            t += a->u8[4*i+j];
2817
        }
2818
        r->u32[i] = cvtuduw(t, &sat);
2819
    }
2820

    
2821
    if (sat) {
2822
        env->vscr |= (1 << VSCR_SAT);
2823
    }
2824
}
2825

    
2826
#if defined(WORDS_BIGENDIAN)
2827
#define UPKHI 1
2828
#define UPKLO 0
2829
#else
2830
#define UPKHI 0
2831
#define UPKLO 1
2832
#endif
2833
#define VUPKPX(suffix, hi)                                      \
2834
    void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b)       \
2835
    {                                                           \
2836
        int i;                                                  \
2837
        ppc_avr_t result;                                       \
2838
        for (i = 0; i < ARRAY_SIZE(r->u32); i++) {              \
2839
            uint16_t e = b->u16[hi ? i : i+4];                  \
2840
            uint8_t a = (e >> 15) ? 0xff : 0;                   \
2841
            uint8_t r = (e >> 10) & 0x1f;                       \
2842
            uint8_t g = (e >> 5) & 0x1f;                        \
2843
            uint8_t b = e & 0x1f;                               \
2844
            result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b;       \
2845
        }                                                               \
2846
        *r = result;                                                    \
2847
    }
2848
VUPKPX(lpx, UPKLO)
2849
VUPKPX(hpx, UPKHI)
2850
#undef VUPKPX
2851

    
2852
#define VUPK(suffix, unpacked, packee, hi)                              \
2853
    void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b)               \
2854
    {                                                                   \
2855
        int i;                                                          \
2856
        ppc_avr_t result;                                               \
2857
        if (hi) {                                                       \
2858
            for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) {             \
2859
                result.unpacked[i] = b->packee[i];                      \
2860
            }                                                           \
2861
        } else {                                                        \
2862
            for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); i++) { \
2863
                result.unpacked[i-ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
2864
            }                                                           \
2865
        }                                                               \
2866
        *r = result;                                                    \
2867
    }
2868
VUPK(hsb, s16, s8, UPKHI)
2869
VUPK(hsh, s32, s16, UPKHI)
2870
VUPK(lsb, s16, s8, UPKLO)
2871
VUPK(lsh, s32, s16, UPKLO)
2872
#undef VUPK
2873
#undef UPKHI
2874
#undef UPKLO
2875

    
2876
#undef DO_HANDLE_NAN
2877
#undef HANDLE_NAN1
2878
#undef HANDLE_NAN2
2879
#undef HANDLE_NAN3
2880
#undef VECTOR_FOR_INORDER_I
2881
#undef HI_IDX
2882
#undef LO_IDX
2883

    
2884
/*****************************************************************************/
2885
/* SPE extension helpers */
2886
/* Use a table to make this quicker */
2887
static uint8_t hbrev[16] = {
2888
    0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
2889
    0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
2890
};
2891

    
2892
static always_inline uint8_t byte_reverse (uint8_t val)
2893
{
2894
    return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
2895
}
2896

    
2897
static always_inline uint32_t word_reverse (uint32_t val)
2898
{
2899
    return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
2900
        (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
2901
}
2902

    
2903
#define MASKBITS 16 // Random value - to be fixed (implementation dependant)
2904
target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
2905
{
2906
    uint32_t a, b, d, mask;
2907

    
2908
    mask = UINT32_MAX >> (32 - MASKBITS);
2909
    a = arg1 & mask;
2910
    b = arg2 & mask;
2911
    d = word_reverse(1 + word_reverse(a | ~b));
2912
    return (arg1 & ~mask) | (d & b);
2913
}
2914

    
2915
uint32_t helper_cntlsw32 (uint32_t val)
2916
{
2917
    if (val & 0x80000000)
2918
        return clz32(~val);
2919
    else
2920
        return clz32(val);
2921
}
2922

    
2923
uint32_t helper_cntlzw32 (uint32_t val)
2924
{
2925
    return clz32(val);
2926
}
2927

    
2928
/* Single-precision floating-point conversions */
2929
static always_inline uint32_t efscfsi (uint32_t val)
2930
{
2931
    CPU_FloatU u;
2932

    
2933
    u.f = int32_to_float32(val, &env->vec_status);
2934

    
2935
    return u.l;
2936
}
2937

    
2938
static always_inline uint32_t efscfui (uint32_t val)
2939
{
2940
    CPU_FloatU u;
2941

    
2942
    u.f = uint32_to_float32(val, &env->vec_status);
2943

    
2944
    return u.l;
2945
}
2946

    
2947
static always_inline int32_t efsctsi (uint32_t val)
2948
{
2949
    CPU_FloatU u;
2950

    
2951
    u.l = val;
2952
    /* NaN are not treated the same way IEEE 754 does */
2953
    if (unlikely(float32_is_nan(u.f)))
2954
        return 0;
2955

    
2956
    return float32_to_int32(u.f, &env->vec_status);
2957
}
2958

    
2959
static always_inline uint32_t efsctui (uint32_t val)
2960
{
2961
    CPU_FloatU u;
2962

    
2963
    u.l = val;
2964
    /* NaN are not treated the same way IEEE 754 does */
2965
    if (unlikely(float32_is_nan(u.f)))
2966
        return 0;
2967

    
2968
    return float32_to_uint32(u.f, &env->vec_status);
2969
}
2970

    
2971
static always_inline uint32_t efsctsiz (uint32_t val)
2972
{
2973
    CPU_FloatU u;
2974

    
2975
    u.l = val;
2976
    /* NaN are not treated the same way IEEE 754 does */
2977
    if (unlikely(float32_is_nan(u.f)))
2978
        return 0;
2979

    
2980
    return float32_to_int32_round_to_zero(u.f, &env->vec_status);
2981
}
2982

    
2983
static always_inline uint32_t efsctuiz (uint32_t val)
2984
{
2985
    CPU_FloatU u;
2986

    
2987
    u.l = val;
2988
    /* NaN are not treated the same way IEEE 754 does */
2989
    if (unlikely(float32_is_nan(u.f)))
2990
        return 0;
2991

    
2992
    return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
2993
}
2994

    
2995
static always_inline uint32_t efscfsf (uint32_t val)
2996
{
2997
    CPU_FloatU u;
2998
    float32 tmp;
2999

    
3000
    u.f = int32_to_float32(val, &env->vec_status);
3001
    tmp = int64_to_float32(1ULL << 32, &env->vec_status);
3002
    u.f = float32_div(u.f, tmp, &env->vec_status);
3003

    
3004
    return u.l;
3005
}
3006

    
3007
static always_inline uint32_t efscfuf (uint32_t val)
3008
{
3009
    CPU_FloatU u;
3010
    float32 tmp;
3011

    
3012
    u.f = uint32_to_float32(val, &env->vec_status);
3013
    tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3014
    u.f = float32_div(u.f, tmp, &env->vec_status);
3015

    
3016
    return u.l;
3017
}
3018

    
3019
static always_inline uint32_t efsctsf (uint32_t val)
3020
{
3021
    CPU_FloatU u;
3022
    float32 tmp;
3023

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

    
3031
    return float32_to_int32(u.f, &env->vec_status);
3032
}
3033

    
3034
static always_inline uint32_t efsctuf (uint32_t val)
3035
{
3036
    CPU_FloatU u;
3037
    float32 tmp;
3038

    
3039
    u.l = val;
3040
    /* NaN are not treated the same way IEEE 754 does */
3041
    if (unlikely(float32_is_nan(u.f)))
3042
        return 0;
3043
    tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3044
    u.f = float32_mul(u.f, tmp, &env->vec_status);
3045

    
3046
    return float32_to_uint32(u.f, &env->vec_status);
3047
}
3048

    
3049
#define HELPER_SPE_SINGLE_CONV(name)                                          \
3050
uint32_t helper_e##name (uint32_t val)                                        \
3051
{                                                                             \
3052
    return e##name(val);                                                      \
3053
}
3054
/* efscfsi */
3055
HELPER_SPE_SINGLE_CONV(fscfsi);
3056
/* efscfui */
3057
HELPER_SPE_SINGLE_CONV(fscfui);
3058
/* efscfuf */
3059
HELPER_SPE_SINGLE_CONV(fscfuf);
3060
/* efscfsf */
3061
HELPER_SPE_SINGLE_CONV(fscfsf);
3062
/* efsctsi */
3063
HELPER_SPE_SINGLE_CONV(fsctsi);
3064
/* efsctui */
3065
HELPER_SPE_SINGLE_CONV(fsctui);
3066
/* efsctsiz */
3067
HELPER_SPE_SINGLE_CONV(fsctsiz);
3068
/* efsctuiz */
3069
HELPER_SPE_SINGLE_CONV(fsctuiz);
3070
/* efsctsf */
3071
HELPER_SPE_SINGLE_CONV(fsctsf);
3072
/* efsctuf */
3073
HELPER_SPE_SINGLE_CONV(fsctuf);
3074

    
3075
#define HELPER_SPE_VECTOR_CONV(name)                                          \
3076
uint64_t helper_ev##name (uint64_t val)                                       \
3077
{                                                                             \
3078
    return ((uint64_t)e##name(val >> 32) << 32) |                             \
3079
            (uint64_t)e##name(val);                                           \
3080
}
3081
/* evfscfsi */
3082
HELPER_SPE_VECTOR_CONV(fscfsi);
3083
/* evfscfui */
3084
HELPER_SPE_VECTOR_CONV(fscfui);
3085
/* evfscfuf */
3086
HELPER_SPE_VECTOR_CONV(fscfuf);
3087
/* evfscfsf */
3088
HELPER_SPE_VECTOR_CONV(fscfsf);
3089
/* evfsctsi */
3090
HELPER_SPE_VECTOR_CONV(fsctsi);
3091
/* evfsctui */
3092
HELPER_SPE_VECTOR_CONV(fsctui);
3093
/* evfsctsiz */
3094
HELPER_SPE_VECTOR_CONV(fsctsiz);
3095
/* evfsctuiz */
3096
HELPER_SPE_VECTOR_CONV(fsctuiz);
3097
/* evfsctsf */
3098
HELPER_SPE_VECTOR_CONV(fsctsf);
3099
/* evfsctuf */
3100
HELPER_SPE_VECTOR_CONV(fsctuf);
3101

    
3102
/* Single-precision floating-point arithmetic */
3103
static always_inline uint32_t efsadd (uint32_t op1, uint32_t op2)
3104
{
3105
    CPU_FloatU u1, u2;
3106
    u1.l = op1;
3107
    u2.l = op2;
3108
    u1.f = float32_add(u1.f, u2.f, &env->vec_status);
3109
    return u1.l;
3110
}
3111

    
3112
static always_inline uint32_t efssub (uint32_t op1, uint32_t op2)
3113
{
3114
    CPU_FloatU u1, u2;
3115
    u1.l = op1;
3116
    u2.l = op2;
3117
    u1.f = float32_sub(u1.f, u2.f, &env->vec_status);
3118
    return u1.l;
3119
}
3120

    
3121
static always_inline uint32_t efsmul (uint32_t op1, uint32_t op2)
3122
{
3123
    CPU_FloatU u1, u2;
3124
    u1.l = op1;
3125
    u2.l = op2;
3126
    u1.f = float32_mul(u1.f, u2.f, &env->vec_status);
3127
    return u1.l;
3128
}
3129

    
3130
static always_inline uint32_t efsdiv (uint32_t op1, uint32_t op2)
3131
{
3132
    CPU_FloatU u1, u2;
3133
    u1.l = op1;
3134
    u2.l = op2;
3135
    u1.f = float32_div(u1.f, u2.f, &env->vec_status);
3136
    return u1.l;
3137
}
3138

    
3139
#define HELPER_SPE_SINGLE_ARITH(name)                                         \
3140
uint32_t helper_e##name (uint32_t op1, uint32_t op2)                          \
3141
{                                                                             \
3142
    return e##name(op1, op2);                                                 \
3143
}
3144
/* efsadd */
3145
HELPER_SPE_SINGLE_ARITH(fsadd);
3146
/* efssub */
3147
HELPER_SPE_SINGLE_ARITH(fssub);
3148
/* efsmul */
3149
HELPER_SPE_SINGLE_ARITH(fsmul);
3150
/* efsdiv */
3151
HELPER_SPE_SINGLE_ARITH(fsdiv);
3152

    
3153
#define HELPER_SPE_VECTOR_ARITH(name)                                         \
3154
uint64_t helper_ev##name (uint64_t op1, uint64_t op2)                         \
3155
{                                                                             \
3156
    return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) |                  \
3157
            (uint64_t)e##name(op1, op2);                                      \
3158
}
3159
/* evfsadd */
3160
HELPER_SPE_VECTOR_ARITH(fsadd);
3161
/* evfssub */
3162
HELPER_SPE_VECTOR_ARITH(fssub);
3163
/* evfsmul */
3164
HELPER_SPE_VECTOR_ARITH(fsmul);
3165
/* evfsdiv */
3166
HELPER_SPE_VECTOR_ARITH(fsdiv);
3167

    
3168
/* Single-precision floating-point comparisons */
3169
static always_inline uint32_t efststlt (uint32_t op1, uint32_t op2)
3170
{
3171
    CPU_FloatU u1, u2;
3172
    u1.l = op1;
3173
    u2.l = op2;
3174
    return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0;
3175
}
3176

    
3177
static always_inline uint32_t efststgt (uint32_t op1, uint32_t op2)
3178
{
3179
    CPU_FloatU u1, u2;
3180
    u1.l = op1;
3181
    u2.l = op2;
3182
    return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4;
3183
}
3184

    
3185
static always_inline uint32_t efststeq (uint32_t op1, uint32_t op2)
3186
{
3187
    CPU_FloatU u1, u2;
3188
    u1.l = op1;
3189
    u2.l = op2;
3190
    return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0;
3191
}
3192

    
3193
static always_inline uint32_t efscmplt (uint32_t op1, uint32_t op2)
3194
{
3195
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3196
    return efststlt(op1, op2);
3197
}
3198

    
3199
static always_inline uint32_t efscmpgt (uint32_t op1, uint32_t op2)
3200
{
3201
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3202
    return efststgt(op1, op2);
3203
}
3204

    
3205
static always_inline uint32_t efscmpeq (uint32_t op1, uint32_t op2)
3206
{
3207
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3208
    return efststeq(op1, op2);
3209
}
3210

    
3211
#define HELPER_SINGLE_SPE_CMP(name)                                           \
3212
uint32_t helper_e##name (uint32_t op1, uint32_t op2)                          \
3213
{                                                                             \
3214
    return e##name(op1, op2) << 2;                                            \
3215
}
3216
/* efststlt */
3217
HELPER_SINGLE_SPE_CMP(fststlt);
3218
/* efststgt */
3219
HELPER_SINGLE_SPE_CMP(fststgt);
3220
/* efststeq */
3221
HELPER_SINGLE_SPE_CMP(fststeq);
3222
/* efscmplt */
3223
HELPER_SINGLE_SPE_CMP(fscmplt);
3224
/* efscmpgt */
3225
HELPER_SINGLE_SPE_CMP(fscmpgt);
3226
/* efscmpeq */
3227
HELPER_SINGLE_SPE_CMP(fscmpeq);
3228

    
3229
static always_inline uint32_t evcmp_merge (int t0, int t1)
3230
{
3231
    return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
3232
}
3233

    
3234
#define HELPER_VECTOR_SPE_CMP(name)                                           \
3235
uint32_t helper_ev##name (uint64_t op1, uint64_t op2)                         \
3236
{                                                                             \
3237
    return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2));     \
3238
}
3239
/* evfststlt */
3240
HELPER_VECTOR_SPE_CMP(fststlt);
3241
/* evfststgt */
3242
HELPER_VECTOR_SPE_CMP(fststgt);
3243
/* evfststeq */
3244
HELPER_VECTOR_SPE_CMP(fststeq);
3245
/* evfscmplt */
3246
HELPER_VECTOR_SPE_CMP(fscmplt);
3247
/* evfscmpgt */
3248
HELPER_VECTOR_SPE_CMP(fscmpgt);
3249
/* evfscmpeq */
3250
HELPER_VECTOR_SPE_CMP(fscmpeq);
3251

    
3252
/* Double-precision floating-point conversion */
3253
uint64_t helper_efdcfsi (uint32_t val)
3254
{
3255
    CPU_DoubleU u;
3256

    
3257
    u.d = int32_to_float64(val, &env->vec_status);
3258

    
3259
    return u.ll;
3260
}
3261

    
3262
uint64_t helper_efdcfsid (uint64_t val)
3263
{
3264
    CPU_DoubleU u;
3265

    
3266
    u.d = int64_to_float64(val, &env->vec_status);
3267

    
3268
    return u.ll;
3269
}
3270

    
3271
uint64_t helper_efdcfui (uint32_t val)
3272
{
3273
    CPU_DoubleU u;
3274

    
3275
    u.d = uint32_to_float64(val, &env->vec_status);
3276

    
3277
    return u.ll;
3278
}
3279

    
3280
uint64_t helper_efdcfuid (uint64_t val)
3281
{
3282
    CPU_DoubleU u;
3283

    
3284
    u.d = uint64_to_float64(val, &env->vec_status);
3285

    
3286
    return u.ll;
3287
}
3288

    
3289
uint32_t helper_efdctsi (uint64_t val)
3290
{
3291
    CPU_DoubleU u;
3292

    
3293
    u.ll = val;
3294
    /* NaN are not treated the same way IEEE 754 does */
3295
    if (unlikely(float64_is_nan(u.d)))
3296
        return 0;
3297

    
3298
    return float64_to_int32(u.d, &env->vec_status);
3299
}
3300

    
3301
uint32_t helper_efdctui (uint64_t val)
3302
{
3303
    CPU_DoubleU u;
3304

    
3305
    u.ll = val;
3306
    /* NaN are not treated the same way IEEE 754 does */
3307
    if (unlikely(float64_is_nan(u.d)))
3308
        return 0;
3309

    
3310
    return float64_to_uint32(u.d, &env->vec_status);
3311
}
3312

    
3313
uint32_t helper_efdctsiz (uint64_t val)
3314
{
3315
    CPU_DoubleU u;
3316

    
3317
    u.ll = val;
3318
    /* NaN are not treated the same way IEEE 754 does */
3319
    if (unlikely(float64_is_nan(u.d)))
3320
        return 0;
3321

    
3322
    return float64_to_int32_round_to_zero(u.d, &env->vec_status);
3323
}
3324

    
3325
uint64_t helper_efdctsidz (uint64_t val)
3326
{
3327
    CPU_DoubleU u;
3328

    
3329
    u.ll = val;
3330
    /* NaN are not treated the same way IEEE 754 does */
3331
    if (unlikely(float64_is_nan(u.d)))
3332
        return 0;
3333

    
3334
    return float64_to_int64_round_to_zero(u.d, &env->vec_status);
3335
}
3336

    
3337
uint32_t helper_efdctuiz (uint64_t val)
3338
{
3339
    CPU_DoubleU u;
3340

    
3341
    u.ll = val;
3342
    /* NaN are not treated the same way IEEE 754 does */
3343
    if (unlikely(float64_is_nan(u.d)))
3344
        return 0;
3345

    
3346
    return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
3347
}
3348

    
3349
uint64_t helper_efdctuidz (uint64_t val)
3350
{
3351
    CPU_DoubleU u;
3352

    
3353
    u.ll = val;
3354
    /* NaN are not treated the same way IEEE 754 does */
3355
    if (unlikely(float64_is_nan(u.d)))
3356
        return 0;
3357

    
3358
    return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
3359
}
3360

    
3361
uint64_t helper_efdcfsf (uint32_t val)
3362
{
3363
    CPU_DoubleU u;
3364
    float64 tmp;
3365

    
3366
    u.d = int32_to_float64(val, &env->vec_status);
3367
    tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3368
    u.d = float64_div(u.d, tmp, &env->vec_status);
3369

    
3370
    return u.ll;
3371
}
3372

    
3373
uint64_t helper_efdcfuf (uint32_t val)
3374
{
3375
    CPU_DoubleU u;
3376
    float64 tmp;
3377

    
3378
    u.d = uint32_to_float64(val, &env->vec_status);
3379
    tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3380
    u.d = float64_div(u.d, tmp, &env->vec_status);
3381

    
3382
    return u.ll;
3383
}
3384

    
3385
uint32_t helper_efdctsf (uint64_t val)
3386
{
3387
    CPU_DoubleU u;
3388
    float64 tmp;
3389

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

    
3397
    return float64_to_int32(u.d, &env->vec_status);
3398
}
3399

    
3400
uint32_t helper_efdctuf (uint64_t val)
3401
{
3402
    CPU_DoubleU u;
3403
    float64 tmp;
3404

    
3405
    u.ll = val;
3406
    /* NaN are not treated the same way IEEE 754 does */
3407
    if (unlikely(float64_is_nan(u.d)))
3408
        return 0;
3409
    tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3410
    u.d = float64_mul(u.d, tmp, &env->vec_status);
3411

    
3412
    return float64_to_uint32(u.d, &env->vec_status);
3413
}
3414

    
3415
uint32_t helper_efscfd (uint64_t val)
3416
{
3417
    CPU_DoubleU u1;
3418
    CPU_FloatU u2;
3419

    
3420
    u1.ll = val;
3421
    u2.f = float64_to_float32(u1.d, &env->vec_status);
3422

    
3423
    return u2.l;
3424
}
3425

    
3426
uint64_t helper_efdcfs (uint32_t val)
3427
{
3428
    CPU_DoubleU u2;
3429
    CPU_FloatU u1;
3430

    
3431
    u1.l = val;
3432
    u2.d = float32_to_float64(u1.f, &env->vec_status);
3433

    
3434
    return u2.ll;
3435
}
3436

    
3437
/* Double precision fixed-point arithmetic */
3438
uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
3439
{
3440
    CPU_DoubleU u1, u2;
3441
    u1.ll = op1;
3442
    u2.ll = op2;
3443
    u1.d = float64_add(u1.d, u2.d, &env->vec_status);
3444
    return u1.ll;
3445
}
3446

    
3447
uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
3448
{
3449
    CPU_DoubleU u1, u2;
3450
    u1.ll = op1;
3451
    u2.ll = op2;
3452
    u1.d = float64_sub(u1.d, u2.d, &env->vec_status);
3453
    return u1.ll;
3454
}
3455

    
3456
uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
3457
{
3458
    CPU_DoubleU u1, u2;
3459
    u1.ll = op1;
3460
    u2.ll = op2;
3461
    u1.d = float64_mul(u1.d, u2.d, &env->vec_status);
3462
    return u1.ll;
3463
}
3464

    
3465
uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
3466
{
3467
    CPU_DoubleU u1, u2;
3468
    u1.ll = op1;
3469
    u2.ll = op2;
3470
    u1.d = float64_div(u1.d, u2.d, &env->vec_status);
3471
    return u1.ll;
3472
}
3473

    
3474
/* Double precision floating point helpers */
3475
uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
3476
{
3477
    CPU_DoubleU u1, u2;
3478
    u1.ll = op1;
3479
    u2.ll = op2;
3480
    return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0;
3481
}
3482

    
3483
uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
3484
{
3485
    CPU_DoubleU u1, u2;
3486
    u1.ll = op1;
3487
    u2.ll = op2;
3488
    return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4;
3489
}
3490

    
3491
uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
3492
{
3493
    CPU_DoubleU u1, u2;
3494
    u1.ll = op1;
3495
    u2.ll = op2;
3496
    return float64_eq(u1.d, u2.d, &env->vec_status) ? 4 : 0;
3497
}
3498

    
3499
uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
3500
{
3501
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3502
    return helper_efdtstlt(op1, op2);
3503
}
3504

    
3505
uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
3506
{
3507
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3508
    return helper_efdtstgt(op1, op2);
3509
}
3510

    
3511
uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
3512
{
3513
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3514
    return helper_efdtsteq(op1, op2);
3515
}
3516

    
3517
/*****************************************************************************/
3518
/* Softmmu support */
3519
#if !defined (CONFIG_USER_ONLY)
3520

    
3521
#define MMUSUFFIX _mmu
3522

    
3523
#define SHIFT 0
3524
#include "softmmu_template.h"
3525

    
3526
#define SHIFT 1
3527
#include "softmmu_template.h"
3528

    
3529
#define SHIFT 2
3530
#include "softmmu_template.h"
3531

    
3532
#define SHIFT 3
3533
#include "softmmu_template.h"
3534

    
3535
/* try to fill the TLB and return an exception if error. If retaddr is
3536
   NULL, it means that the function was called in C code (i.e. not
3537
   from generated code or from helper.c) */
3538
/* XXX: fix it to restore all registers */
3539
void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
3540
{
3541
    TranslationBlock *tb;
3542
    CPUState *saved_env;
3543
    unsigned long pc;
3544
    int ret;
3545

    
3546
    /* XXX: hack to restore env in all cases, even if not called from
3547
       generated code */
3548
    saved_env = env;
3549
    env = cpu_single_env;
3550
    ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
3551
    if (unlikely(ret != 0)) {
3552
        if (likely(retaddr)) {
3553
            /* now we have a real cpu fault */
3554
            pc = (unsigned long)retaddr;
3555
            tb = tb_find_pc(pc);
3556
            if (likely(tb)) {
3557
                /* the PC is inside the translated code. It means that we have
3558
                   a virtual CPU fault */
3559
                cpu_restore_state(tb, env, pc, NULL);
3560
            }
3561
        }
3562
        helper_raise_exception_err(env->exception_index, env->error_code);
3563
    }
3564
    env = saved_env;
3565
}
3566

    
3567
/* Segment registers load and store */
3568
target_ulong helper_load_sr (target_ulong sr_num)
3569
{
3570
    return env->sr[sr_num];
3571
}
3572

    
3573
void helper_store_sr (target_ulong sr_num, target_ulong val)
3574
{
3575
    ppc_store_sr(env, sr_num, val);
3576
}
3577

    
3578
/* SLB management */
3579
#if defined(TARGET_PPC64)
3580
target_ulong helper_load_slb (target_ulong slb_nr)
3581
{
3582
    return ppc_load_slb(env, slb_nr);
3583
}
3584

    
3585
void helper_store_slb (target_ulong slb_nr, target_ulong rs)
3586
{
3587
    ppc_store_slb(env, slb_nr, rs);
3588
}
3589

    
3590
void helper_slbia (void)
3591
{
3592
    ppc_slb_invalidate_all(env);
3593
}
3594

    
3595
void helper_slbie (target_ulong addr)
3596
{
3597
    ppc_slb_invalidate_one(env, addr);
3598
}
3599

    
3600
#endif /* defined(TARGET_PPC64) */
3601

    
3602
/* TLB management */
3603
void helper_tlbia (void)
3604
{
3605
    ppc_tlb_invalidate_all(env);
3606
}
3607

    
3608
void helper_tlbie (target_ulong addr)
3609
{
3610
    ppc_tlb_invalidate_one(env, addr);
3611
}
3612

    
3613
/* Software driven TLBs management */
3614
/* PowerPC 602/603 software TLB load instructions helpers */
3615
static void do_6xx_tlb (target_ulong new_EPN, int is_code)
3616
{
3617
    target_ulong RPN, CMP, EPN;
3618
    int way;
3619

    
3620
    RPN = env->spr[SPR_RPA];
3621
    if (is_code) {
3622
        CMP = env->spr[SPR_ICMP];
3623
        EPN = env->spr[SPR_IMISS];
3624
    } else {
3625
        CMP = env->spr[SPR_DCMP];
3626
        EPN = env->spr[SPR_DMISS];
3627
    }
3628
    way = (env->spr[SPR_SRR1] >> 17) & 1;
3629
    LOG_SWTLB("%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
3630
                " PTE1 " ADDRX " way %d\n",
3631
                __func__, new_EPN, EPN, CMP, RPN, way);
3632
    /* Store this TLB */
3633
    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3634
                     way, is_code, CMP, RPN);
3635
}
3636

    
3637
void helper_6xx_tlbd (target_ulong EPN)
3638
{
3639
    do_6xx_tlb(EPN, 0);
3640
}
3641

    
3642
void helper_6xx_tlbi (target_ulong EPN)
3643
{
3644
    do_6xx_tlb(EPN, 1);
3645
}
3646

    
3647
/* PowerPC 74xx software TLB load instructions helpers */
3648
static void do_74xx_tlb (target_ulong new_EPN, int is_code)
3649
{
3650
    target_ulong RPN, CMP, EPN;
3651
    int way;
3652

    
3653
    RPN = env->spr[SPR_PTELO];
3654
    CMP = env->spr[SPR_PTEHI];
3655
    EPN = env->spr[SPR_TLBMISS] & ~0x3;
3656
    way = env->spr[SPR_TLBMISS] & 0x3;
3657
    LOG_SWTLB("%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
3658
                " PTE1 " ADDRX " way %d\n",
3659
                __func__, new_EPN, EPN, CMP, RPN, way);
3660
    /* Store this TLB */
3661
    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3662
                     way, is_code, CMP, RPN);
3663
}
3664

    
3665
void helper_74xx_tlbd (target_ulong EPN)
3666
{
3667
    do_74xx_tlb(EPN, 0);
3668
}
3669

    
3670
void helper_74xx_tlbi (target_ulong EPN)
3671
{
3672
    do_74xx_tlb(EPN, 1);
3673
}
3674

    
3675
static always_inline target_ulong booke_tlb_to_page_size (int size)
3676
{
3677
    return 1024 << (2 * size);
3678
}
3679

    
3680
static always_inline int booke_page_size_to_tlb (target_ulong page_size)
3681
{
3682
    int size;
3683

    
3684
    switch (page_size) {
3685
    case 0x00000400UL:
3686
        size = 0x0;
3687
        break;
3688
    case 0x00001000UL:
3689
        size = 0x1;
3690
        break;
3691
    case 0x00004000UL:
3692
        size = 0x2;
3693
        break;
3694
    case 0x00010000UL:
3695
        size = 0x3;
3696
        break;
3697
    case 0x00040000UL:
3698
        size = 0x4;
3699
        break;
3700
    case 0x00100000UL:
3701
        size = 0x5;
3702
        break;
3703
    case 0x00400000UL:
3704
        size = 0x6;
3705
        break;
3706
    case 0x01000000UL:
3707
        size = 0x7;
3708
        break;
3709
    case 0x04000000UL:
3710
        size = 0x8;
3711
        break;
3712
    case 0x10000000UL:
3713
        size = 0x9;
3714
        break;
3715
    case 0x40000000UL:
3716
        size = 0xA;
3717
        break;
3718
#if defined (TARGET_PPC64)
3719
    case 0x000100000000ULL:
3720
        size = 0xB;
3721
        break;
3722
    case 0x000400000000ULL:
3723
        size = 0xC;
3724
        break;
3725
    case 0x001000000000ULL:
3726
        size = 0xD;
3727
        break;
3728
    case 0x004000000000ULL:
3729
        size = 0xE;
3730
        break;
3731
    case 0x010000000000ULL:
3732
        size = 0xF;
3733
        break;
3734
#endif
3735
    default:
3736
        size = -1;
3737
        break;
3738
    }
3739

    
3740
    return size;
3741
}
3742

    
3743
/* Helpers for 4xx TLB management */
3744
target_ulong helper_4xx_tlbre_lo (target_ulong entry)
3745
{
3746
    ppcemb_tlb_t *tlb;
3747
    target_ulong ret;
3748
    int size;
3749

    
3750
    entry &= 0x3F;
3751
    tlb = &env->tlb[entry].tlbe;
3752
    ret = tlb->EPN;
3753
    if (tlb->prot & PAGE_VALID)
3754
        ret |= 0x400;
3755
    size = booke_page_size_to_tlb(tlb->size);
3756
    if (size < 0 || size > 0x7)
3757
        size = 1;
3758
    ret |= size << 7;
3759
    env->spr[SPR_40x_PID] = tlb->PID;
3760
    return ret;
3761
}
3762

    
3763
target_ulong helper_4xx_tlbre_hi (target_ulong entry)
3764
{
3765
    ppcemb_tlb_t *tlb;
3766
    target_ulong ret;
3767

    
3768
    entry &= 0x3F;
3769
    tlb = &env->tlb[entry].tlbe;
3770
    ret = tlb->RPN;
3771
    if (tlb->prot & PAGE_EXEC)
3772
        ret |= 0x200;
3773
    if (tlb->prot & PAGE_WRITE)
3774
        ret |= 0x100;
3775
    return ret;
3776
}
3777

    
3778
void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
3779
{
3780
    ppcemb_tlb_t *tlb;
3781
    target_ulong page, end;
3782

    
3783
    LOG_SWTLB("%s entry %d val " ADDRX "\n", __func__, (int)entry, val);
3784
    entry &= 0x3F;
3785
    tlb = &env->tlb[entry].tlbe;
3786
    /* Invalidate previous TLB (if it's valid) */
3787
    if (tlb->prot & PAGE_VALID) {
3788
        end = tlb->EPN + tlb->size;
3789
        LOG_SWTLB("%s: invalidate old TLB %d start " ADDRX
3790
                    " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
3791
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3792
            tlb_flush_page(env, page);
3793
    }
3794
    tlb->size = booke_tlb_to_page_size((val >> 7) & 0x7);
3795
    /* We cannot handle TLB size < TARGET_PAGE_SIZE.
3796
     * If this ever occurs, one should use the ppcemb target instead
3797
     * of the ppc or ppc64 one
3798
     */
3799
    if ((val & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
3800
        cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
3801
                  "are not supported (%d)\n",
3802
                  tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
3803
    }
3804
    tlb->EPN = val & ~(tlb->size - 1);
3805
    if (val & 0x40)
3806
        tlb->prot |= PAGE_VALID;
3807
    else
3808
        tlb->prot &= ~PAGE_VALID;
3809
    if (val & 0x20) {
3810
        /* XXX: TO BE FIXED */
3811
        cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
3812
    }
3813
    tlb->PID = env->spr[SPR_40x_PID]; /* PID */
3814
    tlb->attr = val & 0xFF;
3815
    LOG_SWTLB("%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
3816
                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
3817
                (int)entry, tlb->RPN, tlb->EPN, tlb->size,
3818
                tlb->prot & PAGE_READ ? 'r' : '-',
3819
                tlb->prot & PAGE_WRITE ? 'w' : '-',
3820
                tlb->prot & PAGE_EXEC ? 'x' : '-',
3821
                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
3822
    /* Invalidate new TLB (if valid) */
3823
    if (tlb->prot & PAGE_VALID) {
3824
        end = tlb->EPN + tlb->size;
3825
        LOG_SWTLB("%s: invalidate TLB %d start " ADDRX
3826
                    " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
3827
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3828
            tlb_flush_page(env, page);
3829
    }
3830
}
3831

    
3832
void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
3833
{
3834
    ppcemb_tlb_t *tlb;
3835

    
3836
    LOG_SWTLB("%s entry %i val " ADDRX "\n", __func__, (int)entry, val);
3837
    entry &= 0x3F;
3838
    tlb = &env->tlb[entry].tlbe;
3839
    tlb->RPN = val & 0xFFFFFC00;
3840
    tlb->prot = PAGE_READ;
3841
    if (val & 0x200)
3842
        tlb->prot |= PAGE_EXEC;
3843
    if (val & 0x100)
3844
        tlb->prot |= PAGE_WRITE;
3845
    LOG_SWTLB("%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
3846
                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
3847
                (int)entry, tlb->RPN, tlb->EPN, tlb->size,
3848
                tlb->prot & PAGE_READ ? 'r' : '-',
3849
                tlb->prot & PAGE_WRITE ? 'w' : '-',
3850
                tlb->prot & PAGE_EXEC ? 'x' : '-',
3851
                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
3852
}
3853

    
3854
target_ulong helper_4xx_tlbsx (target_ulong address)
3855
{
3856
    return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
3857
}
3858

    
3859
/* PowerPC 440 TLB management */
3860
void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
3861
{
3862
    ppcemb_tlb_t *tlb;
3863
    target_ulong EPN, RPN, size;
3864
    int do_flush_tlbs;
3865

    
3866
    LOG_SWTLB("%s word %d entry %d value " ADDRX "\n",
3867
                __func__, word, (int)entry, value);
3868
    do_flush_tlbs = 0;
3869
    entry &= 0x3F;
3870
    tlb = &env->tlb[entry].tlbe;
3871
    switch (word) {
3872
    default:
3873
        /* Just here to please gcc */
3874
    case 0:
3875
        EPN = value & 0xFFFFFC00;
3876
        if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
3877
            do_flush_tlbs = 1;
3878
        tlb->EPN = EPN;
3879
        size = booke_tlb_to_page_size((value >> 4) & 0xF);
3880
        if ((tlb->prot & PAGE_VALID) && tlb->size < size)
3881
            do_flush_tlbs = 1;
3882
        tlb->size = size;
3883
        tlb->attr &= ~0x1;
3884
        tlb->attr |= (value >> 8) & 1;
3885
        if (value & 0x200) {
3886
            tlb->prot |= PAGE_VALID;
3887
        } else {
3888
            if (tlb->prot & PAGE_VALID) {
3889
                tlb->prot &= ~PAGE_VALID;
3890
                do_flush_tlbs = 1;
3891
            }
3892
        }
3893
        tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
3894
        if (do_flush_tlbs)
3895
            tlb_flush(env, 1);
3896
        break;
3897
    case 1:
3898
        RPN = value & 0xFFFFFC0F;
3899
        if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
3900
            tlb_flush(env, 1);
3901
        tlb->RPN = RPN;
3902
        break;
3903
    case 2:
3904
        tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
3905
        tlb->prot = tlb->prot & PAGE_VALID;
3906
        if (value & 0x1)
3907
            tlb->prot |= PAGE_READ << 4;
3908
        if (value & 0x2)
3909
            tlb->prot |= PAGE_WRITE << 4;
3910
        if (value & 0x4)
3911
            tlb->prot |= PAGE_EXEC << 4;
3912
        if (value & 0x8)
3913
            tlb->prot |= PAGE_READ;
3914
        if (value & 0x10)
3915
            tlb->prot |= PAGE_WRITE;
3916
        if (value & 0x20)
3917
            tlb->prot |= PAGE_EXEC;
3918
        break;
3919
    }
3920
}
3921

    
3922
target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
3923
{
3924
    ppcemb_tlb_t *tlb;
3925
    target_ulong ret;
3926
    int size;
3927

    
3928
    entry &= 0x3F;
3929
    tlb = &env->tlb[entry].tlbe;
3930
    switch (word) {
3931
    default:
3932
        /* Just here to please gcc */
3933
    case 0:
3934
        ret = tlb->EPN;
3935
        size = booke_page_size_to_tlb(tlb->size);
3936
        if (size < 0 || size > 0xF)
3937
            size = 1;
3938
        ret |= size << 4;
3939
        if (tlb->attr & 0x1)
3940
            ret |= 0x100;
3941
        if (tlb->prot & PAGE_VALID)
3942
            ret |= 0x200;
3943
        env->spr[SPR_440_MMUCR] &= ~0x000000FF;
3944
        env->spr[SPR_440_MMUCR] |= tlb->PID;
3945
        break;
3946
    case 1:
3947
        ret = tlb->RPN;
3948
        break;
3949
    case 2:
3950
        ret = tlb->attr & ~0x1;
3951
        if (tlb->prot & (PAGE_READ << 4))
3952
            ret |= 0x1;
3953
        if (tlb->prot & (PAGE_WRITE << 4))
3954
            ret |= 0x2;
3955
        if (tlb->prot & (PAGE_EXEC << 4))
3956
            ret |= 0x4;
3957
        if (tlb->prot & PAGE_READ)
3958
            ret |= 0x8;
3959
        if (tlb->prot & PAGE_WRITE)
3960
            ret |= 0x10;
3961
        if (tlb->prot & PAGE_EXEC)
3962
            ret |= 0x20;
3963
        break;
3964
    }
3965
    return ret;
3966
}
3967

    
3968
target_ulong helper_440_tlbsx (target_ulong address)
3969
{
3970
    return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
3971
}
3972

    
3973
#endif /* !CONFIG_USER_ONLY */