Statistics
| Branch: | Revision:

root / target-ppc / op_helper.c @ 7863667f

History | View | Annotate | Download (76.3 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 */
20
#include "exec.h"
21
#include "host-utils.h"
22

    
23
#include "helper_regs.h"
24
#include "op_helper.h"
25

    
26
#define MEMSUFFIX _raw
27
#include "op_helper.h"
28
#include "op_helper_mem.h"
29
#if !defined(CONFIG_USER_ONLY)
30
#define MEMSUFFIX _user
31
#include "op_helper.h"
32
#include "op_helper_mem.h"
33
#define MEMSUFFIX _kernel
34
#include "op_helper.h"
35
#include "op_helper_mem.h"
36
#define MEMSUFFIX _hypv
37
#include "op_helper.h"
38
#include "op_helper_mem.h"
39
#endif
40

    
41
//#define DEBUG_OP
42
//#define DEBUG_EXCEPTIONS
43
//#define DEBUG_SOFTWARE_TLB
44

    
45
/*****************************************************************************/
46
/* Exceptions processing helpers */
47

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

    
58
void do_raise_exception (uint32_t exception)
59
{
60
    do_raise_exception_err(exception, 0);
61
}
62

    
63
void cpu_dump_EA (target_ulong EA);
64
void do_print_mem_EA (target_ulong EA)
65
{
66
    cpu_dump_EA(EA);
67
}
68

    
69
/*****************************************************************************/
70
/* Registers load and stores */
71
void do_load_cr (void)
72
{
73
    T0 = (env->crf[0] << 28) |
74
        (env->crf[1] << 24) |
75
        (env->crf[2] << 20) |
76
        (env->crf[3] << 16) |
77
        (env->crf[4] << 12) |
78
        (env->crf[5] << 8) |
79
        (env->crf[6] << 4) |
80
        (env->crf[7] << 0);
81
}
82

    
83
void do_store_cr (uint32_t mask)
84
{
85
    int i, sh;
86

    
87
    for (i = 0, sh = 7; i < 8; i++, sh--) {
88
        if (mask & (1 << sh))
89
            env->crf[i] = (T0 >> (sh * 4)) & 0xFUL;
90
    }
91
}
92

    
93
#if defined(TARGET_PPC64)
94
void do_store_pri (int prio)
95
{
96
    env->spr[SPR_PPR] &= ~0x001C000000000000ULL;
97
    env->spr[SPR_PPR] |= ((uint64_t)prio & 0x7) << 50;
98
}
99
#endif
100

    
101
target_ulong ppc_load_dump_spr (int sprn)
102
{
103
    if (loglevel != 0) {
104
        fprintf(logfile, "Read SPR %d %03x => " ADDRX "\n",
105
                sprn, sprn, env->spr[sprn]);
106
    }
107

    
108
    return env->spr[sprn];
109
}
110

    
111
void ppc_store_dump_spr (int sprn, target_ulong val)
112
{
113
    if (loglevel != 0) {
114
        fprintf(logfile, "Write SPR %d %03x => " ADDRX " <= " ADDRX "\n",
115
                sprn, sprn, env->spr[sprn], val);
116
    }
117
    env->spr[sprn] = val;
118
}
119

    
120
/*****************************************************************************/
121
/* Fixed point operations helpers */
122
void do_adde (void)
123
{
124
    T2 = T0;
125
    T0 += T1 + xer_ca;
126
    if (likely(!((uint32_t)T0 < (uint32_t)T2 ||
127
                 (xer_ca == 1 && (uint32_t)T0 == (uint32_t)T2)))) {
128
        xer_ca = 0;
129
    } else {
130
        xer_ca = 1;
131
    }
132
}
133

    
134
#if defined(TARGET_PPC64)
135
void do_adde_64 (void)
136
{
137
    T2 = T0;
138
    T0 += T1 + xer_ca;
139
    if (likely(!((uint64_t)T0 < (uint64_t)T2 ||
140
                 (xer_ca == 1 && (uint64_t)T0 == (uint64_t)T2)))) {
141
        xer_ca = 0;
142
    } else {
143
        xer_ca = 1;
144
    }
145
}
146
#endif
147

    
148
void do_addmeo (void)
149
{
150
    T1 = T0;
151
    T0 += xer_ca + (-1);
152
    xer_ov = ((uint32_t)T1 & ((uint32_t)T1 ^ (uint32_t)T0)) >> 31;
153
    xer_so |= xer_ov;
154
    if (likely(T1 != 0))
155
        xer_ca = 1;
156
    else
157
        xer_ca = 0;
158
}
159

    
160
#if defined(TARGET_PPC64)
161
void do_addmeo_64 (void)
162
{
163
    T1 = T0;
164
    T0 += xer_ca + (-1);
165
    xer_ov = ((uint64_t)T1 & ((uint64_t)T1 ^ (uint64_t)T0)) >> 63;
166
    xer_so |= xer_ov;
167
    if (likely(T1 != 0))
168
        xer_ca = 1;
169
    else
170
        xer_ca = 0;
171
}
172
#endif
173

    
174
void do_divwo (void)
175
{
176
    if (likely(!(((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
177
                 (int32_t)T1 == 0))) {
178
        xer_ov = 0;
179
        T0 = (int32_t)T0 / (int32_t)T1;
180
    } else {
181
        xer_ov = 1;
182
        T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
183
    }
184
    xer_so |= xer_ov;
185
}
186

    
187
#if defined(TARGET_PPC64)
188
void do_divdo (void)
189
{
190
    if (likely(!(((int64_t)T0 == INT64_MIN && (int64_t)T1 == (int64_t)-1LL) ||
191
                 (int64_t)T1 == 0))) {
192
        xer_ov = 0;
193
        T0 = (int64_t)T0 / (int64_t)T1;
194
    } else {
195
        xer_ov = 1;
196
        T0 = UINT64_MAX * ((uint64_t)T0 >> 63);
197
    }
198
    xer_so |= xer_ov;
199
}
200
#endif
201

    
202
void do_divwuo (void)
203
{
204
    if (likely((uint32_t)T1 != 0)) {
205
        xer_ov = 0;
206
        T0 = (uint32_t)T0 / (uint32_t)T1;
207
    } else {
208
        xer_ov = 1;
209
        xer_so = 1;
210
        T0 = 0;
211
    }
212
}
213

    
214
#if defined(TARGET_PPC64)
215
void do_divduo (void)
216
{
217
    if (likely((uint64_t)T1 != 0)) {
218
        xer_ov = 0;
219
        T0 = (uint64_t)T0 / (uint64_t)T1;
220
    } else {
221
        xer_ov = 1;
222
        xer_so = 1;
223
        T0 = 0;
224
    }
225
}
226
#endif
227

    
228
void do_mullwo (void)
229
{
230
    int64_t res = (int64_t)T0 * (int64_t)T1;
231

    
232
    if (likely((int32_t)res == res)) {
233
        xer_ov = 0;
234
    } else {
235
        xer_ov = 1;
236
        xer_so = 1;
237
    }
238
    T0 = (int32_t)res;
239
}
240

    
241
#if defined(TARGET_PPC64)
242
void do_mulldo (void)
243
{
244
    int64_t th;
245
    uint64_t tl;
246

    
247
    muls64(&tl, &th, T0, T1);
248
    T0 = (int64_t)tl;
249
    /* If th != 0 && th != -1, then we had an overflow */
250
    if (likely((uint64_t)(th + 1) <= 1)) {
251
        xer_ov = 0;
252
    } else {
253
        xer_ov = 1;
254
    }
255
    xer_so |= xer_ov;
256
}
257
#endif
258

    
259
void do_nego (void)
260
{
261
    if (likely((int32_t)T0 != INT32_MIN)) {
262
        xer_ov = 0;
263
        T0 = -(int32_t)T0;
264
    } else {
265
        xer_ov = 1;
266
        xer_so = 1;
267
    }
268
}
269

    
270
#if defined(TARGET_PPC64)
271
void do_nego_64 (void)
272
{
273
    if (likely((int64_t)T0 != INT64_MIN)) {
274
        xer_ov = 0;
275
        T0 = -(int64_t)T0;
276
    } else {
277
        xer_ov = 1;
278
        xer_so = 1;
279
    }
280
}
281
#endif
282

    
283
void do_subfe (void)
284
{
285
    T0 = T1 + ~T0 + xer_ca;
286
    if (likely((uint32_t)T0 >= (uint32_t)T1 &&
287
               (xer_ca == 0 || (uint32_t)T0 != (uint32_t)T1))) {
288
        xer_ca = 0;
289
    } else {
290
        xer_ca = 1;
291
    }
292
}
293

    
294
#if defined(TARGET_PPC64)
295
void do_subfe_64 (void)
296
{
297
    T0 = T1 + ~T0 + xer_ca;
298
    if (likely((uint64_t)T0 >= (uint64_t)T1 &&
299
               (xer_ca == 0 || (uint64_t)T0 != (uint64_t)T1))) {
300
        xer_ca = 0;
301
    } else {
302
        xer_ca = 1;
303
    }
304
}
305
#endif
306

    
307
void do_subfmeo (void)
308
{
309
    T1 = T0;
310
    T0 = ~T0 + xer_ca - 1;
311
    xer_ov = ((uint32_t)~T1 & ((uint32_t)~T1 ^ (uint32_t)T0)) >> 31;
312
    xer_so |= xer_ov;
313
    if (likely((uint32_t)T1 != UINT32_MAX))
314
        xer_ca = 1;
315
    else
316
        xer_ca = 0;
317
}
318

    
319
#if defined(TARGET_PPC64)
320
void do_subfmeo_64 (void)
321
{
322
    T1 = T0;
323
    T0 = ~T0 + xer_ca - 1;
324
    xer_ov = ((uint64_t)~T1 & ((uint64_t)~T1 ^ (uint64_t)T0)) >> 63;
325
    xer_so |= xer_ov;
326
    if (likely((uint64_t)T1 != UINT64_MAX))
327
        xer_ca = 1;
328
    else
329
        xer_ca = 0;
330
}
331
#endif
332

    
333
void do_subfzeo (void)
334
{
335
    T1 = T0;
336
    T0 = ~T0 + xer_ca;
337
    xer_ov = (((uint32_t)~T1 ^ UINT32_MAX) &
338
              ((uint32_t)(~T1) ^ (uint32_t)T0)) >> 31;
339
    xer_so |= xer_ov;
340
    if (likely((uint32_t)T0 >= (uint32_t)~T1)) {
341
        xer_ca = 0;
342
    } else {
343
        xer_ca = 1;
344
    }
345
}
346

    
347
#if defined(TARGET_PPC64)
348
void do_subfzeo_64 (void)
349
{
350
    T1 = T0;
351
    T0 = ~T0 + xer_ca;
352
    xer_ov = (((uint64_t)~T1 ^  UINT64_MAX) &
353
              ((uint64_t)(~T1) ^ (uint64_t)T0)) >> 63;
354
    xer_so |= xer_ov;
355
    if (likely((uint64_t)T0 >= (uint64_t)~T1)) {
356
        xer_ca = 0;
357
    } else {
358
        xer_ca = 1;
359
    }
360
}
361
#endif
362

    
363
void do_cntlzw (void)
364
{
365
    T0 = clz32(T0);
366
}
367

    
368
#if defined(TARGET_PPC64)
369
void do_cntlzd (void)
370
{
371
    T0 = clz64(T0);
372
}
373
#endif
374

    
375
/* shift right arithmetic helper */
376
void do_sraw (void)
377
{
378
    int32_t ret;
379

    
380
    if (likely(!(T1 & 0x20UL))) {
381
        if (likely((uint32_t)T1 != 0)) {
382
            ret = (int32_t)T0 >> (T1 & 0x1fUL);
383
            if (likely(ret >= 0 || ((int32_t)T0 & ((1 << T1) - 1)) == 0)) {
384
                xer_ca = 0;
385
            } else {
386
                xer_ca = 1;
387
            }
388
        } else {
389
            ret = T0;
390
            xer_ca = 0;
391
        }
392
    } else {
393
        ret = UINT32_MAX * ((uint32_t)T0 >> 31);
394
        if (likely(ret >= 0 || ((uint32_t)T0 & ~0x80000000UL) == 0)) {
395
            xer_ca = 0;
396
        } else {
397
            xer_ca = 1;
398
        }
399
    }
400
    T0 = ret;
401
}
402

    
403
#if defined(TARGET_PPC64)
404
void do_srad (void)
405
{
406
    int64_t ret;
407

    
408
    if (likely(!(T1 & 0x40UL))) {
409
        if (likely((uint64_t)T1 != 0)) {
410
            ret = (int64_t)T0 >> (T1 & 0x3FUL);
411
            if (likely(ret >= 0 || ((int64_t)T0 & ((1 << T1) - 1)) == 0)) {
412
                xer_ca = 0;
413
            } else {
414
                xer_ca = 1;
415
            }
416
        } else {
417
            ret = T0;
418
            xer_ca = 0;
419
        }
420
    } else {
421
        ret = UINT64_MAX * ((uint64_t)T0 >> 63);
422
        if (likely(ret >= 0 || ((uint64_t)T0 & ~0x8000000000000000ULL) == 0)) {
423
            xer_ca = 0;
424
        } else {
425
            xer_ca = 1;
426
        }
427
    }
428
    T0 = ret;
429
}
430
#endif
431

    
432
void do_popcntb (void)
433
{
434
    uint32_t ret;
435
    int i;
436

    
437
    ret = 0;
438
    for (i = 0; i < 32; i += 8)
439
        ret |= ctpop8((T0 >> i) & 0xFF) << i;
440
    T0 = ret;
441
}
442

    
443
#if defined(TARGET_PPC64)
444
void do_popcntb_64 (void)
445
{
446
    uint64_t ret;
447
    int i;
448

    
449
    ret = 0;
450
    for (i = 0; i < 64; i += 8)
451
        ret |= ctpop8((T0 >> i) & 0xFF) << i;
452
    T0 = ret;
453
}
454
#endif
455

    
456
/*****************************************************************************/
457
/* Floating point operations helpers */
458
static always_inline int fpisneg (float64 f)
459
{
460
    union {
461
        float64 f;
462
        uint64_t u;
463
    } u;
464

    
465
    u.f = f;
466

    
467
    return u.u >> 63 != 0;
468
}
469

    
470
static always_inline int isden (float f)
471
{
472
    union {
473
        float64 f;
474
        uint64_t u;
475
    } u;
476

    
477
    u.f = f;
478

    
479
    return ((u.u >> 52) & 0x7FF) == 0;
480
}
481

    
482
static always_inline int iszero (float64 f)
483
{
484
    union {
485
        float64 f;
486
        uint64_t u;
487
    } u;
488

    
489
    u.f = f;
490

    
491
    return (u.u & ~0x8000000000000000ULL) == 0;
492
}
493

    
494
static always_inline int isinfinity (float64 f)
495
{
496
    union {
497
        float64 f;
498
        uint64_t u;
499
    } u;
500

    
501
    u.f = f;
502

    
503
    return ((u.u >> 52) & 0x7FF) == 0x7FF &&
504
        (u.u & 0x000FFFFFFFFFFFFFULL) == 0;
505
}
506

    
507
void do_compute_fprf (int set_fprf)
508
{
509
    int isneg;
510

    
511
    isneg = fpisneg(FT0);
512
    if (unlikely(float64_is_nan(FT0))) {
513
        if (float64_is_signaling_nan(FT0)) {
514
            /* Signaling NaN: flags are undefined */
515
            T0 = 0x00;
516
        } else {
517
            /* Quiet NaN */
518
            T0 = 0x11;
519
        }
520
    } else if (unlikely(isinfinity(FT0))) {
521
        /* +/- infinity */
522
        if (isneg)
523
            T0 = 0x09;
524
        else
525
            T0 = 0x05;
526
    } else {
527
        if (iszero(FT0)) {
528
            /* +/- zero */
529
            if (isneg)
530
                T0 = 0x12;
531
            else
532
                T0 = 0x02;
533
        } else {
534
            if (isden(FT0)) {
535
                /* Denormalized numbers */
536
                T0 = 0x10;
537
            } else {
538
                /* Normalized numbers */
539
                T0 = 0x00;
540
            }
541
            if (isneg) {
542
                T0 |= 0x08;
543
            } else {
544
                T0 |= 0x04;
545
            }
546
        }
547
    }
548
    if (set_fprf) {
549
        /* We update FPSCR_FPRF */
550
        env->fpscr &= ~(0x1F << FPSCR_FPRF);
551
        env->fpscr |= T0 << FPSCR_FPRF;
552
    }
553
    /* We just need fpcc to update Rc1 */
554
    T0 &= 0xF;
555
}
556

    
557
/* Floating-point invalid operations exception */
558
static always_inline void fload_invalid_op_excp (int op)
559
{
560
    int ve;
561

    
562
    ve = fpscr_ve;
563
    if (op & POWERPC_EXCP_FP_VXSNAN) {
564
        /* Operation on signaling NaN */
565
        env->fpscr |= 1 << FPSCR_VXSNAN;
566
    }
567
    if (op & POWERPC_EXCP_FP_VXSOFT) {
568
        /* Software-defined condition */
569
        env->fpscr |= 1 << FPSCR_VXSOFT;
570
    }
571
    switch (op & ~(POWERPC_EXCP_FP_VXSOFT | POWERPC_EXCP_FP_VXSNAN)) {
572
    case POWERPC_EXCP_FP_VXISI:
573
        /* Magnitude subtraction of infinities */
574
        env->fpscr |= 1 << FPSCR_VXISI;
575
        goto update_arith;
576
    case POWERPC_EXCP_FP_VXIDI:
577
        /* Division of infinity by infinity */
578
        env->fpscr |= 1 << FPSCR_VXIDI;
579
        goto update_arith;
580
    case POWERPC_EXCP_FP_VXZDZ:
581
        /* Division of zero by zero */
582
        env->fpscr |= 1 << FPSCR_VXZDZ;
583
        goto update_arith;
584
    case POWERPC_EXCP_FP_VXIMZ:
585
        /* Multiplication of zero by infinity */
586
        env->fpscr |= 1 << FPSCR_VXIMZ;
587
        goto update_arith;
588
    case POWERPC_EXCP_FP_VXVC:
589
        /* Ordered comparison of NaN */
590
        env->fpscr |= 1 << FPSCR_VXVC;
591
        env->fpscr &= ~(0xF << FPSCR_FPCC);
592
        env->fpscr |= 0x11 << FPSCR_FPCC;
593
        /* We must update the target FPR before raising the exception */
594
        if (ve != 0) {
595
            env->exception_index = POWERPC_EXCP_PROGRAM;
596
            env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
597
            /* Update the floating-point enabled exception summary */
598
            env->fpscr |= 1 << FPSCR_FEX;
599
            /* Exception is differed */
600
            ve = 0;
601
        }
602
        break;
603
    case POWERPC_EXCP_FP_VXSQRT:
604
        /* Square root of a negative number */
605
        env->fpscr |= 1 << FPSCR_VXSQRT;
606
    update_arith:
607
        env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
608
        if (ve == 0) {
609
            /* Set the result to quiet NaN */
610
            FT0 = UINT64_MAX;
611
            env->fpscr &= ~(0xF << FPSCR_FPCC);
612
            env->fpscr |= 0x11 << FPSCR_FPCC;
613
        }
614
        break;
615
    case POWERPC_EXCP_FP_VXCVI:
616
        /* Invalid conversion */
617
        env->fpscr |= 1 << FPSCR_VXCVI;
618
        env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
619
        if (ve == 0) {
620
            /* Set the result to quiet NaN */
621
            FT0 = UINT64_MAX;
622
            env->fpscr &= ~(0xF << FPSCR_FPCC);
623
            env->fpscr |= 0x11 << FPSCR_FPCC;
624
        }
625
        break;
626
    }
627
    /* Update the floating-point invalid operation summary */
628
    env->fpscr |= 1 << FPSCR_VX;
629
    /* Update the floating-point exception summary */
630
    env->fpscr |= 1 << FPSCR_FX;
631
    if (ve != 0) {
632
        /* Update the floating-point enabled exception summary */
633
        env->fpscr |= 1 << FPSCR_FEX;
634
        if (msr_fe0 != 0 || msr_fe1 != 0)
635
            do_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | op);
636
    }
637
}
638

    
639
static always_inline void float_zero_divide_excp (void)
640
{
641
    union {
642
        float64 f;
643
        uint64_t u;
644
    } u0, u1;
645

    
646
    env->fpscr |= 1 << FPSCR_ZX;
647
    env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
648
    /* Update the floating-point exception summary */
649
    env->fpscr |= 1 << FPSCR_FX;
650
    if (fpscr_ze != 0) {
651
        /* Update the floating-point enabled exception summary */
652
        env->fpscr |= 1 << FPSCR_FEX;
653
        if (msr_fe0 != 0 || msr_fe1 != 0) {
654
            do_raise_exception_err(POWERPC_EXCP_PROGRAM,
655
                                   POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
656
        }
657
    } else {
658
        /* Set the result to infinity */
659
        u0.f = FT0;
660
        u1.f = FT1;
661
        u0.u = ((u0.u ^ u1.u) & 0x8000000000000000ULL);
662
        u0.u |= 0x7FFULL << 52;
663
        FT0 = u0.f;
664
    }
665
}
666

    
667
static always_inline void float_overflow_excp (void)
668
{
669
    env->fpscr |= 1 << FPSCR_OX;
670
    /* Update the floating-point exception summary */
671
    env->fpscr |= 1 << FPSCR_FX;
672
    if (fpscr_oe != 0) {
673
        /* XXX: should adjust the result */
674
        /* Update the floating-point enabled exception summary */
675
        env->fpscr |= 1 << FPSCR_FEX;
676
        /* We must update the target FPR before raising the exception */
677
        env->exception_index = POWERPC_EXCP_PROGRAM;
678
        env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
679
    } else {
680
        env->fpscr |= 1 << FPSCR_XX;
681
        env->fpscr |= 1 << FPSCR_FI;
682
    }
683
}
684

    
685
static always_inline void float_underflow_excp (void)
686
{
687
    env->fpscr |= 1 << FPSCR_UX;
688
    /* Update the floating-point exception summary */
689
    env->fpscr |= 1 << FPSCR_FX;
690
    if (fpscr_ue != 0) {
691
        /* XXX: should adjust the result */
692
        /* Update the floating-point enabled exception summary */
693
        env->fpscr |= 1 << FPSCR_FEX;
694
        /* We must update the target FPR before raising the exception */
695
        env->exception_index = POWERPC_EXCP_PROGRAM;
696
        env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
697
    }
698
}
699

    
700
static always_inline void float_inexact_excp (void)
701
{
702
    env->fpscr |= 1 << FPSCR_XX;
703
    /* Update the floating-point exception summary */
704
    env->fpscr |= 1 << FPSCR_FX;
705
    if (fpscr_xe != 0) {
706
        /* Update the floating-point enabled exception summary */
707
        env->fpscr |= 1 << FPSCR_FEX;
708
        /* We must update the target FPR before raising the exception */
709
        env->exception_index = POWERPC_EXCP_PROGRAM;
710
        env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
711
    }
712
}
713

    
714
static always_inline void fpscr_set_rounding_mode (void)
715
{
716
    int rnd_type;
717

    
718
    /* Set rounding mode */
719
    switch (fpscr_rn) {
720
    case 0:
721
        /* Best approximation (round to nearest) */
722
        rnd_type = float_round_nearest_even;
723
        break;
724
    case 1:
725
        /* Smaller magnitude (round toward zero) */
726
        rnd_type = float_round_to_zero;
727
        break;
728
    case 2:
729
        /* Round toward +infinite */
730
        rnd_type = float_round_up;
731
        break;
732
    default:
733
    case 3:
734
        /* Round toward -infinite */
735
        rnd_type = float_round_down;
736
        break;
737
    }
738
    set_float_rounding_mode(rnd_type, &env->fp_status);
739
}
740

    
741
void do_fpscr_setbit (int bit)
742
{
743
    int prev;
744

    
745
    prev = (env->fpscr >> bit) & 1;
746
    env->fpscr |= 1 << bit;
747
    if (prev == 0) {
748
        switch (bit) {
749
        case FPSCR_VX:
750
            env->fpscr |= 1 << FPSCR_FX;
751
            if (fpscr_ve)
752
                goto raise_ve;
753
        case FPSCR_OX:
754
            env->fpscr |= 1 << FPSCR_FX;
755
            if (fpscr_oe)
756
                goto raise_oe;
757
            break;
758
        case FPSCR_UX:
759
            env->fpscr |= 1 << FPSCR_FX;
760
            if (fpscr_ue)
761
                goto raise_ue;
762
            break;
763
        case FPSCR_ZX:
764
            env->fpscr |= 1 << FPSCR_FX;
765
            if (fpscr_ze)
766
                goto raise_ze;
767
            break;
768
        case FPSCR_XX:
769
            env->fpscr |= 1 << FPSCR_FX;
770
            if (fpscr_xe)
771
                goto raise_xe;
772
            break;
773
        case FPSCR_VXSNAN:
774
        case FPSCR_VXISI:
775
        case FPSCR_VXIDI:
776
        case FPSCR_VXZDZ:
777
        case FPSCR_VXIMZ:
778
        case FPSCR_VXVC:
779
        case FPSCR_VXSOFT:
780
        case FPSCR_VXSQRT:
781
        case FPSCR_VXCVI:
782
            env->fpscr |= 1 << FPSCR_VX;
783
            env->fpscr |= 1 << FPSCR_FX;
784
            if (fpscr_ve != 0)
785
                goto raise_ve;
786
            break;
787
        case FPSCR_VE:
788
            if (fpscr_vx != 0) {
789
            raise_ve:
790
                env->error_code = POWERPC_EXCP_FP;
791
                if (fpscr_vxsnan)
792
                    env->error_code |= POWERPC_EXCP_FP_VXSNAN;
793
                if (fpscr_vxisi)
794
                    env->error_code |= POWERPC_EXCP_FP_VXISI;
795
                if (fpscr_vxidi)
796
                    env->error_code |= POWERPC_EXCP_FP_VXIDI;
797
                if (fpscr_vxzdz)
798
                    env->error_code |= POWERPC_EXCP_FP_VXZDZ;
799
                if (fpscr_vximz)
800
                    env->error_code |= POWERPC_EXCP_FP_VXIMZ;
801
                if (fpscr_vxvc)
802
                    env->error_code |= POWERPC_EXCP_FP_VXVC;
803
                if (fpscr_vxsoft)
804
                    env->error_code |= POWERPC_EXCP_FP_VXSOFT;
805
                if (fpscr_vxsqrt)
806
                    env->error_code |= POWERPC_EXCP_FP_VXSQRT;
807
                if (fpscr_vxcvi)
808
                    env->error_code |= POWERPC_EXCP_FP_VXCVI;
809
                goto raise_excp;
810
            }
811
            break;
812
        case FPSCR_OE:
813
            if (fpscr_ox != 0) {
814
            raise_oe:
815
                env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
816
                goto raise_excp;
817
            }
818
            break;
819
        case FPSCR_UE:
820
            if (fpscr_ux != 0) {
821
            raise_ue:
822
                env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
823
                goto raise_excp;
824
            }
825
            break;
826
        case FPSCR_ZE:
827
            if (fpscr_zx != 0) {
828
            raise_ze:
829
                env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX;
830
                goto raise_excp;
831
            }
832
            break;
833
        case FPSCR_XE:
834
            if (fpscr_xx != 0) {
835
            raise_xe:
836
                env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
837
                goto raise_excp;
838
            }
839
            break;
840
        case FPSCR_RN1:
841
        case FPSCR_RN:
842
            fpscr_set_rounding_mode();
843
            break;
844
        default:
845
            break;
846
        raise_excp:
847
            /* Update the floating-point enabled exception summary */
848
            env->fpscr |= 1 << FPSCR_FEX;
849
                /* We have to update Rc1 before raising the exception */
850
            env->exception_index = POWERPC_EXCP_PROGRAM;
851
            break;
852
        }
853
    }
854
}
855

    
856
#if defined(WORDS_BIGENDIAN)
857
#define WORD0 0
858
#define WORD1 1
859
#else
860
#define WORD0 1
861
#define WORD1 0
862
#endif
863
void do_store_fpscr (uint32_t mask)
864
{
865
    /*
866
     * We use only the 32 LSB of the incoming fpr
867
     */
868
    union {
869
        double d;
870
        struct {
871
            uint32_t u[2];
872
        } s;
873
    } u;
874
    uint32_t prev, new;
875
    int i;
876

    
877
    u.d = FT0;
878
    prev = env->fpscr;
879
    new = u.s.u[WORD1];
880
    new &= ~0x90000000;
881
    new |= prev & 0x90000000;
882
    for (i = 0; i < 7; i++) {
883
        if (mask & (1 << i)) {
884
            env->fpscr &= ~(0xF << (4 * i));
885
            env->fpscr |= new & (0xF << (4 * i));
886
        }
887
    }
888
    /* Update VX and FEX */
889
    if (fpscr_ix != 0)
890
        env->fpscr |= 1 << FPSCR_VX;
891
    if ((fpscr_ex & fpscr_eex) != 0) {
892
        env->fpscr |= 1 << FPSCR_FEX;
893
        env->exception_index = POWERPC_EXCP_PROGRAM;
894
        /* XXX: we should compute it properly */
895
        env->error_code = POWERPC_EXCP_FP;
896
    }
897
    fpscr_set_rounding_mode();
898
}
899
#undef WORD0
900
#undef WORD1
901

    
902
#ifdef CONFIG_SOFTFLOAT
903
void do_float_check_status (void)
904
{
905
    if (env->exception_index == POWERPC_EXCP_PROGRAM &&
906
        (env->error_code & POWERPC_EXCP_FP)) {
907
        /* Differred floating-point exception after target FPR update */
908
        if (msr_fe0 != 0 || msr_fe1 != 0)
909
            do_raise_exception_err(env->exception_index, env->error_code);
910
    } else if (env->fp_status.float_exception_flags & float_flag_overflow) {
911
        float_overflow_excp();
912
    } else if (env->fp_status.float_exception_flags & float_flag_underflow) {
913
        float_underflow_excp();
914
    } else if (env->fp_status.float_exception_flags & float_flag_inexact) {
915
        float_inexact_excp();
916
    }
917
}
918
#endif
919

    
920
#if USE_PRECISE_EMULATION
921
void do_fadd (void)
922
{
923
    if (unlikely(float64_is_signaling_nan(FT0) ||
924
                 float64_is_signaling_nan(FT1))) {
925
        /* sNaN addition */
926
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
927
    } else if (likely(isfinite(FT0) || isfinite(FT1) ||
928
                      fpisneg(FT0) == fpisneg(FT1))) {
929
        FT0 = float64_add(FT0, FT1, &env->fp_status);
930
    } else {
931
        /* Magnitude subtraction of infinities */
932
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
933
    }
934
}
935

    
936
void do_fsub (void)
937
{
938
    if (unlikely(float64_is_signaling_nan(FT0) ||
939
                 float64_is_signaling_nan(FT1))) {
940
        /* sNaN subtraction */
941
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
942
    } else if (likely(isfinite(FT0) || isfinite(FT1) ||
943
                      fpisneg(FT0) != fpisneg(FT1))) {
944
        FT0 = float64_sub(FT0, FT1, &env->fp_status);
945
    } else {
946
        /* Magnitude subtraction of infinities */
947
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
948
    }
949
}
950

    
951
void do_fmul (void)
952
{
953
    if (unlikely(float64_is_signaling_nan(FT0) ||
954
                 float64_is_signaling_nan(FT1))) {
955
        /* sNaN multiplication */
956
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
957
    } else if (unlikely((isinfinity(FT0) && iszero(FT1)) ||
958
                        (iszero(FT0) && isinfinity(FT1)))) {
959
        /* Multiplication of zero by infinity */
960
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
961
    } else {
962
        FT0 = float64_mul(FT0, FT1, &env->fp_status);
963
    }
964
}
965

    
966
void do_fdiv (void)
967
{
968
    if (unlikely(float64_is_signaling_nan(FT0) ||
969
                 float64_is_signaling_nan(FT1))) {
970
        /* sNaN division */
971
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
972
    } else if (unlikely(isinfinity(FT0) && isinfinity(FT1))) {
973
        /* Division of infinity by infinity */
974
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
975
    } else if (unlikely(iszero(FT1))) {
976
        if (iszero(FT0)) {
977
            /* Division of zero by zero */
978
            fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
979
        } else {
980
            /* Division by zero */
981
            float_zero_divide_excp();
982
        }
983
    } else {
984
        FT0 = float64_div(FT0, FT1, &env->fp_status);
985
    }
986
}
987
#endif /* USE_PRECISE_EMULATION */
988

    
989
void do_fctiw (void)
990
{
991
    union {
992
        double d;
993
        uint64_t i;
994
    } p;
995

    
996
    if (unlikely(float64_is_signaling_nan(FT0))) {
997
        /* sNaN conversion */
998
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
999
    } else if (unlikely(float64_is_nan(FT0) || isinfinity(FT0))) {
1000
        /* qNan / infinity conversion */
1001
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1002
    } else {
1003
        p.i = float64_to_int32(FT0, &env->fp_status);
1004
#if USE_PRECISE_EMULATION
1005
        /* XXX: higher bits are not supposed to be significant.
1006
         *     to make tests easier, return the same as a real PowerPC 750
1007
         */
1008
        p.i |= 0xFFF80000ULL << 32;
1009
#endif
1010
        FT0 = p.d;
1011
    }
1012
}
1013

    
1014
void do_fctiwz (void)
1015
{
1016
    union {
1017
        double d;
1018
        uint64_t i;
1019
    } p;
1020

    
1021
    if (unlikely(float64_is_signaling_nan(FT0))) {
1022
        /* sNaN conversion */
1023
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1024
    } else if (unlikely(float64_is_nan(FT0) || isinfinity(FT0))) {
1025
        /* qNan / infinity conversion */
1026
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1027
    } else {
1028
        p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status);
1029
#if USE_PRECISE_EMULATION
1030
        /* XXX: higher bits are not supposed to be significant.
1031
         *     to make tests easier, return the same as a real PowerPC 750
1032
         */
1033
        p.i |= 0xFFF80000ULL << 32;
1034
#endif
1035
        FT0 = p.d;
1036
    }
1037
}
1038

    
1039
#if defined(TARGET_PPC64)
1040
void do_fcfid (void)
1041
{
1042
    union {
1043
        double d;
1044
        uint64_t i;
1045
    } p;
1046

    
1047
    p.d = FT0;
1048
    FT0 = int64_to_float64(p.i, &env->fp_status);
1049
}
1050

    
1051
void do_fctid (void)
1052
{
1053
    union {
1054
        double d;
1055
        uint64_t i;
1056
    } p;
1057

    
1058
    if (unlikely(float64_is_signaling_nan(FT0))) {
1059
        /* sNaN conversion */
1060
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1061
    } else if (unlikely(float64_is_nan(FT0) || isinfinity(FT0))) {
1062
        /* qNan / infinity conversion */
1063
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1064
    } else {
1065
        p.i = float64_to_int64(FT0, &env->fp_status);
1066
        FT0 = p.d;
1067
    }
1068
}
1069

    
1070
void do_fctidz (void)
1071
{
1072
    union {
1073
        double d;
1074
        uint64_t i;
1075
    } p;
1076

    
1077
    if (unlikely(float64_is_signaling_nan(FT0))) {
1078
        /* sNaN conversion */
1079
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1080
    } else if (unlikely(float64_is_nan(FT0) || isinfinity(FT0))) {
1081
        /* qNan / infinity conversion */
1082
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1083
    } else {
1084
        p.i = float64_to_int64_round_to_zero(FT0, &env->fp_status);
1085
        FT0 = p.d;
1086
    }
1087
}
1088

    
1089
#endif
1090

    
1091
static always_inline void do_fri (int rounding_mode)
1092
{
1093
    if (unlikely(float64_is_signaling_nan(FT0))) {
1094
        /* sNaN round */
1095
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1096
    } else if (unlikely(float64_is_nan(FT0) || isinfinity(FT0))) {
1097
        /* qNan / infinity round */
1098
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1099
    } else {
1100
        set_float_rounding_mode(rounding_mode, &env->fp_status);
1101
        FT0 = float64_round_to_int(FT0, &env->fp_status);
1102
        /* Restore rounding mode from FPSCR */
1103
        fpscr_set_rounding_mode();
1104
    }
1105
}
1106

    
1107
void do_frin (void)
1108
{
1109
    do_fri(float_round_nearest_even);
1110
}
1111

    
1112
void do_friz (void)
1113
{
1114
    do_fri(float_round_to_zero);
1115
}
1116

    
1117
void do_frip (void)
1118
{
1119
    do_fri(float_round_up);
1120
}
1121

    
1122
void do_frim (void)
1123
{
1124
    do_fri(float_round_down);
1125
}
1126

    
1127
#if USE_PRECISE_EMULATION
1128
void do_fmadd (void)
1129
{
1130
    if (unlikely(float64_is_signaling_nan(FT0) ||
1131
                 float64_is_signaling_nan(FT1) ||
1132
                 float64_is_signaling_nan(FT2))) {
1133
        /* sNaN operation */
1134
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1135
    } else {
1136
#ifdef FLOAT128
1137
        /* This is the way the PowerPC specification defines it */
1138
        float128 ft0_128, ft1_128;
1139

    
1140
        ft0_128 = float64_to_float128(FT0, &env->fp_status);
1141
        ft1_128 = float64_to_float128(FT1, &env->fp_status);
1142
        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1143
        ft1_128 = float64_to_float128(FT2, &env->fp_status);
1144
        ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1145
        FT0 = float128_to_float64(ft0_128, &env->fp_status);
1146
#else
1147
        /* This is OK on x86 hosts */
1148
        FT0 = (FT0 * FT1) + FT2;
1149
#endif
1150
    }
1151
}
1152

    
1153
void do_fmsub (void)
1154
{
1155
    if (unlikely(float64_is_signaling_nan(FT0) ||
1156
                 float64_is_signaling_nan(FT1) ||
1157
                 float64_is_signaling_nan(FT2))) {
1158
        /* sNaN operation */
1159
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1160
    } else {
1161
#ifdef FLOAT128
1162
        /* This is the way the PowerPC specification defines it */
1163
        float128 ft0_128, ft1_128;
1164

    
1165
        ft0_128 = float64_to_float128(FT0, &env->fp_status);
1166
        ft1_128 = float64_to_float128(FT1, &env->fp_status);
1167
        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1168
        ft1_128 = float64_to_float128(FT2, &env->fp_status);
1169
        ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1170
        FT0 = float128_to_float64(ft0_128, &env->fp_status);
1171
#else
1172
        /* This is OK on x86 hosts */
1173
        FT0 = (FT0 * FT1) - FT2;
1174
#endif
1175
    }
1176
}
1177
#endif /* USE_PRECISE_EMULATION */
1178

    
1179
void do_fnmadd (void)
1180
{
1181
    if (unlikely(float64_is_signaling_nan(FT0) ||
1182
                 float64_is_signaling_nan(FT1) ||
1183
                 float64_is_signaling_nan(FT2))) {
1184
        /* sNaN operation */
1185
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1186
    } else {
1187
#if USE_PRECISE_EMULATION
1188
#ifdef FLOAT128
1189
        /* This is the way the PowerPC specification defines it */
1190
        float128 ft0_128, ft1_128;
1191

    
1192
        ft0_128 = float64_to_float128(FT0, &env->fp_status);
1193
        ft1_128 = float64_to_float128(FT1, &env->fp_status);
1194
        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1195
        ft1_128 = float64_to_float128(FT2, &env->fp_status);
1196
        ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1197
        FT0 = float128_to_float64(ft0_128, &env->fp_status);
1198
#else
1199
        /* This is OK on x86 hosts */
1200
        FT0 = (FT0 * FT1) + FT2;
1201
#endif
1202
#else
1203
        FT0 = float64_mul(FT0, FT1, &env->fp_status);
1204
        FT0 = float64_add(FT0, FT2, &env->fp_status);
1205
#endif
1206
        if (likely(!isnan(FT0)))
1207
            FT0 = float64_chs(FT0);
1208
    }
1209
}
1210

    
1211
void do_fnmsub (void)
1212
{
1213
    if (unlikely(float64_is_signaling_nan(FT0) ||
1214
                 float64_is_signaling_nan(FT1) ||
1215
                 float64_is_signaling_nan(FT2))) {
1216
        /* sNaN operation */
1217
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1218
    } else {
1219
#if USE_PRECISE_EMULATION
1220
#ifdef FLOAT128
1221
        /* This is the way the PowerPC specification defines it */
1222
        float128 ft0_128, ft1_128;
1223

    
1224
        ft0_128 = float64_to_float128(FT0, &env->fp_status);
1225
        ft1_128 = float64_to_float128(FT1, &env->fp_status);
1226
        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1227
        ft1_128 = float64_to_float128(FT2, &env->fp_status);
1228
        ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1229
        FT0 = float128_to_float64(ft0_128, &env->fp_status);
1230
#else
1231
        /* This is OK on x86 hosts */
1232
        FT0 = (FT0 * FT1) - FT2;
1233
#endif
1234
#else
1235
        FT0 = float64_mul(FT0, FT1, &env->fp_status);
1236
        FT0 = float64_sub(FT0, FT2, &env->fp_status);
1237
#endif
1238
        if (likely(!isnan(FT0)))
1239
            FT0 = float64_chs(FT0);
1240
    }
1241
}
1242

    
1243
#if USE_PRECISE_EMULATION
1244
void do_frsp (void)
1245
{
1246
    if (unlikely(float64_is_signaling_nan(FT0))) {
1247
        /* sNaN square root */
1248
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1249
    } else {
1250
        FT0 = float64_to_float32(FT0, &env->fp_status);
1251
    }
1252
}
1253
#endif /* USE_PRECISE_EMULATION */
1254

    
1255
void do_fsqrt (void)
1256
{
1257
    if (unlikely(float64_is_signaling_nan(FT0))) {
1258
        /* sNaN square root */
1259
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1260
    } else if (unlikely(fpisneg(FT0) && !iszero(FT0))) {
1261
        /* Square root of a negative nonzero number */
1262
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
1263
    } else {
1264
        FT0 = float64_sqrt(FT0, &env->fp_status);
1265
    }
1266
}
1267

    
1268
void do_fre (void)
1269
{
1270
    union {
1271
        double d;
1272
        uint64_t i;
1273
    } p;
1274

    
1275
    if (unlikely(float64_is_signaling_nan(FT0))) {
1276
        /* sNaN reciprocal */
1277
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1278
    } else if (unlikely(iszero(FT0))) {
1279
        /* Zero reciprocal */
1280
        float_zero_divide_excp();
1281
    } else if (likely(isnormal(FT0))) {
1282
        FT0 = float64_div(1.0, FT0, &env->fp_status);
1283
    } else {
1284
        p.d = FT0;
1285
        if (p.i == 0x8000000000000000ULL) {
1286
            p.i = 0xFFF0000000000000ULL;
1287
        } else if (p.i == 0x0000000000000000ULL) {
1288
            p.i = 0x7FF0000000000000ULL;
1289
        } else if (isnan(FT0)) {
1290
            p.i = 0x7FF8000000000000ULL;
1291
        } else if (fpisneg(FT0)) {
1292
            p.i = 0x8000000000000000ULL;
1293
        } else {
1294
            p.i = 0x0000000000000000ULL;
1295
        }
1296
        FT0 = p.d;
1297
    }
1298
}
1299

    
1300
void do_fres (void)
1301
{
1302
    union {
1303
        double d;
1304
        uint64_t i;
1305
    } p;
1306

    
1307
    if (unlikely(float64_is_signaling_nan(FT0))) {
1308
        /* sNaN reciprocal */
1309
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1310
    } else if (unlikely(iszero(FT0))) {
1311
        /* Zero reciprocal */
1312
        float_zero_divide_excp();
1313
    } else if (likely(isnormal(FT0))) {
1314
#if USE_PRECISE_EMULATION
1315
        FT0 = float64_div(1.0, FT0, &env->fp_status);
1316
        FT0 = float64_to_float32(FT0, &env->fp_status);
1317
#else
1318
        FT0 = float32_div(1.0, FT0, &env->fp_status);
1319
#endif
1320
    } else {
1321
        p.d = FT0;
1322
        if (p.i == 0x8000000000000000ULL) {
1323
            p.i = 0xFFF0000000000000ULL;
1324
        } else if (p.i == 0x0000000000000000ULL) {
1325
            p.i = 0x7FF0000000000000ULL;
1326
        } else if (isnan(FT0)) {
1327
            p.i = 0x7FF8000000000000ULL;
1328
        } else if (fpisneg(FT0)) {
1329
            p.i = 0x8000000000000000ULL;
1330
        } else {
1331
            p.i = 0x0000000000000000ULL;
1332
        }
1333
        FT0 = p.d;
1334
    }
1335
}
1336

    
1337
void do_frsqrte (void)
1338
{
1339
    union {
1340
        double d;
1341
        uint64_t i;
1342
    } p;
1343

    
1344
    if (unlikely(float64_is_signaling_nan(FT0))) {
1345
        /* sNaN reciprocal square root */
1346
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1347
    } else if (unlikely(fpisneg(FT0) && !iszero(FT0))) {
1348
        /* Reciprocal square root of a negative nonzero number */
1349
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
1350
    } else if (likely(isnormal(FT0))) {
1351
        FT0 = float64_sqrt(FT0, &env->fp_status);
1352
        FT0 = float32_div(1.0, FT0, &env->fp_status);
1353
    } else {
1354
        p.d = FT0;
1355
        if (p.i == 0x8000000000000000ULL) {
1356
            p.i = 0xFFF0000000000000ULL;
1357
        } else if (p.i == 0x0000000000000000ULL) {
1358
            p.i = 0x7FF0000000000000ULL;
1359
        } else if (isnan(FT0)) {
1360
            p.i |= 0x000FFFFFFFFFFFFFULL;
1361
        } else if (fpisneg(FT0)) {
1362
            p.i = 0x7FF8000000000000ULL;
1363
        } else {
1364
            p.i = 0x0000000000000000ULL;
1365
        }
1366
        FT0 = p.d;
1367
    }
1368
}
1369

    
1370
void do_fsel (void)
1371
{
1372
    if (!fpisneg(FT0) || iszero(FT0))
1373
        FT0 = FT1;
1374
    else
1375
        FT0 = FT2;
1376
}
1377

    
1378
void do_fcmpu (void)
1379
{
1380
    if (unlikely(float64_is_signaling_nan(FT0) ||
1381
                 float64_is_signaling_nan(FT1))) {
1382
        /* sNaN comparison */
1383
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1384
    } else {
1385
        if (float64_lt(FT0, FT1, &env->fp_status)) {
1386
            T0 = 0x08UL;
1387
        } else if (!float64_le(FT0, FT1, &env->fp_status)) {
1388
            T0 = 0x04UL;
1389
        } else {
1390
            T0 = 0x02UL;
1391
        }
1392
    }
1393
    env->fpscr &= ~(0x0F << FPSCR_FPRF);
1394
    env->fpscr |= T0 << FPSCR_FPRF;
1395
}
1396

    
1397
void do_fcmpo (void)
1398
{
1399
    if (unlikely(float64_is_nan(FT0) ||
1400
                 float64_is_nan(FT1))) {
1401
        if (float64_is_signaling_nan(FT0) ||
1402
            float64_is_signaling_nan(FT1)) {
1403
            /* sNaN comparison */
1404
            fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
1405
                                  POWERPC_EXCP_FP_VXVC);
1406
        } else {
1407
            /* qNaN comparison */
1408
            fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
1409
        }
1410
    } else {
1411
        if (float64_lt(FT0, FT1, &env->fp_status)) {
1412
            T0 = 0x08UL;
1413
        } else if (!float64_le(FT0, FT1, &env->fp_status)) {
1414
            T0 = 0x04UL;
1415
        } else {
1416
            T0 = 0x02UL;
1417
        }
1418
    }
1419
    env->fpscr &= ~(0x0F << FPSCR_FPRF);
1420
    env->fpscr |= T0 << FPSCR_FPRF;
1421
}
1422

    
1423
#if !defined (CONFIG_USER_ONLY)
1424
void cpu_dump_rfi (target_ulong RA, target_ulong msr);
1425

    
1426
void do_store_msr (void)
1427
{
1428
    T0 = hreg_store_msr(env, T0);
1429
    if (T0 != 0) {
1430
        env->interrupt_request |= CPU_INTERRUPT_EXITTB;
1431
        do_raise_exception(T0);
1432
    }
1433
}
1434

    
1435
static always_inline void __do_rfi (target_ulong nip, target_ulong msr,
1436
                                    target_ulong msrm, int keep_msrh)
1437
{
1438
#if defined(TARGET_PPC64)
1439
    if (msr & (1ULL << MSR_SF)) {
1440
        nip = (uint64_t)nip;
1441
        msr &= (uint64_t)msrm;
1442
    } else {
1443
        nip = (uint32_t)nip;
1444
        msr = (uint32_t)(msr & msrm);
1445
        if (keep_msrh)
1446
            msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
1447
    }
1448
#else
1449
    nip = (uint32_t)nip;
1450
    msr &= (uint32_t)msrm;
1451
#endif
1452
    /* XXX: beware: this is false if VLE is supported */
1453
    env->nip = nip & ~((target_ulong)0x00000003);
1454
    hreg_store_msr(env, msr);
1455
#if defined (DEBUG_OP)
1456
    cpu_dump_rfi(env->nip, env->msr);
1457
#endif
1458
    /* No need to raise an exception here,
1459
     * as rfi is always the last insn of a TB
1460
     */
1461
    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
1462
}
1463

    
1464
void do_rfi (void)
1465
{
1466
    __do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1467
             ~((target_ulong)0xFFFF0000), 1);
1468
}
1469

    
1470
#if defined(TARGET_PPC64)
1471
void do_rfid (void)
1472
{
1473
    __do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1474
             ~((target_ulong)0xFFFF0000), 0);
1475
}
1476

    
1477
void do_hrfid (void)
1478
{
1479
    __do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
1480
             ~((target_ulong)0xFFFF0000), 0);
1481
}
1482
#endif
1483
#endif
1484

    
1485
void do_tw (int flags)
1486
{
1487
    if (!likely(!(((int32_t)T0 < (int32_t)T1 && (flags & 0x10)) ||
1488
                  ((int32_t)T0 > (int32_t)T1 && (flags & 0x08)) ||
1489
                  ((int32_t)T0 == (int32_t)T1 && (flags & 0x04)) ||
1490
                  ((uint32_t)T0 < (uint32_t)T1 && (flags & 0x02)) ||
1491
                  ((uint32_t)T0 > (uint32_t)T1 && (flags & 0x01))))) {
1492
        do_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
1493
    }
1494
}
1495

    
1496
#if defined(TARGET_PPC64)
1497
void do_td (int flags)
1498
{
1499
    if (!likely(!(((int64_t)T0 < (int64_t)T1 && (flags & 0x10)) ||
1500
                  ((int64_t)T0 > (int64_t)T1 && (flags & 0x08)) ||
1501
                  ((int64_t)T0 == (int64_t)T1 && (flags & 0x04)) ||
1502
                  ((uint64_t)T0 < (uint64_t)T1 && (flags & 0x02)) ||
1503
                  ((uint64_t)T0 > (uint64_t)T1 && (flags & 0x01)))))
1504
        do_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
1505
}
1506
#endif
1507

    
1508
/*****************************************************************************/
1509
/* PowerPC 601 specific instructions (POWER bridge) */
1510
void do_POWER_abso (void)
1511
{
1512
    if ((int32_t)T0 == INT32_MIN) {
1513
        T0 = INT32_MAX;
1514
        xer_ov = 1;
1515
    } else if ((int32_t)T0 < 0) {
1516
        T0 = -T0;
1517
        xer_ov = 0;
1518
    } else {
1519
        xer_ov = 0;
1520
    }
1521
    xer_so |= xer_ov;
1522
}
1523

    
1524
void do_POWER_clcs (void)
1525
{
1526
    switch (T0) {
1527
    case 0x0CUL:
1528
        /* Instruction cache line size */
1529
        T0 = env->icache_line_size;
1530
        break;
1531
    case 0x0DUL:
1532
        /* Data cache line size */
1533
        T0 = env->dcache_line_size;
1534
        break;
1535
    case 0x0EUL:
1536
        /* Minimum cache line size */
1537
        T0 = env->icache_line_size < env->dcache_line_size ?
1538
            env->icache_line_size : env->dcache_line_size;
1539
        break;
1540
    case 0x0FUL:
1541
        /* Maximum cache line size */
1542
        T0 = env->icache_line_size > env->dcache_line_size ?
1543
            env->icache_line_size : env->dcache_line_size;
1544
        break;
1545
    default:
1546
        /* Undefined */
1547
        break;
1548
    }
1549
}
1550

    
1551
void do_POWER_div (void)
1552
{
1553
    uint64_t tmp;
1554

    
1555
    if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
1556
        (int32_t)T1 == 0) {
1557
        T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
1558
        env->spr[SPR_MQ] = 0;
1559
    } else {
1560
        tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ];
1561
        env->spr[SPR_MQ] = tmp % T1;
1562
        T0 = tmp / (int32_t)T1;
1563
    }
1564
}
1565

    
1566
void do_POWER_divo (void)
1567
{
1568
    int64_t tmp;
1569

    
1570
    if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
1571
        (int32_t)T1 == 0) {
1572
        T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
1573
        env->spr[SPR_MQ] = 0;
1574
        xer_ov = 1;
1575
    } else {
1576
        tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ];
1577
        env->spr[SPR_MQ] = tmp % T1;
1578
        tmp /= (int32_t)T1;
1579
        if (tmp > (int64_t)INT32_MAX || tmp < (int64_t)INT32_MIN) {
1580
            xer_ov = 1;
1581
        } else {
1582
            xer_ov = 0;
1583
        }
1584
        T0 = tmp;
1585
    }
1586
    xer_so |= xer_ov;
1587
}
1588

    
1589
void do_POWER_divs (void)
1590
{
1591
    if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
1592
        (int32_t)T1 == 0) {
1593
        T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
1594
        env->spr[SPR_MQ] = 0;
1595
    } else {
1596
        env->spr[SPR_MQ] = T0 % T1;
1597
        T0 = (int32_t)T0 / (int32_t)T1;
1598
    }
1599
}
1600

    
1601
void do_POWER_divso (void)
1602
{
1603
    if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
1604
        (int32_t)T1 == 0) {
1605
        T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
1606
        env->spr[SPR_MQ] = 0;
1607
        xer_ov = 1;
1608
    } else {
1609
        T0 = (int32_t)T0 / (int32_t)T1;
1610
        env->spr[SPR_MQ] = (int32_t)T0 % (int32_t)T1;
1611
        xer_ov = 0;
1612
    }
1613
    xer_so |= xer_ov;
1614
}
1615

    
1616
void do_POWER_dozo (void)
1617
{
1618
    if ((int32_t)T1 > (int32_t)T0) {
1619
        T2 = T0;
1620
        T0 = T1 - T0;
1621
        if (((uint32_t)(~T2) ^ (uint32_t)T1 ^ UINT32_MAX) &
1622
            ((uint32_t)(~T2) ^ (uint32_t)T0) & (1UL << 31)) {
1623
            xer_ov = 1;
1624
            xer_so = 1;
1625
        } else {
1626
            xer_ov = 0;
1627
        }
1628
    } else {
1629
        T0 = 0;
1630
        xer_ov = 0;
1631
    }
1632
}
1633

    
1634
void do_POWER_maskg (void)
1635
{
1636
    uint32_t ret;
1637

    
1638
    if ((uint32_t)T0 == (uint32_t)(T1 + 1)) {
1639
        ret = UINT32_MAX;
1640
    } else {
1641
        ret = (UINT32_MAX >> ((uint32_t)T0)) ^
1642
            ((UINT32_MAX >> ((uint32_t)T1)) >> 1);
1643
        if ((uint32_t)T0 > (uint32_t)T1)
1644
            ret = ~ret;
1645
    }
1646
    T0 = ret;
1647
}
1648

    
1649
void do_POWER_mulo (void)
1650
{
1651
    uint64_t tmp;
1652

    
1653
    tmp = (uint64_t)T0 * (uint64_t)T1;
1654
    env->spr[SPR_MQ] = tmp >> 32;
1655
    T0 = tmp;
1656
    if (tmp >> 32 != ((uint64_t)T0 >> 16) * ((uint64_t)T1 >> 16)) {
1657
        xer_ov = 1;
1658
        xer_so = 1;
1659
    } else {
1660
        xer_ov = 0;
1661
    }
1662
}
1663

    
1664
#if !defined (CONFIG_USER_ONLY)
1665
void do_POWER_rac (void)
1666
{
1667
    mmu_ctx_t ctx;
1668
    int nb_BATs;
1669

    
1670
    /* We don't have to generate many instances of this instruction,
1671
     * as rac is supervisor only.
1672
     */
1673
    /* XXX: FIX THIS: Pretend we have no BAT */
1674
    nb_BATs = env->nb_BATs;
1675
    env->nb_BATs = 0;
1676
    if (get_physical_address(env, &ctx, T0, 0, ACCESS_INT) == 0)
1677
        T0 = ctx.raddr;
1678
    env->nb_BATs = nb_BATs;
1679
}
1680

    
1681
void do_POWER_rfsvc (void)
1682
{
1683
    __do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
1684
}
1685

    
1686
void do_store_hid0_601 (void)
1687
{
1688
    uint32_t hid0;
1689

    
1690
    hid0 = env->spr[SPR_HID0];
1691
    if ((T0 ^ hid0) & 0x00000008) {
1692
        /* Change current endianness */
1693
        env->hflags &= ~(1 << MSR_LE);
1694
        env->hflags_nmsr &= ~(1 << MSR_LE);
1695
        env->hflags_nmsr |= (1 << MSR_LE) & (((T0 >> 3) & 1) << MSR_LE);
1696
        env->hflags |= env->hflags_nmsr;
1697
        if (loglevel != 0) {
1698
            fprintf(logfile, "%s: set endianness to %c => " ADDRX "\n",
1699
                    __func__, T0 & 0x8 ? 'l' : 'b', env->hflags);
1700
        }
1701
    }
1702
    env->spr[SPR_HID0] = T0;
1703
}
1704
#endif
1705

    
1706
/*****************************************************************************/
1707
/* 602 specific instructions */
1708
/* mfrom is the most crazy instruction ever seen, imho ! */
1709
/* Real implementation uses a ROM table. Do the same */
1710
#define USE_MFROM_ROM_TABLE
1711
void do_op_602_mfrom (void)
1712
{
1713
    if (likely(T0 < 602)) {
1714
#if defined(USE_MFROM_ROM_TABLE)
1715
#include "mfrom_table.c"
1716
        T0 = mfrom_ROM_table[T0];
1717
#else
1718
        double d;
1719
        /* Extremly decomposed:
1720
         *                    -T0 / 256
1721
         * T0 = 256 * log10(10          + 1.0) + 0.5
1722
         */
1723
        d = T0;
1724
        d = float64_div(d, 256, &env->fp_status);
1725
        d = float64_chs(d);
1726
        d = exp10(d); // XXX: use float emulation function
1727
        d = float64_add(d, 1.0, &env->fp_status);
1728
        d = log10(d); // XXX: use float emulation function
1729
        d = float64_mul(d, 256, &env->fp_status);
1730
        d = float64_add(d, 0.5, &env->fp_status);
1731
        T0 = float64_round_to_int(d, &env->fp_status);
1732
#endif
1733
    } else {
1734
        T0 = 0;
1735
    }
1736
}
1737

    
1738
/*****************************************************************************/
1739
/* Embedded PowerPC specific helpers */
1740
void do_405_check_sat (void)
1741
{
1742
    if (!likely((((uint32_t)T1 ^ (uint32_t)T2) >> 31) ||
1743
                !(((uint32_t)T0 ^ (uint32_t)T2) >> 31))) {
1744
        /* Saturate result */
1745
        if (T2 >> 31) {
1746
            T0 = INT32_MIN;
1747
        } else {
1748
            T0 = INT32_MAX;
1749
        }
1750
    }
1751
}
1752

    
1753
/* XXX: to be improved to check access rights when in user-mode */
1754
void do_load_dcr (void)
1755
{
1756
    target_ulong val;
1757

    
1758
    if (unlikely(env->dcr_env == NULL)) {
1759
        if (loglevel != 0) {
1760
            fprintf(logfile, "No DCR environment\n");
1761
        }
1762
        do_raise_exception_err(POWERPC_EXCP_PROGRAM,
1763
                               POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
1764
    } else if (unlikely(ppc_dcr_read(env->dcr_env, T0, &val) != 0)) {
1765
        if (loglevel != 0) {
1766
            fprintf(logfile, "DCR read error %d %03x\n", (int)T0, (int)T0);
1767
        }
1768
        do_raise_exception_err(POWERPC_EXCP_PROGRAM,
1769
                               POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1770
    } else {
1771
        T0 = val;
1772
    }
1773
}
1774

    
1775
void do_store_dcr (void)
1776
{
1777
    if (unlikely(env->dcr_env == NULL)) {
1778
        if (loglevel != 0) {
1779
            fprintf(logfile, "No DCR environment\n");
1780
        }
1781
        do_raise_exception_err(POWERPC_EXCP_PROGRAM,
1782
                               POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
1783
    } else if (unlikely(ppc_dcr_write(env->dcr_env, T0, T1) != 0)) {
1784
        if (loglevel != 0) {
1785
            fprintf(logfile, "DCR write error %d %03x\n", (int)T0, (int)T0);
1786
        }
1787
        do_raise_exception_err(POWERPC_EXCP_PROGRAM,
1788
                               POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1789
    }
1790
}
1791

    
1792
#if !defined(CONFIG_USER_ONLY)
1793
void do_40x_rfci (void)
1794
{
1795
    __do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
1796
             ~((target_ulong)0xFFFF0000), 0);
1797
}
1798

    
1799
void do_rfci (void)
1800
{
1801
    __do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
1802
             ~((target_ulong)0x3FFF0000), 0);
1803
}
1804

    
1805
void do_rfdi (void)
1806
{
1807
    __do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
1808
             ~((target_ulong)0x3FFF0000), 0);
1809
}
1810

    
1811
void do_rfmci (void)
1812
{
1813
    __do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
1814
             ~((target_ulong)0x3FFF0000), 0);
1815
}
1816

    
1817
void do_load_403_pb (int num)
1818
{
1819
    T0 = env->pb[num];
1820
}
1821

    
1822
void do_store_403_pb (int num)
1823
{
1824
    if (likely(env->pb[num] != T0)) {
1825
        env->pb[num] = T0;
1826
        /* Should be optimized */
1827
        tlb_flush(env, 1);
1828
    }
1829
}
1830
#endif
1831

    
1832
/* 440 specific */
1833
void do_440_dlmzb (void)
1834
{
1835
    target_ulong mask;
1836
    int i;
1837

    
1838
    i = 1;
1839
    for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1840
        if ((T0 & mask) == 0)
1841
            goto done;
1842
        i++;
1843
    }
1844
    for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1845
        if ((T1 & mask) == 0)
1846
            break;
1847
        i++;
1848
    }
1849
 done:
1850
    T0 = i;
1851
}
1852

    
1853
/* SPE extension helpers */
1854
/* Use a table to make this quicker */
1855
static uint8_t hbrev[16] = {
1856
    0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
1857
    0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
1858
};
1859

    
1860
static always_inline uint8_t byte_reverse (uint8_t val)
1861
{
1862
    return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
1863
}
1864

    
1865
static always_inline uint32_t word_reverse (uint32_t val)
1866
{
1867
    return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
1868
        (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
1869
}
1870

    
1871
#define MASKBITS 16 // Random value - to be fixed (implementation dependant)
1872
void do_brinc (void)
1873
{
1874
    uint32_t a, b, d, mask;
1875

    
1876
    mask = UINT32_MAX >> (32 - MASKBITS);
1877
    a = T0 & mask;
1878
    b = T1 & mask;
1879
    d = word_reverse(1 + word_reverse(a | ~b));
1880
    T0 = (T0 & ~mask) | (d & b);
1881
}
1882

    
1883
#define DO_SPE_OP2(name)                                                      \
1884
void do_ev##name (void)                                                       \
1885
{                                                                             \
1886
    T0_64 = ((uint64_t)_do_e##name(T0_64 >> 32, T1_64 >> 32) << 32) |         \
1887
        (uint64_t)_do_e##name(T0_64, T1_64);                                  \
1888
}
1889

    
1890
#define DO_SPE_OP1(name)                                                      \
1891
void do_ev##name (void)                                                       \
1892
{                                                                             \
1893
    T0_64 = ((uint64_t)_do_e##name(T0_64 >> 32) << 32) |                      \
1894
        (uint64_t)_do_e##name(T0_64);                                         \
1895
}
1896

    
1897
/* Fixed-point vector arithmetic */
1898
static always_inline uint32_t _do_eabs (uint32_t val)
1899
{
1900
    if ((val & 0x80000000) && val != 0x80000000)
1901
        val -= val;
1902

    
1903
    return val;
1904
}
1905

    
1906
static always_inline uint32_t _do_eaddw (uint32_t op1, uint32_t op2)
1907
{
1908
    return op1 + op2;
1909
}
1910

    
1911
static always_inline int _do_ecntlsw (uint32_t val)
1912
{
1913
    if (val & 0x80000000)
1914
        return clz32(~val);
1915
    else
1916
        return clz32(val);
1917
}
1918

    
1919
static always_inline int _do_ecntlzw (uint32_t val)
1920
{
1921
    return clz32(val);
1922
}
1923

    
1924
static always_inline uint32_t _do_eneg (uint32_t val)
1925
{
1926
    if (val != 0x80000000)
1927
        val -= val;
1928

    
1929
    return val;
1930
}
1931

    
1932
static always_inline uint32_t _do_erlw (uint32_t op1, uint32_t op2)
1933
{
1934
    return rotl32(op1, op2);
1935
}
1936

    
1937
static always_inline uint32_t _do_erndw (uint32_t val)
1938
{
1939
    return (val + 0x000080000000) & 0xFFFF0000;
1940
}
1941

    
1942
static always_inline uint32_t _do_eslw (uint32_t op1, uint32_t op2)
1943
{
1944
    /* No error here: 6 bits are used */
1945
    return op1 << (op2 & 0x3F);
1946
}
1947

    
1948
static always_inline int32_t _do_esrws (int32_t op1, uint32_t op2)
1949
{
1950
    /* No error here: 6 bits are used */
1951
    return op1 >> (op2 & 0x3F);
1952
}
1953

    
1954
static always_inline uint32_t _do_esrwu (uint32_t op1, uint32_t op2)
1955
{
1956
    /* No error here: 6 bits are used */
1957
    return op1 >> (op2 & 0x3F);
1958
}
1959

    
1960
static always_inline uint32_t _do_esubfw (uint32_t op1, uint32_t op2)
1961
{
1962
    return op2 - op1;
1963
}
1964

    
1965
/* evabs */
1966
DO_SPE_OP1(abs);
1967
/* evaddw */
1968
DO_SPE_OP2(addw);
1969
/* evcntlsw */
1970
DO_SPE_OP1(cntlsw);
1971
/* evcntlzw */
1972
DO_SPE_OP1(cntlzw);
1973
/* evneg */
1974
DO_SPE_OP1(neg);
1975
/* evrlw */
1976
DO_SPE_OP2(rlw);
1977
/* evrnd */
1978
DO_SPE_OP1(rndw);
1979
/* evslw */
1980
DO_SPE_OP2(slw);
1981
/* evsrws */
1982
DO_SPE_OP2(srws);
1983
/* evsrwu */
1984
DO_SPE_OP2(srwu);
1985
/* evsubfw */
1986
DO_SPE_OP2(subfw);
1987

    
1988
/* evsel is a little bit more complicated... */
1989
static always_inline uint32_t _do_esel (uint32_t op1, uint32_t op2, int n)
1990
{
1991
    if (n)
1992
        return op1;
1993
    else
1994
        return op2;
1995
}
1996

    
1997
void do_evsel (void)
1998
{
1999
    T0_64 = ((uint64_t)_do_esel(T0_64 >> 32, T1_64 >> 32, T0 >> 3) << 32) |
2000
        (uint64_t)_do_esel(T0_64, T1_64, (T0 >> 2) & 1);
2001
}
2002

    
2003
/* Fixed-point vector comparisons */
2004
#define DO_SPE_CMP(name)                                                      \
2005
void do_ev##name (void)                                                       \
2006
{                                                                             \
2007
    T0 = _do_evcmp_merge((uint64_t)_do_e##name(T0_64 >> 32,                   \
2008
                                               T1_64 >> 32) << 32,            \
2009
                         _do_e##name(T0_64, T1_64));                          \
2010
}
2011

    
2012
static always_inline uint32_t _do_evcmp_merge (int t0, int t1)
2013
{
2014
    return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
2015
}
2016
static always_inline int _do_ecmpeq (uint32_t op1, uint32_t op2)
2017
{
2018
    return op1 == op2 ? 1 : 0;
2019
}
2020

    
2021
static always_inline int _do_ecmpgts (int32_t op1, int32_t op2)
2022
{
2023
    return op1 > op2 ? 1 : 0;
2024
}
2025

    
2026
static always_inline int _do_ecmpgtu (uint32_t op1, uint32_t op2)
2027
{
2028
    return op1 > op2 ? 1 : 0;
2029
}
2030

    
2031
static always_inline int _do_ecmplts (int32_t op1, int32_t op2)
2032
{
2033
    return op1 < op2 ? 1 : 0;
2034
}
2035

    
2036
static always_inline int _do_ecmpltu (uint32_t op1, uint32_t op2)
2037
{
2038
    return op1 < op2 ? 1 : 0;
2039
}
2040

    
2041
/* evcmpeq */
2042
DO_SPE_CMP(cmpeq);
2043
/* evcmpgts */
2044
DO_SPE_CMP(cmpgts);
2045
/* evcmpgtu */
2046
DO_SPE_CMP(cmpgtu);
2047
/* evcmplts */
2048
DO_SPE_CMP(cmplts);
2049
/* evcmpltu */
2050
DO_SPE_CMP(cmpltu);
2051

    
2052
/* Single precision floating-point conversions from/to integer */
2053
static always_inline uint32_t _do_efscfsi (int32_t val)
2054
{
2055
    union {
2056
        uint32_t u;
2057
        float32 f;
2058
    } u;
2059

    
2060
    u.f = int32_to_float32(val, &env->spe_status);
2061

    
2062
    return u.u;
2063
}
2064

    
2065
static always_inline uint32_t _do_efscfui (uint32_t val)
2066
{
2067
    union {
2068
        uint32_t u;
2069
        float32 f;
2070
    } u;
2071

    
2072
    u.f = uint32_to_float32(val, &env->spe_status);
2073

    
2074
    return u.u;
2075
}
2076

    
2077
static always_inline int32_t _do_efsctsi (uint32_t val)
2078
{
2079
    union {
2080
        int32_t u;
2081
        float32 f;
2082
    } u;
2083

    
2084
    u.u = val;
2085
    /* NaN are not treated the same way IEEE 754 does */
2086
    if (unlikely(isnan(u.f)))
2087
        return 0;
2088

    
2089
    return float32_to_int32(u.f, &env->spe_status);
2090
}
2091

    
2092
static always_inline uint32_t _do_efsctui (uint32_t val)
2093
{
2094
    union {
2095
        int32_t u;
2096
        float32 f;
2097
    } u;
2098

    
2099
    u.u = val;
2100
    /* NaN are not treated the same way IEEE 754 does */
2101
    if (unlikely(isnan(u.f)))
2102
        return 0;
2103

    
2104
    return float32_to_uint32(u.f, &env->spe_status);
2105
}
2106

    
2107
static always_inline int32_t _do_efsctsiz (uint32_t val)
2108
{
2109
    union {
2110
        int32_t u;
2111
        float32 f;
2112
    } u;
2113

    
2114
    u.u = val;
2115
    /* NaN are not treated the same way IEEE 754 does */
2116
    if (unlikely(isnan(u.f)))
2117
        return 0;
2118

    
2119
    return float32_to_int32_round_to_zero(u.f, &env->spe_status);
2120
}
2121

    
2122
static always_inline uint32_t _do_efsctuiz (uint32_t val)
2123
{
2124
    union {
2125
        int32_t u;
2126
        float32 f;
2127
    } u;
2128

    
2129
    u.u = val;
2130
    /* NaN are not treated the same way IEEE 754 does */
2131
    if (unlikely(isnan(u.f)))
2132
        return 0;
2133

    
2134
    return float32_to_uint32_round_to_zero(u.f, &env->spe_status);
2135
}
2136

    
2137
void do_efscfsi (void)
2138
{
2139
    T0_64 = _do_efscfsi(T0_64);
2140
}
2141

    
2142
void do_efscfui (void)
2143
{
2144
    T0_64 = _do_efscfui(T0_64);
2145
}
2146

    
2147
void do_efsctsi (void)
2148
{
2149
    T0_64 = _do_efsctsi(T0_64);
2150
}
2151

    
2152
void do_efsctui (void)
2153
{
2154
    T0_64 = _do_efsctui(T0_64);
2155
}
2156

    
2157
void do_efsctsiz (void)
2158
{
2159
    T0_64 = _do_efsctsiz(T0_64);
2160
}
2161

    
2162
void do_efsctuiz (void)
2163
{
2164
    T0_64 = _do_efsctuiz(T0_64);
2165
}
2166

    
2167
/* Single precision floating-point conversion to/from fractional */
2168
static always_inline uint32_t _do_efscfsf (uint32_t val)
2169
{
2170
    union {
2171
        uint32_t u;
2172
        float32 f;
2173
    } u;
2174
    float32 tmp;
2175

    
2176
    u.f = int32_to_float32(val, &env->spe_status);
2177
    tmp = int64_to_float32(1ULL << 32, &env->spe_status);
2178
    u.f = float32_div(u.f, tmp, &env->spe_status);
2179

    
2180
    return u.u;
2181
}
2182

    
2183
static always_inline uint32_t _do_efscfuf (uint32_t val)
2184
{
2185
    union {
2186
        uint32_t u;
2187
        float32 f;
2188
    } u;
2189
    float32 tmp;
2190

    
2191
    u.f = uint32_to_float32(val, &env->spe_status);
2192
    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2193
    u.f = float32_div(u.f, tmp, &env->spe_status);
2194

    
2195
    return u.u;
2196
}
2197

    
2198
static always_inline int32_t _do_efsctsf (uint32_t val)
2199
{
2200
    union {
2201
        int32_t u;
2202
        float32 f;
2203
    } u;
2204
    float32 tmp;
2205

    
2206
    u.u = val;
2207
    /* NaN are not treated the same way IEEE 754 does */
2208
    if (unlikely(isnan(u.f)))
2209
        return 0;
2210
    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2211
    u.f = float32_mul(u.f, tmp, &env->spe_status);
2212

    
2213
    return float32_to_int32(u.f, &env->spe_status);
2214
}
2215

    
2216
static always_inline uint32_t _do_efsctuf (uint32_t val)
2217
{
2218
    union {
2219
        int32_t u;
2220
        float32 f;
2221
    } u;
2222
    float32 tmp;
2223

    
2224
    u.u = val;
2225
    /* NaN are not treated the same way IEEE 754 does */
2226
    if (unlikely(isnan(u.f)))
2227
        return 0;
2228
    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2229
    u.f = float32_mul(u.f, tmp, &env->spe_status);
2230

    
2231
    return float32_to_uint32(u.f, &env->spe_status);
2232
}
2233

    
2234
static always_inline int32_t _do_efsctsfz (uint32_t val)
2235
{
2236
    union {
2237
        int32_t u;
2238
        float32 f;
2239
    } u;
2240
    float32 tmp;
2241

    
2242
    u.u = val;
2243
    /* NaN are not treated the same way IEEE 754 does */
2244
    if (unlikely(isnan(u.f)))
2245
        return 0;
2246
    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2247
    u.f = float32_mul(u.f, tmp, &env->spe_status);
2248

    
2249
    return float32_to_int32_round_to_zero(u.f, &env->spe_status);
2250
}
2251

    
2252
static always_inline uint32_t _do_efsctufz (uint32_t val)
2253
{
2254
    union {
2255
        int32_t u;
2256
        float32 f;
2257
    } u;
2258
    float32 tmp;
2259

    
2260
    u.u = val;
2261
    /* NaN are not treated the same way IEEE 754 does */
2262
    if (unlikely(isnan(u.f)))
2263
        return 0;
2264
    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2265
    u.f = float32_mul(u.f, tmp, &env->spe_status);
2266

    
2267
    return float32_to_uint32_round_to_zero(u.f, &env->spe_status);
2268
}
2269

    
2270
void do_efscfsf (void)
2271
{
2272
    T0_64 = _do_efscfsf(T0_64);
2273
}
2274

    
2275
void do_efscfuf (void)
2276
{
2277
    T0_64 = _do_efscfuf(T0_64);
2278
}
2279

    
2280
void do_efsctsf (void)
2281
{
2282
    T0_64 = _do_efsctsf(T0_64);
2283
}
2284

    
2285
void do_efsctuf (void)
2286
{
2287
    T0_64 = _do_efsctuf(T0_64);
2288
}
2289

    
2290
void do_efsctsfz (void)
2291
{
2292
    T0_64 = _do_efsctsfz(T0_64);
2293
}
2294

    
2295
void do_efsctufz (void)
2296
{
2297
    T0_64 = _do_efsctufz(T0_64);
2298
}
2299

    
2300
/* Double precision floating point helpers */
2301
static always_inline int _do_efdcmplt (uint64_t op1, uint64_t op2)
2302
{
2303
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2304
    return _do_efdtstlt(op1, op2);
2305
}
2306

    
2307
static always_inline int _do_efdcmpgt (uint64_t op1, uint64_t op2)
2308
{
2309
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2310
    return _do_efdtstgt(op1, op2);
2311
}
2312

    
2313
static always_inline int _do_efdcmpeq (uint64_t op1, uint64_t op2)
2314
{
2315
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2316
    return _do_efdtsteq(op1, op2);
2317
}
2318

    
2319
void do_efdcmplt (void)
2320
{
2321
    T0 = _do_efdcmplt(T0_64, T1_64);
2322
}
2323

    
2324
void do_efdcmpgt (void)
2325
{
2326
    T0 = _do_efdcmpgt(T0_64, T1_64);
2327
}
2328

    
2329
void do_efdcmpeq (void)
2330
{
2331
    T0 = _do_efdcmpeq(T0_64, T1_64);
2332
}
2333

    
2334
/* Double precision floating-point conversion to/from integer */
2335
static always_inline uint64_t _do_efdcfsi (int64_t val)
2336
{
2337
    union {
2338
        uint64_t u;
2339
        float64 f;
2340
    } u;
2341

    
2342
    u.f = int64_to_float64(val, &env->spe_status);
2343

    
2344
    return u.u;
2345
}
2346

    
2347
static always_inline uint64_t _do_efdcfui (uint64_t val)
2348
{
2349
    union {
2350
        uint64_t u;
2351
        float64 f;
2352
    } u;
2353

    
2354
    u.f = uint64_to_float64(val, &env->spe_status);
2355

    
2356
    return u.u;
2357
}
2358

    
2359
static always_inline int64_t _do_efdctsi (uint64_t val)
2360
{
2361
    union {
2362
        int64_t u;
2363
        float64 f;
2364
    } u;
2365

    
2366
    u.u = val;
2367
    /* NaN are not treated the same way IEEE 754 does */
2368
    if (unlikely(isnan(u.f)))
2369
        return 0;
2370

    
2371
    return float64_to_int64(u.f, &env->spe_status);
2372
}
2373

    
2374
static always_inline uint64_t _do_efdctui (uint64_t val)
2375
{
2376
    union {
2377
        int64_t u;
2378
        float64 f;
2379
    } u;
2380

    
2381
    u.u = val;
2382
    /* NaN are not treated the same way IEEE 754 does */
2383
    if (unlikely(isnan(u.f)))
2384
        return 0;
2385

    
2386
    return float64_to_uint64(u.f, &env->spe_status);
2387
}
2388

    
2389
static always_inline int64_t _do_efdctsiz (uint64_t val)
2390
{
2391
    union {
2392
        int64_t u;
2393
        float64 f;
2394
    } u;
2395

    
2396
    u.u = val;
2397
    /* NaN are not treated the same way IEEE 754 does */
2398
    if (unlikely(isnan(u.f)))
2399
        return 0;
2400

    
2401
    return float64_to_int64_round_to_zero(u.f, &env->spe_status);
2402
}
2403

    
2404
static always_inline uint64_t _do_efdctuiz (uint64_t val)
2405
{
2406
    union {
2407
        int64_t u;
2408
        float64 f;
2409
    } u;
2410

    
2411
    u.u = val;
2412
    /* NaN are not treated the same way IEEE 754 does */
2413
    if (unlikely(isnan(u.f)))
2414
        return 0;
2415

    
2416
    return float64_to_uint64_round_to_zero(u.f, &env->spe_status);
2417
}
2418

    
2419
void do_efdcfsi (void)
2420
{
2421
    T0_64 = _do_efdcfsi(T0_64);
2422
}
2423

    
2424
void do_efdcfui (void)
2425
{
2426
    T0_64 = _do_efdcfui(T0_64);
2427
}
2428

    
2429
void do_efdctsi (void)
2430
{
2431
    T0_64 = _do_efdctsi(T0_64);
2432
}
2433

    
2434
void do_efdctui (void)
2435
{
2436
    T0_64 = _do_efdctui(T0_64);
2437
}
2438

    
2439
void do_efdctsiz (void)
2440
{
2441
    T0_64 = _do_efdctsiz(T0_64);
2442
}
2443

    
2444
void do_efdctuiz (void)
2445
{
2446
    T0_64 = _do_efdctuiz(T0_64);
2447
}
2448

    
2449
/* Double precision floating-point conversion to/from fractional */
2450
static always_inline uint64_t _do_efdcfsf (int64_t val)
2451
{
2452
    union {
2453
        uint64_t u;
2454
        float64 f;
2455
    } u;
2456
    float64 tmp;
2457

    
2458
    u.f = int32_to_float64(val, &env->spe_status);
2459
    tmp = int64_to_float64(1ULL << 32, &env->spe_status);
2460
    u.f = float64_div(u.f, tmp, &env->spe_status);
2461

    
2462
    return u.u;
2463
}
2464

    
2465
static always_inline uint64_t _do_efdcfuf (uint64_t val)
2466
{
2467
    union {
2468
        uint64_t u;
2469
        float64 f;
2470
    } u;
2471
    float64 tmp;
2472

    
2473
    u.f = uint32_to_float64(val, &env->spe_status);
2474
    tmp = int64_to_float64(1ULL << 32, &env->spe_status);
2475
    u.f = float64_div(u.f, tmp, &env->spe_status);
2476

    
2477
    return u.u;
2478
}
2479

    
2480
static always_inline int64_t _do_efdctsf (uint64_t val)
2481
{
2482
    union {
2483
        int64_t u;
2484
        float64 f;
2485
    } u;
2486
    float64 tmp;
2487

    
2488
    u.u = val;
2489
    /* NaN are not treated the same way IEEE 754 does */
2490
    if (unlikely(isnan(u.f)))
2491
        return 0;
2492
    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
2493
    u.f = float64_mul(u.f, tmp, &env->spe_status);
2494

    
2495
    return float64_to_int32(u.f, &env->spe_status);
2496
}
2497

    
2498
static always_inline uint64_t _do_efdctuf (uint64_t val)
2499
{
2500
    union {
2501
        int64_t u;
2502
        float64 f;
2503
    } u;
2504
    float64 tmp;
2505

    
2506
    u.u = val;
2507
    /* NaN are not treated the same way IEEE 754 does */
2508
    if (unlikely(isnan(u.f)))
2509
        return 0;
2510
    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
2511
    u.f = float64_mul(u.f, tmp, &env->spe_status);
2512

    
2513
    return float64_to_uint32(u.f, &env->spe_status);
2514
}
2515

    
2516
static always_inline int64_t _do_efdctsfz (uint64_t val)
2517
{
2518
    union {
2519
        int64_t u;
2520
        float64 f;
2521
    } u;
2522
    float64 tmp;
2523

    
2524
    u.u = val;
2525
    /* NaN are not treated the same way IEEE 754 does */
2526
    if (unlikely(isnan(u.f)))
2527
        return 0;
2528
    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
2529
    u.f = float64_mul(u.f, tmp, &env->spe_status);
2530

    
2531
    return float64_to_int32_round_to_zero(u.f, &env->spe_status);
2532
}
2533

    
2534
static always_inline uint64_t _do_efdctufz (uint64_t val)
2535
{
2536
    union {
2537
        int64_t u;
2538
        float64 f;
2539
    } u;
2540
    float64 tmp;
2541

    
2542
    u.u = val;
2543
    /* NaN are not treated the same way IEEE 754 does */
2544
    if (unlikely(isnan(u.f)))
2545
        return 0;
2546
    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
2547
    u.f = float64_mul(u.f, tmp, &env->spe_status);
2548

    
2549
    return float64_to_uint32_round_to_zero(u.f, &env->spe_status);
2550
}
2551

    
2552
void do_efdcfsf (void)
2553
{
2554
    T0_64 = _do_efdcfsf(T0_64);
2555
}
2556

    
2557
void do_efdcfuf (void)
2558
{
2559
    T0_64 = _do_efdcfuf(T0_64);
2560
}
2561

    
2562
void do_efdctsf (void)
2563
{
2564
    T0_64 = _do_efdctsf(T0_64);
2565
}
2566

    
2567
void do_efdctuf (void)
2568
{
2569
    T0_64 = _do_efdctuf(T0_64);
2570
}
2571

    
2572
void do_efdctsfz (void)
2573
{
2574
    T0_64 = _do_efdctsfz(T0_64);
2575
}
2576

    
2577
void do_efdctufz (void)
2578
{
2579
    T0_64 = _do_efdctufz(T0_64);
2580
}
2581

    
2582
/* Floating point conversion between single and double precision */
2583
static always_inline uint32_t _do_efscfd (uint64_t val)
2584
{
2585
    union {
2586
        uint64_t u;
2587
        float64 f;
2588
    } u1;
2589
    union {
2590
        uint32_t u;
2591
        float32 f;
2592
    } u2;
2593

    
2594
    u1.u = val;
2595
    u2.f = float64_to_float32(u1.f, &env->spe_status);
2596

    
2597
    return u2.u;
2598
}
2599

    
2600
static always_inline uint64_t _do_efdcfs (uint32_t val)
2601
{
2602
    union {
2603
        uint64_t u;
2604
        float64 f;
2605
    } u2;
2606
    union {
2607
        uint32_t u;
2608
        float32 f;
2609
    } u1;
2610

    
2611
    u1.u = val;
2612
    u2.f = float32_to_float64(u1.f, &env->spe_status);
2613

    
2614
    return u2.u;
2615
}
2616

    
2617
void do_efscfd (void)
2618
{
2619
    T0_64 = _do_efscfd(T0_64);
2620
}
2621

    
2622
void do_efdcfs (void)
2623
{
2624
    T0_64 = _do_efdcfs(T0_64);
2625
}
2626

    
2627
/* Single precision fixed-point vector arithmetic */
2628
/* evfsabs */
2629
DO_SPE_OP1(fsabs);
2630
/* evfsnabs */
2631
DO_SPE_OP1(fsnabs);
2632
/* evfsneg */
2633
DO_SPE_OP1(fsneg);
2634
/* evfsadd */
2635
DO_SPE_OP2(fsadd);
2636
/* evfssub */
2637
DO_SPE_OP2(fssub);
2638
/* evfsmul */
2639
DO_SPE_OP2(fsmul);
2640
/* evfsdiv */
2641
DO_SPE_OP2(fsdiv);
2642

    
2643
/* Single-precision floating-point comparisons */
2644
static always_inline int _do_efscmplt (uint32_t op1, uint32_t op2)
2645
{
2646
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2647
    return _do_efststlt(op1, op2);
2648
}
2649

    
2650
static always_inline int _do_efscmpgt (uint32_t op1, uint32_t op2)
2651
{
2652
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2653
    return _do_efststgt(op1, op2);
2654
}
2655

    
2656
static always_inline int _do_efscmpeq (uint32_t op1, uint32_t op2)
2657
{
2658
    /* XXX: TODO: test special values (NaN, infinites, ...) */
2659
    return _do_efststeq(op1, op2);
2660
}
2661

    
2662
void do_efscmplt (void)
2663
{
2664
    T0 = _do_efscmplt(T0_64, T1_64);
2665
}
2666

    
2667
void do_efscmpgt (void)
2668
{
2669
    T0 = _do_efscmpgt(T0_64, T1_64);
2670
}
2671

    
2672
void do_efscmpeq (void)
2673
{
2674
    T0 = _do_efscmpeq(T0_64, T1_64);
2675
}
2676

    
2677
/* Single-precision floating-point vector comparisons */
2678
/* evfscmplt */
2679
DO_SPE_CMP(fscmplt);
2680
/* evfscmpgt */
2681
DO_SPE_CMP(fscmpgt);
2682
/* evfscmpeq */
2683
DO_SPE_CMP(fscmpeq);
2684
/* evfststlt */
2685
DO_SPE_CMP(fststlt);
2686
/* evfststgt */
2687
DO_SPE_CMP(fststgt);
2688
/* evfststeq */
2689
DO_SPE_CMP(fststeq);
2690

    
2691
/* Single-precision floating-point vector conversions */
2692
/* evfscfsi */
2693
DO_SPE_OP1(fscfsi);
2694
/* evfscfui */
2695
DO_SPE_OP1(fscfui);
2696
/* evfscfuf */
2697
DO_SPE_OP1(fscfuf);
2698
/* evfscfsf */
2699
DO_SPE_OP1(fscfsf);
2700
/* evfsctsi */
2701
DO_SPE_OP1(fsctsi);
2702
/* evfsctui */
2703
DO_SPE_OP1(fsctui);
2704
/* evfsctsiz */
2705
DO_SPE_OP1(fsctsiz);
2706
/* evfsctuiz */
2707
DO_SPE_OP1(fsctuiz);
2708
/* evfsctsf */
2709
DO_SPE_OP1(fsctsf);
2710
/* evfsctuf */
2711
DO_SPE_OP1(fsctuf);
2712

    
2713
/*****************************************************************************/
2714
/* Softmmu support */
2715
#if !defined (CONFIG_USER_ONLY)
2716

    
2717
#define MMUSUFFIX _mmu
2718
#ifdef __s390__
2719
# define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL))
2720
#else
2721
# define GETPC() (__builtin_return_address(0))
2722
#endif
2723

    
2724
#define SHIFT 0
2725
#include "softmmu_template.h"
2726

    
2727
#define SHIFT 1
2728
#include "softmmu_template.h"
2729

    
2730
#define SHIFT 2
2731
#include "softmmu_template.h"
2732

    
2733
#define SHIFT 3
2734
#include "softmmu_template.h"
2735

    
2736
/* try to fill the TLB and return an exception if error. If retaddr is
2737
   NULL, it means that the function was called in C code (i.e. not
2738
   from generated code or from helper.c) */
2739
/* XXX: fix it to restore all registers */
2740
void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
2741
{
2742
    TranslationBlock *tb;
2743
    CPUState *saved_env;
2744
    unsigned long pc;
2745
    int ret;
2746

    
2747
    /* XXX: hack to restore env in all cases, even if not called from
2748
       generated code */
2749
    saved_env = env;
2750
    env = cpu_single_env;
2751
    ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
2752
    if (unlikely(ret != 0)) {
2753
        if (likely(retaddr)) {
2754
            /* now we have a real cpu fault */
2755
            pc = (unsigned long)retaddr;
2756
            tb = tb_find_pc(pc);
2757
            if (likely(tb)) {
2758
                /* the PC is inside the translated code. It means that we have
2759
                   a virtual CPU fault */
2760
                cpu_restore_state(tb, env, pc, NULL);
2761
            }
2762
        }
2763
        do_raise_exception_err(env->exception_index, env->error_code);
2764
    }
2765
    env = saved_env;
2766
}
2767

    
2768
/* Software driven TLBs management */
2769
/* PowerPC 602/603 software TLB load instructions helpers */
2770
void do_load_6xx_tlb (int is_code)
2771
{
2772
    target_ulong RPN, CMP, EPN;
2773
    int way;
2774

    
2775
    RPN = env->spr[SPR_RPA];
2776
    if (is_code) {
2777
        CMP = env->spr[SPR_ICMP];
2778
        EPN = env->spr[SPR_IMISS];
2779
    } else {
2780
        CMP = env->spr[SPR_DCMP];
2781
        EPN = env->spr[SPR_DMISS];
2782
    }
2783
    way = (env->spr[SPR_SRR1] >> 17) & 1;
2784
#if defined (DEBUG_SOFTWARE_TLB)
2785
    if (loglevel != 0) {
2786
        fprintf(logfile, "%s: EPN %08lx %08lx PTE0 %08lx PTE1 %08lx way %d\n",
2787
                __func__, (unsigned long)T0, (unsigned long)EPN,
2788
                (unsigned long)CMP, (unsigned long)RPN, way);
2789
    }
2790
#endif
2791
    /* Store this TLB */
2792
    ppc6xx_tlb_store(env, (uint32_t)(T0 & TARGET_PAGE_MASK),
2793
                     way, is_code, CMP, RPN);
2794
}
2795

    
2796
void do_load_74xx_tlb (int is_code)
2797
{
2798
    target_ulong RPN, CMP, EPN;
2799
    int way;
2800

    
2801
    RPN = env->spr[SPR_PTELO];
2802
    CMP = env->spr[SPR_PTEHI];
2803
    EPN = env->spr[SPR_TLBMISS] & ~0x3;
2804
    way = env->spr[SPR_TLBMISS] & 0x3;
2805
#if defined (DEBUG_SOFTWARE_TLB)
2806
    if (loglevel != 0) {
2807
        fprintf(logfile, "%s: EPN %08lx %08lx PTE0 %08lx PTE1 %08lx way %d\n",
2808
                __func__, (unsigned long)T0, (unsigned long)EPN,
2809
                (unsigned long)CMP, (unsigned long)RPN, way);
2810
    }
2811
#endif
2812
    /* Store this TLB */
2813
    ppc6xx_tlb_store(env, (uint32_t)(T0 & TARGET_PAGE_MASK),
2814
                     way, is_code, CMP, RPN);
2815
}
2816

    
2817
static always_inline target_ulong booke_tlb_to_page_size (int size)
2818
{
2819
    return 1024 << (2 * size);
2820
}
2821

    
2822
static always_inline int booke_page_size_to_tlb (target_ulong page_size)
2823
{
2824
    int size;
2825

    
2826
    switch (page_size) {
2827
    case 0x00000400UL:
2828
        size = 0x0;
2829
        break;
2830
    case 0x00001000UL:
2831
        size = 0x1;
2832
        break;
2833
    case 0x00004000UL:
2834
        size = 0x2;
2835
        break;
2836
    case 0x00010000UL:
2837
        size = 0x3;
2838
        break;
2839
    case 0x00040000UL:
2840
        size = 0x4;
2841
        break;
2842
    case 0x00100000UL:
2843
        size = 0x5;
2844
        break;
2845
    case 0x00400000UL:
2846
        size = 0x6;
2847
        break;
2848
    case 0x01000000UL:
2849
        size = 0x7;
2850
        break;
2851
    case 0x04000000UL:
2852
        size = 0x8;
2853
        break;
2854
    case 0x10000000UL:
2855
        size = 0x9;
2856
        break;
2857
    case 0x40000000UL:
2858
        size = 0xA;
2859
        break;
2860
#if defined (TARGET_PPC64)
2861
    case 0x000100000000ULL:
2862
        size = 0xB;
2863
        break;
2864
    case 0x000400000000ULL:
2865
        size = 0xC;
2866
        break;
2867
    case 0x001000000000ULL:
2868
        size = 0xD;
2869
        break;
2870
    case 0x004000000000ULL:
2871
        size = 0xE;
2872
        break;
2873
    case 0x010000000000ULL:
2874
        size = 0xF;
2875
        break;
2876
#endif
2877
    default:
2878
        size = -1;
2879
        break;
2880
    }
2881

    
2882
    return size;
2883
}
2884

    
2885
/* Helpers for 4xx TLB management */
2886
void do_4xx_tlbre_lo (void)
2887
{
2888
    ppcemb_tlb_t *tlb;
2889
    int size;
2890

    
2891
    T0 &= 0x3F;
2892
    tlb = &env->tlb[T0].tlbe;
2893
    T0 = tlb->EPN;
2894
    if (tlb->prot & PAGE_VALID)
2895
        T0 |= 0x400;
2896
    size = booke_page_size_to_tlb(tlb->size);
2897
    if (size < 0 || size > 0x7)
2898
        size = 1;
2899
    T0 |= size << 7;
2900
    env->spr[SPR_40x_PID] = tlb->PID;
2901
}
2902

    
2903
void do_4xx_tlbre_hi (void)
2904
{
2905
    ppcemb_tlb_t *tlb;
2906

    
2907
    T0 &= 0x3F;
2908
    tlb = &env->tlb[T0].tlbe;
2909
    T0 = tlb->RPN;
2910
    if (tlb->prot & PAGE_EXEC)
2911
        T0 |= 0x200;
2912
    if (tlb->prot & PAGE_WRITE)
2913
        T0 |= 0x100;
2914
}
2915

    
2916
void do_4xx_tlbwe_hi (void)
2917
{
2918
    ppcemb_tlb_t *tlb;
2919
    target_ulong page, end;
2920

    
2921
#if defined (DEBUG_SOFTWARE_TLB)
2922
    if (loglevel != 0) {
2923
        fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1);
2924
    }
2925
#endif
2926
    T0 &= 0x3F;
2927
    tlb = &env->tlb[T0].tlbe;
2928
    /* Invalidate previous TLB (if it's valid) */
2929
    if (tlb->prot & PAGE_VALID) {
2930
        end = tlb->EPN + tlb->size;
2931
#if defined (DEBUG_SOFTWARE_TLB)
2932
        if (loglevel != 0) {
2933
            fprintf(logfile, "%s: invalidate old TLB %d start " ADDRX
2934
                    " end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end);
2935
        }
2936
#endif
2937
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
2938
            tlb_flush_page(env, page);
2939
    }
2940
    tlb->size = booke_tlb_to_page_size((T1 >> 7) & 0x7);
2941
    /* We cannot handle TLB size < TARGET_PAGE_SIZE.
2942
     * If this ever occurs, one should use the ppcemb target instead
2943
     * of the ppc or ppc64 one
2944
     */
2945
    if ((T1 & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
2946
        cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
2947
                  "are not supported (%d)\n",
2948
                  tlb->size, TARGET_PAGE_SIZE, (int)((T1 >> 7) & 0x7));
2949
    }
2950
    tlb->EPN = T1 & ~(tlb->size - 1);
2951
    if (T1 & 0x40)
2952
        tlb->prot |= PAGE_VALID;
2953
    else
2954
        tlb->prot &= ~PAGE_VALID;
2955
    if (T1 & 0x20) {
2956
        /* XXX: TO BE FIXED */
2957
        cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
2958
    }
2959
    tlb->PID = env->spr[SPR_40x_PID]; /* PID */
2960
    tlb->attr = T1 & 0xFF;
2961
#if defined (DEBUG_SOFTWARE_TLB)
2962
    if (loglevel != 0) {
2963
        fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
2964
                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
2965
                (int)T0, tlb->RPN, tlb->EPN, tlb->size,
2966
                tlb->prot & PAGE_READ ? 'r' : '-',
2967
                tlb->prot & PAGE_WRITE ? 'w' : '-',
2968
                tlb->prot & PAGE_EXEC ? 'x' : '-',
2969
                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2970
    }
2971
#endif
2972
    /* Invalidate new TLB (if valid) */
2973
    if (tlb->prot & PAGE_VALID) {
2974
        end = tlb->EPN + tlb->size;
2975
#if defined (DEBUG_SOFTWARE_TLB)
2976
        if (loglevel != 0) {
2977
            fprintf(logfile, "%s: invalidate TLB %d start " ADDRX
2978
                    " end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end);
2979
        }
2980
#endif
2981
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
2982
            tlb_flush_page(env, page);
2983
    }
2984
}
2985

    
2986
void do_4xx_tlbwe_lo (void)
2987
{
2988
    ppcemb_tlb_t *tlb;
2989

    
2990
#if defined (DEBUG_SOFTWARE_TLB)
2991
    if (loglevel != 0) {
2992
        fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1);
2993
    }
2994
#endif
2995
    T0 &= 0x3F;
2996
    tlb = &env->tlb[T0].tlbe;
2997
    tlb->RPN = T1 & 0xFFFFFC00;
2998
    tlb->prot = PAGE_READ;
2999
    if (T1 & 0x200)
3000
        tlb->prot |= PAGE_EXEC;
3001
    if (T1 & 0x100)
3002
        tlb->prot |= PAGE_WRITE;
3003
#if defined (DEBUG_SOFTWARE_TLB)
3004
    if (loglevel != 0) {
3005
        fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
3006
                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
3007
                (int)T0, tlb->RPN, tlb->EPN, tlb->size,
3008
                tlb->prot & PAGE_READ ? 'r' : '-',
3009
                tlb->prot & PAGE_WRITE ? 'w' : '-',
3010
                tlb->prot & PAGE_EXEC ? 'x' : '-',
3011
                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
3012
    }
3013
#endif
3014
}
3015

    
3016
/* PowerPC 440 TLB management */
3017
void do_440_tlbwe (int word)
3018
{
3019
    ppcemb_tlb_t *tlb;
3020
    target_ulong EPN, RPN, size;
3021
    int do_flush_tlbs;
3022

    
3023
#if defined (DEBUG_SOFTWARE_TLB)
3024
    if (loglevel != 0) {
3025
        fprintf(logfile, "%s word %d T0 " REGX " T1 " REGX "\n",
3026
                __func__, word, T0, T1);
3027
    }
3028
#endif
3029
    do_flush_tlbs = 0;
3030
    T0 &= 0x3F;
3031
    tlb = &env->tlb[T0].tlbe;
3032
    switch (word) {
3033
    default:
3034
        /* Just here to please gcc */
3035
    case 0:
3036
        EPN = T1 & 0xFFFFFC00;
3037
        if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
3038
            do_flush_tlbs = 1;
3039
        tlb->EPN = EPN;
3040
        size = booke_tlb_to_page_size((T1 >> 4) & 0xF);
3041
        if ((tlb->prot & PAGE_VALID) && tlb->size < size)
3042
            do_flush_tlbs = 1;
3043
        tlb->size = size;
3044
        tlb->attr &= ~0x1;
3045
        tlb->attr |= (T1 >> 8) & 1;
3046
        if (T1 & 0x200) {
3047
            tlb->prot |= PAGE_VALID;
3048
        } else {
3049
            if (tlb->prot & PAGE_VALID) {
3050
                tlb->prot &= ~PAGE_VALID;
3051
                do_flush_tlbs = 1;
3052
            }
3053
        }
3054
        tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
3055
        if (do_flush_tlbs)
3056
            tlb_flush(env, 1);
3057
        break;
3058
    case 1:
3059
        RPN = T1 & 0xFFFFFC0F;
3060
        if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
3061
            tlb_flush(env, 1);
3062
        tlb->RPN = RPN;
3063
        break;
3064
    case 2:
3065
        tlb->attr = (tlb->attr & 0x1) | (T1 & 0x0000FF00);
3066
        tlb->prot = tlb->prot & PAGE_VALID;
3067
        if (T1 & 0x1)
3068
            tlb->prot |= PAGE_READ << 4;
3069
        if (T1 & 0x2)
3070
            tlb->prot |= PAGE_WRITE << 4;
3071
        if (T1 & 0x4)
3072
            tlb->prot |= PAGE_EXEC << 4;
3073
        if (T1 & 0x8)
3074
            tlb->prot |= PAGE_READ;
3075
        if (T1 & 0x10)
3076
            tlb->prot |= PAGE_WRITE;
3077
        if (T1 & 0x20)
3078
            tlb->prot |= PAGE_EXEC;
3079
        break;
3080
    }
3081
}
3082

    
3083
void do_440_tlbre (int word)
3084
{
3085
    ppcemb_tlb_t *tlb;
3086
    int size;
3087

    
3088
    T0 &= 0x3F;
3089
    tlb = &env->tlb[T0].tlbe;
3090
    switch (word) {
3091
    default:
3092
        /* Just here to please gcc */
3093
    case 0:
3094
        T0 = tlb->EPN;
3095
        size = booke_page_size_to_tlb(tlb->size);
3096
        if (size < 0 || size > 0xF)
3097
            size = 1;
3098
        T0 |= size << 4;
3099
        if (tlb->attr & 0x1)
3100
            T0 |= 0x100;
3101
        if (tlb->prot & PAGE_VALID)
3102
            T0 |= 0x200;
3103
        env->spr[SPR_440_MMUCR] &= ~0x000000FF;
3104
        env->spr[SPR_440_MMUCR] |= tlb->PID;
3105
        break;
3106
    case 1:
3107
        T0 = tlb->RPN;
3108
        break;
3109
    case 2:
3110
        T0 = tlb->attr & ~0x1;
3111
        if (tlb->prot & (PAGE_READ << 4))
3112
            T0 |= 0x1;
3113
        if (tlb->prot & (PAGE_WRITE << 4))
3114
            T0 |= 0x2;
3115
        if (tlb->prot & (PAGE_EXEC << 4))
3116
            T0 |= 0x4;
3117
        if (tlb->prot & PAGE_READ)
3118
            T0 |= 0x8;
3119
        if (tlb->prot & PAGE_WRITE)
3120
            T0 |= 0x10;
3121
        if (tlb->prot & PAGE_EXEC)
3122
            T0 |= 0x20;
3123
        break;
3124
    }
3125
}
3126
#endif /* !CONFIG_USER_ONLY */