Statistics
| Branch: | Revision:

root / target-ppc / op_helper.c @ 136be99e

History | View | Annotate | Download (135.8 kB)

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

    
25
#include "helper_regs.h"
26

    
27
#if !defined(CONFIG_USER_ONLY)
28
#include "softmmu_exec.h"
29
#endif /* !defined(CONFIG_USER_ONLY) */
30

    
31
//#define DEBUG_OP
32
//#define DEBUG_EXCEPTIONS
33
//#define DEBUG_SOFTWARE_TLB
34

    
35
#ifdef DEBUG_SOFTWARE_TLB
36
#  define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
37
#else
38
#  define LOG_SWTLB(...) do { } while (0)
39
#endif
40

    
41

    
42
/*****************************************************************************/
43
/* Exceptions processing helpers */
44

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

    
55
void helper_raise_exception (uint32_t exception)
56
{
57
    helper_raise_exception_err(exception, 0);
58
}
59

    
60
/*****************************************************************************/
61
/* SPR accesses */
62
void helper_load_dump_spr (uint32_t sprn)
63
{
64
    qemu_log("Read SPR %d %03x => " TARGET_FMT_lx "\n", sprn, sprn,
65
             env->spr[sprn]);
66
}
67

    
68
void helper_store_dump_spr (uint32_t sprn)
69
{
70
    qemu_log("Write SPR %d %03x <= " TARGET_FMT_lx "\n", sprn, sprn,
71
             env->spr[sprn]);
72
}
73

    
74
target_ulong helper_load_tbl (void)
75
{
76
    return (target_ulong)cpu_ppc_load_tbl(env);
77
}
78

    
79
target_ulong helper_load_tbu (void)
80
{
81
    return cpu_ppc_load_tbu(env);
82
}
83

    
84
target_ulong helper_load_atbl (void)
85
{
86
    return (target_ulong)cpu_ppc_load_atbl(env);
87
}
88

    
89
target_ulong helper_load_atbu (void)
90
{
91
    return cpu_ppc_load_atbu(env);
92
}
93

    
94
#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
95
target_ulong helper_load_purr (void)
96
{
97
    return (target_ulong)cpu_ppc_load_purr(env);
98
}
99
#endif
100

    
101
target_ulong helper_load_601_rtcl (void)
102
{
103
    return cpu_ppc601_load_rtcl(env);
104
}
105

    
106
target_ulong helper_load_601_rtcu (void)
107
{
108
    return cpu_ppc601_load_rtcu(env);
109
}
110

    
111
#if !defined(CONFIG_USER_ONLY)
112
#if defined (TARGET_PPC64)
113
void helper_store_asr (target_ulong val)
114
{
115
    ppc_store_asr(env, val);
116
}
117
#endif
118

    
119
void helper_store_sdr1 (target_ulong val)
120
{
121
    ppc_store_sdr1(env, val);
122
}
123

    
124
void helper_store_tbl (target_ulong val)
125
{
126
    cpu_ppc_store_tbl(env, val);
127
}
128

    
129
void helper_store_tbu (target_ulong val)
130
{
131
    cpu_ppc_store_tbu(env, val);
132
}
133

    
134
void helper_store_atbl (target_ulong val)
135
{
136
    cpu_ppc_store_atbl(env, val);
137
}
138

    
139
void helper_store_atbu (target_ulong val)
140
{
141
    cpu_ppc_store_atbu(env, val);
142
}
143

    
144
void helper_store_601_rtcl (target_ulong val)
145
{
146
    cpu_ppc601_store_rtcl(env, val);
147
}
148

    
149
void helper_store_601_rtcu (target_ulong val)
150
{
151
    cpu_ppc601_store_rtcu(env, val);
152
}
153

    
154
target_ulong helper_load_decr (void)
155
{
156
    return cpu_ppc_load_decr(env);
157
}
158

    
159
void helper_store_decr (target_ulong val)
160
{
161
    cpu_ppc_store_decr(env, val);
162
}
163

    
164
void helper_store_hid0_601 (target_ulong val)
165
{
166
    target_ulong hid0;
167

    
168
    hid0 = env->spr[SPR_HID0];
169
    if ((val ^ hid0) & 0x00000008) {
170
        /* Change current endianness */
171
        env->hflags &= ~(1 << MSR_LE);
172
        env->hflags_nmsr &= ~(1 << MSR_LE);
173
        env->hflags_nmsr |= (1 << MSR_LE) & (((val >> 3) & 1) << MSR_LE);
174
        env->hflags |= env->hflags_nmsr;
175
        qemu_log("%s: set endianness to %c => " TARGET_FMT_lx "\n", __func__,
176
                 val & 0x8 ? 'l' : 'b', env->hflags);
177
    }
178
    env->spr[SPR_HID0] = (uint32_t)val;
179
}
180

    
181
void helper_store_403_pbr (uint32_t num, target_ulong value)
182
{
183
    if (likely(env->pb[num] != value)) {
184
        env->pb[num] = value;
185
        /* Should be optimized */
186
        tlb_flush(env, 1);
187
    }
188
}
189

    
190
target_ulong helper_load_40x_pit (void)
191
{
192
    return load_40x_pit(env);
193
}
194

    
195
void helper_store_40x_pit (target_ulong val)
196
{
197
    store_40x_pit(env, val);
198
}
199

    
200
void helper_store_40x_dbcr0 (target_ulong val)
201
{
202
    store_40x_dbcr0(env, val);
203
}
204

    
205
void helper_store_40x_sler (target_ulong val)
206
{
207
    store_40x_sler(env, val);
208
}
209

    
210
void helper_store_booke_tcr (target_ulong val)
211
{
212
    store_booke_tcr(env, val);
213
}
214

    
215
void helper_store_booke_tsr (target_ulong val)
216
{
217
    store_booke_tsr(env, val);
218
}
219

    
220
void helper_store_ibatu (uint32_t nr, target_ulong val)
221
{
222
    ppc_store_ibatu(env, nr, val);
223
}
224

    
225
void helper_store_ibatl (uint32_t nr, target_ulong val)
226
{
227
    ppc_store_ibatl(env, nr, val);
228
}
229

    
230
void helper_store_dbatu (uint32_t nr, target_ulong val)
231
{
232
    ppc_store_dbatu(env, nr, val);
233
}
234

    
235
void helper_store_dbatl (uint32_t nr, target_ulong val)
236
{
237
    ppc_store_dbatl(env, nr, val);
238
}
239

    
240
void helper_store_601_batl (uint32_t nr, target_ulong val)
241
{
242
    ppc_store_ibatl_601(env, nr, val);
243
}
244

    
245
void helper_store_601_batu (uint32_t nr, target_ulong val)
246
{
247
    ppc_store_ibatu_601(env, nr, val);
248
}
249
#endif
250

    
251
/*****************************************************************************/
252
/* Memory load and stores */
253

    
254
static inline target_ulong addr_add(target_ulong addr, target_long arg)
255
{
256
#if defined(TARGET_PPC64)
257
        if (!msr_sf)
258
            return (uint32_t)(addr + arg);
259
        else
260
#endif
261
            return addr + arg;
262
}
263

    
264
void helper_lmw (target_ulong addr, uint32_t reg)
265
{
266
    for (; reg < 32; reg++) {
267
        if (msr_le)
268
            env->gpr[reg] = bswap32(ldl(addr));
269
        else
270
            env->gpr[reg] = ldl(addr);
271
        addr = addr_add(addr, 4);
272
    }
273
}
274

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

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

    
321
void helper_stsw(target_ulong addr, uint32_t nb, uint32_t reg)
322
{
323
    int sh;
324
    for (; nb > 3; nb -= 4) {
325
        stl(addr, env->gpr[reg]);
326
        reg = (reg + 1) % 32;
327
        addr = addr_add(addr, 4);
328
    }
329
    if (unlikely(nb > 0)) {
330
        for (sh = 24; nb > 0; nb--, sh -= 8) {
331
            stb(addr, (env->gpr[reg] >> sh) & 0xFF);
332
            addr = addr_add(addr, 1);
333
        }
334
    }
335
}
336

    
337
static void do_dcbz(target_ulong addr, int dcache_line_size)
338
{
339
    addr &= ~(dcache_line_size - 1);
340
    int i;
341
    for (i = 0 ; i < dcache_line_size ; i += 4) {
342
        stl(addr + i , 0);
343
    }
344
    if (env->reserve_addr == addr)
345
        env->reserve_addr = (target_ulong)-1ULL;
346
}
347

    
348
void helper_dcbz(target_ulong addr)
349
{
350
    do_dcbz(addr, env->dcache_line_size);
351
}
352

    
353
void helper_dcbz_970(target_ulong addr)
354
{
355
    if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1)
356
        do_dcbz(addr, 32);
357
    else
358
        do_dcbz(addr, env->dcache_line_size);
359
}
360

    
361
void helper_icbi(target_ulong addr)
362
{
363
    addr &= ~(env->dcache_line_size - 1);
364
    /* Invalidate one cache line :
365
     * PowerPC specification says this is to be treated like a load
366
     * (not a fetch) by the MMU. To be sure it will be so,
367
     * do the load "by hand".
368
     */
369
    ldl(addr);
370
}
371

    
372
// XXX: to be tested
373
target_ulong helper_lscbx (target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
374
{
375
    int i, c, d;
376
    d = 24;
377
    for (i = 0; i < xer_bc; i++) {
378
        c = ldub(addr);
379
        addr = addr_add(addr, 1);
380
        /* ra (if not 0) and rb are never modified */
381
        if (likely(reg != rb && (ra == 0 || reg != ra))) {
382
            env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d);
383
        }
384
        if (unlikely(c == xer_cmp))
385
            break;
386
        if (likely(d != 0)) {
387
            d -= 8;
388
        } else {
389
            d = 24;
390
            reg++;
391
            reg = reg & 0x1F;
392
        }
393
    }
394
    return i;
395
}
396

    
397
/*****************************************************************************/
398
/* Fixed point operations helpers */
399
#if defined(TARGET_PPC64)
400

    
401
/* multiply high word */
402
uint64_t helper_mulhd (uint64_t arg1, uint64_t arg2)
403
{
404
    uint64_t tl, th;
405

    
406
    muls64(&tl, &th, arg1, arg2);
407
    return th;
408
}
409

    
410
/* multiply high word unsigned */
411
uint64_t helper_mulhdu (uint64_t arg1, uint64_t arg2)
412
{
413
    uint64_t tl, th;
414

    
415
    mulu64(&tl, &th, arg1, arg2);
416
    return th;
417
}
418

    
419
uint64_t helper_mulldo (uint64_t arg1, uint64_t arg2)
420
{
421
    int64_t th;
422
    uint64_t tl;
423

    
424
    muls64(&tl, (uint64_t *)&th, arg1, arg2);
425
    /* If th != 0 && th != -1, then we had an overflow */
426
    if (likely((uint64_t)(th + 1) <= 1)) {
427
        env->xer &= ~(1 << XER_OV);
428
    } else {
429
        env->xer |= (1 << XER_OV) | (1 << XER_SO);
430
    }
431
    return (int64_t)tl;
432
}
433
#endif
434

    
435
target_ulong helper_cntlzw (target_ulong t)
436
{
437
    return clz32(t);
438
}
439

    
440
#if defined(TARGET_PPC64)
441
target_ulong helper_cntlzd (target_ulong t)
442
{
443
    return clz64(t);
444
}
445
#endif
446

    
447
/* shift right arithmetic helper */
448
target_ulong helper_sraw (target_ulong value, target_ulong shift)
449
{
450
    int32_t ret;
451

    
452
    if (likely(!(shift & 0x20))) {
453
        if (likely((uint32_t)shift != 0)) {
454
            shift &= 0x1f;
455
            ret = (int32_t)value >> shift;
456
            if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
457
                env->xer &= ~(1 << XER_CA);
458
            } else {
459
                env->xer |= (1 << XER_CA);
460
            }
461
        } else {
462
            ret = (int32_t)value;
463
            env->xer &= ~(1 << XER_CA);
464
        }
465
    } else {
466
        ret = (int32_t)value >> 31;
467
        if (ret) {
468
            env->xer |= (1 << XER_CA);
469
        } else {
470
            env->xer &= ~(1 << XER_CA);
471
        }
472
    }
473
    return (target_long)ret;
474
}
475

    
476
#if defined(TARGET_PPC64)
477
target_ulong helper_srad (target_ulong value, target_ulong shift)
478
{
479
    int64_t ret;
480

    
481
    if (likely(!(shift & 0x40))) {
482
        if (likely((uint64_t)shift != 0)) {
483
            shift &= 0x3f;
484
            ret = (int64_t)value >> shift;
485
            if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
486
                env->xer &= ~(1 << XER_CA);
487
            } else {
488
                env->xer |= (1 << XER_CA);
489
            }
490
        } else {
491
            ret = (int64_t)value;
492
            env->xer &= ~(1 << XER_CA);
493
        }
494
    } else {
495
        ret = (int64_t)value >> 63;
496
        if (ret) {
497
            env->xer |= (1 << XER_CA);
498
        } else {
499
            env->xer &= ~(1 << XER_CA);
500
        }
501
    }
502
    return ret;
503
}
504
#endif
505

    
506
#if defined(TARGET_PPC64)
507
target_ulong helper_popcntb (target_ulong val)
508
{
509
    val = (val & 0x5555555555555555ULL) + ((val >>  1) &
510
                                           0x5555555555555555ULL);
511
    val = (val & 0x3333333333333333ULL) + ((val >>  2) &
512
                                           0x3333333333333333ULL);
513
    val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >>  4) &
514
                                           0x0f0f0f0f0f0f0f0fULL);
515
    return val;
516
}
517

    
518
target_ulong helper_popcntw (target_ulong val)
519
{
520
    val = (val & 0x5555555555555555ULL) + ((val >>  1) &
521
                                           0x5555555555555555ULL);
522
    val = (val & 0x3333333333333333ULL) + ((val >>  2) &
523
                                           0x3333333333333333ULL);
524
    val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >>  4) &
525
                                           0x0f0f0f0f0f0f0f0fULL);
526
    val = (val & 0x00ff00ff00ff00ffULL) + ((val >>  8) &
527
                                           0x00ff00ff00ff00ffULL);
528
    val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) &
529
                                           0x0000ffff0000ffffULL);
530
    return val;
531
}
532

    
533
target_ulong helper_popcntd (target_ulong val)
534
{
535
    return ctpop64(val);
536
}
537
#else
538
target_ulong helper_popcntb (target_ulong val)
539
{
540
    val = (val & 0x55555555) + ((val >>  1) & 0x55555555);
541
    val = (val & 0x33333333) + ((val >>  2) & 0x33333333);
542
    val = (val & 0x0f0f0f0f) + ((val >>  4) & 0x0f0f0f0f);
543
    return val;
544
}
545

    
546
target_ulong helper_popcntw (target_ulong val)
547
{
548
    val = (val & 0x55555555) + ((val >>  1) & 0x55555555);
549
    val = (val & 0x33333333) + ((val >>  2) & 0x33333333);
550
    val = (val & 0x0f0f0f0f) + ((val >>  4) & 0x0f0f0f0f);
551
    val = (val & 0x00ff00ff) + ((val >>  8) & 0x00ff00ff);
552
    val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff);
553
    return val;
554
}
555
#endif
556

    
557
/*****************************************************************************/
558
/* Floating point operations helpers */
559
uint64_t helper_float32_to_float64(uint32_t arg)
560
{
561
    CPU_FloatU f;
562
    CPU_DoubleU d;
563
    f.l = arg;
564
    d.d = float32_to_float64(f.f, &env->fp_status);
565
    return d.ll;
566
}
567

    
568
uint32_t helper_float64_to_float32(uint64_t arg)
569
{
570
    CPU_FloatU f;
571
    CPU_DoubleU d;
572
    d.ll = arg;
573
    f.f = float64_to_float32(d.d, &env->fp_status);
574
    return f.l;
575
}
576

    
577
static inline int isden(float64 d)
578
{
579
    CPU_DoubleU u;
580

    
581
    u.d = d;
582

    
583
    return ((u.ll >> 52) & 0x7FF) == 0;
584
}
585

    
586
uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf)
587
{
588
    CPU_DoubleU farg;
589
    int isneg;
590
    int ret;
591
    farg.ll = arg;
592
    isneg = float64_is_neg(farg.d);
593
    if (unlikely(float64_is_any_nan(farg.d))) {
594
        if (float64_is_signaling_nan(farg.d)) {
595
            /* Signaling NaN: flags are undefined */
596
            ret = 0x00;
597
        } else {
598
            /* Quiet NaN */
599
            ret = 0x11;
600
        }
601
    } else if (unlikely(float64_is_infinity(farg.d))) {
602
        /* +/- infinity */
603
        if (isneg)
604
            ret = 0x09;
605
        else
606
            ret = 0x05;
607
    } else {
608
        if (float64_is_zero(farg.d)) {
609
            /* +/- zero */
610
            if (isneg)
611
                ret = 0x12;
612
            else
613
                ret = 0x02;
614
        } else {
615
            if (isden(farg.d)) {
616
                /* Denormalized numbers */
617
                ret = 0x10;
618
            } else {
619
                /* Normalized numbers */
620
                ret = 0x00;
621
            }
622
            if (isneg) {
623
                ret |= 0x08;
624
            } else {
625
                ret |= 0x04;
626
            }
627
        }
628
    }
629
    if (set_fprf) {
630
        /* We update FPSCR_FPRF */
631
        env->fpscr &= ~(0x1F << FPSCR_FPRF);
632
        env->fpscr |= ret << FPSCR_FPRF;
633
    }
634
    /* We just need fpcc to update Rc1 */
635
    return ret & 0xF;
636
}
637

    
638
/* Floating-point invalid operations exception */
639
static inline uint64_t fload_invalid_op_excp(int op)
640
{
641
    uint64_t ret = 0;
642
    int ve;
643

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

    
720
static inline void float_zero_divide_excp(void)
721
{
722
    env->fpscr |= 1 << FPSCR_ZX;
723
    env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
724
    /* Update the floating-point exception summary */
725
    env->fpscr |= 1 << FPSCR_FX;
726
    if (fpscr_ze != 0) {
727
        /* Update the floating-point enabled exception summary */
728
        env->fpscr |= 1 << FPSCR_FEX;
729
        if (msr_fe0 != 0 || msr_fe1 != 0) {
730
            helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
731
                                       POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
732
        }
733
    }
734
}
735

    
736
static inline void float_overflow_excp(void)
737
{
738
    env->fpscr |= 1 << FPSCR_OX;
739
    /* Update the floating-point exception summary */
740
    env->fpscr |= 1 << FPSCR_FX;
741
    if (fpscr_oe != 0) {
742
        /* XXX: should adjust the result */
743
        /* Update the floating-point enabled exception summary */
744
        env->fpscr |= 1 << FPSCR_FEX;
745
        /* We must update the target FPR before raising the exception */
746
        env->exception_index = POWERPC_EXCP_PROGRAM;
747
        env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
748
    } else {
749
        env->fpscr |= 1 << FPSCR_XX;
750
        env->fpscr |= 1 << FPSCR_FI;
751
    }
752
}
753

    
754
static inline void float_underflow_excp(void)
755
{
756
    env->fpscr |= 1 << FPSCR_UX;
757
    /* Update the floating-point exception summary */
758
    env->fpscr |= 1 << FPSCR_FX;
759
    if (fpscr_ue != 0) {
760
        /* XXX: should adjust the result */
761
        /* Update the floating-point enabled exception summary */
762
        env->fpscr |= 1 << FPSCR_FEX;
763
        /* We must update the target FPR before raising the exception */
764
        env->exception_index = POWERPC_EXCP_PROGRAM;
765
        env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
766
    }
767
}
768

    
769
static inline void float_inexact_excp(void)
770
{
771
    env->fpscr |= 1 << FPSCR_XX;
772
    /* Update the floating-point exception summary */
773
    env->fpscr |= 1 << FPSCR_FX;
774
    if (fpscr_xe != 0) {
775
        /* Update the floating-point enabled exception summary */
776
        env->fpscr |= 1 << FPSCR_FEX;
777
        /* We must update the target FPR before raising the exception */
778
        env->exception_index = POWERPC_EXCP_PROGRAM;
779
        env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
780
    }
781
}
782

    
783
static inline void fpscr_set_rounding_mode(void)
784
{
785
    int rnd_type;
786

    
787
    /* Set rounding mode */
788
    switch (fpscr_rn) {
789
    case 0:
790
        /* Best approximation (round to nearest) */
791
        rnd_type = float_round_nearest_even;
792
        break;
793
    case 1:
794
        /* Smaller magnitude (round toward zero) */
795
        rnd_type = float_round_to_zero;
796
        break;
797
    case 2:
798
        /* Round toward +infinite */
799
        rnd_type = float_round_up;
800
        break;
801
    default:
802
    case 3:
803
        /* Round toward -infinite */
804
        rnd_type = float_round_down;
805
        break;
806
    }
807
    set_float_rounding_mode(rnd_type, &env->fp_status);
808
}
809

    
810
void helper_fpscr_clrbit (uint32_t bit)
811
{
812
    int prev;
813

    
814
    prev = (env->fpscr >> bit) & 1;
815
    env->fpscr &= ~(1 << bit);
816
    if (prev == 1) {
817
        switch (bit) {
818
        case FPSCR_RN1:
819
        case FPSCR_RN:
820
            fpscr_set_rounding_mode();
821
            break;
822
        default:
823
            break;
824
        }
825
    }
826
}
827

    
828
void helper_fpscr_setbit (uint32_t bit)
829
{
830
    int prev;
831

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

    
943
void helper_store_fpscr (uint64_t arg, uint32_t mask)
944
{
945
    /*
946
     * We use only the 32 LSB of the incoming fpr
947
     */
948
    uint32_t prev, new;
949
    int i;
950

    
951
    prev = env->fpscr;
952
    new = (uint32_t)arg;
953
    new &= ~0x60000000;
954
    new |= prev & 0x60000000;
955
    for (i = 0; i < 8; i++) {
956
        if (mask & (1 << i)) {
957
            env->fpscr &= ~(0xF << (4 * i));
958
            env->fpscr |= new & (0xF << (4 * i));
959
        }
960
    }
961
    /* Update VX and FEX */
962
    if (fpscr_ix != 0)
963
        env->fpscr |= 1 << FPSCR_VX;
964
    else
965
        env->fpscr &= ~(1 << FPSCR_VX);
966
    if ((fpscr_ex & fpscr_eex) != 0) {
967
        env->fpscr |= 1 << FPSCR_FEX;
968
        env->exception_index = POWERPC_EXCP_PROGRAM;
969
        /* XXX: we should compute it properly */
970
        env->error_code = POWERPC_EXCP_FP;
971
    }
972
    else
973
        env->fpscr &= ~(1 << FPSCR_FEX);
974
    fpscr_set_rounding_mode();
975
}
976

    
977
void helper_float_check_status (void)
978
{
979
    if (env->exception_index == POWERPC_EXCP_PROGRAM &&
980
        (env->error_code & POWERPC_EXCP_FP)) {
981
        /* Differred floating-point exception after target FPR update */
982
        if (msr_fe0 != 0 || msr_fe1 != 0)
983
            helper_raise_exception_err(env->exception_index, env->error_code);
984
    } else {
985
        int status = get_float_exception_flags(&env->fp_status);
986
        if (status & float_flag_divbyzero) {
987
            float_zero_divide_excp();
988
        } else if (status & float_flag_overflow) {
989
            float_overflow_excp();
990
        } else if (status & float_flag_underflow) {
991
            float_underflow_excp();
992
        } else if (status & float_flag_inexact) {
993
            float_inexact_excp();
994
        }
995
    }
996
}
997

    
998
void helper_reset_fpstatus (void)
999
{
1000
    set_float_exception_flags(0, &env->fp_status);
1001
}
1002

    
1003
/* fadd - fadd. */
1004
uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
1005
{
1006
    CPU_DoubleU farg1, farg2;
1007

    
1008
    farg1.ll = arg1;
1009
    farg2.ll = arg2;
1010

    
1011
    if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
1012
                 float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
1013
        /* Magnitude subtraction of infinities */
1014
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1015
    } else {
1016
        if (unlikely(float64_is_signaling_nan(farg1.d) ||
1017
                     float64_is_signaling_nan(farg2.d))) {
1018
            /* sNaN addition */
1019
            fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1020
        }
1021
        farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
1022
    }
1023

    
1024
    return farg1.ll;
1025
}
1026

    
1027
/* fsub - fsub. */
1028
uint64_t helper_fsub (uint64_t arg1, uint64_t arg2)
1029
{
1030
    CPU_DoubleU farg1, farg2;
1031

    
1032
    farg1.ll = arg1;
1033
    farg2.ll = arg2;
1034

    
1035
    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
        if (unlikely(float64_is_signaling_nan(farg1.d) ||
1041
                     float64_is_signaling_nan(farg2.d))) {
1042
            /* sNaN subtraction */
1043
            fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1044
        }
1045
        farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
1046
    }
1047

    
1048
    return farg1.ll;
1049
}
1050

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

    
1056
    farg1.ll = arg1;
1057
    farg2.ll = arg2;
1058

    
1059
    if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1060
                 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1061
        /* Multiplication of zero by infinity */
1062
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1063
    } else {
1064
        if (unlikely(float64_is_signaling_nan(farg1.d) ||
1065
                     float64_is_signaling_nan(farg2.d))) {
1066
            /* sNaN multiplication */
1067
            fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1068
        }
1069
        farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1070
    }
1071

    
1072
    return farg1.ll;
1073
}
1074

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

    
1080
    farg1.ll = arg1;
1081
    farg2.ll = arg2;
1082

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

    
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_quiet_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
        /* XXX: higher bits are not supposed to be significant.
1147
         *     to make tests easier, return the same as a real PowerPC 750
1148
         */
1149
        farg.ll |= 0xFFF80000ULL << 32;
1150
    }
1151
    return farg.ll;
1152
}
1153

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

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

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

    
1185
/* fctid - fctid. */
1186
uint64_t helper_fctid (uint64_t arg)
1187
{
1188
    CPU_DoubleU farg;
1189
    farg.ll = arg;
1190

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

    
1203
/* fctidz - fctidz. */
1204
uint64_t helper_fctidz (uint64_t arg)
1205
{
1206
    CPU_DoubleU farg;
1207
    farg.ll = arg;
1208

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

    
1221
#endif
1222

    
1223
static inline uint64_t do_fri(uint64_t arg, int rounding_mode)
1224
{
1225
    CPU_DoubleU farg;
1226
    farg.ll = arg;
1227

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

    
1243
uint64_t helper_frin (uint64_t arg)
1244
{
1245
    return do_fri(arg, float_round_nearest_even);
1246
}
1247

    
1248
uint64_t helper_friz (uint64_t arg)
1249
{
1250
    return do_fri(arg, float_round_to_zero);
1251
}
1252

    
1253
uint64_t helper_frip (uint64_t arg)
1254
{
1255
    return do_fri(arg, float_round_up);
1256
}
1257

    
1258
uint64_t helper_frim (uint64_t arg)
1259
{
1260
    return do_fri(arg, float_round_down);
1261
}
1262

    
1263
/* fmadd - fmadd. */
1264
uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1265
{
1266
    CPU_DoubleU farg1, farg2, farg3;
1267

    
1268
    farg1.ll = arg1;
1269
    farg2.ll = arg2;
1270
    farg3.ll = arg3;
1271

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

    
1286
        ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1287
        ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1288
        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1289
        if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1290
                     float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1291
            /* Magnitude subtraction of infinities */
1292
            farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1293
        } else {
1294
            ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1295
            ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1296
            farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1297
        }
1298
    }
1299

    
1300
    return farg1.ll;
1301
}
1302

    
1303
/* fmsub - fmsub. */
1304
uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1305
{
1306
    CPU_DoubleU farg1, farg2, farg3;
1307

    
1308
    farg1.ll = arg1;
1309
    farg2.ll = arg2;
1310
    farg3.ll = arg3;
1311

    
1312
    if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1313
                        (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1314
        /* Multiplication of zero by infinity */
1315
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1316
    } else {
1317
        if (unlikely(float64_is_signaling_nan(farg1.d) ||
1318
                     float64_is_signaling_nan(farg2.d) ||
1319
                     float64_is_signaling_nan(farg3.d))) {
1320
            /* sNaN operation */
1321
            fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1322
        }
1323
        /* This is the way the PowerPC specification defines it */
1324
        float128 ft0_128, ft1_128;
1325

    
1326
        ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1327
        ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1328
        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1329
        if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1330
                     float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1331
            /* Magnitude subtraction of infinities */
1332
            farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1333
        } else {
1334
            ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1335
            ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1336
            farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1337
        }
1338
    }
1339
    return farg1.ll;
1340
}
1341

    
1342
/* fnmadd - fnmadd. */
1343
uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1344
{
1345
    CPU_DoubleU farg1, farg2, farg3;
1346

    
1347
    farg1.ll = arg1;
1348
    farg2.ll = arg2;
1349
    farg3.ll = arg3;
1350

    
1351
    if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1352
                 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1353
        /* Multiplication of zero by infinity */
1354
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1355
    } else {
1356
        if (unlikely(float64_is_signaling_nan(farg1.d) ||
1357
                     float64_is_signaling_nan(farg2.d) ||
1358
                     float64_is_signaling_nan(farg3.d))) {
1359
            /* sNaN operation */
1360
            fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1361
        }
1362
        /* This is the way the PowerPC specification defines it */
1363
        float128 ft0_128, ft1_128;
1364

    
1365
        ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1366
        ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1367
        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1368
        if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1369
                     float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1370
            /* Magnitude subtraction of infinities */
1371
            farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1372
        } else {
1373
            ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1374
            ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1375
            farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1376
        }
1377
        if (likely(!float64_is_any_nan(farg1.d))) {
1378
            farg1.d = float64_chs(farg1.d);
1379
        }
1380
    }
1381
    return farg1.ll;
1382
}
1383

    
1384
/* fnmsub - fnmsub. */
1385
uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1386
{
1387
    CPU_DoubleU farg1, farg2, farg3;
1388

    
1389
    farg1.ll = arg1;
1390
    farg2.ll = arg2;
1391
    farg3.ll = arg3;
1392

    
1393
    if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1394
                        (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1395
        /* Multiplication of zero by infinity */
1396
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1397
    } else {
1398
        if (unlikely(float64_is_signaling_nan(farg1.d) ||
1399
                     float64_is_signaling_nan(farg2.d) ||
1400
                     float64_is_signaling_nan(farg3.d))) {
1401
            /* sNaN operation */
1402
            fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1403
        }
1404
        /* This is the way the PowerPC specification defines it */
1405
        float128 ft0_128, ft1_128;
1406

    
1407
        ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1408
        ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1409
        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1410
        if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1411
                     float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1412
            /* Magnitude subtraction of infinities */
1413
            farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1414
        } else {
1415
            ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1416
            ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1417
            farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1418
        }
1419
        if (likely(!float64_is_any_nan(farg1.d))) {
1420
            farg1.d = float64_chs(farg1.d);
1421
        }
1422
    }
1423
    return farg1.ll;
1424
}
1425

    
1426
/* frsp - frsp. */
1427
uint64_t helper_frsp (uint64_t arg)
1428
{
1429
    CPU_DoubleU farg;
1430
    float32 f32;
1431
    farg.ll = arg;
1432

    
1433
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1434
        /* sNaN square root */
1435
       fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1436
    }
1437
    f32 = float64_to_float32(farg.d, &env->fp_status);
1438
    farg.d = float32_to_float64(f32, &env->fp_status);
1439

    
1440
    return farg.ll;
1441
}
1442

    
1443
/* fsqrt - fsqrt. */
1444
uint64_t helper_fsqrt (uint64_t arg)
1445
{
1446
    CPU_DoubleU farg;
1447
    farg.ll = arg;
1448

    
1449
    if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
1450
        /* Square root of a negative nonzero number */
1451
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
1452
    } else {
1453
        if (unlikely(float64_is_signaling_nan(farg.d))) {
1454
            /* sNaN square root */
1455
            fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1456
        }
1457
        farg.d = float64_sqrt(farg.d, &env->fp_status);
1458
    }
1459
    return farg.ll;
1460
}
1461

    
1462
/* fre - fre. */
1463
uint64_t helper_fre (uint64_t arg)
1464
{
1465
    CPU_DoubleU farg;
1466
    farg.ll = arg;
1467

    
1468
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1469
        /* sNaN reciprocal */
1470
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1471
    }
1472
    farg.d = float64_div(float64_one, farg.d, &env->fp_status);
1473
    return farg.d;
1474
}
1475

    
1476
/* fres - fres. */
1477
uint64_t helper_fres (uint64_t arg)
1478
{
1479
    CPU_DoubleU farg;
1480
    float32 f32;
1481
    farg.ll = arg;
1482

    
1483
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1484
        /* sNaN reciprocal */
1485
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1486
    }
1487
    farg.d = float64_div(float64_one, farg.d, &env->fp_status);
1488
    f32 = float64_to_float32(farg.d, &env->fp_status);
1489
    farg.d = float32_to_float64(f32, &env->fp_status);
1490

    
1491
    return farg.ll;
1492
}
1493

    
1494
/* frsqrte  - frsqrte. */
1495
uint64_t helper_frsqrte (uint64_t arg)
1496
{
1497
    CPU_DoubleU farg;
1498
    float32 f32;
1499
    farg.ll = arg;
1500

    
1501
    if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
1502
        /* Reciprocal square root of a negative nonzero number */
1503
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
1504
    } else {
1505
        if (unlikely(float64_is_signaling_nan(farg.d))) {
1506
            /* sNaN reciprocal square root */
1507
            fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1508
        }
1509
        farg.d = float64_sqrt(farg.d, &env->fp_status);
1510
        farg.d = float64_div(float64_one, farg.d, &env->fp_status);
1511
        f32 = float64_to_float32(farg.d, &env->fp_status);
1512
        farg.d = float32_to_float64(f32, &env->fp_status);
1513
    }
1514
    return farg.ll;
1515
}
1516

    
1517
/* fsel - fsel. */
1518
uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1519
{
1520
    CPU_DoubleU farg1;
1521

    
1522
    farg1.ll = arg1;
1523

    
1524
    if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_any_nan(farg1.d)) {
1525
        return arg2;
1526
    } else {
1527
        return arg3;
1528
    }
1529
}
1530

    
1531
void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD)
1532
{
1533
    CPU_DoubleU farg1, farg2;
1534
    uint32_t ret = 0;
1535
    farg1.ll = arg1;
1536
    farg2.ll = arg2;
1537

    
1538
    if (unlikely(float64_is_any_nan(farg1.d) ||
1539
                 float64_is_any_nan(farg2.d))) {
1540
        ret = 0x01UL;
1541
    } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1542
        ret = 0x08UL;
1543
    } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1544
        ret = 0x04UL;
1545
    } else {
1546
        ret = 0x02UL;
1547
    }
1548

    
1549
    env->fpscr &= ~(0x0F << FPSCR_FPRF);
1550
    env->fpscr |= ret << FPSCR_FPRF;
1551
    env->crf[crfD] = ret;
1552
    if (unlikely(ret == 0x01UL
1553
                 && (float64_is_signaling_nan(farg1.d) ||
1554
                     float64_is_signaling_nan(farg2.d)))) {
1555
        /* sNaN comparison */
1556
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1557
    }
1558
}
1559

    
1560
void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD)
1561
{
1562
    CPU_DoubleU farg1, farg2;
1563
    uint32_t ret = 0;
1564
    farg1.ll = arg1;
1565
    farg2.ll = arg2;
1566

    
1567
    if (unlikely(float64_is_any_nan(farg1.d) ||
1568
                 float64_is_any_nan(farg2.d))) {
1569
        ret = 0x01UL;
1570
    } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1571
        ret = 0x08UL;
1572
    } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1573
        ret = 0x04UL;
1574
    } else {
1575
        ret = 0x02UL;
1576
    }
1577

    
1578
    env->fpscr &= ~(0x0F << FPSCR_FPRF);
1579
    env->fpscr |= ret << FPSCR_FPRF;
1580
    env->crf[crfD] = ret;
1581
    if (unlikely (ret == 0x01UL)) {
1582
        if (float64_is_signaling_nan(farg1.d) ||
1583
            float64_is_signaling_nan(farg2.d)) {
1584
            /* sNaN comparison */
1585
            fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
1586
                                  POWERPC_EXCP_FP_VXVC);
1587
        } else {
1588
            /* qNaN comparison */
1589
            fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
1590
        }
1591
    }
1592
}
1593

    
1594
#if !defined (CONFIG_USER_ONLY)
1595
void helper_store_msr (target_ulong val)
1596
{
1597
    val = hreg_store_msr(env, val, 0);
1598
    if (val != 0) {
1599
        env->interrupt_request |= CPU_INTERRUPT_EXITTB;
1600
        helper_raise_exception(val);
1601
    }
1602
}
1603

    
1604
static inline void do_rfi(target_ulong nip, target_ulong msr,
1605
                          target_ulong msrm, int keep_msrh)
1606
{
1607
#if defined(TARGET_PPC64)
1608
    if (msr & (1ULL << MSR_SF)) {
1609
        nip = (uint64_t)nip;
1610
        msr &= (uint64_t)msrm;
1611
    } else {
1612
        nip = (uint32_t)nip;
1613
        msr = (uint32_t)(msr & msrm);
1614
        if (keep_msrh)
1615
            msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
1616
    }
1617
#else
1618
    nip = (uint32_t)nip;
1619
    msr &= (uint32_t)msrm;
1620
#endif
1621
    /* XXX: beware: this is false if VLE is supported */
1622
    env->nip = nip & ~((target_ulong)0x00000003);
1623
    hreg_store_msr(env, msr, 1);
1624
#if defined (DEBUG_OP)
1625
    cpu_dump_rfi(env->nip, env->msr);
1626
#endif
1627
    /* No need to raise an exception here,
1628
     * as rfi is always the last insn of a TB
1629
     */
1630
    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
1631
}
1632

    
1633
void helper_rfi (void)
1634
{
1635
    do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1636
           ~((target_ulong)0x783F0000), 1);
1637
}
1638

    
1639
#if defined(TARGET_PPC64)
1640
void helper_rfid (void)
1641
{
1642
    do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1643
           ~((target_ulong)0x783F0000), 0);
1644
}
1645

    
1646
void helper_hrfid (void)
1647
{
1648
    do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
1649
           ~((target_ulong)0x783F0000), 0);
1650
}
1651
#endif
1652
#endif
1653

    
1654
void helper_tw (target_ulong arg1, target_ulong arg2, uint32_t flags)
1655
{
1656
    if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
1657
                  ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
1658
                  ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
1659
                  ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
1660
                  ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
1661
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
1662
    }
1663
}
1664

    
1665
#if defined(TARGET_PPC64)
1666
void helper_td (target_ulong arg1, target_ulong arg2, uint32_t flags)
1667
{
1668
    if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
1669
                  ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
1670
                  ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
1671
                  ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
1672
                  ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01)))))
1673
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
1674
}
1675
#endif
1676

    
1677
/*****************************************************************************/
1678
/* PowerPC 601 specific instructions (POWER bridge) */
1679

    
1680
target_ulong helper_clcs (uint32_t arg)
1681
{
1682
    switch (arg) {
1683
    case 0x0CUL:
1684
        /* Instruction cache line size */
1685
        return env->icache_line_size;
1686
        break;
1687
    case 0x0DUL:
1688
        /* Data cache line size */
1689
        return env->dcache_line_size;
1690
        break;
1691
    case 0x0EUL:
1692
        /* Minimum cache line size */
1693
        return (env->icache_line_size < env->dcache_line_size) ?
1694
                env->icache_line_size : env->dcache_line_size;
1695
        break;
1696
    case 0x0FUL:
1697
        /* Maximum cache line size */
1698
        return (env->icache_line_size > env->dcache_line_size) ?
1699
                env->icache_line_size : env->dcache_line_size;
1700
        break;
1701
    default:
1702
        /* Undefined */
1703
        return 0;
1704
        break;
1705
    }
1706
}
1707

    
1708
target_ulong helper_div (target_ulong arg1, target_ulong arg2)
1709
{
1710
    uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
1711

    
1712
    if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1713
        (int32_t)arg2 == 0) {
1714
        env->spr[SPR_MQ] = 0;
1715
        return INT32_MIN;
1716
    } else {
1717
        env->spr[SPR_MQ] = tmp % arg2;
1718
        return  tmp / (int32_t)arg2;
1719
    }
1720
}
1721

    
1722
target_ulong helper_divo (target_ulong arg1, target_ulong arg2)
1723
{
1724
    uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
1725

    
1726
    if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1727
        (int32_t)arg2 == 0) {
1728
        env->xer |= (1 << XER_OV) | (1 << XER_SO);
1729
        env->spr[SPR_MQ] = 0;
1730
        return INT32_MIN;
1731
    } else {
1732
        env->spr[SPR_MQ] = tmp % arg2;
1733
        tmp /= (int32_t)arg2;
1734
        if ((int32_t)tmp != tmp) {
1735
            env->xer |= (1 << XER_OV) | (1 << XER_SO);
1736
        } else {
1737
            env->xer &= ~(1 << XER_OV);
1738
        }
1739
        return tmp;
1740
    }
1741
}
1742

    
1743
target_ulong helper_divs (target_ulong arg1, target_ulong arg2)
1744
{
1745
    if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1746
        (int32_t)arg2 == 0) {
1747
        env->spr[SPR_MQ] = 0;
1748
        return INT32_MIN;
1749
    } else {
1750
        env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1751
        return (int32_t)arg1 / (int32_t)arg2;
1752
    }
1753
}
1754

    
1755
target_ulong helper_divso (target_ulong arg1, target_ulong arg2)
1756
{
1757
    if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1758
        (int32_t)arg2 == 0) {
1759
        env->xer |= (1 << XER_OV) | (1 << XER_SO);
1760
        env->spr[SPR_MQ] = 0;
1761
        return INT32_MIN;
1762
    } else {
1763
        env->xer &= ~(1 << XER_OV);
1764
        env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1765
        return (int32_t)arg1 / (int32_t)arg2;
1766
    }
1767
}
1768

    
1769
#if !defined (CONFIG_USER_ONLY)
1770
target_ulong helper_rac (target_ulong addr)
1771
{
1772
    mmu_ctx_t ctx;
1773
    int nb_BATs;
1774
    target_ulong ret = 0;
1775

    
1776
    /* We don't have to generate many instances of this instruction,
1777
     * as rac is supervisor only.
1778
     */
1779
    /* XXX: FIX THIS: Pretend we have no BAT */
1780
    nb_BATs = env->nb_BATs;
1781
    env->nb_BATs = 0;
1782
    if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0)
1783
        ret = ctx.raddr;
1784
    env->nb_BATs = nb_BATs;
1785
    return ret;
1786
}
1787

    
1788
void helper_rfsvc (void)
1789
{
1790
    do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
1791
}
1792
#endif
1793

    
1794
/*****************************************************************************/
1795
/* 602 specific instructions */
1796
/* mfrom is the most crazy instruction ever seen, imho ! */
1797
/* Real implementation uses a ROM table. Do the same */
1798
/* Extremely decomposed:
1799
 *                      -arg / 256
1800
 * return 256 * log10(10           + 1.0) + 0.5
1801
 */
1802
#if !defined (CONFIG_USER_ONLY)
1803
target_ulong helper_602_mfrom (target_ulong arg)
1804
{
1805
    if (likely(arg < 602)) {
1806
#include "mfrom_table.c"
1807
        return mfrom_ROM_table[arg];
1808
    } else {
1809
        return 0;
1810
    }
1811
}
1812
#endif
1813

    
1814
/*****************************************************************************/
1815
/* Embedded PowerPC specific helpers */
1816

    
1817
/* XXX: to be improved to check access rights when in user-mode */
1818
target_ulong helper_load_dcr (target_ulong dcrn)
1819
{
1820
    uint32_t val = 0;
1821

    
1822
    if (unlikely(env->dcr_env == NULL)) {
1823
        qemu_log("No DCR environment\n");
1824
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1825
                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
1826
    } else if (unlikely(ppc_dcr_read(env->dcr_env, (uint32_t)dcrn, &val) != 0)) {
1827
        qemu_log("DCR read error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
1828
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1829
                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1830
    }
1831
    return val;
1832
}
1833

    
1834
void helper_store_dcr (target_ulong dcrn, target_ulong val)
1835
{
1836
    if (unlikely(env->dcr_env == NULL)) {
1837
        qemu_log("No DCR environment\n");
1838
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1839
                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
1840
    } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn, (uint32_t)val) != 0)) {
1841
        qemu_log("DCR write error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
1842
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1843
                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1844
    }
1845
}
1846

    
1847
#if !defined(CONFIG_USER_ONLY)
1848
void helper_40x_rfci (void)
1849
{
1850
    do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
1851
           ~((target_ulong)0xFFFF0000), 0);
1852
}
1853

    
1854
void helper_rfci (void)
1855
{
1856
    do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
1857
           ~((target_ulong)0x3FFF0000), 0);
1858
}
1859

    
1860
void helper_rfdi (void)
1861
{
1862
    do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
1863
           ~((target_ulong)0x3FFF0000), 0);
1864
}
1865

    
1866
void helper_rfmci (void)
1867
{
1868
    do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
1869
           ~((target_ulong)0x3FFF0000), 0);
1870
}
1871
#endif
1872

    
1873
/* 440 specific */
1874
target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_Rc)
1875
{
1876
    target_ulong mask;
1877
    int i;
1878

    
1879
    i = 1;
1880
    for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1881
        if ((high & mask) == 0) {
1882
            if (update_Rc) {
1883
                env->crf[0] = 0x4;
1884
            }
1885
            goto done;
1886
        }
1887
        i++;
1888
    }
1889
    for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1890
        if ((low & mask) == 0) {
1891
            if (update_Rc) {
1892
                env->crf[0] = 0x8;
1893
            }
1894
            goto done;
1895
        }
1896
        i++;
1897
    }
1898
    if (update_Rc) {
1899
        env->crf[0] = 0x2;
1900
    }
1901
 done:
1902
    env->xer = (env->xer & ~0x7F) | i;
1903
    if (update_Rc) {
1904
        env->crf[0] |= xer_so;
1905
    }
1906
    return i;
1907
}
1908

    
1909
/*****************************************************************************/
1910
/* Altivec extension helpers */
1911
#if defined(HOST_WORDS_BIGENDIAN)
1912
#define HI_IDX 0
1913
#define LO_IDX 1
1914
#else
1915
#define HI_IDX 1
1916
#define LO_IDX 0
1917
#endif
1918

    
1919
#if defined(HOST_WORDS_BIGENDIAN)
1920
#define VECTOR_FOR_INORDER_I(index, element)            \
1921
    for (index = 0; index < ARRAY_SIZE(r->element); index++)
1922
#else
1923
#define VECTOR_FOR_INORDER_I(index, element)            \
1924
  for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
1925
#endif
1926

    
1927
/* If X is a NaN, store the corresponding QNaN into RESULT.  Otherwise,
1928
 * execute the following block.  */
1929
#define DO_HANDLE_NAN(result, x)                \
1930
    if (float32_is_any_nan(x)) {                                \
1931
        CPU_FloatU __f;                                         \
1932
        __f.f = x;                                              \
1933
        __f.l = __f.l | (1 << 22);  /* Set QNaN bit. */         \
1934
        result = __f.f;                                         \
1935
    } else
1936

    
1937
#define HANDLE_NAN1(result, x)                  \
1938
    DO_HANDLE_NAN(result, x)
1939
#define HANDLE_NAN2(result, x, y)               \
1940
    DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y)
1941
#define HANDLE_NAN3(result, x, y, z)            \
1942
    DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) DO_HANDLE_NAN(result, z)
1943

    
1944
/* Saturating arithmetic helpers.  */
1945
#define SATCVT(from, to, from_type, to_type, min, max)                  \
1946
    static inline to_type cvt##from##to(from_type x, int *sat)          \
1947
    {                                                                   \
1948
        to_type r;                                                      \
1949
        if (x < (from_type)min) {                                       \
1950
            r = min;                                                    \
1951
            *sat = 1;                                                   \
1952
        } else if (x > (from_type)max) {                                \
1953
            r = max;                                                    \
1954
            *sat = 1;                                                   \
1955
        } else {                                                        \
1956
            r = x;                                                      \
1957
        }                                                               \
1958
        return r;                                                       \
1959
    }
1960
#define SATCVTU(from, to, from_type, to_type, min, max)                 \
1961
    static inline to_type cvt##from##to(from_type x, int *sat)          \
1962
    {                                                                   \
1963
        to_type r;                                                      \
1964
        if (x > (from_type)max) {                                       \
1965
            r = max;                                                    \
1966
            *sat = 1;                                                   \
1967
        } else {                                                        \
1968
            r = x;                                                      \
1969
        }                                                               \
1970
        return r;                                                       \
1971
    }
1972
SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX)
1973
SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX)
1974
SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX)
1975

    
1976
SATCVTU(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX)
1977
SATCVTU(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX)
1978
SATCVTU(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX)
1979
SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX)
1980
SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX)
1981
SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX)
1982
#undef SATCVT
1983
#undef SATCVTU
1984

    
1985
#define LVE(name, access, swap, element)                        \
1986
    void helper_##name (ppc_avr_t *r, target_ulong addr)        \
1987
    {                                                           \
1988
        size_t n_elems = ARRAY_SIZE(r->element);                \
1989
        int adjust = HI_IDX*(n_elems-1);                        \
1990
        int sh = sizeof(r->element[0]) >> 1;                    \
1991
        int index = (addr & 0xf) >> sh;                         \
1992
        if(msr_le) {                                            \
1993
            r->element[LO_IDX ? index : (adjust - index)] = swap(access(addr)); \
1994
        } else {                                                        \
1995
            r->element[LO_IDX ? index : (adjust - index)] = access(addr); \
1996
        }                                                               \
1997
    }
1998
#define I(x) (x)
1999
LVE(lvebx, ldub, I, u8)
2000
LVE(lvehx, lduw, bswap16, u16)
2001
LVE(lvewx, ldl, bswap32, u32)
2002
#undef I
2003
#undef LVE
2004

    
2005
void helper_lvsl (ppc_avr_t *r, target_ulong sh)
2006
{
2007
    int i, j = (sh & 0xf);
2008

    
2009
    VECTOR_FOR_INORDER_I (i, u8) {
2010
        r->u8[i] = j++;
2011
    }
2012
}
2013

    
2014
void helper_lvsr (ppc_avr_t *r, target_ulong sh)
2015
{
2016
    int i, j = 0x10 - (sh & 0xf);
2017

    
2018
    VECTOR_FOR_INORDER_I (i, u8) {
2019
        r->u8[i] = j++;
2020
    }
2021
}
2022

    
2023
#define STVE(name, access, swap, element)                       \
2024
    void helper_##name (ppc_avr_t *r, target_ulong addr)        \
2025
    {                                                           \
2026
        size_t n_elems = ARRAY_SIZE(r->element);                \
2027
        int adjust = HI_IDX*(n_elems-1);                        \
2028
        int sh = sizeof(r->element[0]) >> 1;                    \
2029
        int index = (addr & 0xf) >> sh;                         \
2030
        if(msr_le) {                                            \
2031
            access(addr, swap(r->element[LO_IDX ? index : (adjust - index)])); \
2032
        } else {                                                        \
2033
            access(addr, r->element[LO_IDX ? index : (adjust - index)]); \
2034
        }                                                               \
2035
    }
2036
#define I(x) (x)
2037
STVE(stvebx, stb, I, u8)
2038
STVE(stvehx, stw, bswap16, u16)
2039
STVE(stvewx, stl, bswap32, u32)
2040
#undef I
2041
#undef LVE
2042

    
2043
void helper_mtvscr (ppc_avr_t *r)
2044
{
2045
#if defined(HOST_WORDS_BIGENDIAN)
2046
    env->vscr = r->u32[3];
2047
#else
2048
    env->vscr = r->u32[0];
2049
#endif
2050
    set_flush_to_zero(vscr_nj, &env->vec_status);
2051
}
2052

    
2053
void helper_vaddcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2054
{
2055
    int i;
2056
    for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2057
        r->u32[i] = ~a->u32[i] < b->u32[i];
2058
    }
2059
}
2060

    
2061
#define VARITH_DO(name, op, element)        \
2062
void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)          \
2063
{                                                                       \
2064
    int i;                                                              \
2065
    for (i = 0; i < ARRAY_SIZE(r->element); i++) {                      \
2066
        r->element[i] = a->element[i] op b->element[i];                 \
2067
    }                                                                   \
2068
}
2069
#define VARITH(suffix, element)                  \
2070
  VARITH_DO(add##suffix, +, element)             \
2071
  VARITH_DO(sub##suffix, -, element)
2072
VARITH(ubm, u8)
2073
VARITH(uhm, u16)
2074
VARITH(uwm, u32)
2075
#undef VARITH_DO
2076
#undef VARITH
2077

    
2078
#define VARITHFP(suffix, func)                                          \
2079
    void helper_v##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)    \
2080
    {                                                                   \
2081
        int i;                                                          \
2082
        for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
2083
            HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) {                    \
2084
                r->f[i] = func(a->f[i], b->f[i], &env->vec_status);     \
2085
            }                                                           \
2086
        }                                                               \
2087
    }
2088
VARITHFP(addfp, float32_add)
2089
VARITHFP(subfp, float32_sub)
2090
#undef VARITHFP
2091

    
2092
#define VARITHSAT_CASE(type, op, cvt, element)                          \
2093
    {                                                                   \
2094
        type result = (type)a->element[i] op (type)b->element[i];       \
2095
        r->element[i] = cvt(result, &sat);                              \
2096
    }
2097

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

    
2131
#define VAVG_DO(name, element, etype)                                   \
2132
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
2133
    {                                                                   \
2134
        int i;                                                          \
2135
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2136
            etype x = (etype)a->element[i] + (etype)b->element[i] + 1;  \
2137
            r->element[i] = x >> 1;                                     \
2138
        }                                                               \
2139
    }
2140

    
2141
#define VAVG(type, signed_element, signed_type, unsigned_element, unsigned_type) \
2142
    VAVG_DO(avgs##type, signed_element, signed_type)                    \
2143
    VAVG_DO(avgu##type, unsigned_element, unsigned_type)
2144
VAVG(b, s8, int16_t, u8, uint16_t)
2145
VAVG(h, s16, int32_t, u16, uint32_t)
2146
VAVG(w, s32, int64_t, u32, uint64_t)
2147
#undef VAVG_DO
2148
#undef VAVG
2149

    
2150
#define VCF(suffix, cvt, element)                                       \
2151
    void helper_vcf##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t uim)  \
2152
    {                                                                   \
2153
        int i;                                                          \
2154
        for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
2155
            float32 t = cvt(b->element[i], &env->vec_status);           \
2156
            r->f[i] = float32_scalbn (t, -uim, &env->vec_status);       \
2157
        }                                                               \
2158
    }
2159
VCF(ux, uint32_to_float32, u32)
2160
VCF(sx, int32_to_float32, s32)
2161
#undef VCF
2162

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

    
2199
#define VCMPFP_DO(suffix, compare, order, record)                       \
2200
    void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2201
    {                                                                   \
2202
        uint32_t ones = (uint32_t)-1;                                   \
2203
        uint32_t all = ones;                                            \
2204
        uint32_t none = 0;                                              \
2205
        int i;                                                          \
2206
        for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
2207
            uint32_t result;                                            \
2208
            int rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status); \
2209
            if (rel == float_relation_unordered) {                      \
2210
                result = 0;                                             \
2211
            } else if (rel compare order) {                             \
2212
                result = ones;                                          \
2213
            } else {                                                    \
2214
                result = 0;                                             \
2215
            }                                                           \
2216
            r->u32[i] = result;                                         \
2217
            all &= result;                                              \
2218
            none |= result;                                             \
2219
        }                                                               \
2220
        if (record) {                                                   \
2221
            env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1);       \
2222
        }                                                               \
2223
    }
2224
#define VCMPFP(suffix, compare, order)           \
2225
    VCMPFP_DO(suffix, compare, order, 0)         \
2226
    VCMPFP_DO(suffix##_dot, compare, order, 1)
2227
VCMPFP(eqfp, ==, float_relation_equal)
2228
VCMPFP(gefp, !=, float_relation_less)
2229
VCMPFP(gtfp, ==, float_relation_greater)
2230
#undef VCMPFP_DO
2231
#undef VCMPFP
2232

    
2233
static inline void vcmpbfp_internal(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
2234
                                    int record)
2235
{
2236
    int i;
2237
    int all_in = 0;
2238
    for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2239
        int le_rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status);
2240
        if (le_rel == float_relation_unordered) {
2241
            r->u32[i] = 0xc0000000;
2242
            /* ALL_IN does not need to be updated here.  */
2243
        } else {
2244
            float32 bneg = float32_chs(b->f[i]);
2245
            int ge_rel = float32_compare_quiet(a->f[i], bneg, &env->vec_status);
2246
            int le = le_rel != float_relation_greater;
2247
            int ge = ge_rel != float_relation_less;
2248
            r->u32[i] = ((!le) << 31) | ((!ge) << 30);
2249
            all_in |= (!le | !ge);
2250
        }
2251
    }
2252
    if (record) {
2253
        env->crf[6] = (all_in == 0) << 1;
2254
    }
2255
}
2256

    
2257
void helper_vcmpbfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2258
{
2259
    vcmpbfp_internal(r, a, b, 0);
2260
}
2261

    
2262
void helper_vcmpbfp_dot (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2263
{
2264
    vcmpbfp_internal(r, a, b, 1);
2265
}
2266

    
2267
#define VCT(suffix, satcvt, element)                                    \
2268
    void helper_vct##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t uim)  \
2269
    {                                                                   \
2270
        int i;                                                          \
2271
        int sat = 0;                                                    \
2272
        float_status s = env->vec_status;                               \
2273
        set_float_rounding_mode(float_round_to_zero, &s);               \
2274
        for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
2275
            if (float32_is_any_nan(b->f[i])) {                          \
2276
                r->element[i] = 0;                                      \
2277
            } else {                                                    \
2278
                float64 t = float32_to_float64(b->f[i], &s);            \
2279
                int64_t j;                                              \
2280
                t = float64_scalbn(t, uim, &s);                         \
2281
                j = float64_to_int64(t, &s);                            \
2282
                r->element[i] = satcvt(j, &sat);                        \
2283
            }                                                           \
2284
        }                                                               \
2285
        if (sat) {                                                      \
2286
            env->vscr |= (1 << VSCR_SAT);                               \
2287
        }                                                               \
2288
    }
2289
VCT(uxs, cvtsduw, u32)
2290
VCT(sxs, cvtsdsw, s32)
2291
#undef VCT
2292

    
2293
void helper_vmaddfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2294
{
2295
    int i;
2296
    for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2297
        HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
2298
            /* Need to do the computation in higher precision and round
2299
             * once at the end.  */
2300
            float64 af, bf, cf, t;
2301
            af = float32_to_float64(a->f[i], &env->vec_status);
2302
            bf = float32_to_float64(b->f[i], &env->vec_status);
2303
            cf = float32_to_float64(c->f[i], &env->vec_status);
2304
            t = float64_mul(af, cf, &env->vec_status);
2305
            t = float64_add(t, bf, &env->vec_status);
2306
            r->f[i] = float64_to_float32(t, &env->vec_status);
2307
        }
2308
    }
2309
}
2310

    
2311
void helper_vmhaddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2312
{
2313
    int sat = 0;
2314
    int i;
2315

    
2316
    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2317
        int32_t prod = a->s16[i] * b->s16[i];
2318
        int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2319
        r->s16[i] = cvtswsh (t, &sat);
2320
    }
2321

    
2322
    if (sat) {
2323
        env->vscr |= (1 << VSCR_SAT);
2324
    }
2325
}
2326

    
2327
void helper_vmhraddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2328
{
2329
    int sat = 0;
2330
    int i;
2331

    
2332
    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2333
        int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
2334
        int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2335
        r->s16[i] = cvtswsh (t, &sat);
2336
    }
2337

    
2338
    if (sat) {
2339
        env->vscr |= (1 << VSCR_SAT);
2340
    }
2341
}
2342

    
2343
#define VMINMAX_DO(name, compare, element)                              \
2344
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
2345
    {                                                                   \
2346
        int i;                                                          \
2347
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2348
            if (a->element[i] compare b->element[i]) {                  \
2349
                r->element[i] = b->element[i];                          \
2350
            } else {                                                    \
2351
                r->element[i] = a->element[i];                          \
2352
            }                                                           \
2353
        }                                                               \
2354
    }
2355
#define VMINMAX(suffix, element)                \
2356
  VMINMAX_DO(min##suffix, >, element)           \
2357
  VMINMAX_DO(max##suffix, <, element)
2358
VMINMAX(sb, s8)
2359
VMINMAX(sh, s16)
2360
VMINMAX(sw, s32)
2361
VMINMAX(ub, u8)
2362
VMINMAX(uh, u16)
2363
VMINMAX(uw, u32)
2364
#undef VMINMAX_DO
2365
#undef VMINMAX
2366

    
2367
#define VMINMAXFP(suffix, rT, rF)                                       \
2368
    void helper_v##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)    \
2369
    {                                                                   \
2370
        int i;                                                          \
2371
        for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
2372
            HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) {                    \
2373
                if (float32_lt_quiet(a->f[i], b->f[i], &env->vec_status)) { \
2374
                    r->f[i] = rT->f[i];                                 \
2375
                } else {                                                \
2376
                    r->f[i] = rF->f[i];                                 \
2377
                }                                                       \
2378
            }                                                           \
2379
        }                                                               \
2380
    }
2381
VMINMAXFP(minfp, a, b)
2382
VMINMAXFP(maxfp, b, a)
2383
#undef VMINMAXFP
2384

    
2385
void helper_vmladduhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2386
{
2387
    int i;
2388
    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2389
        int32_t prod = a->s16[i] * b->s16[i];
2390
        r->s16[i] = (int16_t) (prod + c->s16[i]);
2391
    }
2392
}
2393

    
2394
#define VMRG_DO(name, element, highp)                                   \
2395
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
2396
    {                                                                   \
2397
        ppc_avr_t result;                                               \
2398
        int i;                                                          \
2399
        size_t n_elems = ARRAY_SIZE(r->element);                        \
2400
        for (i = 0; i < n_elems/2; i++) {                               \
2401
            if (highp) {                                                \
2402
                result.element[i*2+HI_IDX] = a->element[i];             \
2403
                result.element[i*2+LO_IDX] = b->element[i];             \
2404
            } else {                                                    \
2405
                result.element[n_elems - i*2 - (1+HI_IDX)] = b->element[n_elems - i - 1]; \
2406
                result.element[n_elems - i*2 - (1+LO_IDX)] = a->element[n_elems - i - 1]; \
2407
            }                                                           \
2408
        }                                                               \
2409
        *r = result;                                                    \
2410
    }
2411
#if defined(HOST_WORDS_BIGENDIAN)
2412
#define MRGHI 0
2413
#define MRGLO 1
2414
#else
2415
#define MRGHI 1
2416
#define MRGLO 0
2417
#endif
2418
#define VMRG(suffix, element)                   \
2419
  VMRG_DO(mrgl##suffix, element, MRGHI)         \
2420
  VMRG_DO(mrgh##suffix, element, MRGLO)
2421
VMRG(b, u8)
2422
VMRG(h, u16)
2423
VMRG(w, u32)
2424
#undef VMRG_DO
2425
#undef VMRG
2426
#undef MRGHI
2427
#undef MRGLO
2428

    
2429
void helper_vmsummbm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2430
{
2431
    int32_t prod[16];
2432
    int i;
2433

    
2434
    for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
2435
        prod[i] = (int32_t)a->s8[i] * b->u8[i];
2436
    }
2437

    
2438
    VECTOR_FOR_INORDER_I(i, s32) {
2439
        r->s32[i] = c->s32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2440
    }
2441
}
2442

    
2443
void helper_vmsumshm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2444
{
2445
    int32_t prod[8];
2446
    int i;
2447

    
2448
    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2449
        prod[i] = a->s16[i] * b->s16[i];
2450
    }
2451

    
2452
    VECTOR_FOR_INORDER_I(i, s32) {
2453
        r->s32[i] = c->s32[i] + prod[2*i] + prod[2*i+1];
2454
    }
2455
}
2456

    
2457
void helper_vmsumshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2458
{
2459
    int32_t prod[8];
2460
    int i;
2461
    int sat = 0;
2462

    
2463
    for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2464
        prod[i] = (int32_t)a->s16[i] * b->s16[i];
2465
    }
2466

    
2467
    VECTOR_FOR_INORDER_I (i, s32) {
2468
        int64_t t = (int64_t)c->s32[i] + prod[2*i] + prod[2*i+1];
2469
        r->u32[i] = cvtsdsw(t, &sat);
2470
    }
2471

    
2472
    if (sat) {
2473
        env->vscr |= (1 << VSCR_SAT);
2474
    }
2475
}
2476

    
2477
void helper_vmsumubm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2478
{
2479
    uint16_t prod[16];
2480
    int i;
2481

    
2482
    for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2483
        prod[i] = a->u8[i] * b->u8[i];
2484
    }
2485

    
2486
    VECTOR_FOR_INORDER_I(i, u32) {
2487
        r->u32[i] = c->u32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2488
    }
2489
}
2490

    
2491
void helper_vmsumuhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2492
{
2493
    uint32_t prod[8];
2494
    int i;
2495

    
2496
    for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2497
        prod[i] = a->u16[i] * b->u16[i];
2498
    }
2499

    
2500
    VECTOR_FOR_INORDER_I(i, u32) {
2501
        r->u32[i] = c->u32[i] + prod[2*i] + prod[2*i+1];
2502
    }
2503
}
2504

    
2505
void helper_vmsumuhs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2506
{
2507
    uint32_t prod[8];
2508
    int i;
2509
    int sat = 0;
2510

    
2511
    for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2512
        prod[i] = a->u16[i] * b->u16[i];
2513
    }
2514

    
2515
    VECTOR_FOR_INORDER_I (i, s32) {
2516
        uint64_t t = (uint64_t)c->u32[i] + prod[2*i] + prod[2*i+1];
2517
        r->u32[i] = cvtuduw(t, &sat);
2518
    }
2519

    
2520
    if (sat) {
2521
        env->vscr |= (1 << VSCR_SAT);
2522
    }
2523
}
2524

    
2525
#define VMUL_DO(name, mul_element, prod_element, evenp)                 \
2526
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
2527
    {                                                                   \
2528
        int i;                                                          \
2529
        VECTOR_FOR_INORDER_I(i, prod_element) {                         \
2530
            if (evenp) {                                                \
2531
                r->prod_element[i] = a->mul_element[i*2+HI_IDX] * b->mul_element[i*2+HI_IDX]; \
2532
            } else {                                                    \
2533
                r->prod_element[i] = a->mul_element[i*2+LO_IDX] * b->mul_element[i*2+LO_IDX]; \
2534
            }                                                           \
2535
        }                                                               \
2536
    }
2537
#define VMUL(suffix, mul_element, prod_element) \
2538
  VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
2539
  VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
2540
VMUL(sb, s8, s16)
2541
VMUL(sh, s16, s32)
2542
VMUL(ub, u8, u16)
2543
VMUL(uh, u16, u32)
2544
#undef VMUL_DO
2545
#undef VMUL
2546

    
2547
void helper_vnmsubfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2548
{
2549
    int i;
2550
    for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2551
        HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
2552
            /* Need to do the computation is higher precision and round
2553
             * once at the end.  */
2554
            float64 af, bf, cf, t;
2555
            af = float32_to_float64(a->f[i], &env->vec_status);
2556
            bf = float32_to_float64(b->f[i], &env->vec_status);
2557
            cf = float32_to_float64(c->f[i], &env->vec_status);
2558
            t = float64_mul(af, cf, &env->vec_status);
2559
            t = float64_sub(t, bf, &env->vec_status);
2560
            t = float64_chs(t);
2561
            r->f[i] = float64_to_float32(t, &env->vec_status);
2562
        }
2563
    }
2564
}
2565

    
2566
void helper_vperm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2567
{
2568
    ppc_avr_t result;
2569
    int i;
2570
    VECTOR_FOR_INORDER_I (i, u8) {
2571
        int s = c->u8[i] & 0x1f;
2572
#if defined(HOST_WORDS_BIGENDIAN)
2573
        int index = s & 0xf;
2574
#else
2575
        int index = 15 - (s & 0xf);
2576
#endif
2577
        if (s & 0x10) {
2578
            result.u8[i] = b->u8[index];
2579
        } else {
2580
            result.u8[i] = a->u8[index];
2581
        }
2582
    }
2583
    *r = result;
2584
}
2585

    
2586
#if defined(HOST_WORDS_BIGENDIAN)
2587
#define PKBIG 1
2588
#else
2589
#define PKBIG 0
2590
#endif
2591
void helper_vpkpx (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2592
{
2593
    int i, j;
2594
    ppc_avr_t result;
2595
#if defined(HOST_WORDS_BIGENDIAN)
2596
    const ppc_avr_t *x[2] = { a, b };
2597
#else
2598
    const ppc_avr_t *x[2] = { b, a };
2599
#endif
2600

    
2601
    VECTOR_FOR_INORDER_I (i, u64) {
2602
        VECTOR_FOR_INORDER_I (j, u32){
2603
            uint32_t e = x[i]->u32[j];
2604
            result.u16[4*i+j] = (((e >> 9) & 0xfc00) |
2605
                                 ((e >> 6) & 0x3e0) |
2606
                                 ((e >> 3) & 0x1f));
2607
        }
2608
    }
2609
    *r = result;
2610
}
2611

    
2612
#define VPK(suffix, from, to, cvt, dosat)       \
2613
    void helper_vpk##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
2614
    {                                                                   \
2615
        int i;                                                          \
2616
        int sat = 0;                                                    \
2617
        ppc_avr_t result;                                               \
2618
        ppc_avr_t *a0 = PKBIG ? a : b;                                  \
2619
        ppc_avr_t *a1 = PKBIG ? b : a;                                  \
2620
        VECTOR_FOR_INORDER_I (i, from) {                                \
2621
            result.to[i] = cvt(a0->from[i], &sat);                      \
2622
            result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat);  \
2623
        }                                                               \
2624
        *r = result;                                                    \
2625
        if (dosat && sat) {                                             \
2626
            env->vscr |= (1 << VSCR_SAT);                               \
2627
        }                                                               \
2628
    }
2629
#define I(x, y) (x)
2630
VPK(shss, s16, s8, cvtshsb, 1)
2631
VPK(shus, s16, u8, cvtshub, 1)
2632
VPK(swss, s32, s16, cvtswsh, 1)
2633
VPK(swus, s32, u16, cvtswuh, 1)
2634
VPK(uhus, u16, u8, cvtuhub, 1)
2635
VPK(uwus, u32, u16, cvtuwuh, 1)
2636
VPK(uhum, u16, u8, I, 0)
2637
VPK(uwum, u32, u16, I, 0)
2638
#undef I
2639
#undef VPK
2640
#undef PKBIG
2641

    
2642
void helper_vrefp (ppc_avr_t *r, ppc_avr_t *b)
2643
{
2644
    int i;
2645
    for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2646
        HANDLE_NAN1(r->f[i], b->f[i]) {
2647
            r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status);
2648
        }
2649
    }
2650
}
2651

    
2652
#define VRFI(suffix, rounding)                                          \
2653
    void helper_vrfi##suffix (ppc_avr_t *r, ppc_avr_t *b)               \
2654
    {                                                                   \
2655
        int i;                                                          \
2656
        float_status s = env->vec_status;                               \
2657
        set_float_rounding_mode(rounding, &s);                          \
2658
        for (i = 0; i < ARRAY_SIZE(r->f); i++) {                        \
2659
            HANDLE_NAN1(r->f[i], b->f[i]) {                             \
2660
                r->f[i] = float32_round_to_int (b->f[i], &s);           \
2661
            }                                                           \
2662
        }                                                               \
2663
    }
2664
VRFI(n, float_round_nearest_even)
2665
VRFI(m, float_round_down)
2666
VRFI(p, float_round_up)
2667
VRFI(z, float_round_to_zero)
2668
#undef VRFI
2669

    
2670
#define VROTATE(suffix, element)                                        \
2671
    void helper_vrl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
2672
    {                                                                   \
2673
        int i;                                                          \
2674
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
2675
            unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2676
            unsigned int shift = b->element[i] & mask;                  \
2677
            r->element[i] = (a->element[i] << shift) | (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
2678
        }                                                               \
2679
    }
2680
VROTATE(b, u8)
2681
VROTATE(h, u16)
2682
VROTATE(w, u32)
2683
#undef VROTATE
2684

    
2685
void helper_vrsqrtefp (ppc_avr_t *r, ppc_avr_t *b)
2686
{
2687
    int i;
2688
    for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2689
        HANDLE_NAN1(r->f[i], b->f[i]) {
2690
            float32 t = float32_sqrt(b->f[i], &env->vec_status);
2691
            r->f[i] = float32_div(float32_one, t, &env->vec_status);
2692
        }
2693
    }
2694
}
2695

    
2696
void helper_vsel (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2697
{
2698
    r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
2699
    r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
2700
}
2701

    
2702
void helper_vexptefp (ppc_avr_t *r, ppc_avr_t *b)
2703
{
2704
    int i;
2705
    for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2706
        HANDLE_NAN1(r->f[i], b->f[i]) {
2707
            r->f[i] = float32_exp2(b->f[i], &env->vec_status);
2708
        }
2709
    }
2710
}
2711

    
2712
void helper_vlogefp (ppc_avr_t *r, ppc_avr_t *b)
2713
{
2714
    int i;
2715
    for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2716
        HANDLE_NAN1(r->f[i], b->f[i]) {
2717
            r->f[i] = float32_log2(b->f[i], &env->vec_status);
2718
        }
2719
    }
2720
}
2721

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

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

    
2776
void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
2777
{
2778
    int sh = shift & 0xf;
2779
    int i;
2780
    ppc_avr_t result;
2781

    
2782
#if defined(HOST_WORDS_BIGENDIAN)
2783
    for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2784
        int index = sh + i;
2785
        if (index > 0xf) {
2786
            result.u8[i] = b->u8[index-0x10];
2787
        } else {
2788
            result.u8[i] = a->u8[index];
2789
        }
2790
    }
2791
#else
2792
    for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2793
        int index = (16 - sh) + i;
2794
        if (index > 0xf) {
2795
            result.u8[i] = a->u8[index-0x10];
2796
        } else {
2797
            result.u8[i] = b->u8[index];
2798
        }
2799
    }
2800
#endif
2801
    *r = result;
2802
}
2803

    
2804
void helper_vslo (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2805
{
2806
  int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2807

    
2808
#if defined (HOST_WORDS_BIGENDIAN)
2809
  memmove (&r->u8[0], &a->u8[sh], 16-sh);
2810
  memset (&r->u8[16-sh], 0, sh);
2811
#else
2812
  memmove (&r->u8[sh], &a->u8[0], 16-sh);
2813
  memset (&r->u8[0], 0, sh);
2814
#endif
2815
}
2816

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

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

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

    
2872
void helper_vsro (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2873
{
2874
  int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2875

    
2876
#if defined (HOST_WORDS_BIGENDIAN)
2877
  memmove (&r->u8[sh], &a->u8[0], 16-sh);
2878
  memset (&r->u8[0], 0, sh);
2879
#else
2880
  memmove (&r->u8[0], &a->u8[sh], 16-sh);
2881
  memset (&r->u8[16-sh], 0, sh);
2882
#endif
2883
}
2884

    
2885
void helper_vsubcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2886
{
2887
    int i;
2888
    for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2889
        r->u32[i] = a->u32[i] >= b->u32[i];
2890
    }
2891
}
2892

    
2893
void helper_vsumsws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2894
{
2895
    int64_t t;
2896
    int i, upper;
2897
    ppc_avr_t result;
2898
    int sat = 0;
2899

    
2900
#if defined(HOST_WORDS_BIGENDIAN)
2901
    upper = ARRAY_SIZE(r->s32)-1;
2902
#else
2903
    upper = 0;
2904
#endif
2905
    t = (int64_t)b->s32[upper];
2906
    for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2907
        t += a->s32[i];
2908
        result.s32[i] = 0;
2909
    }
2910
    result.s32[upper] = cvtsdsw(t, &sat);
2911
    *r = result;
2912

    
2913
    if (sat) {
2914
        env->vscr |= (1 << VSCR_SAT);
2915
    }
2916
}
2917

    
2918
void helper_vsum2sws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2919
{
2920
    int i, j, upper;
2921
    ppc_avr_t result;
2922
    int sat = 0;
2923

    
2924
#if defined(HOST_WORDS_BIGENDIAN)
2925
    upper = 1;
2926
#else
2927
    upper = 0;
2928
#endif
2929
    for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
2930
        int64_t t = (int64_t)b->s32[upper+i*2];
2931
        result.u64[i] = 0;
2932
        for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
2933
            t += a->s32[2*i+j];
2934
        }
2935
        result.s32[upper+i*2] = cvtsdsw(t, &sat);
2936
    }
2937

    
2938
    *r = result;
2939
    if (sat) {
2940
        env->vscr |= (1 << VSCR_SAT);
2941
    }
2942
}
2943

    
2944
void helper_vsum4sbs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2945
{
2946
    int i, j;
2947
    int sat = 0;
2948

    
2949
    for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2950
        int64_t t = (int64_t)b->s32[i];
2951
        for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
2952
            t += a->s8[4*i+j];
2953
        }
2954
        r->s32[i] = cvtsdsw(t, &sat);
2955
    }
2956

    
2957
    if (sat) {
2958
        env->vscr |= (1 << VSCR_SAT);
2959
    }
2960
}
2961

    
2962
void helper_vsum4shs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2963
{
2964
    int sat = 0;
2965
    int i;
2966

    
2967
    for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2968
        int64_t t = (int64_t)b->s32[i];
2969
        t += a->s16[2*i] + a->s16[2*i+1];
2970
        r->s32[i] = cvtsdsw(t, &sat);
2971
    }
2972

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

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

    
2983
    for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2984
        uint64_t t = (uint64_t)b->u32[i];
2985
        for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
2986
            t += a->u8[4*i+j];
2987
        }
2988
        r->u32[i] = cvtuduw(t, &sat);
2989
    }
2990

    
2991
    if (sat) {
2992
        env->vscr |= (1 << VSCR_SAT);
2993
    }
2994
}
2995

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

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

    
3046
#undef DO_HANDLE_NAN
3047
#undef HANDLE_NAN1
3048
#undef HANDLE_NAN2
3049
#undef HANDLE_NAN3
3050
#undef VECTOR_FOR_INORDER_I
3051
#undef HI_IDX
3052
#undef LO_IDX
3053

    
3054
/*****************************************************************************/
3055
/* SPE extension helpers */
3056
/* Use a table to make this quicker */
3057
static uint8_t hbrev[16] = {
3058
    0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
3059
    0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
3060
};
3061

    
3062
static inline uint8_t byte_reverse(uint8_t val)
3063
{
3064
    return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
3065
}
3066

    
3067
static inline uint32_t word_reverse(uint32_t val)
3068
{
3069
    return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
3070
        (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
3071
}
3072

    
3073
#define MASKBITS 16 // Random value - to be fixed (implementation dependent)
3074
target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
3075
{
3076
    uint32_t a, b, d, mask;
3077

    
3078
    mask = UINT32_MAX >> (32 - MASKBITS);
3079
    a = arg1 & mask;
3080
    b = arg2 & mask;
3081
    d = word_reverse(1 + word_reverse(a | ~b));
3082
    return (arg1 & ~mask) | (d & b);
3083
}
3084

    
3085
uint32_t helper_cntlsw32 (uint32_t val)
3086
{
3087
    if (val & 0x80000000)
3088
        return clz32(~val);
3089
    else
3090
        return clz32(val);
3091
}
3092

    
3093
uint32_t helper_cntlzw32 (uint32_t val)
3094
{
3095
    return clz32(val);
3096
}
3097

    
3098
/* Single-precision floating-point conversions */
3099
static inline uint32_t efscfsi(uint32_t val)
3100
{
3101
    CPU_FloatU u;
3102

    
3103
    u.f = int32_to_float32(val, &env->vec_status);
3104

    
3105
    return u.l;
3106
}
3107

    
3108
static inline uint32_t efscfui(uint32_t val)
3109
{
3110
    CPU_FloatU u;
3111

    
3112
    u.f = uint32_to_float32(val, &env->vec_status);
3113

    
3114
    return u.l;
3115
}
3116

    
3117
static inline int32_t efsctsi(uint32_t val)
3118
{
3119
    CPU_FloatU u;
3120

    
3121
    u.l = val;
3122
    /* NaN are not treated the same way IEEE 754 does */
3123
    if (unlikely(float32_is_quiet_nan(u.f)))
3124
        return 0;
3125

    
3126
    return float32_to_int32(u.f, &env->vec_status);
3127
}
3128

    
3129
static inline uint32_t efsctui(uint32_t val)
3130
{
3131
    CPU_FloatU u;
3132

    
3133
    u.l = val;
3134
    /* NaN are not treated the same way IEEE 754 does */
3135
    if (unlikely(float32_is_quiet_nan(u.f)))
3136
        return 0;
3137

    
3138
    return float32_to_uint32(u.f, &env->vec_status);
3139
}
3140

    
3141
static inline uint32_t efsctsiz(uint32_t val)
3142
{
3143
    CPU_FloatU u;
3144

    
3145
    u.l = val;
3146
    /* NaN are not treated the same way IEEE 754 does */
3147
    if (unlikely(float32_is_quiet_nan(u.f)))
3148
        return 0;
3149

    
3150
    return float32_to_int32_round_to_zero(u.f, &env->vec_status);
3151
}
3152

    
3153
static inline uint32_t efsctuiz(uint32_t val)
3154
{
3155
    CPU_FloatU u;
3156

    
3157
    u.l = val;
3158
    /* NaN are not treated the same way IEEE 754 does */
3159
    if (unlikely(float32_is_quiet_nan(u.f)))
3160
        return 0;
3161

    
3162
    return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
3163
}
3164

    
3165
static inline uint32_t efscfsf(uint32_t val)
3166
{
3167
    CPU_FloatU u;
3168
    float32 tmp;
3169

    
3170
    u.f = int32_to_float32(val, &env->vec_status);
3171
    tmp = int64_to_float32(1ULL << 32, &env->vec_status);
3172
    u.f = float32_div(u.f, tmp, &env->vec_status);
3173

    
3174
    return u.l;
3175
}
3176

    
3177
static inline uint32_t efscfuf(uint32_t val)
3178
{
3179
    CPU_FloatU u;
3180
    float32 tmp;
3181

    
3182
    u.f = uint32_to_float32(val, &env->vec_status);
3183
    tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3184
    u.f = float32_div(u.f, tmp, &env->vec_status);
3185

    
3186
    return u.l;
3187
}
3188

    
3189
static inline uint32_t efsctsf(uint32_t val)
3190
{
3191
    CPU_FloatU u;
3192
    float32 tmp;
3193

    
3194
    u.l = val;
3195
    /* NaN are not treated the same way IEEE 754 does */
3196
    if (unlikely(float32_is_quiet_nan(u.f)))
3197
        return 0;
3198
    tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3199
    u.f = float32_mul(u.f, tmp, &env->vec_status);
3200

    
3201
    return float32_to_int32(u.f, &env->vec_status);
3202
}
3203

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

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

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

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

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

    
3272
/* Single-precision floating-point arithmetic */
3273
static inline uint32_t efsadd(uint32_t op1, uint32_t op2)
3274
{
3275
    CPU_FloatU u1, u2;
3276
    u1.l = op1;
3277
    u2.l = op2;
3278
    u1.f = float32_add(u1.f, u2.f, &env->vec_status);
3279
    return u1.l;
3280
}
3281

    
3282
static inline uint32_t efssub(uint32_t op1, uint32_t op2)
3283
{
3284
    CPU_FloatU u1, u2;
3285
    u1.l = op1;
3286
    u2.l = op2;
3287
    u1.f = float32_sub(u1.f, u2.f, &env->vec_status);
3288
    return u1.l;
3289
}
3290

    
3291
static inline uint32_t efsmul(uint32_t op1, uint32_t op2)
3292
{
3293
    CPU_FloatU u1, u2;
3294
    u1.l = op1;
3295
    u2.l = op2;
3296
    u1.f = float32_mul(u1.f, u2.f, &env->vec_status);
3297
    return u1.l;
3298
}
3299

    
3300
static inline uint32_t efsdiv(uint32_t op1, uint32_t op2)
3301
{
3302
    CPU_FloatU u1, u2;
3303
    u1.l = op1;
3304
    u2.l = op2;
3305
    u1.f = float32_div(u1.f, u2.f, &env->vec_status);
3306
    return u1.l;
3307
}
3308

    
3309
#define HELPER_SPE_SINGLE_ARITH(name)                                         \
3310
uint32_t helper_e##name (uint32_t op1, uint32_t op2)                          \
3311
{                                                                             \
3312
    return e##name(op1, op2);                                                 \
3313
}
3314
/* efsadd */
3315
HELPER_SPE_SINGLE_ARITH(fsadd);
3316
/* efssub */
3317
HELPER_SPE_SINGLE_ARITH(fssub);
3318
/* efsmul */
3319
HELPER_SPE_SINGLE_ARITH(fsmul);
3320
/* efsdiv */
3321
HELPER_SPE_SINGLE_ARITH(fsdiv);
3322

    
3323
#define HELPER_SPE_VECTOR_ARITH(name)                                         \
3324
uint64_t helper_ev##name (uint64_t op1, uint64_t op2)                         \
3325
{                                                                             \
3326
    return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) |                  \
3327
            (uint64_t)e##name(op1, op2);                                      \
3328
}
3329
/* evfsadd */
3330
HELPER_SPE_VECTOR_ARITH(fsadd);
3331
/* evfssub */
3332
HELPER_SPE_VECTOR_ARITH(fssub);
3333
/* evfsmul */
3334
HELPER_SPE_VECTOR_ARITH(fsmul);
3335
/* evfsdiv */
3336
HELPER_SPE_VECTOR_ARITH(fsdiv);
3337

    
3338
/* Single-precision floating-point comparisons */
3339
static inline uint32_t efscmplt(uint32_t op1, uint32_t op2)
3340
{
3341
    CPU_FloatU u1, u2;
3342
    u1.l = op1;
3343
    u2.l = op2;
3344
    return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0;
3345
}
3346

    
3347
static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2)
3348
{
3349
    CPU_FloatU u1, u2;
3350
    u1.l = op1;
3351
    u2.l = op2;
3352
    return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4;
3353
}
3354

    
3355
static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2)
3356
{
3357
    CPU_FloatU u1, u2;
3358
    u1.l = op1;
3359
    u2.l = op2;
3360
    return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0;
3361
}
3362

    
3363
static inline uint32_t efststlt(uint32_t op1, uint32_t op2)
3364
{
3365
    /* XXX: TODO: ignore special values (NaN, infinites, ...) */
3366
    return efscmplt(op1, op2);
3367
}
3368

    
3369
static inline uint32_t efststgt(uint32_t op1, uint32_t op2)
3370
{
3371
    /* XXX: TODO: ignore special values (NaN, infinites, ...) */
3372
    return efscmpgt(op1, op2);
3373
}
3374

    
3375
static inline uint32_t efststeq(uint32_t op1, uint32_t op2)
3376
{
3377
    /* XXX: TODO: ignore special values (NaN, infinites, ...) */
3378
    return efscmpeq(op1, op2);
3379
}
3380

    
3381
#define HELPER_SINGLE_SPE_CMP(name)                                           \
3382
uint32_t helper_e##name (uint32_t op1, uint32_t op2)                          \
3383
{                                                                             \
3384
    return e##name(op1, op2) << 2;                                            \
3385
}
3386
/* efststlt */
3387
HELPER_SINGLE_SPE_CMP(fststlt);
3388
/* efststgt */
3389
HELPER_SINGLE_SPE_CMP(fststgt);
3390
/* efststeq */
3391
HELPER_SINGLE_SPE_CMP(fststeq);
3392
/* efscmplt */
3393
HELPER_SINGLE_SPE_CMP(fscmplt);
3394
/* efscmpgt */
3395
HELPER_SINGLE_SPE_CMP(fscmpgt);
3396
/* efscmpeq */
3397
HELPER_SINGLE_SPE_CMP(fscmpeq);
3398

    
3399
static inline uint32_t evcmp_merge(int t0, int t1)
3400
{
3401
    return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
3402
}
3403

    
3404
#define HELPER_VECTOR_SPE_CMP(name)                                           \
3405
uint32_t helper_ev##name (uint64_t op1, uint64_t op2)                         \
3406
{                                                                             \
3407
    return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2));     \
3408
}
3409
/* evfststlt */
3410
HELPER_VECTOR_SPE_CMP(fststlt);
3411
/* evfststgt */
3412
HELPER_VECTOR_SPE_CMP(fststgt);
3413
/* evfststeq */
3414
HELPER_VECTOR_SPE_CMP(fststeq);
3415
/* evfscmplt */
3416
HELPER_VECTOR_SPE_CMP(fscmplt);
3417
/* evfscmpgt */
3418
HELPER_VECTOR_SPE_CMP(fscmpgt);
3419
/* evfscmpeq */
3420
HELPER_VECTOR_SPE_CMP(fscmpeq);
3421

    
3422
/* Double-precision floating-point conversion */
3423
uint64_t helper_efdcfsi (uint32_t val)
3424
{
3425
    CPU_DoubleU u;
3426

    
3427
    u.d = int32_to_float64(val, &env->vec_status);
3428

    
3429
    return u.ll;
3430
}
3431

    
3432
uint64_t helper_efdcfsid (uint64_t val)
3433
{
3434
    CPU_DoubleU u;
3435

    
3436
    u.d = int64_to_float64(val, &env->vec_status);
3437

    
3438
    return u.ll;
3439
}
3440

    
3441
uint64_t helper_efdcfui (uint32_t val)
3442
{
3443
    CPU_DoubleU u;
3444

    
3445
    u.d = uint32_to_float64(val, &env->vec_status);
3446

    
3447
    return u.ll;
3448
}
3449

    
3450
uint64_t helper_efdcfuid (uint64_t val)
3451
{
3452
    CPU_DoubleU u;
3453

    
3454
    u.d = uint64_to_float64(val, &env->vec_status);
3455

    
3456
    return u.ll;
3457
}
3458

    
3459
uint32_t helper_efdctsi (uint64_t val)
3460
{
3461
    CPU_DoubleU u;
3462

    
3463
    u.ll = val;
3464
    /* NaN are not treated the same way IEEE 754 does */
3465
    if (unlikely(float64_is_any_nan(u.d))) {
3466
        return 0;
3467
    }
3468

    
3469
    return float64_to_int32(u.d, &env->vec_status);
3470
}
3471

    
3472
uint32_t helper_efdctui (uint64_t val)
3473
{
3474
    CPU_DoubleU u;
3475

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

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

    
3485
uint32_t helper_efdctsiz (uint64_t val)
3486
{
3487
    CPU_DoubleU u;
3488

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

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

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

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

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

    
3511
uint32_t helper_efdctuiz (uint64_t val)
3512
{
3513
    CPU_DoubleU u;
3514

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

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

    
3524
uint64_t helper_efdctuidz (uint64_t val)
3525
{
3526
    CPU_DoubleU u;
3527

    
3528
    u.ll = val;
3529
    /* NaN are not treated the same way IEEE 754 does */
3530
    if (unlikely(float64_is_any_nan(u.d))) {
3531
        return 0;
3532
    }
3533

    
3534
    return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
3535
}
3536

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

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

    
3546
    return u.ll;
3547
}
3548

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

    
3554
    u.d = uint32_to_float64(val, &env->vec_status);
3555
    tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3556
    u.d = float64_div(u.d, tmp, &env->vec_status);
3557

    
3558
    return u.ll;
3559
}
3560

    
3561
uint32_t helper_efdctsf (uint64_t val)
3562
{
3563
    CPU_DoubleU u;
3564
    float64 tmp;
3565

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

    
3574
    return float64_to_int32(u.d, &env->vec_status);
3575
}
3576

    
3577
uint32_t helper_efdctuf (uint64_t val)
3578
{
3579
    CPU_DoubleU u;
3580
    float64 tmp;
3581

    
3582
    u.ll = val;
3583
    /* NaN are not treated the same way IEEE 754 does */
3584
    if (unlikely(float64_is_any_nan(u.d))) {
3585
        return 0;
3586
    }
3587
    tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3588
    u.d = float64_mul(u.d, tmp, &env->vec_status);
3589

    
3590
    return float64_to_uint32(u.d, &env->vec_status);
3591
}
3592

    
3593
uint32_t helper_efscfd (uint64_t val)
3594
{
3595
    CPU_DoubleU u1;
3596
    CPU_FloatU u2;
3597

    
3598
    u1.ll = val;
3599
    u2.f = float64_to_float32(u1.d, &env->vec_status);
3600

    
3601
    return u2.l;
3602
}
3603

    
3604
uint64_t helper_efdcfs (uint32_t val)
3605
{
3606
    CPU_DoubleU u2;
3607
    CPU_FloatU u1;
3608

    
3609
    u1.l = val;
3610
    u2.d = float32_to_float64(u1.f, &env->vec_status);
3611

    
3612
    return u2.ll;
3613
}
3614

    
3615
/* Double precision fixed-point arithmetic */
3616
uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
3617
{
3618
    CPU_DoubleU u1, u2;
3619
    u1.ll = op1;
3620
    u2.ll = op2;
3621
    u1.d = float64_add(u1.d, u2.d, &env->vec_status);
3622
    return u1.ll;
3623
}
3624

    
3625
uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
3626
{
3627
    CPU_DoubleU u1, u2;
3628
    u1.ll = op1;
3629
    u2.ll = op2;
3630
    u1.d = float64_sub(u1.d, u2.d, &env->vec_status);
3631
    return u1.ll;
3632
}
3633

    
3634
uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
3635
{
3636
    CPU_DoubleU u1, u2;
3637
    u1.ll = op1;
3638
    u2.ll = op2;
3639
    u1.d = float64_mul(u1.d, u2.d, &env->vec_status);
3640
    return u1.ll;
3641
}
3642

    
3643
uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
3644
{
3645
    CPU_DoubleU u1, u2;
3646
    u1.ll = op1;
3647
    u2.ll = op2;
3648
    u1.d = float64_div(u1.d, u2.d, &env->vec_status);
3649
    return u1.ll;
3650
}
3651

    
3652
/* Double precision floating point helpers */
3653
uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
3654
{
3655
    CPU_DoubleU u1, u2;
3656
    u1.ll = op1;
3657
    u2.ll = op2;
3658
    return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0;
3659
}
3660

    
3661
uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
3662
{
3663
    CPU_DoubleU u1, u2;
3664
    u1.ll = op1;
3665
    u2.ll = op2;
3666
    return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4;
3667
}
3668

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

    
3677
uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
3678
{
3679
    /* XXX: TODO: test special values (NaN, infinites, ...) */
3680
    return helper_efdtstlt(op1, op2);
3681
}
3682

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

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

    
3695
/*****************************************************************************/
3696
/* Softmmu support */
3697
#if !defined (CONFIG_USER_ONLY)
3698

    
3699
#define MMUSUFFIX _mmu
3700

    
3701
#define SHIFT 0
3702
#include "softmmu_template.h"
3703

    
3704
#define SHIFT 1
3705
#include "softmmu_template.h"
3706

    
3707
#define SHIFT 2
3708
#include "softmmu_template.h"
3709

    
3710
#define SHIFT 3
3711
#include "softmmu_template.h"
3712

    
3713
/* try to fill the TLB and return an exception if error. If retaddr is
3714
   NULL, it means that the function was called in C code (i.e. not
3715
   from generated code or from helper.c) */
3716
/* XXX: fix it to restore all registers */
3717
void tlb_fill(CPUPPCState *env1, target_ulong addr, int is_write, int mmu_idx,
3718
              uintptr_t retaddr)
3719
{
3720
    TranslationBlock *tb;
3721
    CPUPPCState *saved_env;
3722
    int ret;
3723

    
3724
    saved_env = env;
3725
    env = env1;
3726
    ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
3727
    if (unlikely(ret != 0)) {
3728
        if (likely(retaddr)) {
3729
            /* now we have a real cpu fault */
3730
            tb = tb_find_pc(retaddr);
3731
            if (likely(tb)) {
3732
                /* the PC is inside the translated code. It means that we have
3733
                   a virtual CPU fault */
3734
                cpu_restore_state(tb, env, retaddr);
3735
            }
3736
        }
3737
        helper_raise_exception_err(env->exception_index, env->error_code);
3738
    }
3739
    env = saved_env;
3740
}
3741

    
3742
/* Segment registers load and store */
3743
target_ulong helper_load_sr (target_ulong sr_num)
3744
{
3745
#if defined(TARGET_PPC64)
3746
    if (env->mmu_model & POWERPC_MMU_64)
3747
        return ppc_load_sr(env, sr_num);
3748
#endif
3749
    return env->sr[sr_num];
3750
}
3751

    
3752
void helper_store_sr (target_ulong sr_num, target_ulong val)
3753
{
3754
    ppc_store_sr(env, sr_num, val);
3755
}
3756

    
3757
/* SLB management */
3758
#if defined(TARGET_PPC64)
3759
void helper_store_slb (target_ulong rb, target_ulong rs)
3760
{
3761
    if (ppc_store_slb(env, rb, rs) < 0) {
3762
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
3763
    }
3764
}
3765

    
3766
target_ulong helper_load_slb_esid (target_ulong rb)
3767
{
3768
    target_ulong rt;
3769

    
3770
    if (ppc_load_slb_esid(env, rb, &rt) < 0) {
3771
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
3772
    }
3773
    return rt;
3774
}
3775

    
3776
target_ulong helper_load_slb_vsid (target_ulong rb)
3777
{
3778
    target_ulong rt;
3779

    
3780
    if (ppc_load_slb_vsid(env, rb, &rt) < 0) {
3781
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
3782
    }
3783
    return rt;
3784
}
3785

    
3786
void helper_slbia (void)
3787
{
3788
    ppc_slb_invalidate_all(env);
3789
}
3790

    
3791
void helper_slbie (target_ulong addr)
3792
{
3793
    ppc_slb_invalidate_one(env, addr);
3794
}
3795

    
3796
#endif /* defined(TARGET_PPC64) */
3797

    
3798
/* TLB management */
3799
void helper_tlbia (void)
3800
{
3801
    ppc_tlb_invalidate_all(env);
3802
}
3803

    
3804
void helper_tlbie (target_ulong addr)
3805
{
3806
    ppc_tlb_invalidate_one(env, addr);
3807
}
3808

    
3809
/* Software driven TLBs management */
3810
/* PowerPC 602/603 software TLB load instructions helpers */
3811
static void do_6xx_tlb (target_ulong new_EPN, int is_code)
3812
{
3813
    target_ulong RPN, CMP, EPN;
3814
    int way;
3815

    
3816
    RPN = env->spr[SPR_RPA];
3817
    if (is_code) {
3818
        CMP = env->spr[SPR_ICMP];
3819
        EPN = env->spr[SPR_IMISS];
3820
    } else {
3821
        CMP = env->spr[SPR_DCMP];
3822
        EPN = env->spr[SPR_DMISS];
3823
    }
3824
    way = (env->spr[SPR_SRR1] >> 17) & 1;
3825
    (void)EPN; /* avoid a compiler warning */
3826
    LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
3827
              " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
3828
              RPN, way);
3829
    /* Store this TLB */
3830
    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3831
                     way, is_code, CMP, RPN);
3832
}
3833

    
3834
void helper_6xx_tlbd (target_ulong EPN)
3835
{
3836
    do_6xx_tlb(EPN, 0);
3837
}
3838

    
3839
void helper_6xx_tlbi (target_ulong EPN)
3840
{
3841
    do_6xx_tlb(EPN, 1);
3842
}
3843

    
3844
/* PowerPC 74xx software TLB load instructions helpers */
3845
static void do_74xx_tlb (target_ulong new_EPN, int is_code)
3846
{
3847
    target_ulong RPN, CMP, EPN;
3848
    int way;
3849

    
3850
    RPN = env->spr[SPR_PTELO];
3851
    CMP = env->spr[SPR_PTEHI];
3852
    EPN = env->spr[SPR_TLBMISS] & ~0x3;
3853
    way = env->spr[SPR_TLBMISS] & 0x3;
3854
    (void)EPN; /* avoid a compiler warning */
3855
    LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
3856
              " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
3857
              RPN, way);
3858
    /* Store this TLB */
3859
    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3860
                     way, is_code, CMP, RPN);
3861
}
3862

    
3863
void helper_74xx_tlbd (target_ulong EPN)
3864
{
3865
    do_74xx_tlb(EPN, 0);
3866
}
3867

    
3868
void helper_74xx_tlbi (target_ulong EPN)
3869
{
3870
    do_74xx_tlb(EPN, 1);
3871
}
3872

    
3873
static inline target_ulong booke_tlb_to_page_size(int size)
3874
{
3875
    return 1024 << (2 * size);
3876
}
3877

    
3878
static inline int booke_page_size_to_tlb(target_ulong page_size)
3879
{
3880
    int size;
3881

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

    
3938
    return size;
3939
}
3940

    
3941
/* Helpers for 4xx TLB management */
3942
#define PPC4XX_TLB_ENTRY_MASK       0x0000003f  /* Mask for 64 TLB entries */
3943

    
3944
#define PPC4XX_TLBHI_V              0x00000040
3945
#define PPC4XX_TLBHI_E              0x00000020
3946
#define PPC4XX_TLBHI_SIZE_MIN       0
3947
#define PPC4XX_TLBHI_SIZE_MAX       7
3948
#define PPC4XX_TLBHI_SIZE_DEFAULT   1
3949
#define PPC4XX_TLBHI_SIZE_SHIFT     7
3950
#define PPC4XX_TLBHI_SIZE_MASK      0x00000007
3951

    
3952
#define PPC4XX_TLBLO_EX             0x00000200
3953
#define PPC4XX_TLBLO_WR             0x00000100
3954
#define PPC4XX_TLBLO_ATTR_MASK      0x000000FF
3955
#define PPC4XX_TLBLO_RPN_MASK       0xFFFFFC00
3956

    
3957
target_ulong helper_4xx_tlbre_hi (target_ulong entry)
3958
{
3959
    ppcemb_tlb_t *tlb;
3960
    target_ulong ret;
3961
    int size;
3962

    
3963
    entry &= PPC4XX_TLB_ENTRY_MASK;
3964
    tlb = &env->tlb.tlbe[entry];
3965
    ret = tlb->EPN;
3966
    if (tlb->prot & PAGE_VALID) {
3967
        ret |= PPC4XX_TLBHI_V;
3968
    }
3969
    size = booke_page_size_to_tlb(tlb->size);
3970
    if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
3971
        size = PPC4XX_TLBHI_SIZE_DEFAULT;
3972
    }
3973
    ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
3974
    env->spr[SPR_40x_PID] = tlb->PID;
3975
    return ret;
3976
}
3977

    
3978
target_ulong helper_4xx_tlbre_lo (target_ulong entry)
3979
{
3980
    ppcemb_tlb_t *tlb;
3981
    target_ulong ret;
3982

    
3983
    entry &= PPC4XX_TLB_ENTRY_MASK;
3984
    tlb = &env->tlb.tlbe[entry];
3985
    ret = tlb->RPN;
3986
    if (tlb->prot & PAGE_EXEC) {
3987
        ret |= PPC4XX_TLBLO_EX;
3988
    }
3989
    if (tlb->prot & PAGE_WRITE) {
3990
        ret |= PPC4XX_TLBLO_WR;
3991
    }
3992
    return ret;
3993
}
3994

    
3995
void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
3996
{
3997
    ppcemb_tlb_t *tlb;
3998
    target_ulong page, end;
3999

    
4000
    LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
4001
              val);
4002
    entry &= PPC4XX_TLB_ENTRY_MASK;
4003
    tlb = &env->tlb.tlbe[entry];
4004
    /* Invalidate previous TLB (if it's valid) */
4005
    if (tlb->prot & PAGE_VALID) {
4006
        end = tlb->EPN + tlb->size;
4007
        LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
4008
                  TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
4009
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
4010
            tlb_flush_page(env, page);
4011
        }
4012
    }
4013
    tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
4014
                                       & PPC4XX_TLBHI_SIZE_MASK);
4015
    /* We cannot handle TLB size < TARGET_PAGE_SIZE.
4016
     * If this ever occurs, one should use the ppcemb target instead
4017
     * of the ppc or ppc64 one
4018
     */
4019
    if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
4020
        cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
4021
                  "are not supported (%d)\n",
4022
                  tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
4023
    }
4024
    tlb->EPN = val & ~(tlb->size - 1);
4025
    if (val & PPC4XX_TLBHI_V) {
4026
        tlb->prot |= PAGE_VALID;
4027
        if (val & PPC4XX_TLBHI_E) {
4028
            /* XXX: TO BE FIXED */
4029
            cpu_abort(env,
4030
                      "Little-endian TLB entries are not supported by now\n");
4031
        }
4032
    } else {
4033
        tlb->prot &= ~PAGE_VALID;
4034
    }
4035
    tlb->PID = env->spr[SPR_40x_PID]; /* PID */
4036
    LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
4037
              " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
4038
              (int)entry, tlb->RPN, tlb->EPN, tlb->size,
4039
              tlb->prot & PAGE_READ ? 'r' : '-',
4040
              tlb->prot & PAGE_WRITE ? 'w' : '-',
4041
              tlb->prot & PAGE_EXEC ? 'x' : '-',
4042
              tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
4043
    /* Invalidate new TLB (if valid) */
4044
    if (tlb->prot & PAGE_VALID) {
4045
        end = tlb->EPN + tlb->size;
4046
        LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
4047
                  TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
4048
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
4049
            tlb_flush_page(env, page);
4050
        }
4051
    }
4052
}
4053

    
4054
void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
4055
{
4056
    ppcemb_tlb_t *tlb;
4057

    
4058
    LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
4059
              val);
4060
    entry &= PPC4XX_TLB_ENTRY_MASK;
4061
    tlb = &env->tlb.tlbe[entry];
4062
    tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
4063
    tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
4064
    tlb->prot = PAGE_READ;
4065
    if (val & PPC4XX_TLBLO_EX) {
4066
        tlb->prot |= PAGE_EXEC;
4067
    }
4068
    if (val & PPC4XX_TLBLO_WR) {
4069
        tlb->prot |= PAGE_WRITE;
4070
    }
4071
    LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
4072
              " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
4073
              (int)entry, tlb->RPN, tlb->EPN, tlb->size,
4074
              tlb->prot & PAGE_READ ? 'r' : '-',
4075
              tlb->prot & PAGE_WRITE ? 'w' : '-',
4076
              tlb->prot & PAGE_EXEC ? 'x' : '-',
4077
              tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
4078
}
4079

    
4080
target_ulong helper_4xx_tlbsx (target_ulong address)
4081
{
4082
    return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
4083
}
4084

    
4085
/* PowerPC 440 TLB management */
4086
void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
4087
{
4088
    ppcemb_tlb_t *tlb;
4089
    target_ulong EPN, RPN, size;
4090
    int do_flush_tlbs;
4091

    
4092
    LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
4093
              __func__, word, (int)entry, value);
4094
    do_flush_tlbs = 0;
4095
    entry &= 0x3F;
4096
    tlb = &env->tlb.tlbe[entry];
4097
    switch (word) {
4098
    default:
4099
        /* Just here to please gcc */
4100
    case 0:
4101
        EPN = value & 0xFFFFFC00;
4102
        if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
4103
            do_flush_tlbs = 1;
4104
        tlb->EPN = EPN;
4105
        size = booke_tlb_to_page_size((value >> 4) & 0xF);
4106
        if ((tlb->prot & PAGE_VALID) && tlb->size < size)
4107
            do_flush_tlbs = 1;
4108
        tlb->size = size;
4109
        tlb->attr &= ~0x1;
4110
        tlb->attr |= (value >> 8) & 1;
4111
        if (value & 0x200) {
4112
            tlb->prot |= PAGE_VALID;
4113
        } else {
4114
            if (tlb->prot & PAGE_VALID) {
4115
                tlb->prot &= ~PAGE_VALID;
4116
                do_flush_tlbs = 1;
4117
            }
4118
        }
4119
        tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
4120
        if (do_flush_tlbs)
4121
            tlb_flush(env, 1);
4122
        break;
4123
    case 1:
4124
        RPN = value & 0xFFFFFC0F;
4125
        if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
4126
            tlb_flush(env, 1);
4127
        tlb->RPN = RPN;
4128
        break;
4129
    case 2:
4130
        tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
4131
        tlb->prot = tlb->prot & PAGE_VALID;
4132
        if (value & 0x1)
4133
            tlb->prot |= PAGE_READ << 4;
4134
        if (value & 0x2)
4135
            tlb->prot |= PAGE_WRITE << 4;
4136
        if (value & 0x4)
4137
            tlb->prot |= PAGE_EXEC << 4;
4138
        if (value & 0x8)
4139
            tlb->prot |= PAGE_READ;
4140
        if (value & 0x10)
4141
            tlb->prot |= PAGE_WRITE;
4142
        if (value & 0x20)
4143
            tlb->prot |= PAGE_EXEC;
4144
        break;
4145
    }
4146
}
4147

    
4148
target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
4149
{
4150
    ppcemb_tlb_t *tlb;
4151
    target_ulong ret;
4152
    int size;
4153

    
4154
    entry &= 0x3F;
4155
    tlb = &env->tlb.tlbe[entry];
4156
    switch (word) {
4157
    default:
4158
        /* Just here to please gcc */
4159
    case 0:
4160
        ret = tlb->EPN;
4161
        size = booke_page_size_to_tlb(tlb->size);
4162
        if (size < 0 || size > 0xF)
4163
            size = 1;
4164
        ret |= size << 4;
4165
        if (tlb->attr & 0x1)
4166
            ret |= 0x100;
4167
        if (tlb->prot & PAGE_VALID)
4168
            ret |= 0x200;
4169
        env->spr[SPR_440_MMUCR] &= ~0x000000FF;
4170
        env->spr[SPR_440_MMUCR] |= tlb->PID;
4171
        break;
4172
    case 1:
4173
        ret = tlb->RPN;
4174
        break;
4175
    case 2:
4176
        ret = tlb->attr & ~0x1;
4177
        if (tlb->prot & (PAGE_READ << 4))
4178
            ret |= 0x1;
4179
        if (tlb->prot & (PAGE_WRITE << 4))
4180
            ret |= 0x2;
4181
        if (tlb->prot & (PAGE_EXEC << 4))
4182
            ret |= 0x4;
4183
        if (tlb->prot & PAGE_READ)
4184
            ret |= 0x8;
4185
        if (tlb->prot & PAGE_WRITE)
4186
            ret |= 0x10;
4187
        if (tlb->prot & PAGE_EXEC)
4188
            ret |= 0x20;
4189
        break;
4190
    }
4191
    return ret;
4192
}
4193

    
4194
target_ulong helper_440_tlbsx (target_ulong address)
4195
{
4196
    return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
4197
}
4198

    
4199
/* PowerPC BookE 2.06 TLB management */
4200

    
4201
static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env)
4202
{
4203
    uint32_t tlbncfg = 0;
4204
    int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
4205
    int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
4206
    int tlb;
4207

    
4208
    tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
4209
    tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
4210

    
4211
    if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
4212
        cpu_abort(env, "we don't support HES yet\n");
4213
    }
4214

    
4215
    return booke206_get_tlbm(env, tlb, ea, esel);
4216
}
4217

    
4218
void helper_booke_setpid(uint32_t pidn, target_ulong pid)
4219
{
4220
    env->spr[pidn] = pid;
4221
    /* changing PIDs mean we're in a different address space now */
4222
    tlb_flush(env, 1);
4223
}
4224

    
4225
void helper_booke206_tlbwe(void)
4226
{
4227
    uint32_t tlbncfg, tlbn;
4228
    ppcmas_tlb_t *tlb;
4229
    uint32_t size_tlb, size_ps;
4230

    
4231
    switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
4232
    case MAS0_WQ_ALWAYS:
4233
        /* good to go, write that entry */
4234
        break;
4235
    case MAS0_WQ_COND:
4236
        /* XXX check if reserved */
4237
        if (0) {
4238
            return;
4239
        }
4240
        break;
4241
    case MAS0_WQ_CLR_RSRV:
4242
        /* XXX clear entry */
4243
        return;
4244
    default:
4245
        /* no idea what to do */
4246
        return;
4247
    }
4248

    
4249
    if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
4250
         !msr_gs) {
4251
        /* XXX we don't support direct LRAT setting yet */
4252
        fprintf(stderr, "cpu: don't support LRAT setting yet\n");
4253
        return;
4254
    }
4255

    
4256
    tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
4257
    tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
4258

    
4259
    tlb = booke206_cur_tlb(env);
4260

    
4261
    if (!tlb) {
4262
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
4263
                                   POWERPC_EXCP_INVAL |
4264
                                   POWERPC_EXCP_INVAL_INVAL);
4265
    }
4266

    
4267
    /* check that we support the targeted size */
4268
    size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
4269
    size_ps = booke206_tlbnps(env, tlbn);
4270
    if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
4271
        !(size_ps & (1 << size_tlb))) {
4272
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
4273
                                   POWERPC_EXCP_INVAL |
4274
                                   POWERPC_EXCP_INVAL_INVAL);
4275
    }
4276

    
4277
    if (msr_gs) {
4278
        cpu_abort(env, "missing HV implementation\n");
4279
    }
4280
    tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
4281
                  env->spr[SPR_BOOKE_MAS3];
4282
    tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
4283

    
4284
    /* MAV 1.0 only */
4285
    if (!(tlbncfg & TLBnCFG_AVAIL)) {
4286
        /* force !AVAIL TLB entries to correct page size */
4287
        tlb->mas1 &= ~MAS1_TSIZE_MASK;
4288
        /* XXX can be configured in MMUCSR0 */
4289
        tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
4290
    }
4291

    
4292
    /* XXX needs to change when supporting 64-bit e500 */
4293
    tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & 0xffffffff;
4294

    
4295
    if (!(tlbncfg & TLBnCFG_IPROT)) {
4296
        /* no IPROT supported by TLB */
4297
        tlb->mas1 &= ~MAS1_IPROT;
4298
    }
4299

    
4300
    if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
4301
        tlb_flush_page(env, tlb->mas2 & MAS2_EPN_MASK);
4302
    } else {
4303
        tlb_flush(env, 1);
4304
    }
4305
}
4306

    
4307
static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb)
4308
{
4309
    int tlbn = booke206_tlbm_to_tlbn(env, tlb);
4310
    int way = booke206_tlbm_to_way(env, tlb);
4311

    
4312
    env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
4313
    env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
4314
    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
4315

    
4316
    env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
4317
    env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
4318
    env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
4319
    env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
4320
}
4321

    
4322
void helper_booke206_tlbre(void)
4323
{
4324
    ppcmas_tlb_t *tlb = NULL;
4325

    
4326
    tlb = booke206_cur_tlb(env);
4327
    if (!tlb) {
4328
        env->spr[SPR_BOOKE_MAS1] = 0;
4329
    } else {
4330
        booke206_tlb_to_mas(env, tlb);
4331
    }
4332
}
4333

    
4334
void helper_booke206_tlbsx(target_ulong address)
4335
{
4336
    ppcmas_tlb_t *tlb = NULL;
4337
    int i, j;
4338
    target_phys_addr_t raddr;
4339
    uint32_t spid, sas;
4340

    
4341
    spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
4342
    sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
4343

    
4344
    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
4345
        int ways = booke206_tlb_ways(env, i);
4346

    
4347
        for (j = 0; j < ways; j++) {
4348
            tlb = booke206_get_tlbm(env, i, address, j);
4349

    
4350
            if (!tlb) {
4351
                continue;
4352
            }
4353

    
4354
            if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
4355
                continue;
4356
            }
4357

    
4358
            if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
4359
                continue;
4360
            }
4361

    
4362
            booke206_tlb_to_mas(env, tlb);
4363
            return;
4364
        }
4365
    }
4366

    
4367
    /* no entry found, fill with defaults */
4368
    env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
4369
    env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
4370
    env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
4371
    env->spr[SPR_BOOKE_MAS3] = 0;
4372
    env->spr[SPR_BOOKE_MAS7] = 0;
4373

    
4374
    if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
4375
        env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
4376
    }
4377

    
4378
    env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
4379
                                << MAS1_TID_SHIFT;
4380

    
4381
    /* next victim logic */
4382
    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
4383
    env->last_way++;
4384
    env->last_way &= booke206_tlb_ways(env, 0) - 1;
4385
    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
4386
}
4387

    
4388
static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn,
4389
                                              uint32_t ea)
4390
{
4391
    int i;
4392
    int ways = booke206_tlb_ways(env, tlbn);
4393
    target_ulong mask;
4394

    
4395
    for (i = 0; i < ways; i++) {
4396
        ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
4397
        if (!tlb) {
4398
            continue;
4399
        }
4400
        mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
4401
        if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
4402
            !(tlb->mas1 & MAS1_IPROT)) {
4403
            tlb->mas1 &= ~MAS1_VALID;
4404
        }
4405
    }
4406
}
4407

    
4408
void helper_booke206_tlbivax(target_ulong address)
4409
{
4410
    if (address & 0x4) {
4411
        /* flush all entries */
4412
        if (address & 0x8) {
4413
            /* flush all of TLB1 */
4414
            booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
4415
        } else {
4416
            /* flush all of TLB0 */
4417
            booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
4418
        }
4419
        return;
4420
    }
4421

    
4422
    if (address & 0x8) {
4423
        /* flush TLB1 entries */
4424
        booke206_invalidate_ea_tlb(env, 1, address);
4425
        tlb_flush(env, 1);
4426
    } else {
4427
        /* flush TLB0 entries */
4428
        booke206_invalidate_ea_tlb(env, 0, address);
4429
        tlb_flush_page(env, address & MAS2_EPN_MASK);
4430
    }
4431
}
4432

    
4433
void helper_booke206_tlbilx0(target_ulong address)
4434
{
4435
    /* XXX missing LPID handling */
4436
    booke206_flush_tlb(env, -1, 1);
4437
}
4438

    
4439
void helper_booke206_tlbilx1(target_ulong address)
4440
{
4441
    int i, j;
4442
    int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
4443
    ppcmas_tlb_t *tlb = env->tlb.tlbm;
4444
    int tlb_size;
4445

    
4446
    /* XXX missing LPID handling */
4447
    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
4448
        tlb_size = booke206_tlb_size(env, i);
4449
        for (j = 0; j < tlb_size; j++) {
4450
            if (!(tlb[j].mas1 & MAS1_IPROT) &&
4451
                ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
4452
                tlb[j].mas1 &= ~MAS1_VALID;
4453
            }
4454
        }
4455
        tlb += booke206_tlb_size(env, i);
4456
    }
4457
    tlb_flush(env, 1);
4458
}
4459

    
4460
void helper_booke206_tlbilx3(target_ulong address)
4461
{
4462
    int i, j;
4463
    ppcmas_tlb_t *tlb;
4464
    int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
4465
    int pid = tid >> MAS6_SPID_SHIFT;
4466
    int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
4467
    int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
4468
    /* XXX check for unsupported isize and raise an invalid opcode then */
4469
    int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
4470
    /* XXX implement MAV2 handling */
4471
    bool mav2 = false;
4472

    
4473
    /* XXX missing LPID handling */
4474
    /* flush by pid and ea */
4475
    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
4476
        int ways = booke206_tlb_ways(env, i);
4477

    
4478
        for (j = 0; j < ways; j++) {
4479
            tlb = booke206_get_tlbm(env, i, address, j);
4480
            if (!tlb) {
4481
                continue;
4482
            }
4483
            if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
4484
                (tlb->mas1 & MAS1_IPROT) ||
4485
                ((tlb->mas1 & MAS1_IND) != ind) ||
4486
                ((tlb->mas8 & MAS8_TGS) != sgs)) {
4487
                continue;
4488
            }
4489
            if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
4490
                /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
4491
                continue;
4492
            }
4493
            /* XXX e500mc doesn't match SAS, but other cores might */
4494
            tlb->mas1 &= ~MAS1_VALID;
4495
        }
4496
    }
4497
    tlb_flush(env, 1);
4498
}
4499

    
4500
void helper_booke206_tlbflush(uint32_t type)
4501
{
4502
    int flags = 0;
4503

    
4504
    if (type & 2) {
4505
        flags |= BOOKE206_FLUSH_TLB1;
4506
    }
4507

    
4508
    if (type & 4) {
4509
        flags |= BOOKE206_FLUSH_TLB0;
4510
    }
4511

    
4512
    booke206_flush_tlb(env, flags, 1);
4513
}
4514

    
4515
/* Embedded.Processor Control */
4516
static int dbell2irq(target_ulong rb)
4517
{
4518
    int msg = rb & DBELL_TYPE_MASK;
4519
    int irq = -1;
4520

    
4521
    switch (msg) {
4522
    case DBELL_TYPE_DBELL:
4523
        irq = PPC_INTERRUPT_DOORBELL;
4524
        break;
4525
    case DBELL_TYPE_DBELL_CRIT:
4526
        irq = PPC_INTERRUPT_CDOORBELL;
4527
        break;
4528
    case DBELL_TYPE_G_DBELL:
4529
    case DBELL_TYPE_G_DBELL_CRIT:
4530
    case DBELL_TYPE_G_DBELL_MC:
4531
        /* XXX implement */
4532
    default:
4533
        break;
4534
    }
4535

    
4536
    return irq;
4537
}
4538

    
4539
void helper_msgclr(target_ulong rb)
4540
{
4541
    int irq = dbell2irq(rb);
4542

    
4543
    if (irq < 0) {
4544
        return;
4545
    }
4546

    
4547
    env->pending_interrupts &= ~(1 << irq);
4548
}
4549

    
4550
void helper_msgsnd(target_ulong rb)
4551
{
4552
    int irq = dbell2irq(rb);
4553
    int pir = rb & DBELL_PIRTAG_MASK;
4554
    CPUPPCState *cenv;
4555

    
4556
    if (irq < 0) {
4557
        return;
4558
    }
4559

    
4560
    for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) {
4561
        if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
4562
            cenv->pending_interrupts |= 1 << irq;
4563
            cpu_interrupt(cenv, CPU_INTERRUPT_HARD);
4564
        }
4565
    }
4566
}
4567

    
4568
#endif /* !CONFIG_USER_ONLY */