Statistics
| Branch: | Revision:

root / target-ppc / op_helper.c @ 56fdd213

History | View | Annotate | Download (117.6 kB)

1
/*
2
 *  PowerPC emulation helpers for qemu.
3
 *
4
 *  Copyright (c) 2003-2007 Jocelyn Mayer
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
19
 */
20
#include <string.h>
21
#include "exec.h"
22
#include "host-utils.h"
23
#include "helper.h"
24

    
25
#include "helper_regs.h"
26

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

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

    
37

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
564
    u.d = d;
565

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1225
#endif
1226

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1501
/* fre - fre. */
1502
uint64_t helper_fre (uint64_t arg)
1503
{
1504
    CPU_DoubleU farg;
1505
    farg.ll = arg;
1506

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

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

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

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

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

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

    
1561
    farg1.ll = arg1;
1562

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2223
void helper_vmhaddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2224
{
2225
    int sat = 0;
2226
    int i;
2227

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

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

    
2239
void helper_vmhraddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2240
{
2241
    int sat = 0;
2242
    int i;
2243

    
2244
    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2245
        int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
2246
        int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2247
        r->s16[i] = cvtswsh (t, &sat);
2248
    }
2249

    
2250
    if (sat) {
2251
        env->vscr |= (1 << VSCR_SAT);
2252
    }
2253
}
2254

    
2255
#define VMINMAX_DO(name, compare, element)                              \
2256
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
2257
    {                                                                   \
2258
        int i;                                                          \
2259
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2260
            if (a->element[i] compare b->element[i]) {                  \
2261
                r->element[i] = b->element[i];                          \
2262
            } else {                                                    \
2263
                r->element[i] = a->element[i];                          \
2264
            }                                                           \
2265
        }                                                               \
2266
    }
2267
#define VMINMAX(suffix, element)                \
2268
  VMINMAX_DO(min##suffix, >, element)           \
2269
  VMINMAX_DO(max##suffix, <, element)
2270
VMINMAX(sb, s8)
2271
VMINMAX(sh, s16)
2272
VMINMAX(sw, s32)
2273
VMINMAX(ub, u8)
2274
VMINMAX(uh, u16)
2275
VMINMAX(uw, u32)
2276
#undef VMINMAX_DO
2277
#undef VMINMAX
2278

    
2279
#define VMINMAXFP(suffix, rT, rF)                                       \
2280
    void helper_v##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)    \
2281
    {                                                                   \
2282
        int i;                                                          \
2283
        for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
2284
            HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) {                    \
2285
                if (float32_lt_quiet(a->f[i], b->f[i], &env->vec_status)) { \
2286
                    r->f[i] = rT->f[i];                                 \
2287
                } else {                                                \
2288
                    r->f[i] = rF->f[i];                                 \
2289
                }                                                       \
2290
            }                                                           \
2291
        }                                                               \
2292
    }
2293
VMINMAXFP(minfp, a, b)
2294
VMINMAXFP(maxfp, b, a)
2295
#undef VMINMAXFP
2296

    
2297
void helper_vmladduhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2298
{
2299
    int i;
2300
    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2301
        int32_t prod = a->s16[i] * b->s16[i];
2302
        r->s16[i] = (int16_t) (prod + c->s16[i]);
2303
    }
2304
}
2305

    
2306
#define VMRG_DO(name, element, highp)                                   \
2307
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
2308
    {                                                                   \
2309
        ppc_avr_t result;                                               \
2310
        int i;                                                          \
2311
        size_t n_elems = ARRAY_SIZE(r->element);                        \
2312
        for (i = 0; i < n_elems/2; i++) {                               \
2313
            if (highp) {                                                \
2314
                result.element[i*2+HI_IDX] = a->element[i];             \
2315
                result.element[i*2+LO_IDX] = b->element[i];             \
2316
            } else {                                                    \
2317
                result.element[n_elems - i*2 - (1+HI_IDX)] = b->element[n_elems - i - 1]; \
2318
                result.element[n_elems - i*2 - (1+LO_IDX)] = a->element[n_elems - i - 1]; \
2319
            }                                                           \
2320
        }                                                               \
2321
        *r = result;                                                    \
2322
    }
2323
#if defined(WORDS_BIGENDIAN)
2324
#define MRGHI 0
2325
#define MRGLO 1
2326
#else
2327
#define MRGHI 1
2328
#define MRGLO 0
2329
#endif
2330
#define VMRG(suffix, element)                   \
2331
  VMRG_DO(mrgl##suffix, element, MRGHI)         \
2332
  VMRG_DO(mrgh##suffix, element, MRGLO)
2333
VMRG(b, u8)
2334
VMRG(h, u16)
2335
VMRG(w, u32)
2336
#undef VMRG_DO
2337
#undef VMRG
2338
#undef MRGHI
2339
#undef MRGLO
2340

    
2341
void helper_vmsummbm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2342
{
2343
    int32_t prod[16];
2344
    int i;
2345

    
2346
    for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
2347
        prod[i] = (int32_t)a->s8[i] * b->u8[i];
2348
    }
2349

    
2350
    VECTOR_FOR_INORDER_I(i, s32) {
2351
        r->s32[i] = c->s32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2352
    }
2353
}
2354

    
2355
void helper_vmsumshm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2356
{
2357
    int32_t prod[8];
2358
    int i;
2359

    
2360
    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2361
        prod[i] = a->s16[i] * b->s16[i];
2362
    }
2363

    
2364
    VECTOR_FOR_INORDER_I(i, s32) {
2365
        r->s32[i] = c->s32[i] + prod[2*i] + prod[2*i+1];
2366
    }
2367
}
2368

    
2369
void helper_vmsumshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2370
{
2371
    int32_t prod[8];
2372
    int i;
2373
    int sat = 0;
2374

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

    
2379
    VECTOR_FOR_INORDER_I (i, s32) {
2380
        int64_t t = (int64_t)c->s32[i] + prod[2*i] + prod[2*i+1];
2381
        r->u32[i] = cvtsdsw(t, &sat);
2382
    }
2383

    
2384
    if (sat) {
2385
        env->vscr |= (1 << VSCR_SAT);
2386
    }
2387
}
2388

    
2389
void helper_vmsumubm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2390
{
2391
    uint16_t prod[16];
2392
    int i;
2393

    
2394
    for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2395
        prod[i] = a->u8[i] * b->u8[i];
2396
    }
2397

    
2398
    VECTOR_FOR_INORDER_I(i, u32) {
2399
        r->u32[i] = c->u32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2400
    }
2401
}
2402

    
2403
void helper_vmsumuhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2404
{
2405
    uint32_t prod[8];
2406
    int i;
2407

    
2408
    for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2409
        prod[i] = a->u16[i] * b->u16[i];
2410
    }
2411

    
2412
    VECTOR_FOR_INORDER_I(i, u32) {
2413
        r->u32[i] = c->u32[i] + prod[2*i] + prod[2*i+1];
2414
    }
2415
}
2416

    
2417
void helper_vmsumuhs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2418
{
2419
    uint32_t prod[8];
2420
    int i;
2421
    int sat = 0;
2422

    
2423
    for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2424
        prod[i] = a->u16[i] * b->u16[i];
2425
    }
2426

    
2427
    VECTOR_FOR_INORDER_I (i, s32) {
2428
        uint64_t t = (uint64_t)c->u32[i] + prod[2*i] + prod[2*i+1];
2429
        r->u32[i] = cvtuduw(t, &sat);
2430
    }
2431

    
2432
    if (sat) {
2433
        env->vscr |= (1 << VSCR_SAT);
2434
    }
2435
}
2436

    
2437
#define VMUL_DO(name, mul_element, prod_element, evenp)                 \
2438
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
2439
    {                                                                   \
2440
        int i;                                                          \
2441
        VECTOR_FOR_INORDER_I(i, prod_element) {                         \
2442
            if (evenp) {                                                \
2443
                r->prod_element[i] = a->mul_element[i*2+HI_IDX] * b->mul_element[i*2+HI_IDX]; \
2444
            } else {                                                    \
2445
                r->prod_element[i] = a->mul_element[i*2+LO_IDX] * b->mul_element[i*2+LO_IDX]; \
2446
            }                                                           \
2447
        }                                                               \
2448
    }
2449
#define VMUL(suffix, mul_element, prod_element) \
2450
  VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
2451
  VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
2452
VMUL(sb, s8, s16)
2453
VMUL(sh, s16, s32)
2454
VMUL(ub, u8, u16)
2455
VMUL(uh, u16, u32)
2456
#undef VMUL_DO
2457
#undef VMUL
2458

    
2459
void helper_vperm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2460
{
2461
    ppc_avr_t result;
2462
    int i;
2463
    VECTOR_FOR_INORDER_I (i, u8) {
2464
        int s = c->u8[i] & 0x1f;
2465
#if defined(WORDS_BIGENDIAN)
2466
        int index = s & 0xf;
2467
#else
2468
        int index = 15 - (s & 0xf);
2469
#endif
2470
        if (s & 0x10) {
2471
            result.u8[i] = b->u8[index];
2472
        } else {
2473
            result.u8[i] = a->u8[index];
2474
        }
2475
    }
2476
    *r = result;
2477
}
2478

    
2479
#if defined(WORDS_BIGENDIAN)
2480
#define PKBIG 1
2481
#else
2482
#define PKBIG 0
2483
#endif
2484
void helper_vpkpx (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2485
{
2486
    int i, j;
2487
    ppc_avr_t result;
2488
#if defined(WORDS_BIGENDIAN)
2489
    const ppc_avr_t *x[2] = { a, b };
2490
#else
2491
    const ppc_avr_t *x[2] = { b, a };
2492
#endif
2493

    
2494
    VECTOR_FOR_INORDER_I (i, u64) {
2495
        VECTOR_FOR_INORDER_I (j, u32){
2496
            uint32_t e = x[i]->u32[j];
2497
            result.u16[4*i+j] = (((e >> 9) & 0xfc00) |
2498
                                 ((e >> 6) & 0x3e0) |
2499
                                 ((e >> 3) & 0x1f));
2500
        }
2501
    }
2502
    *r = result;
2503
}
2504

    
2505
#define VPK(suffix, from, to, cvt, dosat)       \
2506
    void helper_vpk##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
2507
    {                                                                   \
2508
        int i;                                                          \
2509
        int sat = 0;                                                    \
2510
        ppc_avr_t result;                                               \
2511
        ppc_avr_t *a0 = PKBIG ? a : b;                                  \
2512
        ppc_avr_t *a1 = PKBIG ? b : a;                                  \
2513
        VECTOR_FOR_INORDER_I (i, from) {                                \
2514
            result.to[i] = cvt(a0->from[i], &sat);                      \
2515
            result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat);  \
2516
        }                                                               \
2517
        *r = result;                                                    \
2518
        if (dosat && sat) {                                             \
2519
            env->vscr |= (1 << VSCR_SAT);                               \
2520
        }                                                               \
2521
    }
2522
#define I(x, y) (x)
2523
VPK(shss, s16, s8, cvtshsb, 1)
2524
VPK(shus, s16, u8, cvtshub, 1)
2525
VPK(swss, s32, s16, cvtswsh, 1)
2526
VPK(swus, s32, u16, cvtswuh, 1)
2527
VPK(uhus, u16, u8, cvtuhub, 1)
2528
VPK(uwus, u32, u16, cvtuwuh, 1)
2529
VPK(uhum, u16, u8, I, 0)
2530
VPK(uwum, u32, u16, I, 0)
2531
#undef I
2532
#undef VPK
2533
#undef PKBIG
2534

    
2535
#define VRFI(suffix, rounding)                                          \
2536
    void helper_vrfi##suffix (ppc_avr_t *r, ppc_avr_t *b)               \
2537
    {                                                                   \
2538
        int i;                                                          \
2539
        float_status s = env->vec_status;                               \
2540
        set_float_rounding_mode(rounding, &s);                          \
2541
        for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
2542
            HANDLE_NAN1(r->f[i], b->f[i]) {                             \
2543
                r->f[i] = float32_round_to_int (b->f[i], &s);           \
2544
            }                                                           \
2545
        }                                                               \
2546
    }
2547
VRFI(n, float_round_nearest_even)
2548
VRFI(m, float_round_down)
2549
VRFI(p, float_round_up)
2550
VRFI(z, float_round_to_zero)
2551
#undef VRFI
2552

    
2553
#define VROTATE(suffix, element)                                        \
2554
    void helper_vrl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
2555
    {                                                                   \
2556
        int i;                                                          \
2557
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2558
            unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2559
            unsigned int shift = b->element[i] & mask;                  \
2560
            r->element[i] = (a->element[i] << shift) | (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
2561
        }                                                               \
2562
    }
2563
VROTATE(b, u8)
2564
VROTATE(h, u16)
2565
VROTATE(w, u32)
2566
#undef VROTATE
2567

    
2568
void helper_vsel (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2569
{
2570
    r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
2571
    r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
2572
}
2573

    
2574
void helper_vlogefp (ppc_avr_t *r, ppc_avr_t *b)
2575
{
2576
    int i;
2577
    for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2578
        HANDLE_NAN1(r->f[i], b->f[i]) {
2579
            r->f[i] = float32_log2(b->f[i], &env->vec_status);
2580
        }
2581
    }
2582
}
2583

    
2584
#if defined(WORDS_BIGENDIAN)
2585
#define LEFT 0
2586
#define RIGHT 1
2587
#else
2588
#define LEFT 1
2589
#define RIGHT 0
2590
#endif
2591
/* The specification says that the results are undefined if all of the
2592
 * shift counts are not identical.  We check to make sure that they are
2593
 * to conform to what real hardware appears to do.  */
2594
#define VSHIFT(suffix, leftp)                                           \
2595
    void helper_vs##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)   \
2596
    {                                                                   \
2597
        int shift = b->u8[LO_IDX*0x15] & 0x7;                           \
2598
        int doit = 1;                                                   \
2599
        int i;                                                          \
2600
        for (i = 0; i < ARRAY_SIZE(r->u8); i++) {                       \
2601
            doit = doit && ((b->u8[i] & 0x7) == shift);                 \
2602
        }                                                               \
2603
        if (doit) {                                                     \
2604
            if (shift == 0) {                                           \
2605
                *r = *a;                                                \
2606
            } else if (leftp) {                                         \
2607
                uint64_t carry = a->u64[LO_IDX] >> (64 - shift);        \
2608
                r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry;     \
2609
                r->u64[LO_IDX] = a->u64[LO_IDX] << shift;               \
2610
            } else {                                                    \
2611
                uint64_t carry = a->u64[HI_IDX] << (64 - shift);        \
2612
                r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry;     \
2613
                r->u64[HI_IDX] = a->u64[HI_IDX] >> shift;               \
2614
            }                                                           \
2615
        }                                                               \
2616
    }
2617
VSHIFT(l, LEFT)
2618
VSHIFT(r, RIGHT)
2619
#undef VSHIFT
2620
#undef LEFT
2621
#undef RIGHT
2622

    
2623
#define VSL(suffix, element)                                            \
2624
    void helper_vsl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
2625
    {                                                                   \
2626
        int i;                                                          \
2627
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2628
            unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2629
            unsigned int shift = b->element[i] & mask;                  \
2630
            r->element[i] = a->element[i] << shift;                     \
2631
        }                                                               \
2632
    }
2633
VSL(b, u8)
2634
VSL(h, u16)
2635
VSL(w, u32)
2636
#undef VSL
2637

    
2638
void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
2639
{
2640
    int sh = shift & 0xf;
2641
    int i;
2642
    ppc_avr_t result;
2643

    
2644
#if defined(WORDS_BIGENDIAN)
2645
    for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2646
        int index = sh + i;
2647
        if (index > 0xf) {
2648
            result.u8[i] = b->u8[index-0x10];
2649
        } else {
2650
            result.u8[i] = a->u8[index];
2651
        }
2652
    }
2653
#else
2654
    for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2655
        int index = (16 - sh) + i;
2656
        if (index > 0xf) {
2657
            result.u8[i] = a->u8[index-0x10];
2658
        } else {
2659
            result.u8[i] = b->u8[index];
2660
        }
2661
    }
2662
#endif
2663
    *r = result;
2664
}
2665

    
2666
void helper_vslo (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2667
{
2668
  int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2669

    
2670
#if defined (WORDS_BIGENDIAN)
2671
  memmove (&r->u8[0], &a->u8[sh], 16-sh);
2672
  memset (&r->u8[16-sh], 0, sh);
2673
#else
2674
  memmove (&r->u8[sh], &a->u8[0], 16-sh);
2675
  memset (&r->u8[0], 0, sh);
2676
#endif
2677
}
2678

    
2679
/* Experimental testing shows that hardware masks the immediate.  */
2680
#define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
2681
#if defined(WORDS_BIGENDIAN)
2682
#define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
2683
#else
2684
#define SPLAT_ELEMENT(element) (ARRAY_SIZE(r->element)-1 - _SPLAT_MASKED(element))
2685
#endif
2686
#define VSPLT(suffix, element)                                          \
2687
    void helper_vsplt##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
2688
    {                                                                   \
2689
        uint32_t s = b->element[SPLAT_ELEMENT(element)];                \
2690
        int i;                                                          \
2691
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2692
            r->element[i] = s;                                          \
2693
        }                                                               \
2694
    }
2695
VSPLT(b, u8)
2696
VSPLT(h, u16)
2697
VSPLT(w, u32)
2698
#undef VSPLT
2699
#undef SPLAT_ELEMENT
2700
#undef _SPLAT_MASKED
2701

    
2702
#define VSPLTI(suffix, element, splat_type)                     \
2703
    void helper_vspltis##suffix (ppc_avr_t *r, uint32_t splat)  \
2704
    {                                                           \
2705
        splat_type x = (int8_t)(splat << 3) >> 3;               \
2706
        int i;                                                  \
2707
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {          \
2708
            r->element[i] = x;                                  \
2709
        }                                                       \
2710
    }
2711
VSPLTI(b, s8, int8_t)
2712
VSPLTI(h, s16, int16_t)
2713
VSPLTI(w, s32, int32_t)
2714
#undef VSPLTI
2715

    
2716
#define VSR(suffix, element)                                            \
2717
    void helper_vsr##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
2718
    {                                                                   \
2719
        int i;                                                          \
2720
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2721
            unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2722
            unsigned int shift = b->element[i] & mask;                  \
2723
            r->element[i] = a->element[i] >> shift;                     \
2724
        }                                                               \
2725
    }
2726
VSR(ab, s8)
2727
VSR(ah, s16)
2728
VSR(aw, s32)
2729
VSR(b, u8)
2730
VSR(h, u16)
2731
VSR(w, u32)
2732
#undef VSR
2733

    
2734
void helper_vsro (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2735
{
2736
  int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2737

    
2738
#if defined (WORDS_BIGENDIAN)
2739
  memmove (&r->u8[sh], &a->u8[0], 16-sh);
2740
  memset (&r->u8[0], 0, sh);
2741
#else
2742
  memmove (&r->u8[0], &a->u8[sh], 16-sh);
2743
  memset (&r->u8[16-sh], 0, sh);
2744
#endif
2745
}
2746

    
2747
void helper_vsubcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2748
{
2749
    int i;
2750
    for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2751
        r->u32[i] = a->u32[i] >= b->u32[i];
2752
    }
2753
}
2754

    
2755
void helper_vsumsws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2756
{
2757
    int64_t t;
2758
    int i, upper;
2759
    ppc_avr_t result;
2760
    int sat = 0;
2761

    
2762
#if defined(WORDS_BIGENDIAN)
2763
    upper = ARRAY_SIZE(r->s32)-1;
2764
#else
2765
    upper = 0;
2766
#endif
2767
    t = (int64_t)b->s32[upper];
2768
    for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2769
        t += a->s32[i];
2770
        result.s32[i] = 0;
2771
    }
2772
    result.s32[upper] = cvtsdsw(t, &sat);
2773
    *r = result;
2774

    
2775
    if (sat) {
2776
        env->vscr |= (1 << VSCR_SAT);
2777
    }
2778
}
2779

    
2780
void helper_vsum2sws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2781
{
2782
    int i, j, upper;
2783
    ppc_avr_t result;
2784
    int sat = 0;
2785

    
2786
#if defined(WORDS_BIGENDIAN)
2787
    upper = 1;
2788
#else
2789
    upper = 0;
2790
#endif
2791
    for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
2792
        int64_t t = (int64_t)b->s32[upper+i*2];
2793
        result.u64[i] = 0;
2794
        for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
2795
            t += a->s32[2*i+j];
2796
        }
2797
        result.s32[upper+i*2] = cvtsdsw(t, &sat);
2798
    }
2799

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

    
2806
void helper_vsum4sbs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2807
{
2808
    int i, j;
2809
    int sat = 0;
2810

    
2811
    for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2812
        int64_t t = (int64_t)b->s32[i];
2813
        for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
2814
            t += a->s8[4*i+j];
2815
        }
2816
        r->s32[i] = cvtsdsw(t, &sat);
2817
    }
2818

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

    
2824
void helper_vsum4shs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2825
{
2826
    int sat = 0;
2827
    int i;
2828

    
2829
    for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2830
        int64_t t = (int64_t)b->s32[i];
2831
        t += a->s16[2*i] + a->s16[2*i+1];
2832
        r->s32[i] = cvtsdsw(t, &sat);
2833
    }
2834

    
2835
    if (sat) {
2836
        env->vscr |= (1 << VSCR_SAT);
2837
    }
2838
}
2839

    
2840
void helper_vsum4ubs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2841
{
2842
    int i, j;
2843
    int sat = 0;
2844

    
2845
    for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2846
        uint64_t t = (uint64_t)b->u32[i];
2847
        for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
2848
            t += a->u8[4*i+j];
2849
        }
2850
        r->u32[i] = cvtuduw(t, &sat);
2851
    }
2852

    
2853
    if (sat) {
2854
        env->vscr |= (1 << VSCR_SAT);
2855
    }
2856
}
2857

    
2858
#if defined(WORDS_BIGENDIAN)
2859
#define UPKHI 1
2860
#define UPKLO 0
2861
#else
2862
#define UPKHI 0
2863
#define UPKLO 1
2864
#endif
2865
#define VUPKPX(suffix, hi)                                      \
2866
    void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b)       \
2867
    {                                                           \
2868
        int i;                                                  \
2869
        ppc_avr_t result;                                       \
2870
        for (i = 0; i < ARRAY_SIZE(r->u32); i++) {              \
2871
            uint16_t e = b->u16[hi ? i : i+4];                  \
2872
            uint8_t a = (e >> 15) ? 0xff : 0;                   \
2873
            uint8_t r = (e >> 10) & 0x1f;                       \
2874
            uint8_t g = (e >> 5) & 0x1f;                        \
2875
            uint8_t b = e & 0x1f;                               \
2876
            result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b;       \
2877
        }                                                               \
2878
        *r = result;                                                    \
2879
    }
2880
VUPKPX(lpx, UPKLO)
2881
VUPKPX(hpx, UPKHI)
2882
#undef VUPKPX
2883

    
2884
#define VUPK(suffix, unpacked, packee, hi)                              \
2885
    void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b)               \
2886
    {                                                                   \
2887
        int i;                                                          \
2888
        ppc_avr_t result;                                               \
2889
        if (hi) {                                                       \
2890
            for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) {             \
2891
                result.unpacked[i] = b->packee[i];                      \
2892
            }                                                           \
2893
        } else {                                                        \
2894
            for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); i++) { \
2895
                result.unpacked[i-ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
2896
            }                                                           \
2897
        }                                                               \
2898
        *r = result;                                                    \
2899
    }
2900
VUPK(hsb, s16, s8, UPKHI)
2901
VUPK(hsh, s32, s16, UPKHI)
2902
VUPK(lsb, s16, s8, UPKLO)
2903
VUPK(lsh, s32, s16, UPKLO)
2904
#undef VUPK
2905
#undef UPKHI
2906
#undef UPKLO
2907

    
2908
#undef DO_HANDLE_NAN
2909
#undef HANDLE_NAN1
2910
#undef HANDLE_NAN2
2911
#undef HANDLE_NAN3
2912
#undef VECTOR_FOR_INORDER_I
2913
#undef HI_IDX
2914
#undef LO_IDX
2915

    
2916
/*****************************************************************************/
2917
/* SPE extension helpers */
2918
/* Use a table to make this quicker */
2919
static uint8_t hbrev[16] = {
2920
    0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
2921
    0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
2922
};
2923

    
2924
static always_inline uint8_t byte_reverse (uint8_t val)
2925
{
2926
    return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
2927
}
2928

    
2929
static always_inline uint32_t word_reverse (uint32_t val)
2930
{
2931
    return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
2932
        (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
2933
}
2934

    
2935
#define MASKBITS 16 // Random value - to be fixed (implementation dependant)
2936
target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
2937
{
2938
    uint32_t a, b, d, mask;
2939

    
2940
    mask = UINT32_MAX >> (32 - MASKBITS);
2941
    a = arg1 & mask;
2942
    b = arg2 & mask;
2943
    d = word_reverse(1 + word_reverse(a | ~b));
2944
    return (arg1 & ~mask) | (d & b);
2945
}
2946

    
2947
uint32_t helper_cntlsw32 (uint32_t val)
2948
{
2949
    if (val & 0x80000000)
2950
        return clz32(~val);
2951
    else
2952
        return clz32(val);
2953
}
2954

    
2955
uint32_t helper_cntlzw32 (uint32_t val)
2956
{
2957
    return clz32(val);
2958
}
2959

    
2960
/* Single-precision floating-point conversions */
2961
static always_inline uint32_t efscfsi (uint32_t val)
2962
{
2963
    CPU_FloatU u;
2964

    
2965
    u.f = int32_to_float32(val, &env->vec_status);
2966

    
2967
    return u.l;
2968
}
2969

    
2970
static always_inline uint32_t efscfui (uint32_t val)
2971
{
2972
    CPU_FloatU u;
2973

    
2974
    u.f = uint32_to_float32(val, &env->vec_status);
2975

    
2976
    return u.l;
2977
}
2978

    
2979
static always_inline int32_t efsctsi (uint32_t val)
2980
{
2981
    CPU_FloatU u;
2982

    
2983
    u.l = val;
2984
    /* NaN are not treated the same way IEEE 754 does */
2985
    if (unlikely(float32_is_nan(u.f)))
2986
        return 0;
2987

    
2988
    return float32_to_int32(u.f, &env->vec_status);
2989
}
2990

    
2991
static always_inline uint32_t efsctui (uint32_t val)
2992
{
2993
    CPU_FloatU u;
2994

    
2995
    u.l = val;
2996
    /* NaN are not treated the same way IEEE 754 does */
2997
    if (unlikely(float32_is_nan(u.f)))
2998
        return 0;
2999

    
3000
    return float32_to_uint32(u.f, &env->vec_status);
3001
}
3002

    
3003
static always_inline uint32_t efsctsiz (uint32_t val)
3004
{
3005
    CPU_FloatU u;
3006

    
3007
    u.l = val;
3008
    /* NaN are not treated the same way IEEE 754 does */
3009
    if (unlikely(float32_is_nan(u.f)))
3010
        return 0;
3011

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

    
3015
static always_inline uint32_t efsctuiz (uint32_t val)
3016
{
3017
    CPU_FloatU u;
3018

    
3019
    u.l = val;
3020
    /* NaN are not treated the same way IEEE 754 does */
3021
    if (unlikely(float32_is_nan(u.f)))
3022
        return 0;
3023

    
3024
    return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
3025
}
3026

    
3027
static always_inline uint32_t efscfsf (uint32_t val)
3028
{
3029
    CPU_FloatU u;
3030
    float32 tmp;
3031

    
3032
    u.f = int32_to_float32(val, &env->vec_status);
3033
    tmp = int64_to_float32(1ULL << 32, &env->vec_status);
3034
    u.f = float32_div(u.f, tmp, &env->vec_status);
3035

    
3036
    return u.l;
3037
}
3038

    
3039
static always_inline uint32_t efscfuf (uint32_t val)
3040
{
3041
    CPU_FloatU u;
3042
    float32 tmp;
3043

    
3044
    u.f = uint32_to_float32(val, &env->vec_status);
3045
    tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3046
    u.f = float32_div(u.f, tmp, &env->vec_status);
3047

    
3048
    return u.l;
3049
}
3050

    
3051
static always_inline uint32_t efsctsf (uint32_t val)
3052
{
3053
    CPU_FloatU u;
3054
    float32 tmp;
3055

    
3056
    u.l = val;
3057
    /* NaN are not treated the same way IEEE 754 does */
3058
    if (unlikely(float32_is_nan(u.f)))
3059
        return 0;
3060
    tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3061
    u.f = float32_mul(u.f, tmp, &env->vec_status);
3062

    
3063
    return float32_to_int32(u.f, &env->vec_status);
3064
}
3065

    
3066
static always_inline uint32_t efsctuf (uint32_t val)
3067
{
3068
    CPU_FloatU u;
3069
    float32 tmp;
3070

    
3071
    u.l = val;
3072
    /* NaN are not treated the same way IEEE 754 does */
3073
    if (unlikely(float32_is_nan(u.f)))
3074
        return 0;
3075
    tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3076
    u.f = float32_mul(u.f, tmp, &env->vec_status);
3077

    
3078
    return float32_to_uint32(u.f, &env->vec_status);
3079
}
3080

    
3081
#define HELPER_SPE_SINGLE_CONV(name)                                          \
3082
uint32_t helper_e##name (uint32_t val)                                        \
3083
{                                                                             \
3084
    return e##name(val);                                                      \
3085
}
3086
/* efscfsi */
3087
HELPER_SPE_SINGLE_CONV(fscfsi);
3088
/* efscfui */
3089
HELPER_SPE_SINGLE_CONV(fscfui);
3090
/* efscfuf */
3091
HELPER_SPE_SINGLE_CONV(fscfuf);
3092
/* efscfsf */
3093
HELPER_SPE_SINGLE_CONV(fscfsf);
3094
/* efsctsi */
3095
HELPER_SPE_SINGLE_CONV(fsctsi);
3096
/* efsctui */
3097
HELPER_SPE_SINGLE_CONV(fsctui);
3098
/* efsctsiz */
3099
HELPER_SPE_SINGLE_CONV(fsctsiz);
3100
/* efsctuiz */
3101
HELPER_SPE_SINGLE_CONV(fsctuiz);
3102
/* efsctsf */
3103
HELPER_SPE_SINGLE_CONV(fsctsf);
3104
/* efsctuf */
3105
HELPER_SPE_SINGLE_CONV(fsctuf);
3106

    
3107
#define HELPER_SPE_VECTOR_CONV(name)                                          \
3108
uint64_t helper_ev##name (uint64_t val)                                       \
3109
{                                                                             \
3110
    return ((uint64_t)e##name(val >> 32) << 32) |                             \
3111
            (uint64_t)e##name(val);                                           \
3112
}
3113
/* evfscfsi */
3114
HELPER_SPE_VECTOR_CONV(fscfsi);
3115
/* evfscfui */
3116
HELPER_SPE_VECTOR_CONV(fscfui);
3117
/* evfscfuf */
3118
HELPER_SPE_VECTOR_CONV(fscfuf);
3119
/* evfscfsf */
3120
HELPER_SPE_VECTOR_CONV(fscfsf);
3121
/* evfsctsi */
3122
HELPER_SPE_VECTOR_CONV(fsctsi);
3123
/* evfsctui */
3124
HELPER_SPE_VECTOR_CONV(fsctui);
3125
/* evfsctsiz */
3126
HELPER_SPE_VECTOR_CONV(fsctsiz);
3127
/* evfsctuiz */
3128
HELPER_SPE_VECTOR_CONV(fsctuiz);
3129
/* evfsctsf */
3130
HELPER_SPE_VECTOR_CONV(fsctsf);
3131
/* evfsctuf */
3132
HELPER_SPE_VECTOR_CONV(fsctuf);
3133

    
3134
/* Single-precision floating-point arithmetic */
3135
static always_inline uint32_t efsadd (uint32_t op1, uint32_t op2)
3136
{
3137
    CPU_FloatU u1, u2;
3138
    u1.l = op1;
3139
    u2.l = op2;
3140
    u1.f = float32_add(u1.f, u2.f, &env->vec_status);
3141
    return u1.l;
3142
}
3143

    
3144
static always_inline uint32_t efssub (uint32_t op1, uint32_t op2)
3145
{
3146
    CPU_FloatU u1, u2;
3147
    u1.l = op1;
3148
    u2.l = op2;
3149
    u1.f = float32_sub(u1.f, u2.f, &env->vec_status);
3150
    return u1.l;
3151
}
3152

    
3153
static always_inline uint32_t efsmul (uint32_t op1, uint32_t op2)
3154
{
3155
    CPU_FloatU u1, u2;
3156
    u1.l = op1;
3157
    u2.l = op2;
3158
    u1.f = float32_mul(u1.f, u2.f, &env->vec_status);
3159
    return u1.l;
3160
}
3161

    
3162
static always_inline uint32_t efsdiv (uint32_t op1, uint32_t op2)
3163
{
3164
    CPU_FloatU u1, u2;
3165
    u1.l = op1;
3166
    u2.l = op2;
3167
    u1.f = float32_div(u1.f, u2.f, &env->vec_status);
3168
    return u1.l;
3169
}
3170

    
3171
#define HELPER_SPE_SINGLE_ARITH(name)                                         \
3172
uint32_t helper_e##name (uint32_t op1, uint32_t op2)                          \
3173
{                                                                             \
3174
    return e##name(op1, op2);                                                 \
3175
}
3176
/* efsadd */
3177
HELPER_SPE_SINGLE_ARITH(fsadd);
3178
/* efssub */
3179
HELPER_SPE_SINGLE_ARITH(fssub);
3180
/* efsmul */
3181
HELPER_SPE_SINGLE_ARITH(fsmul);
3182
/* efsdiv */
3183
HELPER_SPE_SINGLE_ARITH(fsdiv);
3184

    
3185
#define HELPER_SPE_VECTOR_ARITH(name)                                         \
3186
uint64_t helper_ev##name (uint64_t op1, uint64_t op2)                         \
3187
{                                                                             \
3188
    return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) |                  \
3189
            (uint64_t)e##name(op1, op2);                                      \
3190
}
3191
/* evfsadd */
3192
HELPER_SPE_VECTOR_ARITH(fsadd);
3193
/* evfssub */
3194
HELPER_SPE_VECTOR_ARITH(fssub);
3195
/* evfsmul */
3196
HELPER_SPE_VECTOR_ARITH(fsmul);
3197
/* evfsdiv */
3198
HELPER_SPE_VECTOR_ARITH(fsdiv);
3199

    
3200
/* Single-precision floating-point comparisons */
3201
static always_inline uint32_t efststlt (uint32_t op1, uint32_t op2)
3202
{
3203
    CPU_FloatU u1, u2;
3204
    u1.l = op1;
3205
    u2.l = op2;
3206
    return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0;
3207
}
3208

    
3209
static always_inline uint32_t efststgt (uint32_t op1, uint32_t op2)
3210
{
3211
    CPU_FloatU u1, u2;
3212
    u1.l = op1;
3213
    u2.l = op2;
3214
    return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4;
3215
}
3216

    
3217
static always_inline uint32_t efststeq (uint32_t op1, uint32_t op2)
3218
{
3219
    CPU_FloatU u1, u2;
3220
    u1.l = op1;
3221
    u2.l = op2;
3222
    return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0;
3223
}
3224

    
3225
static always_inline uint32_t efscmplt (uint32_t op1, uint32_t op2)
3226
{
3227
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3228
    return efststlt(op1, op2);
3229
}
3230

    
3231
static always_inline uint32_t efscmpgt (uint32_t op1, uint32_t op2)
3232
{
3233
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3234
    return efststgt(op1, op2);
3235
}
3236

    
3237
static always_inline uint32_t efscmpeq (uint32_t op1, uint32_t op2)
3238
{
3239
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3240
    return efststeq(op1, op2);
3241
}
3242

    
3243
#define HELPER_SINGLE_SPE_CMP(name)                                           \
3244
uint32_t helper_e##name (uint32_t op1, uint32_t op2)                          \
3245
{                                                                             \
3246
    return e##name(op1, op2) << 2;                                            \
3247
}
3248
/* efststlt */
3249
HELPER_SINGLE_SPE_CMP(fststlt);
3250
/* efststgt */
3251
HELPER_SINGLE_SPE_CMP(fststgt);
3252
/* efststeq */
3253
HELPER_SINGLE_SPE_CMP(fststeq);
3254
/* efscmplt */
3255
HELPER_SINGLE_SPE_CMP(fscmplt);
3256
/* efscmpgt */
3257
HELPER_SINGLE_SPE_CMP(fscmpgt);
3258
/* efscmpeq */
3259
HELPER_SINGLE_SPE_CMP(fscmpeq);
3260

    
3261
static always_inline uint32_t evcmp_merge (int t0, int t1)
3262
{
3263
    return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
3264
}
3265

    
3266
#define HELPER_VECTOR_SPE_CMP(name)                                           \
3267
uint32_t helper_ev##name (uint64_t op1, uint64_t op2)                         \
3268
{                                                                             \
3269
    return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2));     \
3270
}
3271
/* evfststlt */
3272
HELPER_VECTOR_SPE_CMP(fststlt);
3273
/* evfststgt */
3274
HELPER_VECTOR_SPE_CMP(fststgt);
3275
/* evfststeq */
3276
HELPER_VECTOR_SPE_CMP(fststeq);
3277
/* evfscmplt */
3278
HELPER_VECTOR_SPE_CMP(fscmplt);
3279
/* evfscmpgt */
3280
HELPER_VECTOR_SPE_CMP(fscmpgt);
3281
/* evfscmpeq */
3282
HELPER_VECTOR_SPE_CMP(fscmpeq);
3283

    
3284
/* Double-precision floating-point conversion */
3285
uint64_t helper_efdcfsi (uint32_t val)
3286
{
3287
    CPU_DoubleU u;
3288

    
3289
    u.d = int32_to_float64(val, &env->vec_status);
3290

    
3291
    return u.ll;
3292
}
3293

    
3294
uint64_t helper_efdcfsid (uint64_t val)
3295
{
3296
    CPU_DoubleU u;
3297

    
3298
    u.d = int64_to_float64(val, &env->vec_status);
3299

    
3300
    return u.ll;
3301
}
3302

    
3303
uint64_t helper_efdcfui (uint32_t val)
3304
{
3305
    CPU_DoubleU u;
3306

    
3307
    u.d = uint32_to_float64(val, &env->vec_status);
3308

    
3309
    return u.ll;
3310
}
3311

    
3312
uint64_t helper_efdcfuid (uint64_t val)
3313
{
3314
    CPU_DoubleU u;
3315

    
3316
    u.d = uint64_to_float64(val, &env->vec_status);
3317

    
3318
    return u.ll;
3319
}
3320

    
3321
uint32_t helper_efdctsi (uint64_t val)
3322
{
3323
    CPU_DoubleU u;
3324

    
3325
    u.ll = val;
3326
    /* NaN are not treated the same way IEEE 754 does */
3327
    if (unlikely(float64_is_nan(u.d)))
3328
        return 0;
3329

    
3330
    return float64_to_int32(u.d, &env->vec_status);
3331
}
3332

    
3333
uint32_t helper_efdctui (uint64_t val)
3334
{
3335
    CPU_DoubleU u;
3336

    
3337
    u.ll = val;
3338
    /* NaN are not treated the same way IEEE 754 does */
3339
    if (unlikely(float64_is_nan(u.d)))
3340
        return 0;
3341

    
3342
    return float64_to_uint32(u.d, &env->vec_status);
3343
}
3344

    
3345
uint32_t helper_efdctsiz (uint64_t val)
3346
{
3347
    CPU_DoubleU u;
3348

    
3349
    u.ll = val;
3350
    /* NaN are not treated the same way IEEE 754 does */
3351
    if (unlikely(float64_is_nan(u.d)))
3352
        return 0;
3353

    
3354
    return float64_to_int32_round_to_zero(u.d, &env->vec_status);
3355
}
3356

    
3357
uint64_t helper_efdctsidz (uint64_t val)
3358
{
3359
    CPU_DoubleU u;
3360

    
3361
    u.ll = val;
3362
    /* NaN are not treated the same way IEEE 754 does */
3363
    if (unlikely(float64_is_nan(u.d)))
3364
        return 0;
3365

    
3366
    return float64_to_int64_round_to_zero(u.d, &env->vec_status);
3367
}
3368

    
3369
uint32_t helper_efdctuiz (uint64_t val)
3370
{
3371
    CPU_DoubleU u;
3372

    
3373
    u.ll = val;
3374
    /* NaN are not treated the same way IEEE 754 does */
3375
    if (unlikely(float64_is_nan(u.d)))
3376
        return 0;
3377

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

    
3381
uint64_t helper_efdctuidz (uint64_t val)
3382
{
3383
    CPU_DoubleU u;
3384

    
3385
    u.ll = val;
3386
    /* NaN are not treated the same way IEEE 754 does */
3387
    if (unlikely(float64_is_nan(u.d)))
3388
        return 0;
3389

    
3390
    return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
3391
}
3392

    
3393
uint64_t helper_efdcfsf (uint32_t val)
3394
{
3395
    CPU_DoubleU u;
3396
    float64 tmp;
3397

    
3398
    u.d = int32_to_float64(val, &env->vec_status);
3399
    tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3400
    u.d = float64_div(u.d, tmp, &env->vec_status);
3401

    
3402
    return u.ll;
3403
}
3404

    
3405
uint64_t helper_efdcfuf (uint32_t val)
3406
{
3407
    CPU_DoubleU u;
3408
    float64 tmp;
3409

    
3410
    u.d = uint32_to_float64(val, &env->vec_status);
3411
    tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3412
    u.d = float64_div(u.d, tmp, &env->vec_status);
3413

    
3414
    return u.ll;
3415
}
3416

    
3417
uint32_t helper_efdctsf (uint64_t val)
3418
{
3419
    CPU_DoubleU u;
3420
    float64 tmp;
3421

    
3422
    u.ll = val;
3423
    /* NaN are not treated the same way IEEE 754 does */
3424
    if (unlikely(float64_is_nan(u.d)))
3425
        return 0;
3426
    tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3427
    u.d = float64_mul(u.d, tmp, &env->vec_status);
3428

    
3429
    return float64_to_int32(u.d, &env->vec_status);
3430
}
3431

    
3432
uint32_t helper_efdctuf (uint64_t val)
3433
{
3434
    CPU_DoubleU u;
3435
    float64 tmp;
3436

    
3437
    u.ll = val;
3438
    /* NaN are not treated the same way IEEE 754 does */
3439
    if (unlikely(float64_is_nan(u.d)))
3440
        return 0;
3441
    tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3442
    u.d = float64_mul(u.d, tmp, &env->vec_status);
3443

    
3444
    return float64_to_uint32(u.d, &env->vec_status);
3445
}
3446

    
3447
uint32_t helper_efscfd (uint64_t val)
3448
{
3449
    CPU_DoubleU u1;
3450
    CPU_FloatU u2;
3451

    
3452
    u1.ll = val;
3453
    u2.f = float64_to_float32(u1.d, &env->vec_status);
3454

    
3455
    return u2.l;
3456
}
3457

    
3458
uint64_t helper_efdcfs (uint32_t val)
3459
{
3460
    CPU_DoubleU u2;
3461
    CPU_FloatU u1;
3462

    
3463
    u1.l = val;
3464
    u2.d = float32_to_float64(u1.f, &env->vec_status);
3465

    
3466
    return u2.ll;
3467
}
3468

    
3469
/* Double precision fixed-point arithmetic */
3470
uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
3471
{
3472
    CPU_DoubleU u1, u2;
3473
    u1.ll = op1;
3474
    u2.ll = op2;
3475
    u1.d = float64_add(u1.d, u2.d, &env->vec_status);
3476
    return u1.ll;
3477
}
3478

    
3479
uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
3480
{
3481
    CPU_DoubleU u1, u2;
3482
    u1.ll = op1;
3483
    u2.ll = op2;
3484
    u1.d = float64_sub(u1.d, u2.d, &env->vec_status);
3485
    return u1.ll;
3486
}
3487

    
3488
uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
3489
{
3490
    CPU_DoubleU u1, u2;
3491
    u1.ll = op1;
3492
    u2.ll = op2;
3493
    u1.d = float64_mul(u1.d, u2.d, &env->vec_status);
3494
    return u1.ll;
3495
}
3496

    
3497
uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
3498
{
3499
    CPU_DoubleU u1, u2;
3500
    u1.ll = op1;
3501
    u2.ll = op2;
3502
    u1.d = float64_div(u1.d, u2.d, &env->vec_status);
3503
    return u1.ll;
3504
}
3505

    
3506
/* Double precision floating point helpers */
3507
uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
3508
{
3509
    CPU_DoubleU u1, u2;
3510
    u1.ll = op1;
3511
    u2.ll = op2;
3512
    return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0;
3513
}
3514

    
3515
uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
3516
{
3517
    CPU_DoubleU u1, u2;
3518
    u1.ll = op1;
3519
    u2.ll = op2;
3520
    return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4;
3521
}
3522

    
3523
uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
3524
{
3525
    CPU_DoubleU u1, u2;
3526
    u1.ll = op1;
3527
    u2.ll = op2;
3528
    return float64_eq(u1.d, u2.d, &env->vec_status) ? 4 : 0;
3529
}
3530

    
3531
uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
3532
{
3533
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3534
    return helper_efdtstlt(op1, op2);
3535
}
3536

    
3537
uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
3538
{
3539
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3540
    return helper_efdtstgt(op1, op2);
3541
}
3542

    
3543
uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
3544
{
3545
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3546
    return helper_efdtsteq(op1, op2);
3547
}
3548

    
3549
/*****************************************************************************/
3550
/* Softmmu support */
3551
#if !defined (CONFIG_USER_ONLY)
3552

    
3553
#define MMUSUFFIX _mmu
3554

    
3555
#define SHIFT 0
3556
#include "softmmu_template.h"
3557

    
3558
#define SHIFT 1
3559
#include "softmmu_template.h"
3560

    
3561
#define SHIFT 2
3562
#include "softmmu_template.h"
3563

    
3564
#define SHIFT 3
3565
#include "softmmu_template.h"
3566

    
3567
/* try to fill the TLB and return an exception if error. If retaddr is
3568
   NULL, it means that the function was called in C code (i.e. not
3569
   from generated code or from helper.c) */
3570
/* XXX: fix it to restore all registers */
3571
void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
3572
{
3573
    TranslationBlock *tb;
3574
    CPUState *saved_env;
3575
    unsigned long pc;
3576
    int ret;
3577

    
3578
    /* XXX: hack to restore env in all cases, even if not called from
3579
       generated code */
3580
    saved_env = env;
3581
    env = cpu_single_env;
3582
    ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
3583
    if (unlikely(ret != 0)) {
3584
        if (likely(retaddr)) {
3585
            /* now we have a real cpu fault */
3586
            pc = (unsigned long)retaddr;
3587
            tb = tb_find_pc(pc);
3588
            if (likely(tb)) {
3589
                /* the PC is inside the translated code. It means that we have
3590
                   a virtual CPU fault */
3591
                cpu_restore_state(tb, env, pc, NULL);
3592
            }
3593
        }
3594
        helper_raise_exception_err(env->exception_index, env->error_code);
3595
    }
3596
    env = saved_env;
3597
}
3598

    
3599
/* Segment registers load and store */
3600
target_ulong helper_load_sr (target_ulong sr_num)
3601
{
3602
    return env->sr[sr_num];
3603
}
3604

    
3605
void helper_store_sr (target_ulong sr_num, target_ulong val)
3606
{
3607
    ppc_store_sr(env, sr_num, val);
3608
}
3609

    
3610
/* SLB management */
3611
#if defined(TARGET_PPC64)
3612
target_ulong helper_load_slb (target_ulong slb_nr)
3613
{
3614
    return ppc_load_slb(env, slb_nr);
3615
}
3616

    
3617
void helper_store_slb (target_ulong slb_nr, target_ulong rs)
3618
{
3619
    ppc_store_slb(env, slb_nr, rs);
3620
}
3621

    
3622
void helper_slbia (void)
3623
{
3624
    ppc_slb_invalidate_all(env);
3625
}
3626

    
3627
void helper_slbie (target_ulong addr)
3628
{
3629
    ppc_slb_invalidate_one(env, addr);
3630
}
3631

    
3632
#endif /* defined(TARGET_PPC64) */
3633

    
3634
/* TLB management */
3635
void helper_tlbia (void)
3636
{
3637
    ppc_tlb_invalidate_all(env);
3638
}
3639

    
3640
void helper_tlbie (target_ulong addr)
3641
{
3642
    ppc_tlb_invalidate_one(env, addr);
3643
}
3644

    
3645
/* Software driven TLBs management */
3646
/* PowerPC 602/603 software TLB load instructions helpers */
3647
static void do_6xx_tlb (target_ulong new_EPN, int is_code)
3648
{
3649
    target_ulong RPN, CMP, EPN;
3650
    int way;
3651

    
3652
    RPN = env->spr[SPR_RPA];
3653
    if (is_code) {
3654
        CMP = env->spr[SPR_ICMP];
3655
        EPN = env->spr[SPR_IMISS];
3656
    } else {
3657
        CMP = env->spr[SPR_DCMP];
3658
        EPN = env->spr[SPR_DMISS];
3659
    }
3660
    way = (env->spr[SPR_SRR1] >> 17) & 1;
3661
    LOG_SWTLB("%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
3662
                " PTE1 " ADDRX " way %d\n",
3663
                __func__, new_EPN, EPN, CMP, RPN, way);
3664
    /* Store this TLB */
3665
    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3666
                     way, is_code, CMP, RPN);
3667
}
3668

    
3669
void helper_6xx_tlbd (target_ulong EPN)
3670
{
3671
    do_6xx_tlb(EPN, 0);
3672
}
3673

    
3674
void helper_6xx_tlbi (target_ulong EPN)
3675
{
3676
    do_6xx_tlb(EPN, 1);
3677
}
3678

    
3679
/* PowerPC 74xx software TLB load instructions helpers */
3680
static void do_74xx_tlb (target_ulong new_EPN, int is_code)
3681
{
3682
    target_ulong RPN, CMP, EPN;
3683
    int way;
3684

    
3685
    RPN = env->spr[SPR_PTELO];
3686
    CMP = env->spr[SPR_PTEHI];
3687
    EPN = env->spr[SPR_TLBMISS] & ~0x3;
3688
    way = env->spr[SPR_TLBMISS] & 0x3;
3689
    LOG_SWTLB("%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
3690
                " PTE1 " ADDRX " way %d\n",
3691
                __func__, new_EPN, EPN, CMP, RPN, way);
3692
    /* Store this TLB */
3693
    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3694
                     way, is_code, CMP, RPN);
3695
}
3696

    
3697
void helper_74xx_tlbd (target_ulong EPN)
3698
{
3699
    do_74xx_tlb(EPN, 0);
3700
}
3701

    
3702
void helper_74xx_tlbi (target_ulong EPN)
3703
{
3704
    do_74xx_tlb(EPN, 1);
3705
}
3706

    
3707
static always_inline target_ulong booke_tlb_to_page_size (int size)
3708
{
3709
    return 1024 << (2 * size);
3710
}
3711

    
3712
static always_inline int booke_page_size_to_tlb (target_ulong page_size)
3713
{
3714
    int size;
3715

    
3716
    switch (page_size) {
3717
    case 0x00000400UL:
3718
        size = 0x0;
3719
        break;
3720
    case 0x00001000UL:
3721
        size = 0x1;
3722
        break;
3723
    case 0x00004000UL:
3724
        size = 0x2;
3725
        break;
3726
    case 0x00010000UL:
3727
        size = 0x3;
3728
        break;
3729
    case 0x00040000UL:
3730
        size = 0x4;
3731
        break;
3732
    case 0x00100000UL:
3733
        size = 0x5;
3734
        break;
3735
    case 0x00400000UL:
3736
        size = 0x6;
3737
        break;
3738
    case 0x01000000UL:
3739
        size = 0x7;
3740
        break;
3741
    case 0x04000000UL:
3742
        size = 0x8;
3743
        break;
3744
    case 0x10000000UL:
3745
        size = 0x9;
3746
        break;
3747
    case 0x40000000UL:
3748
        size = 0xA;
3749
        break;
3750
#if defined (TARGET_PPC64)
3751
    case 0x000100000000ULL:
3752
        size = 0xB;
3753
        break;
3754
    case 0x000400000000ULL:
3755
        size = 0xC;
3756
        break;
3757
    case 0x001000000000ULL:
3758
        size = 0xD;
3759
        break;
3760
    case 0x004000000000ULL:
3761
        size = 0xE;
3762
        break;
3763
    case 0x010000000000ULL:
3764
        size = 0xF;
3765
        break;
3766
#endif
3767
    default:
3768
        size = -1;
3769
        break;
3770
    }
3771

    
3772
    return size;
3773
}
3774

    
3775
/* Helpers for 4xx TLB management */
3776
target_ulong helper_4xx_tlbre_lo (target_ulong entry)
3777
{
3778
    ppcemb_tlb_t *tlb;
3779
    target_ulong ret;
3780
    int size;
3781

    
3782
    entry &= 0x3F;
3783
    tlb = &env->tlb[entry].tlbe;
3784
    ret = tlb->EPN;
3785
    if (tlb->prot & PAGE_VALID)
3786
        ret |= 0x400;
3787
    size = booke_page_size_to_tlb(tlb->size);
3788
    if (size < 0 || size > 0x7)
3789
        size = 1;
3790
    ret |= size << 7;
3791
    env->spr[SPR_40x_PID] = tlb->PID;
3792
    return ret;
3793
}
3794

    
3795
target_ulong helper_4xx_tlbre_hi (target_ulong entry)
3796
{
3797
    ppcemb_tlb_t *tlb;
3798
    target_ulong ret;
3799

    
3800
    entry &= 0x3F;
3801
    tlb = &env->tlb[entry].tlbe;
3802
    ret = tlb->RPN;
3803
    if (tlb->prot & PAGE_EXEC)
3804
        ret |= 0x200;
3805
    if (tlb->prot & PAGE_WRITE)
3806
        ret |= 0x100;
3807
    return ret;
3808
}
3809

    
3810
void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
3811
{
3812
    ppcemb_tlb_t *tlb;
3813
    target_ulong page, end;
3814

    
3815
    LOG_SWTLB("%s entry %d val " ADDRX "\n", __func__, (int)entry, val);
3816
    entry &= 0x3F;
3817
    tlb = &env->tlb[entry].tlbe;
3818
    /* Invalidate previous TLB (if it's valid) */
3819
    if (tlb->prot & PAGE_VALID) {
3820
        end = tlb->EPN + tlb->size;
3821
        LOG_SWTLB("%s: invalidate old TLB %d start " ADDRX
3822
                    " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
3823
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3824
            tlb_flush_page(env, page);
3825
    }
3826
    tlb->size = booke_tlb_to_page_size((val >> 7) & 0x7);
3827
    /* We cannot handle TLB size < TARGET_PAGE_SIZE.
3828
     * If this ever occurs, one should use the ppcemb target instead
3829
     * of the ppc or ppc64 one
3830
     */
3831
    if ((val & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
3832
        cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
3833
                  "are not supported (%d)\n",
3834
                  tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
3835
    }
3836
    tlb->EPN = val & ~(tlb->size - 1);
3837
    if (val & 0x40)
3838
        tlb->prot |= PAGE_VALID;
3839
    else
3840
        tlb->prot &= ~PAGE_VALID;
3841
    if (val & 0x20) {
3842
        /* XXX: TO BE FIXED */
3843
        cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
3844
    }
3845
    tlb->PID = env->spr[SPR_40x_PID]; /* PID */
3846
    tlb->attr = val & 0xFF;
3847
    LOG_SWTLB("%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
3848
                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
3849
                (int)entry, tlb->RPN, tlb->EPN, tlb->size,
3850
                tlb->prot & PAGE_READ ? 'r' : '-',
3851
                tlb->prot & PAGE_WRITE ? 'w' : '-',
3852
                tlb->prot & PAGE_EXEC ? 'x' : '-',
3853
                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
3854
    /* Invalidate new TLB (if valid) */
3855
    if (tlb->prot & PAGE_VALID) {
3856
        end = tlb->EPN + tlb->size;
3857
        LOG_SWTLB("%s: invalidate TLB %d start " ADDRX
3858
                    " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
3859
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3860
            tlb_flush_page(env, page);
3861
    }
3862
}
3863

    
3864
void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
3865
{
3866
    ppcemb_tlb_t *tlb;
3867

    
3868
    LOG_SWTLB("%s entry %i val " ADDRX "\n", __func__, (int)entry, val);
3869
    entry &= 0x3F;
3870
    tlb = &env->tlb[entry].tlbe;
3871
    tlb->RPN = val & 0xFFFFFC00;
3872
    tlb->prot = PAGE_READ;
3873
    if (val & 0x200)
3874
        tlb->prot |= PAGE_EXEC;
3875
    if (val & 0x100)
3876
        tlb->prot |= PAGE_WRITE;
3877
    LOG_SWTLB("%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
3878
                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
3879
                (int)entry, tlb->RPN, tlb->EPN, tlb->size,
3880
                tlb->prot & PAGE_READ ? 'r' : '-',
3881
                tlb->prot & PAGE_WRITE ? 'w' : '-',
3882
                tlb->prot & PAGE_EXEC ? 'x' : '-',
3883
                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
3884
}
3885

    
3886
target_ulong helper_4xx_tlbsx (target_ulong address)
3887
{
3888
    return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
3889
}
3890

    
3891
/* PowerPC 440 TLB management */
3892
void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
3893
{
3894
    ppcemb_tlb_t *tlb;
3895
    target_ulong EPN, RPN, size;
3896
    int do_flush_tlbs;
3897

    
3898
    LOG_SWTLB("%s word %d entry %d value " ADDRX "\n",
3899
                __func__, word, (int)entry, value);
3900
    do_flush_tlbs = 0;
3901
    entry &= 0x3F;
3902
    tlb = &env->tlb[entry].tlbe;
3903
    switch (word) {
3904
    default:
3905
        /* Just here to please gcc */
3906
    case 0:
3907
        EPN = value & 0xFFFFFC00;
3908
        if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
3909
            do_flush_tlbs = 1;
3910
        tlb->EPN = EPN;
3911
        size = booke_tlb_to_page_size((value >> 4) & 0xF);
3912
        if ((tlb->prot & PAGE_VALID) && tlb->size < size)
3913
            do_flush_tlbs = 1;
3914
        tlb->size = size;
3915
        tlb->attr &= ~0x1;
3916
        tlb->attr |= (value >> 8) & 1;
3917
        if (value & 0x200) {
3918
            tlb->prot |= PAGE_VALID;
3919
        } else {
3920
            if (tlb->prot & PAGE_VALID) {
3921
                tlb->prot &= ~PAGE_VALID;
3922
                do_flush_tlbs = 1;
3923
            }
3924
        }
3925
        tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
3926
        if (do_flush_tlbs)
3927
            tlb_flush(env, 1);
3928
        break;
3929
    case 1:
3930
        RPN = value & 0xFFFFFC0F;
3931
        if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
3932
            tlb_flush(env, 1);
3933
        tlb->RPN = RPN;
3934
        break;
3935
    case 2:
3936
        tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
3937
        tlb->prot = tlb->prot & PAGE_VALID;
3938
        if (value & 0x1)
3939
            tlb->prot |= PAGE_READ << 4;
3940
        if (value & 0x2)
3941
            tlb->prot |= PAGE_WRITE << 4;
3942
        if (value & 0x4)
3943
            tlb->prot |= PAGE_EXEC << 4;
3944
        if (value & 0x8)
3945
            tlb->prot |= PAGE_READ;
3946
        if (value & 0x10)
3947
            tlb->prot |= PAGE_WRITE;
3948
        if (value & 0x20)
3949
            tlb->prot |= PAGE_EXEC;
3950
        break;
3951
    }
3952
}
3953

    
3954
target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
3955
{
3956
    ppcemb_tlb_t *tlb;
3957
    target_ulong ret;
3958
    int size;
3959

    
3960
    entry &= 0x3F;
3961
    tlb = &env->tlb[entry].tlbe;
3962
    switch (word) {
3963
    default:
3964
        /* Just here to please gcc */
3965
    case 0:
3966
        ret = tlb->EPN;
3967
        size = booke_page_size_to_tlb(tlb->size);
3968
        if (size < 0 || size > 0xF)
3969
            size = 1;
3970
        ret |= size << 4;
3971
        if (tlb->attr & 0x1)
3972
            ret |= 0x100;
3973
        if (tlb->prot & PAGE_VALID)
3974
            ret |= 0x200;
3975
        env->spr[SPR_440_MMUCR] &= ~0x000000FF;
3976
        env->spr[SPR_440_MMUCR] |= tlb->PID;
3977
        break;
3978
    case 1:
3979
        ret = tlb->RPN;
3980
        break;
3981
    case 2:
3982
        ret = tlb->attr & ~0x1;
3983
        if (tlb->prot & (PAGE_READ << 4))
3984
            ret |= 0x1;
3985
        if (tlb->prot & (PAGE_WRITE << 4))
3986
            ret |= 0x2;
3987
        if (tlb->prot & (PAGE_EXEC << 4))
3988
            ret |= 0x4;
3989
        if (tlb->prot & PAGE_READ)
3990
            ret |= 0x8;
3991
        if (tlb->prot & PAGE_WRITE)
3992
            ret |= 0x10;
3993
        if (tlb->prot & PAGE_EXEC)
3994
            ret |= 0x20;
3995
        break;
3996
    }
3997
    return ret;
3998
}
3999

    
4000
target_ulong helper_440_tlbsx (target_ulong address)
4001
{
4002
    return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
4003
}
4004

    
4005
#endif /* !CONFIG_USER_ONLY */