|
|
1.1 ! root 1: /* ! 2: * m68k micro operations ! 3: * ! 4: * Copyright (c) 2006 CodeSourcery ! 5: * Written by Paul Brook ! 6: * ! 7: * This library is free software; you can redistribute it and/or ! 8: * modify it under the terms of the GNU Lesser General Public ! 9: * License as published by the Free Software Foundation; either ! 10: * version 2 of the License, or (at your option) any later version. ! 11: * ! 12: * This library is distributed in the hope that it will be useful, ! 13: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 15: * General Public License for more details. ! 16: * ! 17: * You should have received a copy of the GNU Lesser General Public ! 18: * License along with this library; if not, write to the Free Software ! 19: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ! 20: */ ! 21: ! 22: #include "exec.h" ! 23: #include "m68k-qreg.h" ! 24: ! 25: #ifndef offsetof ! 26: #define offsetof(type, field) ((size_t) &((type *)0)->field) ! 27: #endif ! 28: ! 29: static long qreg_offsets[] = { ! 30: #define DEFO32(name, offset) offsetof(CPUState, offset), ! 31: #define DEFR(name, reg, mode) -1, ! 32: #define DEFF64(name, offset) offsetof(CPUState, offset), ! 33: 0, ! 34: #include "qregs.def" ! 35: }; ! 36: ! 37: #define CPU_FP_STATUS env->fp_status ! 38: ! 39: #define RAISE_EXCEPTION(n) do { \ ! 40: env->exception_index = n; \ ! 41: cpu_loop_exit(); \ ! 42: } while(0) ! 43: ! 44: #define get_op helper_get_op ! 45: #define set_op helper_set_op ! 46: #define get_opf64 helper_get_opf64 ! 47: #define set_opf64 helper_set_opf64 ! 48: uint32_t ! 49: get_op(int qreg) ! 50: { ! 51: if (qreg == QREG_T0) { ! 52: return T0; ! 53: } else if (qreg < TARGET_NUM_QREGS) { ! 54: return *(uint32_t *)(((long)env) + qreg_offsets[qreg]); ! 55: } else { ! 56: return env->qregs[qreg - TARGET_NUM_QREGS]; ! 57: } ! 58: } ! 59: ! 60: void set_op(int qreg, uint32_t val) ! 61: { ! 62: if (qreg == QREG_T0) { ! 63: T0 = val; ! 64: } else if (qreg < TARGET_NUM_QREGS) { ! 65: *(uint32_t *)(((long)env) + qreg_offsets[qreg]) = val; ! 66: } else { ! 67: env->qregs[qreg - TARGET_NUM_QREGS] = val; ! 68: } ! 69: } ! 70: ! 71: float64 get_opf64(int qreg) ! 72: { ! 73: if (qreg < TARGET_NUM_QREGS) { ! 74: return *(float64 *)(((long)env) + qreg_offsets[qreg]); ! 75: } else { ! 76: return *(float64 *)&env->qregs[qreg - TARGET_NUM_QREGS]; ! 77: } ! 78: } ! 79: ! 80: void set_opf64(int qreg, float64 val) ! 81: { ! 82: if (qreg < TARGET_NUM_QREGS) { ! 83: *(float64 *)(((long)env) + qreg_offsets[qreg]) = val; ! 84: } else { ! 85: *(float64 *)&env->qregs[qreg - TARGET_NUM_QREGS] = val; ! 86: } ! 87: } ! 88: ! 89: #define OP(name) void OPPROTO op_##name (void) ! 90: ! 91: OP(mov32) ! 92: { ! 93: set_op(PARAM1, get_op(PARAM2)); ! 94: FORCE_RET(); ! 95: } ! 96: ! 97: OP(mov32_im) ! 98: { ! 99: set_op(PARAM1, PARAM2); ! 100: FORCE_RET(); ! 101: } ! 102: ! 103: OP(movf64) ! 104: { ! 105: set_opf64(PARAM1, get_opf64(PARAM2)); ! 106: FORCE_RET(); ! 107: } ! 108: ! 109: OP(zerof64) ! 110: { ! 111: set_opf64(PARAM1, 0); ! 112: FORCE_RET(); ! 113: } ! 114: ! 115: OP(add32) ! 116: { ! 117: uint32_t op2 = get_op(PARAM2); ! 118: uint32_t op3 = get_op(PARAM3); ! 119: set_op(PARAM1, op2 + op3); ! 120: FORCE_RET(); ! 121: } ! 122: ! 123: OP(sub32) ! 124: { ! 125: uint32_t op2 = get_op(PARAM2); ! 126: uint32_t op3 = get_op(PARAM3); ! 127: set_op(PARAM1, op2 - op3); ! 128: FORCE_RET(); ! 129: } ! 130: ! 131: OP(mul32) ! 132: { ! 133: uint32_t op2 = get_op(PARAM2); ! 134: uint32_t op3 = get_op(PARAM3); ! 135: set_op(PARAM1, op2 * op3); ! 136: FORCE_RET(); ! 137: } ! 138: ! 139: OP(not32) ! 140: { ! 141: uint32_t arg = get_op(PARAM2); ! 142: set_op(PARAM1, ~arg); ! 143: FORCE_RET(); ! 144: } ! 145: ! 146: OP(neg32) ! 147: { ! 148: uint32_t arg = get_op(PARAM2); ! 149: set_op(PARAM1, -arg); ! 150: FORCE_RET(); ! 151: } ! 152: ! 153: OP(bswap32) ! 154: { ! 155: uint32_t arg = get_op(PARAM2); ! 156: arg = (arg >> 24) | (arg << 24) ! 157: | ((arg >> 16) & 0xff00) | ((arg << 16) & 0xff0000); ! 158: set_op(PARAM1, arg); ! 159: FORCE_RET(); ! 160: } ! 161: ! 162: OP(btest) ! 163: { ! 164: uint32_t op1 = get_op(PARAM1); ! 165: uint32_t op2 = get_op(PARAM2); ! 166: if (op1 & op2) ! 167: env->cc_dest &= ~CCF_Z; ! 168: else ! 169: env->cc_dest |= CCF_Z; ! 170: FORCE_RET(); ! 171: } ! 172: ! 173: OP(addx_cc) ! 174: { ! 175: uint32_t op1 = get_op(PARAM1); ! 176: uint32_t op2 = get_op(PARAM2); ! 177: uint32_t res; ! 178: if (env->cc_x) { ! 179: env->cc_x = (op1 <= op2); ! 180: env->cc_op = CC_OP_SUBX; ! 181: res = op1 - (op2 + 1); ! 182: } else { ! 183: env->cc_x = (op1 < op2); ! 184: env->cc_op = CC_OP_SUB; ! 185: res = op1 - op2; ! 186: } ! 187: set_op(PARAM1, res); ! 188: FORCE_RET(); ! 189: } ! 190: ! 191: OP(subx_cc) ! 192: { ! 193: uint32_t op1 = get_op(PARAM1); ! 194: uint32_t op2 = get_op(PARAM2); ! 195: uint32_t res; ! 196: if (env->cc_x) { ! 197: res = op1 + op2 + 1; ! 198: env->cc_x = (res <= op2); ! 199: env->cc_op = CC_OP_ADDX; ! 200: } else { ! 201: res = op1 + op2; ! 202: env->cc_x = (res < op2); ! 203: env->cc_op = CC_OP_ADD; ! 204: } ! 205: set_op(PARAM1, res); ! 206: FORCE_RET(); ! 207: } ! 208: ! 209: /* Logic ops. */ ! 210: ! 211: OP(and32) ! 212: { ! 213: uint32_t op2 = get_op(PARAM2); ! 214: uint32_t op3 = get_op(PARAM3); ! 215: set_op(PARAM1, op2 & op3); ! 216: FORCE_RET(); ! 217: } ! 218: ! 219: OP(or32) ! 220: { ! 221: uint32_t op2 = get_op(PARAM2); ! 222: uint32_t op3 = get_op(PARAM3); ! 223: set_op(PARAM1, op2 | op3); ! 224: FORCE_RET(); ! 225: } ! 226: ! 227: OP(xor32) ! 228: { ! 229: uint32_t op2 = get_op(PARAM2); ! 230: uint32_t op3 = get_op(PARAM3); ! 231: set_op(PARAM1, op2 ^ op3); ! 232: FORCE_RET(); ! 233: } ! 234: ! 235: /* Shifts. */ ! 236: OP(shl32) ! 237: { ! 238: uint32_t op2 = get_op(PARAM2); ! 239: uint32_t op3 = get_op(PARAM3); ! 240: uint32_t result; ! 241: result = op2 << op3; ! 242: set_op(PARAM1, result); ! 243: FORCE_RET(); ! 244: } ! 245: ! 246: OP(shl_cc) ! 247: { ! 248: uint32_t op1 = get_op(PARAM1); ! 249: uint32_t op2 = get_op(PARAM2); ! 250: uint32_t result; ! 251: result = op1 << op2; ! 252: set_op(PARAM1, result); ! 253: env->cc_x = (op1 << (op2 - 1)) & 1; ! 254: FORCE_RET(); ! 255: } ! 256: ! 257: OP(shr32) ! 258: { ! 259: uint32_t op2 = get_op(PARAM2); ! 260: uint32_t op3 = get_op(PARAM3); ! 261: uint32_t result; ! 262: result = op2 >> op3; ! 263: set_op(PARAM1, result); ! 264: FORCE_RET(); ! 265: } ! 266: ! 267: OP(shr_cc) ! 268: { ! 269: uint32_t op1 = get_op(PARAM1); ! 270: uint32_t op2 = get_op(PARAM2); ! 271: uint32_t result; ! 272: result = op1 >> op2; ! 273: set_op(PARAM1, result); ! 274: env->cc_x = (op1 >> (op2 - 1)) & 1; ! 275: FORCE_RET(); ! 276: } ! 277: ! 278: OP(sar_cc) ! 279: { ! 280: int32_t op1 = get_op(PARAM1); ! 281: uint32_t op2 = get_op(PARAM2); ! 282: uint32_t result; ! 283: result = op1 >> op2; ! 284: set_op(PARAM1, result); ! 285: env->cc_x = (op1 >> (op2 - 1)) & 1; ! 286: FORCE_RET(); ! 287: } ! 288: ! 289: /* Value extend. */ ! 290: ! 291: OP(ext8u32) ! 292: { ! 293: uint32_t op2 = get_op(PARAM2); ! 294: set_op(PARAM1, (uint8_t)op2); ! 295: FORCE_RET(); ! 296: } ! 297: ! 298: OP(ext8s32) ! 299: { ! 300: uint32_t op2 = get_op(PARAM2); ! 301: set_op(PARAM1, (int8_t)op2); ! 302: FORCE_RET(); ! 303: } ! 304: ! 305: OP(ext16u32) ! 306: { ! 307: uint32_t op2 = get_op(PARAM2); ! 308: set_op(PARAM1, (uint16_t)op2); ! 309: FORCE_RET(); ! 310: } ! 311: ! 312: OP(ext16s32) ! 313: { ! 314: uint32_t op2 = get_op(PARAM2); ! 315: set_op(PARAM1, (int16_t)op2); ! 316: FORCE_RET(); ! 317: } ! 318: ! 319: /* Load/store ops. */ ! 320: OP(ld8u32) ! 321: { ! 322: uint32_t addr = get_op(PARAM2); ! 323: set_op(PARAM1, ldub(addr)); ! 324: FORCE_RET(); ! 325: } ! 326: ! 327: OP(ld8s32) ! 328: { ! 329: uint32_t addr = get_op(PARAM2); ! 330: set_op(PARAM1, ldsb(addr)); ! 331: FORCE_RET(); ! 332: } ! 333: ! 334: OP(ld16u32) ! 335: { ! 336: uint32_t addr = get_op(PARAM2); ! 337: set_op(PARAM1, lduw(addr)); ! 338: FORCE_RET(); ! 339: } ! 340: ! 341: OP(ld16s32) ! 342: { ! 343: uint32_t addr = get_op(PARAM2); ! 344: set_op(PARAM1, ldsw(addr)); ! 345: FORCE_RET(); ! 346: } ! 347: ! 348: OP(ld32) ! 349: { ! 350: uint32_t addr = get_op(PARAM2); ! 351: set_op(PARAM1, ldl(addr)); ! 352: FORCE_RET(); ! 353: } ! 354: ! 355: OP(st8) ! 356: { ! 357: uint32_t addr = get_op(PARAM1); ! 358: stb(addr, get_op(PARAM2)); ! 359: FORCE_RET(); ! 360: } ! 361: ! 362: OP(st16) ! 363: { ! 364: uint32_t addr = get_op(PARAM1); ! 365: stw(addr, get_op(PARAM2)); ! 366: FORCE_RET(); ! 367: } ! 368: ! 369: OP(st32) ! 370: { ! 371: uint32_t addr = get_op(PARAM1); ! 372: stl(addr, get_op(PARAM2)); ! 373: FORCE_RET(); ! 374: } ! 375: ! 376: OP(ldf64) ! 377: { ! 378: uint32_t addr = get_op(PARAM2); ! 379: set_opf64(PARAM1, ldfq(addr)); ! 380: FORCE_RET(); ! 381: } ! 382: ! 383: OP(stf64) ! 384: { ! 385: uint32_t addr = get_op(PARAM1); ! 386: stfq(addr, get_opf64(PARAM2)); ! 387: FORCE_RET(); ! 388: } ! 389: ! 390: OP(flush_flags) ! 391: { ! 392: int cc_op = PARAM1; ! 393: if (cc_op == CC_OP_DYNAMIC) ! 394: cc_op = env->cc_op; ! 395: cpu_m68k_flush_flags(env, cc_op); ! 396: FORCE_RET(); ! 397: } ! 398: ! 399: OP(divu) ! 400: { ! 401: uint32_t num; ! 402: uint32_t den; ! 403: uint32_t quot; ! 404: uint32_t rem; ! 405: uint32_t flags; ! 406: ! 407: num = env->div1; ! 408: den = env->div2; ! 409: /* ??? This needs to make sure the throwing location is accurate. */ ! 410: if (den == 0) ! 411: RAISE_EXCEPTION(EXCP_DIV0); ! 412: quot = num / den; ! 413: rem = num % den; ! 414: flags = 0; ! 415: /* Avoid using a PARAM1 of zero. This breaks dyngen because it uses ! 416: the address of a symbol, and gcc knows symbols can't have address ! 417: zero. */ ! 418: if (PARAM1 == 2 && quot > 0xffff) ! 419: flags |= CCF_V; ! 420: if (quot == 0) ! 421: flags |= CCF_Z; ! 422: else if ((int32_t)quot < 0) ! 423: flags |= CCF_N; ! 424: env->div1 = quot; ! 425: env->div2 = rem; ! 426: env->cc_dest = flags; ! 427: FORCE_RET(); ! 428: } ! 429: ! 430: OP(divs) ! 431: { ! 432: int32_t num; ! 433: int32_t den; ! 434: int32_t quot; ! 435: int32_t rem; ! 436: int32_t flags; ! 437: ! 438: num = env->div1; ! 439: den = env->div2; ! 440: if (den == 0) ! 441: RAISE_EXCEPTION(EXCP_DIV0); ! 442: quot = num / den; ! 443: rem = num % den; ! 444: flags = 0; ! 445: if (PARAM1 == 2 && quot != (int16_t)quot) ! 446: flags |= CCF_V; ! 447: if (quot == 0) ! 448: flags |= CCF_Z; ! 449: else if (quot < 0) ! 450: flags |= CCF_N; ! 451: env->div1 = quot; ! 452: env->div2 = rem; ! 453: env->cc_dest = flags; ! 454: FORCE_RET(); ! 455: } ! 456: ! 457: OP(raise_exception) ! 458: { ! 459: RAISE_EXCEPTION(PARAM1); ! 460: FORCE_RET(); ! 461: } ! 462: ! 463: /* Floating point comparison sets flags differently to other instructions. */ ! 464: ! 465: OP(sub_cmpf64) ! 466: { ! 467: float64 src0; ! 468: float64 src1; ! 469: src0 = get_opf64(PARAM2); ! 470: src1 = get_opf64(PARAM3); ! 471: set_opf64(PARAM1, helper_sub_cmpf64(env, src0, src1)); ! 472: FORCE_RET(); ! 473: } ! 474: ! 475: OP(update_xflag_tst) ! 476: { ! 477: uint32_t op1 = get_op(PARAM1); ! 478: env->cc_x = op1; ! 479: FORCE_RET(); ! 480: } ! 481: ! 482: OP(update_xflag_lt) ! 483: { ! 484: uint32_t op1 = get_op(PARAM1); ! 485: uint32_t op2 = get_op(PARAM2); ! 486: env->cc_x = (op1 < op2); ! 487: FORCE_RET(); ! 488: } ! 489: ! 490: OP(get_xflag) ! 491: { ! 492: set_op(PARAM1, env->cc_x); ! 493: FORCE_RET(); ! 494: } ! 495: ! 496: OP(logic_cc) ! 497: { ! 498: uint32_t op1 = get_op(PARAM1); ! 499: env->cc_dest = op1; ! 500: FORCE_RET(); ! 501: } ! 502: ! 503: OP(update_cc_add) ! 504: { ! 505: uint32_t op1 = get_op(PARAM1); ! 506: uint32_t op2 = get_op(PARAM2); ! 507: env->cc_dest = op1; ! 508: env->cc_src = op2; ! 509: FORCE_RET(); ! 510: } ! 511: ! 512: OP(fp_result) ! 513: { ! 514: env->fp_result = get_opf64(PARAM1); ! 515: FORCE_RET(); ! 516: } ! 517: ! 518: OP(jmp) ! 519: { ! 520: GOTO_LABEL_PARAM(1); ! 521: } ! 522: ! 523: /* These ops involve a function call, which probably requires a stack frame ! 524: and breaks things on some hosts. */ ! 525: OP(jmp_z32) ! 526: { ! 527: uint32_t arg = get_op(PARAM1); ! 528: if (arg == 0) ! 529: GOTO_LABEL_PARAM(2); ! 530: FORCE_RET(); ! 531: } ! 532: ! 533: OP(jmp_nz32) ! 534: { ! 535: uint32_t arg = get_op(PARAM1); ! 536: if (arg != 0) ! 537: GOTO_LABEL_PARAM(2); ! 538: FORCE_RET(); ! 539: } ! 540: ! 541: OP(jmp_s32) ! 542: { ! 543: int32_t arg = get_op(PARAM1); ! 544: if (arg < 0) ! 545: GOTO_LABEL_PARAM(2); ! 546: FORCE_RET(); ! 547: } ! 548: ! 549: OP(jmp_ns32) ! 550: { ! 551: int32_t arg = get_op(PARAM1); ! 552: if (arg >= 0) ! 553: GOTO_LABEL_PARAM(2); ! 554: FORCE_RET(); ! 555: } ! 556: ! 557: void OPPROTO op_goto_tb0(void) ! 558: { ! 559: GOTO_TB(op_goto_tb0, PARAM1, 0); ! 560: } ! 561: ! 562: void OPPROTO op_goto_tb1(void) ! 563: { ! 564: GOTO_TB(op_goto_tb1, PARAM1, 1); ! 565: } ! 566: ! 567: OP(exit_tb) ! 568: { ! 569: EXIT_TB(); ! 570: } ! 571: ! 572: ! 573: /* Floating point. */ ! 574: OP(f64_to_i32) ! 575: { ! 576: set_op(PARAM1, float64_to_int32(get_opf64(PARAM2), &CPU_FP_STATUS)); ! 577: FORCE_RET(); ! 578: } ! 579: ! 580: OP(f64_to_f32) ! 581: { ! 582: union { ! 583: float32 f; ! 584: uint32_t i; ! 585: } u; ! 586: u.f = float64_to_float32(get_opf64(PARAM2), &CPU_FP_STATUS); ! 587: set_op(PARAM1, u.i); ! 588: FORCE_RET(); ! 589: } ! 590: ! 591: OP(i32_to_f64) ! 592: { ! 593: set_opf64(PARAM1, int32_to_float64(get_op(PARAM2), &CPU_FP_STATUS)); ! 594: FORCE_RET(); ! 595: } ! 596: ! 597: OP(f32_to_f64) ! 598: { ! 599: union { ! 600: float32 f; ! 601: uint32_t i; ! 602: } u; ! 603: u.i = get_op(PARAM2); ! 604: set_opf64(PARAM1, float32_to_float64(u.f, &CPU_FP_STATUS)); ! 605: FORCE_RET(); ! 606: } ! 607: ! 608: OP(absf64) ! 609: { ! 610: float64 op0 = get_opf64(PARAM2); ! 611: set_opf64(PARAM1, float64_abs(op0)); ! 612: FORCE_RET(); ! 613: } ! 614: ! 615: OP(chsf64) ! 616: { ! 617: float64 op0 = get_opf64(PARAM2); ! 618: set_opf64(PARAM1, float64_chs(op0)); ! 619: FORCE_RET(); ! 620: } ! 621: ! 622: OP(sqrtf64) ! 623: { ! 624: float64 op0 = get_opf64(PARAM2); ! 625: set_opf64(PARAM1, float64_sqrt(op0, &CPU_FP_STATUS)); ! 626: FORCE_RET(); ! 627: } ! 628: ! 629: OP(addf64) ! 630: { ! 631: float64 op0 = get_opf64(PARAM2); ! 632: float64 op1 = get_opf64(PARAM3); ! 633: set_opf64(PARAM1, float64_add(op0, op1, &CPU_FP_STATUS)); ! 634: FORCE_RET(); ! 635: } ! 636: ! 637: OP(subf64) ! 638: { ! 639: float64 op0 = get_opf64(PARAM2); ! 640: float64 op1 = get_opf64(PARAM3); ! 641: set_opf64(PARAM1, float64_sub(op0, op1, &CPU_FP_STATUS)); ! 642: FORCE_RET(); ! 643: } ! 644: ! 645: OP(mulf64) ! 646: { ! 647: float64 op0 = get_opf64(PARAM2); ! 648: float64 op1 = get_opf64(PARAM3); ! 649: set_opf64(PARAM1, float64_mul(op0, op1, &CPU_FP_STATUS)); ! 650: FORCE_RET(); ! 651: } ! 652: ! 653: OP(divf64) ! 654: { ! 655: float64 op0 = get_opf64(PARAM2); ! 656: float64 op1 = get_opf64(PARAM3); ! 657: set_opf64(PARAM1, float64_div(op0, op1, &CPU_FP_STATUS)); ! 658: FORCE_RET(); ! 659: } ! 660: ! 661: OP(iround_f64) ! 662: { ! 663: float64 op0 = get_opf64(PARAM2); ! 664: set_opf64(PARAM1, float64_round_to_int(op0, &CPU_FP_STATUS)); ! 665: FORCE_RET(); ! 666: } ! 667: ! 668: OP(itrunc_f64) ! 669: { ! 670: float64 op0 = get_opf64(PARAM2); ! 671: set_opf64(PARAM1, float64_trunc_to_int(op0, &CPU_FP_STATUS)); ! 672: FORCE_RET(); ! 673: } ! 674: ! 675: OP(compare_quietf64) ! 676: { ! 677: float64 op0 = get_opf64(PARAM2); ! 678: float64 op1 = get_opf64(PARAM3); ! 679: set_op(PARAM1, float64_compare_quiet(op0, op1, &CPU_FP_STATUS)); ! 680: FORCE_RET(); ! 681: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.