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

25
#include "helper_regs.h"
26

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

31 32 33
/*****************************************************************************/
/* Exceptions processing helpers */

34
void helper_raise_exception_err (uint32_t exception, uint32_t error_code)
35
{
A
aurel32 已提交
36 37 38 39 40 41
#if 0
    printf("Raise exception %3x code : %d\n", exception, error_code);
#endif
    env->exception_index = exception;
    env->error_code = error_code;
    cpu_loop_exit();
42
}
43

A
aurel32 已提交
44
void helper_raise_exception (uint32_t exception)
45
{
A
aurel32 已提交
46
    helper_raise_exception_err(exception, 0);
47 48
}

49 50
/*****************************************************************************/
/* Registers load and stores */
P
pbrook 已提交
51
target_ulong helper_load_cr (void)
52
{
53 54 55 56 57 58 59 60
    return (env->crf[0] << 28) |
           (env->crf[1] << 24) |
           (env->crf[2] << 20) |
           (env->crf[3] << 16) |
           (env->crf[4] << 12) |
           (env->crf[5] << 8) |
           (env->crf[6] << 4) |
           (env->crf[7] << 0);
61 62
}

63
void helper_store_cr (target_ulong val, uint32_t mask)
64 65 66
{
    int i, sh;

67
    for (i = 0, sh = 7; i < 8; i++, sh--) {
68
        if (mask & (1 << sh))
69
            env->crf[i] = (val >> (sh * 4)) & 0xFUL;
70 71 72
    }
}

A
aurel32 已提交
73 74 75
/*****************************************************************************/
/* SPR accesses */
void helper_load_dump_spr (uint32_t sprn)
76
{
J
j_mayer 已提交
77
    if (loglevel != 0) {
78 79 80 81 82
        fprintf(logfile, "Read SPR %d %03x => " ADDRX "\n",
                sprn, sprn, env->spr[sprn]);
    }
}

A
aurel32 已提交
83
void helper_store_dump_spr (uint32_t sprn)
84
{
J
j_mayer 已提交
85
    if (loglevel != 0) {
A
aurel32 已提交
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
        fprintf(logfile, "Write SPR %d %03x <= " ADDRX "\n",
                sprn, sprn, env->spr[sprn]);
    }
}

target_ulong helper_load_tbl (void)
{
    return cpu_ppc_load_tbl(env);
}

target_ulong helper_load_tbu (void)
{
    return cpu_ppc_load_tbu(env);
}

target_ulong helper_load_atbl (void)
{
    return cpu_ppc_load_atbl(env);
}

target_ulong helper_load_atbu (void)
{
    return cpu_ppc_load_atbu(env);
}

target_ulong helper_load_601_rtcl (void)
{
    return cpu_ppc601_load_rtcl(env);
}

target_ulong helper_load_601_rtcu (void)
{
    return cpu_ppc601_load_rtcu(env);
}

#if !defined(CONFIG_USER_ONLY)
#if defined (TARGET_PPC64)
void helper_store_asr (target_ulong val)
{
    ppc_store_asr(env, val);
}
#endif

void helper_store_sdr1 (target_ulong val)
{
    ppc_store_sdr1(env, val);
}

void helper_store_tbl (target_ulong val)
{
    cpu_ppc_store_tbl(env, val);
}

void helper_store_tbu (target_ulong val)
{
    cpu_ppc_store_tbu(env, val);
}

void helper_store_atbl (target_ulong val)
{
    cpu_ppc_store_atbl(env, val);
}

void helper_store_atbu (target_ulong val)
{
    cpu_ppc_store_atbu(env, val);
}

void helper_store_601_rtcl (target_ulong val)
{
    cpu_ppc601_store_rtcl(env, val);
}

void helper_store_601_rtcu (target_ulong val)
{
    cpu_ppc601_store_rtcu(env, val);
}

target_ulong helper_load_decr (void)
{
    return cpu_ppc_load_decr(env);
}

void helper_store_decr (target_ulong val)
{
    cpu_ppc_store_decr(env, val);
}

void helper_store_hid0_601 (target_ulong val)
{
    target_ulong hid0;

    hid0 = env->spr[SPR_HID0];
    if ((val ^ hid0) & 0x00000008) {
        /* Change current endianness */
        env->hflags &= ~(1 << MSR_LE);
        env->hflags_nmsr &= ~(1 << MSR_LE);
        env->hflags_nmsr |= (1 << MSR_LE) & (((val >> 3) & 1) << MSR_LE);
        env->hflags |= env->hflags_nmsr;
        if (loglevel != 0) {
            fprintf(logfile, "%s: set endianness to %c => " ADDRX "\n",
                    __func__, val & 0x8 ? 'l' : 'b', env->hflags);
        }
189
    }
A
aurel32 已提交
190
    env->spr[SPR_HID0] = (uint32_t)val;
191 192
}

A
aurel32 已提交
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
void helper_store_403_pbr (uint32_t num, target_ulong value)
{
    if (likely(env->pb[num] != value)) {
        env->pb[num] = value;
        /* Should be optimized */
        tlb_flush(env, 1);
    }
}

target_ulong helper_load_40x_pit (void)
{
    return load_40x_pit(env);
}

void helper_store_40x_pit (target_ulong val)
{
    store_40x_pit(env, val);
}

void helper_store_40x_dbcr0 (target_ulong val)
{
    store_40x_dbcr0(env, val);
}

void helper_store_40x_sler (target_ulong val)
{
    store_40x_sler(env, val);
}

void helper_store_booke_tcr (target_ulong val)
{
    store_booke_tcr(env, val);
}

void helper_store_booke_tsr (target_ulong val)
{
    store_booke_tsr(env, val);
}

void helper_store_ibatu (uint32_t nr, target_ulong val)
{
    ppc_store_ibatu(env, nr, val);
}

void helper_store_ibatl (uint32_t nr, target_ulong val)
{
    ppc_store_ibatl(env, nr, val);
}

void helper_store_dbatu (uint32_t nr, target_ulong val)
{
    ppc_store_dbatu(env, nr, val);
}

void helper_store_dbatl (uint32_t nr, target_ulong val)
{
    ppc_store_dbatl(env, nr, val);
}

void helper_store_601_batl (uint32_t nr, target_ulong val)
{
    ppc_store_ibatl_601(env, nr, val);
}

void helper_store_601_batu (uint32_t nr, target_ulong val)
{
    ppc_store_ibatu_601(env, nr, val);
}
#endif

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

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

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

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

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

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

349 350
static void do_dcbz(target_ulong addr, int dcache_line_size)
{
A
aurel32 已提交
351
    addr &= ~(dcache_line_size - 1);
352 353
    int i;
    for (i = 0 ; i < dcache_line_size ; i += 4) {
354
        stl(addr + i , 0);
355
    }
A
aurel32 已提交
356
    if (env->reserve == addr)
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
        env->reserve = (target_ulong)-1ULL;
}

void helper_dcbz(target_ulong addr)
{
    do_dcbz(addr, env->dcache_line_size);
}

void helper_dcbz_970(target_ulong addr)
{
    if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1)
        do_dcbz(addr, 32);
    else
        do_dcbz(addr, env->dcache_line_size);
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

uint32_t helper_float64_to_float32(uint64_t arg)
{
    CPU_FloatU f;
    CPU_DoubleU d;
    d.ll = arg;
    f.f = float64_to_float32(d.d, &env->fp_status);
    return f.l;
}

A
aurel32 已提交
559
static always_inline int isden (float64 d)
560
{
A
aurel32 已提交
561
    CPU_DoubleU u;
562

A
aurel32 已提交
563
    u.d = d;
564

A
aurel32 已提交
565
    return ((u.ll >> 52) & 0x7FF) == 0;
566 567
}

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

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

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

702
static always_inline void float_zero_divide_excp (void)
703 704 705 706 707 708 709 710 711
{
    env->fpscr |= 1 << FPSCR_ZX;
    env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
    /* Update the floating-point exception summary */
    env->fpscr |= 1 << FPSCR_FX;
    if (fpscr_ze != 0) {
        /* Update the floating-point enabled exception summary */
        env->fpscr |= 1 << FPSCR_FEX;
        if (msr_fe0 != 0 || msr_fe1 != 0) {
A
aurel32 已提交
712 713
            helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
                                       POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791
        }
    }
}

static always_inline void float_overflow_excp (void)
{
    env->fpscr |= 1 << FPSCR_OX;
    /* Update the floating-point exception summary */
    env->fpscr |= 1 << FPSCR_FX;
    if (fpscr_oe != 0) {
        /* XXX: should adjust the result */
        /* Update the floating-point enabled exception summary */
        env->fpscr |= 1 << FPSCR_FEX;
        /* We must update the target FPR before raising the exception */
        env->exception_index = POWERPC_EXCP_PROGRAM;
        env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
    } else {
        env->fpscr |= 1 << FPSCR_XX;
        env->fpscr |= 1 << FPSCR_FI;
    }
}

static always_inline void float_underflow_excp (void)
{
    env->fpscr |= 1 << FPSCR_UX;
    /* Update the floating-point exception summary */
    env->fpscr |= 1 << FPSCR_FX;
    if (fpscr_ue != 0) {
        /* XXX: should adjust the result */
        /* Update the floating-point enabled exception summary */
        env->fpscr |= 1 << FPSCR_FEX;
        /* We must update the target FPR before raising the exception */
        env->exception_index = POWERPC_EXCP_PROGRAM;
        env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
    }
}

static always_inline void float_inexact_excp (void)
{
    env->fpscr |= 1 << FPSCR_XX;
    /* Update the floating-point exception summary */
    env->fpscr |= 1 << FPSCR_FX;
    if (fpscr_xe != 0) {
        /* Update the floating-point enabled exception summary */
        env->fpscr |= 1 << FPSCR_FEX;
        /* We must update the target FPR before raising the exception */
        env->exception_index = POWERPC_EXCP_PROGRAM;
        env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
    }
}

static always_inline void fpscr_set_rounding_mode (void)
{
    int rnd_type;

    /* Set rounding mode */
    switch (fpscr_rn) {
    case 0:
        /* Best approximation (round to nearest) */
        rnd_type = float_round_nearest_even;
        break;
    case 1:
        /* Smaller magnitude (round toward zero) */
        rnd_type = float_round_to_zero;
        break;
    case 2:
        /* Round toward +infinite */
        rnd_type = float_round_up;
        break;
    default:
    case 3:
        /* Round toward -infinite */
        rnd_type = float_round_down;
        break;
    }
    set_float_rounding_mode(rnd_type, &env->fp_status);
}

A
aurel32 已提交
792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809
void helper_fpscr_clrbit (uint32_t bit)
{
    int prev;

    prev = (env->fpscr >> bit) & 1;
    env->fpscr &= ~(1 << bit);
    if (prev == 1) {
        switch (bit) {
        case FPSCR_RN1:
        case FPSCR_RN:
            fpscr_set_rounding_mode();
            break;
        default:
            break;
        }
    }
}

A
aurel32 已提交
810
void helper_fpscr_setbit (uint32_t bit)
811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924
{
    int prev;

    prev = (env->fpscr >> bit) & 1;
    env->fpscr |= 1 << bit;
    if (prev == 0) {
        switch (bit) {
        case FPSCR_VX:
            env->fpscr |= 1 << FPSCR_FX;
            if (fpscr_ve)
                goto raise_ve;
        case FPSCR_OX:
            env->fpscr |= 1 << FPSCR_FX;
            if (fpscr_oe)
                goto raise_oe;
            break;
        case FPSCR_UX:
            env->fpscr |= 1 << FPSCR_FX;
            if (fpscr_ue)
                goto raise_ue;
            break;
        case FPSCR_ZX:
            env->fpscr |= 1 << FPSCR_FX;
            if (fpscr_ze)
                goto raise_ze;
            break;
        case FPSCR_XX:
            env->fpscr |= 1 << FPSCR_FX;
            if (fpscr_xe)
                goto raise_xe;
            break;
        case FPSCR_VXSNAN:
        case FPSCR_VXISI:
        case FPSCR_VXIDI:
        case FPSCR_VXZDZ:
        case FPSCR_VXIMZ:
        case FPSCR_VXVC:
        case FPSCR_VXSOFT:
        case FPSCR_VXSQRT:
        case FPSCR_VXCVI:
            env->fpscr |= 1 << FPSCR_VX;
            env->fpscr |= 1 << FPSCR_FX;
            if (fpscr_ve != 0)
                goto raise_ve;
            break;
        case FPSCR_VE:
            if (fpscr_vx != 0) {
            raise_ve:
                env->error_code = POWERPC_EXCP_FP;
                if (fpscr_vxsnan)
                    env->error_code |= POWERPC_EXCP_FP_VXSNAN;
                if (fpscr_vxisi)
                    env->error_code |= POWERPC_EXCP_FP_VXISI;
                if (fpscr_vxidi)
                    env->error_code |= POWERPC_EXCP_FP_VXIDI;
                if (fpscr_vxzdz)
                    env->error_code |= POWERPC_EXCP_FP_VXZDZ;
                if (fpscr_vximz)
                    env->error_code |= POWERPC_EXCP_FP_VXIMZ;
                if (fpscr_vxvc)
                    env->error_code |= POWERPC_EXCP_FP_VXVC;
                if (fpscr_vxsoft)
                    env->error_code |= POWERPC_EXCP_FP_VXSOFT;
                if (fpscr_vxsqrt)
                    env->error_code |= POWERPC_EXCP_FP_VXSQRT;
                if (fpscr_vxcvi)
                    env->error_code |= POWERPC_EXCP_FP_VXCVI;
                goto raise_excp;
            }
            break;
        case FPSCR_OE:
            if (fpscr_ox != 0) {
            raise_oe:
                env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
                goto raise_excp;
            }
            break;
        case FPSCR_UE:
            if (fpscr_ux != 0) {
            raise_ue:
                env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
                goto raise_excp;
            }
            break;
        case FPSCR_ZE:
            if (fpscr_zx != 0) {
            raise_ze:
                env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX;
                goto raise_excp;
            }
            break;
        case FPSCR_XE:
            if (fpscr_xx != 0) {
            raise_xe:
                env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
                goto raise_excp;
            }
            break;
        case FPSCR_RN1:
        case FPSCR_RN:
            fpscr_set_rounding_mode();
            break;
        default:
            break;
        raise_excp:
            /* Update the floating-point enabled exception summary */
            env->fpscr |= 1 << FPSCR_FEX;
                /* We have to update Rc1 before raising the exception */
            env->exception_index = POWERPC_EXCP_PROGRAM;
            break;
        }
    }
}

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

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

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

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

A
aurel32 已提交
996 997
/* fadd - fadd. */
uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
998
{
A
aurel32 已提交
999 1000 1001 1002 1003 1004 1005
    CPU_DoubleU farg1, farg2;

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

A
aurel32 已提交
1021 1022 1023 1024 1025 1026 1027 1028
/* fsub - fsub. */
uint64_t helper_fsub (uint64_t arg1, uint64_t arg2)
{
    CPU_DoubleU farg1, farg2;

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

A
aurel32 已提交
1048 1049
/* fmul - fmul. */
uint64_t helper_fmul (uint64_t arg1, uint64_t arg2)
1050
{
A
aurel32 已提交
1051 1052 1053 1054 1055 1056 1057
    CPU_DoubleU farg1, farg2;

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

A
aurel32 已提交
1073 1074
/* fdiv - fdiv. */
uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2)
1075
{
A
aurel32 已提交
1076 1077 1078 1079 1080 1081 1082
    CPU_DoubleU farg1, farg2;

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

A
aurel32 已提交
1100 1101
/* fabs */
uint64_t helper_fabs (uint64_t arg)
1102
{
A
aurel32 已提交
1103
    CPU_DoubleU farg;
1104

A
aurel32 已提交
1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137
    farg.ll = arg;
    farg.d = float64_abs(farg.d);
    return farg.ll;
}

/* fnabs */
uint64_t helper_fnabs (uint64_t arg)
{
    CPU_DoubleU farg;

    farg.ll = arg;
    farg.d = float64_abs(farg.d);
    farg.d = float64_chs(farg.d);
    return farg.ll;
}

/* fneg */
uint64_t helper_fneg (uint64_t arg)
{
    CPU_DoubleU farg;

    farg.ll = arg;
    farg.d = float64_chs(farg.d);
    return farg.ll;
}

/* fctiw - fctiw. */
uint64_t helper_fctiw (uint64_t arg)
{
    CPU_DoubleU farg;
    farg.ll = arg;

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

A
aurel32 已提交
1155 1156
/* fctiwz - fctiwz. */
uint64_t helper_fctiwz (uint64_t arg)
1157
{
A
aurel32 已提交
1158 1159
    CPU_DoubleU farg;
    farg.ll = arg;
1160

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

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

A
aurel32 已提交
1188 1189
/* fctid - fctid. */
uint64_t helper_fctid (uint64_t arg)
J
j_mayer 已提交
1190
{
A
aurel32 已提交
1191 1192
    CPU_DoubleU farg;
    farg.ll = arg;
J
j_mayer 已提交
1193

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

A
aurel32 已提交
1206 1207
/* fctidz - fctidz. */
uint64_t helper_fctidz (uint64_t arg)
J
j_mayer 已提交
1208
{
A
aurel32 已提交
1209 1210
    CPU_DoubleU farg;
    farg.ll = arg;
J
j_mayer 已提交
1211

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

#endif

A
aurel32 已提交
1226
static always_inline uint64_t do_fri (uint64_t arg, int rounding_mode)
1227
{
A
aurel32 已提交
1228 1229 1230 1231
    CPU_DoubleU farg;
    farg.ll = arg;

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

A
aurel32 已提交
1246
uint64_t helper_frin (uint64_t arg)
1247
{
A
aurel32 已提交
1248
    return do_fri(arg, float_round_nearest_even);
1249 1250
}

A
aurel32 已提交
1251
uint64_t helper_friz (uint64_t arg)
1252
{
A
aurel32 已提交
1253
    return do_fri(arg, float_round_to_zero);
1254 1255
}

A
aurel32 已提交
1256
uint64_t helper_frip (uint64_t arg)
1257
{
A
aurel32 已提交
1258
    return do_fri(arg, float_round_up);
1259 1260
}

A
aurel32 已提交
1261
uint64_t helper_frim (uint64_t arg)
1262
{
A
aurel32 已提交
1263
    return do_fri(arg, float_round_down);
1264 1265
}

A
aurel32 已提交
1266 1267
/* fmadd - fmadd. */
uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
J
j_mayer 已提交
1268
{
A
aurel32 已提交
1269 1270 1271 1272 1273 1274 1275 1276 1277
    CPU_DoubleU farg1, farg2, farg3;

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

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

A
aurel32 已提交
1313 1314
/* fmsub - fmsub. */
uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
J
j_mayer 已提交
1315
{
A
aurel32 已提交
1316 1317 1318 1319 1320 1321 1322 1323 1324
    CPU_DoubleU farg1, farg2, farg3;

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

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

A
aurel32 已提交
1360 1361
/* fnmadd - fnmadd. */
uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
B
bellard 已提交
1362
{
A
aurel32 已提交
1363 1364 1365 1366 1367 1368 1369 1370 1371
    CPU_DoubleU farg1, farg2, farg3;

    farg1.ll = arg1;
    farg2.ll = arg2;
    farg3.ll = arg3;

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

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

A
aurel32 已提交
1410 1411
/* fnmsub - fnmsub. */
uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
B
bellard 已提交
1412
{
A
aurel32 已提交
1413 1414 1415 1416 1417 1418 1419 1420 1421
    CPU_DoubleU farg1, farg2, farg3;

    farg1.ll = arg1;
    farg2.ll = arg2;
    farg3.ll = arg3;

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

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

A
aurel32 已提交
1460 1461
/* frsp - frsp. */
uint64_t helper_frsp (uint64_t arg)
1462
{
A
aurel32 已提交
1463
    CPU_DoubleU farg;
A
aurel32 已提交
1464
    float32 f32;
A
aurel32 已提交
1465 1466 1467 1468
    farg.ll = arg;

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

A
aurel32 已提交
1482 1483
/* fsqrt - fsqrt. */
uint64_t helper_fsqrt (uint64_t arg)
1484
{
A
aurel32 已提交
1485 1486 1487 1488
    CPU_DoubleU farg;
    farg.ll = arg;

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

A
aurel32 已提交
1500 1501
/* fre - fre. */
uint64_t helper_fre (uint64_t arg)
1502
{
1503
    CPU_DoubleU fone, farg;
1504
    fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
A
aurel32 已提交
1505
    farg.ll = arg;
1506

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

A
aurel32 已提交
1516 1517
/* fres - fres. */
uint64_t helper_fres (uint64_t arg)
1518
{
1519
    CPU_DoubleU fone, farg;
1520
    float32 f32;
1521
    fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
A
aurel32 已提交
1522
    farg.ll = arg;
1523

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

A
aurel32 已提交
1535 1536
/* frsqrte  - frsqrte. */
uint64_t helper_frsqrte (uint64_t arg)
1537
{
1538
    CPU_DoubleU fone, farg;
1539
    float32 f32;
1540
    fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
A
aurel32 已提交
1541
    farg.ll = arg;
1542

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

A
aurel32 已提交
1558 1559
/* fsel - fsel. */
uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1560
{
A
aurel32 已提交
1561
    CPU_DoubleU farg1;
A
aurel32 已提交
1562 1563 1564

    farg1.ll = arg1;

1565
    if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_nan(farg1.d))
A
aurel32 已提交
1566
        return arg2;
1567
    else
A
aurel32 已提交
1568
        return arg3;
1569 1570
}

A
aurel32 已提交
1571
void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD)
1572
{
A
aurel32 已提交
1573
    CPU_DoubleU farg1, farg2;
1574
    uint32_t ret = 0;
A
aurel32 已提交
1575 1576
    farg1.ll = arg1;
    farg2.ll = arg2;
1577

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

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

A
aurel32 已提交
1600
void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD)
1601
{
A
aurel32 已提交
1602
    CPU_DoubleU farg1, farg2;
1603
    uint32_t ret = 0;
A
aurel32 已提交
1604 1605
    farg1.ll = arg1;
    farg2.ll = arg2;
1606

A
aurel32 已提交
1607 1608
    if (unlikely(float64_is_nan(farg1.d) ||
                 float64_is_nan(farg2.d))) {
A
aurel32 已提交
1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621
        ret = 0x01UL;
    } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
        ret = 0x08UL;
    } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
        ret = 0x04UL;
    } else {
        ret = 0x02UL;
    }

    env->fpscr &= ~(0x0F << FPSCR_FPRF);
    env->fpscr |= ret << FPSCR_FPRF;
    env->crf[crfD] = ret;
    if (unlikely (ret == 0x01UL)) {
A
aurel32 已提交
1622 1623
        if (float64_is_signaling_nan(farg1.d) ||
            float64_is_signaling_nan(farg2.d)) {
1624 1625 1626 1627 1628 1629 1630
            /* sNaN comparison */
            fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
                                  POWERPC_EXCP_FP_VXVC);
        } else {
            /* qNaN comparison */
            fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
        }
1631 1632 1633
    }
}

1634
#if !defined (CONFIG_USER_ONLY)
1635
void helper_store_msr (target_ulong val)
1636
{
1637 1638
    val = hreg_store_msr(env, val, 0);
    if (val != 0) {
1639
        env->interrupt_request |= CPU_INTERRUPT_EXITTB;
A
aurel32 已提交
1640
        helper_raise_exception(val);
1641 1642 1643
    }
}

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

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

1679
#if defined(TARGET_PPC64)
1680
void helper_rfid (void)
J
j_mayer 已提交
1681
{
1682 1683
    do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
           ~((target_ulong)0xFFFF0000), 0);
1684
}
1685

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

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

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

1717
/*****************************************************************************/
1718
/* PowerPC 601 specific instructions (POWER bridge) */
1719

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

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

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

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

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

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

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

#if !defined (CONFIG_USER_ONLY)
1810
target_ulong helper_rac (target_ulong addr)
1811 1812
{
    mmu_ctx_t ctx;
J
j_mayer 已提交
1813
    int nb_BATs;
1814
    target_ulong ret = 0;
1815 1816 1817 1818

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

1828
void helper_rfsvc (void)
1829
{
1830
    do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
1831 1832 1833 1834 1835 1836 1837
}
#endif

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

/*****************************************************************************/
/* Embedded PowerPC specific helpers */

1857
/* XXX: to be improved to check access rights when in user-mode */
1858
target_ulong helper_load_dcr (target_ulong dcrn)
1859
{
1860
    target_ulong val = 0;
1861 1862 1863 1864 1865

    if (unlikely(env->dcr_env == NULL)) {
        if (loglevel != 0) {
            fprintf(logfile, "No DCR environment\n");
        }
A
aurel32 已提交
1866 1867
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
1868
    } else if (unlikely(ppc_dcr_read(env->dcr_env, dcrn, &val) != 0)) {
1869
        if (loglevel != 0) {
A
aurel32 已提交
1870
            fprintf(logfile, "DCR read error %d %03x\n", (int)dcrn, (int)dcrn);
1871
        }
A
aurel32 已提交
1872 1873
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1874
    }
1875
    return val;
1876 1877
}

1878
void helper_store_dcr (target_ulong dcrn, target_ulong val)
1879 1880 1881 1882 1883
{
    if (unlikely(env->dcr_env == NULL)) {
        if (loglevel != 0) {
            fprintf(logfile, "No DCR environment\n");
        }
A
aurel32 已提交
1884 1885
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
1886
    } else if (unlikely(ppc_dcr_write(env->dcr_env, dcrn, val) != 0)) {
1887
        if (loglevel != 0) {
A
aurel32 已提交
1888
            fprintf(logfile, "DCR write error %d %03x\n", (int)dcrn, (int)dcrn);
1889
        }
A
aurel32 已提交
1890 1891
        helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1892 1893 1894
    }
}

1895
#if !defined(CONFIG_USER_ONLY)
1896
void helper_40x_rfci (void)
1897
{
1898 1899
    do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
           ~((target_ulong)0xFFFF0000), 0);
1900 1901
}

1902
void helper_rfci (void)
1903
{
1904 1905
    do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
           ~((target_ulong)0x3FFF0000), 0);
1906 1907
}

1908
void helper_rfdi (void)
1909
{
1910 1911
    do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
           ~((target_ulong)0x3FFF0000), 0);
1912 1913
}

1914
void helper_rfmci (void)
1915
{
1916 1917
    do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
           ~((target_ulong)0x3FFF0000), 0);
1918 1919 1920 1921
}
#endif

/* 440 specific */
1922
target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_Rc)
1923 1924 1925 1926 1927 1928
{
    target_ulong mask;
    int i;

    i = 1;
    for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1929 1930 1931 1932
        if ((high & mask) == 0) {
            if (update_Rc) {
                env->crf[0] = 0x4;
            }
1933
            goto done;
1934
        }
1935 1936 1937
        i++;
    }
    for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1938 1939 1940 1941 1942 1943
        if ((low & mask) == 0) {
            if (update_Rc) {
                env->crf[0] = 0x8;
            }
            goto done;
        }
1944 1945
        i++;
    }
1946 1947 1948
    if (update_Rc) {
        env->crf[0] = 0x2;
    }
1949
 done:
1950 1951 1952 1953 1954
    env->xer = (env->xer & ~0x7F) | i;
    if (update_Rc) {
        env->crf[0] |= xer_so;
    }
    return i;
1955 1956
}

A
aurel32 已提交
1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974
/*****************************************************************************/
/* Altivec extension helpers */
#if defined(WORDS_BIGENDIAN)
#define HI_IDX 0
#define LO_IDX 1
#else
#define HI_IDX 1
#define LO_IDX 0
#endif

#if defined(WORDS_BIGENDIAN)
#define VECTOR_FOR_INORDER_I(index, element)            \
    for (index = 0; index < ARRAY_SIZE(r->element); index++)
#else
#define VECTOR_FOR_INORDER_I(index, element)            \
  for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
#endif

A
aurel32 已提交
1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991
#define VARITH_DO(name, op, element)        \
void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)          \
{                                                                       \
    int i;                                                              \
    for (i = 0; i < ARRAY_SIZE(r->element); i++) {                      \
        r->element[i] = a->element[i] op b->element[i];                 \
    }                                                                   \
}
#define VARITH(suffix, element)                  \
  VARITH_DO(add##suffix, +, element)             \
  VARITH_DO(sub##suffix, -, element)
VARITH(ubm, u8)
VARITH(uhm, u16)
VARITH(uwm, u32)
#undef VARITH_DO
#undef VARITH

A
aurel32 已提交
1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010
#define VAVG_DO(name, element, etype)                                   \
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
    {                                                                   \
        int i;                                                          \
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
            etype x = (etype)a->element[i] + (etype)b->element[i] + 1;  \
            r->element[i] = x >> 1;                                     \
        }                                                               \
    }

#define VAVG(type, signed_element, signed_type, unsigned_element, unsigned_type) \
    VAVG_DO(avgs##type, signed_element, signed_type)                    \
    VAVG_DO(avgu##type, unsigned_element, unsigned_type)
VAVG(b, s8, int16_t, u8, uint16_t)
VAVG(h, s16, int32_t, u16, uint32_t)
VAVG(w, s32, int64_t, u32, uint64_t)
#undef VAVG_DO
#undef VAVG

2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034
#define VMINMAX_DO(name, compare, element)                              \
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
    {                                                                   \
        int i;                                                          \
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
            if (a->element[i] compare b->element[i]) {                  \
                r->element[i] = b->element[i];                          \
            } else {                                                    \
                r->element[i] = a->element[i];                          \
            }                                                           \
        }                                                               \
    }
#define VMINMAX(suffix, element)                \
  VMINMAX_DO(min##suffix, >, element)           \
  VMINMAX_DO(max##suffix, <, element)
VMINMAX(sb, s8)
VMINMAX(sh, s16)
VMINMAX(sw, s32)
VMINMAX(ub, u8)
VMINMAX(uh, u16)
VMINMAX(uw, u32)
#undef VMINMAX_DO
#undef VMINMAX

A
aurel32 已提交
2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069
#define VMRG_DO(name, element, highp)                                   \
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
    {                                                                   \
        ppc_avr_t result;                                               \
        int i;                                                          \
        size_t n_elems = ARRAY_SIZE(r->element);                        \
        for (i = 0; i < n_elems/2; i++) {                               \
            if (highp) {                                                \
                result.element[i*2+HI_IDX] = a->element[i];             \
                result.element[i*2+LO_IDX] = b->element[i];             \
            } else {                                                    \
                result.element[n_elems - i*2 - (1+HI_IDX)] = b->element[n_elems - i - 1]; \
                result.element[n_elems - i*2 - (1+LO_IDX)] = a->element[n_elems - i - 1]; \
            }                                                           \
        }                                                               \
        *r = result;                                                    \
    }
#if defined(WORDS_BIGENDIAN)
#define MRGHI 0
#define MRGL0 1
#else
#define MRGHI 1
#define MRGLO 0
#endif
#define VMRG(suffix, element)                   \
  VMRG_DO(mrgl##suffix, element, MRGHI)         \
  VMRG_DO(mrgh##suffix, element, MRGLO)
VMRG(b, u8)
VMRG(h, u16)
VMRG(w, u32)
#undef VMRG_DO
#undef VMRG
#undef MRGHI
#undef MRGLO

A
aurel32 已提交
2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091
#define VMUL_DO(name, mul_element, prod_element, evenp)                 \
    void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)      \
    {                                                                   \
        int i;                                                          \
        VECTOR_FOR_INORDER_I(i, prod_element) {                         \
            if (evenp) {                                                \
                r->prod_element[i] = a->mul_element[i*2+HI_IDX] * b->mul_element[i*2+HI_IDX]; \
            } else {                                                    \
                r->prod_element[i] = a->mul_element[i*2+LO_IDX] * b->mul_element[i*2+LO_IDX]; \
            }                                                           \
        }                                                               \
    }
#define VMUL(suffix, mul_element, prod_element) \
  VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
  VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
VMUL(sb, s8, s16)
VMUL(sh, s16, s32)
VMUL(ub, u8, u16)
VMUL(uh, u16, u32)
#undef VMUL_DO
#undef VMUL

A
aurel32 已提交
2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106
#define VSL(suffix, element)                                            \
    void helper_vsl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
    {                                                                   \
        int i;                                                          \
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
            unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
            unsigned int shift = b->element[i] & mask;                  \
            r->element[i] = a->element[i] << shift;                     \
        }                                                               \
    }
VSL(b, u8)
VSL(h, u16)
VSL(w, u32)
#undef VSL

A
aurel32 已提交
2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119
void helper_vslo (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
  int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;

#if defined (WORDS_BIGENDIAN)
  memmove (&r->u8[0], &a->u8[sh], 16-sh);
  memset (&r->u8[16-sh], 0, sh);
#else
  memmove (&r->u8[sh], &a->u8[0], 16-sh);
  memset (&r->u8[0], 0, sh);
#endif
}

A
aurel32 已提交
2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137
#define VSR(suffix, element)                                            \
    void helper_vsr##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)  \
    {                                                                   \
        int i;                                                          \
        for (i = 0; i < ARRAY_SIZE(r->element); i++) {                  \
            unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
            unsigned int shift = b->element[i] & mask;                  \
            r->element[i] = a->element[i] >> shift;                     \
        }                                                               \
    }
VSR(ab, s8)
VSR(ah, s16)
VSR(aw, s32)
VSR(b, u8)
VSR(h, u16)
VSR(w, u32)
#undef VSR

A
aurel32 已提交
2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150
void helper_vsro (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
  int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;

#if defined (WORDS_BIGENDIAN)
  memmove (&r->u8[sh], &a->u8[0], 16-sh);
  memset (&r->u8[0], 0, sh);
#else
  memmove (&r->u8[0], &a->u8[sh], 16-sh);
  memset (&r->u8[16-sh], 0, sh);
#endif
}

A
aurel32 已提交
2151 2152 2153 2154
#undef VECTOR_FOR_INORDER_I
#undef HI_IDX
#undef LO_IDX

A
aurel32 已提交
2155
/*****************************************************************************/
2156 2157 2158 2159 2160 2161 2162
/* SPE extension helpers */
/* Use a table to make this quicker */
static uint8_t hbrev[16] = {
    0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
    0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
};

2163
static always_inline uint8_t byte_reverse (uint8_t val)
2164 2165 2166 2167
{
    return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
}

2168
static always_inline uint32_t word_reverse (uint32_t val)
2169 2170 2171 2172 2173
{
    return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
        (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
}

2174
#define MASKBITS 16 // Random value - to be fixed (implementation dependant)
2175
target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
2176 2177 2178
{
    uint32_t a, b, d, mask;

2179
    mask = UINT32_MAX >> (32 - MASKBITS);
2180 2181
    a = arg1 & mask;
    b = arg2 & mask;
2182
    d = word_reverse(1 + word_reverse(a | ~b));
2183
    return (arg1 & ~mask) | (d & b);
2184 2185
}

2186
uint32_t helper_cntlsw32 (uint32_t val)
2187 2188
{
    if (val & 0x80000000)
2189
        return clz32(~val);
2190
    else
2191
        return clz32(val);
2192 2193
}

2194
uint32_t helper_cntlzw32 (uint32_t val)
2195
{
2196
    return clz32(val);
2197 2198
}

A
aurel32 已提交
2199 2200
/* Single-precision floating-point conversions */
static always_inline uint32_t efscfsi (uint32_t val)
2201
{
A
aurel32 已提交
2202
    CPU_FloatU u;
2203 2204 2205

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

A
aurel32 已提交
2206
    return u.l;
2207 2208
}

A
aurel32 已提交
2209
static always_inline uint32_t efscfui (uint32_t val)
2210
{
A
aurel32 已提交
2211
    CPU_FloatU u;
2212 2213 2214

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

A
aurel32 已提交
2215
    return u.l;
2216 2217
}

A
aurel32 已提交
2218
static always_inline int32_t efsctsi (uint32_t val)
2219
{
A
aurel32 已提交
2220
    CPU_FloatU u;
2221

A
aurel32 已提交
2222
    u.l = val;
2223
    /* NaN are not treated the same way IEEE 754 does */
2224
    if (unlikely(float32_is_nan(u.f)))
2225 2226 2227 2228 2229
        return 0;

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

A
aurel32 已提交
2230
static always_inline uint32_t efsctui (uint32_t val)
2231
{
A
aurel32 已提交
2232
    CPU_FloatU u;
2233

A
aurel32 已提交
2234
    u.l = val;
2235
    /* NaN are not treated the same way IEEE 754 does */
2236
    if (unlikely(float32_is_nan(u.f)))
2237 2238 2239 2240 2241
        return 0;

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

A
aurel32 已提交
2242
static always_inline uint32_t efsctsiz (uint32_t val)
2243
{
A
aurel32 已提交
2244
    CPU_FloatU u;
2245

A
aurel32 已提交
2246
    u.l = val;
2247
    /* NaN are not treated the same way IEEE 754 does */
2248
    if (unlikely(float32_is_nan(u.f)))
2249 2250 2251 2252 2253
        return 0;

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

A
aurel32 已提交
2254
static always_inline uint32_t efsctuiz (uint32_t val)
2255
{
A
aurel32 已提交
2256
    CPU_FloatU u;
2257

A
aurel32 已提交
2258
    u.l = val;
2259
    /* NaN are not treated the same way IEEE 754 does */
2260
    if (unlikely(float32_is_nan(u.f)))
2261 2262 2263 2264 2265
        return 0;

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

A
aurel32 已提交
2266
static always_inline uint32_t efscfsf (uint32_t val)
2267
{
A
aurel32 已提交
2268
    CPU_FloatU u;
2269 2270 2271 2272 2273 2274
    float32 tmp;

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

A
aurel32 已提交
2275
    return u.l;
2276 2277
}

A
aurel32 已提交
2278
static always_inline uint32_t efscfuf (uint32_t val)
2279
{
A
aurel32 已提交
2280
    CPU_FloatU u;
2281 2282 2283 2284 2285 2286
    float32 tmp;

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

A
aurel32 已提交
2287
    return u.l;
2288 2289
}

A
aurel32 已提交
2290
static always_inline uint32_t efsctsf (uint32_t val)
2291
{
A
aurel32 已提交
2292
    CPU_FloatU u;
2293 2294
    float32 tmp;

A
aurel32 已提交
2295
    u.l = val;
2296
    /* NaN are not treated the same way IEEE 754 does */
2297
    if (unlikely(float32_is_nan(u.f)))
2298 2299 2300 2301 2302 2303 2304
        return 0;
    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
    u.f = float32_mul(u.f, tmp, &env->spe_status);

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

A
aurel32 已提交
2305
static always_inline uint32_t efsctuf (uint32_t val)
2306
{
A
aurel32 已提交
2307
    CPU_FloatU u;
2308 2309
    float32 tmp;

A
aurel32 已提交
2310
    u.l = val;
2311
    /* NaN are not treated the same way IEEE 754 does */
2312
    if (unlikely(float32_is_nan(u.f)))
2313 2314 2315 2316 2317 2318 2319
        return 0;
    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
    u.f = float32_mul(u.f, tmp, &env->spe_status);

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

A
aurel32 已提交
2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350
#define HELPER_SPE_SINGLE_CONV(name)                                          \
uint32_t helper_e##name (uint32_t val)                                        \
{                                                                             \
    return e##name(val);                                                      \
}
/* efscfsi */
HELPER_SPE_SINGLE_CONV(fscfsi);
/* efscfui */
HELPER_SPE_SINGLE_CONV(fscfui);
/* efscfuf */
HELPER_SPE_SINGLE_CONV(fscfuf);
/* efscfsf */
HELPER_SPE_SINGLE_CONV(fscfsf);
/* efsctsi */
HELPER_SPE_SINGLE_CONV(fsctsi);
/* efsctui */
HELPER_SPE_SINGLE_CONV(fsctui);
/* efsctsiz */
HELPER_SPE_SINGLE_CONV(fsctsiz);
/* efsctuiz */
HELPER_SPE_SINGLE_CONV(fsctuiz);
/* efsctsf */
HELPER_SPE_SINGLE_CONV(fsctsf);
/* efsctuf */
HELPER_SPE_SINGLE_CONV(fsctuf);

#define HELPER_SPE_VECTOR_CONV(name)                                          \
uint64_t helper_ev##name (uint64_t val)                                       \
{                                                                             \
    return ((uint64_t)e##name(val >> 32) << 32) |                             \
            (uint64_t)e##name(val);                                           \
2351
}
A
aurel32 已提交
2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371
/* evfscfsi */
HELPER_SPE_VECTOR_CONV(fscfsi);
/* evfscfui */
HELPER_SPE_VECTOR_CONV(fscfui);
/* evfscfuf */
HELPER_SPE_VECTOR_CONV(fscfuf);
/* evfscfsf */
HELPER_SPE_VECTOR_CONV(fscfsf);
/* evfsctsi */
HELPER_SPE_VECTOR_CONV(fsctsi);
/* evfsctui */
HELPER_SPE_VECTOR_CONV(fsctui);
/* evfsctsiz */
HELPER_SPE_VECTOR_CONV(fsctsiz);
/* evfsctuiz */
HELPER_SPE_VECTOR_CONV(fsctuiz);
/* evfsctsf */
HELPER_SPE_VECTOR_CONV(fsctsf);
/* evfsctuf */
HELPER_SPE_VECTOR_CONV(fsctuf);
2372

A
aurel32 已提交
2373 2374
/* Single-precision floating-point arithmetic */
static always_inline uint32_t efsadd (uint32_t op1, uint32_t op2)
2375
{
A
aurel32 已提交
2376 2377 2378 2379 2380
    CPU_FloatU u1, u2;
    u1.l = op1;
    u2.l = op2;
    u1.f = float32_add(u1.f, u2.f, &env->spe_status);
    return u1.l;
2381 2382
}

A
aurel32 已提交
2383
static always_inline uint32_t efssub (uint32_t op1, uint32_t op2)
2384
{
A
aurel32 已提交
2385 2386 2387 2388 2389
    CPU_FloatU u1, u2;
    u1.l = op1;
    u2.l = op2;
    u1.f = float32_sub(u1.f, u2.f, &env->spe_status);
    return u1.l;
2390 2391
}

A
aurel32 已提交
2392
static always_inline uint32_t efsmul (uint32_t op1, uint32_t op2)
2393
{
A
aurel32 已提交
2394 2395 2396 2397 2398
    CPU_FloatU u1, u2;
    u1.l = op1;
    u2.l = op2;
    u1.f = float32_mul(u1.f, u2.f, &env->spe_status);
    return u1.l;
2399 2400
}

A
aurel32 已提交
2401
static always_inline uint32_t efsdiv (uint32_t op1, uint32_t op2)
2402
{
A
aurel32 已提交
2403 2404 2405 2406 2407
    CPU_FloatU u1, u2;
    u1.l = op1;
    u2.l = op2;
    u1.f = float32_div(u1.f, u2.f, &env->spe_status);
    return u1.l;
2408 2409
}

A
aurel32 已提交
2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440
#define HELPER_SPE_SINGLE_ARITH(name)                                         \
uint32_t helper_e##name (uint32_t op1, uint32_t op2)                          \
{                                                                             \
    return e##name(op1, op2);                                                 \
}
/* efsadd */
HELPER_SPE_SINGLE_ARITH(fsadd);
/* efssub */
HELPER_SPE_SINGLE_ARITH(fssub);
/* efsmul */
HELPER_SPE_SINGLE_ARITH(fsmul);
/* efsdiv */
HELPER_SPE_SINGLE_ARITH(fsdiv);

#define HELPER_SPE_VECTOR_ARITH(name)                                         \
uint64_t helper_ev##name (uint64_t op1, uint64_t op2)                         \
{                                                                             \
    return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) |                  \
            (uint64_t)e##name(op1, op2);                                      \
}
/* evfsadd */
HELPER_SPE_VECTOR_ARITH(fsadd);
/* evfssub */
HELPER_SPE_VECTOR_ARITH(fssub);
/* evfsmul */
HELPER_SPE_VECTOR_ARITH(fsmul);
/* evfsdiv */
HELPER_SPE_VECTOR_ARITH(fsdiv);

/* Single-precision floating-point comparisons */
static always_inline uint32_t efststlt (uint32_t op1, uint32_t op2)
2441
{
A
aurel32 已提交
2442 2443 2444 2445
    CPU_FloatU u1, u2;
    u1.l = op1;
    u2.l = op2;
    return float32_lt(u1.f, u2.f, &env->spe_status) ? 4 : 0;
2446 2447
}

A
aurel32 已提交
2448
static always_inline uint32_t efststgt (uint32_t op1, uint32_t op2)
2449
{
A
aurel32 已提交
2450 2451 2452 2453
    CPU_FloatU u1, u2;
    u1.l = op1;
    u2.l = op2;
    return float32_le(u1.f, u2.f, &env->spe_status) ? 0 : 4;
2454 2455
}

A
aurel32 已提交
2456
static always_inline uint32_t efststeq (uint32_t op1, uint32_t op2)
2457
{
A
aurel32 已提交
2458 2459 2460 2461
    CPU_FloatU u1, u2;
    u1.l = op1;
    u2.l = op2;
    return float32_eq(u1.f, u2.f, &env->spe_status) ? 4 : 0;
2462 2463
}

A
aurel32 已提交
2464
static always_inline uint32_t efscmplt (uint32_t op1, uint32_t op2)
2465 2466
{
    /* XXX: TODO: test special values (NaN, infinites, ...) */
A
aurel32 已提交
2467
    return efststlt(op1, op2);
2468 2469
}

A
aurel32 已提交
2470
static always_inline uint32_t efscmpgt (uint32_t op1, uint32_t op2)
2471 2472
{
    /* XXX: TODO: test special values (NaN, infinites, ...) */
A
aurel32 已提交
2473
    return efststgt(op1, op2);
2474 2475
}

A
aurel32 已提交
2476
static always_inline uint32_t efscmpeq (uint32_t op1, uint32_t op2)
2477 2478
{
    /* XXX: TODO: test special values (NaN, infinites, ...) */
A
aurel32 已提交
2479
    return efststeq(op1, op2);
2480 2481
}

A
aurel32 已提交
2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500
#define HELPER_SINGLE_SPE_CMP(name)                                           \
uint32_t helper_e##name (uint32_t op1, uint32_t op2)                          \
{                                                                             \
    return e##name(op1, op2) << 2;                                            \
}
/* efststlt */
HELPER_SINGLE_SPE_CMP(fststlt);
/* efststgt */
HELPER_SINGLE_SPE_CMP(fststgt);
/* efststeq */
HELPER_SINGLE_SPE_CMP(fststeq);
/* efscmplt */
HELPER_SINGLE_SPE_CMP(fscmplt);
/* efscmpgt */
HELPER_SINGLE_SPE_CMP(fscmpgt);
/* efscmpeq */
HELPER_SINGLE_SPE_CMP(fscmpeq);

static always_inline uint32_t evcmp_merge (int t0, int t1)
2501
{
A
aurel32 已提交
2502
    return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
2503 2504
}

A
aurel32 已提交
2505 2506 2507 2508
#define HELPER_VECTOR_SPE_CMP(name)                                           \
uint32_t helper_ev##name (uint64_t op1, uint64_t op2)                         \
{                                                                             \
    return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2));     \
2509
}
A
aurel32 已提交
2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521
/* evfststlt */
HELPER_VECTOR_SPE_CMP(fststlt);
/* evfststgt */
HELPER_VECTOR_SPE_CMP(fststgt);
/* evfststeq */
HELPER_VECTOR_SPE_CMP(fststeq);
/* evfscmplt */
HELPER_VECTOR_SPE_CMP(fscmplt);
/* evfscmpgt */
HELPER_VECTOR_SPE_CMP(fscmpgt);
/* evfscmpeq */
HELPER_VECTOR_SPE_CMP(fscmpeq);
2522

A
aurel32 已提交
2523 2524
/* Double-precision floating-point conversion */
uint64_t helper_efdcfsi (uint32_t val)
2525
{
A
aurel32 已提交
2526 2527 2528 2529 2530
    CPU_DoubleU u;

    u.d = int32_to_float64(val, &env->spe_status);

    return u.ll;
2531 2532
}

A
aurel32 已提交
2533
uint64_t helper_efdcfsid (uint64_t val)
2534
{
A
aurel32 已提交
2535
    CPU_DoubleU u;
2536

A
aurel32 已提交
2537
    u.d = int64_to_float64(val, &env->spe_status);
2538

A
aurel32 已提交
2539
    return u.ll;
2540 2541
}

A
aurel32 已提交
2542 2543 2544 2545 2546 2547 2548 2549 2550 2551
uint64_t helper_efdcfui (uint32_t val)
{
    CPU_DoubleU u;

    u.d = uint32_to_float64(val, &env->spe_status);

    return u.ll;
}

uint64_t helper_efdcfuid (uint64_t val)
2552
{
A
aurel32 已提交
2553
    CPU_DoubleU u;
2554

A
aurel32 已提交
2555
    u.d = uint64_to_float64(val, &env->spe_status);
2556

A
aurel32 已提交
2557
    return u.ll;
2558 2559
}

A
aurel32 已提交
2560
uint32_t helper_efdctsi (uint64_t val)
2561
{
A
aurel32 已提交
2562
    CPU_DoubleU u;
2563

A
aurel32 已提交
2564
    u.ll = val;
2565
    /* NaN are not treated the same way IEEE 754 does */
2566
    if (unlikely(float64_is_nan(u.d)))
2567 2568
        return 0;

A
aurel32 已提交
2569
    return float64_to_int32(u.d, &env->spe_status);
2570 2571
}

A
aurel32 已提交
2572
uint32_t helper_efdctui (uint64_t val)
2573
{
A
aurel32 已提交
2574
    CPU_DoubleU u;
2575

A
aurel32 已提交
2576
    u.ll = val;
2577
    /* NaN are not treated the same way IEEE 754 does */
2578
    if (unlikely(float64_is_nan(u.d)))
2579 2580
        return 0;

A
aurel32 已提交
2581
    return float64_to_uint32(u.d, &env->spe_status);
2582 2583
}

A
aurel32 已提交
2584
uint32_t helper_efdctsiz (uint64_t val)
2585
{
A
aurel32 已提交
2586
    CPU_DoubleU u;
2587

A
aurel32 已提交
2588
    u.ll = val;
2589
    /* NaN are not treated the same way IEEE 754 does */
2590
    if (unlikely(float64_is_nan(u.d)))
2591 2592
        return 0;

A
aurel32 已提交
2593
    return float64_to_int32_round_to_zero(u.d, &env->spe_status);
2594 2595
}

A
aurel32 已提交
2596
uint64_t helper_efdctsidz (uint64_t val)
2597
{
A
aurel32 已提交
2598
    CPU_DoubleU u;
2599

A
aurel32 已提交
2600
    u.ll = val;
2601
    /* NaN are not treated the same way IEEE 754 does */
2602
    if (unlikely(float64_is_nan(u.d)))
2603 2604
        return 0;

A
aurel32 已提交
2605
    return float64_to_int64_round_to_zero(u.d, &env->spe_status);
2606 2607
}

A
aurel32 已提交
2608
uint32_t helper_efdctuiz (uint64_t val)
2609
{
A
aurel32 已提交
2610
    CPU_DoubleU u;
2611

A
aurel32 已提交
2612 2613
    u.ll = val;
    /* NaN are not treated the same way IEEE 754 does */
2614
    if (unlikely(float64_is_nan(u.d)))
A
aurel32 已提交
2615
        return 0;
2616

A
aurel32 已提交
2617
    return float64_to_uint32_round_to_zero(u.d, &env->spe_status);
2618 2619
}

A
aurel32 已提交
2620
uint64_t helper_efdctuidz (uint64_t val)
2621
{
A
aurel32 已提交
2622
    CPU_DoubleU u;
2623

A
aurel32 已提交
2624 2625
    u.ll = val;
    /* NaN are not treated the same way IEEE 754 does */
2626
    if (unlikely(float64_is_nan(u.d)))
A
aurel32 已提交
2627
        return 0;
2628

A
aurel32 已提交
2629
    return float64_to_uint64_round_to_zero(u.d, &env->spe_status);
2630 2631
}

A
aurel32 已提交
2632
uint64_t helper_efdcfsf (uint32_t val)
2633
{
A
aurel32 已提交
2634
    CPU_DoubleU u;
2635 2636
    float64 tmp;

A
aurel32 已提交
2637
    u.d = int32_to_float64(val, &env->spe_status);
2638
    tmp = int64_to_float64(1ULL << 32, &env->spe_status);
A
aurel32 已提交
2639
    u.d = float64_div(u.d, tmp, &env->spe_status);
2640

A
aurel32 已提交
2641
    return u.ll;
2642 2643
}

A
aurel32 已提交
2644
uint64_t helper_efdcfuf (uint32_t val)
2645
{
A
aurel32 已提交
2646
    CPU_DoubleU u;
2647 2648
    float64 tmp;

A
aurel32 已提交
2649
    u.d = uint32_to_float64(val, &env->spe_status);
2650
    tmp = int64_to_float64(1ULL << 32, &env->spe_status);
A
aurel32 已提交
2651
    u.d = float64_div(u.d, tmp, &env->spe_status);
2652

A
aurel32 已提交
2653
    return u.ll;
2654 2655
}

A
aurel32 已提交
2656
uint32_t helper_efdctsf (uint64_t val)
2657
{
A
aurel32 已提交
2658
    CPU_DoubleU u;
2659 2660
    float64 tmp;

A
aurel32 已提交
2661
    u.ll = val;
2662
    /* NaN are not treated the same way IEEE 754 does */
2663
    if (unlikely(float64_is_nan(u.d)))
2664 2665
        return 0;
    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
A
aurel32 已提交
2666
    u.d = float64_mul(u.d, tmp, &env->spe_status);
2667

A
aurel32 已提交
2668
    return float64_to_int32(u.d, &env->spe_status);
2669 2670
}

A
aurel32 已提交
2671
uint32_t helper_efdctuf (uint64_t val)
2672
{
A
aurel32 已提交
2673
    CPU_DoubleU u;
2674 2675
    float64 tmp;

A
aurel32 已提交
2676
    u.ll = val;
2677
    /* NaN are not treated the same way IEEE 754 does */
2678
    if (unlikely(float64_is_nan(u.d)))
2679 2680
        return 0;
    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
A
aurel32 已提交
2681
    u.d = float64_mul(u.d, tmp, &env->spe_status);
2682

A
aurel32 已提交
2683
    return float64_to_uint32(u.d, &env->spe_status);
2684 2685
}

A
aurel32 已提交
2686
uint32_t helper_efscfd (uint64_t val)
2687
{
A
aurel32 已提交
2688 2689
    CPU_DoubleU u1;
    CPU_FloatU u2;
2690

A
aurel32 已提交
2691 2692
    u1.ll = val;
    u2.f = float64_to_float32(u1.d, &env->spe_status);
2693

A
aurel32 已提交
2694
    return u2.l;
2695 2696
}

A
aurel32 已提交
2697
uint64_t helper_efdcfs (uint32_t val)
2698
{
A
aurel32 已提交
2699 2700
    CPU_DoubleU u2;
    CPU_FloatU u1;
2701

A
aurel32 已提交
2702 2703
    u1.l = val;
    u2.d = float32_to_float64(u1.f, &env->spe_status);
2704

A
aurel32 已提交
2705
    return u2.ll;
2706 2707
}

A
aurel32 已提交
2708 2709
/* Double precision fixed-point arithmetic */
uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
2710
{
A
aurel32 已提交
2711 2712 2713 2714 2715
    CPU_DoubleU u1, u2;
    u1.ll = op1;
    u2.ll = op2;
    u1.d = float64_add(u1.d, u2.d, &env->spe_status);
    return u1.ll;
2716 2717
}

A
aurel32 已提交
2718
uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
2719
{
A
aurel32 已提交
2720 2721 2722 2723 2724
    CPU_DoubleU u1, u2;
    u1.ll = op1;
    u2.ll = op2;
    u1.d = float64_sub(u1.d, u2.d, &env->spe_status);
    return u1.ll;
2725 2726
}

A
aurel32 已提交
2727
uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
2728
{
A
aurel32 已提交
2729 2730 2731 2732 2733
    CPU_DoubleU u1, u2;
    u1.ll = op1;
    u2.ll = op2;
    u1.d = float64_mul(u1.d, u2.d, &env->spe_status);
    return u1.ll;
2734 2735
}

A
aurel32 已提交
2736
uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
2737
{
A
aurel32 已提交
2738 2739 2740 2741 2742
    CPU_DoubleU u1, u2;
    u1.ll = op1;
    u2.ll = op2;
    u1.d = float64_div(u1.d, u2.d, &env->spe_status);
    return u1.ll;
2743 2744
}

A
aurel32 已提交
2745 2746
/* Double precision floating point helpers */
uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
2747
{
A
aurel32 已提交
2748 2749 2750 2751
    CPU_DoubleU u1, u2;
    u1.ll = op1;
    u2.ll = op2;
    return float64_lt(u1.d, u2.d, &env->spe_status) ? 4 : 0;
2752 2753
}

A
aurel32 已提交
2754
uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
2755
{
A
aurel32 已提交
2756 2757 2758 2759
    CPU_DoubleU u1, u2;
    u1.ll = op1;
    u2.ll = op2;
    return float64_le(u1.d, u2.d, &env->spe_status) ? 0 : 4;
2760 2761
}

A
aurel32 已提交
2762
uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
2763
{
A
aurel32 已提交
2764 2765 2766 2767
    CPU_DoubleU u1, u2;
    u1.ll = op1;
    u2.ll = op2;
    return float64_eq(u1.d, u2.d, &env->spe_status) ? 4 : 0;
2768 2769
}

A
aurel32 已提交
2770
uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
2771
{
A
aurel32 已提交
2772 2773
    /* XXX: TODO: test special values (NaN, infinites, ...) */
    return helper_efdtstlt(op1, op2);
2774 2775
}

A
aurel32 已提交
2776 2777 2778 2779 2780
uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
{
    /* XXX: TODO: test special values (NaN, infinites, ...) */
    return helper_efdtstgt(op1, op2);
}
2781

A
aurel32 已提交
2782 2783 2784 2785 2786
uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
{
    /* XXX: TODO: test special values (NaN, infinites, ...) */
    return helper_efdtsteq(op1, op2);
}
2787

2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809
/*****************************************************************************/
/* Softmmu support */
#if !defined (CONFIG_USER_ONLY)

#define MMUSUFFIX _mmu

#define SHIFT 0
#include "softmmu_template.h"

#define SHIFT 1
#include "softmmu_template.h"

#define SHIFT 2
#include "softmmu_template.h"

#define SHIFT 3
#include "softmmu_template.h"

/* try to fill the TLB and return an exception if error. If retaddr is
   NULL, it means that the function was called in C code (i.e. not
   from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
2810
void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
2811 2812 2813
{
    TranslationBlock *tb;
    CPUState *saved_env;
B
bellard 已提交
2814
    unsigned long pc;
2815 2816 2817 2818 2819 2820
    int ret;

    /* XXX: hack to restore env in all cases, even if not called from
       generated code */
    saved_env = env;
    env = cpu_single_env;
2821
    ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
2822
    if (unlikely(ret != 0)) {
2823 2824
        if (likely(retaddr)) {
            /* now we have a real cpu fault */
B
bellard 已提交
2825
            pc = (unsigned long)retaddr;
2826 2827 2828 2829 2830
            tb = tb_find_pc(pc);
            if (likely(tb)) {
                /* the PC is inside the translated code. It means that we have
                   a virtual CPU fault */
                cpu_restore_state(tb, env, pc, NULL);
2831
            }
2832
        }
A
aurel32 已提交
2833
        helper_raise_exception_err(env->exception_index, env->error_code);
2834 2835
    }
    env = saved_env;
2836 2837
}

2838 2839 2840 2841 2842 2843 2844 2845
/* Segment registers load and store */
target_ulong helper_load_sr (target_ulong sr_num)
{
    return env->sr[sr_num];
}

void helper_store_sr (target_ulong sr_num, target_ulong val)
{
A
aurel32 已提交
2846
    ppc_store_sr(env, sr_num, val);
2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883
}

/* SLB management */
#if defined(TARGET_PPC64)
target_ulong helper_load_slb (target_ulong slb_nr)
{
    return ppc_load_slb(env, slb_nr);
}

void helper_store_slb (target_ulong slb_nr, target_ulong rs)
{
    ppc_store_slb(env, slb_nr, rs);
}

void helper_slbia (void)
{
    ppc_slb_invalidate_all(env);
}

void helper_slbie (target_ulong addr)
{
    ppc_slb_invalidate_one(env, addr);
}

#endif /* defined(TARGET_PPC64) */

/* TLB management */
void helper_tlbia (void)
{
    ppc_tlb_invalidate_all(env);
}

void helper_tlbie (target_ulong addr)
{
    ppc_tlb_invalidate_one(env, addr);
}

2884 2885
/* Software driven TLBs management */
/* PowerPC 602/603 software TLB load instructions helpers */
2886
static void do_6xx_tlb (target_ulong new_EPN, int is_code)
2887 2888 2889
{
    target_ulong RPN, CMP, EPN;
    int way;
2890

2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901
    RPN = env->spr[SPR_RPA];
    if (is_code) {
        CMP = env->spr[SPR_ICMP];
        EPN = env->spr[SPR_IMISS];
    } else {
        CMP = env->spr[SPR_DCMP];
        EPN = env->spr[SPR_DMISS];
    }
    way = (env->spr[SPR_SRR1] >> 17) & 1;
#if defined (DEBUG_SOFTWARE_TLB)
    if (loglevel != 0) {
2902
        fprintf(logfile, "%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
2903
                " PTE1 " ADDRX " way %d\n",
2904
                __func__, new_EPN, EPN, CMP, RPN, way);
2905 2906 2907
    }
#endif
    /* Store this TLB */
2908
    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2909
                     way, is_code, CMP, RPN);
2910 2911
}

2912
void helper_6xx_tlbd (target_ulong EPN)
2913
{
2914
    do_6xx_tlb(EPN, 0);
2915 2916
}

2917
void helper_6xx_tlbi (target_ulong EPN)
2918
{
2919
    do_6xx_tlb(EPN, 1);
2920 2921 2922
}

/* PowerPC 74xx software TLB load instructions helpers */
2923
static void do_74xx_tlb (target_ulong new_EPN, int is_code)
2924 2925 2926 2927 2928 2929 2930 2931 2932 2933
{
    target_ulong RPN, CMP, EPN;
    int way;

    RPN = env->spr[SPR_PTELO];
    CMP = env->spr[SPR_PTEHI];
    EPN = env->spr[SPR_TLBMISS] & ~0x3;
    way = env->spr[SPR_TLBMISS] & 0x3;
#if defined (DEBUG_SOFTWARE_TLB)
    if (loglevel != 0) {
2934
        fprintf(logfile, "%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
2935
                " PTE1 " ADDRX " way %d\n",
2936
                __func__, new_EPN, EPN, CMP, RPN, way);
2937 2938 2939
    }
#endif
    /* Store this TLB */
2940
    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2941 2942 2943
                     way, is_code, CMP, RPN);
}

2944
void helper_74xx_tlbd (target_ulong EPN)
2945
{
2946
    do_74xx_tlb(EPN, 0);
2947 2948
}

2949
void helper_74xx_tlbi (target_ulong EPN)
2950
{
2951
    do_74xx_tlb(EPN, 1);
2952 2953
}

J
j_mayer 已提交
2954
static always_inline target_ulong booke_tlb_to_page_size (int size)
J
j_mayer 已提交
2955 2956 2957 2958
{
    return 1024 << (2 * size);
}

J
j_mayer 已提交
2959
static always_inline int booke_page_size_to_tlb (target_ulong page_size)
J
j_mayer 已提交
2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021
{
    int size;

    switch (page_size) {
    case 0x00000400UL:
        size = 0x0;
        break;
    case 0x00001000UL:
        size = 0x1;
        break;
    case 0x00004000UL:
        size = 0x2;
        break;
    case 0x00010000UL:
        size = 0x3;
        break;
    case 0x00040000UL:
        size = 0x4;
        break;
    case 0x00100000UL:
        size = 0x5;
        break;
    case 0x00400000UL:
        size = 0x6;
        break;
    case 0x01000000UL:
        size = 0x7;
        break;
    case 0x04000000UL:
        size = 0x8;
        break;
    case 0x10000000UL:
        size = 0x9;
        break;
    case 0x40000000UL:
        size = 0xA;
        break;
#if defined (TARGET_PPC64)
    case 0x000100000000ULL:
        size = 0xB;
        break;
    case 0x000400000000ULL:
        size = 0xC;
        break;
    case 0x001000000000ULL:
        size = 0xD;
        break;
    case 0x004000000000ULL:
        size = 0xE;
        break;
    case 0x010000000000ULL:
        size = 0xF;
        break;
#endif
    default:
        size = -1;
        break;
    }

    return size;
}

3022
/* Helpers for 4xx TLB management */
3023
target_ulong helper_4xx_tlbre_lo (target_ulong entry)
3024
{
J
j_mayer 已提交
3025
    ppcemb_tlb_t *tlb;
3026
    target_ulong ret;
J
j_mayer 已提交
3027
    int size;
3028

3029 3030 3031
    entry &= 0x3F;
    tlb = &env->tlb[entry].tlbe;
    ret = tlb->EPN;
J
j_mayer 已提交
3032
    if (tlb->prot & PAGE_VALID)
3033
        ret |= 0x400;
J
j_mayer 已提交
3034 3035 3036
    size = booke_page_size_to_tlb(tlb->size);
    if (size < 0 || size > 0x7)
        size = 1;
3037
    ret |= size << 7;
J
j_mayer 已提交
3038
    env->spr[SPR_40x_PID] = tlb->PID;
3039
    return ret;
3040 3041
}

3042
target_ulong helper_4xx_tlbre_hi (target_ulong entry)
3043
{
J
j_mayer 已提交
3044
    ppcemb_tlb_t *tlb;
3045
    target_ulong ret;
3046

3047 3048 3049
    entry &= 0x3F;
    tlb = &env->tlb[entry].tlbe;
    ret = tlb->RPN;
J
j_mayer 已提交
3050
    if (tlb->prot & PAGE_EXEC)
3051
        ret |= 0x200;
J
j_mayer 已提交
3052
    if (tlb->prot & PAGE_WRITE)
3053 3054
        ret |= 0x100;
    return ret;
3055 3056
}

3057
void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
3058
{
J
j_mayer 已提交
3059
    ppcemb_tlb_t *tlb;
3060 3061
    target_ulong page, end;

3062
#if defined (DEBUG_SOFTWARE_TLB)
J
j_mayer 已提交
3063
    if (loglevel != 0) {
3064
        fprintf(logfile, "%s entry %d val " ADDRX "\n", __func__, (int)entry, val);
3065 3066
    }
#endif
3067 3068
    entry &= 0x3F;
    tlb = &env->tlb[entry].tlbe;
3069 3070 3071
    /* Invalidate previous TLB (if it's valid) */
    if (tlb->prot & PAGE_VALID) {
        end = tlb->EPN + tlb->size;
3072
#if defined (DEBUG_SOFTWARE_TLB)
J
j_mayer 已提交
3073
        if (loglevel != 0) {
3074
            fprintf(logfile, "%s: invalidate old TLB %d start " ADDRX
3075
                    " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
3076 3077
        }
#endif
3078 3079 3080
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
            tlb_flush_page(env, page);
    }
3081
    tlb->size = booke_tlb_to_page_size((val >> 7) & 0x7);
3082 3083 3084 3085
    /* We cannot handle TLB size < TARGET_PAGE_SIZE.
     * If this ever occurs, one should use the ppcemb target instead
     * of the ppc or ppc64 one
     */
3086
    if ((val & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
J
j_mayer 已提交
3087 3088
        cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
                  "are not supported (%d)\n",
3089
                  tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
3090
    }
3091 3092
    tlb->EPN = val & ~(tlb->size - 1);
    if (val & 0x40)
3093 3094 3095
        tlb->prot |= PAGE_VALID;
    else
        tlb->prot &= ~PAGE_VALID;
3096
    if (val & 0x20) {
3097 3098 3099
        /* XXX: TO BE FIXED */
        cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
    }
3100
    tlb->PID = env->spr[SPR_40x_PID]; /* PID */
3101
    tlb->attr = val & 0xFF;
3102
#if defined (DEBUG_SOFTWARE_TLB)
3103 3104
    if (loglevel != 0) {
        fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
3105
                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
3106
                (int)entry, tlb->RPN, tlb->EPN, tlb->size,
3107 3108 3109 3110 3111 3112
                tlb->prot & PAGE_READ ? 'r' : '-',
                tlb->prot & PAGE_WRITE ? 'w' : '-',
                tlb->prot & PAGE_EXEC ? 'x' : '-',
                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
    }
#endif
3113 3114 3115
    /* Invalidate new TLB (if valid) */
    if (tlb->prot & PAGE_VALID) {
        end = tlb->EPN + tlb->size;
3116
#if defined (DEBUG_SOFTWARE_TLB)
J
j_mayer 已提交
3117
        if (loglevel != 0) {
3118
            fprintf(logfile, "%s: invalidate TLB %d start " ADDRX
3119
                    " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
3120 3121
        }
#endif
3122 3123 3124 3125 3126
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
            tlb_flush_page(env, page);
    }
}

3127
void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
3128
{
J
j_mayer 已提交
3129
    ppcemb_tlb_t *tlb;
3130

3131
#if defined (DEBUG_SOFTWARE_TLB)
J
j_mayer 已提交
3132
    if (loglevel != 0) {
3133
        fprintf(logfile, "%s entry %i val " ADDRX "\n", __func__, (int)entry, val);
3134 3135
    }
#endif
3136 3137 3138
    entry &= 0x3F;
    tlb = &env->tlb[entry].tlbe;
    tlb->RPN = val & 0xFFFFFC00;
3139
    tlb->prot = PAGE_READ;
3140
    if (val & 0x200)
3141
        tlb->prot |= PAGE_EXEC;
3142
    if (val & 0x100)
3143
        tlb->prot |= PAGE_WRITE;
3144
#if defined (DEBUG_SOFTWARE_TLB)
J
j_mayer 已提交
3145 3146
    if (loglevel != 0) {
        fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
3147
                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
3148
                (int)entry, tlb->RPN, tlb->EPN, tlb->size,
3149 3150 3151 3152 3153 3154
                tlb->prot & PAGE_READ ? 'r' : '-',
                tlb->prot & PAGE_WRITE ? 'w' : '-',
                tlb->prot & PAGE_EXEC ? 'x' : '-',
                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
    }
#endif
3155
}
3156

3157 3158 3159 3160 3161
target_ulong helper_4xx_tlbsx (target_ulong address)
{
    return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
}

3162
/* PowerPC 440 TLB management */
3163
void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
3164 3165
{
    ppcemb_tlb_t *tlb;
3166
    target_ulong EPN, RPN, size;
3167 3168 3169 3170
    int do_flush_tlbs;

#if defined (DEBUG_SOFTWARE_TLB)
    if (loglevel != 0) {
3171 3172
        fprintf(logfile, "%s word %d entry %d value " ADDRX "\n",
                __func__, word, (int)entry, value);
3173 3174 3175
    }
#endif
    do_flush_tlbs = 0;
3176 3177
    entry &= 0x3F;
    tlb = &env->tlb[entry].tlbe;
3178 3179 3180 3181
    switch (word) {
    default:
        /* Just here to please gcc */
    case 0:
3182
        EPN = value & 0xFFFFFC00;
3183
        if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
3184
            do_flush_tlbs = 1;
3185
        tlb->EPN = EPN;
3186
        size = booke_tlb_to_page_size((value >> 4) & 0xF);
3187 3188 3189 3190
        if ((tlb->prot & PAGE_VALID) && tlb->size < size)
            do_flush_tlbs = 1;
        tlb->size = size;
        tlb->attr &= ~0x1;
3191 3192
        tlb->attr |= (value >> 8) & 1;
        if (value & 0x200) {
3193 3194 3195 3196 3197 3198
            tlb->prot |= PAGE_VALID;
        } else {
            if (tlb->prot & PAGE_VALID) {
                tlb->prot &= ~PAGE_VALID;
                do_flush_tlbs = 1;
            }
3199
        }
3200 3201 3202 3203 3204
        tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
        if (do_flush_tlbs)
            tlb_flush(env, 1);
        break;
    case 1:
3205
        RPN = value & 0xFFFFFC0F;
3206 3207 3208 3209 3210
        if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
            tlb_flush(env, 1);
        tlb->RPN = RPN;
        break;
    case 2:
3211
        tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
3212
        tlb->prot = tlb->prot & PAGE_VALID;
3213
        if (value & 0x1)
3214
            tlb->prot |= PAGE_READ << 4;
3215
        if (value & 0x2)
3216
            tlb->prot |= PAGE_WRITE << 4;
3217
        if (value & 0x4)
3218
            tlb->prot |= PAGE_EXEC << 4;
3219
        if (value & 0x8)
3220
            tlb->prot |= PAGE_READ;
3221
        if (value & 0x10)
3222
            tlb->prot |= PAGE_WRITE;
3223
        if (value & 0x20)
3224 3225
            tlb->prot |= PAGE_EXEC;
        break;
3226 3227 3228
    }
}

3229
target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
3230 3231
{
    ppcemb_tlb_t *tlb;
3232
    target_ulong ret;
3233 3234
    int size;

3235 3236
    entry &= 0x3F;
    tlb = &env->tlb[entry].tlbe;
3237 3238 3239 3240
    switch (word) {
    default:
        /* Just here to please gcc */
    case 0:
3241
        ret = tlb->EPN;
3242 3243 3244
        size = booke_page_size_to_tlb(tlb->size);
        if (size < 0 || size > 0xF)
            size = 1;
3245
        ret |= size << 4;
3246
        if (tlb->attr & 0x1)
3247
            ret |= 0x100;
3248
        if (tlb->prot & PAGE_VALID)
3249
            ret |= 0x200;
3250 3251 3252 3253
        env->spr[SPR_440_MMUCR] &= ~0x000000FF;
        env->spr[SPR_440_MMUCR] |= tlb->PID;
        break;
    case 1:
3254
        ret = tlb->RPN;
3255 3256
        break;
    case 2:
3257
        ret = tlb->attr & ~0x1;
3258
        if (tlb->prot & (PAGE_READ << 4))
3259
            ret |= 0x1;
3260
        if (tlb->prot & (PAGE_WRITE << 4))
3261
            ret |= 0x2;
3262
        if (tlb->prot & (PAGE_EXEC << 4))
3263
            ret |= 0x4;
3264
        if (tlb->prot & PAGE_READ)
3265
            ret |= 0x8;
3266
        if (tlb->prot & PAGE_WRITE)
3267
            ret |= 0x10;
3268
        if (tlb->prot & PAGE_EXEC)
3269
            ret |= 0x20;
3270 3271
        break;
    }
3272
    return ret;
3273
}
3274 3275 3276 3277 3278 3279

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

3280
#endif /* !CONFIG_USER_ONLY */