|
|
1.1 ! root 1: /* ! 2: SPARC translation ! 3: ! 4: Copyright (C) 2003 Thomas M. Ogrisegg <[email protected]> ! 5: Copyright (C) 2003-2005 Fabrice Bellard ! 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: Lesser 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: /* ! 23: TODO-list: ! 24: ! 25: Rest of V9 instructions, VIS instructions ! 26: NPC/PC static optimisations (use JUMP_TB when possible) ! 27: Optimize synthetic instructions ! 28: Optional alignment check ! 29: 128-bit float ! 30: Tagged add/sub ! 31: */ ! 32: ! 33: #include <stdarg.h> ! 34: #include <stdlib.h> ! 35: #include <stdio.h> ! 36: #include <string.h> ! 37: #include <inttypes.h> ! 38: ! 39: #include "cpu.h" ! 40: #include "exec-all.h" ! 41: #include "disas.h" ! 42: ! 43: #define DEBUG_DISAS ! 44: ! 45: #define DYNAMIC_PC 1 /* dynamic pc value */ ! 46: #define JUMP_PC 2 /* dynamic pc value which takes only two values ! 47: according to jump_pc[T2] */ ! 48: ! 49: typedef struct DisasContext { ! 50: target_ulong pc; /* current Program Counter: integer or DYNAMIC_PC */ ! 51: target_ulong npc; /* next PC: integer or DYNAMIC_PC or JUMP_PC */ ! 52: target_ulong jump_pc[2]; /* used when JUMP_PC pc value is used */ ! 53: int is_br; ! 54: int mem_idx; ! 55: struct TranslationBlock *tb; ! 56: } DisasContext; ! 57: ! 58: static uint16_t *gen_opc_ptr; ! 59: static uint32_t *gen_opparam_ptr; ! 60: extern FILE *logfile; ! 61: extern int loglevel; ! 62: ! 63: enum { ! 64: #define DEF(s,n,copy_size) INDEX_op_ ## s, ! 65: #include "opc.h" ! 66: #undef DEF ! 67: NB_OPS ! 68: }; ! 69: ! 70: #include "gen-op.h" ! 71: ! 72: // This function uses non-native bit order ! 73: #define GET_FIELD(X, FROM, TO) \ ! 74: ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1)) ! 75: ! 76: // This function uses the order in the manuals, i.e. bit 0 is 2^0 ! 77: #define GET_FIELD_SP(X, FROM, TO) \ ! 78: GET_FIELD(X, 31 - (TO), 31 - (FROM)) ! 79: ! 80: #define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), (b) - (a) + 1) ! 81: #define GET_FIELD_SPs(x,a,b) sign_extend (GET_FIELD_SP(x,a,b), 32 - ((b) - (a) + 1)) ! 82: ! 83: #ifdef TARGET_SPARC64 ! 84: #define DFPREG(r) (((r & 1) << 6) | (r & 0x1e)) ! 85: #else ! 86: #define DFPREG(r) (r) ! 87: #endif ! 88: ! 89: #ifdef USE_DIRECT_JUMP ! 90: #define TBPARAM(x) ! 91: #else ! 92: #define TBPARAM(x) (long)(x) ! 93: #endif ! 94: ! 95: static int sign_extend(int x, int len) ! 96: { ! 97: len = 32 - len; ! 98: return (x << len) >> len; ! 99: } ! 100: ! 101: #define IS_IMM (insn & (1<<13)) ! 102: ! 103: static void disas_sparc_insn(DisasContext * dc); ! 104: ! 105: static GenOpFunc *gen_op_movl_TN_reg[2][32] = { ! 106: { ! 107: gen_op_movl_g0_T0, ! 108: gen_op_movl_g1_T0, ! 109: gen_op_movl_g2_T0, ! 110: gen_op_movl_g3_T0, ! 111: gen_op_movl_g4_T0, ! 112: gen_op_movl_g5_T0, ! 113: gen_op_movl_g6_T0, ! 114: gen_op_movl_g7_T0, ! 115: gen_op_movl_o0_T0, ! 116: gen_op_movl_o1_T0, ! 117: gen_op_movl_o2_T0, ! 118: gen_op_movl_o3_T0, ! 119: gen_op_movl_o4_T0, ! 120: gen_op_movl_o5_T0, ! 121: gen_op_movl_o6_T0, ! 122: gen_op_movl_o7_T0, ! 123: gen_op_movl_l0_T0, ! 124: gen_op_movl_l1_T0, ! 125: gen_op_movl_l2_T0, ! 126: gen_op_movl_l3_T0, ! 127: gen_op_movl_l4_T0, ! 128: gen_op_movl_l5_T0, ! 129: gen_op_movl_l6_T0, ! 130: gen_op_movl_l7_T0, ! 131: gen_op_movl_i0_T0, ! 132: gen_op_movl_i1_T0, ! 133: gen_op_movl_i2_T0, ! 134: gen_op_movl_i3_T0, ! 135: gen_op_movl_i4_T0, ! 136: gen_op_movl_i5_T0, ! 137: gen_op_movl_i6_T0, ! 138: gen_op_movl_i7_T0, ! 139: }, ! 140: { ! 141: gen_op_movl_g0_T1, ! 142: gen_op_movl_g1_T1, ! 143: gen_op_movl_g2_T1, ! 144: gen_op_movl_g3_T1, ! 145: gen_op_movl_g4_T1, ! 146: gen_op_movl_g5_T1, ! 147: gen_op_movl_g6_T1, ! 148: gen_op_movl_g7_T1, ! 149: gen_op_movl_o0_T1, ! 150: gen_op_movl_o1_T1, ! 151: gen_op_movl_o2_T1, ! 152: gen_op_movl_o3_T1, ! 153: gen_op_movl_o4_T1, ! 154: gen_op_movl_o5_T1, ! 155: gen_op_movl_o6_T1, ! 156: gen_op_movl_o7_T1, ! 157: gen_op_movl_l0_T1, ! 158: gen_op_movl_l1_T1, ! 159: gen_op_movl_l2_T1, ! 160: gen_op_movl_l3_T1, ! 161: gen_op_movl_l4_T1, ! 162: gen_op_movl_l5_T1, ! 163: gen_op_movl_l6_T1, ! 164: gen_op_movl_l7_T1, ! 165: gen_op_movl_i0_T1, ! 166: gen_op_movl_i1_T1, ! 167: gen_op_movl_i2_T1, ! 168: gen_op_movl_i3_T1, ! 169: gen_op_movl_i4_T1, ! 170: gen_op_movl_i5_T1, ! 171: gen_op_movl_i6_T1, ! 172: gen_op_movl_i7_T1, ! 173: } ! 174: }; ! 175: ! 176: static GenOpFunc *gen_op_movl_reg_TN[3][32] = { ! 177: { ! 178: gen_op_movl_T0_g0, ! 179: gen_op_movl_T0_g1, ! 180: gen_op_movl_T0_g2, ! 181: gen_op_movl_T0_g3, ! 182: gen_op_movl_T0_g4, ! 183: gen_op_movl_T0_g5, ! 184: gen_op_movl_T0_g6, ! 185: gen_op_movl_T0_g7, ! 186: gen_op_movl_T0_o0, ! 187: gen_op_movl_T0_o1, ! 188: gen_op_movl_T0_o2, ! 189: gen_op_movl_T0_o3, ! 190: gen_op_movl_T0_o4, ! 191: gen_op_movl_T0_o5, ! 192: gen_op_movl_T0_o6, ! 193: gen_op_movl_T0_o7, ! 194: gen_op_movl_T0_l0, ! 195: gen_op_movl_T0_l1, ! 196: gen_op_movl_T0_l2, ! 197: gen_op_movl_T0_l3, ! 198: gen_op_movl_T0_l4, ! 199: gen_op_movl_T0_l5, ! 200: gen_op_movl_T0_l6, ! 201: gen_op_movl_T0_l7, ! 202: gen_op_movl_T0_i0, ! 203: gen_op_movl_T0_i1, ! 204: gen_op_movl_T0_i2, ! 205: gen_op_movl_T0_i3, ! 206: gen_op_movl_T0_i4, ! 207: gen_op_movl_T0_i5, ! 208: gen_op_movl_T0_i6, ! 209: gen_op_movl_T0_i7, ! 210: }, ! 211: { ! 212: gen_op_movl_T1_g0, ! 213: gen_op_movl_T1_g1, ! 214: gen_op_movl_T1_g2, ! 215: gen_op_movl_T1_g3, ! 216: gen_op_movl_T1_g4, ! 217: gen_op_movl_T1_g5, ! 218: gen_op_movl_T1_g6, ! 219: gen_op_movl_T1_g7, ! 220: gen_op_movl_T1_o0, ! 221: gen_op_movl_T1_o1, ! 222: gen_op_movl_T1_o2, ! 223: gen_op_movl_T1_o3, ! 224: gen_op_movl_T1_o4, ! 225: gen_op_movl_T1_o5, ! 226: gen_op_movl_T1_o6, ! 227: gen_op_movl_T1_o7, ! 228: gen_op_movl_T1_l0, ! 229: gen_op_movl_T1_l1, ! 230: gen_op_movl_T1_l2, ! 231: gen_op_movl_T1_l3, ! 232: gen_op_movl_T1_l4, ! 233: gen_op_movl_T1_l5, ! 234: gen_op_movl_T1_l6, ! 235: gen_op_movl_T1_l7, ! 236: gen_op_movl_T1_i0, ! 237: gen_op_movl_T1_i1, ! 238: gen_op_movl_T1_i2, ! 239: gen_op_movl_T1_i3, ! 240: gen_op_movl_T1_i4, ! 241: gen_op_movl_T1_i5, ! 242: gen_op_movl_T1_i6, ! 243: gen_op_movl_T1_i7, ! 244: }, ! 245: { ! 246: gen_op_movl_T2_g0, ! 247: gen_op_movl_T2_g1, ! 248: gen_op_movl_T2_g2, ! 249: gen_op_movl_T2_g3, ! 250: gen_op_movl_T2_g4, ! 251: gen_op_movl_T2_g5, ! 252: gen_op_movl_T2_g6, ! 253: gen_op_movl_T2_g7, ! 254: gen_op_movl_T2_o0, ! 255: gen_op_movl_T2_o1, ! 256: gen_op_movl_T2_o2, ! 257: gen_op_movl_T2_o3, ! 258: gen_op_movl_T2_o4, ! 259: gen_op_movl_T2_o5, ! 260: gen_op_movl_T2_o6, ! 261: gen_op_movl_T2_o7, ! 262: gen_op_movl_T2_l0, ! 263: gen_op_movl_T2_l1, ! 264: gen_op_movl_T2_l2, ! 265: gen_op_movl_T2_l3, ! 266: gen_op_movl_T2_l4, ! 267: gen_op_movl_T2_l5, ! 268: gen_op_movl_T2_l6, ! 269: gen_op_movl_T2_l7, ! 270: gen_op_movl_T2_i0, ! 271: gen_op_movl_T2_i1, ! 272: gen_op_movl_T2_i2, ! 273: gen_op_movl_T2_i3, ! 274: gen_op_movl_T2_i4, ! 275: gen_op_movl_T2_i5, ! 276: gen_op_movl_T2_i6, ! 277: gen_op_movl_T2_i7, ! 278: } ! 279: }; ! 280: ! 281: static GenOpFunc1 *gen_op_movl_TN_im[3] = { ! 282: gen_op_movl_T0_im, ! 283: gen_op_movl_T1_im, ! 284: gen_op_movl_T2_im ! 285: }; ! 286: ! 287: // Sign extending version ! 288: static GenOpFunc1 * const gen_op_movl_TN_sim[3] = { ! 289: gen_op_movl_T0_sim, ! 290: gen_op_movl_T1_sim, ! 291: gen_op_movl_T2_sim ! 292: }; ! 293: ! 294: #ifdef TARGET_SPARC64 ! 295: #define GEN32(func, NAME) \ ! 296: static GenOpFunc *NAME ## _table [64] = { \ ! 297: NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ ! 298: NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ ! 299: NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ ! 300: NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ ! 301: NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ ! 302: NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ ! 303: NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ ! 304: NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ ! 305: NAME ## 32, 0, NAME ## 34, 0, NAME ## 36, 0, NAME ## 38, 0, \ ! 306: NAME ## 40, 0, NAME ## 42, 0, NAME ## 44, 0, NAME ## 46, 0, \ ! 307: NAME ## 48, 0, NAME ## 50, 0, NAME ## 52, 0, NAME ## 54, 0, \ ! 308: NAME ## 56, 0, NAME ## 58, 0, NAME ## 60, 0, NAME ## 62, 0, \ ! 309: }; \ ! 310: static inline void func(int n) \ ! 311: { \ ! 312: NAME ## _table[n](); \ ! 313: } ! 314: #else ! 315: #define GEN32(func, NAME) \ ! 316: static GenOpFunc *NAME ## _table [32] = { \ ! 317: NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \ ! 318: NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \ ! 319: NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \ ! 320: NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \ ! 321: NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \ ! 322: NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \ ! 323: NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \ ! 324: NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \ ! 325: }; \ ! 326: static inline void func(int n) \ ! 327: { \ ! 328: NAME ## _table[n](); \ ! 329: } ! 330: #endif ! 331: ! 332: /* floating point registers moves */ ! 333: GEN32(gen_op_load_fpr_FT0, gen_op_load_fpr_FT0_fprf); ! 334: GEN32(gen_op_load_fpr_FT1, gen_op_load_fpr_FT1_fprf); ! 335: GEN32(gen_op_store_FT0_fpr, gen_op_store_FT0_fpr_fprf); ! 336: GEN32(gen_op_store_FT1_fpr, gen_op_store_FT1_fpr_fprf); ! 337: ! 338: GEN32(gen_op_load_fpr_DT0, gen_op_load_fpr_DT0_fprf); ! 339: GEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fprf); ! 340: GEN32(gen_op_store_DT0_fpr, gen_op_store_DT0_fpr_fprf); ! 341: GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf); ! 342: ! 343: #ifdef TARGET_SPARC64 ! 344: // 'a' versions allowed to user depending on asi ! 345: #if defined(CONFIG_USER_ONLY) ! 346: #define supervisor(dc) 0 ! 347: #define gen_op_ldst(name) gen_op_##name##_raw() ! 348: #define OP_LD_TABLE(width) \ ! 349: static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \ ! 350: { \ ! 351: int asi, offset; \ ! 352: \ ! 353: if (IS_IMM) { \ ! 354: offset = GET_FIELD(insn, 25, 31); \ ! 355: if (is_ld) \ ! 356: gen_op_ld_asi_reg(offset, size, sign); \ ! 357: else \ ! 358: gen_op_st_asi_reg(offset, size, sign); \ ! 359: return; \ ! 360: } \ ! 361: asi = GET_FIELD(insn, 19, 26); \ ! 362: switch (asi) { \ ! 363: case 0x80: /* Primary address space */ \ ! 364: gen_op_##width##_raw(); \ ! 365: break; \ ! 366: default: \ ! 367: break; \ ! 368: } \ ! 369: } ! 370: ! 371: #else ! 372: #define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])() ! 373: #define OP_LD_TABLE(width) \ ! 374: static GenOpFunc *gen_op_##width[] = { \ ! 375: &gen_op_##width##_user, \ ! 376: &gen_op_##width##_kernel, \ ! 377: }; \ ! 378: \ ! 379: static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \ ! 380: { \ ! 381: int asi, offset; \ ! 382: \ ! 383: if (IS_IMM) { \ ! 384: offset = GET_FIELD(insn, 25, 31); \ ! 385: if (is_ld) \ ! 386: gen_op_ld_asi_reg(offset, size, sign); \ ! 387: else \ ! 388: gen_op_st_asi_reg(offset, size, sign); \ ! 389: return; \ ! 390: } \ ! 391: asi = GET_FIELD(insn, 19, 26); \ ! 392: if (is_ld) \ ! 393: gen_op_ld_asi(asi, size, sign); \ ! 394: else \ ! 395: gen_op_st_asi(asi, size, sign); \ ! 396: } ! 397: ! 398: #define supervisor(dc) (dc->mem_idx == 1) ! 399: #endif ! 400: #else ! 401: #if defined(CONFIG_USER_ONLY) ! 402: #define gen_op_ldst(name) gen_op_##name##_raw() ! 403: #define OP_LD_TABLE(width) ! 404: #define supervisor(dc) 0 ! 405: #else ! 406: #define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])() ! 407: #define OP_LD_TABLE(width) \ ! 408: static GenOpFunc *gen_op_##width[] = { \ ! 409: &gen_op_##width##_user, \ ! 410: &gen_op_##width##_kernel, \ ! 411: }; \ ! 412: \ ! 413: static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \ ! 414: { \ ! 415: int asi; \ ! 416: \ ! 417: asi = GET_FIELD(insn, 19, 26); \ ! 418: switch (asi) { \ ! 419: case 10: /* User data access */ \ ! 420: gen_op_##width##_user(); \ ! 421: break; \ ! 422: case 11: /* Supervisor data access */ \ ! 423: gen_op_##width##_kernel(); \ ! 424: break; \ ! 425: case 0x20 ... 0x2f: /* MMU passthrough */ \ ! 426: if (is_ld) \ ! 427: gen_op_ld_asi(asi, size, sign); \ ! 428: else \ ! 429: gen_op_st_asi(asi, size, sign); \ ! 430: break; \ ! 431: default: \ ! 432: if (is_ld) \ ! 433: gen_op_ld_asi(asi, size, sign); \ ! 434: else \ ! 435: gen_op_st_asi(asi, size, sign); \ ! 436: break; \ ! 437: } \ ! 438: } ! 439: ! 440: #define supervisor(dc) (dc->mem_idx == 1) ! 441: #endif ! 442: #endif ! 443: ! 444: OP_LD_TABLE(ld); ! 445: OP_LD_TABLE(st); ! 446: OP_LD_TABLE(ldub); ! 447: OP_LD_TABLE(lduh); ! 448: OP_LD_TABLE(ldsb); ! 449: OP_LD_TABLE(ldsh); ! 450: OP_LD_TABLE(stb); ! 451: OP_LD_TABLE(sth); ! 452: OP_LD_TABLE(std); ! 453: OP_LD_TABLE(ldstub); ! 454: OP_LD_TABLE(swap); ! 455: OP_LD_TABLE(ldd); ! 456: OP_LD_TABLE(stf); ! 457: OP_LD_TABLE(stdf); ! 458: OP_LD_TABLE(ldf); ! 459: OP_LD_TABLE(lddf); ! 460: ! 461: #ifdef TARGET_SPARC64 ! 462: OP_LD_TABLE(ldsw); ! 463: OP_LD_TABLE(ldx); ! 464: OP_LD_TABLE(stx); ! 465: OP_LD_TABLE(cas); ! 466: OP_LD_TABLE(casx); ! 467: #endif ! 468: ! 469: static inline void gen_movl_imm_TN(int reg, uint32_t imm) ! 470: { ! 471: gen_op_movl_TN_im[reg](imm); ! 472: } ! 473: ! 474: static inline void gen_movl_imm_T1(uint32_t val) ! 475: { ! 476: gen_movl_imm_TN(1, val); ! 477: } ! 478: ! 479: static inline void gen_movl_imm_T0(uint32_t val) ! 480: { ! 481: gen_movl_imm_TN(0, val); ! 482: } ! 483: ! 484: static inline void gen_movl_simm_TN(int reg, int32_t imm) ! 485: { ! 486: gen_op_movl_TN_sim[reg](imm); ! 487: } ! 488: ! 489: static inline void gen_movl_simm_T1(int32_t val) ! 490: { ! 491: gen_movl_simm_TN(1, val); ! 492: } ! 493: ! 494: static inline void gen_movl_simm_T0(int32_t val) ! 495: { ! 496: gen_movl_simm_TN(0, val); ! 497: } ! 498: ! 499: static inline void gen_movl_reg_TN(int reg, int t) ! 500: { ! 501: if (reg) ! 502: gen_op_movl_reg_TN[t][reg] (); ! 503: else ! 504: gen_movl_imm_TN(t, 0); ! 505: } ! 506: ! 507: static inline void gen_movl_reg_T0(int reg) ! 508: { ! 509: gen_movl_reg_TN(reg, 0); ! 510: } ! 511: ! 512: static inline void gen_movl_reg_T1(int reg) ! 513: { ! 514: gen_movl_reg_TN(reg, 1); ! 515: } ! 516: ! 517: static inline void gen_movl_reg_T2(int reg) ! 518: { ! 519: gen_movl_reg_TN(reg, 2); ! 520: } ! 521: ! 522: static inline void gen_movl_TN_reg(int reg, int t) ! 523: { ! 524: if (reg) ! 525: gen_op_movl_TN_reg[t][reg] (); ! 526: } ! 527: ! 528: static inline void gen_movl_T0_reg(int reg) ! 529: { ! 530: gen_movl_TN_reg(reg, 0); ! 531: } ! 532: ! 533: static inline void gen_movl_T1_reg(int reg) ! 534: { ! 535: gen_movl_TN_reg(reg, 1); ! 536: } ! 537: ! 538: static inline void gen_jmp_im(target_ulong pc) ! 539: { ! 540: #ifdef TARGET_SPARC64 ! 541: if (pc == (uint32_t)pc) { ! 542: gen_op_jmp_im(pc); ! 543: } else { ! 544: gen_op_jmp_im64(pc >> 32, pc); ! 545: } ! 546: #else ! 547: gen_op_jmp_im(pc); ! 548: #endif ! 549: } ! 550: ! 551: static inline void gen_movl_npc_im(target_ulong npc) ! 552: { ! 553: #ifdef TARGET_SPARC64 ! 554: if (npc == (uint32_t)npc) { ! 555: gen_op_movl_npc_im(npc); ! 556: } else { ! 557: gen_op_movq_npc_im64(npc >> 32, npc); ! 558: } ! 559: #else ! 560: gen_op_movl_npc_im(npc); ! 561: #endif ! 562: } ! 563: ! 564: static inline void gen_branch2(DisasContext *dc, long tb, target_ulong pc1, target_ulong pc2) ! 565: { ! 566: int l1; ! 567: ! 568: l1 = gen_new_label(); ! 569: ! 570: gen_op_jz_T2_label(l1); ! 571: ! 572: gen_op_goto_tb0(TBPARAM(tb)); ! 573: gen_jmp_im(pc1); ! 574: gen_movl_npc_im(pc1 + 4); ! 575: gen_op_movl_T0_im((long)tb + 0); ! 576: gen_op_exit_tb(); ! 577: ! 578: gen_set_label(l1); ! 579: gen_op_goto_tb1(TBPARAM(tb)); ! 580: gen_jmp_im(pc2); ! 581: gen_movl_npc_im(pc2 + 4); ! 582: gen_op_movl_T0_im((long)tb + 1); ! 583: gen_op_exit_tb(); ! 584: } ! 585: ! 586: static inline void gen_branch_a(DisasContext *dc, long tb, target_ulong pc1, target_ulong pc2) ! 587: { ! 588: int l1; ! 589: ! 590: l1 = gen_new_label(); ! 591: ! 592: gen_op_jz_T2_label(l1); ! 593: ! 594: gen_op_goto_tb0(TBPARAM(tb)); ! 595: gen_jmp_im(pc2); ! 596: gen_movl_npc_im(pc1); ! 597: gen_op_movl_T0_im((long)tb + 0); ! 598: gen_op_exit_tb(); ! 599: ! 600: gen_set_label(l1); ! 601: gen_op_goto_tb1(TBPARAM(tb)); ! 602: gen_jmp_im(pc2 + 4); ! 603: gen_movl_npc_im(pc2 + 8); ! 604: gen_op_movl_T0_im((long)tb + 1); ! 605: gen_op_exit_tb(); ! 606: } ! 607: ! 608: static inline void gen_branch(DisasContext *dc, long tb, target_ulong pc, target_ulong npc) ! 609: { ! 610: gen_op_goto_tb0(TBPARAM(tb)); ! 611: gen_jmp_im(pc); ! 612: gen_movl_npc_im(npc); ! 613: gen_op_movl_T0_im((long)tb + 0); ! 614: gen_op_exit_tb(); ! 615: } ! 616: ! 617: static inline void gen_generic_branch(DisasContext *dc, target_ulong npc1, target_ulong npc2) ! 618: { ! 619: int l1, l2; ! 620: ! 621: l1 = gen_new_label(); ! 622: l2 = gen_new_label(); ! 623: gen_op_jz_T2_label(l1); ! 624: ! 625: gen_movl_npc_im(npc1); ! 626: gen_op_jmp_label(l2); ! 627: ! 628: gen_set_label(l1); ! 629: gen_movl_npc_im(npc2); ! 630: gen_set_label(l2); ! 631: } ! 632: ! 633: /* call this function before using T2 as it may have been set for a jump */ ! 634: static inline void flush_T2(DisasContext * dc) ! 635: { ! 636: if (dc->npc == JUMP_PC) { ! 637: gen_generic_branch(dc, dc->jump_pc[0], dc->jump_pc[1]); ! 638: dc->npc = DYNAMIC_PC; ! 639: } ! 640: } ! 641: ! 642: static inline void save_npc(DisasContext * dc) ! 643: { ! 644: if (dc->npc == JUMP_PC) { ! 645: gen_generic_branch(dc, dc->jump_pc[0], dc->jump_pc[1]); ! 646: dc->npc = DYNAMIC_PC; ! 647: } else if (dc->npc != DYNAMIC_PC) { ! 648: gen_movl_npc_im(dc->npc); ! 649: } ! 650: } ! 651: ! 652: static inline void save_state(DisasContext * dc) ! 653: { ! 654: gen_jmp_im(dc->pc); ! 655: save_npc(dc); ! 656: } ! 657: ! 658: static inline void gen_mov_pc_npc(DisasContext * dc) ! 659: { ! 660: if (dc->npc == JUMP_PC) { ! 661: gen_generic_branch(dc, dc->jump_pc[0], dc->jump_pc[1]); ! 662: gen_op_mov_pc_npc(); ! 663: dc->pc = DYNAMIC_PC; ! 664: } else if (dc->npc == DYNAMIC_PC) { ! 665: gen_op_mov_pc_npc(); ! 666: dc->pc = DYNAMIC_PC; ! 667: } else { ! 668: dc->pc = dc->npc; ! 669: } ! 670: } ! 671: ! 672: static GenOpFunc * const gen_cond[2][16] = { ! 673: { ! 674: gen_op_eval_ba, ! 675: gen_op_eval_be, ! 676: gen_op_eval_ble, ! 677: gen_op_eval_bl, ! 678: gen_op_eval_bleu, ! 679: gen_op_eval_bcs, ! 680: gen_op_eval_bneg, ! 681: gen_op_eval_bvs, ! 682: gen_op_eval_bn, ! 683: gen_op_eval_bne, ! 684: gen_op_eval_bg, ! 685: gen_op_eval_bge, ! 686: gen_op_eval_bgu, ! 687: gen_op_eval_bcc, ! 688: gen_op_eval_bpos, ! 689: gen_op_eval_bvc, ! 690: }, ! 691: { ! 692: #ifdef TARGET_SPARC64 ! 693: gen_op_eval_ba, ! 694: gen_op_eval_xbe, ! 695: gen_op_eval_xble, ! 696: gen_op_eval_xbl, ! 697: gen_op_eval_xbleu, ! 698: gen_op_eval_xbcs, ! 699: gen_op_eval_xbneg, ! 700: gen_op_eval_xbvs, ! 701: gen_op_eval_bn, ! 702: gen_op_eval_xbne, ! 703: gen_op_eval_xbg, ! 704: gen_op_eval_xbge, ! 705: gen_op_eval_xbgu, ! 706: gen_op_eval_xbcc, ! 707: gen_op_eval_xbpos, ! 708: gen_op_eval_xbvc, ! 709: #endif ! 710: }, ! 711: }; ! 712: ! 713: static GenOpFunc * const gen_fcond[4][16] = { ! 714: { ! 715: gen_op_eval_ba, ! 716: gen_op_eval_fbne, ! 717: gen_op_eval_fblg, ! 718: gen_op_eval_fbul, ! 719: gen_op_eval_fbl, ! 720: gen_op_eval_fbug, ! 721: gen_op_eval_fbg, ! 722: gen_op_eval_fbu, ! 723: gen_op_eval_bn, ! 724: gen_op_eval_fbe, ! 725: gen_op_eval_fbue, ! 726: gen_op_eval_fbge, ! 727: gen_op_eval_fbuge, ! 728: gen_op_eval_fble, ! 729: gen_op_eval_fbule, ! 730: gen_op_eval_fbo, ! 731: }, ! 732: #ifdef TARGET_SPARC64 ! 733: { ! 734: gen_op_eval_ba, ! 735: gen_op_eval_fbne_fcc1, ! 736: gen_op_eval_fblg_fcc1, ! 737: gen_op_eval_fbul_fcc1, ! 738: gen_op_eval_fbl_fcc1, ! 739: gen_op_eval_fbug_fcc1, ! 740: gen_op_eval_fbg_fcc1, ! 741: gen_op_eval_fbu_fcc1, ! 742: gen_op_eval_bn, ! 743: gen_op_eval_fbe_fcc1, ! 744: gen_op_eval_fbue_fcc1, ! 745: gen_op_eval_fbge_fcc1, ! 746: gen_op_eval_fbuge_fcc1, ! 747: gen_op_eval_fble_fcc1, ! 748: gen_op_eval_fbule_fcc1, ! 749: gen_op_eval_fbo_fcc1, ! 750: }, ! 751: { ! 752: gen_op_eval_ba, ! 753: gen_op_eval_fbne_fcc2, ! 754: gen_op_eval_fblg_fcc2, ! 755: gen_op_eval_fbul_fcc2, ! 756: gen_op_eval_fbl_fcc2, ! 757: gen_op_eval_fbug_fcc2, ! 758: gen_op_eval_fbg_fcc2, ! 759: gen_op_eval_fbu_fcc2, ! 760: gen_op_eval_bn, ! 761: gen_op_eval_fbe_fcc2, ! 762: gen_op_eval_fbue_fcc2, ! 763: gen_op_eval_fbge_fcc2, ! 764: gen_op_eval_fbuge_fcc2, ! 765: gen_op_eval_fble_fcc2, ! 766: gen_op_eval_fbule_fcc2, ! 767: gen_op_eval_fbo_fcc2, ! 768: }, ! 769: { ! 770: gen_op_eval_ba, ! 771: gen_op_eval_fbne_fcc3, ! 772: gen_op_eval_fblg_fcc3, ! 773: gen_op_eval_fbul_fcc3, ! 774: gen_op_eval_fbl_fcc3, ! 775: gen_op_eval_fbug_fcc3, ! 776: gen_op_eval_fbg_fcc3, ! 777: gen_op_eval_fbu_fcc3, ! 778: gen_op_eval_bn, ! 779: gen_op_eval_fbe_fcc3, ! 780: gen_op_eval_fbue_fcc3, ! 781: gen_op_eval_fbge_fcc3, ! 782: gen_op_eval_fbuge_fcc3, ! 783: gen_op_eval_fble_fcc3, ! 784: gen_op_eval_fbule_fcc3, ! 785: gen_op_eval_fbo_fcc3, ! 786: }, ! 787: #else ! 788: {}, {}, {}, ! 789: #endif ! 790: }; ! 791: ! 792: #ifdef TARGET_SPARC64 ! 793: static void gen_cond_reg(int cond) ! 794: { ! 795: switch (cond) { ! 796: case 0x1: ! 797: gen_op_eval_brz(); ! 798: break; ! 799: case 0x2: ! 800: gen_op_eval_brlez(); ! 801: break; ! 802: case 0x3: ! 803: gen_op_eval_brlz(); ! 804: break; ! 805: case 0x5: ! 806: gen_op_eval_brnz(); ! 807: break; ! 808: case 0x6: ! 809: gen_op_eval_brgz(); ! 810: break; ! 811: default: ! 812: case 0x7: ! 813: gen_op_eval_brgez(); ! 814: break; ! 815: } ! 816: } ! 817: #endif ! 818: ! 819: /* XXX: potentially incorrect if dynamic npc */ ! 820: static void do_branch(DisasContext * dc, int32_t offset, uint32_t insn, int cc) ! 821: { ! 822: unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29)); ! 823: target_ulong target = dc->pc + offset; ! 824: ! 825: if (cond == 0x0) { ! 826: /* unconditional not taken */ ! 827: if (a) { ! 828: dc->pc = dc->npc + 4; ! 829: dc->npc = dc->pc + 4; ! 830: } else { ! 831: dc->pc = dc->npc; ! 832: dc->npc = dc->pc + 4; ! 833: } ! 834: } else if (cond == 0x8) { ! 835: /* unconditional taken */ ! 836: if (a) { ! 837: dc->pc = target; ! 838: dc->npc = dc->pc + 4; ! 839: } else { ! 840: dc->pc = dc->npc; ! 841: dc->npc = target; ! 842: } ! 843: } else { ! 844: flush_T2(dc); ! 845: gen_cond[cc][cond](); ! 846: if (a) { ! 847: gen_branch_a(dc, (long)dc->tb, target, dc->npc); ! 848: dc->is_br = 1; ! 849: } else { ! 850: dc->pc = dc->npc; ! 851: dc->jump_pc[0] = target; ! 852: dc->jump_pc[1] = dc->npc + 4; ! 853: dc->npc = JUMP_PC; ! 854: } ! 855: } ! 856: } ! 857: ! 858: /* XXX: potentially incorrect if dynamic npc */ ! 859: static void do_fbranch(DisasContext * dc, int32_t offset, uint32_t insn, int cc) ! 860: { ! 861: unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29)); ! 862: target_ulong target = dc->pc + offset; ! 863: ! 864: if (cond == 0x0) { ! 865: /* unconditional not taken */ ! 866: if (a) { ! 867: dc->pc = dc->npc + 4; ! 868: dc->npc = dc->pc + 4; ! 869: } else { ! 870: dc->pc = dc->npc; ! 871: dc->npc = dc->pc + 4; ! 872: } ! 873: } else if (cond == 0x8) { ! 874: /* unconditional taken */ ! 875: if (a) { ! 876: dc->pc = target; ! 877: dc->npc = dc->pc + 4; ! 878: } else { ! 879: dc->pc = dc->npc; ! 880: dc->npc = target; ! 881: } ! 882: } else { ! 883: flush_T2(dc); ! 884: gen_fcond[cc][cond](); ! 885: if (a) { ! 886: gen_branch_a(dc, (long)dc->tb, target, dc->npc); ! 887: dc->is_br = 1; ! 888: } else { ! 889: dc->pc = dc->npc; ! 890: dc->jump_pc[0] = target; ! 891: dc->jump_pc[1] = dc->npc + 4; ! 892: dc->npc = JUMP_PC; ! 893: } ! 894: } ! 895: } ! 896: ! 897: #ifdef TARGET_SPARC64 ! 898: /* XXX: potentially incorrect if dynamic npc */ ! 899: static void do_branch_reg(DisasContext * dc, int32_t offset, uint32_t insn) ! 900: { ! 901: unsigned int cond = GET_FIELD_SP(insn, 25, 27), a = (insn & (1 << 29)); ! 902: target_ulong target = dc->pc + offset; ! 903: ! 904: flush_T2(dc); ! 905: gen_cond_reg(cond); ! 906: if (a) { ! 907: gen_branch_a(dc, (long)dc->tb, target, dc->npc); ! 908: dc->is_br = 1; ! 909: } else { ! 910: dc->pc = dc->npc; ! 911: dc->jump_pc[0] = target; ! 912: dc->jump_pc[1] = dc->npc + 4; ! 913: dc->npc = JUMP_PC; ! 914: } ! 915: } ! 916: ! 917: static GenOpFunc * const gen_fcmps[4] = { ! 918: gen_op_fcmps, ! 919: gen_op_fcmps_fcc1, ! 920: gen_op_fcmps_fcc2, ! 921: gen_op_fcmps_fcc3, ! 922: }; ! 923: ! 924: static GenOpFunc * const gen_fcmpd[4] = { ! 925: gen_op_fcmpd, ! 926: gen_op_fcmpd_fcc1, ! 927: gen_op_fcmpd_fcc2, ! 928: gen_op_fcmpd_fcc3, ! 929: }; ! 930: #endif ! 931: ! 932: /* before an instruction, dc->pc must be static */ ! 933: static void disas_sparc_insn(DisasContext * dc) ! 934: { ! 935: unsigned int insn, opc, rs1, rs2, rd; ! 936: ! 937: insn = ldl_code(dc->pc); ! 938: opc = GET_FIELD(insn, 0, 1); ! 939: ! 940: rd = GET_FIELD(insn, 2, 6); ! 941: switch (opc) { ! 942: case 0: /* branches/sethi */ ! 943: { ! 944: unsigned int xop = GET_FIELD(insn, 7, 9); ! 945: int32_t target; ! 946: switch (xop) { ! 947: #ifdef TARGET_SPARC64 ! 948: case 0x1: /* V9 BPcc */ ! 949: { ! 950: int cc; ! 951: ! 952: target = GET_FIELD_SP(insn, 0, 18); ! 953: target <<= 2; ! 954: target = sign_extend(target, 18); ! 955: cc = GET_FIELD_SP(insn, 20, 21); ! 956: if (cc == 0) ! 957: do_branch(dc, target, insn, 0); ! 958: else if (cc == 2) ! 959: do_branch(dc, target, insn, 1); ! 960: else ! 961: goto illegal_insn; ! 962: goto jmp_insn; ! 963: } ! 964: case 0x3: /* V9 BPr */ ! 965: { ! 966: target = GET_FIELD_SP(insn, 0, 13) | ! 967: (GET_FIELD_SP(insn, 20, 21) >> 7); ! 968: target <<= 2; ! 969: target = sign_extend(target, 16); ! 970: rs1 = GET_FIELD(insn, 13, 17); ! 971: gen_movl_reg_T0(rs1); ! 972: do_branch_reg(dc, target, insn); ! 973: goto jmp_insn; ! 974: } ! 975: case 0x5: /* V9 FBPcc */ ! 976: { ! 977: int cc = GET_FIELD_SP(insn, 20, 21); ! 978: #if !defined(CONFIG_USER_ONLY) ! 979: gen_op_trap_ifnofpu(); ! 980: #endif ! 981: target = GET_FIELD_SP(insn, 0, 18); ! 982: target <<= 2; ! 983: target = sign_extend(target, 19); ! 984: do_fbranch(dc, target, insn, cc); ! 985: goto jmp_insn; ! 986: } ! 987: #endif ! 988: case 0x2: /* BN+x */ ! 989: { ! 990: target = GET_FIELD(insn, 10, 31); ! 991: target <<= 2; ! 992: target = sign_extend(target, 22); ! 993: do_branch(dc, target, insn, 0); ! 994: goto jmp_insn; ! 995: } ! 996: case 0x6: /* FBN+x */ ! 997: { ! 998: #if !defined(CONFIG_USER_ONLY) ! 999: gen_op_trap_ifnofpu(); ! 1000: #endif ! 1001: target = GET_FIELD(insn, 10, 31); ! 1002: target <<= 2; ! 1003: target = sign_extend(target, 22); ! 1004: do_fbranch(dc, target, insn, 0); ! 1005: goto jmp_insn; ! 1006: } ! 1007: case 0x4: /* SETHI */ ! 1008: #define OPTIM ! 1009: #if defined(OPTIM) ! 1010: if (rd) { // nop ! 1011: #endif ! 1012: uint32_t value = GET_FIELD(insn, 10, 31); ! 1013: gen_movl_imm_T0(value << 10); ! 1014: gen_movl_T0_reg(rd); ! 1015: #if defined(OPTIM) ! 1016: } ! 1017: #endif ! 1018: break; ! 1019: case 0x0: /* UNIMPL */ ! 1020: default: ! 1021: goto illegal_insn; ! 1022: } ! 1023: break; ! 1024: } ! 1025: break; ! 1026: case 1: ! 1027: /*CALL*/ { ! 1028: target_long target = GET_FIELDs(insn, 2, 31) << 2; ! 1029: ! 1030: #ifdef TARGET_SPARC64 ! 1031: if (dc->pc == (uint32_t)dc->pc) { ! 1032: gen_op_movl_T0_im(dc->pc); ! 1033: } else { ! 1034: gen_op_movq_T0_im64(dc->pc >> 32, dc->pc); ! 1035: } ! 1036: #else ! 1037: gen_op_movl_T0_im(dc->pc); ! 1038: #endif ! 1039: gen_movl_T0_reg(15); ! 1040: target += dc->pc; ! 1041: gen_mov_pc_npc(dc); ! 1042: dc->npc = target; ! 1043: } ! 1044: goto jmp_insn; ! 1045: case 2: /* FPU & Logical Operations */ ! 1046: { ! 1047: unsigned int xop = GET_FIELD(insn, 7, 12); ! 1048: if (xop == 0x3a) { /* generate trap */ ! 1049: int cond; ! 1050: ! 1051: rs1 = GET_FIELD(insn, 13, 17); ! 1052: gen_movl_reg_T0(rs1); ! 1053: if (IS_IMM) { ! 1054: rs2 = GET_FIELD(insn, 25, 31); ! 1055: #if defined(OPTIM) ! 1056: if (rs2 != 0) { ! 1057: #endif ! 1058: gen_movl_simm_T1(rs2); ! 1059: gen_op_add_T1_T0(); ! 1060: #if defined(OPTIM) ! 1061: } ! 1062: #endif ! 1063: } else { ! 1064: rs2 = GET_FIELD(insn, 27, 31); ! 1065: #if defined(OPTIM) ! 1066: if (rs2 != 0) { ! 1067: #endif ! 1068: gen_movl_reg_T1(rs2); ! 1069: gen_op_add_T1_T0(); ! 1070: #if defined(OPTIM) ! 1071: } ! 1072: #endif ! 1073: } ! 1074: save_state(dc); ! 1075: cond = GET_FIELD(insn, 3, 6); ! 1076: if (cond == 0x8) { ! 1077: gen_op_trap_T0(); ! 1078: dc->is_br = 1; ! 1079: goto jmp_insn; ! 1080: } else if (cond != 0) { ! 1081: #ifdef TARGET_SPARC64 ! 1082: /* V9 icc/xcc */ ! 1083: int cc = GET_FIELD_SP(insn, 11, 12); ! 1084: if (cc == 0) ! 1085: gen_cond[0][cond](); ! 1086: else if (cc == 2) ! 1087: gen_cond[1][cond](); ! 1088: else ! 1089: goto illegal_insn; ! 1090: #else ! 1091: gen_cond[0][cond](); ! 1092: #endif ! 1093: gen_op_trapcc_T0(); ! 1094: } ! 1095: } else if (xop == 0x28) { ! 1096: rs1 = GET_FIELD(insn, 13, 17); ! 1097: switch(rs1) { ! 1098: case 0: /* rdy */ ! 1099: gen_op_movtl_T0_env(offsetof(CPUSPARCState, y)); ! 1100: gen_movl_T0_reg(rd); ! 1101: break; ! 1102: case 15: /* stbar / V9 membar */ ! 1103: break; /* no effect? */ ! 1104: #ifdef TARGET_SPARC64 ! 1105: case 0x2: /* V9 rdccr */ ! 1106: gen_op_rdccr(); ! 1107: gen_movl_T0_reg(rd); ! 1108: break; ! 1109: case 0x3: /* V9 rdasi */ ! 1110: gen_op_movl_T0_env(offsetof(CPUSPARCState, asi)); ! 1111: gen_movl_T0_reg(rd); ! 1112: break; ! 1113: case 0x4: /* V9 rdtick */ ! 1114: gen_op_rdtick(); ! 1115: gen_movl_T0_reg(rd); ! 1116: break; ! 1117: case 0x5: /* V9 rdpc */ ! 1118: gen_op_movl_T0_im(dc->pc); ! 1119: gen_movl_T0_reg(rd); ! 1120: break; ! 1121: case 0x6: /* V9 rdfprs */ ! 1122: gen_op_movl_T0_env(offsetof(CPUSPARCState, fprs)); ! 1123: gen_movl_T0_reg(rd); ! 1124: break; ! 1125: case 0x17: /* Tick compare */ ! 1126: gen_op_movtl_T0_env(offsetof(CPUSPARCState, tick_cmpr)); ! 1127: gen_movl_T0_reg(rd); ! 1128: break; ! 1129: case 0x18: /* System tick */ ! 1130: gen_op_rdtick(); // XXX ! 1131: gen_movl_T0_reg(rd); ! 1132: break; ! 1133: case 0x19: /* System tick compare */ ! 1134: gen_op_movtl_T0_env(offsetof(CPUSPARCState, stick_cmpr)); ! 1135: gen_movl_T0_reg(rd); ! 1136: break; ! 1137: case 0x10: /* Performance Control */ ! 1138: case 0x11: /* Performance Instrumentation Counter */ ! 1139: case 0x12: /* Dispatch Control */ ! 1140: case 0x13: /* Graphics Status */ ! 1141: case 0x14: /* Softint set, WO */ ! 1142: case 0x15: /* Softint clear, WO */ ! 1143: case 0x16: /* Softint write */ ! 1144: #endif ! 1145: default: ! 1146: goto illegal_insn; ! 1147: } ! 1148: #if !defined(CONFIG_USER_ONLY) ! 1149: #ifndef TARGET_SPARC64 ! 1150: } else if (xop == 0x29) { /* rdpsr / V9 unimp */ ! 1151: if (!supervisor(dc)) ! 1152: goto priv_insn; ! 1153: gen_op_rdpsr(); ! 1154: gen_movl_T0_reg(rd); ! 1155: break; ! 1156: #endif ! 1157: } else if (xop == 0x2a) { /* rdwim / V9 rdpr */ ! 1158: if (!supervisor(dc)) ! 1159: goto priv_insn; ! 1160: #ifdef TARGET_SPARC64 ! 1161: rs1 = GET_FIELD(insn, 13, 17); ! 1162: switch (rs1) { ! 1163: case 0: // tpc ! 1164: gen_op_rdtpc(); ! 1165: break; ! 1166: case 1: // tnpc ! 1167: gen_op_rdtnpc(); ! 1168: break; ! 1169: case 2: // tstate ! 1170: gen_op_rdtstate(); ! 1171: break; ! 1172: case 3: // tt ! 1173: gen_op_rdtt(); ! 1174: break; ! 1175: case 4: // tick ! 1176: gen_op_rdtick(); ! 1177: break; ! 1178: case 5: // tba ! 1179: gen_op_movtl_T0_env(offsetof(CPUSPARCState, tbr)); ! 1180: break; ! 1181: case 6: // pstate ! 1182: gen_op_rdpstate(); ! 1183: break; ! 1184: case 7: // tl ! 1185: gen_op_movl_T0_env(offsetof(CPUSPARCState, tl)); ! 1186: break; ! 1187: case 8: // pil ! 1188: gen_op_movl_T0_env(offsetof(CPUSPARCState, psrpil)); ! 1189: break; ! 1190: case 9: // cwp ! 1191: gen_op_rdcwp(); ! 1192: break; ! 1193: case 10: // cansave ! 1194: gen_op_movl_T0_env(offsetof(CPUSPARCState, cansave)); ! 1195: break; ! 1196: case 11: // canrestore ! 1197: gen_op_movl_T0_env(offsetof(CPUSPARCState, canrestore)); ! 1198: break; ! 1199: case 12: // cleanwin ! 1200: gen_op_movl_T0_env(offsetof(CPUSPARCState, cleanwin)); ! 1201: break; ! 1202: case 13: // otherwin ! 1203: gen_op_movl_T0_env(offsetof(CPUSPARCState, otherwin)); ! 1204: break; ! 1205: case 14: // wstate ! 1206: gen_op_movl_T0_env(offsetof(CPUSPARCState, wstate)); ! 1207: break; ! 1208: case 31: // ver ! 1209: gen_op_movtl_T0_env(offsetof(CPUSPARCState, version)); ! 1210: break; ! 1211: case 15: // fq ! 1212: default: ! 1213: goto illegal_insn; ! 1214: } ! 1215: #else ! 1216: gen_op_movl_T0_env(offsetof(CPUSPARCState, wim)); ! 1217: #endif ! 1218: gen_movl_T0_reg(rd); ! 1219: break; ! 1220: } else if (xop == 0x2b) { /* rdtbr / V9 flushw */ ! 1221: #ifdef TARGET_SPARC64 ! 1222: gen_op_flushw(); ! 1223: #else ! 1224: if (!supervisor(dc)) ! 1225: goto priv_insn; ! 1226: gen_op_movtl_T0_env(offsetof(CPUSPARCState, tbr)); ! 1227: gen_movl_T0_reg(rd); ! 1228: #endif ! 1229: break; ! 1230: #endif ! 1231: } else if (xop == 0x34) { /* FPU Operations */ ! 1232: #if !defined(CONFIG_USER_ONLY) ! 1233: gen_op_trap_ifnofpu(); ! 1234: #endif ! 1235: rs1 = GET_FIELD(insn, 13, 17); ! 1236: rs2 = GET_FIELD(insn, 27, 31); ! 1237: xop = GET_FIELD(insn, 18, 26); ! 1238: switch (xop) { ! 1239: case 0x1: /* fmovs */ ! 1240: gen_op_load_fpr_FT0(rs2); ! 1241: gen_op_store_FT0_fpr(rd); ! 1242: break; ! 1243: case 0x5: /* fnegs */ ! 1244: gen_op_load_fpr_FT1(rs2); ! 1245: gen_op_fnegs(); ! 1246: gen_op_store_FT0_fpr(rd); ! 1247: break; ! 1248: case 0x9: /* fabss */ ! 1249: gen_op_load_fpr_FT1(rs2); ! 1250: gen_op_fabss(); ! 1251: gen_op_store_FT0_fpr(rd); ! 1252: break; ! 1253: case 0x29: /* fsqrts */ ! 1254: gen_op_load_fpr_FT1(rs2); ! 1255: gen_op_fsqrts(); ! 1256: gen_op_store_FT0_fpr(rd); ! 1257: break; ! 1258: case 0x2a: /* fsqrtd */ ! 1259: gen_op_load_fpr_DT1(DFPREG(rs2)); ! 1260: gen_op_fsqrtd(); ! 1261: gen_op_store_DT0_fpr(DFPREG(rd)); ! 1262: break; ! 1263: case 0x2b: /* fsqrtq */ ! 1264: goto nfpu_insn; ! 1265: case 0x41: ! 1266: gen_op_load_fpr_FT0(rs1); ! 1267: gen_op_load_fpr_FT1(rs2); ! 1268: gen_op_fadds(); ! 1269: gen_op_store_FT0_fpr(rd); ! 1270: break; ! 1271: case 0x42: ! 1272: gen_op_load_fpr_DT0(DFPREG(rs1)); ! 1273: gen_op_load_fpr_DT1(DFPREG(rs2)); ! 1274: gen_op_faddd(); ! 1275: gen_op_store_DT0_fpr(DFPREG(rd)); ! 1276: break; ! 1277: case 0x43: /* faddq */ ! 1278: goto nfpu_insn; ! 1279: case 0x45: ! 1280: gen_op_load_fpr_FT0(rs1); ! 1281: gen_op_load_fpr_FT1(rs2); ! 1282: gen_op_fsubs(); ! 1283: gen_op_store_FT0_fpr(rd); ! 1284: break; ! 1285: case 0x46: ! 1286: gen_op_load_fpr_DT0(DFPREG(rs1)); ! 1287: gen_op_load_fpr_DT1(DFPREG(rs2)); ! 1288: gen_op_fsubd(); ! 1289: gen_op_store_DT0_fpr(DFPREG(rd)); ! 1290: break; ! 1291: case 0x47: /* fsubq */ ! 1292: goto nfpu_insn; ! 1293: case 0x49: ! 1294: gen_op_load_fpr_FT0(rs1); ! 1295: gen_op_load_fpr_FT1(rs2); ! 1296: gen_op_fmuls(); ! 1297: gen_op_store_FT0_fpr(rd); ! 1298: break; ! 1299: case 0x4a: ! 1300: gen_op_load_fpr_DT0(DFPREG(rs1)); ! 1301: gen_op_load_fpr_DT1(DFPREG(rs2)); ! 1302: gen_op_fmuld(); ! 1303: gen_op_store_DT0_fpr(rd); ! 1304: break; ! 1305: case 0x4b: /* fmulq */ ! 1306: goto nfpu_insn; ! 1307: case 0x4d: ! 1308: gen_op_load_fpr_FT0(rs1); ! 1309: gen_op_load_fpr_FT1(rs2); ! 1310: gen_op_fdivs(); ! 1311: gen_op_store_FT0_fpr(rd); ! 1312: break; ! 1313: case 0x4e: ! 1314: gen_op_load_fpr_DT0(DFPREG(rs1)); ! 1315: gen_op_load_fpr_DT1(DFPREG(rs2)); ! 1316: gen_op_fdivd(); ! 1317: gen_op_store_DT0_fpr(DFPREG(rd)); ! 1318: break; ! 1319: case 0x4f: /* fdivq */ ! 1320: goto nfpu_insn; ! 1321: case 0x69: ! 1322: gen_op_load_fpr_FT0(rs1); ! 1323: gen_op_load_fpr_FT1(rs2); ! 1324: gen_op_fsmuld(); ! 1325: gen_op_store_DT0_fpr(DFPREG(rd)); ! 1326: break; ! 1327: case 0x6e: /* fdmulq */ ! 1328: goto nfpu_insn; ! 1329: case 0xc4: ! 1330: gen_op_load_fpr_FT1(rs2); ! 1331: gen_op_fitos(); ! 1332: gen_op_store_FT0_fpr(rd); ! 1333: break; ! 1334: case 0xc6: ! 1335: gen_op_load_fpr_DT1(DFPREG(rs2)); ! 1336: gen_op_fdtos(); ! 1337: gen_op_store_FT0_fpr(rd); ! 1338: break; ! 1339: case 0xc7: /* fqtos */ ! 1340: goto nfpu_insn; ! 1341: case 0xc8: ! 1342: gen_op_load_fpr_FT1(rs2); ! 1343: gen_op_fitod(); ! 1344: gen_op_store_DT0_fpr(DFPREG(rd)); ! 1345: break; ! 1346: case 0xc9: ! 1347: gen_op_load_fpr_FT1(rs2); ! 1348: gen_op_fstod(); ! 1349: gen_op_store_DT0_fpr(DFPREG(rd)); ! 1350: break; ! 1351: case 0xcb: /* fqtod */ ! 1352: goto nfpu_insn; ! 1353: case 0xcc: /* fitoq */ ! 1354: goto nfpu_insn; ! 1355: case 0xcd: /* fstoq */ ! 1356: goto nfpu_insn; ! 1357: case 0xce: /* fdtoq */ ! 1358: goto nfpu_insn; ! 1359: case 0xd1: ! 1360: gen_op_load_fpr_FT1(rs2); ! 1361: gen_op_fstoi(); ! 1362: gen_op_store_FT0_fpr(rd); ! 1363: break; ! 1364: case 0xd2: ! 1365: gen_op_load_fpr_DT1(rs2); ! 1366: gen_op_fdtoi(); ! 1367: gen_op_store_FT0_fpr(rd); ! 1368: break; ! 1369: case 0xd3: /* fqtoi */ ! 1370: goto nfpu_insn; ! 1371: #ifdef TARGET_SPARC64 ! 1372: case 0x2: /* V9 fmovd */ ! 1373: gen_op_load_fpr_DT0(DFPREG(rs2)); ! 1374: gen_op_store_DT0_fpr(DFPREG(rd)); ! 1375: break; ! 1376: case 0x6: /* V9 fnegd */ ! 1377: gen_op_load_fpr_DT1(DFPREG(rs2)); ! 1378: gen_op_fnegd(); ! 1379: gen_op_store_DT0_fpr(DFPREG(rd)); ! 1380: break; ! 1381: case 0xa: /* V9 fabsd */ ! 1382: gen_op_load_fpr_DT1(DFPREG(rs2)); ! 1383: gen_op_fabsd(); ! 1384: gen_op_store_DT0_fpr(DFPREG(rd)); ! 1385: break; ! 1386: case 0x81: /* V9 fstox */ ! 1387: gen_op_load_fpr_FT1(rs2); ! 1388: gen_op_fstox(); ! 1389: gen_op_store_DT0_fpr(DFPREG(rd)); ! 1390: break; ! 1391: case 0x82: /* V9 fdtox */ ! 1392: gen_op_load_fpr_DT1(DFPREG(rs2)); ! 1393: gen_op_fdtox(); ! 1394: gen_op_store_DT0_fpr(DFPREG(rd)); ! 1395: break; ! 1396: case 0x84: /* V9 fxtos */ ! 1397: gen_op_load_fpr_DT1(DFPREG(rs2)); ! 1398: gen_op_fxtos(); ! 1399: gen_op_store_FT0_fpr(rd); ! 1400: break; ! 1401: case 0x88: /* V9 fxtod */ ! 1402: gen_op_load_fpr_DT1(DFPREG(rs2)); ! 1403: gen_op_fxtod(); ! 1404: gen_op_store_DT0_fpr(DFPREG(rd)); ! 1405: break; ! 1406: case 0x3: /* V9 fmovq */ ! 1407: case 0x7: /* V9 fnegq */ ! 1408: case 0xb: /* V9 fabsq */ ! 1409: case 0x83: /* V9 fqtox */ ! 1410: case 0x8c: /* V9 fxtoq */ ! 1411: goto nfpu_insn; ! 1412: #endif ! 1413: default: ! 1414: goto illegal_insn; ! 1415: } ! 1416: } else if (xop == 0x35) { /* FPU Operations */ ! 1417: #ifdef TARGET_SPARC64 ! 1418: int cond; ! 1419: #endif ! 1420: #if !defined(CONFIG_USER_ONLY) ! 1421: gen_op_trap_ifnofpu(); ! 1422: #endif ! 1423: rs1 = GET_FIELD(insn, 13, 17); ! 1424: rs2 = GET_FIELD(insn, 27, 31); ! 1425: xop = GET_FIELD(insn, 18, 26); ! 1426: #ifdef TARGET_SPARC64 ! 1427: if ((xop & 0x11f) == 0x005) { // V9 fmovsr ! 1428: cond = GET_FIELD_SP(insn, 14, 17); ! 1429: gen_op_load_fpr_FT0(rd); ! 1430: gen_op_load_fpr_FT1(rs2); ! 1431: rs1 = GET_FIELD(insn, 13, 17); ! 1432: gen_movl_reg_T0(rs1); ! 1433: flush_T2(dc); ! 1434: gen_cond_reg(cond); ! 1435: gen_op_fmovs_cc(); ! 1436: gen_op_store_FT0_fpr(rd); ! 1437: break; ! 1438: } else if ((xop & 0x11f) == 0x006) { // V9 fmovdr ! 1439: cond = GET_FIELD_SP(insn, 14, 17); ! 1440: gen_op_load_fpr_DT0(rd); ! 1441: gen_op_load_fpr_DT1(rs2); ! 1442: flush_T2(dc); ! 1443: rs1 = GET_FIELD(insn, 13, 17); ! 1444: gen_movl_reg_T0(rs1); ! 1445: gen_cond_reg(cond); ! 1446: gen_op_fmovs_cc(); ! 1447: gen_op_store_DT0_fpr(rd); ! 1448: break; ! 1449: } else if ((xop & 0x11f) == 0x007) { // V9 fmovqr ! 1450: goto nfpu_insn; ! 1451: } ! 1452: #endif ! 1453: switch (xop) { ! 1454: #ifdef TARGET_SPARC64 ! 1455: case 0x001: /* V9 fmovscc %fcc0 */ ! 1456: cond = GET_FIELD_SP(insn, 14, 17); ! 1457: gen_op_load_fpr_FT0(rd); ! 1458: gen_op_load_fpr_FT1(rs2); ! 1459: flush_T2(dc); ! 1460: gen_fcond[0][cond](); ! 1461: gen_op_fmovs_cc(); ! 1462: gen_op_store_FT0_fpr(rd); ! 1463: break; ! 1464: case 0x002: /* V9 fmovdcc %fcc0 */ ! 1465: cond = GET_FIELD_SP(insn, 14, 17); ! 1466: gen_op_load_fpr_DT0(rd); ! 1467: gen_op_load_fpr_DT1(rs2); ! 1468: flush_T2(dc); ! 1469: gen_fcond[0][cond](); ! 1470: gen_op_fmovd_cc(); ! 1471: gen_op_store_DT0_fpr(rd); ! 1472: break; ! 1473: case 0x003: /* V9 fmovqcc %fcc0 */ ! 1474: goto nfpu_insn; ! 1475: case 0x041: /* V9 fmovscc %fcc1 */ ! 1476: cond = GET_FIELD_SP(insn, 14, 17); ! 1477: gen_op_load_fpr_FT0(rd); ! 1478: gen_op_load_fpr_FT1(rs2); ! 1479: flush_T2(dc); ! 1480: gen_fcond[1][cond](); ! 1481: gen_op_fmovs_cc(); ! 1482: gen_op_store_FT0_fpr(rd); ! 1483: break; ! 1484: case 0x042: /* V9 fmovdcc %fcc1 */ ! 1485: cond = GET_FIELD_SP(insn, 14, 17); ! 1486: gen_op_load_fpr_DT0(rd); ! 1487: gen_op_load_fpr_DT1(rs2); ! 1488: flush_T2(dc); ! 1489: gen_fcond[1][cond](); ! 1490: gen_op_fmovd_cc(); ! 1491: gen_op_store_DT0_fpr(rd); ! 1492: break; ! 1493: case 0x043: /* V9 fmovqcc %fcc1 */ ! 1494: goto nfpu_insn; ! 1495: case 0x081: /* V9 fmovscc %fcc2 */ ! 1496: cond = GET_FIELD_SP(insn, 14, 17); ! 1497: gen_op_load_fpr_FT0(rd); ! 1498: gen_op_load_fpr_FT1(rs2); ! 1499: flush_T2(dc); ! 1500: gen_fcond[2][cond](); ! 1501: gen_op_fmovs_cc(); ! 1502: gen_op_store_FT0_fpr(rd); ! 1503: break; ! 1504: case 0x082: /* V9 fmovdcc %fcc2 */ ! 1505: cond = GET_FIELD_SP(insn, 14, 17); ! 1506: gen_op_load_fpr_DT0(rd); ! 1507: gen_op_load_fpr_DT1(rs2); ! 1508: flush_T2(dc); ! 1509: gen_fcond[2][cond](); ! 1510: gen_op_fmovd_cc(); ! 1511: gen_op_store_DT0_fpr(rd); ! 1512: break; ! 1513: case 0x083: /* V9 fmovqcc %fcc2 */ ! 1514: goto nfpu_insn; ! 1515: case 0x0c1: /* V9 fmovscc %fcc3 */ ! 1516: cond = GET_FIELD_SP(insn, 14, 17); ! 1517: gen_op_load_fpr_FT0(rd); ! 1518: gen_op_load_fpr_FT1(rs2); ! 1519: flush_T2(dc); ! 1520: gen_fcond[3][cond](); ! 1521: gen_op_fmovs_cc(); ! 1522: gen_op_store_FT0_fpr(rd); ! 1523: break; ! 1524: case 0x0c2: /* V9 fmovdcc %fcc3 */ ! 1525: cond = GET_FIELD_SP(insn, 14, 17); ! 1526: gen_op_load_fpr_DT0(rd); ! 1527: gen_op_load_fpr_DT1(rs2); ! 1528: flush_T2(dc); ! 1529: gen_fcond[3][cond](); ! 1530: gen_op_fmovd_cc(); ! 1531: gen_op_store_DT0_fpr(rd); ! 1532: break; ! 1533: case 0x0c3: /* V9 fmovqcc %fcc3 */ ! 1534: goto nfpu_insn; ! 1535: case 0x101: /* V9 fmovscc %icc */ ! 1536: cond = GET_FIELD_SP(insn, 14, 17); ! 1537: gen_op_load_fpr_FT0(rd); ! 1538: gen_op_load_fpr_FT1(rs2); ! 1539: flush_T2(dc); ! 1540: gen_cond[0][cond](); ! 1541: gen_op_fmovs_cc(); ! 1542: gen_op_store_FT0_fpr(rd); ! 1543: break; ! 1544: case 0x102: /* V9 fmovdcc %icc */ ! 1545: cond = GET_FIELD_SP(insn, 14, 17); ! 1546: gen_op_load_fpr_DT0(rd); ! 1547: gen_op_load_fpr_DT1(rs2); ! 1548: flush_T2(dc); ! 1549: gen_cond[0][cond](); ! 1550: gen_op_fmovd_cc(); ! 1551: gen_op_store_DT0_fpr(rd); ! 1552: break; ! 1553: case 0x103: /* V9 fmovqcc %icc */ ! 1554: goto nfpu_insn; ! 1555: case 0x181: /* V9 fmovscc %xcc */ ! 1556: cond = GET_FIELD_SP(insn, 14, 17); ! 1557: gen_op_load_fpr_FT0(rd); ! 1558: gen_op_load_fpr_FT1(rs2); ! 1559: flush_T2(dc); ! 1560: gen_cond[1][cond](); ! 1561: gen_op_fmovs_cc(); ! 1562: gen_op_store_FT0_fpr(rd); ! 1563: break; ! 1564: case 0x182: /* V9 fmovdcc %xcc */ ! 1565: cond = GET_FIELD_SP(insn, 14, 17); ! 1566: gen_op_load_fpr_DT0(rd); ! 1567: gen_op_load_fpr_DT1(rs2); ! 1568: flush_T2(dc); ! 1569: gen_cond[1][cond](); ! 1570: gen_op_fmovd_cc(); ! 1571: gen_op_store_DT0_fpr(rd); ! 1572: break; ! 1573: case 0x183: /* V9 fmovqcc %xcc */ ! 1574: goto nfpu_insn; ! 1575: #endif ! 1576: case 0x51: /* V9 %fcc */ ! 1577: gen_op_load_fpr_FT0(rs1); ! 1578: gen_op_load_fpr_FT1(rs2); ! 1579: #ifdef TARGET_SPARC64 ! 1580: gen_fcmps[rd & 3](); ! 1581: #else ! 1582: gen_op_fcmps(); ! 1583: #endif ! 1584: break; ! 1585: case 0x52: /* V9 %fcc */ ! 1586: gen_op_load_fpr_DT0(DFPREG(rs1)); ! 1587: gen_op_load_fpr_DT1(DFPREG(rs2)); ! 1588: #ifdef TARGET_SPARC64 ! 1589: gen_fcmpd[rd & 3](); ! 1590: #else ! 1591: gen_op_fcmpd(); ! 1592: #endif ! 1593: break; ! 1594: case 0x53: /* fcmpq */ ! 1595: goto nfpu_insn; ! 1596: case 0x55: /* fcmpes, V9 %fcc */ ! 1597: gen_op_load_fpr_FT0(rs1); ! 1598: gen_op_load_fpr_FT1(rs2); ! 1599: #ifdef TARGET_SPARC64 ! 1600: gen_fcmps[rd & 3](); ! 1601: #else ! 1602: gen_op_fcmps(); /* XXX should trap if qNaN or sNaN */ ! 1603: #endif ! 1604: break; ! 1605: case 0x56: /* fcmped, V9 %fcc */ ! 1606: gen_op_load_fpr_DT0(DFPREG(rs1)); ! 1607: gen_op_load_fpr_DT1(DFPREG(rs2)); ! 1608: #ifdef TARGET_SPARC64 ! 1609: gen_fcmpd[rd & 3](); ! 1610: #else ! 1611: gen_op_fcmpd(); /* XXX should trap if qNaN or sNaN */ ! 1612: #endif ! 1613: break; ! 1614: case 0x57: /* fcmpeq */ ! 1615: goto nfpu_insn; ! 1616: default: ! 1617: goto illegal_insn; ! 1618: } ! 1619: #if defined(OPTIM) ! 1620: } else if (xop == 0x2) { ! 1621: // clr/mov shortcut ! 1622: ! 1623: rs1 = GET_FIELD(insn, 13, 17); ! 1624: if (rs1 == 0) { ! 1625: // or %g0, x, y -> mov T1, x; mov y, T1 ! 1626: if (IS_IMM) { /* immediate */ ! 1627: rs2 = GET_FIELDs(insn, 19, 31); ! 1628: gen_movl_simm_T1(rs2); ! 1629: } else { /* register */ ! 1630: rs2 = GET_FIELD(insn, 27, 31); ! 1631: gen_movl_reg_T1(rs2); ! 1632: } ! 1633: gen_movl_T1_reg(rd); ! 1634: } else { ! 1635: gen_movl_reg_T0(rs1); ! 1636: if (IS_IMM) { /* immediate */ ! 1637: // or x, #0, y -> mov T1, x; mov y, T1 ! 1638: rs2 = GET_FIELDs(insn, 19, 31); ! 1639: if (rs2 != 0) { ! 1640: gen_movl_simm_T1(rs2); ! 1641: gen_op_or_T1_T0(); ! 1642: } ! 1643: } else { /* register */ ! 1644: // or x, %g0, y -> mov T1, x; mov y, T1 ! 1645: rs2 = GET_FIELD(insn, 27, 31); ! 1646: if (rs2 != 0) { ! 1647: gen_movl_reg_T1(rs2); ! 1648: gen_op_or_T1_T0(); ! 1649: } ! 1650: } ! 1651: gen_movl_T0_reg(rd); ! 1652: } ! 1653: #endif ! 1654: #ifdef TARGET_SPARC64 ! 1655: } else if (xop == 0x25) { /* sll, V9 sllx ( == sll) */ ! 1656: rs1 = GET_FIELD(insn, 13, 17); ! 1657: gen_movl_reg_T0(rs1); ! 1658: if (IS_IMM) { /* immediate */ ! 1659: rs2 = GET_FIELDs(insn, 20, 31); ! 1660: gen_movl_simm_T1(rs2); ! 1661: } else { /* register */ ! 1662: rs2 = GET_FIELD(insn, 27, 31); ! 1663: gen_movl_reg_T1(rs2); ! 1664: } ! 1665: gen_op_sll(); ! 1666: gen_movl_T0_reg(rd); ! 1667: } else if (xop == 0x26) { /* srl, V9 srlx */ ! 1668: rs1 = GET_FIELD(insn, 13, 17); ! 1669: gen_movl_reg_T0(rs1); ! 1670: if (IS_IMM) { /* immediate */ ! 1671: rs2 = GET_FIELDs(insn, 20, 31); ! 1672: gen_movl_simm_T1(rs2); ! 1673: } else { /* register */ ! 1674: rs2 = GET_FIELD(insn, 27, 31); ! 1675: gen_movl_reg_T1(rs2); ! 1676: } ! 1677: if (insn & (1 << 12)) ! 1678: gen_op_srlx(); ! 1679: else ! 1680: gen_op_srl(); ! 1681: gen_movl_T0_reg(rd); ! 1682: } else if (xop == 0x27) { /* sra, V9 srax */ ! 1683: rs1 = GET_FIELD(insn, 13, 17); ! 1684: gen_movl_reg_T0(rs1); ! 1685: if (IS_IMM) { /* immediate */ ! 1686: rs2 = GET_FIELDs(insn, 20, 31); ! 1687: gen_movl_simm_T1(rs2); ! 1688: } else { /* register */ ! 1689: rs2 = GET_FIELD(insn, 27, 31); ! 1690: gen_movl_reg_T1(rs2); ! 1691: } ! 1692: if (insn & (1 << 12)) ! 1693: gen_op_srax(); ! 1694: else ! 1695: gen_op_sra(); ! 1696: gen_movl_T0_reg(rd); ! 1697: #endif ! 1698: } else if (xop < 0x38) { ! 1699: rs1 = GET_FIELD(insn, 13, 17); ! 1700: gen_movl_reg_T0(rs1); ! 1701: if (IS_IMM) { /* immediate */ ! 1702: rs2 = GET_FIELDs(insn, 19, 31); ! 1703: gen_movl_simm_T1(rs2); ! 1704: } else { /* register */ ! 1705: rs2 = GET_FIELD(insn, 27, 31); ! 1706: gen_movl_reg_T1(rs2); ! 1707: } ! 1708: if (xop < 0x20) { ! 1709: switch (xop & ~0x10) { ! 1710: case 0x0: ! 1711: if (xop & 0x10) ! 1712: gen_op_add_T1_T0_cc(); ! 1713: else ! 1714: gen_op_add_T1_T0(); ! 1715: break; ! 1716: case 0x1: ! 1717: gen_op_and_T1_T0(); ! 1718: if (xop & 0x10) ! 1719: gen_op_logic_T0_cc(); ! 1720: break; ! 1721: case 0x2: ! 1722: gen_op_or_T1_T0(); ! 1723: if (xop & 0x10) ! 1724: gen_op_logic_T0_cc(); ! 1725: break; ! 1726: case 0x3: ! 1727: gen_op_xor_T1_T0(); ! 1728: if (xop & 0x10) ! 1729: gen_op_logic_T0_cc(); ! 1730: break; ! 1731: case 0x4: ! 1732: if (xop & 0x10) ! 1733: gen_op_sub_T1_T0_cc(); ! 1734: else ! 1735: gen_op_sub_T1_T0(); ! 1736: break; ! 1737: case 0x5: ! 1738: gen_op_andn_T1_T0(); ! 1739: if (xop & 0x10) ! 1740: gen_op_logic_T0_cc(); ! 1741: break; ! 1742: case 0x6: ! 1743: gen_op_orn_T1_T0(); ! 1744: if (xop & 0x10) ! 1745: gen_op_logic_T0_cc(); ! 1746: break; ! 1747: case 0x7: ! 1748: gen_op_xnor_T1_T0(); ! 1749: if (xop & 0x10) ! 1750: gen_op_logic_T0_cc(); ! 1751: break; ! 1752: case 0x8: ! 1753: if (xop & 0x10) ! 1754: gen_op_addx_T1_T0_cc(); ! 1755: else ! 1756: gen_op_addx_T1_T0(); ! 1757: break; ! 1758: case 0xa: ! 1759: gen_op_umul_T1_T0(); ! 1760: if (xop & 0x10) ! 1761: gen_op_logic_T0_cc(); ! 1762: break; ! 1763: case 0xb: ! 1764: gen_op_smul_T1_T0(); ! 1765: if (xop & 0x10) ! 1766: gen_op_logic_T0_cc(); ! 1767: break; ! 1768: case 0xc: ! 1769: if (xop & 0x10) ! 1770: gen_op_subx_T1_T0_cc(); ! 1771: else ! 1772: gen_op_subx_T1_T0(); ! 1773: break; ! 1774: case 0xe: ! 1775: gen_op_udiv_T1_T0(); ! 1776: if (xop & 0x10) ! 1777: gen_op_div_cc(); ! 1778: break; ! 1779: case 0xf: ! 1780: gen_op_sdiv_T1_T0(); ! 1781: if (xop & 0x10) ! 1782: gen_op_div_cc(); ! 1783: break; ! 1784: default: ! 1785: goto illegal_insn; ! 1786: } ! 1787: gen_movl_T0_reg(rd); ! 1788: } else { ! 1789: switch (xop) { ! 1790: #ifdef TARGET_SPARC64 ! 1791: case 0x9: /* V9 mulx */ ! 1792: gen_op_mulx_T1_T0(); ! 1793: gen_movl_T0_reg(rd); ! 1794: break; ! 1795: case 0xd: /* V9 udivx */ ! 1796: gen_op_udivx_T1_T0(); ! 1797: gen_movl_T0_reg(rd); ! 1798: break; ! 1799: #endif ! 1800: case 0x20: /* taddcc */ ! 1801: case 0x21: /* tsubcc */ ! 1802: case 0x22: /* taddcctv */ ! 1803: case 0x23: /* tsubcctv */ ! 1804: goto illegal_insn; ! 1805: case 0x24: /* mulscc */ ! 1806: gen_op_mulscc_T1_T0(); ! 1807: gen_movl_T0_reg(rd); ! 1808: break; ! 1809: #ifndef TARGET_SPARC64 ! 1810: case 0x25: /* sll */ ! 1811: gen_op_sll(); ! 1812: gen_movl_T0_reg(rd); ! 1813: break; ! 1814: case 0x26: /* srl */ ! 1815: gen_op_srl(); ! 1816: gen_movl_T0_reg(rd); ! 1817: break; ! 1818: case 0x27: /* sra */ ! 1819: gen_op_sra(); ! 1820: gen_movl_T0_reg(rd); ! 1821: break; ! 1822: #endif ! 1823: case 0x30: ! 1824: { ! 1825: switch(rd) { ! 1826: case 0: /* wry */ ! 1827: gen_op_xor_T1_T0(); ! 1828: gen_op_movtl_env_T0(offsetof(CPUSPARCState, y)); ! 1829: break; ! 1830: #ifdef TARGET_SPARC64 ! 1831: case 0x2: /* V9 wrccr */ ! 1832: gen_op_wrccr(); ! 1833: break; ! 1834: case 0x3: /* V9 wrasi */ ! 1835: gen_op_movl_env_T0(offsetof(CPUSPARCState, asi)); ! 1836: break; ! 1837: case 0x6: /* V9 wrfprs */ ! 1838: gen_op_movl_env_T0(offsetof(CPUSPARCState, fprs)); ! 1839: break; ! 1840: case 0xf: /* V9 sir, nop if user */ ! 1841: #if !defined(CONFIG_USER_ONLY) ! 1842: if (supervisor(dc)) ! 1843: gen_op_sir(); ! 1844: #endif ! 1845: break; ! 1846: case 0x17: /* Tick compare */ ! 1847: #if !defined(CONFIG_USER_ONLY) ! 1848: if (!supervisor(dc)) ! 1849: goto illegal_insn; ! 1850: #endif ! 1851: gen_op_movtl_env_T0(offsetof(CPUSPARCState, tick_cmpr)); ! 1852: break; ! 1853: case 0x18: /* System tick */ ! 1854: #if !defined(CONFIG_USER_ONLY) ! 1855: if (!supervisor(dc)) ! 1856: goto illegal_insn; ! 1857: #endif ! 1858: gen_op_movtl_env_T0(offsetof(CPUSPARCState, stick_cmpr)); ! 1859: break; ! 1860: case 0x19: /* System tick compare */ ! 1861: #if !defined(CONFIG_USER_ONLY) ! 1862: if (!supervisor(dc)) ! 1863: goto illegal_insn; ! 1864: #endif ! 1865: gen_op_movtl_env_T0(offsetof(CPUSPARCState, stick_cmpr)); ! 1866: break; ! 1867: ! 1868: case 0x10: /* Performance Control */ ! 1869: case 0x11: /* Performance Instrumentation Counter */ ! 1870: case 0x12: /* Dispatch Control */ ! 1871: case 0x13: /* Graphics Status */ ! 1872: case 0x14: /* Softint set */ ! 1873: case 0x15: /* Softint clear */ ! 1874: case 0x16: /* Softint write */ ! 1875: #endif ! 1876: default: ! 1877: goto illegal_insn; ! 1878: } ! 1879: } ! 1880: break; ! 1881: #if !defined(CONFIG_USER_ONLY) ! 1882: case 0x31: /* wrpsr, V9 saved, restored */ ! 1883: { ! 1884: if (!supervisor(dc)) ! 1885: goto priv_insn; ! 1886: #ifdef TARGET_SPARC64 ! 1887: switch (rd) { ! 1888: case 0: ! 1889: gen_op_saved(); ! 1890: break; ! 1891: case 1: ! 1892: gen_op_restored(); ! 1893: break; ! 1894: default: ! 1895: goto illegal_insn; ! 1896: } ! 1897: #else ! 1898: gen_op_xor_T1_T0(); ! 1899: gen_op_wrpsr(); ! 1900: #endif ! 1901: } ! 1902: break; ! 1903: case 0x32: /* wrwim, V9 wrpr */ ! 1904: { ! 1905: if (!supervisor(dc)) ! 1906: goto priv_insn; ! 1907: gen_op_xor_T1_T0(); ! 1908: #ifdef TARGET_SPARC64 ! 1909: switch (rd) { ! 1910: case 0: // tpc ! 1911: gen_op_wrtpc(); ! 1912: break; ! 1913: case 1: // tnpc ! 1914: gen_op_wrtnpc(); ! 1915: break; ! 1916: case 2: // tstate ! 1917: gen_op_wrtstate(); ! 1918: break; ! 1919: case 3: // tt ! 1920: gen_op_wrtt(); ! 1921: break; ! 1922: case 4: // tick ! 1923: gen_op_wrtick(); ! 1924: break; ! 1925: case 5: // tba ! 1926: gen_op_movtl_env_T0(offsetof(CPUSPARCState, tbr)); ! 1927: break; ! 1928: case 6: // pstate ! 1929: gen_op_wrpstate(); ! 1930: break; ! 1931: case 7: // tl ! 1932: gen_op_movl_env_T0(offsetof(CPUSPARCState, tl)); ! 1933: break; ! 1934: case 8: // pil ! 1935: gen_op_movl_env_T0(offsetof(CPUSPARCState, psrpil)); ! 1936: break; ! 1937: case 9: // cwp ! 1938: gen_op_wrcwp(); ! 1939: break; ! 1940: case 10: // cansave ! 1941: gen_op_movl_env_T0(offsetof(CPUSPARCState, cansave)); ! 1942: break; ! 1943: case 11: // canrestore ! 1944: gen_op_movl_env_T0(offsetof(CPUSPARCState, canrestore)); ! 1945: break; ! 1946: case 12: // cleanwin ! 1947: gen_op_movl_env_T0(offsetof(CPUSPARCState, cleanwin)); ! 1948: break; ! 1949: case 13: // otherwin ! 1950: gen_op_movl_env_T0(offsetof(CPUSPARCState, otherwin)); ! 1951: break; ! 1952: case 14: // wstate ! 1953: gen_op_movl_env_T0(offsetof(CPUSPARCState, wstate)); ! 1954: break; ! 1955: default: ! 1956: goto illegal_insn; ! 1957: } ! 1958: #else ! 1959: gen_op_movl_env_T0(offsetof(CPUSPARCState, wim)); ! 1960: #endif ! 1961: } ! 1962: break; ! 1963: #ifndef TARGET_SPARC64 ! 1964: case 0x33: /* wrtbr, V9 unimp */ ! 1965: { ! 1966: if (!supervisor(dc)) ! 1967: goto priv_insn; ! 1968: gen_op_xor_T1_T0(); ! 1969: gen_op_movtl_env_T0(offsetof(CPUSPARCState, tbr)); ! 1970: } ! 1971: break; ! 1972: #endif ! 1973: #endif ! 1974: #ifdef TARGET_SPARC64 ! 1975: case 0x2c: /* V9 movcc */ ! 1976: { ! 1977: int cc = GET_FIELD_SP(insn, 11, 12); ! 1978: int cond = GET_FIELD_SP(insn, 14, 17); ! 1979: if (IS_IMM) { /* immediate */ ! 1980: rs2 = GET_FIELD_SPs(insn, 0, 10); ! 1981: gen_movl_simm_T1(rs2); ! 1982: } ! 1983: else { ! 1984: rs2 = GET_FIELD_SP(insn, 0, 4); ! 1985: gen_movl_reg_T1(rs2); ! 1986: } ! 1987: gen_movl_reg_T0(rd); ! 1988: flush_T2(dc); ! 1989: if (insn & (1 << 18)) { ! 1990: if (cc == 0) ! 1991: gen_cond[0][cond](); ! 1992: else if (cc == 2) ! 1993: gen_cond[1][cond](); ! 1994: else ! 1995: goto illegal_insn; ! 1996: } else { ! 1997: gen_fcond[cc][cond](); ! 1998: } ! 1999: gen_op_mov_cc(); ! 2000: gen_movl_T0_reg(rd); ! 2001: break; ! 2002: } ! 2003: case 0x2d: /* V9 sdivx */ ! 2004: gen_op_sdivx_T1_T0(); ! 2005: gen_movl_T0_reg(rd); ! 2006: break; ! 2007: case 0x2e: /* V9 popc */ ! 2008: { ! 2009: if (IS_IMM) { /* immediate */ ! 2010: rs2 = GET_FIELD_SPs(insn, 0, 12); ! 2011: gen_movl_simm_T1(rs2); ! 2012: // XXX optimize: popc(constant) ! 2013: } ! 2014: else { ! 2015: rs2 = GET_FIELD_SP(insn, 0, 4); ! 2016: gen_movl_reg_T1(rs2); ! 2017: } ! 2018: gen_op_popc(); ! 2019: gen_movl_T0_reg(rd); ! 2020: } ! 2021: case 0x2f: /* V9 movr */ ! 2022: { ! 2023: int cond = GET_FIELD_SP(insn, 10, 12); ! 2024: rs1 = GET_FIELD(insn, 13, 17); ! 2025: flush_T2(dc); ! 2026: gen_movl_reg_T0(rs1); ! 2027: gen_cond_reg(cond); ! 2028: if (IS_IMM) { /* immediate */ ! 2029: rs2 = GET_FIELD_SPs(insn, 0, 10); ! 2030: gen_movl_simm_T1(rs2); ! 2031: } ! 2032: else { ! 2033: rs2 = GET_FIELD_SP(insn, 0, 4); ! 2034: gen_movl_reg_T1(rs2); ! 2035: } ! 2036: gen_movl_reg_T0(rd); ! 2037: gen_op_mov_cc(); ! 2038: gen_movl_T0_reg(rd); ! 2039: break; ! 2040: } ! 2041: case 0x36: /* UltraSparc shutdown, VIS */ ! 2042: { ! 2043: // XXX ! 2044: } ! 2045: #endif ! 2046: default: ! 2047: goto illegal_insn; ! 2048: } ! 2049: } ! 2050: #ifdef TARGET_SPARC64 ! 2051: } else if (xop == 0x39) { /* V9 return */ ! 2052: rs1 = GET_FIELD(insn, 13, 17); ! 2053: gen_movl_reg_T0(rs1); ! 2054: if (IS_IMM) { /* immediate */ ! 2055: rs2 = GET_FIELDs(insn, 19, 31); ! 2056: #if defined(OPTIM) ! 2057: if (rs2) { ! 2058: #endif ! 2059: gen_movl_simm_T1(rs2); ! 2060: gen_op_add_T1_T0(); ! 2061: #if defined(OPTIM) ! 2062: } ! 2063: #endif ! 2064: } else { /* register */ ! 2065: rs2 = GET_FIELD(insn, 27, 31); ! 2066: #if defined(OPTIM) ! 2067: if (rs2) { ! 2068: #endif ! 2069: gen_movl_reg_T1(rs2); ! 2070: gen_op_add_T1_T0(); ! 2071: #if defined(OPTIM) ! 2072: } ! 2073: #endif ! 2074: } ! 2075: gen_op_restore(); ! 2076: gen_mov_pc_npc(dc); ! 2077: gen_op_movl_npc_T0(); ! 2078: dc->npc = DYNAMIC_PC; ! 2079: goto jmp_insn; ! 2080: #endif ! 2081: } else { ! 2082: rs1 = GET_FIELD(insn, 13, 17); ! 2083: gen_movl_reg_T0(rs1); ! 2084: if (IS_IMM) { /* immediate */ ! 2085: rs2 = GET_FIELDs(insn, 19, 31); ! 2086: #if defined(OPTIM) ! 2087: if (rs2) { ! 2088: #endif ! 2089: gen_movl_simm_T1(rs2); ! 2090: gen_op_add_T1_T0(); ! 2091: #if defined(OPTIM) ! 2092: } ! 2093: #endif ! 2094: } else { /* register */ ! 2095: rs2 = GET_FIELD(insn, 27, 31); ! 2096: #if defined(OPTIM) ! 2097: if (rs2) { ! 2098: #endif ! 2099: gen_movl_reg_T1(rs2); ! 2100: gen_op_add_T1_T0(); ! 2101: #if defined(OPTIM) ! 2102: } ! 2103: #endif ! 2104: } ! 2105: switch (xop) { ! 2106: case 0x38: /* jmpl */ ! 2107: { ! 2108: if (rd != 0) { ! 2109: gen_op_movl_T1_im(dc->pc); ! 2110: gen_movl_T1_reg(rd); ! 2111: } ! 2112: gen_mov_pc_npc(dc); ! 2113: gen_op_movl_npc_T0(); ! 2114: dc->npc = DYNAMIC_PC; ! 2115: } ! 2116: goto jmp_insn; ! 2117: #if !defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64) ! 2118: case 0x39: /* rett, V9 return */ ! 2119: { ! 2120: if (!supervisor(dc)) ! 2121: goto priv_insn; ! 2122: gen_mov_pc_npc(dc); ! 2123: gen_op_movl_npc_T0(); ! 2124: dc->npc = DYNAMIC_PC; ! 2125: gen_op_rett(); ! 2126: } ! 2127: goto jmp_insn; ! 2128: #endif ! 2129: case 0x3b: /* flush */ ! 2130: gen_op_flush_T0(); ! 2131: break; ! 2132: case 0x3c: /* save */ ! 2133: save_state(dc); ! 2134: gen_op_save(); ! 2135: gen_movl_T0_reg(rd); ! 2136: break; ! 2137: case 0x3d: /* restore */ ! 2138: save_state(dc); ! 2139: gen_op_restore(); ! 2140: gen_movl_T0_reg(rd); ! 2141: break; ! 2142: #if !defined(CONFIG_USER_ONLY) && defined(TARGET_SPARC64) ! 2143: case 0x3e: /* V9 done/retry */ ! 2144: { ! 2145: switch (rd) { ! 2146: case 0: ! 2147: if (!supervisor(dc)) ! 2148: goto priv_insn; ! 2149: dc->npc = DYNAMIC_PC; ! 2150: dc->pc = DYNAMIC_PC; ! 2151: gen_op_done(); ! 2152: goto jmp_insn; ! 2153: case 1: ! 2154: if (!supervisor(dc)) ! 2155: goto priv_insn; ! 2156: dc->npc = DYNAMIC_PC; ! 2157: dc->pc = DYNAMIC_PC; ! 2158: gen_op_retry(); ! 2159: goto jmp_insn; ! 2160: default: ! 2161: goto illegal_insn; ! 2162: } ! 2163: } ! 2164: break; ! 2165: #endif ! 2166: default: ! 2167: goto illegal_insn; ! 2168: } ! 2169: } ! 2170: break; ! 2171: } ! 2172: break; ! 2173: case 3: /* load/store instructions */ ! 2174: { ! 2175: unsigned int xop = GET_FIELD(insn, 7, 12); ! 2176: rs1 = GET_FIELD(insn, 13, 17); ! 2177: gen_movl_reg_T0(rs1); ! 2178: if (IS_IMM) { /* immediate */ ! 2179: rs2 = GET_FIELDs(insn, 19, 31); ! 2180: #if defined(OPTIM) ! 2181: if (rs2 != 0) { ! 2182: #endif ! 2183: gen_movl_simm_T1(rs2); ! 2184: gen_op_add_T1_T0(); ! 2185: #if defined(OPTIM) ! 2186: } ! 2187: #endif ! 2188: } else { /* register */ ! 2189: rs2 = GET_FIELD(insn, 27, 31); ! 2190: #if defined(OPTIM) ! 2191: if (rs2 != 0) { ! 2192: #endif ! 2193: gen_movl_reg_T1(rs2); ! 2194: gen_op_add_T1_T0(); ! 2195: #if defined(OPTIM) ! 2196: } ! 2197: #endif ! 2198: } ! 2199: if (xop < 4 || (xop > 7 && xop < 0x14 && xop != 0x0e) || \ ! 2200: (xop > 0x17 && xop < 0x1d ) || \ ! 2201: (xop > 0x2c && xop < 0x33) || xop == 0x1f) { ! 2202: switch (xop) { ! 2203: case 0x0: /* load word */ ! 2204: gen_op_ldst(ld); ! 2205: break; ! 2206: case 0x1: /* load unsigned byte */ ! 2207: gen_op_ldst(ldub); ! 2208: break; ! 2209: case 0x2: /* load unsigned halfword */ ! 2210: gen_op_ldst(lduh); ! 2211: break; ! 2212: case 0x3: /* load double word */ ! 2213: gen_op_ldst(ldd); ! 2214: gen_movl_T0_reg(rd + 1); ! 2215: break; ! 2216: case 0x9: /* load signed byte */ ! 2217: gen_op_ldst(ldsb); ! 2218: break; ! 2219: case 0xa: /* load signed halfword */ ! 2220: gen_op_ldst(ldsh); ! 2221: break; ! 2222: case 0xd: /* ldstub -- XXX: should be atomically */ ! 2223: gen_op_ldst(ldstub); ! 2224: break; ! 2225: case 0x0f: /* swap register with memory. Also atomically */ ! 2226: gen_movl_reg_T1(rd); ! 2227: gen_op_ldst(swap); ! 2228: break; ! 2229: #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) ! 2230: case 0x10: /* load word alternate */ ! 2231: #ifndef TARGET_SPARC64 ! 2232: if (!supervisor(dc)) ! 2233: goto priv_insn; ! 2234: #endif ! 2235: gen_op_lda(insn, 1, 4, 0); ! 2236: break; ! 2237: case 0x11: /* load unsigned byte alternate */ ! 2238: #ifndef TARGET_SPARC64 ! 2239: if (!supervisor(dc)) ! 2240: goto priv_insn; ! 2241: #endif ! 2242: gen_op_lduba(insn, 1, 1, 0); ! 2243: break; ! 2244: case 0x12: /* load unsigned halfword alternate */ ! 2245: #ifndef TARGET_SPARC64 ! 2246: if (!supervisor(dc)) ! 2247: goto priv_insn; ! 2248: #endif ! 2249: gen_op_lduha(insn, 1, 2, 0); ! 2250: break; ! 2251: case 0x13: /* load double word alternate */ ! 2252: #ifndef TARGET_SPARC64 ! 2253: if (!supervisor(dc)) ! 2254: goto priv_insn; ! 2255: #endif ! 2256: gen_op_ldda(insn, 1, 8, 0); ! 2257: gen_movl_T0_reg(rd + 1); ! 2258: break; ! 2259: case 0x19: /* load signed byte alternate */ ! 2260: #ifndef TARGET_SPARC64 ! 2261: if (!supervisor(dc)) ! 2262: goto priv_insn; ! 2263: #endif ! 2264: gen_op_ldsba(insn, 1, 1, 1); ! 2265: break; ! 2266: case 0x1a: /* load signed halfword alternate */ ! 2267: #ifndef TARGET_SPARC64 ! 2268: if (!supervisor(dc)) ! 2269: goto priv_insn; ! 2270: #endif ! 2271: gen_op_ldsha(insn, 1, 2 ,1); ! 2272: break; ! 2273: case 0x1d: /* ldstuba -- XXX: should be atomically */ ! 2274: #ifndef TARGET_SPARC64 ! 2275: if (!supervisor(dc)) ! 2276: goto priv_insn; ! 2277: #endif ! 2278: gen_op_ldstuba(insn, 1, 1, 0); ! 2279: break; ! 2280: case 0x1f: /* swap reg with alt. memory. Also atomically */ ! 2281: #ifndef TARGET_SPARC64 ! 2282: if (!supervisor(dc)) ! 2283: goto priv_insn; ! 2284: #endif ! 2285: gen_movl_reg_T1(rd); ! 2286: gen_op_swapa(insn, 1, 4, 0); ! 2287: break; ! 2288: ! 2289: #ifndef TARGET_SPARC64 ! 2290: /* avoid warnings */ ! 2291: (void) &gen_op_stfa; ! 2292: (void) &gen_op_stdfa; ! 2293: (void) &gen_op_ldfa; ! 2294: (void) &gen_op_lddfa; ! 2295: #else ! 2296: #if !defined(CONFIG_USER_ONLY) ! 2297: (void) &gen_op_cas; ! 2298: (void) &gen_op_casx; ! 2299: #endif ! 2300: #endif ! 2301: #endif ! 2302: #ifdef TARGET_SPARC64 ! 2303: case 0x08: /* V9 ldsw */ ! 2304: gen_op_ldst(ldsw); ! 2305: break; ! 2306: case 0x0b: /* V9 ldx */ ! 2307: gen_op_ldst(ldx); ! 2308: break; ! 2309: case 0x18: /* V9 ldswa */ ! 2310: gen_op_ldswa(insn, 1, 4, 1); ! 2311: break; ! 2312: case 0x1b: /* V9 ldxa */ ! 2313: gen_op_ldxa(insn, 1, 8, 0); ! 2314: break; ! 2315: case 0x2d: /* V9 prefetch, no effect */ ! 2316: goto skip_move; ! 2317: case 0x30: /* V9 ldfa */ ! 2318: gen_op_ldfa(insn, 1, 8, 0); // XXX ! 2319: break; ! 2320: case 0x33: /* V9 lddfa */ ! 2321: gen_op_lddfa(insn, 1, 8, 0); // XXX ! 2322: ! 2323: break; ! 2324: case 0x3d: /* V9 prefetcha, no effect */ ! 2325: goto skip_move; ! 2326: case 0x32: /* V9 ldqfa */ ! 2327: goto nfpu_insn; ! 2328: #endif ! 2329: default: ! 2330: goto illegal_insn; ! 2331: } ! 2332: gen_movl_T1_reg(rd); ! 2333: #ifdef TARGET_SPARC64 ! 2334: skip_move: ; ! 2335: #endif ! 2336: } else if (xop >= 0x20 && xop < 0x24) { ! 2337: #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) ! 2338: gen_op_trap_ifnofpu(); ! 2339: #endif ! 2340: switch (xop) { ! 2341: case 0x20: /* load fpreg */ ! 2342: gen_op_ldst(ldf); ! 2343: gen_op_store_FT0_fpr(rd); ! 2344: break; ! 2345: case 0x21: /* load fsr */ ! 2346: gen_op_ldfsr(); ! 2347: gen_op_store_FT0_fpr(rd); ! 2348: break; ! 2349: case 0x22: /* load quad fpreg */ ! 2350: goto nfpu_insn; ! 2351: case 0x23: /* load double fpreg */ ! 2352: gen_op_ldst(lddf); ! 2353: gen_op_store_DT0_fpr(DFPREG(rd)); ! 2354: break; ! 2355: default: ! 2356: goto illegal_insn; ! 2357: } ! 2358: } else if (xop < 8 || (xop >= 0x14 && xop < 0x18) || \ ! 2359: xop == 0xe || xop == 0x1e) { ! 2360: gen_movl_reg_T1(rd); ! 2361: switch (xop) { ! 2362: case 0x4: ! 2363: gen_op_ldst(st); ! 2364: break; ! 2365: case 0x5: ! 2366: gen_op_ldst(stb); ! 2367: break; ! 2368: case 0x6: ! 2369: gen_op_ldst(sth); ! 2370: break; ! 2371: case 0x7: ! 2372: flush_T2(dc); ! 2373: gen_movl_reg_T2(rd + 1); ! 2374: gen_op_ldst(std); ! 2375: break; ! 2376: #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) ! 2377: case 0x14: ! 2378: #ifndef TARGET_SPARC64 ! 2379: if (!supervisor(dc)) ! 2380: goto priv_insn; ! 2381: #endif ! 2382: gen_op_sta(insn, 0, 4, 0); ! 2383: break; ! 2384: case 0x15: ! 2385: #ifndef TARGET_SPARC64 ! 2386: if (!supervisor(dc)) ! 2387: goto priv_insn; ! 2388: #endif ! 2389: gen_op_stba(insn, 0, 1, 0); ! 2390: break; ! 2391: case 0x16: ! 2392: #ifndef TARGET_SPARC64 ! 2393: if (!supervisor(dc)) ! 2394: goto priv_insn; ! 2395: #endif ! 2396: gen_op_stha(insn, 0, 2, 0); ! 2397: break; ! 2398: case 0x17: ! 2399: #ifndef TARGET_SPARC64 ! 2400: if (!supervisor(dc)) ! 2401: goto priv_insn; ! 2402: #endif ! 2403: flush_T2(dc); ! 2404: gen_movl_reg_T2(rd + 1); ! 2405: gen_op_stda(insn, 0, 8, 0); ! 2406: break; ! 2407: #endif ! 2408: #ifdef TARGET_SPARC64 ! 2409: case 0x0e: /* V9 stx */ ! 2410: gen_op_ldst(stx); ! 2411: break; ! 2412: case 0x1e: /* V9 stxa */ ! 2413: gen_op_stxa(insn, 0, 8, 0); // XXX ! 2414: break; ! 2415: #endif ! 2416: default: ! 2417: goto illegal_insn; ! 2418: } ! 2419: } else if (xop > 0x23 && xop < 0x28) { ! 2420: #if !defined(CONFIG_USER_ONLY) ! 2421: gen_op_trap_ifnofpu(); ! 2422: #endif ! 2423: switch (xop) { ! 2424: case 0x24: ! 2425: gen_op_load_fpr_FT0(rd); ! 2426: gen_op_ldst(stf); ! 2427: break; ! 2428: case 0x25: /* stfsr, V9 stxfsr */ ! 2429: gen_op_load_fpr_FT0(rd); ! 2430: // XXX ! 2431: gen_op_stfsr(); ! 2432: break; ! 2433: case 0x26: /* stdfq */ ! 2434: goto nfpu_insn; ! 2435: case 0x27: ! 2436: gen_op_load_fpr_DT0(DFPREG(rd)); ! 2437: gen_op_ldst(stdf); ! 2438: break; ! 2439: default: ! 2440: goto illegal_insn; ! 2441: } ! 2442: } else if (xop > 0x33 && xop < 0x3f) { ! 2443: #ifdef TARGET_SPARC64 ! 2444: switch (xop) { ! 2445: case 0x34: /* V9 stfa */ ! 2446: gen_op_stfa(insn, 0, 0, 0); // XXX ! 2447: break; ! 2448: case 0x37: /* V9 stdfa */ ! 2449: gen_op_stdfa(insn, 0, 0, 0); // XXX ! 2450: break; ! 2451: case 0x3c: /* V9 casa */ ! 2452: gen_op_casa(insn, 0, 4, 0); // XXX ! 2453: break; ! 2454: case 0x3e: /* V9 casxa */ ! 2455: gen_op_casxa(insn, 0, 8, 0); // XXX ! 2456: break; ! 2457: case 0x36: /* V9 stqfa */ ! 2458: goto nfpu_insn; ! 2459: default: ! 2460: goto illegal_insn; ! 2461: } ! 2462: #else ! 2463: goto illegal_insn; ! 2464: #endif ! 2465: } ! 2466: else ! 2467: goto illegal_insn; ! 2468: } ! 2469: break; ! 2470: } ! 2471: /* default case for non jump instructions */ ! 2472: if (dc->npc == DYNAMIC_PC) { ! 2473: dc->pc = DYNAMIC_PC; ! 2474: gen_op_next_insn(); ! 2475: } else if (dc->npc == JUMP_PC) { ! 2476: /* we can do a static jump */ ! 2477: gen_branch2(dc, (long)dc->tb, dc->jump_pc[0], dc->jump_pc[1]); ! 2478: dc->is_br = 1; ! 2479: } else { ! 2480: dc->pc = dc->npc; ! 2481: dc->npc = dc->npc + 4; ! 2482: } ! 2483: jmp_insn: ! 2484: return; ! 2485: illegal_insn: ! 2486: save_state(dc); ! 2487: gen_op_exception(TT_ILL_INSN); ! 2488: dc->is_br = 1; ! 2489: return; ! 2490: #if !defined(CONFIG_USER_ONLY) ! 2491: priv_insn: ! 2492: save_state(dc); ! 2493: gen_op_exception(TT_PRIV_INSN); ! 2494: dc->is_br = 1; ! 2495: return; ! 2496: #endif ! 2497: nfpu_insn: ! 2498: save_state(dc); ! 2499: gen_op_fpexception_im(FSR_FTT_UNIMPFPOP); ! 2500: dc->is_br = 1; ! 2501: } ! 2502: ! 2503: static inline int gen_intermediate_code_internal(TranslationBlock * tb, ! 2504: int spc, CPUSPARCState *env) ! 2505: { ! 2506: target_ulong pc_start, last_pc; ! 2507: uint16_t *gen_opc_end; ! 2508: DisasContext dc1, *dc = &dc1; ! 2509: int j, lj = -1; ! 2510: ! 2511: memset(dc, 0, sizeof(DisasContext)); ! 2512: dc->tb = tb; ! 2513: pc_start = tb->pc; ! 2514: dc->pc = pc_start; ! 2515: last_pc = dc->pc; ! 2516: dc->npc = (target_ulong) tb->cs_base; ! 2517: #if defined(CONFIG_USER_ONLY) ! 2518: dc->mem_idx = 0; ! 2519: #else ! 2520: dc->mem_idx = ((env->psrs) != 0); ! 2521: #endif ! 2522: gen_opc_ptr = gen_opc_buf; ! 2523: gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; ! 2524: gen_opparam_ptr = gen_opparam_buf; ! 2525: nb_gen_labels = 0; ! 2526: ! 2527: do { ! 2528: if (env->nb_breakpoints > 0) { ! 2529: for(j = 0; j < env->nb_breakpoints; j++) { ! 2530: if (env->breakpoints[j] == dc->pc) { ! 2531: if (dc->pc != pc_start) ! 2532: save_state(dc); ! 2533: gen_op_debug(); ! 2534: gen_op_movl_T0_0(); ! 2535: gen_op_exit_tb(); ! 2536: dc->is_br = 1; ! 2537: goto exit_gen_loop; ! 2538: } ! 2539: } ! 2540: } ! 2541: if (spc) { ! 2542: if (loglevel > 0) ! 2543: fprintf(logfile, "Search PC...\n"); ! 2544: j = gen_opc_ptr - gen_opc_buf; ! 2545: if (lj < j) { ! 2546: lj++; ! 2547: while (lj < j) ! 2548: gen_opc_instr_start[lj++] = 0; ! 2549: gen_opc_pc[lj] = dc->pc; ! 2550: gen_opc_npc[lj] = dc->npc; ! 2551: gen_opc_instr_start[lj] = 1; ! 2552: } ! 2553: } ! 2554: last_pc = dc->pc; ! 2555: disas_sparc_insn(dc); ! 2556: ! 2557: if (dc->is_br) ! 2558: break; ! 2559: /* if the next PC is different, we abort now */ ! 2560: if (dc->pc != (last_pc + 4)) ! 2561: break; ! 2562: /* if we reach a page boundary, we stop generation so that the ! 2563: PC of a TT_TFAULT exception is always in the right page */ ! 2564: if ((dc->pc & (TARGET_PAGE_SIZE - 1)) == 0) ! 2565: break; ! 2566: /* if single step mode, we generate only one instruction and ! 2567: generate an exception */ ! 2568: if (env->singlestep_enabled) { ! 2569: gen_jmp_im(dc->pc); ! 2570: gen_op_movl_T0_0(); ! 2571: gen_op_exit_tb(); ! 2572: break; ! 2573: } ! 2574: } while ((gen_opc_ptr < gen_opc_end) && ! 2575: (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32)); ! 2576: ! 2577: exit_gen_loop: ! 2578: if (!dc->is_br) { ! 2579: if (dc->pc != DYNAMIC_PC && ! 2580: (dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) { ! 2581: /* static PC and NPC: we can use direct chaining */ ! 2582: gen_branch(dc, (long)tb, dc->pc, dc->npc); ! 2583: } else { ! 2584: if (dc->pc != DYNAMIC_PC) ! 2585: gen_jmp_im(dc->pc); ! 2586: save_npc(dc); ! 2587: gen_op_movl_T0_0(); ! 2588: gen_op_exit_tb(); ! 2589: } ! 2590: } ! 2591: *gen_opc_ptr = INDEX_op_end; ! 2592: if (spc) { ! 2593: j = gen_opc_ptr - gen_opc_buf; ! 2594: lj++; ! 2595: while (lj <= j) ! 2596: gen_opc_instr_start[lj++] = 0; ! 2597: tb->size = 0; ! 2598: #if 0 ! 2599: if (loglevel > 0) { ! 2600: page_dump(logfile); ! 2601: } ! 2602: #endif ! 2603: gen_opc_jump_pc[0] = dc->jump_pc[0]; ! 2604: gen_opc_jump_pc[1] = dc->jump_pc[1]; ! 2605: } else { ! 2606: tb->size = last_pc + 4 - pc_start; ! 2607: } ! 2608: #ifdef DEBUG_DISAS ! 2609: if (loglevel & CPU_LOG_TB_IN_ASM) { ! 2610: fprintf(logfile, "--------------\n"); ! 2611: fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); ! 2612: target_disas(logfile, pc_start, last_pc + 4 - pc_start, 0); ! 2613: fprintf(logfile, "\n"); ! 2614: if (loglevel & CPU_LOG_TB_OP) { ! 2615: fprintf(logfile, "OP:\n"); ! 2616: dump_ops(gen_opc_buf, gen_opparam_buf); ! 2617: fprintf(logfile, "\n"); ! 2618: } ! 2619: } ! 2620: #endif ! 2621: return 0; ! 2622: } ! 2623: ! 2624: int gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb) ! 2625: { ! 2626: return gen_intermediate_code_internal(tb, 0, env); ! 2627: } ! 2628: ! 2629: int gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb) ! 2630: { ! 2631: return gen_intermediate_code_internal(tb, 1, env); ! 2632: } ! 2633: ! 2634: extern int ram_size; ! 2635: ! 2636: void cpu_reset(CPUSPARCState *env) ! 2637: { ! 2638: memset(env, 0, sizeof(*env)); ! 2639: tlb_flush(env, 1); ! 2640: env->cwp = 0; ! 2641: env->wim = 1; ! 2642: env->regwptr = env->regbase + (env->cwp * 16); ! 2643: #if defined(CONFIG_USER_ONLY) ! 2644: env->user_mode_only = 1; ! 2645: #else ! 2646: env->psrs = 1; ! 2647: env->psrps = 1; ! 2648: env->gregs[1] = ram_size; ! 2649: #ifdef TARGET_SPARC64 ! 2650: env->pstate = PS_PRIV; ! 2651: env->version = GET_VER(env); ! 2652: env->pc = 0x1fff0000000ULL; ! 2653: #else ! 2654: env->mmuregs[0] = (0x04 << 24); /* Impl 0, ver 4, MMU disabled */ ! 2655: env->pc = 0xffd00000; ! 2656: #endif ! 2657: env->npc = env->pc + 4; ! 2658: #endif ! 2659: } ! 2660: ! 2661: CPUSPARCState *cpu_sparc_init(void) ! 2662: { ! 2663: CPUSPARCState *env; ! 2664: ! 2665: cpu_exec_init(); ! 2666: ! 2667: if (!(env = malloc(sizeof(CPUSPARCState)))) ! 2668: return (NULL); ! 2669: cpu_single_env = env; ! 2670: cpu_reset(env); ! 2671: return (env); ! 2672: } ! 2673: ! 2674: #define GET_FLAG(a,b) ((env->psr & a)?b:'-') ! 2675: ! 2676: void cpu_dump_state(CPUState *env, FILE *f, ! 2677: int (*cpu_fprintf)(FILE *f, const char *fmt, ...), ! 2678: int flags) ! 2679: { ! 2680: int i, x; ! 2681: ! 2682: cpu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc, env->npc); ! 2683: cpu_fprintf(f, "General Registers:\n"); ! 2684: for (i = 0; i < 4; i++) ! 2685: cpu_fprintf(f, "%%g%c: " TARGET_FMT_lx "\t", i + '0', env->gregs[i]); ! 2686: cpu_fprintf(f, "\n"); ! 2687: for (; i < 8; i++) ! 2688: cpu_fprintf(f, "%%g%c: " TARGET_FMT_lx "\t", i + '0', env->gregs[i]); ! 2689: cpu_fprintf(f, "\nCurrent Register Window:\n"); ! 2690: for (x = 0; x < 3; x++) { ! 2691: for (i = 0; i < 4; i++) ! 2692: cpu_fprintf(f, "%%%c%d: " TARGET_FMT_lx "\t", ! 2693: (x == 0 ? 'o' : (x == 1 ? 'l' : 'i')), i, ! 2694: env->regwptr[i + x * 8]); ! 2695: cpu_fprintf(f, "\n"); ! 2696: for (; i < 8; i++) ! 2697: cpu_fprintf(f, "%%%c%d: " TARGET_FMT_lx "\t", ! 2698: (x == 0 ? 'o' : x == 1 ? 'l' : 'i'), i, ! 2699: env->regwptr[i + x * 8]); ! 2700: cpu_fprintf(f, "\n"); ! 2701: } ! 2702: cpu_fprintf(f, "\nFloating Point Registers:\n"); ! 2703: for (i = 0; i < 32; i++) { ! 2704: if ((i & 3) == 0) ! 2705: cpu_fprintf(f, "%%f%02d:", i); ! 2706: cpu_fprintf(f, " %016lf", env->fpr[i]); ! 2707: if ((i & 3) == 3) ! 2708: cpu_fprintf(f, "\n"); ! 2709: } ! 2710: cpu_fprintf(f, "psr: 0x%08x -> %c%c%c%c %c%c%c wim: 0x%08x\n", GET_PSR(env), ! 2711: GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'), ! 2712: GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'), ! 2713: env->psrs?'S':'-', env->psrps?'P':'-', ! 2714: env->psret?'E':'-', env->wim); ! 2715: cpu_fprintf(f, "fsr: 0x%08x\n", GET_FSR32(env)); ! 2716: } ! 2717: ! 2718: #if defined(CONFIG_USER_ONLY) ! 2719: target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) ! 2720: { ! 2721: return addr; ! 2722: } ! 2723: ! 2724: #else ! 2725: extern int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot, ! 2726: int *access_index, target_ulong address, int rw, ! 2727: int is_user); ! 2728: ! 2729: target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr) ! 2730: { ! 2731: target_phys_addr_t phys_addr; ! 2732: int prot, access_index; ! 2733: ! 2734: if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2, 0) != 0) ! 2735: return -1; ! 2736: return phys_addr; ! 2737: } ! 2738: #endif ! 2739: ! 2740: void helper_flush(target_ulong addr) ! 2741: { ! 2742: addr &= ~7; ! 2743: tb_invalidate_page_range(addr, addr + 8); ! 2744: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.