|
|
1.1 ! root 1: /* ! 2: * PowerPC emulation helpers for qemu. ! 3: * ! 4: * Copyright (c) 2003-2005 Jocelyn Mayer ! 5: * ! 6: * This library is free software; you can redistribute it and/or ! 7: * modify it under the terms of the GNU Lesser General Public ! 8: * License as published by the Free Software Foundation; either ! 9: * version 2 of the License, or (at your option) any later version. ! 10: * ! 11: * This library is distributed in the hope that it will be useful, ! 12: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 14: * Lesser General Public License for more details. ! 15: * ! 16: * You should have received a copy of the GNU Lesser General Public ! 17: * License along with this library; if not, write to the Free Software ! 18: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ! 19: */ ! 20: #include <math.h> ! 21: #include "exec.h" ! 22: ! 23: #define MEMSUFFIX _raw ! 24: #include "op_helper_mem.h" ! 25: #if !defined(CONFIG_USER_ONLY) ! 26: #define MEMSUFFIX _user ! 27: #include "op_helper_mem.h" ! 28: #define MEMSUFFIX _kernel ! 29: #include "op_helper_mem.h" ! 30: #endif ! 31: ! 32: //#define DEBUG_OP ! 33: //#define DEBUG_EXCEPTIONS ! 34: //#define FLUSH_ALL_TLBS ! 35: ! 36: #define Ts0 (long)((target_long)T0) ! 37: #define Ts1 (long)((target_long)T1) ! 38: #define Ts2 (long)((target_long)T2) ! 39: ! 40: /*****************************************************************************/ ! 41: /* Exceptions processing helpers */ ! 42: void cpu_loop_exit(void) ! 43: { ! 44: longjmp(env->jmp_env, 1); ! 45: } ! 46: ! 47: void do_raise_exception_err (uint32_t exception, int error_code) ! 48: { ! 49: #if 0 ! 50: printf("Raise exception %3x code : %d\n", exception, error_code); ! 51: #endif ! 52: switch (exception) { ! 53: case EXCP_PROGRAM: ! 54: if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0) ! 55: return; ! 56: break; ! 57: default: ! 58: break; ! 59: } ! 60: env->exception_index = exception; ! 61: env->error_code = error_code; ! 62: cpu_loop_exit(); ! 63: } ! 64: ! 65: void do_raise_exception (uint32_t exception) ! 66: { ! 67: do_raise_exception_err(exception, 0); ! 68: } ! 69: ! 70: /*****************************************************************************/ ! 71: /* Fixed point operations helpers */ ! 72: void do_addo (void) ! 73: { ! 74: T2 = T0; ! 75: T0 += T1; ! 76: if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) { ! 77: xer_ov = 0; ! 78: } else { ! 79: xer_so = 1; ! 80: xer_ov = 1; ! 81: } ! 82: } ! 83: ! 84: void do_addco (void) ! 85: { ! 86: T2 = T0; ! 87: T0 += T1; ! 88: if (likely(T0 >= T2)) { ! 89: xer_ca = 0; ! 90: } else { ! 91: xer_ca = 1; ! 92: } ! 93: if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) { ! 94: xer_ov = 0; ! 95: } else { ! 96: xer_so = 1; ! 97: xer_ov = 1; ! 98: } ! 99: } ! 100: ! 101: void do_adde (void) ! 102: { ! 103: T2 = T0; ! 104: T0 += T1 + xer_ca; ! 105: if (likely(!(T0 < T2 || (xer_ca == 1 && T0 == T2)))) { ! 106: xer_ca = 0; ! 107: } else { ! 108: xer_ca = 1; ! 109: } ! 110: } ! 111: ! 112: void do_addeo (void) ! 113: { ! 114: T2 = T0; ! 115: T0 += T1 + xer_ca; ! 116: if (likely(!(T0 < T2 || (xer_ca == 1 && T0 == T2)))) { ! 117: xer_ca = 0; ! 118: } else { ! 119: xer_ca = 1; ! 120: } ! 121: if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) { ! 122: xer_ov = 0; ! 123: } else { ! 124: xer_so = 1; ! 125: xer_ov = 1; ! 126: } ! 127: } ! 128: ! 129: void do_addmeo (void) ! 130: { ! 131: T1 = T0; ! 132: T0 += xer_ca + (-1); ! 133: if (likely(!(T1 & (T1 ^ T0) & (1 << 31)))) { ! 134: xer_ov = 0; ! 135: } else { ! 136: xer_so = 1; ! 137: xer_ov = 1; ! 138: } ! 139: if (likely(T1 != 0)) ! 140: xer_ca = 1; ! 141: } ! 142: ! 143: void do_addzeo (void) ! 144: { ! 145: T1 = T0; ! 146: T0 += xer_ca; ! 147: if (likely(!((T1 ^ (-1)) & (T1 ^ T0) & (1 << 31)))) { ! 148: xer_ov = 0; ! 149: } else { ! 150: xer_so = 1; ! 151: xer_ov = 1; ! 152: } ! 153: if (likely(T0 >= T1)) { ! 154: xer_ca = 0; ! 155: } else { ! 156: xer_ca = 1; ! 157: } ! 158: } ! 159: ! 160: void do_divwo (void) ! 161: { ! 162: if (likely(!((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0))) { ! 163: xer_ov = 0; ! 164: T0 = (Ts0 / Ts1); ! 165: } else { ! 166: xer_so = 1; ! 167: xer_ov = 1; ! 168: T0 = (-1) * ((uint32_t)T0 >> 31); ! 169: } ! 170: } ! 171: ! 172: void do_divwuo (void) ! 173: { ! 174: if (likely((uint32_t)T1 != 0)) { ! 175: xer_ov = 0; ! 176: T0 = (uint32_t)T0 / (uint32_t)T1; ! 177: } else { ! 178: xer_so = 1; ! 179: xer_ov = 1; ! 180: T0 = 0; ! 181: } ! 182: } ! 183: ! 184: void do_mullwo (void) ! 185: { ! 186: int64_t res = (int64_t)Ts0 * (int64_t)Ts1; ! 187: ! 188: if (likely((int32_t)res == res)) { ! 189: xer_ov = 0; ! 190: } else { ! 191: xer_ov = 1; ! 192: xer_so = 1; ! 193: } ! 194: T0 = (int32_t)res; ! 195: } ! 196: ! 197: void do_nego (void) ! 198: { ! 199: if (likely(T0 != INT32_MIN)) { ! 200: xer_ov = 0; ! 201: T0 = -Ts0; ! 202: } else { ! 203: xer_ov = 1; ! 204: xer_so = 1; ! 205: } ! 206: } ! 207: ! 208: void do_subfo (void) ! 209: { ! 210: T2 = T0; ! 211: T0 = T1 - T0; ! 212: if (likely(!(((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)))) { ! 213: xer_ov = 0; ! 214: } else { ! 215: xer_so = 1; ! 216: xer_ov = 1; ! 217: } ! 218: RETURN(); ! 219: } ! 220: ! 221: void do_subfco (void) ! 222: { ! 223: T2 = T0; ! 224: T0 = T1 - T0; ! 225: if (likely(T0 > T1)) { ! 226: xer_ca = 0; ! 227: } else { ! 228: xer_ca = 1; ! 229: } ! 230: if (likely(!(((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)))) { ! 231: xer_ov = 0; ! 232: } else { ! 233: xer_so = 1; ! 234: xer_ov = 1; ! 235: } ! 236: } ! 237: ! 238: void do_subfe (void) ! 239: { ! 240: T0 = T1 + ~T0 + xer_ca; ! 241: if (likely(T0 >= T1 && (xer_ca == 0 || T0 != T1))) { ! 242: xer_ca = 0; ! 243: } else { ! 244: xer_ca = 1; ! 245: } ! 246: } ! 247: ! 248: void do_subfeo (void) ! 249: { ! 250: T2 = T0; ! 251: T0 = T1 + ~T0 + xer_ca; ! 252: if (likely(!((~T2 ^ T1 ^ (-1)) & (~T2 ^ T0) & (1 << 31)))) { ! 253: xer_ov = 0; ! 254: } else { ! 255: xer_so = 1; ! 256: xer_ov = 1; ! 257: } ! 258: if (likely(T0 >= T1 && (xer_ca == 0 || T0 != T1))) { ! 259: xer_ca = 0; ! 260: } else { ! 261: xer_ca = 1; ! 262: } ! 263: } ! 264: ! 265: void do_subfmeo (void) ! 266: { ! 267: T1 = T0; ! 268: T0 = ~T0 + xer_ca - 1; ! 269: if (likely(!(~T1 & (~T1 ^ T0) & (1 << 31)))) { ! 270: xer_ov = 0; ! 271: } else { ! 272: xer_so = 1; ! 273: xer_ov = 1; ! 274: } ! 275: if (likely(T1 != -1)) ! 276: xer_ca = 1; ! 277: } ! 278: ! 279: void do_subfzeo (void) ! 280: { ! 281: T1 = T0; ! 282: T0 = ~T0 + xer_ca; ! 283: if (likely(!((~T1 ^ (-1)) & ((~T1) ^ T0) & (1 << 31)))) { ! 284: xer_ov = 0; ! 285: } else { ! 286: xer_ov = 1; ! 287: xer_so = 1; ! 288: } ! 289: if (likely(T0 >= ~T1)) { ! 290: xer_ca = 0; ! 291: } else { ! 292: xer_ca = 1; ! 293: } ! 294: } ! 295: ! 296: /* shift right arithmetic helper */ ! 297: void do_sraw (void) ! 298: { ! 299: int32_t ret; ! 300: ! 301: if (likely(!(T1 & 0x20UL))) { ! 302: if (likely(T1 != 0)) { ! 303: ret = (int32_t)T0 >> (T1 & 0x1fUL); ! 304: if (likely(ret >= 0 || ((int32_t)T0 & ((1 << T1) - 1)) == 0)) { ! 305: xer_ca = 0; ! 306: } else { ! 307: xer_ca = 1; ! 308: } ! 309: } else { ! 310: ret = T0; ! 311: xer_ca = 0; ! 312: } ! 313: } else { ! 314: ret = (-1) * ((uint32_t)T0 >> 31); ! 315: if (likely(ret >= 0 || ((uint32_t)T0 & ~0x80000000UL) == 0)) { ! 316: xer_ca = 0; ! 317: } else { ! 318: xer_ca = 1; ! 319: } ! 320: } ! 321: T0 = ret; ! 322: } ! 323: ! 324: /*****************************************************************************/ ! 325: /* Floating point operations helpers */ ! 326: void do_fctiw (void) ! 327: { ! 328: union { ! 329: double d; ! 330: uint64_t i; ! 331: } p; ! 332: ! 333: /* XXX: higher bits are not supposed to be significant. ! 334: * to make tests easier, return the same as a real PowerPC 750 (aka G3) ! 335: */ ! 336: p.i = float64_to_int32(FT0, &env->fp_status); ! 337: p.i |= 0xFFF80000ULL << 32; ! 338: FT0 = p.d; ! 339: } ! 340: ! 341: void do_fctiwz (void) ! 342: { ! 343: union { ! 344: double d; ! 345: uint64_t i; ! 346: } p; ! 347: ! 348: /* XXX: higher bits are not supposed to be significant. ! 349: * to make tests easier, return the same as a real PowerPC 750 (aka G3) ! 350: */ ! 351: p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status); ! 352: p.i |= 0xFFF80000ULL << 32; ! 353: FT0 = p.d; ! 354: } ! 355: ! 356: void do_fnmadd (void) ! 357: { ! 358: FT0 = float64_mul(FT0, FT1, &env->fp_status); ! 359: FT0 = float64_add(FT0, FT2, &env->fp_status); ! 360: if (likely(!isnan(FT0))) ! 361: FT0 = float64_chs(FT0); ! 362: } ! 363: ! 364: void do_fnmsub (void) ! 365: { ! 366: FT0 = float64_mul(FT0, FT1, &env->fp_status); ! 367: FT0 = float64_sub(FT0, FT2, &env->fp_status); ! 368: if (likely(!isnan(FT0))) ! 369: FT0 = float64_chs(FT0); ! 370: } ! 371: ! 372: void do_fsqrt (void) ! 373: { ! 374: FT0 = float64_sqrt(FT0, &env->fp_status); ! 375: } ! 376: ! 377: void do_fres (void) ! 378: { ! 379: union { ! 380: double d; ! 381: uint64_t i; ! 382: } p; ! 383: ! 384: if (likely(isnormal(FT0))) { ! 385: FT0 = (float)(1.0 / FT0); ! 386: } else { ! 387: p.d = FT0; ! 388: if (p.i == 0x8000000000000000ULL) { ! 389: p.i = 0xFFF0000000000000ULL; ! 390: } else if (p.i == 0x0000000000000000ULL) { ! 391: p.i = 0x7FF0000000000000ULL; ! 392: } else if (isnan(FT0)) { ! 393: p.i = 0x7FF8000000000000ULL; ! 394: } else if (FT0 < 0.0) { ! 395: p.i = 0x8000000000000000ULL; ! 396: } else { ! 397: p.i = 0x0000000000000000ULL; ! 398: } ! 399: FT0 = p.d; ! 400: } ! 401: } ! 402: ! 403: void do_frsqrte (void) ! 404: { ! 405: union { ! 406: double d; ! 407: uint64_t i; ! 408: } p; ! 409: ! 410: if (likely(isnormal(FT0) && FT0 > 0.0)) { ! 411: FT0 = float64_sqrt(FT0, &env->fp_status); ! 412: FT0 = float32_div(1.0, FT0, &env->fp_status); ! 413: } else { ! 414: p.d = FT0; ! 415: if (p.i == 0x8000000000000000ULL) { ! 416: p.i = 0xFFF0000000000000ULL; ! 417: } else if (p.i == 0x0000000000000000ULL) { ! 418: p.i = 0x7FF0000000000000ULL; ! 419: } else if (isnan(FT0)) { ! 420: if (!(p.i & 0x0008000000000000ULL)) ! 421: p.i |= 0x000FFFFFFFFFFFFFULL; ! 422: } else if (FT0 < 0) { ! 423: p.i = 0x7FF8000000000000ULL; ! 424: } else { ! 425: p.i = 0x0000000000000000ULL; ! 426: } ! 427: FT0 = p.d; ! 428: } ! 429: } ! 430: ! 431: void do_fsel (void) ! 432: { ! 433: if (FT0 >= 0) ! 434: FT0 = FT1; ! 435: else ! 436: FT0 = FT2; ! 437: } ! 438: ! 439: void do_fcmpu (void) ! 440: { ! 441: if (likely(!isnan(FT0) && !isnan(FT1))) { ! 442: if (float64_lt(FT0, FT1, &env->fp_status)) { ! 443: T0 = 0x08UL; ! 444: } else if (!float64_le(FT0, FT1, &env->fp_status)) { ! 445: T0 = 0x04UL; ! 446: } else { ! 447: T0 = 0x02UL; ! 448: } ! 449: } else { ! 450: T0 = 0x01UL; ! 451: env->fpscr[4] |= 0x1; ! 452: env->fpscr[6] |= 0x1; ! 453: } ! 454: env->fpscr[3] = T0; ! 455: } ! 456: ! 457: void do_fcmpo (void) ! 458: { ! 459: env->fpscr[4] &= ~0x1; ! 460: if (likely(!isnan(FT0) && !isnan(FT1))) { ! 461: if (float64_lt(FT0, FT1, &env->fp_status)) { ! 462: T0 = 0x08UL; ! 463: } else if (!float64_le(FT0, FT1, &env->fp_status)) { ! 464: T0 = 0x04UL; ! 465: } else { ! 466: T0 = 0x02UL; ! 467: } ! 468: } else { ! 469: T0 = 0x01UL; ! 470: env->fpscr[4] |= 0x1; ! 471: /* I don't know how to test "quiet" nan... */ ! 472: if (0 /* || ! quiet_nan(...) */) { ! 473: env->fpscr[6] |= 0x1; ! 474: if (!(env->fpscr[1] & 0x8)) ! 475: env->fpscr[4] |= 0x8; ! 476: } else { ! 477: env->fpscr[4] |= 0x8; ! 478: } ! 479: } ! 480: env->fpscr[3] = T0; ! 481: } ! 482: ! 483: void do_rfi (void) ! 484: { ! 485: env->nip = env->spr[SPR_SRR0] & ~0x00000003; ! 486: T0 = env->spr[SPR_SRR1] & ~0xFFFF0000UL; ! 487: do_store_msr(env, T0); ! 488: #if defined (DEBUG_OP) ! 489: dump_rfi(); ! 490: #endif ! 491: env->interrupt_request |= CPU_INTERRUPT_EXITTB; ! 492: } ! 493: ! 494: void do_tw (uint32_t cmp, int flags) ! 495: { ! 496: if (!likely(!((Ts0 < (int32_t)cmp && (flags & 0x10)) || ! 497: (Ts0 > (int32_t)cmp && (flags & 0x08)) || ! 498: (Ts0 == (int32_t)cmp && (flags & 0x04)) || ! 499: (T0 < cmp && (flags & 0x02)) || ! 500: (T0 > cmp && (flags & 0x01))))) ! 501: do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP); ! 502: } ! 503: ! 504: /* Instruction cache invalidation helper */ ! 505: void do_icbi (void) ! 506: { ! 507: uint32_t tmp; ! 508: /* Invalidate one cache line : ! 509: * PowerPC specification says this is to be treated like a load ! 510: * (not a fetch) by the MMU. To be sure it will be so, ! 511: * do the load "by hand". ! 512: */ ! 513: #if defined(TARGET_PPC64) ! 514: if (!msr_sf) ! 515: T0 &= 0xFFFFFFFFULL; ! 516: #endif ! 517: tmp = ldl_kernel(T0); ! 518: T0 &= ~(ICACHE_LINE_SIZE - 1); ! 519: tb_invalidate_page_range(T0, T0 + ICACHE_LINE_SIZE); ! 520: } ! 521: ! 522: /*****************************************************************************/ ! 523: /* MMU related helpers */ ! 524: /* TLB invalidation helpers */ ! 525: void do_tlbia (void) ! 526: { ! 527: tlb_flush(env, 1); ! 528: } ! 529: ! 530: void do_tlbie (void) ! 531: { ! 532: #if !defined(FLUSH_ALL_TLBS) ! 533: tlb_flush_page(env, T0); ! 534: #else ! 535: do_tlbia(); ! 536: #endif ! 537: } ! 538: ! 539: /*****************************************************************************/ ! 540: /* Softmmu support */ ! 541: #if !defined (CONFIG_USER_ONLY) ! 542: ! 543: #define MMUSUFFIX _mmu ! 544: #define GETPC() (__builtin_return_address(0)) ! 545: ! 546: #define SHIFT 0 ! 547: #include "softmmu_template.h" ! 548: ! 549: #define SHIFT 1 ! 550: #include "softmmu_template.h" ! 551: ! 552: #define SHIFT 2 ! 553: #include "softmmu_template.h" ! 554: ! 555: #define SHIFT 3 ! 556: #include "softmmu_template.h" ! 557: ! 558: /* try to fill the TLB and return an exception if error. If retaddr is ! 559: NULL, it means that the function was called in C code (i.e. not ! 560: from generated code or from helper.c) */ ! 561: /* XXX: fix it to restore all registers */ ! 562: void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) ! 563: { ! 564: TranslationBlock *tb; ! 565: CPUState *saved_env; ! 566: target_phys_addr_t pc; ! 567: int ret; ! 568: ! 569: /* XXX: hack to restore env in all cases, even if not called from ! 570: generated code */ ! 571: saved_env = env; ! 572: env = cpu_single_env; ! 573: ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1); ! 574: if (!likely(ret == 0)) { ! 575: if (likely(retaddr)) { ! 576: /* now we have a real cpu fault */ ! 577: pc = (target_phys_addr_t)retaddr; ! 578: tb = tb_find_pc(pc); ! 579: if (likely(tb)) { ! 580: /* the PC is inside the translated code. It means that we have ! 581: a virtual CPU fault */ ! 582: cpu_restore_state(tb, env, pc, NULL); ! 583: } ! 584: } ! 585: do_raise_exception_err(env->exception_index, env->error_code); ! 586: } ! 587: env = saved_env; ! 588: } ! 589: #endif /* !CONFIG_USER_ONLY */ ! 590:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.