Statistics
| Branch: | Revision:

root / target-ppc / op_helper.c @ 651721b2

History | View | Annotate | Download (123.8 kB)

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

    
25
#include "helper_regs.h"
26

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

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

    
37

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

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

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

    
56
/*****************************************************************************/
57
/* SPR accesses */
58
void helper_load_dump_spr (uint32_t sprn)
59
{
60
    qemu_log("Read SPR %d %03x => " ADDRX "\n",
61
                sprn, sprn, env->spr[sprn]);
62
}
63

    
64
void helper_store_dump_spr (uint32_t sprn)
65
{
66
    qemu_log("Write SPR %d %03x <= " ADDRX "\n",
67
                sprn, sprn, env->spr[sprn]);
68
}
69

    
70
target_ulong helper_load_tbl (void)
71
{
72
    return cpu_ppc_load_tbl(env);
73
}
74

    
75
target_ulong helper_load_tbu (void)
76
{
77
    return cpu_ppc_load_tbu(env);
78
}
79

    
80
target_ulong helper_load_atbl (void)
81
{
82
    return cpu_ppc_load_atbl(env);
83
}
84

    
85
target_ulong helper_load_atbu (void)
86
{
87
    return cpu_ppc_load_atbu(env);
88
}
89

    
90
target_ulong helper_load_601_rtcl (void)
91
{
92
    return cpu_ppc601_load_rtcl(env);
93
}
94

    
95
target_ulong helper_load_601_rtcu (void)
96
{
97
    return cpu_ppc601_load_rtcu(env);
98
}
99

    
100
#if !defined(CONFIG_USER_ONLY)
101
#if defined (TARGET_PPC64)
102
void helper_store_asr (target_ulong val)
103
{
104
    ppc_store_asr(env, val);
105
}
106
#endif
107

    
108
void helper_store_sdr1 (target_ulong val)
109
{
110
    ppc_store_sdr1(env, val);
111
}
112

    
113
void helper_store_tbl (target_ulong val)
114
{
115
    cpu_ppc_store_tbl(env, val);
116
}
117

    
118
void helper_store_tbu (target_ulong val)
119
{
120
    cpu_ppc_store_tbu(env, val);
121
}
122

    
123
void helper_store_atbl (target_ulong val)
124
{
125
    cpu_ppc_store_atbl(env, val);
126
}
127

    
128
void helper_store_atbu (target_ulong val)
129
{
130
    cpu_ppc_store_atbu(env, val);
131
}
132

    
133
void helper_store_601_rtcl (target_ulong val)
134
{
135
    cpu_ppc601_store_rtcl(env, val);
136
}
137

    
138
void helper_store_601_rtcu (target_ulong val)
139
{
140
    cpu_ppc601_store_rtcu(env, val);
141
}
142

    
143
target_ulong helper_load_decr (void)
144
{
145
    return cpu_ppc_load_decr(env);
146
}
147

    
148
void helper_store_decr (target_ulong val)
149
{
150
    cpu_ppc_store_decr(env, val);
151
}
152

    
153
void helper_store_hid0_601 (target_ulong val)
154
{
155
    target_ulong hid0;
156

    
157
    hid0 = env->spr[SPR_HID0];
158
    if ((val ^ hid0) & 0x00000008) {
159
        /* Change current endianness */
160
        env->hflags &= ~(1 << MSR_LE);
161
        env->hflags_nmsr &= ~(1 << MSR_LE);
162
        env->hflags_nmsr |= (1 << MSR_LE) & (((val >> 3) & 1) << MSR_LE);
163
        env->hflags |= env->hflags_nmsr;
164
        qemu_log("%s: set endianness to %c => " ADDRX "\n",
165
                    __func__, val & 0x8 ? 'l' : 'b', env->hflags);
166
    }
167
    env->spr[SPR_HID0] = (uint32_t)val;
168
}
169

    
170
void helper_store_403_pbr (uint32_t num, target_ulong value)
171
{
172
    if (likely(env->pb[num] != value)) {
173
        env->pb[num] = value;
174
        /* Should be optimized */
175
        tlb_flush(env, 1);
176
    }
177
}
178

    
179
target_ulong helper_load_40x_pit (void)
180
{
181
    return load_40x_pit(env);
182
}
183

    
184
void helper_store_40x_pit (target_ulong val)
185
{
186
    store_40x_pit(env, val);
187
}
188

    
189
void helper_store_40x_dbcr0 (target_ulong val)
190
{
191
    store_40x_dbcr0(env, val);
192
}
193

    
194
void helper_store_40x_sler (target_ulong val)
195
{
196
    store_40x_sler(env, val);
197
}
198

    
199
void helper_store_booke_tcr (target_ulong val)
200
{
201
    store_booke_tcr(env, val);
202
}
203

    
204
void helper_store_booke_tsr (target_ulong val)
205
{
206
    store_booke_tsr(env, val);
207
}
208

    
209
void helper_store_ibatu (uint32_t nr, target_ulong val)
210
{
211
    ppc_store_ibatu(env, nr, val);
212
}
213

    
214
void helper_store_ibatl (uint32_t nr, target_ulong val)
215
{
216
    ppc_store_ibatl(env, nr, val);
217
}
218

    
219
void helper_store_dbatu (uint32_t nr, target_ulong val)
220
{
221
    ppc_store_dbatu(env, nr, val);
222
}
223

    
224
void helper_store_dbatl (uint32_t nr, target_ulong val)
225
{
226
    ppc_store_dbatl(env, nr, val);
227
}
228

    
229
void helper_store_601_batl (uint32_t nr, target_ulong val)
230
{
231
    ppc_store_ibatl_601(env, nr, val);
232
}
233

    
234
void helper_store_601_batu (uint32_t nr, target_ulong val)
235
{
236
    ppc_store_ibatu_601(env, nr, val);
237
}
238
#endif
239

    
240
/*****************************************************************************/
241
/* Memory load and stores */
242

    
243
static always_inline target_ulong addr_add(target_ulong addr, target_long arg)
244
{
245
#if defined(TARGET_PPC64)
246
        if (!msr_sf)
247
            return (uint32_t)(addr + arg);
248
        else
249
#endif
250
            return addr + arg;
251
}
252

    
253
void helper_lmw (target_ulong addr, uint32_t reg)
254
{
255
    for (; reg < 32; reg++) {
256
        if (msr_le)
257
            env->gpr[reg] = bswap32(ldl(addr));
258
        else
259
            env->gpr[reg] = ldl(addr);
260
        addr = addr_add(addr, 4);
261
    }
262
}
263

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

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

    
310
void helper_stsw(target_ulong addr, uint32_t nb, uint32_t reg)
311
{
312
    int sh;
313
    for (; nb > 3; nb -= 4) {
314
        stl(addr, env->gpr[reg]);
315
        reg = (reg + 1) % 32;
316
        addr = addr_add(addr, 4);
317
    }
318
    if (unlikely(nb > 0)) {
319
        for (sh = 24; nb > 0; nb--, sh -= 8) {
320
            stb(addr, (env->gpr[reg] >> sh) & 0xFF);
321
            addr = addr_add(addr, 1);
322
        }
323
    }
324
}
325

    
326
static void do_dcbz(target_ulong addr, int dcache_line_size)
327
{
328
    addr &= ~(dcache_line_size - 1);
329
    int i;
330
    for (i = 0 ; i < dcache_line_size ; i += 4) {
331
        stl(addr + i , 0);
332
    }
333
    if (env->reserve == addr)
334
        env->reserve = (target_ulong)-1ULL;
335
}
336

    
337
void helper_dcbz(target_ulong addr)
338
{
339
    do_dcbz(addr, env->dcache_line_size);
340
}
341

    
342
void helper_dcbz_970(target_ulong addr)
343
{
344
    if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1)
345
        do_dcbz(addr, 32);
346
    else
347
        do_dcbz(addr, env->dcache_line_size);
348
}
349

    
350
void helper_icbi(target_ulong addr)
351
{
352
    uint32_t tmp;
353

    
354
    addr &= ~(env->dcache_line_size - 1);
355
    /* Invalidate one cache line :
356
     * PowerPC specification says this is to be treated like a load
357
     * (not a fetch) by the MMU. To be sure it will be so,
358
     * do the load "by hand".
359
     */
360
    tmp = ldl(addr);
361
    tb_invalidate_page_range(addr, addr + env->icache_line_size);
362
}
363

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

    
389
/*****************************************************************************/
390
/* Fixed point operations helpers */
391
#if defined(TARGET_PPC64)
392

    
393
/* multiply high word */
394
uint64_t helper_mulhd (uint64_t arg1, uint64_t arg2)
395
{
396
    uint64_t tl, th;
397

    
398
    muls64(&tl, &th, arg1, arg2);
399
    return th;
400
}
401

    
402
/* multiply high word unsigned */
403
uint64_t helper_mulhdu (uint64_t arg1, uint64_t arg2)
404
{
405
    uint64_t tl, th;
406

    
407
    mulu64(&tl, &th, arg1, arg2);
408
    return th;
409
}
410

    
411
uint64_t helper_mulldo (uint64_t arg1, uint64_t arg2)
412
{
413
    int64_t th;
414
    uint64_t tl;
415

    
416
    muls64(&tl, (uint64_t *)&th, arg1, arg2);
417
    /* If th != 0 && th != -1, then we had an overflow */
418
    if (likely((uint64_t)(th + 1) <= 1)) {
419
        env->xer &= ~(1 << XER_OV);
420
    } else {
421
        env->xer |= (1 << XER_OV) | (1 << XER_SO);
422
    }
423
    return (int64_t)tl;
424
}
425
#endif
426

    
427
target_ulong helper_cntlzw (target_ulong t)
428
{
429
    return clz32(t);
430
}
431

    
432
#if defined(TARGET_PPC64)
433
target_ulong helper_cntlzd (target_ulong t)
434
{
435
    return clz64(t);
436
}
437
#endif
438

    
439
/* shift right arithmetic helper */
440
target_ulong helper_sraw (target_ulong value, target_ulong shift)
441
{
442
    int32_t ret;
443

    
444
    if (likely(!(shift & 0x20))) {
445
        if (likely((uint32_t)shift != 0)) {
446
            shift &= 0x1f;
447
            ret = (int32_t)value >> shift;
448
            if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
449
                env->xer &= ~(1 << XER_CA);
450
            } else {
451
                env->xer |= (1 << XER_CA);
452
            }
453
        } else {
454
            ret = (int32_t)value;
455
            env->xer &= ~(1 << XER_CA);
456
        }
457
    } else {
458
        ret = (int32_t)value >> 31;
459
        if (ret) {
460
            env->xer |= (1 << XER_CA);
461
        } else {
462
            env->xer &= ~(1 << XER_CA);
463
        }
464
    }
465
    return (target_long)ret;
466
}
467

    
468
#if defined(TARGET_PPC64)
469
target_ulong helper_srad (target_ulong value, target_ulong shift)
470
{
471
    int64_t ret;
472

    
473
    if (likely(!(shift & 0x40))) {
474
        if (likely((uint64_t)shift != 0)) {
475
            shift &= 0x3f;
476
            ret = (int64_t)value >> shift;
477
            if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
478
                env->xer &= ~(1 << XER_CA);
479
            } else {
480
                env->xer |= (1 << XER_CA);
481
            }
482
        } else {
483
            ret = (int64_t)value;
484
            env->xer &= ~(1 << XER_CA);
485
        }
486
    } else {
487
        ret = (int64_t)value >> 63;
488
        if (ret) {
489
            env->xer |= (1 << XER_CA);
490
        } else {
491
            env->xer &= ~(1 << XER_CA);
492
        }
493
    }
494
    return ret;
495
}
496
#endif
497

    
498
target_ulong helper_popcntb (target_ulong val)
499
{
500
    val = (val & 0x55555555) + ((val >>  1) & 0x55555555);
501
    val = (val & 0x33333333) + ((val >>  2) & 0x33333333);
502
    val = (val & 0x0f0f0f0f) + ((val >>  4) & 0x0f0f0f0f);
503
    return val;
504
}
505

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

    
516
/*****************************************************************************/
517
/* Floating point operations helpers */
518
uint64_t helper_float32_to_float64(uint32_t arg)
519
{
520
    CPU_FloatU f;
521
    CPU_DoubleU d;
522
    f.l = arg;
523
    d.d = float32_to_float64(f.f, &env->fp_status);
524
    return d.ll;
525
}
526

    
527
uint32_t helper_float64_to_float32(uint64_t arg)
528
{
529
    CPU_FloatU f;
530
    CPU_DoubleU d;
531
    d.ll = arg;
532
    f.f = float64_to_float32(d.d, &env->fp_status);
533
    return f.l;
534
}
535

    
536
static always_inline int isden (float64 d)
537
{
538
    CPU_DoubleU u;
539

    
540
    u.d = d;
541

    
542
    return ((u.ll >> 52) & 0x7FF) == 0;
543
}
544

    
545
uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf)
546
{
547
    CPU_DoubleU farg;
548
    int isneg;
549
    int ret;
550
    farg.ll = arg;
551
    isneg = float64_is_neg(farg.d);
552
    if (unlikely(float64_is_nan(farg.d))) {
553
        if (float64_is_signaling_nan(farg.d)) {
554
            /* Signaling NaN: flags are undefined */
555
            ret = 0x00;
556
        } else {
557
            /* Quiet NaN */
558
            ret = 0x11;
559
        }
560
    } else if (unlikely(float64_is_infinity(farg.d))) {
561
        /* +/- infinity */
562
        if (isneg)
563
            ret = 0x09;
564
        else
565
            ret = 0x05;
566
    } else {
567
        if (float64_is_zero(farg.d)) {
568
            /* +/- zero */
569
            if (isneg)
570
                ret = 0x12;
571
            else
572
                ret = 0x02;
573
        } else {
574
            if (isden(farg.d)) {
575
                /* Denormalized numbers */
576
                ret = 0x10;
577
            } else {
578
                /* Normalized numbers */
579
                ret = 0x00;
580
            }
581
            if (isneg) {
582
                ret |= 0x08;
583
            } else {
584
                ret |= 0x04;
585
            }
586
        }
587
    }
588
    if (set_fprf) {
589
        /* We update FPSCR_FPRF */
590
        env->fpscr &= ~(0x1F << FPSCR_FPRF);
591
        env->fpscr |= ret << FPSCR_FPRF;
592
    }
593
    /* We just need fpcc to update Rc1 */
594
    return ret & 0xF;
595
}
596

    
597
/* Floating-point invalid operations exception */
598
static always_inline uint64_t fload_invalid_op_excp (int op)
599
{
600
    uint64_t ret = 0;
601
    int ve;
602

    
603
    ve = fpscr_ve;
604
    switch (op) {
605
    case POWERPC_EXCP_FP_VXSNAN:
606
        env->fpscr |= 1 << FPSCR_VXSNAN;
607
        break;
608
    case POWERPC_EXCP_FP_VXSOFT:
609
        env->fpscr |= 1 << FPSCR_VXSOFT;
610
        break;
611
    case POWERPC_EXCP_FP_VXISI:
612
        /* Magnitude subtraction of infinities */
613
        env->fpscr |= 1 << FPSCR_VXISI;
614
        goto update_arith;
615
    case POWERPC_EXCP_FP_VXIDI:
616
        /* Division of infinity by infinity */
617
        env->fpscr |= 1 << FPSCR_VXIDI;
618
        goto update_arith;
619
    case POWERPC_EXCP_FP_VXZDZ:
620
        /* Division of zero by zero */
621
        env->fpscr |= 1 << FPSCR_VXZDZ;
622
        goto update_arith;
623
    case POWERPC_EXCP_FP_VXIMZ:
624
        /* Multiplication of zero by infinity */
625
        env->fpscr |= 1 << FPSCR_VXIMZ;
626
        goto update_arith;
627
    case POWERPC_EXCP_FP_VXVC:
628
        /* Ordered comparison of NaN */
629
        env->fpscr |= 1 << FPSCR_VXVC;
630
        env->fpscr &= ~(0xF << FPSCR_FPCC);
631
        env->fpscr |= 0x11 << FPSCR_FPCC;
632
        /* We must update the target FPR before raising the exception */
633
        if (ve != 0) {
634
            env->exception_index = POWERPC_EXCP_PROGRAM;
635
            env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
636
            /* Update the floating-point enabled exception summary */
637
            env->fpscr |= 1 << FPSCR_FEX;
638
            /* Exception is differed */
639
            ve = 0;
640
        }
641
        break;
642
    case POWERPC_EXCP_FP_VXSQRT:
643
        /* Square root of a negative number */
644
        env->fpscr |= 1 << FPSCR_VXSQRT;
645
    update_arith:
646
        env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
647
        if (ve == 0) {
648
            /* Set the result to quiet NaN */
649
            ret = 0xFFF8000000000000ULL;
650
            env->fpscr &= ~(0xF << FPSCR_FPCC);
651
            env->fpscr |= 0x11 << FPSCR_FPCC;
652
        }
653
        break;
654
    case POWERPC_EXCP_FP_VXCVI:
655
        /* Invalid conversion */
656
        env->fpscr |= 1 << FPSCR_VXCVI;
657
        env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
658
        if (ve == 0) {
659
            /* Set the result to quiet NaN */
660
            ret = 0xFFF8000000000000ULL;
661
            env->fpscr &= ~(0xF << FPSCR_FPCC);
662
            env->fpscr |= 0x11 << FPSCR_FPCC;
663
        }
664
        break;
665
    }
666
    /* Update the floating-point invalid operation summary */
667
    env->fpscr |= 1 << FPSCR_VX;
668
    /* Update the floating-point exception summary */
669
    env->fpscr |= 1 << FPSCR_FX;
670
    if (ve != 0) {
671
        /* Update the floating-point enabled exception summary */
672
        env->fpscr |= 1 << FPSCR_FEX;
673
        if (msr_fe0 != 0 || msr_fe1 != 0)
674
            helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | op);
675
    }
676
    return ret;
677
}
678

    
679
static always_inline void float_zero_divide_excp (void)
680
{
681
    env->fpscr |= 1 << FPSCR_ZX;
682
    env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
683
    /* Update the floating-point exception summary */
684
    env->fpscr |= 1 << FPSCR_FX;
685
    if (fpscr_ze != 0) {
686
        /* Update the floating-point enabled exception summary */
687
        env->fpscr |= 1 << FPSCR_FEX;
688
        if (msr_fe0 != 0 || msr_fe1 != 0) {
689
            helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
690
                                       POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
691
        }
692
    }
693
}
694

    
695
static always_inline void float_overflow_excp (void)
696
{
697
    env->fpscr |= 1 << FPSCR_OX;
698
    /* Update the floating-point exception summary */
699
    env->fpscr |= 1 << FPSCR_FX;
700
    if (fpscr_oe != 0) {
701
        /* XXX: should adjust the result */
702
        /* Update the floating-point enabled exception summary */
703
        env->fpscr |= 1 << FPSCR_FEX;
704
        /* We must update the target FPR before raising the exception */
705
        env->exception_index = POWERPC_EXCP_PROGRAM;
706
        env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
707
    } else {
708
        env->fpscr |= 1 << FPSCR_XX;
709
        env->fpscr |= 1 << FPSCR_FI;
710
    }
711
}
712

    
713
static always_inline void float_underflow_excp (void)
714
{
715
    env->fpscr |= 1 << FPSCR_UX;
716
    /* Update the floating-point exception summary */
717
    env->fpscr |= 1 << FPSCR_FX;
718
    if (fpscr_ue != 0) {
719
        /* XXX: should adjust the result */
720
        /* Update the floating-point enabled exception summary */
721
        env->fpscr |= 1 << FPSCR_FEX;
722
        /* We must update the target FPR before raising the exception */
723
        env->exception_index = POWERPC_EXCP_PROGRAM;
724
        env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
725
    }
726
}
727

    
728
static always_inline void float_inexact_excp (void)
729
{
730
    env->fpscr |= 1 << FPSCR_XX;
731
    /* Update the floating-point exception summary */
732
    env->fpscr |= 1 << FPSCR_FX;
733
    if (fpscr_xe != 0) {
734
        /* Update the floating-point enabled exception summary */
735
        env->fpscr |= 1 << FPSCR_FEX;
736
        /* We must update the target FPR before raising the exception */
737
        env->exception_index = POWERPC_EXCP_PROGRAM;
738
        env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
739
    }
740
}
741

    
742
static always_inline void fpscr_set_rounding_mode (void)
743
{
744
    int rnd_type;
745

    
746
    /* Set rounding mode */
747
    switch (fpscr_rn) {
748
    case 0:
749
        /* Best approximation (round to nearest) */
750
        rnd_type = float_round_nearest_even;
751
        break;
752
    case 1:
753
        /* Smaller magnitude (round toward zero) */
754
        rnd_type = float_round_to_zero;
755
        break;
756
    case 2:
757
        /* Round toward +infinite */
758
        rnd_type = float_round_up;
759
        break;
760
    default:
761
    case 3:
762
        /* Round toward -infinite */
763
        rnd_type = float_round_down;
764
        break;
765
    }
766
    set_float_rounding_mode(rnd_type, &env->fp_status);
767
}
768

    
769
void helper_fpscr_clrbit (uint32_t bit)
770
{
771
    int prev;
772

    
773
    prev = (env->fpscr >> bit) & 1;
774
    env->fpscr &= ~(1 << bit);
775
    if (prev == 1) {
776
        switch (bit) {
777
        case FPSCR_RN1:
778
        case FPSCR_RN:
779
            fpscr_set_rounding_mode();
780
            break;
781
        default:
782
            break;
783
        }
784
    }
785
}
786

    
787
void helper_fpscr_setbit (uint32_t bit)
788
{
789
    int prev;
790

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

    
902
void helper_store_fpscr (uint64_t arg, uint32_t mask)
903
{
904
    /*
905
     * We use only the 32 LSB of the incoming fpr
906
     */
907
    uint32_t prev, new;
908
    int i;
909

    
910
    prev = env->fpscr;
911
    new = (uint32_t)arg;
912
    new &= ~0x60000000;
913
    new |= prev & 0x60000000;
914
    for (i = 0; i < 8; i++) {
915
        if (mask & (1 << i)) {
916
            env->fpscr &= ~(0xF << (4 * i));
917
            env->fpscr |= new & (0xF << (4 * i));
918
        }
919
    }
920
    /* Update VX and FEX */
921
    if (fpscr_ix != 0)
922
        env->fpscr |= 1 << FPSCR_VX;
923
    else
924
        env->fpscr &= ~(1 << FPSCR_VX);
925
    if ((fpscr_ex & fpscr_eex) != 0) {
926
        env->fpscr |= 1 << FPSCR_FEX;
927
        env->exception_index = POWERPC_EXCP_PROGRAM;
928
        /* XXX: we should compute it properly */
929
        env->error_code = POWERPC_EXCP_FP;
930
    }
931
    else
932
        env->fpscr &= ~(1 << FPSCR_FEX);
933
    fpscr_set_rounding_mode();
934
}
935

    
936
void helper_float_check_status (void)
937
{
938
#ifdef CONFIG_SOFTFLOAT
939
    if (env->exception_index == POWERPC_EXCP_PROGRAM &&
940
        (env->error_code & POWERPC_EXCP_FP)) {
941
        /* Differred floating-point exception after target FPR update */
942
        if (msr_fe0 != 0 || msr_fe1 != 0)
943
            helper_raise_exception_err(env->exception_index, env->error_code);
944
    } else {
945
        int status = get_float_exception_flags(&env->fp_status);
946
        if (status & float_flag_divbyzero) {
947
            float_zero_divide_excp();
948
        } else if (status & float_flag_overflow) {
949
            float_overflow_excp();
950
        } else if (status & float_flag_underflow) {
951
            float_underflow_excp();
952
        } else if (status & float_flag_inexact) {
953
            float_inexact_excp();
954
        }
955
    }
956
#else
957
    if (env->exception_index == POWERPC_EXCP_PROGRAM &&
958
        (env->error_code & POWERPC_EXCP_FP)) {
959
        /* Differred floating-point exception after target FPR update */
960
        if (msr_fe0 != 0 || msr_fe1 != 0)
961
            helper_raise_exception_err(env->exception_index, env->error_code);
962
    }
963
#endif
964
}
965

    
966
#ifdef CONFIG_SOFTFLOAT
967
void helper_reset_fpstatus (void)
968
{
969
    set_float_exception_flags(0, &env->fp_status);
970
}
971
#endif
972

    
973
/* fadd - fadd. */
974
uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
975
{
976
    CPU_DoubleU farg1, farg2;
977

    
978
    farg1.ll = arg1;
979
    farg2.ll = arg2;
980
#if USE_PRECISE_EMULATION
981
    if (unlikely(float64_is_signaling_nan(farg1.d) ||
982
                 float64_is_signaling_nan(farg2.d))) {
983
        /* sNaN addition */
984
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
985
    } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
986
                      float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
987
        /* Magnitude subtraction of infinities */
988
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
989
    } else {
990
        farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
991
    }
992
#else
993
    farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
994
#endif
995
    return farg1.ll;
996
}
997

    
998
/* fsub - fsub. */
999
uint64_t helper_fsub (uint64_t arg1, uint64_t arg2)
1000
{
1001
    CPU_DoubleU farg1, farg2;
1002

    
1003
    farg1.ll = arg1;
1004
    farg2.ll = arg2;
1005
#if USE_PRECISE_EMULATION
1006
{
1007
    if (unlikely(float64_is_signaling_nan(farg1.d) ||
1008
                 float64_is_signaling_nan(farg2.d))) {
1009
        /* sNaN subtraction */
1010
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1011
    } else 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
        farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
1017
    }
1018
}
1019
#else
1020
    farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
1021
#endif
1022
    return farg1.ll;
1023
}
1024

    
1025
/* fmul - fmul. */
1026
uint64_t helper_fmul (uint64_t arg1, uint64_t arg2)
1027
{
1028
    CPU_DoubleU farg1, farg2;
1029

    
1030
    farg1.ll = arg1;
1031
    farg2.ll = arg2;
1032
#if USE_PRECISE_EMULATION
1033
    if (unlikely(float64_is_signaling_nan(farg1.d) ||
1034
                 float64_is_signaling_nan(farg2.d))) {
1035
        /* sNaN multiplication */
1036
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1037
    } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1038
                        (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1039
        /* Multiplication of zero by infinity */
1040
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1041
    } else {
1042
        farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1043
    }
1044
#else
1045
    farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1046
#endif
1047
    return farg1.ll;
1048
}
1049

    
1050
/* fdiv - fdiv. */
1051
uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2)
1052
{
1053
    CPU_DoubleU farg1, farg2;
1054

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

    
1077
/* fabs */
1078
uint64_t helper_fabs (uint64_t arg)
1079
{
1080
    CPU_DoubleU farg;
1081

    
1082
    farg.ll = arg;
1083
    farg.d = float64_abs(farg.d);
1084
    return farg.ll;
1085
}
1086

    
1087
/* fnabs */
1088
uint64_t helper_fnabs (uint64_t arg)
1089
{
1090
    CPU_DoubleU farg;
1091

    
1092
    farg.ll = arg;
1093
    farg.d = float64_abs(farg.d);
1094
    farg.d = float64_chs(farg.d);
1095
    return farg.ll;
1096
}
1097

    
1098
/* fneg */
1099
uint64_t helper_fneg (uint64_t arg)
1100
{
1101
    CPU_DoubleU farg;
1102

    
1103
    farg.ll = arg;
1104
    farg.d = float64_chs(farg.d);
1105
    return farg.ll;
1106
}
1107

    
1108
/* fctiw - fctiw. */
1109
uint64_t helper_fctiw (uint64_t arg)
1110
{
1111
    CPU_DoubleU farg;
1112
    farg.ll = arg;
1113

    
1114
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1115
        /* sNaN conversion */
1116
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1117
    } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
1118
        /* qNan / infinity conversion */
1119
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1120
    } else {
1121
        farg.ll = float64_to_int32(farg.d, &env->fp_status);
1122
#if USE_PRECISE_EMULATION
1123
        /* XXX: higher bits are not supposed to be significant.
1124
         *     to make tests easier, return the same as a real PowerPC 750
1125
         */
1126
        farg.ll |= 0xFFF80000ULL << 32;
1127
#endif
1128
    }
1129
    return farg.ll;
1130
}
1131

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

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

    
1156
#if defined(TARGET_PPC64)
1157
/* fcfid - fcfid. */
1158
uint64_t helper_fcfid (uint64_t arg)
1159
{
1160
    CPU_DoubleU farg;
1161
    farg.d = int64_to_float64(arg, &env->fp_status);
1162
    return farg.ll;
1163
}
1164

    
1165
/* fctid - fctid. */
1166
uint64_t helper_fctid (uint64_t arg)
1167
{
1168
    CPU_DoubleU farg;
1169
    farg.ll = arg;
1170

    
1171
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1172
        /* sNaN conversion */
1173
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1174
    } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
1175
        /* qNan / infinity conversion */
1176
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1177
    } else {
1178
        farg.ll = float64_to_int64(farg.d, &env->fp_status);
1179
    }
1180
    return farg.ll;
1181
}
1182

    
1183
/* fctidz - fctidz. */
1184
uint64_t helper_fctidz (uint64_t arg)
1185
{
1186
    CPU_DoubleU farg;
1187
    farg.ll = arg;
1188

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

    
1201
#endif
1202

    
1203
static always_inline uint64_t do_fri (uint64_t arg, int rounding_mode)
1204
{
1205
    CPU_DoubleU farg;
1206
    farg.ll = arg;
1207

    
1208
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1209
        /* sNaN round */
1210
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1211
    } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
1212
        /* qNan / infinity round */
1213
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1214
    } else {
1215
        set_float_rounding_mode(rounding_mode, &env->fp_status);
1216
        farg.ll = float64_round_to_int(farg.d, &env->fp_status);
1217
        /* Restore rounding mode from FPSCR */
1218
        fpscr_set_rounding_mode();
1219
    }
1220
    return farg.ll;
1221
}
1222

    
1223
uint64_t helper_frin (uint64_t arg)
1224
{
1225
    return do_fri(arg, float_round_nearest_even);
1226
}
1227

    
1228
uint64_t helper_friz (uint64_t arg)
1229
{
1230
    return do_fri(arg, float_round_to_zero);
1231
}
1232

    
1233
uint64_t helper_frip (uint64_t arg)
1234
{
1235
    return do_fri(arg, float_round_up);
1236
}
1237

    
1238
uint64_t helper_frim (uint64_t arg)
1239
{
1240
    return do_fri(arg, float_round_down);
1241
}
1242

    
1243
/* fmadd - fmadd. */
1244
uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1245
{
1246
    CPU_DoubleU farg1, farg2, farg3;
1247

    
1248
    farg1.ll = arg1;
1249
    farg2.ll = arg2;
1250
    farg3.ll = arg3;
1251
#if USE_PRECISE_EMULATION
1252
    if (unlikely(float64_is_signaling_nan(farg1.d) ||
1253
                 float64_is_signaling_nan(farg2.d) ||
1254
                 float64_is_signaling_nan(farg3.d))) {
1255
        /* sNaN operation */
1256
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1257
    } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1258
                        (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1259
        /* Multiplication of zero by infinity */
1260
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1261
    } else {
1262
#ifdef FLOAT128
1263
        /* This is the way the PowerPC specification defines it */
1264
        float128 ft0_128, ft1_128;
1265

    
1266
        ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1267
        ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1268
        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1269
        if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1270
                     float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1271
            /* Magnitude subtraction of infinities */
1272
            farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1273
        } else {
1274
            ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1275
            ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1276
            farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1277
        }
1278
#else
1279
        /* This is OK on x86 hosts */
1280
        farg1.d = (farg1.d * farg2.d) + farg3.d;
1281
#endif
1282
    }
1283
#else
1284
    farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1285
    farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status);
1286
#endif
1287
    return farg1.ll;
1288
}
1289

    
1290
/* fmsub - fmsub. */
1291
uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1292
{
1293
    CPU_DoubleU farg1, farg2, farg3;
1294

    
1295
    farg1.ll = arg1;
1296
    farg2.ll = arg2;
1297
    farg3.ll = arg3;
1298
#if USE_PRECISE_EMULATION
1299
    if (unlikely(float64_is_signaling_nan(farg1.d) ||
1300
                 float64_is_signaling_nan(farg2.d) ||
1301
                 float64_is_signaling_nan(farg3.d))) {
1302
        /* sNaN operation */
1303
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1304
    } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1305
                        (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1306
        /* Multiplication of zero by infinity */
1307
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1308
    } else {
1309
#ifdef FLOAT128
1310
        /* This is the way the PowerPC specification defines it */
1311
        float128 ft0_128, ft1_128;
1312

    
1313
        ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1314
        ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1315
        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1316
        if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1317
                     float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1318
            /* Magnitude subtraction of infinities */
1319
            farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1320
        } else {
1321
            ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1322
            ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1323
            farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1324
        }
1325
#else
1326
        /* This is OK on x86 hosts */
1327
        farg1.d = (farg1.d * farg2.d) - farg3.d;
1328
#endif
1329
    }
1330
#else
1331
    farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1332
    farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status);
1333
#endif
1334
    return farg1.ll;
1335
}
1336

    
1337
/* fnmadd - fnmadd. */
1338
uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1339
{
1340
    CPU_DoubleU farg1, farg2, farg3;
1341

    
1342
    farg1.ll = arg1;
1343
    farg2.ll = arg2;
1344
    farg3.ll = arg3;
1345

    
1346
    if (unlikely(float64_is_signaling_nan(farg1.d) ||
1347
                 float64_is_signaling_nan(farg2.d) ||
1348
                 float64_is_signaling_nan(farg3.d))) {
1349
        /* sNaN operation */
1350
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1351
    } else 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 USE_PRECISE_EMULATION
1357
#ifdef FLOAT128
1358
        /* This is the way the PowerPC specification defines it */
1359
        float128 ft0_128, ft1_128;
1360

    
1361
        ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1362
        ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1363
        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1364
        if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1365
                     float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1366
            /* Magnitude subtraction of infinities */
1367
            farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1368
        } else {
1369
            ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1370
            ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1371
            farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1372
        }
1373
#else
1374
        /* This is OK on x86 hosts */
1375
        farg1.d = (farg1.d * farg2.d) + farg3.d;
1376
#endif
1377
#else
1378
        farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1379
        farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status);
1380
#endif
1381
        if (likely(!float64_is_nan(farg1.d)))
1382
            farg1.d = float64_chs(farg1.d);
1383
    }
1384
    return farg1.ll;
1385
}
1386

    
1387
/* fnmsub - fnmsub. */
1388
uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1389
{
1390
    CPU_DoubleU farg1, farg2, farg3;
1391

    
1392
    farg1.ll = arg1;
1393
    farg2.ll = arg2;
1394
    farg3.ll = arg3;
1395

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

    
1411
        ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1412
        ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1413
        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1414
        if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1415
                     float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1416
            /* Magnitude subtraction of infinities */
1417
            farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1418
        } else {
1419
            ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1420
            ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1421
            farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1422
        }
1423
#else
1424
        /* This is OK on x86 hosts */
1425
        farg1.d = (farg1.d * farg2.d) - farg3.d;
1426
#endif
1427
#else
1428
        farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1429
        farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status);
1430
#endif
1431
        if (likely(!float64_is_nan(farg1.d)))
1432
            farg1.d = float64_chs(farg1.d);
1433
    }
1434
    return farg1.ll;
1435
}
1436

    
1437
/* frsp - frsp. */
1438
uint64_t helper_frsp (uint64_t arg)
1439
{
1440
    CPU_DoubleU farg;
1441
    float32 f32;
1442
    farg.ll = arg;
1443

    
1444
#if USE_PRECISE_EMULATION
1445
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1446
        /* sNaN square root */
1447
       farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1448
    } else {
1449
       f32 = float64_to_float32(farg.d, &env->fp_status);
1450
       farg.d = float32_to_float64(f32, &env->fp_status);
1451
    }
1452
#else
1453
    f32 = float64_to_float32(farg.d, &env->fp_status);
1454
    farg.d = float32_to_float64(f32, &env->fp_status);
1455
#endif
1456
    return farg.ll;
1457
}
1458

    
1459
/* fsqrt - fsqrt. */
1460
uint64_t helper_fsqrt (uint64_t arg)
1461
{
1462
    CPU_DoubleU farg;
1463
    farg.ll = arg;
1464

    
1465
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1466
        /* sNaN square root */
1467
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1468
    } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
1469
        /* Square root of a negative nonzero number */
1470
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
1471
    } else {
1472
        farg.d = float64_sqrt(farg.d, &env->fp_status);
1473
    }
1474
    return farg.ll;
1475
}
1476

    
1477
/* fre - fre. */
1478
uint64_t helper_fre (uint64_t arg)
1479
{
1480
    CPU_DoubleU farg;
1481
    farg.ll = arg;
1482

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

    
1492
/* fres - fres. */
1493
uint64_t helper_fres (uint64_t arg)
1494
{
1495
    CPU_DoubleU farg;
1496
    float32 f32;
1497
    farg.ll = arg;
1498

    
1499
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1500
        /* sNaN reciprocal */
1501
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1502
    } else {
1503
        farg.d = float64_div(float64_one, farg.d, &env->fp_status);
1504
        f32 = float64_to_float32(farg.d, &env->fp_status);
1505
        farg.d = float32_to_float64(f32, &env->fp_status);
1506
    }
1507
    return farg.ll;
1508
}
1509

    
1510
/* frsqrte  - frsqrte. */
1511
uint64_t helper_frsqrte (uint64_t arg)
1512
{
1513
    CPU_DoubleU farg;
1514
    float32 f32;
1515
    farg.ll = arg;
1516

    
1517
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1518
        /* sNaN reciprocal square root */
1519
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1520
    } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
1521
        /* Reciprocal square root of a negative nonzero number */
1522
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
1523
    } else {
1524
        farg.d = float64_sqrt(farg.d, &env->fp_status);
1525
        farg.d = float64_div(float64_one, farg.d, &env->fp_status);
1526
        f32 = float64_to_float32(farg.d, &env->fp_status);
1527
        farg.d = float32_to_float64(f32, &env->fp_status);
1528
    }
1529
    return farg.ll;
1530
}
1531

    
1532
/* fsel - fsel. */
1533
uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1534
{
1535
    CPU_DoubleU farg1;
1536

    
1537
    farg1.ll = arg1;
1538

    
1539
    if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_nan(farg1.d))
1540
        return arg2;
1541
    else
1542
        return arg3;
1543
}
1544

    
1545
void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD)
1546
{
1547
    CPU_DoubleU farg1, farg2;
1548
    uint32_t ret = 0;
1549
    farg1.ll = arg1;
1550
    farg2.ll = arg2;
1551

    
1552
    if (unlikely(float64_is_nan(farg1.d) ||
1553
                 float64_is_nan(farg2.d))) {
1554
        ret = 0x01UL;
1555
    } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1556
        ret = 0x08UL;
1557
    } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1558
        ret = 0x04UL;
1559
    } else {
1560
        ret = 0x02UL;
1561
    }
1562

    
1563
    env->fpscr &= ~(0x0F << FPSCR_FPRF);
1564
    env->fpscr |= ret << FPSCR_FPRF;
1565
    env->crf[crfD] = ret;
1566
    if (unlikely(ret == 0x01UL
1567
                 && (float64_is_signaling_nan(farg1.d) ||
1568
                     float64_is_signaling_nan(farg2.d)))) {
1569
        /* sNaN comparison */
1570
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1571
    }
1572
}
1573

    
1574
void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD)
1575
{
1576
    CPU_DoubleU farg1, farg2;
1577
    uint32_t ret = 0;
1578
    farg1.ll = arg1;
1579
    farg2.ll = arg2;
1580

    
1581
    if (unlikely(float64_is_nan(farg1.d) ||
1582
                 float64_is_nan(farg2.d))) {
1583
        ret = 0x01UL;
1584
    } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1585
        ret = 0x08UL;
1586
    } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1587
        ret = 0x04UL;
1588
    } else {
1589
        ret = 0x02UL;
1590
    }
1591

    
1592
    env->fpscr &= ~(0x0F << FPSCR_FPRF);
1593
    env->fpscr |= ret << FPSCR_FPRF;
1594
    env->crf[crfD] = ret;
1595
    if (unlikely (ret == 0x01UL)) {
1596
        if (float64_is_signaling_nan(farg1.d) ||
1597
            float64_is_signaling_nan(farg2.d)) {
1598
            /* sNaN comparison */
1599
            fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
1600
                                  POWERPC_EXCP_FP_VXVC);
1601
        } else {
1602
            /* qNaN comparison */
1603
            fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
1604
        }
1605
    }
1606
}
1607

    
1608
#if !defined (CONFIG_USER_ONLY)
1609
void helper_store_msr (target_ulong val)
1610
{
1611
    val = hreg_store_msr(env, val, 0);
1612
    if (val != 0) {
1613
        env->interrupt_request |= CPU_INTERRUPT_EXITTB;
1614
        helper_raise_exception(val);
1615
    }
1616
}
1617

    
1618
static always_inline void do_rfi (target_ulong nip, target_ulong msr,
1619
                                    target_ulong msrm, int keep_msrh)
1620
{
1621
#if defined(TARGET_PPC64)
1622
    if (msr & (1ULL << MSR_SF)) {
1623
        nip = (uint64_t)nip;
1624
        msr &= (uint64_t)msrm;
1625
    } else {
1626
        nip = (uint32_t)nip;
1627
        msr = (uint32_t)(msr & msrm);
1628
        if (keep_msrh)
1629
            msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
1630
    }
1631
#else
1632
    nip = (uint32_t)nip;
1633
    msr &= (uint32_t)msrm;
1634
#endif
1635
    /* XXX: beware: this is false if VLE is supported */
1636
    env->nip = nip & ~((target_ulong)0x00000003);
1637
    hreg_store_msr(env, msr, 1);
1638
#if defined (DEBUG_OP)
1639
    cpu_dump_rfi(env->nip, env->msr);
1640
#endif
1641
    /* No need to raise an exception here,
1642
     * as rfi is always the last insn of a TB
1643
     */
1644
    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
1645
}
1646

    
1647
void helper_rfi (void)
1648
{
1649
    do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1650
           ~((target_ulong)0x0), 1);
1651
}
1652

    
1653
#if defined(TARGET_PPC64)
1654
void helper_rfid (void)
1655
{
1656
    do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1657
           ~((target_ulong)0x0), 0);
1658
}
1659

    
1660
void helper_hrfid (void)
1661
{
1662
    do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
1663
           ~((target_ulong)0x0), 0);
1664
}
1665
#endif
1666
#endif
1667

    
1668
void helper_tw (target_ulong arg1, target_ulong arg2, uint32_t flags)
1669
{
1670
    if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
1671
                  ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
1672
                  ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
1673
                  ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
1674
                  ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
1675
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
1676
    }
1677
}
1678

    
1679
#if defined(TARGET_PPC64)
1680
void helper_td (target_ulong arg1, target_ulong arg2, uint32_t flags)
1681
{
1682
    if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
1683
                  ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
1684
                  ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
1685
                  ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
1686
                  ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01)))))
1687
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
1688
}
1689
#endif
1690

    
1691
/*****************************************************************************/
1692
/* PowerPC 601 specific instructions (POWER bridge) */
1693

    
1694
target_ulong helper_clcs (uint32_t arg)
1695
{
1696
    switch (arg) {
1697
    case 0x0CUL:
1698
        /* Instruction cache line size */
1699
        return env->icache_line_size;
1700
        break;
1701
    case 0x0DUL:
1702
        /* Data cache line size */
1703
        return env->dcache_line_size;
1704
        break;
1705
    case 0x0EUL:
1706
        /* Minimum cache line size */
1707
        return (env->icache_line_size < env->dcache_line_size) ?
1708
                env->icache_line_size : env->dcache_line_size;
1709
        break;
1710
    case 0x0FUL:
1711
        /* Maximum cache line size */
1712
        return (env->icache_line_size > env->dcache_line_size) ?
1713
                env->icache_line_size : env->dcache_line_size;
1714
        break;
1715
    default:
1716
        /* Undefined */
1717
        return 0;
1718
        break;
1719
    }
1720
}
1721

    
1722
target_ulong helper_div (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->spr[SPR_MQ] = 0;
1729
        return INT32_MIN;
1730
    } else {
1731
        env->spr[SPR_MQ] = tmp % arg2;
1732
        return  tmp / (int32_t)arg2;
1733
    }
1734
}
1735

    
1736
target_ulong helper_divo (target_ulong arg1, target_ulong arg2)
1737
{
1738
    uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
1739

    
1740
    if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1741
        (int32_t)arg2 == 0) {
1742
        env->xer |= (1 << XER_OV) | (1 << XER_SO);
1743
        env->spr[SPR_MQ] = 0;
1744
        return INT32_MIN;
1745
    } else {
1746
        env->spr[SPR_MQ] = tmp % arg2;
1747
        tmp /= (int32_t)arg2;
1748
        if ((int32_t)tmp != tmp) {
1749
            env->xer |= (1 << XER_OV) | (1 << XER_SO);
1750
        } else {
1751
            env->xer &= ~(1 << XER_OV);
1752
        }
1753
        return tmp;
1754
    }
1755
}
1756

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

    
1769
target_ulong helper_divso (target_ulong arg1, target_ulong arg2)
1770
{
1771
    if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1772
        (int32_t)arg2 == 0) {
1773
        env->xer |= (1 << XER_OV) | (1 << XER_SO);
1774
        env->spr[SPR_MQ] = 0;
1775
        return INT32_MIN;
1776
    } else {
1777
        env->xer &= ~(1 << XER_OV);
1778
        env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1779
        return (int32_t)arg1 / (int32_t)arg2;
1780
    }
1781
}
1782

    
1783
#if !defined (CONFIG_USER_ONLY)
1784
target_ulong helper_rac (target_ulong addr)
1785
{
1786
    mmu_ctx_t ctx;
1787
    int nb_BATs;
1788
    target_ulong ret = 0;
1789

    
1790
    /* We don't have to generate many instances of this instruction,
1791
     * as rac is supervisor only.
1792
     */
1793
    /* XXX: FIX THIS: Pretend we have no BAT */
1794
    nb_BATs = env->nb_BATs;
1795
    env->nb_BATs = 0;
1796
    if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0)
1797
        ret = ctx.raddr;
1798
    env->nb_BATs = nb_BATs;
1799
    return ret;
1800
}
1801

    
1802
void helper_rfsvc (void)
1803
{
1804
    do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
1805
}
1806
#endif
1807

    
1808
/*****************************************************************************/
1809
/* 602 specific instructions */
1810
/* mfrom is the most crazy instruction ever seen, imho ! */
1811
/* Real implementation uses a ROM table. Do the same */
1812
/* Extremly decomposed:
1813
 *                      -arg / 256
1814
 * return 256 * log10(10           + 1.0) + 0.5
1815
 */
1816
#if !defined (CONFIG_USER_ONLY)
1817
target_ulong helper_602_mfrom (target_ulong arg)
1818
{
1819
    if (likely(arg < 602)) {
1820
#include "mfrom_table.c"
1821
        return mfrom_ROM_table[arg];
1822
    } else {
1823
        return 0;
1824
    }
1825
}
1826
#endif
1827

    
1828
/*****************************************************************************/
1829
/* Embedded PowerPC specific helpers */
1830

    
1831
/* XXX: to be improved to check access rights when in user-mode */
1832
target_ulong helper_load_dcr (target_ulong dcrn)
1833
{
1834
    target_ulong val = 0;
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_read(env->dcr_env, dcrn, &val) != 0)) {
1841
        qemu_log("DCR read error %d %03x\n", (int)dcrn, (int)dcrn);
1842
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1843
                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1844
    }
1845
    return val;
1846
}
1847

    
1848
void helper_store_dcr (target_ulong dcrn, target_ulong val)
1849
{
1850
    if (unlikely(env->dcr_env == NULL)) {
1851
        qemu_log("No DCR environment\n");
1852
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1853
                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
1854
    } else if (unlikely(ppc_dcr_write(env->dcr_env, dcrn, val) != 0)) {
1855
        qemu_log("DCR write error %d %03x\n", (int)dcrn, (int)dcrn);
1856
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1857
                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1858
    }
1859
}
1860

    
1861
#if !defined(CONFIG_USER_ONLY)
1862
void helper_40x_rfci (void)
1863
{
1864
    do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
1865
           ~((target_ulong)0xFFFF0000), 0);
1866
}
1867

    
1868
void helper_rfci (void)
1869
{
1870
    do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
1871
           ~((target_ulong)0x3FFF0000), 0);
1872
}
1873

    
1874
void helper_rfdi (void)
1875
{
1876
    do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
1877
           ~((target_ulong)0x3FFF0000), 0);
1878
}
1879

    
1880
void helper_rfmci (void)
1881
{
1882
    do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
1883
           ~((target_ulong)0x3FFF0000), 0);
1884
}
1885
#endif
1886

    
1887
/* 440 specific */
1888
target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_Rc)
1889
{
1890
    target_ulong mask;
1891
    int i;
1892

    
1893
    i = 1;
1894
    for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1895
        if ((high & mask) == 0) {
1896
            if (update_Rc) {
1897
                env->crf[0] = 0x4;
1898
            }
1899
            goto done;
1900
        }
1901
        i++;
1902
    }
1903
    for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1904
        if ((low & mask) == 0) {
1905
            if (update_Rc) {
1906
                env->crf[0] = 0x8;
1907
            }
1908
            goto done;
1909
        }
1910
        i++;
1911
    }
1912
    if (update_Rc) {
1913
        env->crf[0] = 0x2;
1914
    }
1915
 done:
1916
    env->xer = (env->xer & ~0x7F) | i;
1917
    if (update_Rc) {
1918
        env->crf[0] |= xer_so;
1919
    }
1920
    return i;
1921
}
1922

    
1923
/*****************************************************************************/
1924
/* Altivec extension helpers */
1925
#if defined(WORDS_BIGENDIAN)
1926
#define HI_IDX 0
1927
#define LO_IDX 1
1928
#else
1929
#define HI_IDX 1
1930
#define LO_IDX 0
1931
#endif
1932

    
1933
#if defined(WORDS_BIGENDIAN)
1934
#define VECTOR_FOR_INORDER_I(index, element)            \
1935
    for (index = 0; index < ARRAY_SIZE(r->element); index++)
1936
#else
1937
#define VECTOR_FOR_INORDER_I(index, element)            \
1938
  for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
1939
#endif
1940

    
1941
/* If X is a NaN, store the corresponding QNaN into RESULT.  Otherwise,
1942
 * execute the following block.  */
1943
#define DO_HANDLE_NAN(result, x)                \
1944
    if (float32_is_nan(x) || float32_is_signaling_nan(x)) {     \
1945
        CPU_FloatU __f;                                         \
1946
        __f.f = x;                                              \
1947
        __f.l = __f.l | (1 << 22);  /* Set QNaN bit. */         \
1948
        result = __f.f;                                         \
1949
    } else
1950

    
1951
#define HANDLE_NAN1(result, x)                  \
1952
    DO_HANDLE_NAN(result, x)
1953
#define HANDLE_NAN2(result, x, y)               \
1954
    DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y)
1955
#define HANDLE_NAN3(result, x, y, z)            \
1956
    DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) DO_HANDLE_NAN(result, z)
1957

    
1958
/* Saturating arithmetic helpers.  */
1959
#define SATCVT(from, to, from_type, to_type, min, max, use_min, use_max) \
1960
    static always_inline to_type cvt##from##to (from_type x, int *sat)  \
1961
    {                                                                   \
1962
        to_type r;                                                      \
1963
        if (use_min && x < min) {                                       \
1964
            r = min;                                                    \
1965
            *sat = 1;                                                   \
1966
        } else if (use_max && x > max) {                                \
1967
            r = max;                                                    \
1968
            *sat = 1;                                                   \
1969
        } else {                                                        \
1970
            r = x;                                                      \
1971
        }                                                               \
1972
        return r;                                                       \
1973
    }
1974
SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX, 1, 1)
1975
SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX, 1, 1)
1976
SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX, 1, 1)
1977
SATCVT(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX, 0, 1)
1978
SATCVT(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX, 0, 1)
1979
SATCVT(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX, 0, 1)
1980
SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX, 1, 1)
1981
SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX, 1, 1)
1982
SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX, 1, 1)
1983
#undef SATCVT
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(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 always_inline void vcmpbfp_internal (ppc_avr_t *r, ppc_avr_t *a,
2234
                                            ppc_avr_t *b, 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_nan(b->f[i]) ||                              \
2276
                float32_is_signaling_nan(b->f[i])) {                    \
2277
                r->element[i] = 0;                                      \
2278
            } else {                                                    \
2279
                float64 t = float32_to_float64(b->f[i], &s);            \
2280
                int64_t j;                                              \
2281
                t = float64_scalbn(t, uim, &s);                         \
2282
                j = float64_to_int64(t, &s);                            \
2283
                r->element[i] = satcvt(j, &sat);                        \
2284
            }                                                           \
2285
        }                                                               \
2286
        if (sat) {                                                      \
2287
            env->vscr |= (1 << VSCR_SAT);                               \
2288
        }                                                               \
2289
    }
2290
VCT(uxs, cvtsduw, u32)
2291
VCT(sxs, cvtsdsw, s32)
2292
#undef VCT
2293

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2904
    if (sat) {
2905
        env->vscr |= (1 << VSCR_SAT);
2906
    }
2907
}
2908

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

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

    
2929
    *r = result;
2930
    if (sat) {
2931
        env->vscr |= (1 << VSCR_SAT);
2932
    }
2933
}
2934

    
2935
void helper_vsum4sbs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2936
{
2937
    int i, j;
2938
    int sat = 0;
2939

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

    
2948
    if (sat) {
2949
        env->vscr |= (1 << VSCR_SAT);
2950
    }
2951
}
2952

    
2953
void helper_vsum4shs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2954
{
2955
    int sat = 0;
2956
    int i;
2957

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

    
2964
    if (sat) {
2965
        env->vscr |= (1 << VSCR_SAT);
2966
    }
2967
}
2968

    
2969
void helper_vsum4ubs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2970
{
2971
    int i, j;
2972
    int sat = 0;
2973

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

    
2982
    if (sat) {
2983
        env->vscr |= (1 << VSCR_SAT);
2984
    }
2985
}
2986

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

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

    
3037
#undef DO_HANDLE_NAN
3038
#undef HANDLE_NAN1
3039
#undef HANDLE_NAN2
3040
#undef HANDLE_NAN3
3041
#undef VECTOR_FOR_INORDER_I
3042
#undef HI_IDX
3043
#undef LO_IDX
3044

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

    
3053
static always_inline uint8_t byte_reverse (uint8_t val)
3054
{
3055
    return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
3056
}
3057

    
3058
static always_inline uint32_t word_reverse (uint32_t val)
3059
{
3060
    return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
3061
        (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
3062
}
3063

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

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

    
3076
uint32_t helper_cntlsw32 (uint32_t val)
3077
{
3078
    if (val & 0x80000000)
3079
        return clz32(~val);
3080
    else
3081
        return clz32(val);
3082
}
3083

    
3084
uint32_t helper_cntlzw32 (uint32_t val)
3085
{
3086
    return clz32(val);
3087
}
3088

    
3089
/* Single-precision floating-point conversions */
3090
static always_inline uint32_t efscfsi (uint32_t val)
3091
{
3092
    CPU_FloatU u;
3093

    
3094
    u.f = int32_to_float32(val, &env->vec_status);
3095

    
3096
    return u.l;
3097
}
3098

    
3099
static always_inline uint32_t efscfui (uint32_t val)
3100
{
3101
    CPU_FloatU u;
3102

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

    
3105
    return u.l;
3106
}
3107

    
3108
static always_inline int32_t efsctsi (uint32_t val)
3109
{
3110
    CPU_FloatU u;
3111

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

    
3117
    return float32_to_int32(u.f, &env->vec_status);
3118
}
3119

    
3120
static always_inline uint32_t efsctui (uint32_t val)
3121
{
3122
    CPU_FloatU u;
3123

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

    
3129
    return float32_to_uint32(u.f, &env->vec_status);
3130
}
3131

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

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

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

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

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

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

    
3156
static always_inline uint32_t efscfsf (uint32_t val)
3157
{
3158
    CPU_FloatU u;
3159
    float32 tmp;
3160

    
3161
    u.f = int32_to_float32(val, &env->vec_status);
3162
    tmp = int64_to_float32(1ULL << 32, &env->vec_status);
3163
    u.f = float32_div(u.f, tmp, &env->vec_status);
3164

    
3165
    return u.l;
3166
}
3167

    
3168
static always_inline uint32_t efscfuf (uint32_t val)
3169
{
3170
    CPU_FloatU u;
3171
    float32 tmp;
3172

    
3173
    u.f = uint32_to_float32(val, &env->vec_status);
3174
    tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3175
    u.f = float32_div(u.f, tmp, &env->vec_status);
3176

    
3177
    return u.l;
3178
}
3179

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

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

    
3192
    return float32_to_int32(u.f, &env->vec_status);
3193
}
3194

    
3195
static always_inline uint32_t efsctuf (uint32_t val)
3196
{
3197
    CPU_FloatU u;
3198
    float32 tmp;
3199

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

    
3207
    return float32_to_uint32(u.f, &env->vec_status);
3208
}
3209

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3390
static always_inline uint32_t evcmp_merge (int t0, int t1)
3391
{
3392
    return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
3393
}
3394

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

    
3413
/* Double-precision floating-point conversion */
3414
uint64_t helper_efdcfsi (uint32_t val)
3415
{
3416
    CPU_DoubleU u;
3417

    
3418
    u.d = int32_to_float64(val, &env->vec_status);
3419

    
3420
    return u.ll;
3421
}
3422

    
3423
uint64_t helper_efdcfsid (uint64_t val)
3424
{
3425
    CPU_DoubleU u;
3426

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

    
3429
    return u.ll;
3430
}
3431

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

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

    
3438
    return u.ll;
3439
}
3440

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

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

    
3447
    return u.ll;
3448
}
3449

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

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

    
3459
    return float64_to_int32(u.d, &env->vec_status);
3460
}
3461

    
3462
uint32_t helper_efdctui (uint64_t val)
3463
{
3464
    CPU_DoubleU u;
3465

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

    
3471
    return float64_to_uint32(u.d, &env->vec_status);
3472
}
3473

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

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

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

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

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

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

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

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

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

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

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

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

    
3522
uint64_t helper_efdcfsf (uint32_t val)
3523
{
3524
    CPU_DoubleU u;
3525
    float64 tmp;
3526

    
3527
    u.d = int32_to_float64(val, &env->vec_status);
3528
    tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3529
    u.d = float64_div(u.d, tmp, &env->vec_status);
3530

    
3531
    return u.ll;
3532
}
3533

    
3534
uint64_t helper_efdcfuf (uint32_t val)
3535
{
3536
    CPU_DoubleU u;
3537
    float64 tmp;
3538

    
3539
    u.d = uint32_to_float64(val, &env->vec_status);
3540
    tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3541
    u.d = float64_div(u.d, tmp, &env->vec_status);
3542

    
3543
    return u.ll;
3544
}
3545

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

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

    
3558
    return float64_to_int32(u.d, &env->vec_status);
3559
}
3560

    
3561
uint32_t helper_efdctuf (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_nan(u.d)))
3569
        return 0;
3570
    tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3571
    u.d = float64_mul(u.d, tmp, &env->vec_status);
3572

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

    
3576
uint32_t helper_efscfd (uint64_t val)
3577
{
3578
    CPU_DoubleU u1;
3579
    CPU_FloatU u2;
3580

    
3581
    u1.ll = val;
3582
    u2.f = float64_to_float32(u1.d, &env->vec_status);
3583

    
3584
    return u2.l;
3585
}
3586

    
3587
uint64_t helper_efdcfs (uint32_t val)
3588
{
3589
    CPU_DoubleU u2;
3590
    CPU_FloatU u1;
3591

    
3592
    u1.l = val;
3593
    u2.d = float32_to_float64(u1.f, &env->vec_status);
3594

    
3595
    return u2.ll;
3596
}
3597

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

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

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

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

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

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

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

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

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

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

    
3678
/*****************************************************************************/
3679
/* Softmmu support */
3680
#if !defined (CONFIG_USER_ONLY)
3681

    
3682
#define MMUSUFFIX _mmu
3683

    
3684
#define SHIFT 0
3685
#include "softmmu_template.h"
3686

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

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

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

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

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

    
3728
/* Segment registers load and store */
3729
target_ulong helper_load_sr (target_ulong sr_num)
3730
{
3731
#if defined(TARGET_PPC64)
3732
    if (env->mmu_model & POWERPC_MMU_64)
3733
        return ppc_load_sr(env, sr_num);
3734
#endif
3735
    return env->sr[sr_num];
3736
}
3737

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3905
    return size;
3906
}
3907

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4138
#endif /* !CONFIG_USER_ONLY */