|
|
1.1 ! root 1: /* ! 2: * MIPS emulation micro-operations for qemu. ! 3: * ! 4: * Copyright (c) 2004-2005 Jocelyn Mayer ! 5: * ! 6: * This library is free software; you can redistribute it and/or ! 7: * modify it under the terms of the GNU Lesser General Public ! 8: * License as published by the Free Software Foundation; either ! 9: * version 2 of the License, or (at your option) any later version. ! 10: * ! 11: * This library is distributed in the hope that it will be useful, ! 12: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 14: * Lesser General Public License for more details. ! 15: * ! 16: * You should have received a copy of the GNU Lesser General Public ! 17: * License along with this library; if not, write to the Free Software ! 18: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ! 19: */ ! 20: ! 21: #include "config.h" ! 22: #include "exec.h" ! 23: ! 24: #ifndef CALL_FROM_TB0 ! 25: #define CALL_FROM_TB0(func) func(); ! 26: #endif ! 27: #ifndef CALL_FROM_TB1 ! 28: #define CALL_FROM_TB1(func, arg0) func(arg0); ! 29: #endif ! 30: #ifndef CALL_FROM_TB1_CONST16 ! 31: #define CALL_FROM_TB1_CONST16(func, arg0) CALL_FROM_TB1(func, arg0); ! 32: #endif ! 33: #ifndef CALL_FROM_TB2 ! 34: #define CALL_FROM_TB2(func, arg0, arg1) func(arg0, arg1); ! 35: #endif ! 36: #ifndef CALL_FROM_TB2_CONST16 ! 37: #define CALL_FROM_TB2_CONST16(func, arg0, arg1) \ ! 38: CALL_FROM_TB2(func, arg0, arg1); ! 39: #endif ! 40: #ifndef CALL_FROM_TB3 ! 41: #define CALL_FROM_TB3(func, arg0, arg1, arg2) func(arg0, arg1, arg2); ! 42: #endif ! 43: #ifndef CALL_FROM_TB4 ! 44: #define CALL_FROM_TB4(func, arg0, arg1, arg2, arg3) \ ! 45: func(arg0, arg1, arg2, arg3); ! 46: #endif ! 47: ! 48: #define REG 1 ! 49: #include "op_template.c" ! 50: #undef REG ! 51: #define REG 2 ! 52: #include "op_template.c" ! 53: #undef REG ! 54: #define REG 3 ! 55: #include "op_template.c" ! 56: #undef REG ! 57: #define REG 4 ! 58: #include "op_template.c" ! 59: #undef REG ! 60: #define REG 5 ! 61: #include "op_template.c" ! 62: #undef REG ! 63: #define REG 6 ! 64: #include "op_template.c" ! 65: #undef REG ! 66: #define REG 7 ! 67: #include "op_template.c" ! 68: #undef REG ! 69: #define REG 8 ! 70: #include "op_template.c" ! 71: #undef REG ! 72: #define REG 9 ! 73: #include "op_template.c" ! 74: #undef REG ! 75: #define REG 10 ! 76: #include "op_template.c" ! 77: #undef REG ! 78: #define REG 11 ! 79: #include "op_template.c" ! 80: #undef REG ! 81: #define REG 12 ! 82: #include "op_template.c" ! 83: #undef REG ! 84: #define REG 13 ! 85: #include "op_template.c" ! 86: #undef REG ! 87: #define REG 14 ! 88: #include "op_template.c" ! 89: #undef REG ! 90: #define REG 15 ! 91: #include "op_template.c" ! 92: #undef REG ! 93: #define REG 16 ! 94: #include "op_template.c" ! 95: #undef REG ! 96: #define REG 17 ! 97: #include "op_template.c" ! 98: #undef REG ! 99: #define REG 18 ! 100: #include "op_template.c" ! 101: #undef REG ! 102: #define REG 19 ! 103: #include "op_template.c" ! 104: #undef REG ! 105: #define REG 20 ! 106: #include "op_template.c" ! 107: #undef REG ! 108: #define REG 21 ! 109: #include "op_template.c" ! 110: #undef REG ! 111: #define REG 22 ! 112: #include "op_template.c" ! 113: #undef REG ! 114: #define REG 23 ! 115: #include "op_template.c" ! 116: #undef REG ! 117: #define REG 24 ! 118: #include "op_template.c" ! 119: #undef REG ! 120: #define REG 25 ! 121: #include "op_template.c" ! 122: #undef REG ! 123: #define REG 26 ! 124: #include "op_template.c" ! 125: #undef REG ! 126: #define REG 27 ! 127: #include "op_template.c" ! 128: #undef REG ! 129: #define REG 28 ! 130: #include "op_template.c" ! 131: #undef REG ! 132: #define REG 29 ! 133: #include "op_template.c" ! 134: #undef REG ! 135: #define REG 30 ! 136: #include "op_template.c" ! 137: #undef REG ! 138: #define REG 31 ! 139: #include "op_template.c" ! 140: #undef REG ! 141: ! 142: #define TN T0 ! 143: #include "op_template.c" ! 144: #undef TN ! 145: #define TN T1 ! 146: #include "op_template.c" ! 147: #undef TN ! 148: #define TN T2 ! 149: #include "op_template.c" ! 150: #undef TN ! 151: ! 152: void op_dup_T0 (void) ! 153: { ! 154: T2 = T0; ! 155: RETURN(); ! 156: } ! 157: ! 158: void op_load_HI (void) ! 159: { ! 160: T0 = env->HI; ! 161: RETURN(); ! 162: } ! 163: ! 164: void op_store_HI (void) ! 165: { ! 166: env->HI = T0; ! 167: RETURN(); ! 168: } ! 169: ! 170: void op_load_LO (void) ! 171: { ! 172: T0 = env->LO; ! 173: RETURN(); ! 174: } ! 175: ! 176: void op_store_LO (void) ! 177: { ! 178: env->LO = T0; ! 179: RETURN(); ! 180: } ! 181: ! 182: /* Load and store */ ! 183: #define MEMSUFFIX _raw ! 184: #include "op_mem.c" ! 185: #undef MEMSUFFIX ! 186: #if !defined(CONFIG_USER_ONLY) ! 187: #define MEMSUFFIX _user ! 188: #include "op_mem.c" ! 189: #undef MEMSUFFIX ! 190: ! 191: #define MEMSUFFIX _kernel ! 192: #include "op_mem.c" ! 193: #undef MEMSUFFIX ! 194: #endif ! 195: ! 196: /* Arithmetic */ ! 197: void op_add (void) ! 198: { ! 199: T0 += T1; ! 200: RETURN(); ! 201: } ! 202: ! 203: void op_addo (void) ! 204: { ! 205: target_ulong tmp; ! 206: ! 207: tmp = T0; ! 208: T0 += T1; ! 209: if ((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31)) { ! 210: CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW); ! 211: } ! 212: RETURN(); ! 213: } ! 214: ! 215: void op_sub (void) ! 216: { ! 217: T0 -= T1; ! 218: RETURN(); ! 219: } ! 220: ! 221: void op_subo (void) ! 222: { ! 223: target_ulong tmp; ! 224: ! 225: tmp = T0; ! 226: T0 = (int32_t)T0 - (int32_t)T1; ! 227: if (!((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31))) { ! 228: CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW); ! 229: } ! 230: RETURN(); ! 231: } ! 232: ! 233: void op_mul (void) ! 234: { ! 235: T0 = (int32_t)T0 * (int32_t)T1; ! 236: RETURN(); ! 237: } ! 238: ! 239: void op_div (void) ! 240: { ! 241: if (T1 != 0) { ! 242: env->LO = (int32_t)T0 / (int32_t)T1; ! 243: env->HI = (int32_t)T0 % (int32_t)T1; ! 244: } ! 245: RETURN(); ! 246: } ! 247: ! 248: void op_divu (void) ! 249: { ! 250: if (T1 != 0) { ! 251: env->LO = T0 / T1; ! 252: env->HI = T0 % T1; ! 253: } ! 254: RETURN(); ! 255: } ! 256: ! 257: /* Logical */ ! 258: void op_and (void) ! 259: { ! 260: T0 &= T1; ! 261: RETURN(); ! 262: } ! 263: ! 264: void op_nor (void) ! 265: { ! 266: T0 = ~(T0 | T1); ! 267: RETURN(); ! 268: } ! 269: ! 270: void op_or (void) ! 271: { ! 272: T0 |= T1; ! 273: RETURN(); ! 274: } ! 275: ! 276: void op_xor (void) ! 277: { ! 278: T0 ^= T1; ! 279: RETURN(); ! 280: } ! 281: ! 282: void op_sll (void) ! 283: { ! 284: T0 = T0 << T1; ! 285: RETURN(); ! 286: } ! 287: ! 288: void op_sra (void) ! 289: { ! 290: T0 = (int32_t)T0 >> T1; ! 291: RETURN(); ! 292: } ! 293: ! 294: void op_srl (void) ! 295: { ! 296: T0 = T0 >> T1; ! 297: RETURN(); ! 298: } ! 299: ! 300: void op_sllv (void) ! 301: { ! 302: T0 = T1 << (T0 & 0x1F); ! 303: RETURN(); ! 304: } ! 305: ! 306: void op_srav (void) ! 307: { ! 308: T0 = (int32_t)T1 >> (T0 & 0x1F); ! 309: RETURN(); ! 310: } ! 311: ! 312: void op_srlv (void) ! 313: { ! 314: T0 = T1 >> (T0 & 0x1F); ! 315: RETURN(); ! 316: } ! 317: ! 318: void op_clo (void) ! 319: { ! 320: int n; ! 321: ! 322: if (T0 == (target_ulong)-1) { ! 323: T0 = 32; ! 324: } else { ! 325: for (n = 0; n < 32; n++) { ! 326: if (!(T0 & (1 << 31))) ! 327: break; ! 328: T0 = T0 << 1; ! 329: } ! 330: T0 = n; ! 331: } ! 332: RETURN(); ! 333: } ! 334: ! 335: void op_clz (void) ! 336: { ! 337: int n; ! 338: ! 339: if (T0 == 0) { ! 340: T0 = 32; ! 341: } else { ! 342: for (n = 0; n < 32; n++) { ! 343: if (T0 & (1 << 31)) ! 344: break; ! 345: T0 = T0 << 1; ! 346: } ! 347: T0 = n; ! 348: } ! 349: RETURN(); ! 350: } ! 351: ! 352: /* 64 bits arithmetic */ ! 353: #if (HOST_LONG_BITS == 64) ! 354: static inline uint64_t get_HILO (void) ! 355: { ! 356: return ((uint64_t)env->HI << 32) | (uint64_t)env->LO; ! 357: } ! 358: ! 359: static inline void set_HILO (uint64_t HILO) ! 360: { ! 361: env->LO = HILO & 0xFFFFFFFF; ! 362: env->HI = HILO >> 32; ! 363: } ! 364: ! 365: void op_mult (void) ! 366: { ! 367: set_HILO((int64_t)T0 * (int64_t)T1); ! 368: RETURN(); ! 369: } ! 370: ! 371: void op_multu (void) ! 372: { ! 373: set_HILO((uint64_t)T0 * (uint64_t)T1); ! 374: RETURN(); ! 375: } ! 376: ! 377: void op_madd (void) ! 378: { ! 379: int64_t tmp; ! 380: ! 381: tmp = ((int64_t)T0 * (int64_t)T1); ! 382: set_HILO((int64_t)get_HILO() + tmp); ! 383: RETURN(); ! 384: } ! 385: ! 386: void op_maddu (void) ! 387: { ! 388: uint64_t tmp; ! 389: ! 390: tmp = ((uint64_t)T0 * (uint64_t)T1); ! 391: set_HILO(get_HILO() + tmp); ! 392: RETURN(); ! 393: } ! 394: ! 395: void op_msub (void) ! 396: { ! 397: int64_t tmp; ! 398: ! 399: tmp = ((int64_t)T0 * (int64_t)T1); ! 400: set_HILO((int64_t)get_HILO() - tmp); ! 401: RETURN(); ! 402: } ! 403: ! 404: void op_msubu (void) ! 405: { ! 406: uint64_t tmp; ! 407: ! 408: tmp = ((uint64_t)T0 * (uint64_t)T1); ! 409: set_HILO(get_HILO() - tmp); ! 410: RETURN(); ! 411: } ! 412: #else ! 413: void op_mult (void) ! 414: { ! 415: CALL_FROM_TB0(do_mult); ! 416: RETURN(); ! 417: } ! 418: ! 419: void op_multu (void) ! 420: { ! 421: CALL_FROM_TB0(do_multu); ! 422: RETURN(); ! 423: } ! 424: ! 425: void op_madd (void) ! 426: { ! 427: CALL_FROM_TB0(do_madd); ! 428: RETURN(); ! 429: } ! 430: ! 431: void op_maddu (void) ! 432: { ! 433: CALL_FROM_TB0(do_maddu); ! 434: RETURN(); ! 435: } ! 436: ! 437: void op_msub (void) ! 438: { ! 439: CALL_FROM_TB0(do_msub); ! 440: RETURN(); ! 441: } ! 442: ! 443: void op_msubu (void) ! 444: { ! 445: CALL_FROM_TB0(do_msubu); ! 446: RETURN(); ! 447: } ! 448: #endif ! 449: ! 450: /* Conditional moves */ ! 451: void op_movn (void) ! 452: { ! 453: if (T1 != 0) ! 454: env->gpr[PARAM1] = T0; ! 455: RETURN(); ! 456: } ! 457: ! 458: void op_movz (void) ! 459: { ! 460: if (T1 == 0) ! 461: env->gpr[PARAM1] = T0; ! 462: RETURN(); ! 463: } ! 464: ! 465: /* Tests */ ! 466: #define OP_COND(name, cond) \ ! 467: void glue(op_, name) (void) \ ! 468: { \ ! 469: if (cond) { \ ! 470: T0 = 1; \ ! 471: } else { \ ! 472: T0 = 0; \ ! 473: } \ ! 474: RETURN(); \ ! 475: } ! 476: ! 477: OP_COND(eq, T0 == T1); ! 478: OP_COND(ne, T0 != T1); ! 479: OP_COND(ge, (int32_t)T0 >= (int32_t)T1); ! 480: OP_COND(geu, T0 >= T1); ! 481: OP_COND(lt, (int32_t)T0 < (int32_t)T1); ! 482: OP_COND(ltu, T0 < T1); ! 483: OP_COND(gez, (int32_t)T0 >= 0); ! 484: OP_COND(gtz, (int32_t)T0 > 0); ! 485: OP_COND(lez, (int32_t)T0 <= 0); ! 486: OP_COND(ltz, (int32_t)T0 < 0); ! 487: ! 488: /* Branchs */ ! 489: //#undef USE_DIRECT_JUMP ! 490: #define EIP env->PC ! 491: ! 492: /* Branch to register */ ! 493: void op_save_breg_target (void) ! 494: { ! 495: env->btarget = T2; ! 496: } ! 497: ! 498: void op_restore_breg_target (void) ! 499: { ! 500: T2 = env->btarget; ! 501: } ! 502: ! 503: void op_breg (void) ! 504: { ! 505: env->PC = T2; ! 506: RETURN(); ! 507: } ! 508: ! 509: /* Unconditional branch */ ! 510: void op_branch (void) ! 511: { ! 512: JUMP_TB(branch, PARAM1, 0, PARAM2); ! 513: RETURN(); ! 514: } ! 515: ! 516: void op_save_btarget (void) ! 517: { ! 518: env->btarget = PARAM1; ! 519: RETURN(); ! 520: } ! 521: ! 522: /* Conditional branch */ ! 523: void op_set_bcond (void) ! 524: { ! 525: T2 = T0; ! 526: RETURN(); ! 527: } ! 528: ! 529: void op_save_bcond (void) ! 530: { ! 531: env->bcond = T2; ! 532: RETURN(); ! 533: } ! 534: ! 535: void op_restore_bcond (void) ! 536: { ! 537: T2 = env->bcond; ! 538: RETURN(); ! 539: } ! 540: ! 541: void op_bcond (void) ! 542: { ! 543: if (T2) { ! 544: JUMP_TB(bcond, PARAM1, 0, PARAM2); ! 545: } else { ! 546: JUMP_TB(bcond, PARAM1, 1, PARAM3); ! 547: } ! 548: RETURN(); ! 549: } ! 550: ! 551: /* Likely branch (used to skip the delay slot) */ ! 552: void op_blikely (void) ! 553: { ! 554: /* If the test is false, skip the delay slot */ ! 555: if (T2 == 0) { ! 556: env->hflags = PARAM3; ! 557: JUMP_TB(blikely, PARAM1, 1, PARAM2); ! 558: } ! 559: RETURN(); ! 560: } ! 561: ! 562: /* CP0 functions */ ! 563: void op_mfc0 (void) ! 564: { ! 565: CALL_FROM_TB2(do_mfc0, PARAM1, PARAM2); ! 566: RETURN(); ! 567: } ! 568: ! 569: void op_mtc0 (void) ! 570: { ! 571: CALL_FROM_TB2(do_mtc0, PARAM1, PARAM2); ! 572: RETURN(); ! 573: } ! 574: ! 575: #if defined(MIPS_USES_R4K_TLB) ! 576: void op_tlbwi (void) ! 577: { ! 578: CALL_FROM_TB0(do_tlbwi); ! 579: RETURN(); ! 580: } ! 581: ! 582: void op_tlbwr (void) ! 583: { ! 584: CALL_FROM_TB0(do_tlbwr); ! 585: RETURN(); ! 586: } ! 587: ! 588: void op_tlbp (void) ! 589: { ! 590: CALL_FROM_TB0(do_tlbp); ! 591: RETURN(); ! 592: } ! 593: ! 594: void op_tlbr (void) ! 595: { ! 596: CALL_FROM_TB0(do_tlbr); ! 597: RETURN(); ! 598: } ! 599: #endif ! 600: ! 601: /* Specials */ ! 602: void op_pmon (void) ! 603: { ! 604: CALL_FROM_TB1(do_pmon, PARAM1); ! 605: } ! 606: ! 607: void op_trap (void) ! 608: { ! 609: if (T0) { ! 610: CALL_FROM_TB1(do_raise_exception, EXCP_TRAP); ! 611: } ! 612: RETURN(); ! 613: } ! 614: ! 615: void op_set_lladdr (void) ! 616: { ! 617: env->CP0_LLAddr = T2; ! 618: } ! 619: ! 620: void debug_eret (void); ! 621: void op_eret (void) ! 622: { ! 623: CALL_FROM_TB0(debug_eret); ! 624: if (env->hflags & MIPS_HFLAG_ERL) { ! 625: env->PC = env->CP0_ErrorEPC; ! 626: env->hflags &= ~MIPS_HFLAG_ERL; ! 627: } else { ! 628: env->PC = env->CP0_EPC; ! 629: env->hflags &= ~MIPS_HFLAG_EXL; ! 630: } ! 631: env->CP0_LLAddr = 1; ! 632: } ! 633: ! 634: void op_deret (void) ! 635: { ! 636: CALL_FROM_TB0(debug_eret); ! 637: env->PC = env->CP0_DEPC; ! 638: } ! 639: ! 640: void op_save_state (void) ! 641: { ! 642: env->hflags = PARAM1; ! 643: RETURN(); ! 644: } ! 645: ! 646: void op_save_pc (void) ! 647: { ! 648: env->PC = PARAM1; ! 649: RETURN(); ! 650: } ! 651: ! 652: void op_raise_exception (void) ! 653: { ! 654: CALL_FROM_TB1(do_raise_exception, PARAM1); ! 655: RETURN(); ! 656: } ! 657: ! 658: void op_raise_exception_err (void) ! 659: { ! 660: CALL_FROM_TB2(do_raise_exception_err, PARAM1, PARAM2); ! 661: RETURN(); ! 662: } ! 663: ! 664: void op_exit_tb (void) ! 665: { ! 666: EXIT_TB(); ! 667: } ! 668:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.