|
|
1.1 root 1: /*
2: * PowerPC emulation helpers for qemu.
1.1.1.3 ! root 3: *
! 4: * Copyright (c) 2003-2007 Jocelyn Mayer
1.1 root 5: *
6: * This library is free software; you can redistribute it and/or
7: * modify it under the terms of the GNU Lesser General Public
8: * License as published by the Free Software Foundation; either
9: * version 2 of the License, or (at your option) any later version.
10: *
11: * This library is distributed in the hope that it will be useful,
12: * but WITHOUT ANY WARRANTY; without even the implied warranty of
13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14: * Lesser General Public License for more details.
15: *
16: * You should have received a copy of the GNU Lesser General Public
17: * License along with this library; if not, write to the Free Software
18: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19: */
20: #include "exec.h"
1.1.1.3 ! root 21: #include "host-utils.h"
! 22:
! 23: #include "helper_regs.h"
! 24: #include "op_helper.h"
1.1 root 25:
26: #define MEMSUFFIX _raw
1.1.1.3 ! root 27: #include "op_helper.h"
1.1 root 28: #include "op_helper_mem.h"
29: #if !defined(CONFIG_USER_ONLY)
30: #define MEMSUFFIX _user
1.1.1.3 ! root 31: #include "op_helper.h"
1.1 root 32: #include "op_helper_mem.h"
33: #define MEMSUFFIX _kernel
1.1.1.3 ! root 34: #include "op_helper.h"
! 35: #include "op_helper_mem.h"
! 36: #define MEMSUFFIX _hypv
! 37: #include "op_helper.h"
1.1 root 38: #include "op_helper_mem.h"
39: #endif
40:
41: //#define DEBUG_OP
42: //#define DEBUG_EXCEPTIONS
1.1.1.3 ! root 43: //#define DEBUG_SOFTWARE_TLB
1.1 root 44:
45: /*****************************************************************************/
46: /* Exceptions processing helpers */
47:
48: void do_raise_exception_err (uint32_t exception, int error_code)
49: {
50: #if 0
51: printf("Raise exception %3x code : %d\n", exception, error_code);
52: #endif
53: env->exception_index = exception;
54: env->error_code = error_code;
1.1.1.3 ! root 55: cpu_loop_exit();
! 56: }
1.1 root 57:
58: void do_raise_exception (uint32_t exception)
59: {
60: do_raise_exception_err(exception, 0);
61: }
62:
1.1.1.3 ! root 63: void cpu_dump_EA (target_ulong EA);
! 64: void do_print_mem_EA (target_ulong EA)
! 65: {
! 66: cpu_dump_EA(EA);
! 67: }
! 68:
1.1 root 69: /*****************************************************************************/
1.1.1.3 ! root 70: /* Registers load and stores */
! 71: void do_load_cr (void)
1.1 root 72: {
1.1.1.3 ! root 73: T0 = (env->crf[0] << 28) |
! 74: (env->crf[1] << 24) |
! 75: (env->crf[2] << 20) |
! 76: (env->crf[3] << 16) |
! 77: (env->crf[4] << 12) |
! 78: (env->crf[5] << 8) |
! 79: (env->crf[6] << 4) |
! 80: (env->crf[7] << 0);
! 81: }
! 82:
! 83: void do_store_cr (uint32_t mask)
! 84: {
! 85: int i, sh;
! 86:
! 87: for (i = 0, sh = 7; i < 8; i++, sh--) {
! 88: if (mask & (1 << sh))
! 89: env->crf[i] = (T0 >> (sh * 4)) & 0xFUL;
1.1 root 90: }
91: }
92:
1.1.1.3 ! root 93: #if defined(TARGET_PPC64)
! 94: void do_store_pri (int prio)
1.1 root 95: {
1.1.1.3 ! root 96: env->spr[SPR_PPR] &= ~0x001C000000000000ULL;
! 97: env->spr[SPR_PPR] |= ((uint64_t)prio & 0x7) << 50;
! 98: }
! 99: #endif
! 100:
! 101: target_ulong ppc_load_dump_spr (int sprn)
! 102: {
! 103: if (loglevel != 0) {
! 104: fprintf(logfile, "Read SPR %d %03x => " ADDRX "\n",
! 105: sprn, sprn, env->spr[sprn]);
1.1 root 106: }
1.1.1.3 ! root 107:
! 108: return env->spr[sprn];
! 109: }
! 110:
! 111: void ppc_store_dump_spr (int sprn, target_ulong val)
! 112: {
! 113: if (loglevel != 0) {
! 114: fprintf(logfile, "Write SPR %d %03x => " ADDRX " <= " ADDRX "\n",
! 115: sprn, sprn, env->spr[sprn], val);
1.1 root 116: }
1.1.1.3 ! root 117: env->spr[sprn] = val;
1.1 root 118: }
119:
1.1.1.3 ! root 120: /*****************************************************************************/
! 121: /* Fixed point operations helpers */
1.1 root 122: void do_adde (void)
123: {
124: T2 = T0;
125: T0 += T1 + xer_ca;
1.1.1.3 ! root 126: if (likely(!((uint32_t)T0 < (uint32_t)T2 ||
! 127: (xer_ca == 1 && (uint32_t)T0 == (uint32_t)T2)))) {
1.1 root 128: xer_ca = 0;
129: } else {
130: xer_ca = 1;
131: }
132: }
133:
1.1.1.3 ! root 134: #if defined(TARGET_PPC64)
! 135: void do_adde_64 (void)
1.1 root 136: {
137: T2 = T0;
138: T0 += T1 + xer_ca;
1.1.1.3 ! root 139: if (likely(!((uint64_t)T0 < (uint64_t)T2 ||
! 140: (xer_ca == 1 && (uint64_t)T0 == (uint64_t)T2)))) {
1.1 root 141: xer_ca = 0;
142: } else {
143: xer_ca = 1;
144: }
145: }
1.1.1.3 ! root 146: #endif
1.1 root 147:
148: void do_addmeo (void)
149: {
150: T1 = T0;
151: T0 += xer_ca + (-1);
1.1.1.3 ! root 152: xer_ov = ((uint32_t)T1 & ((uint32_t)T1 ^ (uint32_t)T0)) >> 31;
! 153: xer_so |= xer_ov;
1.1 root 154: if (likely(T1 != 0))
155: xer_ca = 1;
1.1.1.3 ! root 156: else
! 157: xer_ca = 0;
1.1 root 158: }
159:
1.1.1.3 ! root 160: #if defined(TARGET_PPC64)
! 161: void do_addmeo_64 (void)
1.1 root 162: {
163: T1 = T0;
1.1.1.3 ! root 164: T0 += xer_ca + (-1);
! 165: xer_ov = ((uint64_t)T1 & ((uint64_t)T1 ^ (uint64_t)T0)) >> 63;
! 166: xer_so |= xer_ov;
! 167: if (likely(T1 != 0))
! 168: xer_ca = 1;
! 169: else
! 170: xer_ca = 0;
! 171: }
! 172: #endif
! 173:
! 174: void do_divwo (void)
! 175: {
! 176: if (likely(!(((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
! 177: (int32_t)T1 == 0))) {
1.1 root 178: xer_ov = 0;
1.1.1.3 ! root 179: T0 = (int32_t)T0 / (int32_t)T1;
1.1 root 180: } else {
181: xer_ov = 1;
1.1.1.3 ! root 182: T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
1.1 root 183: }
1.1.1.3 ! root 184: xer_so |= xer_ov;
1.1 root 185: }
186:
1.1.1.3 ! root 187: #if defined(TARGET_PPC64)
! 188: void do_divdo (void)
1.1 root 189: {
1.1.1.3 ! root 190: if (likely(!(((int64_t)T0 == INT64_MIN && (int64_t)T1 == (int64_t)-1LL) ||
! 191: (int64_t)T1 == 0))) {
1.1 root 192: xer_ov = 0;
1.1.1.3 ! root 193: T0 = (int64_t)T0 / (int64_t)T1;
1.1 root 194: } else {
195: xer_ov = 1;
1.1.1.3 ! root 196: T0 = UINT64_MAX * ((uint64_t)T0 >> 63);
1.1 root 197: }
1.1.1.3 ! root 198: xer_so |= xer_ov;
1.1 root 199: }
1.1.1.3 ! root 200: #endif
1.1 root 201:
202: void do_divwuo (void)
203: {
204: if (likely((uint32_t)T1 != 0)) {
205: xer_ov = 0;
206: T0 = (uint32_t)T0 / (uint32_t)T1;
207: } else {
1.1.1.3 ! root 208: xer_ov = 1;
1.1 root 209: xer_so = 1;
1.1.1.3 ! root 210: T0 = 0;
! 211: }
! 212: }
! 213:
! 214: #if defined(TARGET_PPC64)
! 215: void do_divduo (void)
! 216: {
! 217: if (likely((uint64_t)T1 != 0)) {
! 218: xer_ov = 0;
! 219: T0 = (uint64_t)T0 / (uint64_t)T1;
! 220: } else {
1.1 root 221: xer_ov = 1;
1.1.1.3 ! root 222: xer_so = 1;
1.1 root 223: T0 = 0;
224: }
225: }
1.1.1.3 ! root 226: #endif
1.1 root 227:
228: void do_mullwo (void)
229: {
1.1.1.3 ! root 230: int64_t res = (int64_t)T0 * (int64_t)T1;
1.1 root 231:
232: if (likely((int32_t)res == res)) {
233: xer_ov = 0;
234: } else {
235: xer_ov = 1;
236: xer_so = 1;
237: }
238: T0 = (int32_t)res;
239: }
240:
1.1.1.3 ! root 241: #if defined(TARGET_PPC64)
! 242: void do_mulldo (void)
1.1 root 243: {
1.1.1.3 ! root 244: int64_t th;
! 245: uint64_t tl;
! 246:
! 247: muls64(&tl, &th, T0, T1);
! 248: T0 = (int64_t)tl;
! 249: /* If th != 0 && th != -1, then we had an overflow */
! 250: if (likely((uint64_t)(th + 1) <= 1)) {
1.1 root 251: xer_ov = 0;
252: } else {
253: xer_ov = 1;
254: }
1.1.1.3 ! root 255: xer_so |= xer_ov;
1.1 root 256: }
1.1.1.3 ! root 257: #endif
1.1 root 258:
1.1.1.3 ! root 259: void do_nego (void)
1.1 root 260: {
1.1.1.3 ! root 261: if (likely((int32_t)T0 != INT32_MIN)) {
1.1 root 262: xer_ov = 0;
1.1.1.3 ! root 263: T0 = -(int32_t)T0;
1.1 root 264: } else {
265: xer_ov = 1;
1.1.1.3 ! root 266: xer_so = 1;
1.1 root 267: }
268: }
269:
1.1.1.3 ! root 270: #if defined(TARGET_PPC64)
! 271: void do_nego_64 (void)
1.1 root 272: {
1.1.1.3 ! root 273: if (likely((int64_t)T0 != INT64_MIN)) {
1.1 root 274: xer_ov = 0;
1.1.1.3 ! root 275: T0 = -(int64_t)T0;
1.1 root 276: } else {
277: xer_ov = 1;
1.1.1.3 ! root 278: xer_so = 1;
1.1 root 279: }
280: }
1.1.1.3 ! root 281: #endif
1.1 root 282:
283: void do_subfe (void)
284: {
285: T0 = T1 + ~T0 + xer_ca;
1.1.1.3 ! root 286: if (likely((uint32_t)T0 >= (uint32_t)T1 &&
! 287: (xer_ca == 0 || (uint32_t)T0 != (uint32_t)T1))) {
1.1 root 288: xer_ca = 0;
289: } else {
290: xer_ca = 1;
291: }
292: }
293:
1.1.1.3 ! root 294: #if defined(TARGET_PPC64)
! 295: void do_subfe_64 (void)
1.1 root 296: {
297: T0 = T1 + ~T0 + xer_ca;
1.1.1.3 ! root 298: if (likely((uint64_t)T0 >= (uint64_t)T1 &&
! 299: (xer_ca == 0 || (uint64_t)T0 != (uint64_t)T1))) {
1.1 root 300: xer_ca = 0;
301: } else {
302: xer_ca = 1;
303: }
304: }
1.1.1.3 ! root 305: #endif
1.1 root 306:
307: void do_subfmeo (void)
308: {
309: T1 = T0;
310: T0 = ~T0 + xer_ca - 1;
1.1.1.3 ! root 311: xer_ov = ((uint32_t)~T1 & ((uint32_t)~T1 ^ (uint32_t)T0)) >> 31;
! 312: xer_so |= xer_ov;
! 313: if (likely((uint32_t)T1 != UINT32_MAX))
! 314: xer_ca = 1;
! 315: else
! 316: xer_ca = 0;
! 317: }
! 318:
! 319: #if defined(TARGET_PPC64)
! 320: void do_subfmeo_64 (void)
! 321: {
! 322: T1 = T0;
! 323: T0 = ~T0 + xer_ca - 1;
! 324: xer_ov = ((uint64_t)~T1 & ((uint64_t)~T1 ^ (uint64_t)T0)) >> 63;
! 325: xer_so |= xer_ov;
! 326: if (likely((uint64_t)T1 != UINT64_MAX))
1.1 root 327: xer_ca = 1;
1.1.1.3 ! root 328: else
! 329: xer_ca = 0;
1.1 root 330: }
1.1.1.3 ! root 331: #endif
1.1 root 332:
333: void do_subfzeo (void)
334: {
335: T1 = T0;
336: T0 = ~T0 + xer_ca;
1.1.1.3 ! root 337: xer_ov = (((uint32_t)~T1 ^ UINT32_MAX) &
! 338: ((uint32_t)(~T1) ^ (uint32_t)T0)) >> 31;
! 339: xer_so |= xer_ov;
! 340: if (likely((uint32_t)T0 >= (uint32_t)~T1)) {
! 341: xer_ca = 0;
1.1 root 342: } else {
1.1.1.3 ! root 343: xer_ca = 1;
1.1 root 344: }
1.1.1.3 ! root 345: }
! 346:
! 347: #if defined(TARGET_PPC64)
! 348: void do_subfzeo_64 (void)
! 349: {
! 350: T1 = T0;
! 351: T0 = ~T0 + xer_ca;
! 352: xer_ov = (((uint64_t)~T1 ^ UINT64_MAX) &
! 353: ((uint64_t)(~T1) ^ (uint64_t)T0)) >> 63;
! 354: xer_so |= xer_ov;
! 355: if (likely((uint64_t)T0 >= (uint64_t)~T1)) {
1.1 root 356: xer_ca = 0;
357: } else {
358: xer_ca = 1;
359: }
360: }
1.1.1.3 ! root 361: #endif
! 362:
! 363: void do_cntlzw (void)
! 364: {
! 365: T0 = clz32(T0);
! 366: }
! 367:
! 368: #if defined(TARGET_PPC64)
! 369: void do_cntlzd (void)
! 370: {
! 371: T0 = clz64(T0);
! 372: }
! 373: #endif
1.1 root 374:
375: /* shift right arithmetic helper */
376: void do_sraw (void)
377: {
378: int32_t ret;
379:
380: if (likely(!(T1 & 0x20UL))) {
1.1.1.3 ! root 381: if (likely((uint32_t)T1 != 0)) {
1.1 root 382: ret = (int32_t)T0 >> (T1 & 0x1fUL);
383: if (likely(ret >= 0 || ((int32_t)T0 & ((1 << T1) - 1)) == 0)) {
1.1.1.3 ! root 384: xer_ca = 0;
1.1 root 385: } else {
1.1.1.3 ! root 386: xer_ca = 1;
1.1 root 387: }
388: } else {
1.1.1.3 ! root 389: ret = T0;
1.1 root 390: xer_ca = 0;
391: }
392: } else {
1.1.1.3 ! root 393: ret = UINT32_MAX * ((uint32_t)T0 >> 31);
1.1 root 394: if (likely(ret >= 0 || ((uint32_t)T0 & ~0x80000000UL) == 0)) {
395: xer_ca = 0;
1.1.1.3 ! root 396: } else {
1.1 root 397: xer_ca = 1;
1.1.1.3 ! root 398: }
1.1 root 399: }
1.1.1.3 ! root 400: T0 = ret;
! 401: }
! 402:
! 403: #if defined(TARGET_PPC64)
! 404: void do_srad (void)
! 405: {
! 406: int64_t ret;
! 407:
! 408: if (likely(!(T1 & 0x40UL))) {
! 409: if (likely((uint64_t)T1 != 0)) {
! 410: ret = (int64_t)T0 >> (T1 & 0x3FUL);
! 411: if (likely(ret >= 0 || ((int64_t)T0 & ((1 << T1) - 1)) == 0)) {
! 412: xer_ca = 0;
! 413: } else {
! 414: xer_ca = 1;
! 415: }
! 416: } else {
! 417: ret = T0;
! 418: xer_ca = 0;
! 419: }
! 420: } else {
! 421: ret = UINT64_MAX * ((uint64_t)T0 >> 63);
! 422: if (likely(ret >= 0 || ((uint64_t)T0 & ~0x8000000000000000ULL) == 0)) {
! 423: xer_ca = 0;
! 424: } else {
! 425: xer_ca = 1;
! 426: }
1.1 root 427: }
428: T0 = ret;
429: }
1.1.1.3 ! root 430: #endif
! 431:
! 432: void do_popcntb (void)
! 433: {
! 434: uint32_t ret;
! 435: int i;
! 436:
! 437: ret = 0;
! 438: for (i = 0; i < 32; i += 8)
! 439: ret |= ctpop8((T0 >> i) & 0xFF) << i;
! 440: T0 = ret;
! 441: }
! 442:
! 443: #if defined(TARGET_PPC64)
! 444: void do_popcntb_64 (void)
! 445: {
! 446: uint64_t ret;
! 447: int i;
! 448:
! 449: ret = 0;
! 450: for (i = 0; i < 64; i += 8)
! 451: ret |= ctpop8((T0 >> i) & 0xFF) << i;
! 452: T0 = ret;
! 453: }
! 454: #endif
1.1 root 455:
456: /*****************************************************************************/
457: /* Floating point operations helpers */
1.1.1.3 ! root 458: static always_inline int fpisneg (float64 f)
1.1 root 459: {
460: union {
1.1.1.3 ! root 461: float64 f;
! 462: uint64_t u;
! 463: } u;
1.1 root 464:
1.1.1.3 ! root 465: u.f = f;
! 466:
! 467: return u.u >> 63 != 0;
1.1 root 468: }
469:
1.1.1.3 ! root 470: static always_inline int isden (float f)
1.1 root 471: {
472: union {
1.1.1.3 ! root 473: float64 f;
! 474: uint64_t u;
! 475: } u;
1.1 root 476:
1.1.1.3 ! root 477: u.f = f;
1.1 root 478:
1.1.1.3 ! root 479: return ((u.u >> 52) & 0x7FF) == 0;
1.1 root 480: }
481:
1.1.1.3 ! root 482: static always_inline int iszero (float64 f)
1.1 root 483: {
1.1.1.3 ! root 484: union {
! 485: float64 f;
! 486: uint64_t u;
! 487: } u;
! 488:
! 489: u.f = f;
! 490:
! 491: return (u.u & ~0x8000000000000000ULL) == 0;
1.1 root 492: }
493:
1.1.1.3 ! root 494: static always_inline int isinfinity (float64 f)
1.1 root 495: {
1.1.1.3 ! root 496: union {
! 497: float64 f;
! 498: uint64_t u;
! 499: } u;
! 500:
! 501: u.f = f;
! 502:
! 503: return ((u.u >> 52) & 0x7FF) == 0x7FF &&
! 504: (u.u & 0x000FFFFFFFFFFFFFULL) == 0;
1.1 root 505: }
506:
1.1.1.3 ! root 507: void do_compute_fprf (int set_fprf)
1.1 root 508: {
1.1.1.3 ! root 509: int isneg;
1.1 root 510:
1.1.1.3 ! root 511: isneg = fpisneg(FT0);
! 512: if (unlikely(float64_is_nan(FT0))) {
! 513: if (float64_is_signaling_nan(FT0)) {
! 514: /* Signaling NaN: flags are undefined */
! 515: T0 = 0x00;
1.1 root 516: } else {
1.1.1.3 ! root 517: /* Quiet NaN */
! 518: T0 = 0x11;
1.1 root 519: }
1.1.1.3 ! root 520: } else if (unlikely(isinfinity(FT0))) {
! 521: /* +/- infinity */
! 522: if (isneg)
! 523: T0 = 0x09;
! 524: else
! 525: T0 = 0x05;
! 526: } else {
! 527: if (iszero(FT0)) {
! 528: /* +/- zero */
! 529: if (isneg)
! 530: T0 = 0x12;
! 531: else
! 532: T0 = 0x02;
! 533: } else {
! 534: if (isden(FT0)) {
! 535: /* Denormalized numbers */
! 536: T0 = 0x10;
! 537: } else {
! 538: /* Normalized numbers */
! 539: T0 = 0x00;
! 540: }
! 541: if (isneg) {
! 542: T0 |= 0x08;
! 543: } else {
! 544: T0 |= 0x04;
! 545: }
! 546: }
! 547: }
! 548: if (set_fprf) {
! 549: /* We update FPSCR_FPRF */
! 550: env->fpscr &= ~(0x1F << FPSCR_FPRF);
! 551: env->fpscr |= T0 << FPSCR_FPRF;
! 552: }
! 553: /* We just need fpcc to update Rc1 */
! 554: T0 &= 0xF;
! 555: }
! 556:
! 557: /* Floating-point invalid operations exception */
! 558: static always_inline void fload_invalid_op_excp (int op)
! 559: {
! 560: int ve;
! 561:
! 562: ve = fpscr_ve;
! 563: if (op & POWERPC_EXCP_FP_VXSNAN) {
! 564: /* Operation on signaling NaN */
! 565: env->fpscr |= 1 << FPSCR_VXSNAN;
! 566: }
! 567: if (op & POWERPC_EXCP_FP_VXSOFT) {
! 568: /* Software-defined condition */
! 569: env->fpscr |= 1 << FPSCR_VXSOFT;
! 570: }
! 571: switch (op & ~(POWERPC_EXCP_FP_VXSOFT | POWERPC_EXCP_FP_VXSNAN)) {
! 572: case POWERPC_EXCP_FP_VXISI:
! 573: /* Magnitude subtraction of infinities */
! 574: env->fpscr |= 1 << FPSCR_VXISI;
! 575: goto update_arith;
! 576: case POWERPC_EXCP_FP_VXIDI:
! 577: /* Division of infinity by infinity */
! 578: env->fpscr |= 1 << FPSCR_VXIDI;
! 579: goto update_arith;
! 580: case POWERPC_EXCP_FP_VXZDZ:
! 581: /* Division of zero by zero */
! 582: env->fpscr |= 1 << FPSCR_VXZDZ;
! 583: goto update_arith;
! 584: case POWERPC_EXCP_FP_VXIMZ:
! 585: /* Multiplication of zero by infinity */
! 586: env->fpscr |= 1 << FPSCR_VXIMZ;
! 587: goto update_arith;
! 588: case POWERPC_EXCP_FP_VXVC:
! 589: /* Ordered comparison of NaN */
! 590: env->fpscr |= 1 << FPSCR_VXVC;
! 591: env->fpscr &= ~(0xF << FPSCR_FPCC);
! 592: env->fpscr |= 0x11 << FPSCR_FPCC;
! 593: /* We must update the target FPR before raising the exception */
! 594: if (ve != 0) {
! 595: env->exception_index = POWERPC_EXCP_PROGRAM;
! 596: env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
! 597: /* Update the floating-point enabled exception summary */
! 598: env->fpscr |= 1 << FPSCR_FEX;
! 599: /* Exception is differed */
! 600: ve = 0;
! 601: }
! 602: break;
! 603: case POWERPC_EXCP_FP_VXSQRT:
! 604: /* Square root of a negative number */
! 605: env->fpscr |= 1 << FPSCR_VXSQRT;
! 606: update_arith:
! 607: env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
! 608: if (ve == 0) {
! 609: /* Set the result to quiet NaN */
! 610: FT0 = UINT64_MAX;
! 611: env->fpscr &= ~(0xF << FPSCR_FPCC);
! 612: env->fpscr |= 0x11 << FPSCR_FPCC;
! 613: }
! 614: break;
! 615: case POWERPC_EXCP_FP_VXCVI:
! 616: /* Invalid conversion */
! 617: env->fpscr |= 1 << FPSCR_VXCVI;
! 618: env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
! 619: if (ve == 0) {
! 620: /* Set the result to quiet NaN */
! 621: FT0 = UINT64_MAX;
! 622: env->fpscr &= ~(0xF << FPSCR_FPCC);
! 623: env->fpscr |= 0x11 << FPSCR_FPCC;
! 624: }
! 625: break;
! 626: }
! 627: /* Update the floating-point invalid operation summary */
! 628: env->fpscr |= 1 << FPSCR_VX;
! 629: /* Update the floating-point exception summary */
! 630: env->fpscr |= 1 << FPSCR_FX;
! 631: if (ve != 0) {
! 632: /* Update the floating-point enabled exception summary */
! 633: env->fpscr |= 1 << FPSCR_FEX;
! 634: if (msr_fe0 != 0 || msr_fe1 != 0)
! 635: do_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | op);
1.1 root 636: }
637: }
638:
1.1.1.3 ! root 639: static always_inline void float_zero_divide_excp (void)
1.1 root 640: {
641: union {
1.1.1.3 ! root 642: float64 f;
! 643: uint64_t u;
! 644: } u0, u1;
! 645:
! 646: env->fpscr |= 1 << FPSCR_ZX;
! 647: env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
! 648: /* Update the floating-point exception summary */
! 649: env->fpscr |= 1 << FPSCR_FX;
! 650: if (fpscr_ze != 0) {
! 651: /* Update the floating-point enabled exception summary */
! 652: env->fpscr |= 1 << FPSCR_FEX;
! 653: if (msr_fe0 != 0 || msr_fe1 != 0) {
! 654: do_raise_exception_err(POWERPC_EXCP_PROGRAM,
! 655: POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
! 656: }
1.1 root 657: } else {
1.1.1.3 ! root 658: /* Set the result to infinity */
! 659: u0.f = FT0;
! 660: u1.f = FT1;
! 661: u0.u = ((u0.u ^ u1.u) & 0x8000000000000000ULL);
! 662: u0.u |= 0x7FFULL << 52;
! 663: FT0 = u0.f;
! 664: }
! 665: }
! 666:
! 667: static always_inline void float_overflow_excp (void)
! 668: {
! 669: env->fpscr |= 1 << FPSCR_OX;
! 670: /* Update the floating-point exception summary */
! 671: env->fpscr |= 1 << FPSCR_FX;
! 672: if (fpscr_oe != 0) {
! 673: /* XXX: should adjust the result */
! 674: /* Update the floating-point enabled exception summary */
! 675: env->fpscr |= 1 << FPSCR_FEX;
! 676: /* We must update the target FPR before raising the exception */
! 677: env->exception_index = POWERPC_EXCP_PROGRAM;
! 678: env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
! 679: } else {
! 680: env->fpscr |= 1 << FPSCR_XX;
! 681: env->fpscr |= 1 << FPSCR_FI;
! 682: }
! 683: }
! 684:
! 685: static always_inline void float_underflow_excp (void)
! 686: {
! 687: env->fpscr |= 1 << FPSCR_UX;
! 688: /* Update the floating-point exception summary */
! 689: env->fpscr |= 1 << FPSCR_FX;
! 690: if (fpscr_ue != 0) {
! 691: /* XXX: should adjust the result */
! 692: /* Update the floating-point enabled exception summary */
! 693: env->fpscr |= 1 << FPSCR_FEX;
! 694: /* We must update the target FPR before raising the exception */
! 695: env->exception_index = POWERPC_EXCP_PROGRAM;
! 696: env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
! 697: }
! 698: }
! 699:
! 700: static always_inline void float_inexact_excp (void)
! 701: {
! 702: env->fpscr |= 1 << FPSCR_XX;
! 703: /* Update the floating-point exception summary */
! 704: env->fpscr |= 1 << FPSCR_FX;
! 705: if (fpscr_xe != 0) {
! 706: /* Update the floating-point enabled exception summary */
! 707: env->fpscr |= 1 << FPSCR_FEX;
! 708: /* We must update the target FPR before raising the exception */
! 709: env->exception_index = POWERPC_EXCP_PROGRAM;
! 710: env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
! 711: }
! 712: }
! 713:
! 714: static always_inline void fpscr_set_rounding_mode (void)
! 715: {
! 716: int rnd_type;
! 717:
! 718: /* Set rounding mode */
! 719: switch (fpscr_rn) {
! 720: case 0:
! 721: /* Best approximation (round to nearest) */
! 722: rnd_type = float_round_nearest_even;
! 723: break;
! 724: case 1:
! 725: /* Smaller magnitude (round toward zero) */
! 726: rnd_type = float_round_to_zero;
! 727: break;
! 728: case 2:
! 729: /* Round toward +infinite */
! 730: rnd_type = float_round_up;
! 731: break;
! 732: default:
! 733: case 3:
! 734: /* Round toward -infinite */
! 735: rnd_type = float_round_down;
! 736: break;
! 737: }
! 738: set_float_rounding_mode(rnd_type, &env->fp_status);
! 739: }
! 740:
! 741: void do_fpscr_setbit (int bit)
! 742: {
! 743: int prev;
! 744:
! 745: prev = (env->fpscr >> bit) & 1;
! 746: env->fpscr |= 1 << bit;
! 747: if (prev == 0) {
! 748: switch (bit) {
! 749: case FPSCR_VX:
! 750: env->fpscr |= 1 << FPSCR_FX;
! 751: if (fpscr_ve)
! 752: goto raise_ve;
! 753: case FPSCR_OX:
! 754: env->fpscr |= 1 << FPSCR_FX;
! 755: if (fpscr_oe)
! 756: goto raise_oe;
! 757: break;
! 758: case FPSCR_UX:
! 759: env->fpscr |= 1 << FPSCR_FX;
! 760: if (fpscr_ue)
! 761: goto raise_ue;
! 762: break;
! 763: case FPSCR_ZX:
! 764: env->fpscr |= 1 << FPSCR_FX;
! 765: if (fpscr_ze)
! 766: goto raise_ze;
! 767: break;
! 768: case FPSCR_XX:
! 769: env->fpscr |= 1 << FPSCR_FX;
! 770: if (fpscr_xe)
! 771: goto raise_xe;
! 772: break;
! 773: case FPSCR_VXSNAN:
! 774: case FPSCR_VXISI:
! 775: case FPSCR_VXIDI:
! 776: case FPSCR_VXZDZ:
! 777: case FPSCR_VXIMZ:
! 778: case FPSCR_VXVC:
! 779: case FPSCR_VXSOFT:
! 780: case FPSCR_VXSQRT:
! 781: case FPSCR_VXCVI:
! 782: env->fpscr |= 1 << FPSCR_VX;
! 783: env->fpscr |= 1 << FPSCR_FX;
! 784: if (fpscr_ve != 0)
! 785: goto raise_ve;
! 786: break;
! 787: case FPSCR_VE:
! 788: if (fpscr_vx != 0) {
! 789: raise_ve:
! 790: env->error_code = POWERPC_EXCP_FP;
! 791: if (fpscr_vxsnan)
! 792: env->error_code |= POWERPC_EXCP_FP_VXSNAN;
! 793: if (fpscr_vxisi)
! 794: env->error_code |= POWERPC_EXCP_FP_VXISI;
! 795: if (fpscr_vxidi)
! 796: env->error_code |= POWERPC_EXCP_FP_VXIDI;
! 797: if (fpscr_vxzdz)
! 798: env->error_code |= POWERPC_EXCP_FP_VXZDZ;
! 799: if (fpscr_vximz)
! 800: env->error_code |= POWERPC_EXCP_FP_VXIMZ;
! 801: if (fpscr_vxvc)
! 802: env->error_code |= POWERPC_EXCP_FP_VXVC;
! 803: if (fpscr_vxsoft)
! 804: env->error_code |= POWERPC_EXCP_FP_VXSOFT;
! 805: if (fpscr_vxsqrt)
! 806: env->error_code |= POWERPC_EXCP_FP_VXSQRT;
! 807: if (fpscr_vxcvi)
! 808: env->error_code |= POWERPC_EXCP_FP_VXCVI;
! 809: goto raise_excp;
! 810: }
! 811: break;
! 812: case FPSCR_OE:
! 813: if (fpscr_ox != 0) {
! 814: raise_oe:
! 815: env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
! 816: goto raise_excp;
! 817: }
! 818: break;
! 819: case FPSCR_UE:
! 820: if (fpscr_ux != 0) {
! 821: raise_ue:
! 822: env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
! 823: goto raise_excp;
! 824: }
! 825: break;
! 826: case FPSCR_ZE:
! 827: if (fpscr_zx != 0) {
! 828: raise_ze:
! 829: env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX;
! 830: goto raise_excp;
! 831: }
! 832: break;
! 833: case FPSCR_XE:
! 834: if (fpscr_xx != 0) {
! 835: raise_xe:
! 836: env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
! 837: goto raise_excp;
! 838: }
! 839: break;
! 840: case FPSCR_RN1:
! 841: case FPSCR_RN:
! 842: fpscr_set_rounding_mode();
! 843: break;
! 844: default:
! 845: break;
! 846: raise_excp:
! 847: /* Update the floating-point enabled exception summary */
! 848: env->fpscr |= 1 << FPSCR_FEX;
! 849: /* We have to update Rc1 before raising the exception */
! 850: env->exception_index = POWERPC_EXCP_PROGRAM;
! 851: break;
1.1 root 852: }
853: }
854: }
855:
1.1.1.3 ! root 856: #if defined(WORDS_BIGENDIAN)
! 857: #define WORD0 0
! 858: #define WORD1 1
! 859: #else
! 860: #define WORD0 1
! 861: #define WORD1 0
! 862: #endif
! 863: void do_store_fpscr (uint32_t mask)
1.1 root 864: {
1.1.1.3 ! root 865: /*
! 866: * We use only the 32 LSB of the incoming fpr
! 867: */
! 868: union {
! 869: double d;
! 870: struct {
! 871: uint32_t u[2];
! 872: } s;
! 873: } u;
! 874: uint32_t prev, new;
! 875: int i;
! 876:
! 877: u.d = FT0;
! 878: prev = env->fpscr;
! 879: new = u.s.u[WORD1];
! 880: new &= ~0x90000000;
! 881: new |= prev & 0x90000000;
! 882: for (i = 0; i < 7; i++) {
! 883: if (mask & (1 << i)) {
! 884: env->fpscr &= ~(0xF << (4 * i));
! 885: env->fpscr |= new & (0xF << (4 * i));
! 886: }
! 887: }
! 888: /* Update VX and FEX */
! 889: if (fpscr_ix != 0)
! 890: env->fpscr |= 1 << FPSCR_VX;
! 891: if ((fpscr_ex & fpscr_eex) != 0) {
! 892: env->fpscr |= 1 << FPSCR_FEX;
! 893: env->exception_index = POWERPC_EXCP_PROGRAM;
! 894: /* XXX: we should compute it properly */
! 895: env->error_code = POWERPC_EXCP_FP;
! 896: }
! 897: fpscr_set_rounding_mode();
! 898: }
! 899: #undef WORD0
! 900: #undef WORD1
! 901:
! 902: #ifdef CONFIG_SOFTFLOAT
! 903: void do_float_check_status (void)
! 904: {
! 905: if (env->exception_index == POWERPC_EXCP_PROGRAM &&
! 906: (env->error_code & POWERPC_EXCP_FP)) {
! 907: /* Differred floating-point exception after target FPR update */
! 908: if (msr_fe0 != 0 || msr_fe1 != 0)
! 909: do_raise_exception_err(env->exception_index, env->error_code);
! 910: } else if (env->fp_status.float_exception_flags & float_flag_overflow) {
! 911: float_overflow_excp();
! 912: } else if (env->fp_status.float_exception_flags & float_flag_underflow) {
! 913: float_underflow_excp();
! 914: } else if (env->fp_status.float_exception_flags & float_flag_inexact) {
! 915: float_inexact_excp();
! 916: }
! 917: }
! 918: #endif
! 919:
! 920: #if USE_PRECISE_EMULATION
! 921: void do_fadd (void)
! 922: {
! 923: if (unlikely(float64_is_signaling_nan(FT0) ||
! 924: float64_is_signaling_nan(FT1))) {
! 925: /* sNaN addition */
! 926: fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
! 927: } else if (likely(isfinite(FT0) || isfinite(FT1) ||
! 928: fpisneg(FT0) == fpisneg(FT1))) {
! 929: FT0 = float64_add(FT0, FT1, &env->fp_status);
! 930: } else {
! 931: /* Magnitude subtraction of infinities */
! 932: fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
! 933: }
! 934: }
! 935:
! 936: void do_fsub (void)
! 937: {
! 938: if (unlikely(float64_is_signaling_nan(FT0) ||
! 939: float64_is_signaling_nan(FT1))) {
! 940: /* sNaN subtraction */
! 941: fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
! 942: } else if (likely(isfinite(FT0) || isfinite(FT1) ||
! 943: fpisneg(FT0) != fpisneg(FT1))) {
! 944: FT0 = float64_sub(FT0, FT1, &env->fp_status);
! 945: } else {
! 946: /* Magnitude subtraction of infinities */
! 947: fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
! 948: }
! 949: }
! 950:
! 951: void do_fmul (void)
! 952: {
! 953: if (unlikely(float64_is_signaling_nan(FT0) ||
! 954: float64_is_signaling_nan(FT1))) {
! 955: /* sNaN multiplication */
! 956: fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
! 957: } else if (unlikely((isinfinity(FT0) && iszero(FT1)) ||
! 958: (iszero(FT0) && isinfinity(FT1)))) {
! 959: /* Multiplication of zero by infinity */
! 960: fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
! 961: } else {
! 962: FT0 = float64_mul(FT0, FT1, &env->fp_status);
! 963: }
! 964: }
! 965:
! 966: void do_fdiv (void)
! 967: {
! 968: if (unlikely(float64_is_signaling_nan(FT0) ||
! 969: float64_is_signaling_nan(FT1))) {
! 970: /* sNaN division */
! 971: fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
! 972: } else if (unlikely(isinfinity(FT0) && isinfinity(FT1))) {
! 973: /* Division of infinity by infinity */
! 974: fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
! 975: } else if (unlikely(iszero(FT1))) {
! 976: if (iszero(FT0)) {
! 977: /* Division of zero by zero */
! 978: fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
! 979: } else {
! 980: /* Division by zero */
! 981: float_zero_divide_excp();
! 982: }
! 983: } else {
! 984: FT0 = float64_div(FT0, FT1, &env->fp_status);
! 985: }
! 986: }
! 987: #endif /* USE_PRECISE_EMULATION */
! 988:
! 989: void do_fctiw (void)
! 990: {
! 991: union {
! 992: double d;
! 993: uint64_t i;
! 994: } p;
! 995:
! 996: if (unlikely(float64_is_signaling_nan(FT0))) {
! 997: /* sNaN conversion */
! 998: fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
! 999: } else if (unlikely(float64_is_nan(FT0) || isinfinity(FT0))) {
! 1000: /* qNan / infinity conversion */
! 1001: fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
! 1002: } else {
! 1003: p.i = float64_to_int32(FT0, &env->fp_status);
! 1004: #if USE_PRECISE_EMULATION
! 1005: /* XXX: higher bits are not supposed to be significant.
! 1006: * to make tests easier, return the same as a real PowerPC 750
! 1007: */
! 1008: p.i |= 0xFFF80000ULL << 32;
! 1009: #endif
! 1010: FT0 = p.d;
! 1011: }
! 1012: }
! 1013:
! 1014: void do_fctiwz (void)
! 1015: {
! 1016: union {
! 1017: double d;
! 1018: uint64_t i;
! 1019: } p;
! 1020:
! 1021: if (unlikely(float64_is_signaling_nan(FT0))) {
! 1022: /* sNaN conversion */
! 1023: fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
! 1024: } else if (unlikely(float64_is_nan(FT0) || isinfinity(FT0))) {
! 1025: /* qNan / infinity conversion */
! 1026: fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
! 1027: } else {
! 1028: p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status);
! 1029: #if USE_PRECISE_EMULATION
! 1030: /* XXX: higher bits are not supposed to be significant.
! 1031: * to make tests easier, return the same as a real PowerPC 750
! 1032: */
! 1033: p.i |= 0xFFF80000ULL << 32;
! 1034: #endif
! 1035: FT0 = p.d;
! 1036: }
! 1037: }
! 1038:
! 1039: #if defined(TARGET_PPC64)
! 1040: void do_fcfid (void)
! 1041: {
! 1042: union {
! 1043: double d;
! 1044: uint64_t i;
! 1045: } p;
! 1046:
! 1047: p.d = FT0;
! 1048: FT0 = int64_to_float64(p.i, &env->fp_status);
! 1049: }
! 1050:
! 1051: void do_fctid (void)
! 1052: {
! 1053: union {
! 1054: double d;
! 1055: uint64_t i;
! 1056: } p;
! 1057:
! 1058: if (unlikely(float64_is_signaling_nan(FT0))) {
! 1059: /* sNaN conversion */
! 1060: fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
! 1061: } else if (unlikely(float64_is_nan(FT0) || isinfinity(FT0))) {
! 1062: /* qNan / infinity conversion */
! 1063: fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
! 1064: } else {
! 1065: p.i = float64_to_int64(FT0, &env->fp_status);
! 1066: FT0 = p.d;
! 1067: }
! 1068: }
! 1069:
! 1070: void do_fctidz (void)
! 1071: {
! 1072: union {
! 1073: double d;
! 1074: uint64_t i;
! 1075: } p;
! 1076:
! 1077: if (unlikely(float64_is_signaling_nan(FT0))) {
! 1078: /* sNaN conversion */
! 1079: fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
! 1080: } else if (unlikely(float64_is_nan(FT0) || isinfinity(FT0))) {
! 1081: /* qNan / infinity conversion */
! 1082: fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
! 1083: } else {
! 1084: p.i = float64_to_int64_round_to_zero(FT0, &env->fp_status);
! 1085: FT0 = p.d;
! 1086: }
! 1087: }
! 1088:
! 1089: #endif
! 1090:
! 1091: static always_inline void do_fri (int rounding_mode)
! 1092: {
! 1093: if (unlikely(float64_is_signaling_nan(FT0))) {
! 1094: /* sNaN round */
! 1095: fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
! 1096: } else if (unlikely(float64_is_nan(FT0) || isinfinity(FT0))) {
! 1097: /* qNan / infinity round */
! 1098: fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
! 1099: } else {
! 1100: set_float_rounding_mode(rounding_mode, &env->fp_status);
! 1101: FT0 = float64_round_to_int(FT0, &env->fp_status);
! 1102: /* Restore rounding mode from FPSCR */
! 1103: fpscr_set_rounding_mode();
! 1104: }
! 1105: }
! 1106:
! 1107: void do_frin (void)
! 1108: {
! 1109: do_fri(float_round_nearest_even);
! 1110: }
! 1111:
! 1112: void do_friz (void)
! 1113: {
! 1114: do_fri(float_round_to_zero);
! 1115: }
! 1116:
! 1117: void do_frip (void)
! 1118: {
! 1119: do_fri(float_round_up);
! 1120: }
! 1121:
! 1122: void do_frim (void)
! 1123: {
! 1124: do_fri(float_round_down);
! 1125: }
! 1126:
! 1127: #if USE_PRECISE_EMULATION
! 1128: void do_fmadd (void)
! 1129: {
! 1130: if (unlikely(float64_is_signaling_nan(FT0) ||
! 1131: float64_is_signaling_nan(FT1) ||
! 1132: float64_is_signaling_nan(FT2))) {
! 1133: /* sNaN operation */
! 1134: fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
! 1135: } else {
! 1136: #ifdef FLOAT128
! 1137: /* This is the way the PowerPC specification defines it */
! 1138: float128 ft0_128, ft1_128;
! 1139:
! 1140: ft0_128 = float64_to_float128(FT0, &env->fp_status);
! 1141: ft1_128 = float64_to_float128(FT1, &env->fp_status);
! 1142: ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
! 1143: ft1_128 = float64_to_float128(FT2, &env->fp_status);
! 1144: ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
! 1145: FT0 = float128_to_float64(ft0_128, &env->fp_status);
! 1146: #else
! 1147: /* This is OK on x86 hosts */
! 1148: FT0 = (FT0 * FT1) + FT2;
! 1149: #endif
! 1150: }
! 1151: }
! 1152:
! 1153: void do_fmsub (void)
! 1154: {
! 1155: if (unlikely(float64_is_signaling_nan(FT0) ||
! 1156: float64_is_signaling_nan(FT1) ||
! 1157: float64_is_signaling_nan(FT2))) {
! 1158: /* sNaN operation */
! 1159: fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
! 1160: } else {
! 1161: #ifdef FLOAT128
! 1162: /* This is the way the PowerPC specification defines it */
! 1163: float128 ft0_128, ft1_128;
! 1164:
! 1165: ft0_128 = float64_to_float128(FT0, &env->fp_status);
! 1166: ft1_128 = float64_to_float128(FT1, &env->fp_status);
! 1167: ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
! 1168: ft1_128 = float64_to_float128(FT2, &env->fp_status);
! 1169: ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
! 1170: FT0 = float128_to_float64(ft0_128, &env->fp_status);
! 1171: #else
! 1172: /* This is OK on x86 hosts */
! 1173: FT0 = (FT0 * FT1) - FT2;
! 1174: #endif
! 1175: }
! 1176: }
! 1177: #endif /* USE_PRECISE_EMULATION */
! 1178:
! 1179: void do_fnmadd (void)
! 1180: {
! 1181: if (unlikely(float64_is_signaling_nan(FT0) ||
! 1182: float64_is_signaling_nan(FT1) ||
! 1183: float64_is_signaling_nan(FT2))) {
! 1184: /* sNaN operation */
! 1185: fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
! 1186: } else {
! 1187: #if USE_PRECISE_EMULATION
! 1188: #ifdef FLOAT128
! 1189: /* This is the way the PowerPC specification defines it */
! 1190: float128 ft0_128, ft1_128;
! 1191:
! 1192: ft0_128 = float64_to_float128(FT0, &env->fp_status);
! 1193: ft1_128 = float64_to_float128(FT1, &env->fp_status);
! 1194: ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
! 1195: ft1_128 = float64_to_float128(FT2, &env->fp_status);
! 1196: ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
! 1197: FT0 = float128_to_float64(ft0_128, &env->fp_status);
! 1198: #else
! 1199: /* This is OK on x86 hosts */
! 1200: FT0 = (FT0 * FT1) + FT2;
! 1201: #endif
! 1202: #else
! 1203: FT0 = float64_mul(FT0, FT1, &env->fp_status);
! 1204: FT0 = float64_add(FT0, FT2, &env->fp_status);
! 1205: #endif
! 1206: if (likely(!isnan(FT0)))
! 1207: FT0 = float64_chs(FT0);
! 1208: }
! 1209: }
! 1210:
! 1211: void do_fnmsub (void)
! 1212: {
! 1213: if (unlikely(float64_is_signaling_nan(FT0) ||
! 1214: float64_is_signaling_nan(FT1) ||
! 1215: float64_is_signaling_nan(FT2))) {
! 1216: /* sNaN operation */
! 1217: fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
! 1218: } else {
! 1219: #if USE_PRECISE_EMULATION
! 1220: #ifdef FLOAT128
! 1221: /* This is the way the PowerPC specification defines it */
! 1222: float128 ft0_128, ft1_128;
! 1223:
! 1224: ft0_128 = float64_to_float128(FT0, &env->fp_status);
! 1225: ft1_128 = float64_to_float128(FT1, &env->fp_status);
! 1226: ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
! 1227: ft1_128 = float64_to_float128(FT2, &env->fp_status);
! 1228: ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
! 1229: FT0 = float128_to_float64(ft0_128, &env->fp_status);
! 1230: #else
! 1231: /* This is OK on x86 hosts */
! 1232: FT0 = (FT0 * FT1) - FT2;
! 1233: #endif
! 1234: #else
! 1235: FT0 = float64_mul(FT0, FT1, &env->fp_status);
! 1236: FT0 = float64_sub(FT0, FT2, &env->fp_status);
! 1237: #endif
! 1238: if (likely(!isnan(FT0)))
! 1239: FT0 = float64_chs(FT0);
! 1240: }
! 1241: }
! 1242:
! 1243: #if USE_PRECISE_EMULATION
! 1244: void do_frsp (void)
! 1245: {
! 1246: if (unlikely(float64_is_signaling_nan(FT0))) {
! 1247: /* sNaN square root */
! 1248: fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
! 1249: } else {
! 1250: FT0 = float64_to_float32(FT0, &env->fp_status);
! 1251: }
! 1252: }
! 1253: #endif /* USE_PRECISE_EMULATION */
! 1254:
! 1255: void do_fsqrt (void)
! 1256: {
! 1257: if (unlikely(float64_is_signaling_nan(FT0))) {
! 1258: /* sNaN square root */
! 1259: fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
! 1260: } else if (unlikely(fpisneg(FT0) && !iszero(FT0))) {
! 1261: /* Square root of a negative nonzero number */
! 1262: fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
! 1263: } else {
! 1264: FT0 = float64_sqrt(FT0, &env->fp_status);
! 1265: }
! 1266: }
! 1267:
! 1268: void do_fre (void)
! 1269: {
! 1270: union {
! 1271: double d;
! 1272: uint64_t i;
! 1273: } p;
! 1274:
! 1275: if (unlikely(float64_is_signaling_nan(FT0))) {
! 1276: /* sNaN reciprocal */
! 1277: fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
! 1278: } else if (unlikely(iszero(FT0))) {
! 1279: /* Zero reciprocal */
! 1280: float_zero_divide_excp();
! 1281: } else if (likely(isnormal(FT0))) {
! 1282: FT0 = float64_div(1.0, FT0, &env->fp_status);
! 1283: } else {
! 1284: p.d = FT0;
! 1285: if (p.i == 0x8000000000000000ULL) {
! 1286: p.i = 0xFFF0000000000000ULL;
! 1287: } else if (p.i == 0x0000000000000000ULL) {
! 1288: p.i = 0x7FF0000000000000ULL;
! 1289: } else if (isnan(FT0)) {
! 1290: p.i = 0x7FF8000000000000ULL;
! 1291: } else if (fpisneg(FT0)) {
! 1292: p.i = 0x8000000000000000ULL;
! 1293: } else {
! 1294: p.i = 0x0000000000000000ULL;
! 1295: }
! 1296: FT0 = p.d;
! 1297: }
! 1298: }
! 1299:
! 1300: void do_fres (void)
! 1301: {
! 1302: union {
! 1303: double d;
! 1304: uint64_t i;
! 1305: } p;
! 1306:
! 1307: if (unlikely(float64_is_signaling_nan(FT0))) {
! 1308: /* sNaN reciprocal */
! 1309: fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
! 1310: } else if (unlikely(iszero(FT0))) {
! 1311: /* Zero reciprocal */
! 1312: float_zero_divide_excp();
! 1313: } else if (likely(isnormal(FT0))) {
! 1314: #if USE_PRECISE_EMULATION
! 1315: FT0 = float64_div(1.0, FT0, &env->fp_status);
! 1316: FT0 = float64_to_float32(FT0, &env->fp_status);
! 1317: #else
! 1318: FT0 = float32_div(1.0, FT0, &env->fp_status);
! 1319: #endif
! 1320: } else {
! 1321: p.d = FT0;
! 1322: if (p.i == 0x8000000000000000ULL) {
! 1323: p.i = 0xFFF0000000000000ULL;
! 1324: } else if (p.i == 0x0000000000000000ULL) {
! 1325: p.i = 0x7FF0000000000000ULL;
! 1326: } else if (isnan(FT0)) {
! 1327: p.i = 0x7FF8000000000000ULL;
! 1328: } else if (fpisneg(FT0)) {
! 1329: p.i = 0x8000000000000000ULL;
! 1330: } else {
! 1331: p.i = 0x0000000000000000ULL;
! 1332: }
! 1333: FT0 = p.d;
! 1334: }
! 1335: }
! 1336:
! 1337: void do_frsqrte (void)
! 1338: {
! 1339: union {
! 1340: double d;
! 1341: uint64_t i;
! 1342: } p;
! 1343:
! 1344: if (unlikely(float64_is_signaling_nan(FT0))) {
! 1345: /* sNaN reciprocal square root */
! 1346: fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
! 1347: } else if (unlikely(fpisneg(FT0) && !iszero(FT0))) {
! 1348: /* Reciprocal square root of a negative nonzero number */
! 1349: fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
! 1350: } else if (likely(isnormal(FT0))) {
! 1351: FT0 = float64_sqrt(FT0, &env->fp_status);
! 1352: FT0 = float32_div(1.0, FT0, &env->fp_status);
! 1353: } else {
! 1354: p.d = FT0;
! 1355: if (p.i == 0x8000000000000000ULL) {
! 1356: p.i = 0xFFF0000000000000ULL;
! 1357: } else if (p.i == 0x0000000000000000ULL) {
! 1358: p.i = 0x7FF0000000000000ULL;
! 1359: } else if (isnan(FT0)) {
! 1360: p.i |= 0x000FFFFFFFFFFFFFULL;
! 1361: } else if (fpisneg(FT0)) {
! 1362: p.i = 0x7FF8000000000000ULL;
! 1363: } else {
! 1364: p.i = 0x0000000000000000ULL;
! 1365: }
! 1366: FT0 = p.d;
! 1367: }
! 1368: }
! 1369:
! 1370: void do_fsel (void)
! 1371: {
! 1372: if (!fpisneg(FT0) || iszero(FT0))
! 1373: FT0 = FT1;
1.1 root 1374: else
1375: FT0 = FT2;
1376: }
1377:
1.1.1.3 ! root 1378: void do_fcmpu (void)
! 1379: {
! 1380: if (unlikely(float64_is_signaling_nan(FT0) ||
! 1381: float64_is_signaling_nan(FT1))) {
! 1382: /* sNaN comparison */
! 1383: fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
! 1384: } else {
! 1385: if (float64_lt(FT0, FT1, &env->fp_status)) {
! 1386: T0 = 0x08UL;
! 1387: } else if (!float64_le(FT0, FT1, &env->fp_status)) {
! 1388: T0 = 0x04UL;
! 1389: } else {
! 1390: T0 = 0x02UL;
! 1391: }
! 1392: }
! 1393: env->fpscr &= ~(0x0F << FPSCR_FPRF);
! 1394: env->fpscr |= T0 << FPSCR_FPRF;
! 1395: }
! 1396:
! 1397: void do_fcmpo (void)
! 1398: {
! 1399: if (unlikely(float64_is_nan(FT0) ||
! 1400: float64_is_nan(FT1))) {
! 1401: if (float64_is_signaling_nan(FT0) ||
! 1402: float64_is_signaling_nan(FT1)) {
! 1403: /* sNaN comparison */
! 1404: fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
! 1405: POWERPC_EXCP_FP_VXVC);
! 1406: } else {
! 1407: /* qNaN comparison */
! 1408: fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
! 1409: }
! 1410: } else {
! 1411: if (float64_lt(FT0, FT1, &env->fp_status)) {
! 1412: T0 = 0x08UL;
! 1413: } else if (!float64_le(FT0, FT1, &env->fp_status)) {
! 1414: T0 = 0x04UL;
! 1415: } else {
! 1416: T0 = 0x02UL;
! 1417: }
! 1418: }
! 1419: env->fpscr &= ~(0x0F << FPSCR_FPRF);
! 1420: env->fpscr |= T0 << FPSCR_FPRF;
! 1421: }
! 1422:
! 1423: #if !defined (CONFIG_USER_ONLY)
! 1424: void cpu_dump_rfi (target_ulong RA, target_ulong msr);
! 1425:
! 1426: void do_store_msr (void)
! 1427: {
! 1428: T0 = hreg_store_msr(env, T0, 0);
! 1429: if (T0 != 0) {
! 1430: env->interrupt_request |= CPU_INTERRUPT_EXITTB;
! 1431: do_raise_exception(T0);
! 1432: }
! 1433: }
! 1434:
! 1435: static always_inline void __do_rfi (target_ulong nip, target_ulong msr,
! 1436: target_ulong msrm, int keep_msrh)
! 1437: {
! 1438: #if defined(TARGET_PPC64)
! 1439: if (msr & (1ULL << MSR_SF)) {
! 1440: nip = (uint64_t)nip;
! 1441: msr &= (uint64_t)msrm;
! 1442: } else {
! 1443: nip = (uint32_t)nip;
! 1444: msr = (uint32_t)(msr & msrm);
! 1445: if (keep_msrh)
! 1446: msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
! 1447: }
! 1448: #else
! 1449: nip = (uint32_t)nip;
! 1450: msr &= (uint32_t)msrm;
! 1451: #endif
! 1452: /* XXX: beware: this is false if VLE is supported */
! 1453: env->nip = nip & ~((target_ulong)0x00000003);
! 1454: hreg_store_msr(env, msr, 1);
! 1455: #if defined (DEBUG_OP)
! 1456: cpu_dump_rfi(env->nip, env->msr);
! 1457: #endif
! 1458: /* No need to raise an exception here,
! 1459: * as rfi is always the last insn of a TB
! 1460: */
! 1461: env->interrupt_request |= CPU_INTERRUPT_EXITTB;
! 1462: }
! 1463:
! 1464: void do_rfi (void)
! 1465: {
! 1466: __do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
! 1467: ~((target_ulong)0xFFFF0000), 1);
! 1468: }
! 1469:
! 1470: #if defined(TARGET_PPC64)
! 1471: void do_rfid (void)
! 1472: {
! 1473: __do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
! 1474: ~((target_ulong)0xFFFF0000), 0);
! 1475: }
! 1476:
! 1477: void do_hrfid (void)
! 1478: {
! 1479: __do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
! 1480: ~((target_ulong)0xFFFF0000), 0);
! 1481: }
! 1482: #endif
! 1483: #endif
! 1484:
! 1485: void do_tw (int flags)
! 1486: {
! 1487: if (!likely(!(((int32_t)T0 < (int32_t)T1 && (flags & 0x10)) ||
! 1488: ((int32_t)T0 > (int32_t)T1 && (flags & 0x08)) ||
! 1489: ((int32_t)T0 == (int32_t)T1 && (flags & 0x04)) ||
! 1490: ((uint32_t)T0 < (uint32_t)T1 && (flags & 0x02)) ||
! 1491: ((uint32_t)T0 > (uint32_t)T1 && (flags & 0x01))))) {
! 1492: do_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
! 1493: }
! 1494: }
! 1495:
! 1496: #if defined(TARGET_PPC64)
! 1497: void do_td (int flags)
! 1498: {
! 1499: if (!likely(!(((int64_t)T0 < (int64_t)T1 && (flags & 0x10)) ||
! 1500: ((int64_t)T0 > (int64_t)T1 && (flags & 0x08)) ||
! 1501: ((int64_t)T0 == (int64_t)T1 && (flags & 0x04)) ||
! 1502: ((uint64_t)T0 < (uint64_t)T1 && (flags & 0x02)) ||
! 1503: ((uint64_t)T0 > (uint64_t)T1 && (flags & 0x01)))))
! 1504: do_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
! 1505: }
! 1506: #endif
! 1507:
! 1508: /*****************************************************************************/
! 1509: /* PowerPC 601 specific instructions (POWER bridge) */
! 1510: void do_POWER_abso (void)
! 1511: {
! 1512: if ((int32_t)T0 == INT32_MIN) {
! 1513: T0 = INT32_MAX;
! 1514: xer_ov = 1;
! 1515: } else if ((int32_t)T0 < 0) {
! 1516: T0 = -T0;
! 1517: xer_ov = 0;
! 1518: } else {
! 1519: xer_ov = 0;
! 1520: }
! 1521: xer_so |= xer_ov;
! 1522: }
! 1523:
! 1524: void do_POWER_clcs (void)
! 1525: {
! 1526: switch (T0) {
! 1527: case 0x0CUL:
! 1528: /* Instruction cache line size */
! 1529: T0 = env->icache_line_size;
! 1530: break;
! 1531: case 0x0DUL:
! 1532: /* Data cache line size */
! 1533: T0 = env->dcache_line_size;
! 1534: break;
! 1535: case 0x0EUL:
! 1536: /* Minimum cache line size */
! 1537: T0 = env->icache_line_size < env->dcache_line_size ?
! 1538: env->icache_line_size : env->dcache_line_size;
! 1539: break;
! 1540: case 0x0FUL:
! 1541: /* Maximum cache line size */
! 1542: T0 = env->icache_line_size > env->dcache_line_size ?
! 1543: env->icache_line_size : env->dcache_line_size;
! 1544: break;
! 1545: default:
! 1546: /* Undefined */
! 1547: break;
! 1548: }
! 1549: }
! 1550:
! 1551: void do_POWER_div (void)
! 1552: {
! 1553: uint64_t tmp;
! 1554:
! 1555: if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
! 1556: (int32_t)T1 == 0) {
! 1557: T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
! 1558: env->spr[SPR_MQ] = 0;
! 1559: } else {
! 1560: tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ];
! 1561: env->spr[SPR_MQ] = tmp % T1;
! 1562: T0 = tmp / (int32_t)T1;
! 1563: }
! 1564: }
! 1565:
! 1566: void do_POWER_divo (void)
! 1567: {
! 1568: int64_t tmp;
! 1569:
! 1570: if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
! 1571: (int32_t)T1 == 0) {
! 1572: T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
! 1573: env->spr[SPR_MQ] = 0;
! 1574: xer_ov = 1;
! 1575: } else {
! 1576: tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ];
! 1577: env->spr[SPR_MQ] = tmp % T1;
! 1578: tmp /= (int32_t)T1;
! 1579: if (tmp > (int64_t)INT32_MAX || tmp < (int64_t)INT32_MIN) {
! 1580: xer_ov = 1;
! 1581: } else {
! 1582: xer_ov = 0;
! 1583: }
! 1584: T0 = tmp;
! 1585: }
! 1586: xer_so |= xer_ov;
! 1587: }
! 1588:
! 1589: void do_POWER_divs (void)
! 1590: {
! 1591: if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
! 1592: (int32_t)T1 == 0) {
! 1593: T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
! 1594: env->spr[SPR_MQ] = 0;
! 1595: } else {
! 1596: env->spr[SPR_MQ] = T0 % T1;
! 1597: T0 = (int32_t)T0 / (int32_t)T1;
! 1598: }
! 1599: }
! 1600:
! 1601: void do_POWER_divso (void)
! 1602: {
! 1603: if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
! 1604: (int32_t)T1 == 0) {
! 1605: T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
! 1606: env->spr[SPR_MQ] = 0;
! 1607: xer_ov = 1;
! 1608: } else {
! 1609: T0 = (int32_t)T0 / (int32_t)T1;
! 1610: env->spr[SPR_MQ] = (int32_t)T0 % (int32_t)T1;
! 1611: xer_ov = 0;
! 1612: }
! 1613: xer_so |= xer_ov;
! 1614: }
! 1615:
! 1616: void do_POWER_dozo (void)
! 1617: {
! 1618: if ((int32_t)T1 > (int32_t)T0) {
! 1619: T2 = T0;
! 1620: T0 = T1 - T0;
! 1621: if (((uint32_t)(~T2) ^ (uint32_t)T1 ^ UINT32_MAX) &
! 1622: ((uint32_t)(~T2) ^ (uint32_t)T0) & (1UL << 31)) {
! 1623: xer_ov = 1;
! 1624: xer_so = 1;
! 1625: } else {
! 1626: xer_ov = 0;
! 1627: }
! 1628: } else {
! 1629: T0 = 0;
! 1630: xer_ov = 0;
! 1631: }
! 1632: }
! 1633:
! 1634: void do_POWER_maskg (void)
! 1635: {
! 1636: uint32_t ret;
! 1637:
! 1638: if ((uint32_t)T0 == (uint32_t)(T1 + 1)) {
! 1639: ret = UINT32_MAX;
! 1640: } else {
! 1641: ret = (UINT32_MAX >> ((uint32_t)T0)) ^
! 1642: ((UINT32_MAX >> ((uint32_t)T1)) >> 1);
! 1643: if ((uint32_t)T0 > (uint32_t)T1)
! 1644: ret = ~ret;
! 1645: }
! 1646: T0 = ret;
! 1647: }
! 1648:
! 1649: void do_POWER_mulo (void)
! 1650: {
! 1651: uint64_t tmp;
! 1652:
! 1653: tmp = (uint64_t)T0 * (uint64_t)T1;
! 1654: env->spr[SPR_MQ] = tmp >> 32;
! 1655: T0 = tmp;
! 1656: if (tmp >> 32 != ((uint64_t)T0 >> 16) * ((uint64_t)T1 >> 16)) {
! 1657: xer_ov = 1;
! 1658: xer_so = 1;
! 1659: } else {
! 1660: xer_ov = 0;
! 1661: }
! 1662: }
! 1663:
! 1664: #if !defined (CONFIG_USER_ONLY)
! 1665: void do_POWER_rac (void)
! 1666: {
! 1667: mmu_ctx_t ctx;
! 1668: int nb_BATs;
! 1669:
! 1670: /* We don't have to generate many instances of this instruction,
! 1671: * as rac is supervisor only.
! 1672: */
! 1673: /* XXX: FIX THIS: Pretend we have no BAT */
! 1674: nb_BATs = env->nb_BATs;
! 1675: env->nb_BATs = 0;
! 1676: if (get_physical_address(env, &ctx, T0, 0, ACCESS_INT) == 0)
! 1677: T0 = ctx.raddr;
! 1678: env->nb_BATs = nb_BATs;
! 1679: }
! 1680:
! 1681: void do_POWER_rfsvc (void)
! 1682: {
! 1683: __do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
! 1684: }
! 1685:
! 1686: void do_store_hid0_601 (void)
! 1687: {
! 1688: uint32_t hid0;
! 1689:
! 1690: hid0 = env->spr[SPR_HID0];
! 1691: if ((T0 ^ hid0) & 0x00000008) {
! 1692: /* Change current endianness */
! 1693: env->hflags &= ~(1 << MSR_LE);
! 1694: env->hflags_nmsr &= ~(1 << MSR_LE);
! 1695: env->hflags_nmsr |= (1 << MSR_LE) & (((T0 >> 3) & 1) << MSR_LE);
! 1696: env->hflags |= env->hflags_nmsr;
! 1697: if (loglevel != 0) {
! 1698: fprintf(logfile, "%s: set endianness to %c => " ADDRX "\n",
! 1699: __func__, T0 & 0x8 ? 'l' : 'b', env->hflags);
! 1700: }
! 1701: }
! 1702: env->spr[SPR_HID0] = T0;
! 1703: }
! 1704: #endif
! 1705:
! 1706: /*****************************************************************************/
! 1707: /* 602 specific instructions */
! 1708: /* mfrom is the most crazy instruction ever seen, imho ! */
! 1709: /* Real implementation uses a ROM table. Do the same */
! 1710: #define USE_MFROM_ROM_TABLE
! 1711: void do_op_602_mfrom (void)
! 1712: {
! 1713: if (likely(T0 < 602)) {
! 1714: #if defined(USE_MFROM_ROM_TABLE)
! 1715: #include "mfrom_table.c"
! 1716: T0 = mfrom_ROM_table[T0];
! 1717: #else
! 1718: double d;
! 1719: /* Extremly decomposed:
! 1720: * -T0 / 256
! 1721: * T0 = 256 * log10(10 + 1.0) + 0.5
! 1722: */
! 1723: d = T0;
! 1724: d = float64_div(d, 256, &env->fp_status);
! 1725: d = float64_chs(d);
! 1726: d = exp10(d); // XXX: use float emulation function
! 1727: d = float64_add(d, 1.0, &env->fp_status);
! 1728: d = log10(d); // XXX: use float emulation function
! 1729: d = float64_mul(d, 256, &env->fp_status);
! 1730: d = float64_add(d, 0.5, &env->fp_status);
! 1731: T0 = float64_round_to_int(d, &env->fp_status);
! 1732: #endif
! 1733: } else {
! 1734: T0 = 0;
! 1735: }
! 1736: }
! 1737:
! 1738: /*****************************************************************************/
! 1739: /* Embedded PowerPC specific helpers */
! 1740: void do_405_check_sat (void)
! 1741: {
! 1742: if (!likely((((uint32_t)T1 ^ (uint32_t)T2) >> 31) ||
! 1743: !(((uint32_t)T0 ^ (uint32_t)T2) >> 31))) {
! 1744: /* Saturate result */
! 1745: if (T2 >> 31) {
! 1746: T0 = INT32_MIN;
! 1747: } else {
! 1748: T0 = INT32_MAX;
! 1749: }
! 1750: }
! 1751: }
! 1752:
! 1753: /* XXX: to be improved to check access rights when in user-mode */
! 1754: void do_load_dcr (void)
! 1755: {
! 1756: target_ulong val;
! 1757:
! 1758: if (unlikely(env->dcr_env == NULL)) {
! 1759: if (loglevel != 0) {
! 1760: fprintf(logfile, "No DCR environment\n");
! 1761: }
! 1762: do_raise_exception_err(POWERPC_EXCP_PROGRAM,
! 1763: POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
! 1764: } else if (unlikely(ppc_dcr_read(env->dcr_env, T0, &val) != 0)) {
! 1765: if (loglevel != 0) {
! 1766: fprintf(logfile, "DCR read error %d %03x\n", (int)T0, (int)T0);
! 1767: }
! 1768: do_raise_exception_err(POWERPC_EXCP_PROGRAM,
! 1769: POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
! 1770: } else {
! 1771: T0 = val;
! 1772: }
! 1773: }
! 1774:
! 1775: void do_store_dcr (void)
! 1776: {
! 1777: if (unlikely(env->dcr_env == NULL)) {
! 1778: if (loglevel != 0) {
! 1779: fprintf(logfile, "No DCR environment\n");
! 1780: }
! 1781: do_raise_exception_err(POWERPC_EXCP_PROGRAM,
! 1782: POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
! 1783: } else if (unlikely(ppc_dcr_write(env->dcr_env, T0, T1) != 0)) {
! 1784: if (loglevel != 0) {
! 1785: fprintf(logfile, "DCR write error %d %03x\n", (int)T0, (int)T0);
! 1786: }
! 1787: do_raise_exception_err(POWERPC_EXCP_PROGRAM,
! 1788: POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
! 1789: }
! 1790: }
! 1791:
! 1792: #if !defined(CONFIG_USER_ONLY)
! 1793: void do_40x_rfci (void)
! 1794: {
! 1795: __do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
! 1796: ~((target_ulong)0xFFFF0000), 0);
! 1797: }
! 1798:
! 1799: void do_rfci (void)
! 1800: {
! 1801: __do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
! 1802: ~((target_ulong)0x3FFF0000), 0);
! 1803: }
! 1804:
! 1805: void do_rfdi (void)
! 1806: {
! 1807: __do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
! 1808: ~((target_ulong)0x3FFF0000), 0);
! 1809: }
! 1810:
! 1811: void do_rfmci (void)
! 1812: {
! 1813: __do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
! 1814: ~((target_ulong)0x3FFF0000), 0);
! 1815: }
! 1816:
! 1817: void do_load_403_pb (int num)
! 1818: {
! 1819: T0 = env->pb[num];
! 1820: }
! 1821:
! 1822: void do_store_403_pb (int num)
! 1823: {
! 1824: if (likely(env->pb[num] != T0)) {
! 1825: env->pb[num] = T0;
! 1826: /* Should be optimized */
! 1827: tlb_flush(env, 1);
! 1828: }
! 1829: }
! 1830: #endif
! 1831:
! 1832: /* 440 specific */
! 1833: void do_440_dlmzb (void)
! 1834: {
! 1835: target_ulong mask;
! 1836: int i;
! 1837:
! 1838: i = 1;
! 1839: for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
! 1840: if ((T0 & mask) == 0)
! 1841: goto done;
! 1842: i++;
! 1843: }
! 1844: for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
! 1845: if ((T1 & mask) == 0)
! 1846: break;
! 1847: i++;
! 1848: }
! 1849: done:
! 1850: T0 = i;
! 1851: }
! 1852:
! 1853: /* SPE extension helpers */
! 1854: /* Use a table to make this quicker */
! 1855: static uint8_t hbrev[16] = {
! 1856: 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
! 1857: 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
! 1858: };
! 1859:
! 1860: static always_inline uint8_t byte_reverse (uint8_t val)
! 1861: {
! 1862: return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
! 1863: }
! 1864:
! 1865: static always_inline uint32_t word_reverse (uint32_t val)
! 1866: {
! 1867: return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
! 1868: (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
! 1869: }
! 1870:
! 1871: #define MASKBITS 16 // Random value - to be fixed (implementation dependant)
! 1872: void do_brinc (void)
! 1873: {
! 1874: uint32_t a, b, d, mask;
! 1875:
! 1876: mask = UINT32_MAX >> (32 - MASKBITS);
! 1877: a = T0 & mask;
! 1878: b = T1 & mask;
! 1879: d = word_reverse(1 + word_reverse(a | ~b));
! 1880: T0 = (T0 & ~mask) | (d & b);
! 1881: }
! 1882:
! 1883: #define DO_SPE_OP2(name) \
! 1884: void do_ev##name (void) \
! 1885: { \
! 1886: T0_64 = ((uint64_t)_do_e##name(T0_64 >> 32, T1_64 >> 32) << 32) | \
! 1887: (uint64_t)_do_e##name(T0_64, T1_64); \
! 1888: }
! 1889:
! 1890: #define DO_SPE_OP1(name) \
! 1891: void do_ev##name (void) \
! 1892: { \
! 1893: T0_64 = ((uint64_t)_do_e##name(T0_64 >> 32) << 32) | \
! 1894: (uint64_t)_do_e##name(T0_64); \
! 1895: }
! 1896:
! 1897: /* Fixed-point vector arithmetic */
! 1898: static always_inline uint32_t _do_eabs (uint32_t val)
! 1899: {
! 1900: if ((val & 0x80000000) && val != 0x80000000)
! 1901: val -= val;
! 1902:
! 1903: return val;
! 1904: }
! 1905:
! 1906: static always_inline uint32_t _do_eaddw (uint32_t op1, uint32_t op2)
! 1907: {
! 1908: return op1 + op2;
! 1909: }
! 1910:
! 1911: static always_inline int _do_ecntlsw (uint32_t val)
! 1912: {
! 1913: if (val & 0x80000000)
! 1914: return clz32(~val);
! 1915: else
! 1916: return clz32(val);
! 1917: }
! 1918:
! 1919: static always_inline int _do_ecntlzw (uint32_t val)
! 1920: {
! 1921: return clz32(val);
! 1922: }
! 1923:
! 1924: static always_inline uint32_t _do_eneg (uint32_t val)
! 1925: {
! 1926: if (val != 0x80000000)
! 1927: val -= val;
! 1928:
! 1929: return val;
! 1930: }
! 1931:
! 1932: static always_inline uint32_t _do_erlw (uint32_t op1, uint32_t op2)
! 1933: {
! 1934: return rotl32(op1, op2);
! 1935: }
! 1936:
! 1937: static always_inline uint32_t _do_erndw (uint32_t val)
! 1938: {
! 1939: return (val + 0x000080000000) & 0xFFFF0000;
! 1940: }
! 1941:
! 1942: static always_inline uint32_t _do_eslw (uint32_t op1, uint32_t op2)
! 1943: {
! 1944: /* No error here: 6 bits are used */
! 1945: return op1 << (op2 & 0x3F);
! 1946: }
! 1947:
! 1948: static always_inline int32_t _do_esrws (int32_t op1, uint32_t op2)
! 1949: {
! 1950: /* No error here: 6 bits are used */
! 1951: return op1 >> (op2 & 0x3F);
! 1952: }
! 1953:
! 1954: static always_inline uint32_t _do_esrwu (uint32_t op1, uint32_t op2)
! 1955: {
! 1956: /* No error here: 6 bits are used */
! 1957: return op1 >> (op2 & 0x3F);
! 1958: }
! 1959:
! 1960: static always_inline uint32_t _do_esubfw (uint32_t op1, uint32_t op2)
! 1961: {
! 1962: return op2 - op1;
! 1963: }
! 1964:
! 1965: /* evabs */
! 1966: DO_SPE_OP1(abs);
! 1967: /* evaddw */
! 1968: DO_SPE_OP2(addw);
! 1969: /* evcntlsw */
! 1970: DO_SPE_OP1(cntlsw);
! 1971: /* evcntlzw */
! 1972: DO_SPE_OP1(cntlzw);
! 1973: /* evneg */
! 1974: DO_SPE_OP1(neg);
! 1975: /* evrlw */
! 1976: DO_SPE_OP2(rlw);
! 1977: /* evrnd */
! 1978: DO_SPE_OP1(rndw);
! 1979: /* evslw */
! 1980: DO_SPE_OP2(slw);
! 1981: /* evsrws */
! 1982: DO_SPE_OP2(srws);
! 1983: /* evsrwu */
! 1984: DO_SPE_OP2(srwu);
! 1985: /* evsubfw */
! 1986: DO_SPE_OP2(subfw);
! 1987:
! 1988: /* evsel is a little bit more complicated... */
! 1989: static always_inline uint32_t _do_esel (uint32_t op1, uint32_t op2, int n)
! 1990: {
! 1991: if (n)
! 1992: return op1;
! 1993: else
! 1994: return op2;
! 1995: }
! 1996:
! 1997: void do_evsel (void)
! 1998: {
! 1999: T0_64 = ((uint64_t)_do_esel(T0_64 >> 32, T1_64 >> 32, T0 >> 3) << 32) |
! 2000: (uint64_t)_do_esel(T0_64, T1_64, (T0 >> 2) & 1);
! 2001: }
! 2002:
! 2003: /* Fixed-point vector comparisons */
! 2004: #define DO_SPE_CMP(name) \
! 2005: void do_ev##name (void) \
! 2006: { \
! 2007: T0 = _do_evcmp_merge((uint64_t)_do_e##name(T0_64 >> 32, \
! 2008: T1_64 >> 32) << 32, \
! 2009: _do_e##name(T0_64, T1_64)); \
! 2010: }
! 2011:
! 2012: static always_inline uint32_t _do_evcmp_merge (int t0, int t1)
! 2013: {
! 2014: return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
! 2015: }
! 2016: static always_inline int _do_ecmpeq (uint32_t op1, uint32_t op2)
! 2017: {
! 2018: return op1 == op2 ? 1 : 0;
! 2019: }
! 2020:
! 2021: static always_inline int _do_ecmpgts (int32_t op1, int32_t op2)
! 2022: {
! 2023: return op1 > op2 ? 1 : 0;
! 2024: }
! 2025:
! 2026: static always_inline int _do_ecmpgtu (uint32_t op1, uint32_t op2)
! 2027: {
! 2028: return op1 > op2 ? 1 : 0;
! 2029: }
! 2030:
! 2031: static always_inline int _do_ecmplts (int32_t op1, int32_t op2)
! 2032: {
! 2033: return op1 < op2 ? 1 : 0;
! 2034: }
! 2035:
! 2036: static always_inline int _do_ecmpltu (uint32_t op1, uint32_t op2)
! 2037: {
! 2038: return op1 < op2 ? 1 : 0;
! 2039: }
! 2040:
! 2041: /* evcmpeq */
! 2042: DO_SPE_CMP(cmpeq);
! 2043: /* evcmpgts */
! 2044: DO_SPE_CMP(cmpgts);
! 2045: /* evcmpgtu */
! 2046: DO_SPE_CMP(cmpgtu);
! 2047: /* evcmplts */
! 2048: DO_SPE_CMP(cmplts);
! 2049: /* evcmpltu */
! 2050: DO_SPE_CMP(cmpltu);
! 2051:
! 2052: /* Single precision floating-point conversions from/to integer */
! 2053: static always_inline uint32_t _do_efscfsi (int32_t val)
! 2054: {
! 2055: union {
! 2056: uint32_t u;
! 2057: float32 f;
! 2058: } u;
! 2059:
! 2060: u.f = int32_to_float32(val, &env->spe_status);
! 2061:
! 2062: return u.u;
! 2063: }
! 2064:
! 2065: static always_inline uint32_t _do_efscfui (uint32_t val)
! 2066: {
! 2067: union {
! 2068: uint32_t u;
! 2069: float32 f;
! 2070: } u;
! 2071:
! 2072: u.f = uint32_to_float32(val, &env->spe_status);
! 2073:
! 2074: return u.u;
! 2075: }
! 2076:
! 2077: static always_inline int32_t _do_efsctsi (uint32_t val)
! 2078: {
! 2079: union {
! 2080: int32_t u;
! 2081: float32 f;
! 2082: } u;
! 2083:
! 2084: u.u = val;
! 2085: /* NaN are not treated the same way IEEE 754 does */
! 2086: if (unlikely(isnan(u.f)))
! 2087: return 0;
! 2088:
! 2089: return float32_to_int32(u.f, &env->spe_status);
! 2090: }
! 2091:
! 2092: static always_inline uint32_t _do_efsctui (uint32_t val)
! 2093: {
! 2094: union {
! 2095: int32_t u;
! 2096: float32 f;
! 2097: } u;
! 2098:
! 2099: u.u = val;
! 2100: /* NaN are not treated the same way IEEE 754 does */
! 2101: if (unlikely(isnan(u.f)))
! 2102: return 0;
! 2103:
! 2104: return float32_to_uint32(u.f, &env->spe_status);
! 2105: }
! 2106:
! 2107: static always_inline int32_t _do_efsctsiz (uint32_t val)
! 2108: {
! 2109: union {
! 2110: int32_t u;
! 2111: float32 f;
! 2112: } u;
! 2113:
! 2114: u.u = val;
! 2115: /* NaN are not treated the same way IEEE 754 does */
! 2116: if (unlikely(isnan(u.f)))
! 2117: return 0;
! 2118:
! 2119: return float32_to_int32_round_to_zero(u.f, &env->spe_status);
! 2120: }
! 2121:
! 2122: static always_inline uint32_t _do_efsctuiz (uint32_t val)
! 2123: {
! 2124: union {
! 2125: int32_t u;
! 2126: float32 f;
! 2127: } u;
! 2128:
! 2129: u.u = val;
! 2130: /* NaN are not treated the same way IEEE 754 does */
! 2131: if (unlikely(isnan(u.f)))
! 2132: return 0;
! 2133:
! 2134: return float32_to_uint32_round_to_zero(u.f, &env->spe_status);
! 2135: }
! 2136:
! 2137: void do_efscfsi (void)
! 2138: {
! 2139: T0_64 = _do_efscfsi(T0_64);
! 2140: }
! 2141:
! 2142: void do_efscfui (void)
! 2143: {
! 2144: T0_64 = _do_efscfui(T0_64);
! 2145: }
! 2146:
! 2147: void do_efsctsi (void)
! 2148: {
! 2149: T0_64 = _do_efsctsi(T0_64);
! 2150: }
! 2151:
! 2152: void do_efsctui (void)
! 2153: {
! 2154: T0_64 = _do_efsctui(T0_64);
! 2155: }
! 2156:
! 2157: void do_efsctsiz (void)
! 2158: {
! 2159: T0_64 = _do_efsctsiz(T0_64);
! 2160: }
! 2161:
! 2162: void do_efsctuiz (void)
! 2163: {
! 2164: T0_64 = _do_efsctuiz(T0_64);
! 2165: }
! 2166:
! 2167: /* Single precision floating-point conversion to/from fractional */
! 2168: static always_inline uint32_t _do_efscfsf (uint32_t val)
! 2169: {
! 2170: union {
! 2171: uint32_t u;
! 2172: float32 f;
! 2173: } u;
! 2174: float32 tmp;
! 2175:
! 2176: u.f = int32_to_float32(val, &env->spe_status);
! 2177: tmp = int64_to_float32(1ULL << 32, &env->spe_status);
! 2178: u.f = float32_div(u.f, tmp, &env->spe_status);
! 2179:
! 2180: return u.u;
! 2181: }
! 2182:
! 2183: static always_inline uint32_t _do_efscfuf (uint32_t val)
! 2184: {
! 2185: union {
! 2186: uint32_t u;
! 2187: float32 f;
! 2188: } u;
! 2189: float32 tmp;
! 2190:
! 2191: u.f = uint32_to_float32(val, &env->spe_status);
! 2192: tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
! 2193: u.f = float32_div(u.f, tmp, &env->spe_status);
! 2194:
! 2195: return u.u;
! 2196: }
! 2197:
! 2198: static always_inline int32_t _do_efsctsf (uint32_t val)
! 2199: {
! 2200: union {
! 2201: int32_t u;
! 2202: float32 f;
! 2203: } u;
! 2204: float32 tmp;
! 2205:
! 2206: u.u = val;
! 2207: /* NaN are not treated the same way IEEE 754 does */
! 2208: if (unlikely(isnan(u.f)))
! 2209: return 0;
! 2210: tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
! 2211: u.f = float32_mul(u.f, tmp, &env->spe_status);
! 2212:
! 2213: return float32_to_int32(u.f, &env->spe_status);
! 2214: }
! 2215:
! 2216: static always_inline uint32_t _do_efsctuf (uint32_t val)
! 2217: {
! 2218: union {
! 2219: int32_t u;
! 2220: float32 f;
! 2221: } u;
! 2222: float32 tmp;
! 2223:
! 2224: u.u = val;
! 2225: /* NaN are not treated the same way IEEE 754 does */
! 2226: if (unlikely(isnan(u.f)))
! 2227: return 0;
! 2228: tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
! 2229: u.f = float32_mul(u.f, tmp, &env->spe_status);
! 2230:
! 2231: return float32_to_uint32(u.f, &env->spe_status);
! 2232: }
! 2233:
! 2234: static always_inline int32_t _do_efsctsfz (uint32_t val)
! 2235: {
! 2236: union {
! 2237: int32_t u;
! 2238: float32 f;
! 2239: } u;
! 2240: float32 tmp;
! 2241:
! 2242: u.u = val;
! 2243: /* NaN are not treated the same way IEEE 754 does */
! 2244: if (unlikely(isnan(u.f)))
! 2245: return 0;
! 2246: tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
! 2247: u.f = float32_mul(u.f, tmp, &env->spe_status);
! 2248:
! 2249: return float32_to_int32_round_to_zero(u.f, &env->spe_status);
! 2250: }
! 2251:
! 2252: static always_inline uint32_t _do_efsctufz (uint32_t val)
! 2253: {
! 2254: union {
! 2255: int32_t u;
! 2256: float32 f;
! 2257: } u;
! 2258: float32 tmp;
! 2259:
! 2260: u.u = val;
! 2261: /* NaN are not treated the same way IEEE 754 does */
! 2262: if (unlikely(isnan(u.f)))
! 2263: return 0;
! 2264: tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
! 2265: u.f = float32_mul(u.f, tmp, &env->spe_status);
! 2266:
! 2267: return float32_to_uint32_round_to_zero(u.f, &env->spe_status);
! 2268: }
! 2269:
! 2270: void do_efscfsf (void)
! 2271: {
! 2272: T0_64 = _do_efscfsf(T0_64);
! 2273: }
! 2274:
! 2275: void do_efscfuf (void)
1.1 root 2276: {
1.1.1.3 ! root 2277: T0_64 = _do_efscfuf(T0_64);
1.1 root 2278: }
2279:
1.1.1.3 ! root 2280: void do_efsctsf (void)
1.1 root 2281: {
1.1.1.3 ! root 2282: T0_64 = _do_efsctsf(T0_64);
1.1 root 2283: }
2284:
1.1.1.3 ! root 2285: void do_efsctuf (void)
1.1 root 2286: {
1.1.1.3 ! root 2287: T0_64 = _do_efsctuf(T0_64);
1.1 root 2288: }
2289:
1.1.1.3 ! root 2290: void do_efsctsfz (void)
1.1 root 2291: {
1.1.1.3 ! root 2292: T0_64 = _do_efsctsfz(T0_64);
1.1 root 2293: }
2294:
1.1.1.3 ! root 2295: void do_efsctufz (void)
1.1 root 2296: {
1.1.1.3 ! root 2297: T0_64 = _do_efsctufz(T0_64);
1.1 root 2298: }
2299:
1.1.1.3 ! root 2300: /* Double precision floating point helpers */
! 2301: static always_inline int _do_efdcmplt (uint64_t op1, uint64_t op2)
1.1 root 2302: {
1.1.1.3 ! root 2303: /* XXX: TODO: test special values (NaN, infinites, ...) */
! 2304: return _do_efdtstlt(op1, op2);
! 2305: }
! 2306:
! 2307: static always_inline int _do_efdcmpgt (uint64_t op1, uint64_t op2)
! 2308: {
! 2309: /* XXX: TODO: test special values (NaN, infinites, ...) */
! 2310: return _do_efdtstgt(op1, op2);
! 2311: }
! 2312:
! 2313: static always_inline int _do_efdcmpeq (uint64_t op1, uint64_t op2)
! 2314: {
! 2315: /* XXX: TODO: test special values (NaN, infinites, ...) */
! 2316: return _do_efdtsteq(op1, op2);
! 2317: }
! 2318:
! 2319: void do_efdcmplt (void)
! 2320: {
! 2321: T0 = _do_efdcmplt(T0_64, T1_64);
! 2322: }
! 2323:
! 2324: void do_efdcmpgt (void)
! 2325: {
! 2326: T0 = _do_efdcmpgt(T0_64, T1_64);
! 2327: }
! 2328:
! 2329: void do_efdcmpeq (void)
! 2330: {
! 2331: T0 = _do_efdcmpeq(T0_64, T1_64);
! 2332: }
! 2333:
! 2334: /* Double precision floating-point conversion to/from integer */
! 2335: static always_inline uint64_t _do_efdcfsi (int64_t val)
! 2336: {
! 2337: union {
! 2338: uint64_t u;
! 2339: float64 f;
! 2340: } u;
! 2341:
! 2342: u.f = int64_to_float64(val, &env->spe_status);
! 2343:
! 2344: return u.u;
! 2345: }
! 2346:
! 2347: static always_inline uint64_t _do_efdcfui (uint64_t val)
! 2348: {
! 2349: union {
! 2350: uint64_t u;
! 2351: float64 f;
! 2352: } u;
! 2353:
! 2354: u.f = uint64_to_float64(val, &env->spe_status);
! 2355:
! 2356: return u.u;
! 2357: }
! 2358:
! 2359: static always_inline int64_t _do_efdctsi (uint64_t val)
! 2360: {
! 2361: union {
! 2362: int64_t u;
! 2363: float64 f;
! 2364: } u;
! 2365:
! 2366: u.u = val;
! 2367: /* NaN are not treated the same way IEEE 754 does */
! 2368: if (unlikely(isnan(u.f)))
! 2369: return 0;
! 2370:
! 2371: return float64_to_int64(u.f, &env->spe_status);
! 2372: }
! 2373:
! 2374: static always_inline uint64_t _do_efdctui (uint64_t val)
! 2375: {
! 2376: union {
! 2377: int64_t u;
! 2378: float64 f;
! 2379: } u;
! 2380:
! 2381: u.u = val;
! 2382: /* NaN are not treated the same way IEEE 754 does */
! 2383: if (unlikely(isnan(u.f)))
! 2384: return 0;
! 2385:
! 2386: return float64_to_uint64(u.f, &env->spe_status);
! 2387: }
! 2388:
! 2389: static always_inline int64_t _do_efdctsiz (uint64_t val)
! 2390: {
! 2391: union {
! 2392: int64_t u;
! 2393: float64 f;
! 2394: } u;
! 2395:
! 2396: u.u = val;
! 2397: /* NaN are not treated the same way IEEE 754 does */
! 2398: if (unlikely(isnan(u.f)))
! 2399: return 0;
! 2400:
! 2401: return float64_to_int64_round_to_zero(u.f, &env->spe_status);
! 2402: }
! 2403:
! 2404: static always_inline uint64_t _do_efdctuiz (uint64_t val)
! 2405: {
! 2406: union {
! 2407: int64_t u;
! 2408: float64 f;
! 2409: } u;
! 2410:
! 2411: u.u = val;
! 2412: /* NaN are not treated the same way IEEE 754 does */
! 2413: if (unlikely(isnan(u.f)))
! 2414: return 0;
! 2415:
! 2416: return float64_to_uint64_round_to_zero(u.f, &env->spe_status);
! 2417: }
! 2418:
! 2419: void do_efdcfsi (void)
! 2420: {
! 2421: T0_64 = _do_efdcfsi(T0_64);
! 2422: }
! 2423:
! 2424: void do_efdcfui (void)
! 2425: {
! 2426: T0_64 = _do_efdcfui(T0_64);
! 2427: }
! 2428:
! 2429: void do_efdctsi (void)
! 2430: {
! 2431: T0_64 = _do_efdctsi(T0_64);
! 2432: }
! 2433:
! 2434: void do_efdctui (void)
! 2435: {
! 2436: T0_64 = _do_efdctui(T0_64);
! 2437: }
! 2438:
! 2439: void do_efdctsiz (void)
! 2440: {
! 2441: T0_64 = _do_efdctsiz(T0_64);
! 2442: }
! 2443:
! 2444: void do_efdctuiz (void)
! 2445: {
! 2446: T0_64 = _do_efdctuiz(T0_64);
! 2447: }
! 2448:
! 2449: /* Double precision floating-point conversion to/from fractional */
! 2450: static always_inline uint64_t _do_efdcfsf (int64_t val)
! 2451: {
! 2452: union {
! 2453: uint64_t u;
! 2454: float64 f;
! 2455: } u;
! 2456: float64 tmp;
! 2457:
! 2458: u.f = int32_to_float64(val, &env->spe_status);
! 2459: tmp = int64_to_float64(1ULL << 32, &env->spe_status);
! 2460: u.f = float64_div(u.f, tmp, &env->spe_status);
! 2461:
! 2462: return u.u;
! 2463: }
! 2464:
! 2465: static always_inline uint64_t _do_efdcfuf (uint64_t val)
! 2466: {
! 2467: union {
! 2468: uint64_t u;
! 2469: float64 f;
! 2470: } u;
! 2471: float64 tmp;
! 2472:
! 2473: u.f = uint32_to_float64(val, &env->spe_status);
! 2474: tmp = int64_to_float64(1ULL << 32, &env->spe_status);
! 2475: u.f = float64_div(u.f, tmp, &env->spe_status);
! 2476:
! 2477: return u.u;
! 2478: }
! 2479:
! 2480: static always_inline int64_t _do_efdctsf (uint64_t val)
! 2481: {
! 2482: union {
! 2483: int64_t u;
! 2484: float64 f;
! 2485: } u;
! 2486: float64 tmp;
! 2487:
! 2488: u.u = val;
! 2489: /* NaN are not treated the same way IEEE 754 does */
! 2490: if (unlikely(isnan(u.f)))
! 2491: return 0;
! 2492: tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
! 2493: u.f = float64_mul(u.f, tmp, &env->spe_status);
! 2494:
! 2495: return float64_to_int32(u.f, &env->spe_status);
! 2496: }
! 2497:
! 2498: static always_inline uint64_t _do_efdctuf (uint64_t val)
! 2499: {
! 2500: union {
! 2501: int64_t u;
! 2502: float64 f;
! 2503: } u;
! 2504: float64 tmp;
! 2505:
! 2506: u.u = val;
! 2507: /* NaN are not treated the same way IEEE 754 does */
! 2508: if (unlikely(isnan(u.f)))
! 2509: return 0;
! 2510: tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
! 2511: u.f = float64_mul(u.f, tmp, &env->spe_status);
! 2512:
! 2513: return float64_to_uint32(u.f, &env->spe_status);
! 2514: }
! 2515:
! 2516: static always_inline int64_t _do_efdctsfz (uint64_t val)
! 2517: {
! 2518: union {
! 2519: int64_t u;
! 2520: float64 f;
! 2521: } u;
! 2522: float64 tmp;
! 2523:
! 2524: u.u = val;
! 2525: /* NaN are not treated the same way IEEE 754 does */
! 2526: if (unlikely(isnan(u.f)))
! 2527: return 0;
! 2528: tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
! 2529: u.f = float64_mul(u.f, tmp, &env->spe_status);
! 2530:
! 2531: return float64_to_int32_round_to_zero(u.f, &env->spe_status);
! 2532: }
! 2533:
! 2534: static always_inline uint64_t _do_efdctufz (uint64_t val)
! 2535: {
! 2536: union {
! 2537: int64_t u;
! 2538: float64 f;
! 2539: } u;
! 2540: float64 tmp;
! 2541:
! 2542: u.u = val;
! 2543: /* NaN are not treated the same way IEEE 754 does */
! 2544: if (unlikely(isnan(u.f)))
! 2545: return 0;
! 2546: tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
! 2547: u.f = float64_mul(u.f, tmp, &env->spe_status);
! 2548:
! 2549: return float64_to_uint32_round_to_zero(u.f, &env->spe_status);
! 2550: }
! 2551:
! 2552: void do_efdcfsf (void)
! 2553: {
! 2554: T0_64 = _do_efdcfsf(T0_64);
! 2555: }
! 2556:
! 2557: void do_efdcfuf (void)
! 2558: {
! 2559: T0_64 = _do_efdcfuf(T0_64);
! 2560: }
! 2561:
! 2562: void do_efdctsf (void)
! 2563: {
! 2564: T0_64 = _do_efdctsf(T0_64);
! 2565: }
! 2566:
! 2567: void do_efdctuf (void)
! 2568: {
! 2569: T0_64 = _do_efdctuf(T0_64);
! 2570: }
! 2571:
! 2572: void do_efdctsfz (void)
! 2573: {
! 2574: T0_64 = _do_efdctsfz(T0_64);
! 2575: }
! 2576:
! 2577: void do_efdctufz (void)
! 2578: {
! 2579: T0_64 = _do_efdctufz(T0_64);
! 2580: }
! 2581:
! 2582: /* Floating point conversion between single and double precision */
! 2583: static always_inline uint32_t _do_efscfd (uint64_t val)
! 2584: {
! 2585: union {
! 2586: uint64_t u;
! 2587: float64 f;
! 2588: } u1;
! 2589: union {
! 2590: uint32_t u;
! 2591: float32 f;
! 2592: } u2;
! 2593:
! 2594: u1.u = val;
! 2595: u2.f = float64_to_float32(u1.f, &env->spe_status);
! 2596:
! 2597: return u2.u;
! 2598: }
! 2599:
! 2600: static always_inline uint64_t _do_efdcfs (uint32_t val)
! 2601: {
! 2602: union {
! 2603: uint64_t u;
! 2604: float64 f;
! 2605: } u2;
! 2606: union {
! 2607: uint32_t u;
! 2608: float32 f;
! 2609: } u1;
! 2610:
! 2611: u1.u = val;
! 2612: u2.f = float32_to_float64(u1.f, &env->spe_status);
! 2613:
! 2614: return u2.u;
! 2615: }
! 2616:
! 2617: void do_efscfd (void)
! 2618: {
! 2619: T0_64 = _do_efscfd(T0_64);
! 2620: }
! 2621:
! 2622: void do_efdcfs (void)
! 2623: {
! 2624: T0_64 = _do_efdcfs(T0_64);
! 2625: }
! 2626:
! 2627: /* Single precision fixed-point vector arithmetic */
! 2628: /* evfsabs */
! 2629: DO_SPE_OP1(fsabs);
! 2630: /* evfsnabs */
! 2631: DO_SPE_OP1(fsnabs);
! 2632: /* evfsneg */
! 2633: DO_SPE_OP1(fsneg);
! 2634: /* evfsadd */
! 2635: DO_SPE_OP2(fsadd);
! 2636: /* evfssub */
! 2637: DO_SPE_OP2(fssub);
! 2638: /* evfsmul */
! 2639: DO_SPE_OP2(fsmul);
! 2640: /* evfsdiv */
! 2641: DO_SPE_OP2(fsdiv);
! 2642:
! 2643: /* Single-precision floating-point comparisons */
! 2644: static always_inline int _do_efscmplt (uint32_t op1, uint32_t op2)
! 2645: {
! 2646: /* XXX: TODO: test special values (NaN, infinites, ...) */
! 2647: return _do_efststlt(op1, op2);
! 2648: }
! 2649:
! 2650: static always_inline int _do_efscmpgt (uint32_t op1, uint32_t op2)
! 2651: {
! 2652: /* XXX: TODO: test special values (NaN, infinites, ...) */
! 2653: return _do_efststgt(op1, op2);
! 2654: }
! 2655:
! 2656: static always_inline int _do_efscmpeq (uint32_t op1, uint32_t op2)
! 2657: {
! 2658: /* XXX: TODO: test special values (NaN, infinites, ...) */
! 2659: return _do_efststeq(op1, op2);
! 2660: }
! 2661:
! 2662: void do_efscmplt (void)
! 2663: {
! 2664: T0 = _do_efscmplt(T0_64, T1_64);
! 2665: }
! 2666:
! 2667: void do_efscmpgt (void)
! 2668: {
! 2669: T0 = _do_efscmpgt(T0_64, T1_64);
! 2670: }
! 2671:
! 2672: void do_efscmpeq (void)
! 2673: {
! 2674: T0 = _do_efscmpeq(T0_64, T1_64);
1.1 root 2675: }
2676:
1.1.1.3 ! root 2677: /* Single-precision floating-point vector comparisons */
! 2678: /* evfscmplt */
! 2679: DO_SPE_CMP(fscmplt);
! 2680: /* evfscmpgt */
! 2681: DO_SPE_CMP(fscmpgt);
! 2682: /* evfscmpeq */
! 2683: DO_SPE_CMP(fscmpeq);
! 2684: /* evfststlt */
! 2685: DO_SPE_CMP(fststlt);
! 2686: /* evfststgt */
! 2687: DO_SPE_CMP(fststgt);
! 2688: /* evfststeq */
! 2689: DO_SPE_CMP(fststeq);
! 2690:
! 2691: /* Single-precision floating-point vector conversions */
! 2692: /* evfscfsi */
! 2693: DO_SPE_OP1(fscfsi);
! 2694: /* evfscfui */
! 2695: DO_SPE_OP1(fscfui);
! 2696: /* evfscfuf */
! 2697: DO_SPE_OP1(fscfuf);
! 2698: /* evfscfsf */
! 2699: DO_SPE_OP1(fscfsf);
! 2700: /* evfsctsi */
! 2701: DO_SPE_OP1(fsctsi);
! 2702: /* evfsctui */
! 2703: DO_SPE_OP1(fsctui);
! 2704: /* evfsctsiz */
! 2705: DO_SPE_OP1(fsctsiz);
! 2706: /* evfsctuiz */
! 2707: DO_SPE_OP1(fsctuiz);
! 2708: /* evfsctsf */
! 2709: DO_SPE_OP1(fsctsf);
! 2710: /* evfsctuf */
! 2711: DO_SPE_OP1(fsctuf);
! 2712:
1.1 root 2713: /*****************************************************************************/
2714: /* Softmmu support */
2715: #if !defined (CONFIG_USER_ONLY)
2716:
2717: #define MMUSUFFIX _mmu
1.1.1.3 ! root 2718: #ifdef __s390__
! 2719: # define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL))
! 2720: #else
! 2721: # define GETPC() (__builtin_return_address(0))
! 2722: #endif
1.1 root 2723:
2724: #define SHIFT 0
2725: #include "softmmu_template.h"
2726:
2727: #define SHIFT 1
2728: #include "softmmu_template.h"
2729:
2730: #define SHIFT 2
2731: #include "softmmu_template.h"
2732:
2733: #define SHIFT 3
2734: #include "softmmu_template.h"
2735:
2736: /* try to fill the TLB and return an exception if error. If retaddr is
2737: NULL, it means that the function was called in C code (i.e. not
2738: from generated code or from helper.c) */
2739: /* XXX: fix it to restore all registers */
1.1.1.3 ! root 2740: void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
1.1 root 2741: {
2742: TranslationBlock *tb;
2743: CPUState *saved_env;
1.1.1.3 ! root 2744: unsigned long pc;
1.1 root 2745: int ret;
2746:
2747: /* XXX: hack to restore env in all cases, even if not called from
2748: generated code */
2749: saved_env = env;
2750: env = cpu_single_env;
1.1.1.3 ! root 2751: ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
! 2752: if (unlikely(ret != 0)) {
1.1 root 2753: if (likely(retaddr)) {
2754: /* now we have a real cpu fault */
1.1.1.3 ! root 2755: pc = (unsigned long)retaddr;
1.1 root 2756: tb = tb_find_pc(pc);
2757: if (likely(tb)) {
2758: /* the PC is inside the translated code. It means that we have
2759: a virtual CPU fault */
2760: cpu_restore_state(tb, env, pc, NULL);
1.1.1.3 ! root 2761: }
1.1 root 2762: }
2763: do_raise_exception_err(env->exception_index, env->error_code);
2764: }
2765: env = saved_env;
2766: }
2767:
1.1.1.3 ! root 2768: /* Software driven TLBs management */
! 2769: /* PowerPC 602/603 software TLB load instructions helpers */
! 2770: void do_load_6xx_tlb (int is_code)
! 2771: {
! 2772: target_ulong RPN, CMP, EPN;
! 2773: int way;
! 2774:
! 2775: RPN = env->spr[SPR_RPA];
! 2776: if (is_code) {
! 2777: CMP = env->spr[SPR_ICMP];
! 2778: EPN = env->spr[SPR_IMISS];
! 2779: } else {
! 2780: CMP = env->spr[SPR_DCMP];
! 2781: EPN = env->spr[SPR_DMISS];
! 2782: }
! 2783: way = (env->spr[SPR_SRR1] >> 17) & 1;
! 2784: #if defined (DEBUG_SOFTWARE_TLB)
! 2785: if (loglevel != 0) {
! 2786: fprintf(logfile, "%s: EPN " TDX " " ADDRX " PTE0 " ADDRX
! 2787: " PTE1 " ADDRX " way %d\n",
! 2788: __func__, T0, EPN, CMP, RPN, way);
! 2789: }
! 2790: #endif
! 2791: /* Store this TLB */
! 2792: ppc6xx_tlb_store(env, (uint32_t)(T0 & TARGET_PAGE_MASK),
! 2793: way, is_code, CMP, RPN);
! 2794: }
! 2795:
! 2796: void do_load_74xx_tlb (int is_code)
! 2797: {
! 2798: target_ulong RPN, CMP, EPN;
! 2799: int way;
! 2800:
! 2801: RPN = env->spr[SPR_PTELO];
! 2802: CMP = env->spr[SPR_PTEHI];
! 2803: EPN = env->spr[SPR_TLBMISS] & ~0x3;
! 2804: way = env->spr[SPR_TLBMISS] & 0x3;
! 2805: #if defined (DEBUG_SOFTWARE_TLB)
! 2806: if (loglevel != 0) {
! 2807: fprintf(logfile, "%s: EPN " TDX " " ADDRX " PTE0 " ADDRX
! 2808: " PTE1 " ADDRX " way %d\n",
! 2809: __func__, T0, EPN, CMP, RPN, way);
! 2810: }
! 2811: #endif
! 2812: /* Store this TLB */
! 2813: ppc6xx_tlb_store(env, (uint32_t)(T0 & TARGET_PAGE_MASK),
! 2814: way, is_code, CMP, RPN);
! 2815: }
! 2816:
! 2817: static always_inline target_ulong booke_tlb_to_page_size (int size)
! 2818: {
! 2819: return 1024 << (2 * size);
! 2820: }
! 2821:
! 2822: static always_inline int booke_page_size_to_tlb (target_ulong page_size)
! 2823: {
! 2824: int size;
! 2825:
! 2826: switch (page_size) {
! 2827: case 0x00000400UL:
! 2828: size = 0x0;
! 2829: break;
! 2830: case 0x00001000UL:
! 2831: size = 0x1;
! 2832: break;
! 2833: case 0x00004000UL:
! 2834: size = 0x2;
! 2835: break;
! 2836: case 0x00010000UL:
! 2837: size = 0x3;
! 2838: break;
! 2839: case 0x00040000UL:
! 2840: size = 0x4;
! 2841: break;
! 2842: case 0x00100000UL:
! 2843: size = 0x5;
! 2844: break;
! 2845: case 0x00400000UL:
! 2846: size = 0x6;
! 2847: break;
! 2848: case 0x01000000UL:
! 2849: size = 0x7;
! 2850: break;
! 2851: case 0x04000000UL:
! 2852: size = 0x8;
! 2853: break;
! 2854: case 0x10000000UL:
! 2855: size = 0x9;
! 2856: break;
! 2857: case 0x40000000UL:
! 2858: size = 0xA;
! 2859: break;
! 2860: #if defined (TARGET_PPC64)
! 2861: case 0x000100000000ULL:
! 2862: size = 0xB;
! 2863: break;
! 2864: case 0x000400000000ULL:
! 2865: size = 0xC;
! 2866: break;
! 2867: case 0x001000000000ULL:
! 2868: size = 0xD;
! 2869: break;
! 2870: case 0x004000000000ULL:
! 2871: size = 0xE;
! 2872: break;
! 2873: case 0x010000000000ULL:
! 2874: size = 0xF;
! 2875: break;
! 2876: #endif
! 2877: default:
! 2878: size = -1;
! 2879: break;
! 2880: }
! 2881:
! 2882: return size;
! 2883: }
! 2884:
! 2885: /* Helpers for 4xx TLB management */
! 2886: void do_4xx_tlbre_lo (void)
! 2887: {
! 2888: ppcemb_tlb_t *tlb;
! 2889: int size;
! 2890:
! 2891: T0 &= 0x3F;
! 2892: tlb = &env->tlb[T0].tlbe;
! 2893: T0 = tlb->EPN;
! 2894: if (tlb->prot & PAGE_VALID)
! 2895: T0 |= 0x400;
! 2896: size = booke_page_size_to_tlb(tlb->size);
! 2897: if (size < 0 || size > 0x7)
! 2898: size = 1;
! 2899: T0 |= size << 7;
! 2900: env->spr[SPR_40x_PID] = tlb->PID;
! 2901: }
! 2902:
! 2903: void do_4xx_tlbre_hi (void)
! 2904: {
! 2905: ppcemb_tlb_t *tlb;
! 2906:
! 2907: T0 &= 0x3F;
! 2908: tlb = &env->tlb[T0].tlbe;
! 2909: T0 = tlb->RPN;
! 2910: if (tlb->prot & PAGE_EXEC)
! 2911: T0 |= 0x200;
! 2912: if (tlb->prot & PAGE_WRITE)
! 2913: T0 |= 0x100;
! 2914: }
! 2915:
! 2916: void do_4xx_tlbwe_hi (void)
! 2917: {
! 2918: ppcemb_tlb_t *tlb;
! 2919: target_ulong page, end;
! 2920:
! 2921: #if defined (DEBUG_SOFTWARE_TLB)
! 2922: if (loglevel != 0) {
! 2923: fprintf(logfile, "%s T0 " TDX " T1 " TDX "\n", __func__, T0, T1);
! 2924: }
! 2925: #endif
! 2926: T0 &= 0x3F;
! 2927: tlb = &env->tlb[T0].tlbe;
! 2928: /* Invalidate previous TLB (if it's valid) */
! 2929: if (tlb->prot & PAGE_VALID) {
! 2930: end = tlb->EPN + tlb->size;
! 2931: #if defined (DEBUG_SOFTWARE_TLB)
! 2932: if (loglevel != 0) {
! 2933: fprintf(logfile, "%s: invalidate old TLB %d start " ADDRX
! 2934: " end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end);
! 2935: }
! 2936: #endif
! 2937: for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
! 2938: tlb_flush_page(env, page);
! 2939: }
! 2940: tlb->size = booke_tlb_to_page_size((T1 >> 7) & 0x7);
! 2941: /* We cannot handle TLB size < TARGET_PAGE_SIZE.
! 2942: * If this ever occurs, one should use the ppcemb target instead
! 2943: * of the ppc or ppc64 one
! 2944: */
! 2945: if ((T1 & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
! 2946: cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
! 2947: "are not supported (%d)\n",
! 2948: tlb->size, TARGET_PAGE_SIZE, (int)((T1 >> 7) & 0x7));
! 2949: }
! 2950: tlb->EPN = T1 & ~(tlb->size - 1);
! 2951: if (T1 & 0x40)
! 2952: tlb->prot |= PAGE_VALID;
! 2953: else
! 2954: tlb->prot &= ~PAGE_VALID;
! 2955: if (T1 & 0x20) {
! 2956: /* XXX: TO BE FIXED */
! 2957: cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
! 2958: }
! 2959: tlb->PID = env->spr[SPR_40x_PID]; /* PID */
! 2960: tlb->attr = T1 & 0xFF;
! 2961: #if defined (DEBUG_SOFTWARE_TLB)
! 2962: if (loglevel != 0) {
! 2963: fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
! 2964: " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
! 2965: (int)T0, tlb->RPN, tlb->EPN, tlb->size,
! 2966: tlb->prot & PAGE_READ ? 'r' : '-',
! 2967: tlb->prot & PAGE_WRITE ? 'w' : '-',
! 2968: tlb->prot & PAGE_EXEC ? 'x' : '-',
! 2969: tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
! 2970: }
! 2971: #endif
! 2972: /* Invalidate new TLB (if valid) */
! 2973: if (tlb->prot & PAGE_VALID) {
! 2974: end = tlb->EPN + tlb->size;
! 2975: #if defined (DEBUG_SOFTWARE_TLB)
! 2976: if (loglevel != 0) {
! 2977: fprintf(logfile, "%s: invalidate TLB %d start " ADDRX
! 2978: " end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end);
! 2979: }
! 2980: #endif
! 2981: for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
! 2982: tlb_flush_page(env, page);
! 2983: }
! 2984: }
! 2985:
! 2986: void do_4xx_tlbwe_lo (void)
! 2987: {
! 2988: ppcemb_tlb_t *tlb;
! 2989:
! 2990: #if defined (DEBUG_SOFTWARE_TLB)
! 2991: if (loglevel != 0) {
! 2992: fprintf(logfile, "%s T0 " TDX " T1 " TDX "\n", __func__, T0, T1);
! 2993: }
! 2994: #endif
! 2995: T0 &= 0x3F;
! 2996: tlb = &env->tlb[T0].tlbe;
! 2997: tlb->RPN = T1 & 0xFFFFFC00;
! 2998: tlb->prot = PAGE_READ;
! 2999: if (T1 & 0x200)
! 3000: tlb->prot |= PAGE_EXEC;
! 3001: if (T1 & 0x100)
! 3002: tlb->prot |= PAGE_WRITE;
! 3003: #if defined (DEBUG_SOFTWARE_TLB)
! 3004: if (loglevel != 0) {
! 3005: fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
! 3006: " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
! 3007: (int)T0, tlb->RPN, tlb->EPN, tlb->size,
! 3008: tlb->prot & PAGE_READ ? 'r' : '-',
! 3009: tlb->prot & PAGE_WRITE ? 'w' : '-',
! 3010: tlb->prot & PAGE_EXEC ? 'x' : '-',
! 3011: tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
! 3012: }
! 3013: #endif
! 3014: }
! 3015:
! 3016: /* PowerPC 440 TLB management */
! 3017: void do_440_tlbwe (int word)
! 3018: {
! 3019: ppcemb_tlb_t *tlb;
! 3020: target_ulong EPN, RPN, size;
! 3021: int do_flush_tlbs;
! 3022:
! 3023: #if defined (DEBUG_SOFTWARE_TLB)
! 3024: if (loglevel != 0) {
! 3025: fprintf(logfile, "%s word %d T0 " TDX " T1 " TDX "\n",
! 3026: __func__, word, T0, T1);
! 3027: }
! 3028: #endif
! 3029: do_flush_tlbs = 0;
! 3030: T0 &= 0x3F;
! 3031: tlb = &env->tlb[T0].tlbe;
! 3032: switch (word) {
! 3033: default:
! 3034: /* Just here to please gcc */
! 3035: case 0:
! 3036: EPN = T1 & 0xFFFFFC00;
! 3037: if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
! 3038: do_flush_tlbs = 1;
! 3039: tlb->EPN = EPN;
! 3040: size = booke_tlb_to_page_size((T1 >> 4) & 0xF);
! 3041: if ((tlb->prot & PAGE_VALID) && tlb->size < size)
! 3042: do_flush_tlbs = 1;
! 3043: tlb->size = size;
! 3044: tlb->attr &= ~0x1;
! 3045: tlb->attr |= (T1 >> 8) & 1;
! 3046: if (T1 & 0x200) {
! 3047: tlb->prot |= PAGE_VALID;
! 3048: } else {
! 3049: if (tlb->prot & PAGE_VALID) {
! 3050: tlb->prot &= ~PAGE_VALID;
! 3051: do_flush_tlbs = 1;
! 3052: }
! 3053: }
! 3054: tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
! 3055: if (do_flush_tlbs)
! 3056: tlb_flush(env, 1);
! 3057: break;
! 3058: case 1:
! 3059: RPN = T1 & 0xFFFFFC0F;
! 3060: if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
! 3061: tlb_flush(env, 1);
! 3062: tlb->RPN = RPN;
! 3063: break;
! 3064: case 2:
! 3065: tlb->attr = (tlb->attr & 0x1) | (T1 & 0x0000FF00);
! 3066: tlb->prot = tlb->prot & PAGE_VALID;
! 3067: if (T1 & 0x1)
! 3068: tlb->prot |= PAGE_READ << 4;
! 3069: if (T1 & 0x2)
! 3070: tlb->prot |= PAGE_WRITE << 4;
! 3071: if (T1 & 0x4)
! 3072: tlb->prot |= PAGE_EXEC << 4;
! 3073: if (T1 & 0x8)
! 3074: tlb->prot |= PAGE_READ;
! 3075: if (T1 & 0x10)
! 3076: tlb->prot |= PAGE_WRITE;
! 3077: if (T1 & 0x20)
! 3078: tlb->prot |= PAGE_EXEC;
! 3079: break;
! 3080: }
! 3081: }
! 3082:
! 3083: void do_440_tlbre (int word)
! 3084: {
! 3085: ppcemb_tlb_t *tlb;
! 3086: int size;
! 3087:
! 3088: T0 &= 0x3F;
! 3089: tlb = &env->tlb[T0].tlbe;
! 3090: switch (word) {
! 3091: default:
! 3092: /* Just here to please gcc */
! 3093: case 0:
! 3094: T0 = tlb->EPN;
! 3095: size = booke_page_size_to_tlb(tlb->size);
! 3096: if (size < 0 || size > 0xF)
! 3097: size = 1;
! 3098: T0 |= size << 4;
! 3099: if (tlb->attr & 0x1)
! 3100: T0 |= 0x100;
! 3101: if (tlb->prot & PAGE_VALID)
! 3102: T0 |= 0x200;
! 3103: env->spr[SPR_440_MMUCR] &= ~0x000000FF;
! 3104: env->spr[SPR_440_MMUCR] |= tlb->PID;
! 3105: break;
! 3106: case 1:
! 3107: T0 = tlb->RPN;
! 3108: break;
! 3109: case 2:
! 3110: T0 = tlb->attr & ~0x1;
! 3111: if (tlb->prot & (PAGE_READ << 4))
! 3112: T0 |= 0x1;
! 3113: if (tlb->prot & (PAGE_WRITE << 4))
! 3114: T0 |= 0x2;
! 3115: if (tlb->prot & (PAGE_EXEC << 4))
! 3116: T0 |= 0x4;
! 3117: if (tlb->prot & PAGE_READ)
! 3118: T0 |= 0x8;
! 3119: if (tlb->prot & PAGE_WRITE)
! 3120: T0 |= 0x10;
! 3121: if (tlb->prot & PAGE_EXEC)
! 3122: T0 |= 0x20;
! 3123: break;
! 3124: }
! 3125: }
! 3126: #endif /* !CONFIG_USER_ONLY */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.