op_helper.c 73.9 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 18 19 20
 *
 * 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
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#include "exec.h"
21
#include "host-utils.h"
P
pbrook 已提交
22
#include "helper.h"
23

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

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

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

46 47 48
/*****************************************************************************/
/* Exceptions processing helpers */

49
void helper_raise_exception_err (uint32_t exception, uint32_t error_code)
50
{
51
    raise_exception_err(env, exception, error_code);
52
}
53

54
void helper_raise_debug (void)
55
{
56
    raise_exception(env, EXCP_DEBUG);
57 58
}

59

60 61
/*****************************************************************************/
/* Registers load and stores */
P
pbrook 已提交
62
target_ulong helper_load_cr (void)
63
{
64 65 66 67 68 69 70 71
    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);
72 73
}

74
void helper_store_cr (target_ulong val, uint32_t mask)
75 76 77
{
    int i, sh;

78
    for (i = 0, sh = 7; i < 8; i++, sh--) {
79
        if (mask & (1 << sh))
80
            env->crf[i] = (val >> (sh * 4)) & 0xFUL;
81 82 83
    }
}

84 85 86 87 88 89 90 91
#if defined(TARGET_PPC64)
void do_store_pri (int prio)
{
    env->spr[SPR_PPR] &= ~0x001C000000000000ULL;
    env->spr[SPR_PPR] |= ((uint64_t)prio & 0x7) << 50;
}
#endif

92 93
target_ulong ppc_load_dump_spr (int sprn)
{
J
j_mayer 已提交
94
    if (loglevel != 0) {
95 96 97 98 99 100 101 102 103
        fprintf(logfile, "Read SPR %d %03x => " ADDRX "\n",
                sprn, sprn, env->spr[sprn]);
    }

    return env->spr[sprn];
}

void ppc_store_dump_spr (int sprn, target_ulong val)
{
J
j_mayer 已提交
104
    if (loglevel != 0) {
105 106 107 108 109 110
        fprintf(logfile, "Write SPR %d %03x => " ADDRX " <= " ADDRX "\n",
                sprn, sprn, env->spr[sprn], val);
    }
    env->spr[sprn] = val;
}

111
/*****************************************************************************/
112
/* Fixed point operations helpers */
113 114
#if defined(TARGET_PPC64)

115 116
/* multiply high word */
uint64_t helper_mulhd (uint64_t arg1, uint64_t arg2)
117
{
118
    uint64_t tl, th;
119

120 121
    muls64(&tl, &th, arg1, arg2);
    return th;
122 123
}

124 125
/* multiply high word unsigned */
uint64_t helper_mulhdu (uint64_t arg1, uint64_t arg2)
126
{
127
    uint64_t tl, th;
128

129 130
    mulu64(&tl, &th, arg1, arg2);
    return th;
131 132
}

133
uint64_t helper_mulldo (uint64_t arg1, uint64_t arg2)
134
{
135 136 137
    int64_t th;
    uint64_t tl;

138
    muls64(&tl, (uint64_t *)&th, arg1, arg2);
139
    /* If th != 0 && th != -1, then we had an overflow */
140
    if (likely((uint64_t)(th + 1) <= 1)) {
A
aurel32 已提交
141
        env->xer &= ~(1 << XER_OV);
142
    } else {
A
aurel32 已提交
143
        env->xer |= (1 << XER_OV) | (1 << XER_SO);
144
    }
145
    return (int64_t)tl;
146 147 148
}
#endif

149
target_ulong helper_cntlzw (target_ulong t)
150
{
151
    return clz32(t);
152 153 154
}

#if defined(TARGET_PPC64)
155
target_ulong helper_cntlzd (target_ulong t)
156
{
157
    return clz64(t);
158 159 160
}
#endif

161
/* shift right arithmetic helper */
162
target_ulong helper_sraw (target_ulong value, target_ulong shift)
163 164 165
{
    int32_t ret;

166 167 168 169 170
    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 已提交
171
                env->xer &= ~(1 << XER_CA);
172
            } else {
A
aurel32 已提交
173
                env->xer |= (1 << XER_CA);
174 175
            }
        } else {
176
            ret = (int32_t)value;
A
aurel32 已提交
177
            env->xer &= ~(1 << XER_CA);
178 179
        }
    } else {
180 181
        ret = (int32_t)value >> 31;
        if (ret) {
A
aurel32 已提交
182
            env->xer |= (1 << XER_CA);
183 184
        } else {
            env->xer &= ~(1 << XER_CA);
185
        }
186
    }
187
    return (target_long)ret;
188 189
}

190
#if defined(TARGET_PPC64)
191
target_ulong helper_srad (target_ulong value, target_ulong shift)
192 193 194
{
    int64_t ret;

195 196 197 198 199
    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 已提交
200
                env->xer &= ~(1 << XER_CA);
201
            } else {
A
aurel32 已提交
202
                env->xer |= (1 << XER_CA);
203 204
            }
        } else {
205
            ret = (int64_t)value;
A
aurel32 已提交
206
            env->xer &= ~(1 << XER_CA);
207 208
        }
    } else {
209 210
        ret = (int64_t)value >> 63;
        if (ret) {
A
aurel32 已提交
211
            env->xer |= (1 << XER_CA);
212 213
        } else {
            env->xer &= ~(1 << XER_CA);
214 215
        }
    }
216
    return ret;
217 218 219
}
#endif

220
target_ulong helper_popcntb (target_ulong val)
221
{
A
aurel32 已提交
222 223 224 225
    val = (val & 0x55555555) + ((val >>  1) & 0x55555555);
    val = (val & 0x33333333) + ((val >>  2) & 0x33333333);
    val = (val & 0x0f0f0f0f) + ((val >>  4) & 0x0f0f0f0f);
    return val;
226 227 228
}

#if defined(TARGET_PPC64)
229
target_ulong helper_popcntb_64 (target_ulong val)
230
{
A
aurel32 已提交
231 232 233 234
    val = (val & 0x5555555555555555ULL) + ((val >>  1) & 0x5555555555555555ULL);
    val = (val & 0x3333333333333333ULL) + ((val >>  2) & 0x3333333333333333ULL);
    val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >>  4) & 0x0f0f0f0f0f0f0f0fULL);
    return val;
235 236 237
}
#endif

238
/*****************************************************************************/
239
/* Floating point operations helpers */
A
aurel32 已提交
240
static always_inline int fpisneg (float64 d)
241
{
A
aurel32 已提交
242
    CPU_DoubleU u;
243

A
aurel32 已提交
244
    u.d = d;
245

A
aurel32 已提交
246
    return u.ll >> 63 != 0;
247 248
}

A
aurel32 已提交
249
static always_inline int isden (float64 d)
250
{
A
aurel32 已提交
251
    CPU_DoubleU u;
252

A
aurel32 已提交
253
    u.d = d;
254

A
aurel32 已提交
255
    return ((u.ll >> 52) & 0x7FF) == 0;
256 257
}

A
aurel32 已提交
258
static always_inline int iszero (float64 d)
259
{
A
aurel32 已提交
260
    CPU_DoubleU u;
261

A
aurel32 已提交
262
    u.d = d;
263

A
aurel32 已提交
264
    return (u.ll & ~0x8000000000000000ULL) == 0;
265 266
}

A
aurel32 已提交
267
static always_inline int isinfinity (float64 d)
268
{
A
aurel32 已提交
269
    CPU_DoubleU u;
270

A
aurel32 已提交
271
    u.d = d;
272

A
aurel32 已提交
273 274
    return ((u.ll >> 52) & 0x7FF) == 0x7FF &&
        (u.ll & 0x000FFFFFFFFFFFFFULL) == 0;
275 276
}

277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
#ifdef CONFIG_SOFTFLOAT
static always_inline int isfinite (float64 d)
{
    CPU_DoubleU u;

    u.d = d;

    return (((u.ll >> 52) & 0x7FF) != 0x7FF);
}

static always_inline int isnormal (float64 d)
{
    CPU_DoubleU u;

    u.d = d;

    uint32_t exp = (u.ll >> 52) & 0x7FF;
    return ((0 < exp) && (exp < 0x7FF));
}
#endif

A
aurel32 已提交
298
uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf)
299
{
A
aurel32 已提交
300
    CPU_DoubleU farg;
301
    int isneg;
A
aurel32 已提交
302 303 304 305 306
    int ret;
    farg.ll = arg;
    isneg = fpisneg(farg.d);
    if (unlikely(float64_is_nan(farg.d))) {
        if (float64_is_signaling_nan(farg.d)) {
307
            /* Signaling NaN: flags are undefined */
A
aurel32 已提交
308
            ret = 0x00;
309 310
        } else {
            /* Quiet NaN */
A
aurel32 已提交
311
            ret = 0x11;
312
        }
A
aurel32 已提交
313
    } else if (unlikely(isinfinity(farg.d))) {
314 315
        /* +/- infinity */
        if (isneg)
A
aurel32 已提交
316
            ret = 0x09;
317
        else
A
aurel32 已提交
318
            ret = 0x05;
319
    } else {
A
aurel32 已提交
320
        if (iszero(farg.d)) {
321 322
            /* +/- zero */
            if (isneg)
A
aurel32 已提交
323
                ret = 0x12;
324
            else
A
aurel32 已提交
325
                ret = 0x02;
326
        } else {
A
aurel32 已提交
327
            if (isden(farg.d)) {
328
                /* Denormalized numbers */
A
aurel32 已提交
329
                ret = 0x10;
330 331
            } else {
                /* Normalized numbers */
A
aurel32 已提交
332
                ret = 0x00;
333 334
            }
            if (isneg) {
A
aurel32 已提交
335
                ret |= 0x08;
336
            } else {
A
aurel32 已提交
337
                ret |= 0x04;
338 339 340 341 342 343
            }
        }
    }
    if (set_fprf) {
        /* We update FPSCR_FPRF */
        env->fpscr &= ~(0x1F << FPSCR_FPRF);
A
aurel32 已提交
344
        env->fpscr |= ret << FPSCR_FPRF;
345 346
    }
    /* We just need fpcc to update Rc1 */
A
aurel32 已提交
347
    return ret & 0xF;
348 349 350
}

/* Floating-point invalid operations exception */
A
aurel32 已提交
351
static always_inline uint64_t fload_invalid_op_excp (int op)
352
{
A
aurel32 已提交
353
    uint64_t ret = 0;
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
    int ve;

    ve = fpscr_ve;
    if (op & POWERPC_EXCP_FP_VXSNAN) {
        /* Operation on signaling NaN */
        env->fpscr |= 1 << FPSCR_VXSNAN;
    }
    if (op & POWERPC_EXCP_FP_VXSOFT) {
        /* Software-defined condition */
        env->fpscr |= 1 << FPSCR_VXSOFT;
    }
    switch (op & ~(POWERPC_EXCP_FP_VXSOFT | POWERPC_EXCP_FP_VXSNAN)) {
    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 已提交
404
            ret = UINT64_MAX;
405 406 407 408 409 410 411 412 413 414
            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 已提交
415
            ret = UINT64_MAX;
416 417 418 419 420 421 422 423 424 425 426 427 428
            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)
429
            raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | op);
430
    }
A
aurel32 已提交
431
    return ret;
432 433
}

A
aurel32 已提交
434
static always_inline uint64_t float_zero_divide_excp (uint64_t arg1, uint64_t arg2)
435 436 437 438 439 440 441 442 443
{
    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) {
444 445
            raise_exception_err(env, POWERPC_EXCP_PROGRAM,
                                POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
446 447 448
        }
    } else {
        /* Set the result to infinity */
A
aurel32 已提交
449 450
        arg1 = ((arg1 ^ arg2) & 0x8000000000000000ULL);
        arg1 |= 0x7FFULL << 52;
451
    }
A
aurel32 已提交
452
    return arg1;
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
}

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 已提交
529
void helper_fpscr_setbit (uint32_t bit)
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643
{
    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 已提交
644
void helper_store_fpscr (uint64_t arg, uint32_t mask)
645 646 647 648 649 650 651 652
{
    /*
     * We use only the 32 LSB of the incoming fpr
     */
    uint32_t prev, new;
    int i;

    prev = env->fpscr;
A
aurel32 已提交
653
    new = (uint32_t)arg;
654 655 656 657 658 659 660 661 662 663 664
    new &= ~0x90000000;
    new |= prev & 0x90000000;
    for (i = 0; i < 7; i++) {
        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;
665 666
    else
        env->fpscr &= ~(1 << FPSCR_VX);
667 668 669 670 671 672
    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;
    }
673 674
    else
        env->fpscr &= ~(1 << FPSCR_FEX);
675 676 677
    fpscr_set_rounding_mode();
}

A
aurel32 已提交
678
void helper_float_check_status (void)
679
{
A
aurel32 已提交
680
#ifdef CONFIG_SOFTFLOAT
681 682 683 684
    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)
685
            raise_exception_err(env, env->exception_index, env->error_code);
686 687 688 689 690 691 692
    } else if (env->fp_status.float_exception_flags & float_flag_overflow) {
        float_overflow_excp();
    } else if (env->fp_status.float_exception_flags & float_flag_underflow) {
        float_underflow_excp();
    } else if (env->fp_status.float_exception_flags & float_flag_inexact) {
        float_inexact_excp();
    }
A
aurel32 已提交
693 694 695 696 697
#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)
698
            raise_exception_err(env, env->exception_index, env->error_code);
A
aurel32 已提交
699 700 701 702 703 704 705 706 707
    }
    RETURN();
#endif
}

#ifdef CONFIG_SOFTFLOAT
void helper_reset_fpstatus (void)
{
    env->fp_status.float_exception_flags = 0;
708 709 710
}
#endif

A
aurel32 已提交
711 712
/* fadd - fadd. */
uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
713
{
A
aurel32 已提交
714 715 716 717 718 719 720
    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))) {
721
        /* sNaN addition */
A
aurel32 已提交
722 723 724 725
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
    } else if (likely(isfinite(farg1.d) || isfinite(farg2.d) ||
                      fpisneg(farg1.d) == fpisneg(farg2.d))) {
        farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
726 727
    } else {
        /* Magnitude subtraction of infinities */
A
aurel32 已提交
728
        farg1.ll == fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
729
    }
A
aurel32 已提交
730 731 732 733
#else
    farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
#endif
    return farg1.ll;
734 735
}

A
aurel32 已提交
736 737 738 739 740 741 742 743
/* 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
744
{
A
aurel32 已提交
745 746
    if (unlikely(float64_is_signaling_nan(farg1.d) ||
                 float64_is_signaling_nan(farg2.d))) {
747
        /* sNaN subtraction */
A
aurel32 已提交
748 749 750 751
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
    } else if (likely(isfinite(farg1.d) || isfinite(farg2.d) ||
                      fpisneg(farg1.d) != fpisneg(farg2.d))) {
        farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
752 753
    } else {
        /* Magnitude subtraction of infinities */
A
aurel32 已提交
754
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
755 756
    }
}
A
aurel32 已提交
757 758 759 760 761
#else
    farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
#endif
    return farg1.ll;
}
762

A
aurel32 已提交
763 764
/* fmul - fmul. */
uint64_t helper_fmul (uint64_t arg1, uint64_t arg2)
765
{
A
aurel32 已提交
766 767 768 769 770 771 772
    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))) {
773
        /* sNaN multiplication */
A
aurel32 已提交
774 775 776
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
    } else if (unlikely((isinfinity(farg1.d) && iszero(farg2.d)) ||
                        (iszero(farg1.d) && isinfinity(farg2.d)))) {
777
        /* Multiplication of zero by infinity */
A
aurel32 已提交
778
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
779
    } else {
A
aurel32 已提交
780
        farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
781 782
    }
}
A
aurel32 已提交
783 784 785 786 787
#else
    farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
#endif
    return farg1.ll;
}
788

A
aurel32 已提交
789 790
/* fdiv - fdiv. */
uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2)
791
{
A
aurel32 已提交
792 793 794 795 796 797 798
    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))) {
799
        /* sNaN division */
A
aurel32 已提交
800 801
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
    } else if (unlikely(isinfinity(farg1.d) && isinfinity(farg2.d))) {
802
        /* Division of infinity by infinity */
A
aurel32 已提交
803 804 805
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
    } else if (unlikely(iszero(farg2.d))) {
        if (iszero(farg1.d)) {
806
            /* Division of zero by zero */
A
aurel32 已提交
807
            farg1.ll fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
808 809
        } else {
            /* Division by zero */
A
aurel32 已提交
810
            farg1.ll = float_zero_divide_excp(farg1.d, farg2.d);
811 812
        }
    } else {
A
aurel32 已提交
813
        farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
814
    }
A
aurel32 已提交
815 816 817 818
#else
    farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
#endif
    return farg1.ll;
819 820
}

A
aurel32 已提交
821 822
/* fabs */
uint64_t helper_fabs (uint64_t arg)
823
{
A
aurel32 已提交
824
    CPU_DoubleU farg;
825

A
aurel32 已提交
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
    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))) {
859
        /* sNaN conversion */
A
aurel32 已提交
860 861
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
    } else if (unlikely(float64_is_nan(farg.d) || isinfinity(farg.d))) {
862
        /* qNan / infinity conversion */
A
aurel32 已提交
863
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
864
    } else {
A
aurel32 已提交
865
        farg.ll = float64_to_int32(farg.d, &env->fp_status);
866
#if USE_PRECISE_EMULATION
867 868 869
        /* XXX: higher bits are not supposed to be significant.
         *     to make tests easier, return the same as a real PowerPC 750
         */
A
aurel32 已提交
870
        farg.ll |= 0xFFF80000ULL << 32;
J
j_mayer 已提交
871
#endif
872
    }
A
aurel32 已提交
873
    return farg.ll;
874 875
}

A
aurel32 已提交
876 877
/* fctiwz - fctiwz. */
uint64_t helper_fctiwz (uint64_t arg)
878
{
A
aurel32 已提交
879 880
    CPU_DoubleU farg;
    farg.ll = arg;
881

A
aurel32 已提交
882
    if (unlikely(float64_is_signaling_nan(farg.d))) {
883
        /* sNaN conversion */
A
aurel32 已提交
884 885
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
    } else if (unlikely(float64_is_nan(farg.d) || isinfinity(farg.d))) {
886
        /* qNan / infinity conversion */
A
aurel32 已提交
887
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
888
    } else {
A
aurel32 已提交
889
        farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status);
890
#if USE_PRECISE_EMULATION
891 892 893
        /* XXX: higher bits are not supposed to be significant.
         *     to make tests easier, return the same as a real PowerPC 750
         */
A
aurel32 已提交
894
        farg.ll |= 0xFFF80000ULL << 32;
J
j_mayer 已提交
895
#endif
896
    }
A
aurel32 已提交
897
    return farg.ll;
898 899
}

J
j_mayer 已提交
900
#if defined(TARGET_PPC64)
A
aurel32 已提交
901 902
/* fcfid - fcfid. */
uint64_t helper_fcfid (uint64_t arg)
J
j_mayer 已提交
903
{
A
aurel32 已提交
904 905 906
    CPU_DoubleU farg;
    farg.d = int64_to_float64(arg, &env->fp_status);
    return farg.ll;
J
j_mayer 已提交
907 908
}

A
aurel32 已提交
909 910
/* fctid - fctid. */
uint64_t helper_fctid (uint64_t arg)
J
j_mayer 已提交
911
{
A
aurel32 已提交
912 913
    CPU_DoubleU farg;
    farg.ll = arg;
J
j_mayer 已提交
914

A
aurel32 已提交
915
    if (unlikely(float64_is_signaling_nan(farg.d))) {
916
        /* sNaN conversion */
A
aurel32 已提交
917 918
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
    } else if (unlikely(float64_is_nan(farg.d) || isinfinity(farg.d))) {
919
        /* qNan / infinity conversion */
A
aurel32 已提交
920
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
921
    } else {
A
aurel32 已提交
922
        farg.ll = float64_to_int64(farg.d, &env->fp_status);
923
    }
A
aurel32 已提交
924
    return farg.ll;
J
j_mayer 已提交
925 926
}

A
aurel32 已提交
927 928
/* fctidz - fctidz. */
uint64_t helper_fctidz (uint64_t arg)
J
j_mayer 已提交
929
{
A
aurel32 已提交
930 931
    CPU_DoubleU farg;
    farg.ll = arg;
J
j_mayer 已提交
932

A
aurel32 已提交
933
    if (unlikely(float64_is_signaling_nan(farg.d))) {
934
        /* sNaN conversion */
A
aurel32 已提交
935 936
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
    } else if (unlikely(float64_is_nan(farg.d) || isinfinity(farg.d))) {
937
        /* qNan / infinity conversion */
A
aurel32 已提交
938
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
939
    } else {
A
aurel32 已提交
940
        farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status);
941
    }
A
aurel32 已提交
942
    return farg.ll;
J
j_mayer 已提交
943 944 945 946
}

#endif

A
aurel32 已提交
947
static always_inline uint64_t do_fri (uint64_t arg, int rounding_mode)
948
{
A
aurel32 已提交
949 950 951 952
    CPU_DoubleU farg;
    farg.ll = arg;

    if (unlikely(float64_is_signaling_nan(farg.d))) {
953
        /* sNaN round */
A
aurel32 已提交
954 955
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
    } else if (unlikely(float64_is_nan(farg.d) || isinfinity(farg.d))) {
956
        /* qNan / infinity round */
A
aurel32 已提交
957
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
958 959
    } else {
        set_float_rounding_mode(rounding_mode, &env->fp_status);
A
aurel32 已提交
960
        farg.ll = float64_round_to_int(farg.d, &env->fp_status);
961 962 963
        /* Restore rounding mode from FPSCR */
        fpscr_set_rounding_mode();
    }
A
aurel32 已提交
964
    return farg.ll;
965 966
}

A
aurel32 已提交
967
uint64_t helper_frin (uint64_t arg)
968
{
A
aurel32 已提交
969
    return do_fri(arg, float_round_nearest_even);
970 971
}

A
aurel32 已提交
972
uint64_t helper_friz (uint64_t arg)
973
{
A
aurel32 已提交
974
    return do_fri(arg, float_round_to_zero);
975 976
}

A
aurel32 已提交
977
uint64_t helper_frip (uint64_t arg)
978
{
A
aurel32 已提交
979
    return do_fri(arg, float_round_up);
980 981
}

A
aurel32 已提交
982
uint64_t helper_frim (uint64_t arg)
983
{
A
aurel32 已提交
984
    return do_fri(arg, float_round_down);
985 986
}

A
aurel32 已提交
987 988
/* fmadd - fmadd. */
uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
J
j_mayer 已提交
989
{
A
aurel32 已提交
990 991 992 993 994 995 996 997 998
    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))) {
999
        /* sNaN operation */
A
aurel32 已提交
1000
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1001
    } else {
J
j_mayer 已提交
1002
#ifdef FLOAT128
1003 1004 1005
        /* This is the way the PowerPC specification defines it */
        float128 ft0_128, ft1_128;

A
aurel32 已提交
1006 1007
        ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
        ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1008
        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
A
aurel32 已提交
1009
        ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1010
        ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
A
aurel32 已提交
1011
        farg1.d = float128_to_float64(ft0_128, &env->fp_status);
J
j_mayer 已提交
1012
#else
1013
        /* This is OK on x86 hosts */
A
aurel32 已提交
1014
        farg1.d = (farg1.d * farg2.d) + farg3.d;
J
j_mayer 已提交
1015
#endif
1016
    }
A
aurel32 已提交
1017 1018 1019 1020 1021
#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 已提交
1022 1023
}

A
aurel32 已提交
1024 1025
/* fmsub - fmsub. */
uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
J
j_mayer 已提交
1026
{
A
aurel32 已提交
1027 1028 1029 1030 1031 1032 1033 1034 1035
    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))) {
1036
        /* sNaN operation */
A
aurel32 已提交
1037
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1038
    } else {
J
j_mayer 已提交
1039
#ifdef FLOAT128
1040 1041 1042
        /* This is the way the PowerPC specification defines it */
        float128 ft0_128, ft1_128;

A
aurel32 已提交
1043 1044
        ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
        ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1045
        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
A
aurel32 已提交
1046
        ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1047
        ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
A
aurel32 已提交
1048
        farg1.d = float128_to_float64(ft0_128, &env->fp_status);
J
j_mayer 已提交
1049
#else
1050
        /* This is OK on x86 hosts */
A
aurel32 已提交
1051
        farg1.d = (farg1.d * farg2.d) - farg3.d;
J
j_mayer 已提交
1052
#endif
1053
    }
A
aurel32 已提交
1054 1055 1056 1057 1058
#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 已提交
1059 1060
}

A
aurel32 已提交
1061 1062
/* fnmadd - fnmadd. */
uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
B
bellard 已提交
1063
{
A
aurel32 已提交
1064 1065 1066 1067 1068 1069 1070 1071 1072
    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))) {
1073
        /* sNaN operation */
A
aurel32 已提交
1074
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1075
    } else {
1076
#if USE_PRECISE_EMULATION
J
j_mayer 已提交
1077
#ifdef FLOAT128
1078 1079 1080
        /* This is the way the PowerPC specification defines it */
        float128 ft0_128, ft1_128;

A
aurel32 已提交
1081 1082
        ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
        ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1083
        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
A
aurel32 已提交
1084
        ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1085
        ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
A
aurel32 已提交
1086
        farg1.d= float128_to_float64(ft0_128, &env->fp_status);
J
j_mayer 已提交
1087
#else
1088
        /* This is OK on x86 hosts */
A
aurel32 已提交
1089
        farg1.d = (farg1.d * farg2.d) + farg3.d;
J
j_mayer 已提交
1090 1091
#endif
#else
A
aurel32 已提交
1092 1093
        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 已提交
1094
#endif
A
aurel32 已提交
1095 1096
        if (likely(!isnan(farg1.d)))
            farg1.d = float64_chs(farg1.d);
1097
    }
A
aurel32 已提交
1098
    return farg1.ll;
B
bellard 已提交
1099 1100
}

A
aurel32 已提交
1101 1102
/* fnmsub - fnmsub. */
uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
B
bellard 已提交
1103
{
A
aurel32 已提交
1104 1105 1106 1107 1108 1109 1110 1111 1112
    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))) {
1113
        /* sNaN operation */
A
aurel32 已提交
1114
        farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1115
    } else {
1116
#if USE_PRECISE_EMULATION
J
j_mayer 已提交
1117
#ifdef FLOAT128
1118 1119 1120
        /* This is the way the PowerPC specification defines it */
        float128 ft0_128, ft1_128;

A
aurel32 已提交
1121 1122
        ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
        ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1123
        ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
A
aurel32 已提交
1124
        ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1125
        ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
A
aurel32 已提交
1126
        farg1.d = float128_to_float64(ft0_128, &env->fp_status);
J
j_mayer 已提交
1127
#else
1128
        /* This is OK on x86 hosts */
A
aurel32 已提交
1129
        farg1.d = (farg1.d * farg2.d) - farg3.d;
J
j_mayer 已提交
1130 1131
#endif
#else
A
aurel32 已提交
1132 1133
        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 已提交
1134
#endif
A
aurel32 已提交
1135 1136
        if (likely(!isnan(farg1.d)))
            farg1.d = float64_chs(farg1.d);
1137
    }
A
aurel32 已提交
1138
    return farg1.ll;
B
bellard 已提交
1139 1140
}

A
aurel32 已提交
1141 1142 1143

/* frsp - frsp. */
uint64_t helper_frsp (uint64_t arg)
1144
{
A
aurel32 已提交
1145 1146 1147 1148 1149
    CPU_DoubleU farg;
    farg.ll = arg;

#if USE_PRECISE_EMULATION
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1150
        /* sNaN square root */
A
aurel32 已提交
1151
       farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1152
    } else {
A
aurel32 已提交
1153
       fard.d = float64_to_float32(farg.d, &env->fp_status);
1154
    }
A
aurel32 已提交
1155 1156 1157 1158
#else
    farg.d = float64_to_float32(farg.d, &env->fp_status);
#endif
    return farg.ll;
1159 1160
}

A
aurel32 已提交
1161 1162
/* fsqrt - fsqrt. */
uint64_t helper_fsqrt (uint64_t arg)
1163
{
A
aurel32 已提交
1164 1165 1166 1167
    CPU_DoubleU farg;
    farg.ll = arg;

    if (unlikely(float64_is_signaling_nan(farg.d))) {
1168
        /* sNaN square root */
A
aurel32 已提交
1169 1170
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
    } else if (unlikely(fpisneg(farg.d) && !iszero(farg.d))) {
1171
        /* Square root of a negative nonzero number */
A
aurel32 已提交
1172
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
1173
    } else {
A
aurel32 已提交
1174
        farg.d = float64_sqrt(farg.d, &env->fp_status);
1175
    }
A
aurel32 已提交
1176
    return farg.ll;
1177 1178
}

A
aurel32 已提交
1179 1180
/* fre - fre. */
uint64_t helper_fre (uint64_t arg)
1181
{
A
aurel32 已提交
1182 1183
    CPU_DoubleU farg;
    farg.ll = arg;
1184

A
aurel32 已提交
1185
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1186
        /* sNaN reciprocal */
A
aurel32 已提交
1187 1188
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
    } else if (unlikely(iszero(farg.d))) {
1189
        /* Zero reciprocal */
A
aurel32 已提交
1190 1191 1192
        farg.ll = float_zero_divide_excp(1.0, farg.d);
    } else if (likely(isnormal(farg.d))) {
        farg.d = float64_div(1.0, farg.d, &env->fp_status);
1193
    } else {
A
aurel32 已提交
1194 1195 1196 1197 1198 1199 1200 1201
        if (farg.ll == 0x8000000000000000ULL) {
            farg.ll = 0xFFF0000000000000ULL;
        } else if (farg.ll == 0x0000000000000000ULL) {
            farg.ll = 0x7FF0000000000000ULL;
        } else if (isnan(farg.d)) {
            farg.ll = 0x7FF8000000000000ULL;
        } else if (fpisneg(farg.d)) {
            farg.ll = 0x8000000000000000ULL;
1202
        } else {
A
aurel32 已提交
1203
            farg.ll = 0x0000000000000000ULL;
1204 1205
        }
    }
A
aurel32 已提交
1206
    return farg.d;
1207 1208
}

A
aurel32 已提交
1209 1210
/* fres - fres. */
uint64_t helper_fres (uint64_t arg)
1211
{
A
aurel32 已提交
1212 1213
    CPU_DoubleU farg;
    farg.ll = arg;
1214

A
aurel32 已提交
1215
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1216
        /* sNaN reciprocal */
A
aurel32 已提交
1217 1218
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
    } else if (unlikely(iszero(farg.d))) {
1219
        /* Zero reciprocal */
A
aurel32 已提交
1220 1221
        farg.ll = float_zero_divide_excp(1.0, farg.d);
    } else if (likely(isnormal(farg.d))) {
1222
#if USE_PRECISE_EMULATION
A
aurel32 已提交
1223 1224
        farg.d = float64_div(1.0, farg.d, &env->fp_status);
        farg.d = float64_to_float32(farg.d, &env->fp_status);
J
j_mayer 已提交
1225
#else
A
aurel32 已提交
1226
        farg.d = float32_div(1.0, farg.d, &env->fp_status);
J
j_mayer 已提交
1227
#endif
1228
    } else {
A
aurel32 已提交
1229 1230 1231 1232 1233 1234 1235 1236
        if (farg.ll == 0x8000000000000000ULL) {
            farg.ll = 0xFFF0000000000000ULL;
        } else if (farg.ll == 0x0000000000000000ULL) {
            farg.ll = 0x7FF0000000000000ULL;
        } else if (isnan(farg.d)) {
            farg.ll = 0x7FF8000000000000ULL;
        } else if (fpisneg(farg.d)) {
            farg.ll = 0x8000000000000000ULL;
1237
        } else {
A
aurel32 已提交
1238
            farg.ll = 0x0000000000000000ULL;
1239 1240
        }
    }
A
aurel32 已提交
1241
    return farg.ll;
1242 1243
}

A
aurel32 已提交
1244 1245
/* frsqrte  - frsqrte. */
uint64_t helper_frsqrte (uint64_t arg)
1246
{
A
aurel32 已提交
1247 1248
    CPU_DoubleU farg;
    farg.ll = arg;
1249

A
aurel32 已提交
1250
    if (unlikely(float64_is_signaling_nan(farg.d))) {
1251
        /* sNaN reciprocal square root */
A
aurel32 已提交
1252 1253
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
    } else if (unlikely(fpisneg(farg.d) && !iszero(farg.d))) {
1254
        /* Reciprocal square root of a negative nonzero number */
A
aurel32 已提交
1255 1256 1257 1258
        farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
    } else if (likely(isnormal(farg.d))) {
        farg.d = float64_sqrt(farg.d, &env->fp_status);
        farg.d = float32_div(1.0, farg.d, &env->fp_status);
1259
    } else {
A
aurel32 已提交
1260 1261 1262 1263 1264 1265 1266 1267
        if (farg.ll == 0x8000000000000000ULL) {
            farg.ll = 0xFFF0000000000000ULL;
        } else if (farg.ll == 0x0000000000000000ULL) {
            farg.ll = 0x7FF0000000000000ULL;
        } else if (isnan(farg.d)) {
            farg.ll |= 0x000FFFFFFFFFFFFFULL;
        } else if (fpisneg(farg.d)) {
            farg.ll = 0x7FF8000000000000ULL;
1268
        } else {
A
aurel32 已提交
1269
            farg.ll = 0x0000000000000000ULL;
1270 1271
        }
    }
A
aurel32 已提交
1272
    return farg.ll;
1273 1274
}

A
aurel32 已提交
1275 1276
/* fsel - fsel. */
uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1277
{
A
aurel32 已提交
1278 1279 1280 1281 1282 1283 1284 1285
    CPU_DoubleU farg1, farg2, farg3;

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

    if (!fpisneg(farg1.d) || iszero(farg1.d))
        return farg2.ll;
1286
    else
A
aurel32 已提交
1287
        return farg2.ll;
1288 1289
}

A
aurel32 已提交
1290
uint32_t helper_fcmpu (uint64_t arg1, uint64_t arg2)
1291
{
A
aurel32 已提交
1292
    CPU_DoubleU farg1, farg2;
1293
    uint32_t ret = 0;
A
aurel32 已提交
1294 1295
    farg1.ll = arg1;
    farg2.ll = arg2;
1296

A
aurel32 已提交
1297 1298
    if (unlikely(float64_is_signaling_nan(farg1.d) ||
                 float64_is_signaling_nan(farg2.d))) {
1299 1300 1301
        /* sNaN comparison */
        fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
    } else {
A
aurel32 已提交
1302
        if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1303
            ret = 0x08UL;
A
aurel32 已提交
1304
        } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1305
            ret = 0x04UL;
1306
        } else {
1307
            ret = 0x02UL;
1308
        }
1309
    }
1310
    env->fpscr &= ~(0x0F << FPSCR_FPRF);
1311 1312
    env->fpscr |= ret << FPSCR_FPRF;
    return ret;
1313 1314
}

A
aurel32 已提交
1315
uint32_t helper_fcmpo (uint64_t arg1, uint64_t arg2)
1316
{
A
aurel32 已提交
1317
    CPU_DoubleU farg1, farg2;
1318
    uint32_t ret = 0;
A
aurel32 已提交
1319 1320
    farg1.ll = arg1;
    farg2.ll = arg2;
1321

A
aurel32 已提交
1322 1323 1324 1325
    if (unlikely(float64_is_nan(farg1.d) ||
                 float64_is_nan(farg2.d))) {
        if (float64_is_signaling_nan(farg1.d) ||
            float64_is_signaling_nan(farg2.d)) {
1326 1327 1328 1329 1330 1331 1332 1333
            /* 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);
        }
    } else {
A
aurel32 已提交
1334
        if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1335
            ret = 0x08UL;
A
aurel32 已提交
1336
        } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1337
            ret = 0x04UL;
1338
        } else {
1339
            ret = 0x02UL;
1340
        }
1341
    }
1342
    env->fpscr &= ~(0x0F << FPSCR_FPRF);
1343 1344
    env->fpscr |= ret << FPSCR_FPRF;
    return ret;
1345 1346
}

1347
#if !defined (CONFIG_USER_ONLY)
J
j_mayer 已提交
1348
void cpu_dump_rfi (target_ulong RA, target_ulong msr);
1349

A
aurel32 已提交
1350
void do_store_msr (void)
1351
{
A
aurel32 已提交
1352 1353
    T0 = hreg_store_msr(env, T0, 0);
    if (T0 != 0) {
1354
        env->interrupt_request |= CPU_INTERRUPT_EXITTB;
1355
        raise_exception(env, T0);
1356 1357 1358 1359 1360
    }
}

static always_inline void __do_rfi (target_ulong nip, target_ulong msr,
                                    target_ulong msrm, int keep_msrh)
1361
{
J
j_mayer 已提交
1362
#if defined(TARGET_PPC64)
1363 1364 1365
    if (msr & (1ULL << MSR_SF)) {
        nip = (uint64_t)nip;
        msr &= (uint64_t)msrm;
1366
    } else {
1367 1368 1369 1370
        nip = (uint32_t)nip;
        msr = (uint32_t)(msr & msrm);
        if (keep_msrh)
            msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
1371
    }
J
j_mayer 已提交
1372
#else
1373 1374
    nip = (uint32_t)nip;
    msr &= (uint32_t)msrm;
J
j_mayer 已提交
1375
#endif
1376 1377
    /* XXX: beware: this is false if VLE is supported */
    env->nip = nip & ~((target_ulong)0x00000003);
1378
    hreg_store_msr(env, msr, 1);
1379
#if defined (DEBUG_OP)
1380
    cpu_dump_rfi(env->nip, env->msr);
1381
#endif
1382 1383 1384
    /* No need to raise an exception here,
     * as rfi is always the last insn of a TB
     */
1385
    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
1386
}
1387

1388 1389 1390 1391 1392 1393
void do_rfi (void)
{
    __do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
             ~((target_ulong)0xFFFF0000), 1);
}

1394
#if defined(TARGET_PPC64)
J
j_mayer 已提交
1395 1396
void do_rfid (void)
{
1397 1398
    __do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
             ~((target_ulong)0xFFFF0000), 0);
1399
}
1400

1401 1402
void do_hrfid (void)
{
1403 1404
    __do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
             ~((target_ulong)0xFFFF0000), 0);
1405 1406
}
#endif
1407
#endif
1408

1409
void do_tw (int flags)
1410
{
1411 1412 1413 1414
    if (!likely(!(((int32_t)T0 < (int32_t)T1 && (flags & 0x10)) ||
                  ((int32_t)T0 > (int32_t)T1 && (flags & 0x08)) ||
                  ((int32_t)T0 == (int32_t)T1 && (flags & 0x04)) ||
                  ((uint32_t)T0 < (uint32_t)T1 && (flags & 0x02)) ||
1415
                  ((uint32_t)T0 > (uint32_t)T1 && (flags & 0x01))))) {
1416
        raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
1417
    }
1418 1419
}

1420 1421 1422 1423 1424 1425 1426 1427
#if defined(TARGET_PPC64)
void do_td (int flags)
{
    if (!likely(!(((int64_t)T0 < (int64_t)T1 && (flags & 0x10)) ||
                  ((int64_t)T0 > (int64_t)T1 && (flags & 0x08)) ||
                  ((int64_t)T0 == (int64_t)T1 && (flags & 0x04)) ||
                  ((uint64_t)T0 < (uint64_t)T1 && (flags & 0x02)) ||
                  ((uint64_t)T0 > (uint64_t)T1 && (flags & 0x01)))))
1428
        raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
1429 1430 1431
}
#endif

1432
/*****************************************************************************/
1433 1434
/* PowerPC 601 specific instructions (POWER bridge) */
void do_POWER_abso (void)
1435
{
J
j_mayer 已提交
1436
    if ((int32_t)T0 == INT32_MIN) {
1437
        T0 = INT32_MAX;
A
aurel32 已提交
1438
        env->xer |= (1 << XER_OV) | (1 << XER_SO);
J
j_mayer 已提交
1439
    } else if ((int32_t)T0 < 0) {
1440
        T0 = -T0;
A
aurel32 已提交
1441
        env->xer &= ~(1 << XER_OV);
J
j_mayer 已提交
1442
    } else {
A
aurel32 已提交
1443
        env->xer &= ~(1 << XER_OV);
1444
    }
1445 1446
}

1447
void do_POWER_clcs (void)
1448
{
1449 1450 1451
    switch (T0) {
    case 0x0CUL:
        /* Instruction cache line size */
1452
        T0 = env->icache_line_size;
1453 1454 1455
        break;
    case 0x0DUL:
        /* Data cache line size */
1456
        T0 = env->dcache_line_size;
1457 1458 1459
        break;
    case 0x0EUL:
        /* Minimum cache line size */
1460 1461
        T0 = env->icache_line_size < env->dcache_line_size ?
            env->icache_line_size : env->dcache_line_size;
1462 1463 1464
        break;
    case 0x0FUL:
        /* Maximum cache line size */
1465 1466
        T0 = env->icache_line_size > env->dcache_line_size ?
            env->icache_line_size : env->dcache_line_size;
1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477
        break;
    default:
        /* Undefined */
        break;
    }
}

void do_POWER_div (void)
{
    uint64_t tmp;

1478 1479 1480
    if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
        (int32_t)T1 == 0) {
        T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
1481 1482 1483 1484
        env->spr[SPR_MQ] = 0;
    } else {
        tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ];
        env->spr[SPR_MQ] = tmp % T1;
1485
        T0 = tmp / (int32_t)T1;
1486 1487 1488 1489 1490 1491 1492
    }
}

void do_POWER_divo (void)
{
    int64_t tmp;

1493 1494 1495
    if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
        (int32_t)T1 == 0) {
        T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
1496
        env->spr[SPR_MQ] = 0;
A
aurel32 已提交
1497
        env->xer |= (1 << XER_OV) | (1 << XER_SO);
1498 1499 1500
    } else {
        tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ];
        env->spr[SPR_MQ] = tmp % T1;
1501
        tmp /= (int32_t)T1;
1502
        if (tmp > (int64_t)INT32_MAX || tmp < (int64_t)INT32_MIN) {
A
aurel32 已提交
1503
            env->xer |= (1 << XER_OV) | (1 << XER_SO);
1504
        } else {
A
aurel32 已提交
1505
            env->xer &= ~(1 << XER_OV);
1506 1507 1508 1509 1510 1511 1512
        }
        T0 = tmp;
    }
}

void do_POWER_divs (void)
{
1513 1514 1515
    if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
        (int32_t)T1 == 0) {
        T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
1516 1517 1518
        env->spr[SPR_MQ] = 0;
    } else {
        env->spr[SPR_MQ] = T0 % T1;
1519
        T0 = (int32_t)T0 / (int32_t)T1;
1520 1521 1522 1523 1524
    }
}

void do_POWER_divso (void)
{
1525 1526 1527
    if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
        (int32_t)T1 == 0) {
        T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
1528
        env->spr[SPR_MQ] = 0;
A
aurel32 已提交
1529
        env->xer |= (1 << XER_OV) | (1 << XER_SO);
1530
    } else {
1531 1532
        T0 = (int32_t)T0 / (int32_t)T1;
        env->spr[SPR_MQ] = (int32_t)T0 % (int32_t)T1;
A
aurel32 已提交
1533
        env->xer &= ~(1 << XER_OV);
1534 1535 1536 1537 1538
    }
}

void do_POWER_dozo (void)
{
1539
    if ((int32_t)T1 > (int32_t)T0) {
1540 1541
        T2 = T0;
        T0 = T1 - T0;
1542 1543
        if (((uint32_t)(~T2) ^ (uint32_t)T1 ^ UINT32_MAX) &
            ((uint32_t)(~T2) ^ (uint32_t)T0) & (1UL << 31)) {
A
aurel32 已提交
1544
            env->xer |= (1 << XER_OV) | (1 << XER_SO);
1545
        } else {
A
aurel32 已提交
1546
            env->xer &= ~(1 << XER_OV);
1547 1548 1549
        }
    } else {
        T0 = 0;
A
aurel32 已提交
1550
        env->xer &= ~(1 << XER_OV);
1551 1552 1553 1554 1555 1556 1557
    }
}

void do_POWER_maskg (void)
{
    uint32_t ret;

1558
    if ((uint32_t)T0 == (uint32_t)(T1 + 1)) {
1559
        ret = UINT32_MAX;
1560
    } else {
1561 1562
        ret = (UINT32_MAX >> ((uint32_t)T0)) ^
            ((UINT32_MAX >> ((uint32_t)T1)) >> 1);
1563
        if ((uint32_t)T0 > (uint32_t)T1)
1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576
            ret = ~ret;
    }
    T0 = ret;
}

void do_POWER_mulo (void)
{
    uint64_t tmp;

    tmp = (uint64_t)T0 * (uint64_t)T1;
    env->spr[SPR_MQ] = tmp >> 32;
    T0 = tmp;
    if (tmp >> 32 != ((uint64_t)T0 >> 16) * ((uint64_t)T1 >> 16)) {
A
aurel32 已提交
1577
        env->xer |= (1 << XER_OV) | (1 << XER_SO);
1578
    } else {
A
aurel32 已提交
1579
        env->xer &= ~(1 << XER_OV);
1580 1581 1582 1583 1584 1585 1586
    }
}

#if !defined (CONFIG_USER_ONLY)
void do_POWER_rac (void)
{
    mmu_ctx_t ctx;
J
j_mayer 已提交
1587
    int nb_BATs;
1588 1589 1590 1591

    /* We don't have to generate many instances of this instruction,
     * as rac is supervisor only.
     */
J
j_mayer 已提交
1592 1593 1594 1595
    /* XXX: FIX THIS: Pretend we have no BAT */
    nb_BATs = env->nb_BATs;
    env->nb_BATs = 0;
    if (get_physical_address(env, &ctx, T0, 0, ACCESS_INT) == 0)
1596
        T0 = ctx.raddr;
J
j_mayer 已提交
1597
    env->nb_BATs = nb_BATs;
1598 1599 1600 1601
}

void do_POWER_rfsvc (void)
{
1602
    __do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
1603 1604
}

1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621
void do_store_hid0_601 (void)
{
    uint32_t hid0;

    hid0 = env->spr[SPR_HID0];
    if ((T0 ^ hid0) & 0x00000008) {
        /* Change current endianness */
        env->hflags &= ~(1 << MSR_LE);
        env->hflags_nmsr &= ~(1 << MSR_LE);
        env->hflags_nmsr |= (1 << MSR_LE) & (((T0 >> 3) & 1) << MSR_LE);
        env->hflags |= env->hflags_nmsr;
        if (loglevel != 0) {
            fprintf(logfile, "%s: set endianness to %c => " ADDRX "\n",
                    __func__, T0 & 0x8 ? 'l' : 'b', env->hflags);
        }
    }
    env->spr[SPR_HID0] = T0;
1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632
}
#endif

/*****************************************************************************/
/* 602 specific instructions */
/* mfrom is the most crazy instruction ever seen, imho ! */
/* Real implementation uses a ROM table. Do the same */
#define USE_MFROM_ROM_TABLE
void do_op_602_mfrom (void)
{
    if (likely(T0 < 602)) {
1633
#if defined(USE_MFROM_ROM_TABLE)
1634 1635
#include "mfrom_table.c"
        T0 = mfrom_ROM_table[T0];
1636
#else
1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650
        double d;
        /* Extremly decomposed:
         *                    -T0 / 256
         * T0 = 256 * log10(10          + 1.0) + 0.5
         */
        d = T0;
        d = float64_div(d, 256, &env->fp_status);
        d = float64_chs(d);
        d = exp10(d); // XXX: use float emulation function
        d = float64_add(d, 1.0, &env->fp_status);
        d = log10(d); // XXX: use float emulation function
        d = float64_mul(d, 256, &env->fp_status);
        d = float64_add(d, 0.5, &env->fp_status);
        T0 = float64_round_to_int(d, &env->fp_status);
1651
#endif
1652 1653 1654 1655 1656 1657 1658 1659
    } else {
        T0 = 0;
    }
}

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

1660 1661 1662 1663 1664 1665 1666 1667 1668
/* XXX: to be improved to check access rights when in user-mode */
void do_load_dcr (void)
{
    target_ulong val;

    if (unlikely(env->dcr_env == NULL)) {
        if (loglevel != 0) {
            fprintf(logfile, "No DCR environment\n");
        }
1669 1670
        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
                            POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
1671 1672 1673 1674
    } else if (unlikely(ppc_dcr_read(env->dcr_env, T0, &val) != 0)) {
        if (loglevel != 0) {
            fprintf(logfile, "DCR read error %d %03x\n", (int)T0, (int)T0);
        }
1675 1676
        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
                            POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687
    } else {
        T0 = val;
    }
}

void do_store_dcr (void)
{
    if (unlikely(env->dcr_env == NULL)) {
        if (loglevel != 0) {
            fprintf(logfile, "No DCR environment\n");
        }
1688 1689
        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
                            POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
1690 1691 1692 1693
    } else if (unlikely(ppc_dcr_write(env->dcr_env, T0, T1) != 0)) {
        if (loglevel != 0) {
            fprintf(logfile, "DCR write error %d %03x\n", (int)T0, (int)T0);
        }
1694 1695
        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
                            POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1696 1697 1698
    }
}

1699
#if !defined(CONFIG_USER_ONLY)
1700
void do_40x_rfci (void)
1701
{
1702 1703
    __do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
             ~((target_ulong)0xFFFF0000), 0);
1704 1705 1706 1707
}

void do_rfci (void)
{
1708 1709
    __do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
             ~((target_ulong)0x3FFF0000), 0);
1710 1711 1712 1713
}

void do_rfdi (void)
{
1714 1715
    __do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
             ~((target_ulong)0x3FFF0000), 0);
1716 1717 1718 1719
}

void do_rfmci (void)
{
1720 1721
    __do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
             ~((target_ulong)0x3FFF0000), 0);
1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757
}

void do_load_403_pb (int num)
{
    T0 = env->pb[num];
}

void do_store_403_pb (int num)
{
    if (likely(env->pb[num] != T0)) {
        env->pb[num] = T0;
        /* Should be optimized */
        tlb_flush(env, 1);
    }
}
#endif

/* 440 specific */
void do_440_dlmzb (void)
{
    target_ulong mask;
    int i;

    i = 1;
    for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
        if ((T0 & mask) == 0)
            goto done;
        i++;
    }
    for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
        if ((T1 & mask) == 0)
            break;
        i++;
    }
 done:
    T0 = i;
1758 1759
}

1760 1761 1762 1763 1764 1765 1766
/* 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,
};

1767
static always_inline uint8_t byte_reverse (uint8_t val)
1768 1769 1770 1771
{
    return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
}

1772
static always_inline uint32_t word_reverse (uint32_t val)
1773 1774 1775 1776 1777
{
    return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
        (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
}

1778
#define MASKBITS 16 // Random value - to be fixed (implementation dependant)
1779
target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
1780 1781 1782
{
    uint32_t a, b, d, mask;

1783
    mask = UINT32_MAX >> (32 - MASKBITS);
1784 1785
    a = arg1 & mask;
    b = arg2 & mask;
1786
    d = word_reverse(1 + word_reverse(a | ~b));
1787
    return (arg1 & ~mask) | (d & b);
1788 1789
}

1790
uint32_t helper_cntlsw32 (uint32_t val)
1791 1792
{
    if (val & 0x80000000)
1793
        return clz32(~val);
1794
    else
1795
        return clz32(val);
1796 1797
}

1798
uint32_t helper_cntlzw32 (uint32_t val)
1799
{
1800
    return clz32(val);
1801 1802
}

1803 1804 1805 1806 1807
#define DO_SPE_OP1(name)                                                      \
void do_ev##name (void)                                                       \
{                                                                             \
    T0_64 = ((uint64_t)_do_e##name(T0_64 >> 32) << 32) |                      \
        (uint64_t)_do_e##name(T0_64);                                         \
1808 1809
}

1810 1811 1812 1813 1814
#define DO_SPE_OP2(name)                                                      \
void do_ev##name (void)                                                       \
{                                                                             \
    T0_64 = ((uint64_t)_do_e##name(T0_64 >> 32, T1_64 >> 32) << 32) |         \
        (uint64_t)_do_e##name(T0_64, T1_64);                                  \
1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825
}

/* Fixed-point vector comparisons */
#define DO_SPE_CMP(name)                                                      \
void do_ev##name (void)                                                       \
{                                                                             \
    T0 = _do_evcmp_merge((uint64_t)_do_e##name(T0_64 >> 32,                   \
                                               T1_64 >> 32) << 32,            \
                         _do_e##name(T0_64, T1_64));                          \
}

1826
static always_inline uint32_t _do_evcmp_merge (int t0, int t1)
1827 1828 1829 1830 1831
{
    return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
}

/* Single precision floating-point conversions from/to integer */
1832
static always_inline uint32_t _do_efscfsi (int32_t val)
1833
{
A
aurel32 已提交
1834
    CPU_FloatU u;
1835 1836 1837

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

A
aurel32 已提交
1838
    return u.l;
1839 1840
}

1841
static always_inline uint32_t _do_efscfui (uint32_t val)
1842
{
A
aurel32 已提交
1843
    CPU_FloatU u;
1844 1845 1846

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

A
aurel32 已提交
1847
    return u.l;
1848 1849
}

1850
static always_inline int32_t _do_efsctsi (uint32_t val)
1851
{
A
aurel32 已提交
1852
    CPU_FloatU u;
1853

A
aurel32 已提交
1854
    u.l = val;
1855 1856 1857 1858 1859 1860 1861
    /* NaN are not treated the same way IEEE 754 does */
    if (unlikely(isnan(u.f)))
        return 0;

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

1862
static always_inline uint32_t _do_efsctui (uint32_t val)
1863
{
A
aurel32 已提交
1864
    CPU_FloatU u;
1865

A
aurel32 已提交
1866
    u.l = val;
1867 1868 1869 1870 1871 1872 1873
    /* NaN are not treated the same way IEEE 754 does */
    if (unlikely(isnan(u.f)))
        return 0;

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

1874
static always_inline int32_t _do_efsctsiz (uint32_t val)
1875
{
A
aurel32 已提交
1876
    CPU_FloatU u;
1877

A
aurel32 已提交
1878
    u.l = val;
1879 1880 1881 1882 1883 1884 1885
    /* NaN are not treated the same way IEEE 754 does */
    if (unlikely(isnan(u.f)))
        return 0;

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

1886
static always_inline uint32_t _do_efsctuiz (uint32_t val)
1887
{
A
aurel32 已提交
1888
    CPU_FloatU u;
1889

A
aurel32 已提交
1890
    u.l = val;
1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928
    /* NaN are not treated the same way IEEE 754 does */
    if (unlikely(isnan(u.f)))
        return 0;

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

void do_efscfsi (void)
{
    T0_64 = _do_efscfsi(T0_64);
}

void do_efscfui (void)
{
    T0_64 = _do_efscfui(T0_64);
}

void do_efsctsi (void)
{
    T0_64 = _do_efsctsi(T0_64);
}

void do_efsctui (void)
{
    T0_64 = _do_efsctui(T0_64);
}

void do_efsctsiz (void)
{
    T0_64 = _do_efsctsiz(T0_64);
}

void do_efsctuiz (void)
{
    T0_64 = _do_efsctuiz(T0_64);
}

/* Single precision floating-point conversion to/from fractional */
1929
static always_inline uint32_t _do_efscfsf (uint32_t val)
1930
{
A
aurel32 已提交
1931
    CPU_FloatU u;
1932 1933 1934 1935 1936 1937
    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 已提交
1938
    return u.l;
1939 1940
}

1941
static always_inline uint32_t _do_efscfuf (uint32_t val)
1942
{
A
aurel32 已提交
1943
    CPU_FloatU u;
1944 1945 1946 1947 1948 1949
    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 已提交
1950
    return u.l;
1951 1952
}

1953
static always_inline int32_t _do_efsctsf (uint32_t val)
1954
{
A
aurel32 已提交
1955
    CPU_FloatU u;
1956 1957
    float32 tmp;

A
aurel32 已提交
1958
    u.l = val;
1959 1960 1961 1962 1963 1964 1965 1966 1967
    /* NaN are not treated the same way IEEE 754 does */
    if (unlikely(isnan(u.f)))
        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);
}

1968
static always_inline uint32_t _do_efsctuf (uint32_t val)
1969
{
A
aurel32 已提交
1970
    CPU_FloatU u;
1971 1972
    float32 tmp;

A
aurel32 已提交
1973
    u.l = val;
1974 1975 1976 1977 1978 1979 1980 1981 1982
    /* NaN are not treated the same way IEEE 754 does */
    if (unlikely(isnan(u.f)))
        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);
}

1983
static always_inline int32_t _do_efsctsfz (uint32_t val)
1984
{
A
aurel32 已提交
1985
    CPU_FloatU u;
1986 1987
    float32 tmp;

A
aurel32 已提交
1988
    u.l = val;
1989 1990 1991 1992 1993 1994 1995 1996 1997
    /* NaN are not treated the same way IEEE 754 does */
    if (unlikely(isnan(u.f)))
        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_round_to_zero(u.f, &env->spe_status);
}

1998
static always_inline uint32_t _do_efsctufz (uint32_t val)
1999
{
A
aurel32 已提交
2000
    CPU_FloatU u;
2001 2002
    float32 tmp;

A
aurel32 已提交
2003
    u.l = val;
2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043
    /* NaN are not treated the same way IEEE 754 does */
    if (unlikely(isnan(u.f)))
        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_round_to_zero(u.f, &env->spe_status);
}

void do_efscfsf (void)
{
    T0_64 = _do_efscfsf(T0_64);
}

void do_efscfuf (void)
{
    T0_64 = _do_efscfuf(T0_64);
}

void do_efsctsf (void)
{
    T0_64 = _do_efsctsf(T0_64);
}

void do_efsctuf (void)
{
    T0_64 = _do_efsctuf(T0_64);
}

void do_efsctsfz (void)
{
    T0_64 = _do_efsctsfz(T0_64);
}

void do_efsctufz (void)
{
    T0_64 = _do_efsctufz(T0_64);
}

/* Double precision floating point helpers */
2044
static always_inline int _do_efdcmplt (uint64_t op1, uint64_t op2)
2045 2046 2047 2048 2049
{
    /* XXX: TODO: test special values (NaN, infinites, ...) */
    return _do_efdtstlt(op1, op2);
}

2050
static always_inline int _do_efdcmpgt (uint64_t op1, uint64_t op2)
2051 2052 2053 2054 2055
{
    /* XXX: TODO: test special values (NaN, infinites, ...) */
    return _do_efdtstgt(op1, op2);
}

2056
static always_inline int _do_efdcmpeq (uint64_t op1, uint64_t op2)
2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077
{
    /* XXX: TODO: test special values (NaN, infinites, ...) */
    return _do_efdtsteq(op1, op2);
}

void do_efdcmplt (void)
{
    T0 = _do_efdcmplt(T0_64, T1_64);
}

void do_efdcmpgt (void)
{
    T0 = _do_efdcmpgt(T0_64, T1_64);
}

void do_efdcmpeq (void)
{
    T0 = _do_efdcmpeq(T0_64, T1_64);
}

/* Double precision floating-point conversion to/from integer */
2078
static always_inline uint64_t _do_efdcfsi (int64_t val)
2079
{
A
aurel32 已提交
2080
    CPU_DoubleU u;
2081

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

A
aurel32 已提交
2084
    return u.ll;
2085 2086
}

2087
static always_inline uint64_t _do_efdcfui (uint64_t val)
2088
{
A
aurel32 已提交
2089
    CPU_DoubleU u;
2090

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

A
aurel32 已提交
2093
    return u.ll;
2094 2095
}

2096
static always_inline int64_t _do_efdctsi (uint64_t val)
2097
{
A
aurel32 已提交
2098
    CPU_DoubleU u;
2099

A
aurel32 已提交
2100
    u.ll = val;
2101
    /* NaN are not treated the same way IEEE 754 does */
A
aurel32 已提交
2102
    if (unlikely(isnan(u.d)))
2103 2104
        return 0;

A
aurel32 已提交
2105
    return float64_to_int64(u.d, &env->spe_status);
2106 2107
}

2108
static always_inline uint64_t _do_efdctui (uint64_t val)
2109
{
A
aurel32 已提交
2110
    CPU_DoubleU u;
2111

A
aurel32 已提交
2112
    u.ll = val;
2113
    /* NaN are not treated the same way IEEE 754 does */
A
aurel32 已提交
2114
    if (unlikely(isnan(u.d)))
2115 2116
        return 0;

A
aurel32 已提交
2117
    return float64_to_uint64(u.d, &env->spe_status);
2118 2119
}

2120
static always_inline int64_t _do_efdctsiz (uint64_t val)
2121
{
A
aurel32 已提交
2122
    CPU_DoubleU u;
2123

A
aurel32 已提交
2124
    u.ll = val;
2125
    /* NaN are not treated the same way IEEE 754 does */
A
aurel32 已提交
2126
    if (unlikely(isnan(u.d)))
2127 2128
        return 0;

A
aurel32 已提交
2129
    return float64_to_int64_round_to_zero(u.d, &env->spe_status);
2130 2131
}

2132
static always_inline uint64_t _do_efdctuiz (uint64_t val)
2133
{
A
aurel32 已提交
2134
    CPU_DoubleU u;
2135

A
aurel32 已提交
2136
    u.ll = val;
2137
    /* NaN are not treated the same way IEEE 754 does */
A
aurel32 已提交
2138
    if (unlikely(isnan(u.d)))
2139 2140
        return 0;

A
aurel32 已提交
2141
    return float64_to_uint64_round_to_zero(u.d, &env->spe_status);
2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174
}

void do_efdcfsi (void)
{
    T0_64 = _do_efdcfsi(T0_64);
}

void do_efdcfui (void)
{
    T0_64 = _do_efdcfui(T0_64);
}

void do_efdctsi (void)
{
    T0_64 = _do_efdctsi(T0_64);
}

void do_efdctui (void)
{
    T0_64 = _do_efdctui(T0_64);
}

void do_efdctsiz (void)
{
    T0_64 = _do_efdctsiz(T0_64);
}

void do_efdctuiz (void)
{
    T0_64 = _do_efdctuiz(T0_64);
}

/* Double precision floating-point conversion to/from fractional */
2175
static always_inline uint64_t _do_efdcfsf (int64_t val)
2176
{
A
aurel32 已提交
2177
    CPU_DoubleU u;
2178 2179
    float64 tmp;

A
aurel32 已提交
2180
    u.d = int32_to_float64(val, &env->spe_status);
2181
    tmp = int64_to_float64(1ULL << 32, &env->spe_status);
A
aurel32 已提交
2182
    u.d = float64_div(u.d, tmp, &env->spe_status);
2183

A
aurel32 已提交
2184
    return u.ll;
2185 2186
}

2187
static always_inline uint64_t _do_efdcfuf (uint64_t val)
2188
{
A
aurel32 已提交
2189
    CPU_DoubleU u;
2190 2191
    float64 tmp;

A
aurel32 已提交
2192
    u.d = uint32_to_float64(val, &env->spe_status);
2193
    tmp = int64_to_float64(1ULL << 32, &env->spe_status);
A
aurel32 已提交
2194
    u.d = float64_div(u.d, tmp, &env->spe_status);
2195

A
aurel32 已提交
2196
    return u.ll;
2197 2198
}

2199
static always_inline int64_t _do_efdctsf (uint64_t val)
2200
{
A
aurel32 已提交
2201
    CPU_DoubleU u;
2202 2203
    float64 tmp;

A
aurel32 已提交
2204
    u.ll = val;
2205
    /* NaN are not treated the same way IEEE 754 does */
A
aurel32 已提交
2206
    if (unlikely(isnan(u.d)))
2207 2208
        return 0;
    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
A
aurel32 已提交
2209
    u.d = float64_mul(u.d, tmp, &env->spe_status);
2210

A
aurel32 已提交
2211
    return float64_to_int32(u.d, &env->spe_status);
2212 2213
}

2214
static always_inline uint64_t _do_efdctuf (uint64_t val)
2215
{
A
aurel32 已提交
2216
    CPU_DoubleU u;
2217 2218
    float64 tmp;

A
aurel32 已提交
2219
    u.ll = val;
2220
    /* NaN are not treated the same way IEEE 754 does */
A
aurel32 已提交
2221
    if (unlikely(isnan(u.d)))
2222 2223
        return 0;
    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
A
aurel32 已提交
2224
    u.d = float64_mul(u.d, tmp, &env->spe_status);
2225

A
aurel32 已提交
2226
    return float64_to_uint32(u.d, &env->spe_status);
2227 2228
}

2229
static always_inline int64_t _do_efdctsfz (uint64_t val)
2230
{
A
aurel32 已提交
2231
    CPU_DoubleU u;
2232 2233
    float64 tmp;

A
aurel32 已提交
2234
    u.ll = val;
2235
    /* NaN are not treated the same way IEEE 754 does */
A
aurel32 已提交
2236
    if (unlikely(isnan(u.d)))
2237 2238
        return 0;
    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
A
aurel32 已提交
2239
    u.d = float64_mul(u.d, tmp, &env->spe_status);
2240

A
aurel32 已提交
2241
    return float64_to_int32_round_to_zero(u.d, &env->spe_status);
2242 2243
}

2244
static always_inline uint64_t _do_efdctufz (uint64_t val)
2245
{
A
aurel32 已提交
2246
    CPU_DoubleU u;
2247 2248
    float64 tmp;

A
aurel32 已提交
2249
    u.ll = val;
2250
    /* NaN are not treated the same way IEEE 754 does */
A
aurel32 已提交
2251
    if (unlikely(isnan(u.d)))
2252 2253
        return 0;
    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
A
aurel32 已提交
2254
    u.d = float64_mul(u.d, tmp, &env->spe_status);
2255

A
aurel32 已提交
2256
    return float64_to_uint32_round_to_zero(u.d, &env->spe_status);
2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289
}

void do_efdcfsf (void)
{
    T0_64 = _do_efdcfsf(T0_64);
}

void do_efdcfuf (void)
{
    T0_64 = _do_efdcfuf(T0_64);
}

void do_efdctsf (void)
{
    T0_64 = _do_efdctsf(T0_64);
}

void do_efdctuf (void)
{
    T0_64 = _do_efdctuf(T0_64);
}

void do_efdctsfz (void)
{
    T0_64 = _do_efdctsfz(T0_64);
}

void do_efdctufz (void)
{
    T0_64 = _do_efdctufz(T0_64);
}

/* Floating point conversion between single and double precision */
2290
static always_inline uint32_t _do_efscfd (uint64_t val)
2291
{
A
aurel32 已提交
2292 2293
    CPU_DoubleU u1;
    CPU_FloatU u2;
2294

A
aurel32 已提交
2295 2296
    u1.ll = val;
    u2.f = float64_to_float32(u1.d, &env->spe_status);
2297

A
aurel32 已提交
2298
    return u2.l;
2299 2300
}

2301
static always_inline uint64_t _do_efdcfs (uint32_t val)
2302
{
A
aurel32 已提交
2303 2304
    CPU_DoubleU u2;
    CPU_FloatU u1;
2305

A
aurel32 已提交
2306 2307
    u1.l = val;
    u2.d = float32_to_float64(u1.f, &env->spe_status);
2308

A
aurel32 已提交
2309
    return u2.ll;
2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338
}

void do_efscfd (void)
{
    T0_64 = _do_efscfd(T0_64);
}

void do_efdcfs (void)
{
    T0_64 = _do_efdcfs(T0_64);
}

/* Single precision fixed-point vector arithmetic */
/* evfsabs */
DO_SPE_OP1(fsabs);
/* evfsnabs */
DO_SPE_OP1(fsnabs);
/* evfsneg */
DO_SPE_OP1(fsneg);
/* evfsadd */
DO_SPE_OP2(fsadd);
/* evfssub */
DO_SPE_OP2(fssub);
/* evfsmul */
DO_SPE_OP2(fsmul);
/* evfsdiv */
DO_SPE_OP2(fsdiv);

/* Single-precision floating-point comparisons */
2339
static always_inline int _do_efscmplt (uint32_t op1, uint32_t op2)
2340 2341 2342 2343 2344
{
    /* XXX: TODO: test special values (NaN, infinites, ...) */
    return _do_efststlt(op1, op2);
}

2345
static always_inline int _do_efscmpgt (uint32_t op1, uint32_t op2)
2346 2347 2348 2349 2350
{
    /* XXX: TODO: test special values (NaN, infinites, ...) */
    return _do_efststgt(op1, op2);
}

2351
static always_inline int _do_efscmpeq (uint32_t op1, uint32_t op2)
2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407
{
    /* XXX: TODO: test special values (NaN, infinites, ...) */
    return _do_efststeq(op1, op2);
}

void do_efscmplt (void)
{
    T0 = _do_efscmplt(T0_64, T1_64);
}

void do_efscmpgt (void)
{
    T0 = _do_efscmpgt(T0_64, T1_64);
}

void do_efscmpeq (void)
{
    T0 = _do_efscmpeq(T0_64, T1_64);
}

/* Single-precision floating-point vector comparisons */
/* evfscmplt */
DO_SPE_CMP(fscmplt);
/* evfscmpgt */
DO_SPE_CMP(fscmpgt);
/* evfscmpeq */
DO_SPE_CMP(fscmpeq);
/* evfststlt */
DO_SPE_CMP(fststlt);
/* evfststgt */
DO_SPE_CMP(fststgt);
/* evfststeq */
DO_SPE_CMP(fststeq);

/* Single-precision floating-point vector conversions */
/* evfscfsi */
DO_SPE_OP1(fscfsi);
/* evfscfui */
DO_SPE_OP1(fscfui);
/* evfscfuf */
DO_SPE_OP1(fscfuf);
/* evfscfsf */
DO_SPE_OP1(fscfsf);
/* evfsctsi */
DO_SPE_OP1(fsctsi);
/* evfsctui */
DO_SPE_OP1(fsctui);
/* evfsctsiz */
DO_SPE_OP1(fsctsiz);
/* evfsctuiz */
DO_SPE_OP1(fsctuiz);
/* evfsctsf */
DO_SPE_OP1(fsctsf);
/* evfsctuf */
DO_SPE_OP1(fsctuf);

2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429
/*****************************************************************************/
/* 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 */
2430
void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
2431 2432 2433
{
    TranslationBlock *tb;
    CPUState *saved_env;
B
bellard 已提交
2434
    unsigned long pc;
2435 2436 2437 2438 2439 2440
    int ret;

    /* XXX: hack to restore env in all cases, even if not called from
       generated code */
    saved_env = env;
    env = cpu_single_env;
2441
    ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
2442
    if (unlikely(ret != 0)) {
2443 2444
        if (likely(retaddr)) {
            /* now we have a real cpu fault */
B
bellard 已提交
2445
            pc = (unsigned long)retaddr;
2446 2447 2448 2449 2450
            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);
2451
            }
2452
        }
2453
        raise_exception_err(env, env->exception_index, env->error_code);
2454 2455
    }
    env = saved_env;
2456 2457
}

2458 2459 2460 2461 2462 2463
/* Software driven TLBs management */
/* PowerPC 602/603 software TLB load instructions helpers */
void do_load_6xx_tlb (int is_code)
{
    target_ulong RPN, CMP, EPN;
    int way;
2464

2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475
    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) {
2476 2477 2478
        fprintf(logfile, "%s: EPN " TDX " " ADDRX " PTE0 " ADDRX
                " PTE1 " ADDRX " way %d\n",
                __func__, T0, EPN, CMP, RPN, way);
2479 2480 2481
    }
#endif
    /* Store this TLB */
2482 2483
    ppc6xx_tlb_store(env, (uint32_t)(T0 & TARGET_PAGE_MASK),
                     way, is_code, CMP, RPN);
2484 2485
}

2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496
void do_load_74xx_tlb (int is_code)
{
    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) {
2497 2498 2499
        fprintf(logfile, "%s: EPN " TDX " " ADDRX " PTE0 " ADDRX
                " PTE1 " ADDRX " way %d\n",
                __func__, T0, EPN, CMP, RPN, way);
2500 2501 2502 2503 2504 2505 2506
    }
#endif
    /* Store this TLB */
    ppc6xx_tlb_store(env, (uint32_t)(T0 & TARGET_PAGE_MASK),
                     way, is_code, CMP, RPN);
}

J
j_mayer 已提交
2507
static always_inline target_ulong booke_tlb_to_page_size (int size)
J
j_mayer 已提交
2508 2509 2510 2511
{
    return 1024 << (2 * size);
}

J
j_mayer 已提交
2512
static always_inline int booke_page_size_to_tlb (target_ulong page_size)
J
j_mayer 已提交
2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574
{
    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;
}

2575 2576 2577
/* Helpers for 4xx TLB management */
void do_4xx_tlbre_lo (void)
{
J
j_mayer 已提交
2578 2579
    ppcemb_tlb_t *tlb;
    int size;
2580 2581

    T0 &= 0x3F;
J
j_mayer 已提交
2582 2583 2584 2585 2586 2587 2588 2589 2590
    tlb = &env->tlb[T0].tlbe;
    T0 = tlb->EPN;
    if (tlb->prot & PAGE_VALID)
        T0 |= 0x400;
    size = booke_page_size_to_tlb(tlb->size);
    if (size < 0 || size > 0x7)
        size = 1;
    T0 |= size << 7;
    env->spr[SPR_40x_PID] = tlb->PID;
2591 2592 2593 2594
}

void do_4xx_tlbre_hi (void)
{
J
j_mayer 已提交
2595
    ppcemb_tlb_t *tlb;
2596 2597

    T0 &= 0x3F;
J
j_mayer 已提交
2598 2599 2600 2601 2602 2603
    tlb = &env->tlb[T0].tlbe;
    T0 = tlb->RPN;
    if (tlb->prot & PAGE_EXEC)
        T0 |= 0x200;
    if (tlb->prot & PAGE_WRITE)
        T0 |= 0x100;
2604 2605
}

2606
void do_4xx_tlbwe_hi (void)
2607
{
J
j_mayer 已提交
2608
    ppcemb_tlb_t *tlb;
2609 2610
    target_ulong page, end;

2611
#if defined (DEBUG_SOFTWARE_TLB)
J
j_mayer 已提交
2612
    if (loglevel != 0) {
2613
        fprintf(logfile, "%s T0 " TDX " T1 " TDX "\n", __func__, T0, T1);
2614 2615
    }
#endif
2616
    T0 &= 0x3F;
J
j_mayer 已提交
2617
    tlb = &env->tlb[T0].tlbe;
2618 2619 2620
    /* Invalidate previous TLB (if it's valid) */
    if (tlb->prot & PAGE_VALID) {
        end = tlb->EPN + tlb->size;
2621
#if defined (DEBUG_SOFTWARE_TLB)
J
j_mayer 已提交
2622
        if (loglevel != 0) {
2623 2624 2625 2626
            fprintf(logfile, "%s: invalidate old TLB %d start " ADDRX
                    " end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end);
        }
#endif
2627 2628 2629
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
            tlb_flush_page(env, page);
    }
J
j_mayer 已提交
2630
    tlb->size = booke_tlb_to_page_size((T1 >> 7) & 0x7);
2631 2632 2633 2634 2635
    /* 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
     */
    if ((T1 & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
J
j_mayer 已提交
2636 2637
        cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
                  "are not supported (%d)\n",
2638 2639
                  tlb->size, TARGET_PAGE_SIZE, (int)((T1 >> 7) & 0x7));
    }
2640
    tlb->EPN = T1 & ~(tlb->size - 1);
2641
    if (T1 & 0x40)
2642 2643 2644
        tlb->prot |= PAGE_VALID;
    else
        tlb->prot &= ~PAGE_VALID;
2645 2646 2647 2648
    if (T1 & 0x20) {
        /* XXX: TO BE FIXED */
        cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
    }
2649
    tlb->PID = env->spr[SPR_40x_PID]; /* PID */
J
j_mayer 已提交
2650
    tlb->attr = T1 & 0xFF;
2651
#if defined (DEBUG_SOFTWARE_TLB)
2652 2653
    if (loglevel != 0) {
        fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
2654
                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
2655
                (int)T0, tlb->RPN, tlb->EPN, tlb->size,
2656 2657 2658 2659 2660 2661
                tlb->prot & PAGE_READ ? 'r' : '-',
                tlb->prot & PAGE_WRITE ? 'w' : '-',
                tlb->prot & PAGE_EXEC ? 'x' : '-',
                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
    }
#endif
2662 2663 2664
    /* Invalidate new TLB (if valid) */
    if (tlb->prot & PAGE_VALID) {
        end = tlb->EPN + tlb->size;
2665
#if defined (DEBUG_SOFTWARE_TLB)
J
j_mayer 已提交
2666
        if (loglevel != 0) {
2667 2668 2669 2670
            fprintf(logfile, "%s: invalidate TLB %d start " ADDRX
                    " end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end);
        }
#endif
2671 2672 2673 2674 2675
        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
            tlb_flush_page(env, page);
    }
}

2676
void do_4xx_tlbwe_lo (void)
2677
{
J
j_mayer 已提交
2678
    ppcemb_tlb_t *tlb;
2679

2680
#if defined (DEBUG_SOFTWARE_TLB)
J
j_mayer 已提交
2681
    if (loglevel != 0) {
2682
        fprintf(logfile, "%s T0 " TDX " T1 " TDX "\n", __func__, T0, T1);
2683 2684
    }
#endif
2685
    T0 &= 0x3F;
J
j_mayer 已提交
2686
    tlb = &env->tlb[T0].tlbe;
2687 2688 2689 2690 2691 2692
    tlb->RPN = T1 & 0xFFFFFC00;
    tlb->prot = PAGE_READ;
    if (T1 & 0x200)
        tlb->prot |= PAGE_EXEC;
    if (T1 & 0x100)
        tlb->prot |= PAGE_WRITE;
2693
#if defined (DEBUG_SOFTWARE_TLB)
J
j_mayer 已提交
2694 2695
    if (loglevel != 0) {
        fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
2696
                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
2697
                (int)T0, tlb->RPN, tlb->EPN, tlb->size,
2698 2699 2700 2701 2702 2703
                tlb->prot & PAGE_READ ? 'r' : '-',
                tlb->prot & PAGE_WRITE ? 'w' : '-',
                tlb->prot & PAGE_EXEC ? 'x' : '-',
                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
    }
#endif
2704
}
2705

2706 2707
/* PowerPC 440 TLB management */
void do_440_tlbwe (int word)
2708 2709
{
    ppcemb_tlb_t *tlb;
2710
    target_ulong EPN, RPN, size;
2711 2712 2713 2714
    int do_flush_tlbs;

#if defined (DEBUG_SOFTWARE_TLB)
    if (loglevel != 0) {
2715
        fprintf(logfile, "%s word %d T0 " TDX " T1 " TDX "\n",
J
j_mayer 已提交
2716
                __func__, word, T0, T1);
2717 2718 2719 2720 2721
    }
#endif
    do_flush_tlbs = 0;
    T0 &= 0x3F;
    tlb = &env->tlb[T0].tlbe;
2722 2723 2724 2725 2726 2727
    switch (word) {
    default:
        /* Just here to please gcc */
    case 0:
        EPN = T1 & 0xFFFFFC00;
        if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
2728
            do_flush_tlbs = 1;
2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742
        tlb->EPN = EPN;
        size = booke_tlb_to_page_size((T1 >> 4) & 0xF);
        if ((tlb->prot & PAGE_VALID) && tlb->size < size)
            do_flush_tlbs = 1;
        tlb->size = size;
        tlb->attr &= ~0x1;
        tlb->attr |= (T1 >> 8) & 1;
        if (T1 & 0x200) {
            tlb->prot |= PAGE_VALID;
        } else {
            if (tlb->prot & PAGE_VALID) {
                tlb->prot &= ~PAGE_VALID;
                do_flush_tlbs = 1;
            }
2743
        }
2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769
        tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
        if (do_flush_tlbs)
            tlb_flush(env, 1);
        break;
    case 1:
        RPN = T1 & 0xFFFFFC0F;
        if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
            tlb_flush(env, 1);
        tlb->RPN = RPN;
        break;
    case 2:
        tlb->attr = (tlb->attr & 0x1) | (T1 & 0x0000FF00);
        tlb->prot = tlb->prot & PAGE_VALID;
        if (T1 & 0x1)
            tlb->prot |= PAGE_READ << 4;
        if (T1 & 0x2)
            tlb->prot |= PAGE_WRITE << 4;
        if (T1 & 0x4)
            tlb->prot |= PAGE_EXEC << 4;
        if (T1 & 0x8)
            tlb->prot |= PAGE_READ;
        if (T1 & 0x10)
            tlb->prot |= PAGE_WRITE;
        if (T1 & 0x20)
            tlb->prot |= PAGE_EXEC;
        break;
2770 2771 2772
    }
}

2773
void do_440_tlbre (int word)
2774 2775 2776 2777 2778 2779
{
    ppcemb_tlb_t *tlb;
    int size;

    T0 &= 0x3F;
    tlb = &env->tlb[T0].tlbe;
2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814
    switch (word) {
    default:
        /* Just here to please gcc */
    case 0:
        T0 = tlb->EPN;
        size = booke_page_size_to_tlb(tlb->size);
        if (size < 0 || size > 0xF)
            size = 1;
        T0 |= size << 4;
        if (tlb->attr & 0x1)
            T0 |= 0x100;
        if (tlb->prot & PAGE_VALID)
            T0 |= 0x200;
        env->spr[SPR_440_MMUCR] &= ~0x000000FF;
        env->spr[SPR_440_MMUCR] |= tlb->PID;
        break;
    case 1:
        T0 = tlb->RPN;
        break;
    case 2:
        T0 = tlb->attr & ~0x1;
        if (tlb->prot & (PAGE_READ << 4))
            T0 |= 0x1;
        if (tlb->prot & (PAGE_WRITE << 4))
            T0 |= 0x2;
        if (tlb->prot & (PAGE_EXEC << 4))
            T0 |= 0x4;
        if (tlb->prot & PAGE_READ)
            T0 |= 0x8;
        if (tlb->prot & PAGE_WRITE)
            T0 |= 0x10;
        if (tlb->prot & PAGE_EXEC)
            T0 |= 0x20;
        break;
    }
2815
}
2816
#endif /* !CONFIG_USER_ONLY */