|
|
1.1 ! root 1: /* ! 2: * Tiny Code Generator for QEMU ! 3: * ! 4: * Copyright (c) 2008 Andrzej Zaborowski ! 5: * ! 6: * Permission is hereby granted, free of charge, to any person obtaining a copy ! 7: * of this software and associated documentation files (the "Software"), to deal ! 8: * in the Software without restriction, including without limitation the rights ! 9: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ! 10: * copies of the Software, and to permit persons to whom the Software is ! 11: * furnished to do so, subject to the following conditions: ! 12: * ! 13: * The above copyright notice and this permission notice shall be included in ! 14: * all copies or substantial portions of the Software. ! 15: * ! 16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ! 17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ! 19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ! 20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ! 21: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ! 22: * THE SOFTWARE. ! 23: */ ! 24: ! 25: #ifndef NDEBUG ! 26: static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { ! 27: "%r0", ! 28: "%r1", ! 29: "%r2", ! 30: "%r3", ! 31: "%r4", ! 32: "%r5", ! 33: "%r6", ! 34: "%r7", ! 35: "%r8", ! 36: "%r9", ! 37: "%r10", ! 38: "%r11", ! 39: "%r12", ! 40: "%r13", ! 41: "%r14", ! 42: }; ! 43: #endif ! 44: ! 45: static const int tcg_target_reg_alloc_order[] = { ! 46: TCG_REG_R0, ! 47: TCG_REG_R1, ! 48: TCG_REG_R2, ! 49: TCG_REG_R3, ! 50: TCG_REG_R4, ! 51: TCG_REG_R5, ! 52: TCG_REG_R6, ! 53: TCG_REG_R7, ! 54: TCG_REG_R8, ! 55: TCG_REG_R9, ! 56: TCG_REG_R10, ! 57: TCG_REG_R11, ! 58: TCG_REG_R12, ! 59: TCG_REG_R13, ! 60: TCG_REG_R14, ! 61: }; ! 62: ! 63: static const int tcg_target_call_iarg_regs[4] = { ! 64: TCG_REG_R0, TCG_REG_R1, TCG_REG_R2, TCG_REG_R3 ! 65: }; ! 66: static const int tcg_target_call_oarg_regs[2] = { ! 67: TCG_REG_R0, TCG_REG_R1 ! 68: }; ! 69: ! 70: static void patch_reloc(uint8_t *code_ptr, int type, ! 71: tcg_target_long value, tcg_target_long addend) ! 72: { ! 73: switch (type) { ! 74: case R_ARM_ABS32: ! 75: *(uint32_t *) code_ptr = value; ! 76: break; ! 77: ! 78: case R_ARM_CALL: ! 79: case R_ARM_JUMP24: ! 80: default: ! 81: tcg_abort(); ! 82: ! 83: case R_ARM_PC24: ! 84: *(uint32_t *) code_ptr = ((*(uint32_t *) code_ptr) & 0xff000000) | ! 85: (((value - ((tcg_target_long) code_ptr + 8)) >> 2) & 0xffffff); ! 86: break; ! 87: } ! 88: } ! 89: ! 90: /* maximum number of register used for input function arguments */ ! 91: static inline int tcg_target_get_call_iarg_regs_count(int flags) ! 92: { ! 93: return 4; ! 94: } ! 95: ! 96: /* parse target specific constraints */ ! 97: static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) ! 98: { ! 99: const char *ct_str; ! 100: ! 101: ct_str = *pct_str; ! 102: switch (ct_str[0]) { ! 103: case 'r': ! 104: #ifndef CONFIG_SOFTMMU ! 105: case 'd': ! 106: case 'D': ! 107: case 'x': ! 108: case 'X': ! 109: #endif ! 110: ct->ct |= TCG_CT_REG; ! 111: tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); ! 112: break; ! 113: ! 114: #ifdef CONFIG_SOFTMMU ! 115: /* qemu_ld/st inputs (unless 'X', 'd' or 'D') */ ! 116: case 'x': ! 117: ct->ct |= TCG_CT_REG; ! 118: tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); ! 119: tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0); ! 120: tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1); ! 121: break; ! 122: ! 123: /* qemu_ld64 data_reg */ ! 124: case 'd': ! 125: ct->ct |= TCG_CT_REG; ! 126: tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); ! 127: /* r1 is still needed to load data_reg2, so don't use it. */ ! 128: tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1); ! 129: break; ! 130: ! 131: /* qemu_ld/st64 data_reg2 */ ! 132: case 'D': ! 133: ct->ct |= TCG_CT_REG; ! 134: tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); ! 135: /* r0, r1 and optionally r2 will be overwritten by the address ! 136: * and the low word of data, so don't use these. */ ! 137: tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0); ! 138: tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1); ! 139: # if TARGET_LONG_BITS == 64 ! 140: tcg_regset_reset_reg(ct->u.regs, TCG_REG_R2); ! 141: # endif ! 142: break; ! 143: ! 144: # if TARGET_LONG_BITS == 64 ! 145: /* qemu_ld/st addr_reg2 */ ! 146: case 'X': ! 147: ct->ct |= TCG_CT_REG; ! 148: tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); ! 149: /* r0 will be overwritten by the low word of base, so don't use it. */ ! 150: tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0); ! 151: tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1); ! 152: break; ! 153: # endif ! 154: #endif ! 155: ! 156: case '1': ! 157: ct->ct |= TCG_CT_REG; ! 158: tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); ! 159: tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0); ! 160: break; ! 161: ! 162: case '2': ! 163: ct->ct |= TCG_CT_REG; ! 164: tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1); ! 165: tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0); ! 166: tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1); ! 167: break; ! 168: ! 169: default: ! 170: return -1; ! 171: } ! 172: ct_str++; ! 173: *pct_str = ct_str; ! 174: ! 175: return 0; ! 176: } ! 177: ! 178: /* Test if a constant matches the constraint. ! 179: * TODO: define constraints for: ! 180: * ! 181: * ldr/str offset: between -0xfff and 0xfff ! 182: * ldrh/strh offset: between -0xff and 0xff ! 183: * mov operand2: values represented with x << (2 * y), x < 0x100 ! 184: * add, sub, eor...: ditto ! 185: */ ! 186: static inline int tcg_target_const_match(tcg_target_long val, ! 187: const TCGArgConstraint *arg_ct) ! 188: { ! 189: int ct; ! 190: ct = arg_ct->ct; ! 191: if (ct & TCG_CT_CONST) ! 192: return 1; ! 193: else ! 194: return 0; ! 195: } ! 196: ! 197: enum arm_data_opc_e { ! 198: ARITH_AND = 0x0, ! 199: ARITH_EOR = 0x1, ! 200: ARITH_SUB = 0x2, ! 201: ARITH_RSB = 0x3, ! 202: ARITH_ADD = 0x4, ! 203: ARITH_ADC = 0x5, ! 204: ARITH_SBC = 0x6, ! 205: ARITH_RSC = 0x7, ! 206: ARITH_TST = 0x8, ! 207: ARITH_CMP = 0xa, ! 208: ARITH_CMN = 0xb, ! 209: ARITH_ORR = 0xc, ! 210: ARITH_MOV = 0xd, ! 211: ARITH_BIC = 0xe, ! 212: ARITH_MVN = 0xf, ! 213: }; ! 214: ! 215: #define TO_CPSR(opc) \ ! 216: ((opc == ARITH_CMP || opc == ARITH_CMN || opc == ARITH_TST) << 20) ! 217: ! 218: #define SHIFT_IMM_LSL(im) (((im) << 7) | 0x00) ! 219: #define SHIFT_IMM_LSR(im) (((im) << 7) | 0x20) ! 220: #define SHIFT_IMM_ASR(im) (((im) << 7) | 0x40) ! 221: #define SHIFT_IMM_ROR(im) (((im) << 7) | 0x60) ! 222: #define SHIFT_REG_LSL(rs) (((rs) << 8) | 0x10) ! 223: #define SHIFT_REG_LSR(rs) (((rs) << 8) | 0x30) ! 224: #define SHIFT_REG_ASR(rs) (((rs) << 8) | 0x50) ! 225: #define SHIFT_REG_ROR(rs) (((rs) << 8) | 0x70) ! 226: ! 227: enum arm_cond_code_e { ! 228: COND_EQ = 0x0, ! 229: COND_NE = 0x1, ! 230: COND_CS = 0x2, /* Unsigned greater or equal */ ! 231: COND_CC = 0x3, /* Unsigned less than */ ! 232: COND_MI = 0x4, /* Negative */ ! 233: COND_PL = 0x5, /* Zero or greater */ ! 234: COND_VS = 0x6, /* Overflow */ ! 235: COND_VC = 0x7, /* No overflow */ ! 236: COND_HI = 0x8, /* Unsigned greater than */ ! 237: COND_LS = 0x9, /* Unsigned less or equal */ ! 238: COND_GE = 0xa, ! 239: COND_LT = 0xb, ! 240: COND_GT = 0xc, ! 241: COND_LE = 0xd, ! 242: COND_AL = 0xe, ! 243: }; ! 244: ! 245: static const uint8_t tcg_cond_to_arm_cond[10] = { ! 246: [TCG_COND_EQ] = COND_EQ, ! 247: [TCG_COND_NE] = COND_NE, ! 248: [TCG_COND_LT] = COND_LT, ! 249: [TCG_COND_GE] = COND_GE, ! 250: [TCG_COND_LE] = COND_LE, ! 251: [TCG_COND_GT] = COND_GT, ! 252: /* unsigned */ ! 253: [TCG_COND_LTU] = COND_CC, ! 254: [TCG_COND_GEU] = COND_CS, ! 255: [TCG_COND_LEU] = COND_LS, ! 256: [TCG_COND_GTU] = COND_HI, ! 257: }; ! 258: ! 259: static inline void tcg_out_bx(TCGContext *s, int cond, int rn) ! 260: { ! 261: tcg_out32(s, (cond << 28) | 0x012fff10 | rn); ! 262: } ! 263: ! 264: static inline void tcg_out_b(TCGContext *s, int cond, int32_t offset) ! 265: { ! 266: tcg_out32(s, (cond << 28) | 0x0a000000 | ! 267: (((offset - 8) >> 2) & 0x00ffffff)); ! 268: } ! 269: ! 270: static inline void tcg_out_b_noaddr(TCGContext *s, int cond) ! 271: { ! 272: #ifdef WORDS_BIGENDIAN ! 273: tcg_out8(s, (cond << 4) | 0x0a); ! 274: s->code_ptr += 3; ! 275: #else ! 276: s->code_ptr += 3; ! 277: tcg_out8(s, (cond << 4) | 0x0a); ! 278: #endif ! 279: } ! 280: ! 281: static inline void tcg_out_bl(TCGContext *s, int cond, int32_t offset) ! 282: { ! 283: tcg_out32(s, (cond << 28) | 0x0b000000 | ! 284: (((offset - 8) >> 2) & 0x00ffffff)); ! 285: } ! 286: ! 287: static inline void tcg_out_dat_reg(TCGContext *s, ! 288: int cond, int opc, int rd, int rn, int rm, int shift) ! 289: { ! 290: tcg_out32(s, (cond << 28) | (0 << 25) | (opc << 21) | TO_CPSR(opc) | ! 291: (rn << 16) | (rd << 12) | shift | rm); ! 292: } ! 293: ! 294: static inline void tcg_out_dat_reg2(TCGContext *s, ! 295: int cond, int opc0, int opc1, int rd0, int rd1, ! 296: int rn0, int rn1, int rm0, int rm1, int shift) ! 297: { ! 298: if (rd0 == rn1 || rd0 == rm1) { ! 299: tcg_out32(s, (cond << 28) | (0 << 25) | (opc0 << 21) | (1 << 20) | ! 300: (rn0 << 16) | (8 << 12) | shift | rm0); ! 301: tcg_out32(s, (cond << 28) | (0 << 25) | (opc1 << 21) | ! 302: (rn1 << 16) | (rd1 << 12) | shift | rm1); ! 303: tcg_out_dat_reg(s, cond, ARITH_MOV, ! 304: rd0, 0, TCG_REG_R8, SHIFT_IMM_LSL(0)); ! 305: } else { ! 306: tcg_out32(s, (cond << 28) | (0 << 25) | (opc0 << 21) | (1 << 20) | ! 307: (rn0 << 16) | (rd0 << 12) | shift | rm0); ! 308: tcg_out32(s, (cond << 28) | (0 << 25) | (opc1 << 21) | ! 309: (rn1 << 16) | (rd1 << 12) | shift | rm1); ! 310: } ! 311: } ! 312: ! 313: static inline void tcg_out_dat_imm(TCGContext *s, ! 314: int cond, int opc, int rd, int rn, int im) ! 315: { ! 316: tcg_out32(s, (cond << 28) | (1 << 25) | (opc << 21) | TO_CPSR(opc) | ! 317: (rn << 16) | (rd << 12) | im); ! 318: } ! 319: ! 320: static inline void tcg_out_movi32(TCGContext *s, ! 321: int cond, int rd, int32_t arg) ! 322: { ! 323: int offset = (uint32_t) arg - ((uint32_t) s->code_ptr + 8); ! 324: ! 325: /* TODO: This is very suboptimal, we can easily have a constant ! 326: * pool somewhere after all the instructions. */ ! 327: ! 328: if (arg < 0 && arg > -0x100) ! 329: return tcg_out_dat_imm(s, cond, ARITH_MVN, rd, 0, (~arg) & 0xff); ! 330: ! 331: if (offset < 0x100 && offset > -0x100) ! 332: return offset >= 0 ? ! 333: tcg_out_dat_imm(s, cond, ARITH_ADD, rd, 15, offset) : ! 334: tcg_out_dat_imm(s, cond, ARITH_SUB, rd, 15, -offset); ! 335: ! 336: tcg_out_dat_imm(s, cond, ARITH_MOV, rd, 0, arg & 0xff); ! 337: if (arg & 0x0000ff00) ! 338: tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd, ! 339: ((arg >> 8) & 0xff) | 0xc00); ! 340: if (arg & 0x00ff0000) ! 341: tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd, ! 342: ((arg >> 16) & 0xff) | 0x800); ! 343: if (arg & 0xff000000) ! 344: tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd, ! 345: ((arg >> 24) & 0xff) | 0x400); ! 346: } ! 347: ! 348: static inline void tcg_out_mul32(TCGContext *s, ! 349: int cond, int rd, int rs, int rm) ! 350: { ! 351: if (rd != rm) ! 352: tcg_out32(s, (cond << 28) | (rd << 16) | (0 << 12) | ! 353: (rs << 8) | 0x90 | rm); ! 354: else if (rd != rs) ! 355: tcg_out32(s, (cond << 28) | (rd << 16) | (0 << 12) | ! 356: (rm << 8) | 0x90 | rs); ! 357: else { ! 358: tcg_out32(s, (cond << 28) | ( 8 << 16) | (0 << 12) | ! 359: (rs << 8) | 0x90 | rm); ! 360: tcg_out_dat_reg(s, cond, ARITH_MOV, ! 361: rd, 0, 8, SHIFT_IMM_LSL(0)); ! 362: } ! 363: } ! 364: ! 365: static inline void tcg_out_umull32(TCGContext *s, ! 366: int cond, int rd0, int rd1, int rs, int rm) ! 367: { ! 368: if (rd0 != rm && rd1 != rm) ! 369: tcg_out32(s, (cond << 28) | 0x800090 | ! 370: (rd1 << 16) | (rd0 << 12) | (rs << 8) | rm); ! 371: else if (rd0 != rs && rd1 != rs) ! 372: tcg_out32(s, (cond << 28) | 0x800090 | ! 373: (rd1 << 16) | (rd0 << 12) | (rm << 8) | rs); ! 374: else { ! 375: tcg_out_dat_reg(s, cond, ARITH_MOV, ! 376: TCG_REG_R8, 0, rm, SHIFT_IMM_LSL(0)); ! 377: tcg_out32(s, (cond << 28) | 0x800098 | ! 378: (rd1 << 16) | (rd0 << 12) | (rs << 8)); ! 379: } ! 380: } ! 381: ! 382: static inline void tcg_out_smull32(TCGContext *s, ! 383: int cond, int rd0, int rd1, int rs, int rm) ! 384: { ! 385: if (rd0 != rm && rd1 != rm) ! 386: tcg_out32(s, (cond << 28) | 0xc00090 | ! 387: (rd1 << 16) | (rd0 << 12) | (rs << 8) | rm); ! 388: else if (rd0 != rs && rd1 != rs) ! 389: tcg_out32(s, (cond << 28) | 0xc00090 | ! 390: (rd1 << 16) | (rd0 << 12) | (rm << 8) | rs); ! 391: else { ! 392: tcg_out_dat_reg(s, cond, ARITH_MOV, ! 393: TCG_REG_R8, 0, rm, SHIFT_IMM_LSL(0)); ! 394: tcg_out32(s, (cond << 28) | 0xc00098 | ! 395: (rd1 << 16) | (rd0 << 12) | (rs << 8)); ! 396: } ! 397: } ! 398: ! 399: static inline void tcg_out_ld32_12(TCGContext *s, int cond, ! 400: int rd, int rn, tcg_target_long im) ! 401: { ! 402: if (im >= 0) ! 403: tcg_out32(s, (cond << 28) | 0x05900000 | ! 404: (rn << 16) | (rd << 12) | (im & 0xfff)); ! 405: else ! 406: tcg_out32(s, (cond << 28) | 0x05100000 | ! 407: (rn << 16) | (rd << 12) | ((-im) & 0xfff)); ! 408: } ! 409: ! 410: static inline void tcg_out_st32_12(TCGContext *s, int cond, ! 411: int rd, int rn, tcg_target_long im) ! 412: { ! 413: if (im >= 0) ! 414: tcg_out32(s, (cond << 28) | 0x05800000 | ! 415: (rn << 16) | (rd << 12) | (im & 0xfff)); ! 416: else ! 417: tcg_out32(s, (cond << 28) | 0x05000000 | ! 418: (rn << 16) | (rd << 12) | ((-im) & 0xfff)); ! 419: } ! 420: ! 421: static inline void tcg_out_ld32_r(TCGContext *s, int cond, ! 422: int rd, int rn, int rm) ! 423: { ! 424: tcg_out32(s, (cond << 28) | 0x07900000 | ! 425: (rn << 16) | (rd << 12) | rm); ! 426: } ! 427: ! 428: static inline void tcg_out_st32_r(TCGContext *s, int cond, ! 429: int rd, int rn, int rm) ! 430: { ! 431: tcg_out32(s, (cond << 28) | 0x07800000 | ! 432: (rn << 16) | (rd << 12) | rm); ! 433: } ! 434: ! 435: /* Register pre-increment with base writeback. */ ! 436: static inline void tcg_out_ld32_rwb(TCGContext *s, int cond, ! 437: int rd, int rn, int rm) ! 438: { ! 439: tcg_out32(s, (cond << 28) | 0x07b00000 | ! 440: (rn << 16) | (rd << 12) | rm); ! 441: } ! 442: ! 443: static inline void tcg_out_st32_rwb(TCGContext *s, int cond, ! 444: int rd, int rn, int rm) ! 445: { ! 446: tcg_out32(s, (cond << 28) | 0x07a00000 | ! 447: (rn << 16) | (rd << 12) | rm); ! 448: } ! 449: ! 450: static inline void tcg_out_ld16u_8(TCGContext *s, int cond, ! 451: int rd, int rn, tcg_target_long im) ! 452: { ! 453: if (im >= 0) ! 454: tcg_out32(s, (cond << 28) | 0x01d000b0 | ! 455: (rn << 16) | (rd << 12) | ! 456: ((im & 0xf0) << 4) | (im & 0xf)); ! 457: else ! 458: tcg_out32(s, (cond << 28) | 0x015000b0 | ! 459: (rn << 16) | (rd << 12) | ! 460: (((-im) & 0xf0) << 4) | ((-im) & 0xf)); ! 461: } ! 462: ! 463: static inline void tcg_out_st16u_8(TCGContext *s, int cond, ! 464: int rd, int rn, tcg_target_long im) ! 465: { ! 466: if (im >= 0) ! 467: tcg_out32(s, (cond << 28) | 0x01c000b0 | ! 468: (rn << 16) | (rd << 12) | ! 469: ((im & 0xf0) << 4) | (im & 0xf)); ! 470: else ! 471: tcg_out32(s, (cond << 28) | 0x014000b0 | ! 472: (rn << 16) | (rd << 12) | ! 473: (((-im) & 0xf0) << 4) | ((-im) & 0xf)); ! 474: } ! 475: ! 476: static inline void tcg_out_ld16u_r(TCGContext *s, int cond, ! 477: int rd, int rn, int rm) ! 478: { ! 479: tcg_out32(s, (cond << 28) | 0x019000b0 | ! 480: (rn << 16) | (rd << 12) | rm); ! 481: } ! 482: ! 483: static inline void tcg_out_st16u_r(TCGContext *s, int cond, ! 484: int rd, int rn, int rm) ! 485: { ! 486: tcg_out32(s, (cond << 28) | 0x018000b0 | ! 487: (rn << 16) | (rd << 12) | rm); ! 488: } ! 489: ! 490: static inline void tcg_out_ld16s_8(TCGContext *s, int cond, ! 491: int rd, int rn, tcg_target_long im) ! 492: { ! 493: if (im >= 0) ! 494: tcg_out32(s, (cond << 28) | 0x01d000f0 | ! 495: (rn << 16) | (rd << 12) | ! 496: ((im & 0xf0) << 4) | (im & 0xf)); ! 497: else ! 498: tcg_out32(s, (cond << 28) | 0x015000f0 | ! 499: (rn << 16) | (rd << 12) | ! 500: (((-im) & 0xf0) << 4) | ((-im) & 0xf)); ! 501: } ! 502: ! 503: static inline void tcg_out_st16s_8(TCGContext *s, int cond, ! 504: int rd, int rn, tcg_target_long im) ! 505: { ! 506: if (im >= 0) ! 507: tcg_out32(s, (cond << 28) | 0x01c000f0 | ! 508: (rn << 16) | (rd << 12) | ! 509: ((im & 0xf0) << 4) | (im & 0xf)); ! 510: else ! 511: tcg_out32(s, (cond << 28) | 0x014000f0 | ! 512: (rn << 16) | (rd << 12) | ! 513: (((-im) & 0xf0) << 4) | ((-im) & 0xf)); ! 514: } ! 515: ! 516: static inline void tcg_out_ld16s_r(TCGContext *s, int cond, ! 517: int rd, int rn, int rm) ! 518: { ! 519: tcg_out32(s, (cond << 28) | 0x019000f0 | ! 520: (rn << 16) | (rd << 12) | rm); ! 521: } ! 522: ! 523: static inline void tcg_out_st16s_r(TCGContext *s, int cond, ! 524: int rd, int rn, int rm) ! 525: { ! 526: tcg_out32(s, (cond << 28) | 0x018000f0 | ! 527: (rn << 16) | (rd << 12) | rm); ! 528: } ! 529: ! 530: static inline void tcg_out_ld8_12(TCGContext *s, int cond, ! 531: int rd, int rn, tcg_target_long im) ! 532: { ! 533: if (im >= 0) ! 534: tcg_out32(s, (cond << 28) | 0x05d00000 | ! 535: (rn << 16) | (rd << 12) | (im & 0xfff)); ! 536: else ! 537: tcg_out32(s, (cond << 28) | 0x05500000 | ! 538: (rn << 16) | (rd << 12) | ((-im) & 0xfff)); ! 539: } ! 540: ! 541: static inline void tcg_out_st8_12(TCGContext *s, int cond, ! 542: int rd, int rn, tcg_target_long im) ! 543: { ! 544: if (im >= 0) ! 545: tcg_out32(s, (cond << 28) | 0x05c00000 | ! 546: (rn << 16) | (rd << 12) | (im & 0xfff)); ! 547: else ! 548: tcg_out32(s, (cond << 28) | 0x05400000 | ! 549: (rn << 16) | (rd << 12) | ((-im) & 0xfff)); ! 550: } ! 551: ! 552: static inline void tcg_out_ld8_r(TCGContext *s, int cond, ! 553: int rd, int rn, int rm) ! 554: { ! 555: tcg_out32(s, (cond << 28) | 0x07d00000 | ! 556: (rn << 16) | (rd << 12) | rm); ! 557: } ! 558: ! 559: static inline void tcg_out_st8_r(TCGContext *s, int cond, ! 560: int rd, int rn, int rm) ! 561: { ! 562: tcg_out32(s, (cond << 28) | 0x07c00000 | ! 563: (rn << 16) | (rd << 12) | rm); ! 564: } ! 565: ! 566: static inline void tcg_out_ld8s_8(TCGContext *s, int cond, ! 567: int rd, int rn, tcg_target_long im) ! 568: { ! 569: if (im >= 0) ! 570: tcg_out32(s, (cond << 28) | 0x01d000d0 | ! 571: (rn << 16) | (rd << 12) | ! 572: ((im & 0xf0) << 4) | (im & 0xf)); ! 573: else ! 574: tcg_out32(s, (cond << 28) | 0x015000d0 | ! 575: (rn << 16) | (rd << 12) | ! 576: (((-im) & 0xf0) << 4) | ((-im) & 0xf)); ! 577: } ! 578: ! 579: static inline void tcg_out_st8s_8(TCGContext *s, int cond, ! 580: int rd, int rn, tcg_target_long im) ! 581: { ! 582: if (im >= 0) ! 583: tcg_out32(s, (cond << 28) | 0x01c000d0 | ! 584: (rn << 16) | (rd << 12) | ! 585: ((im & 0xf0) << 4) | (im & 0xf)); ! 586: else ! 587: tcg_out32(s, (cond << 28) | 0x014000d0 | ! 588: (rn << 16) | (rd << 12) | ! 589: (((-im) & 0xf0) << 4) | ((-im) & 0xf)); ! 590: } ! 591: ! 592: static inline void tcg_out_ld8s_r(TCGContext *s, int cond, ! 593: int rd, int rn, int rm) ! 594: { ! 595: tcg_out32(s, (cond << 28) | 0x019000d0 | ! 596: (rn << 16) | (rd << 12) | rm); ! 597: } ! 598: ! 599: static inline void tcg_out_st8s_r(TCGContext *s, int cond, ! 600: int rd, int rn, int rm) ! 601: { ! 602: tcg_out32(s, (cond << 28) | 0x018000d0 | ! 603: (rn << 16) | (rd << 12) | rm); ! 604: } ! 605: ! 606: static inline void tcg_out_ld32u(TCGContext *s, int cond, ! 607: int rd, int rn, int32_t offset) ! 608: { ! 609: if (offset > 0xfff || offset < -0xfff) { ! 610: tcg_out_movi32(s, cond, TCG_REG_R8, offset); ! 611: tcg_out_ld32_r(s, cond, rd, rn, TCG_REG_R8); ! 612: } else ! 613: tcg_out_ld32_12(s, cond, rd, rn, offset); ! 614: } ! 615: ! 616: static inline void tcg_out_st32(TCGContext *s, int cond, ! 617: int rd, int rn, int32_t offset) ! 618: { ! 619: if (offset > 0xfff || offset < -0xfff) { ! 620: tcg_out_movi32(s, cond, TCG_REG_R8, offset); ! 621: tcg_out_st32_r(s, cond, rd, rn, TCG_REG_R8); ! 622: } else ! 623: tcg_out_st32_12(s, cond, rd, rn, offset); ! 624: } ! 625: ! 626: static inline void tcg_out_ld16u(TCGContext *s, int cond, ! 627: int rd, int rn, int32_t offset) ! 628: { ! 629: if (offset > 0xff || offset < -0xff) { ! 630: tcg_out_movi32(s, cond, TCG_REG_R8, offset); ! 631: tcg_out_ld16u_r(s, cond, rd, rn, TCG_REG_R8); ! 632: } else ! 633: tcg_out_ld16u_8(s, cond, rd, rn, offset); ! 634: } ! 635: ! 636: static inline void tcg_out_ld16s(TCGContext *s, int cond, ! 637: int rd, int rn, int32_t offset) ! 638: { ! 639: if (offset > 0xff || offset < -0xff) { ! 640: tcg_out_movi32(s, cond, TCG_REG_R8, offset); ! 641: tcg_out_ld16s_r(s, cond, rd, rn, TCG_REG_R8); ! 642: } else ! 643: tcg_out_ld16s_8(s, cond, rd, rn, offset); ! 644: } ! 645: ! 646: static inline void tcg_out_st16u(TCGContext *s, int cond, ! 647: int rd, int rn, int32_t offset) ! 648: { ! 649: if (offset > 0xff || offset < -0xff) { ! 650: tcg_out_movi32(s, cond, TCG_REG_R8, offset); ! 651: tcg_out_st16u_r(s, cond, rd, rn, TCG_REG_R8); ! 652: } else ! 653: tcg_out_st16u_8(s, cond, rd, rn, offset); ! 654: } ! 655: ! 656: static inline void tcg_out_ld8u(TCGContext *s, int cond, ! 657: int rd, int rn, int32_t offset) ! 658: { ! 659: if (offset > 0xfff || offset < -0xfff) { ! 660: tcg_out_movi32(s, cond, TCG_REG_R8, offset); ! 661: tcg_out_ld8_r(s, cond, rd, rn, TCG_REG_R8); ! 662: } else ! 663: tcg_out_ld8_12(s, cond, rd, rn, offset); ! 664: } ! 665: ! 666: static inline void tcg_out_ld8s(TCGContext *s, int cond, ! 667: int rd, int rn, int32_t offset) ! 668: { ! 669: if (offset > 0xff || offset < -0xff) { ! 670: tcg_out_movi32(s, cond, TCG_REG_R8, offset); ! 671: tcg_out_ld8s_r(s, cond, rd, rn, TCG_REG_R8); ! 672: } else ! 673: tcg_out_ld8s_8(s, cond, rd, rn, offset); ! 674: } ! 675: ! 676: static inline void tcg_out_st8u(TCGContext *s, int cond, ! 677: int rd, int rn, int32_t offset) ! 678: { ! 679: if (offset > 0xfff || offset < -0xfff) { ! 680: tcg_out_movi32(s, cond, TCG_REG_R8, offset); ! 681: tcg_out_st8_r(s, cond, rd, rn, TCG_REG_R8); ! 682: } else ! 683: tcg_out_st8_12(s, cond, rd, rn, offset); ! 684: } ! 685: ! 686: static inline void tcg_out_goto(TCGContext *s, int cond, uint32_t addr) ! 687: { ! 688: int32_t val; ! 689: ! 690: val = addr - (tcg_target_long) s->code_ptr; ! 691: if (val - 8 < 0x01fffffd && val - 8 > -0x01fffffd) ! 692: tcg_out_b(s, cond, val); ! 693: else { ! 694: #if 1 ! 695: tcg_abort(); ! 696: #else ! 697: if (cond == COND_AL) { ! 698: tcg_out_ld32_12(s, COND_AL, 15, 15, -4); ! 699: tcg_out32(s, addr); /* XXX: This is l->u.value, can we use it? */ ! 700: } else { ! 701: tcg_out_movi32(s, cond, TCG_REG_R8, val - 8); ! 702: tcg_out_dat_reg(s, cond, ARITH_ADD, ! 703: 15, 15, TCG_REG_R8, SHIFT_IMM_LSL(0)); ! 704: } ! 705: #endif ! 706: } ! 707: } ! 708: ! 709: static inline void tcg_out_call(TCGContext *s, int cond, uint32_t addr) ! 710: { ! 711: int32_t val; ! 712: ! 713: #ifdef SAVE_LR ! 714: tcg_out_dat_reg(s, cond, ARITH_MOV, TCG_REG_R8, 0, 14, SHIFT_IMM_LSL(0)); ! 715: #endif ! 716: ! 717: val = addr - (tcg_target_long) s->code_ptr; ! 718: if (val < 0x01fffffd && val > -0x01fffffd) ! 719: tcg_out_bl(s, cond, val); ! 720: else { ! 721: #if 1 ! 722: tcg_abort(); ! 723: #else ! 724: if (cond == COND_AL) { ! 725: tcg_out_dat_imm(s, cond, ARITH_ADD, 14, 15, 4); ! 726: tcg_out_ld32_12(s, COND_AL, 15, 15, -4); ! 727: tcg_out32(s, addr); /* XXX: This is l->u.value, can we use it? */ ! 728: } else { ! 729: tcg_out_movi32(s, cond, TCG_REG_R9, addr); ! 730: tcg_out_dat_imm(s, cond, ARITH_MOV, 14, 0, 15); ! 731: tcg_out_bx(s, cond, TCG_REG_R9); ! 732: } ! 733: #endif ! 734: } ! 735: ! 736: #ifdef SAVE_LR ! 737: tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, TCG_REG_R8, SHIFT_IMM_LSL(0)); ! 738: #endif ! 739: } ! 740: ! 741: static inline void tcg_out_callr(TCGContext *s, int cond, int arg) ! 742: { ! 743: #ifdef SAVE_LR ! 744: tcg_out_dat_reg(s, cond, ARITH_MOV, TCG_REG_R8, 0, 14, SHIFT_IMM_LSL(0)); ! 745: #endif ! 746: /* TODO: on ARMv5 and ARMv6 replace with tcg_out_blx(s, cond, arg); */ ! 747: tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, 15, SHIFT_IMM_LSL(0)); ! 748: tcg_out_bx(s, cond, arg); ! 749: #ifdef SAVE_LR ! 750: tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, TCG_REG_R8, SHIFT_IMM_LSL(0)); ! 751: #endif ! 752: } ! 753: ! 754: static inline void tcg_out_goto_label(TCGContext *s, int cond, int label_index) ! 755: { ! 756: TCGLabel *l = &s->labels[label_index]; ! 757: ! 758: if (l->has_value) ! 759: tcg_out_goto(s, cond, l->u.value); ! 760: else if (cond == COND_AL) { ! 761: tcg_out_ld32_12(s, COND_AL, 15, 15, -4); ! 762: tcg_out_reloc(s, s->code_ptr, R_ARM_ABS32, label_index, 31337); ! 763: s->code_ptr += 4; ! 764: } else { ! 765: /* Probably this should be preferred even for COND_AL... */ ! 766: tcg_out_reloc(s, s->code_ptr, R_ARM_PC24, label_index, 31337); ! 767: tcg_out_b_noaddr(s, cond); ! 768: } ! 769: } ! 770: ! 771: static void tcg_out_div_helper(TCGContext *s, int cond, const TCGArg *args, ! 772: void *helper_div, void *helper_rem, int shift) ! 773: { ! 774: int div_reg = args[0]; ! 775: int rem_reg = args[1]; ! 776: ! 777: /* stmdb sp!, { r0 - r3, ip, lr } */ ! 778: /* (Note that we need an even number of registers as per EABI) */ ! 779: tcg_out32(s, (cond << 28) | 0x092d500f); ! 780: ! 781: tcg_out_dat_reg(s, cond, ARITH_MOV, 0, 0, args[2], SHIFT_IMM_LSL(0)); ! 782: tcg_out_dat_reg(s, cond, ARITH_MOV, 1, 0, args[3], SHIFT_IMM_LSL(0)); ! 783: tcg_out_dat_reg(s, cond, ARITH_MOV, 2, 0, args[4], SHIFT_IMM_LSL(0)); ! 784: tcg_out_dat_reg(s, cond, ARITH_MOV, 3, 0, 2, shift); ! 785: ! 786: tcg_out_call(s, cond, (uint32_t) helper_div); ! 787: tcg_out_dat_reg(s, cond, ARITH_MOV, 8, 0, 0, SHIFT_IMM_LSL(0)); ! 788: ! 789: /* ldmia sp, { r0 - r3, fp, lr } */ ! 790: tcg_out32(s, (cond << 28) | 0x089d500f); ! 791: ! 792: tcg_out_dat_reg(s, cond, ARITH_MOV, 0, 0, args[2], SHIFT_IMM_LSL(0)); ! 793: tcg_out_dat_reg(s, cond, ARITH_MOV, 1, 0, args[3], SHIFT_IMM_LSL(0)); ! 794: tcg_out_dat_reg(s, cond, ARITH_MOV, 2, 0, args[4], SHIFT_IMM_LSL(0)); ! 795: tcg_out_dat_reg(s, cond, ARITH_MOV, 3, 0, 2, shift); ! 796: ! 797: tcg_out_call(s, cond, (uint32_t) helper_rem); ! 798: ! 799: tcg_out_dat_reg(s, cond, ARITH_MOV, rem_reg, 0, 0, SHIFT_IMM_LSL(0)); ! 800: tcg_out_dat_reg(s, cond, ARITH_MOV, div_reg, 0, 8, SHIFT_IMM_LSL(0)); ! 801: ! 802: /* ldr r0, [sp], #4 */ ! 803: if (rem_reg != 0 && div_reg != 0) ! 804: tcg_out32(s, (cond << 28) | 0x04bd0004); ! 805: /* ldr r1, [sp], #4 */ ! 806: if (rem_reg != 1 && div_reg != 1) ! 807: tcg_out32(s, (cond << 28) | 0x04bd1004); ! 808: /* ldr r2, [sp], #4 */ ! 809: if (rem_reg != 2 && div_reg != 2) ! 810: tcg_out32(s, (cond << 28) | 0x04bd2004); ! 811: /* ldr r3, [sp], #4 */ ! 812: if (rem_reg != 3 && div_reg != 3) ! 813: tcg_out32(s, (cond << 28) | 0x04bd3004); ! 814: /* ldr ip, [sp], #4 */ ! 815: if (rem_reg != 12 && div_reg != 12) ! 816: tcg_out32(s, (cond << 28) | 0x04bdc004); ! 817: /* ldr lr, [sp], #4 */ ! 818: if (rem_reg != 14 && div_reg != 14) ! 819: tcg_out32(s, (cond << 28) | 0x04bde004); ! 820: } ! 821: ! 822: #ifdef CONFIG_SOFTMMU ! 823: ! 824: #include "../../softmmu_defs.h" ! 825: ! 826: static void *qemu_ld_helpers[4] = { ! 827: __ldb_mmu, ! 828: __ldw_mmu, ! 829: __ldl_mmu, ! 830: __ldq_mmu, ! 831: }; ! 832: ! 833: static void *qemu_st_helpers[4] = { ! 834: __stb_mmu, ! 835: __stw_mmu, ! 836: __stl_mmu, ! 837: __stq_mmu, ! 838: }; ! 839: #endif ! 840: ! 841: #define TLB_SHIFT (CPU_TLB_ENTRY_BITS + CPU_TLB_BITS) ! 842: ! 843: static inline void tcg_out_qemu_ld(TCGContext *s, int cond, ! 844: const TCGArg *args, int opc) ! 845: { ! 846: int addr_reg, data_reg, data_reg2; ! 847: #ifdef CONFIG_SOFTMMU ! 848: int mem_index, s_bits; ! 849: # if TARGET_LONG_BITS == 64 ! 850: int addr_reg2; ! 851: # endif ! 852: uint32_t *label_ptr; ! 853: #endif ! 854: ! 855: data_reg = *args++; ! 856: if (opc == 3) ! 857: data_reg2 = *args++; ! 858: else ! 859: data_reg2 = 0; /* surpress warning */ ! 860: addr_reg = *args++; ! 861: #ifdef CONFIG_SOFTMMU ! 862: # if TARGET_LONG_BITS == 64 ! 863: addr_reg2 = *args++; ! 864: # endif ! 865: mem_index = *args; ! 866: s_bits = opc & 3; ! 867: ! 868: /* Should generate something like the following: ! 869: * shr r8, addr_reg, #TARGET_PAGE_BITS ! 870: * and r0, r8, #(CPU_TLB_SIZE - 1) @ Assumption: CPU_TLB_BITS <= 8 ! 871: * add r0, env, r0 lsl #CPU_TLB_ENTRY_BITS ! 872: */ ! 873: # if CPU_TLB_BITS > 8 ! 874: # error ! 875: # endif ! 876: tcg_out_dat_reg(s, COND_AL, ARITH_MOV, ! 877: 8, 0, addr_reg, SHIFT_IMM_LSR(TARGET_PAGE_BITS)); ! 878: tcg_out_dat_imm(s, COND_AL, ARITH_AND, ! 879: 0, 8, CPU_TLB_SIZE - 1); ! 880: tcg_out_dat_reg(s, COND_AL, ARITH_ADD, ! 881: 0, TCG_AREG0, 0, SHIFT_IMM_LSL(CPU_TLB_ENTRY_BITS)); ! 882: /* In the ! 883: * ldr r1 [r0, #(offsetof(CPUState, tlb_table[mem_index][0].addr_read))] ! 884: * below, the offset is likely to exceed 12 bits if mem_index != 0 and ! 885: * not exceed otherwise, so use an ! 886: * add r0, r0, #(mem_index * sizeof *CPUState.tlb_table) ! 887: * before. ! 888: */ ! 889: if (mem_index) ! 890: tcg_out_dat_imm(s, COND_AL, ARITH_ADD, 0, 0, ! 891: (mem_index << (TLB_SHIFT & 1)) | ! 892: ((16 - (TLB_SHIFT >> 1)) << 8)); ! 893: tcg_out_ld32_12(s, COND_AL, 1, 0, ! 894: offsetof(CPUState, tlb_table[0][0].addr_read)); ! 895: tcg_out_dat_reg(s, COND_AL, ARITH_CMP, ! 896: 0, 1, 8, SHIFT_IMM_LSL(TARGET_PAGE_BITS)); ! 897: /* Check alignment. */ ! 898: if (s_bits) ! 899: tcg_out_dat_imm(s, COND_EQ, ARITH_TST, ! 900: 0, addr_reg, (1 << s_bits) - 1); ! 901: # if TARGET_LONG_BITS == 64 ! 902: /* XXX: possibly we could use a block data load or writeback in ! 903: * the first access. */ ! 904: tcg_out_ld32_12(s, COND_EQ, 1, 0, ! 905: offsetof(CPUState, tlb_table[0][0].addr_read) + 4); ! 906: tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, ! 907: 0, 1, addr_reg2, SHIFT_IMM_LSL(0)); ! 908: # endif ! 909: tcg_out_ld32_12(s, COND_EQ, 1, 0, ! 910: offsetof(CPUState, tlb_table[0][0].addend)); ! 911: ! 912: switch (opc) { ! 913: case 0: ! 914: tcg_out_ld8_r(s, COND_EQ, data_reg, addr_reg, 1); ! 915: break; ! 916: case 0 | 4: ! 917: tcg_out_ld8s_r(s, COND_EQ, data_reg, addr_reg, 1); ! 918: break; ! 919: case 1: ! 920: tcg_out_ld16u_r(s, COND_EQ, data_reg, addr_reg, 1); ! 921: break; ! 922: case 1 | 4: ! 923: tcg_out_ld16s_r(s, COND_EQ, data_reg, addr_reg, 1); ! 924: break; ! 925: case 2: ! 926: default: ! 927: tcg_out_ld32_r(s, COND_EQ, data_reg, addr_reg, 1); ! 928: break; ! 929: case 3: ! 930: tcg_out_ld32_rwb(s, COND_EQ, data_reg, 1, addr_reg); ! 931: tcg_out_ld32_12(s, COND_EQ, data_reg2, 1, 4); ! 932: break; ! 933: } ! 934: ! 935: label_ptr = (void *) s->code_ptr; ! 936: tcg_out_b(s, COND_EQ, 8); ! 937: ! 938: # ifdef SAVE_LR ! 939: tcg_out_dat_reg(s, cond, ARITH_MOV, 8, 0, 14, SHIFT_IMM_LSL(0)); ! 940: # endif ! 941: ! 942: /* TODO: move this code to where the constants pool will be */ ! 943: if (addr_reg) ! 944: tcg_out_dat_reg(s, cond, ARITH_MOV, ! 945: 0, 0, addr_reg, SHIFT_IMM_LSL(0)); ! 946: # if TARGET_LONG_BITS == 32 ! 947: tcg_out_dat_imm(s, cond, ARITH_MOV, 1, 0, mem_index); ! 948: # else ! 949: if (addr_reg2 != 1) ! 950: tcg_out_dat_reg(s, cond, ARITH_MOV, ! 951: 1, 0, addr_reg2, SHIFT_IMM_LSL(0)); ! 952: tcg_out_dat_imm(s, cond, ARITH_MOV, 2, 0, mem_index); ! 953: # endif ! 954: tcg_out_bl(s, cond, (tcg_target_long) qemu_ld_helpers[s_bits] - ! 955: (tcg_target_long) s->code_ptr); ! 956: ! 957: switch (opc) { ! 958: case 0 | 4: ! 959: tcg_out_dat_reg(s, cond, ARITH_MOV, ! 960: 0, 0, 0, SHIFT_IMM_LSL(24)); ! 961: tcg_out_dat_reg(s, cond, ARITH_MOV, ! 962: data_reg, 0, 0, SHIFT_IMM_ASR(24)); ! 963: break; ! 964: case 1 | 4: ! 965: tcg_out_dat_reg(s, cond, ARITH_MOV, ! 966: 0, 0, 0, SHIFT_IMM_LSL(16)); ! 967: tcg_out_dat_reg(s, cond, ARITH_MOV, ! 968: data_reg, 0, 0, SHIFT_IMM_ASR(16)); ! 969: break; ! 970: case 0: ! 971: case 1: ! 972: case 2: ! 973: default: ! 974: if (data_reg) ! 975: tcg_out_dat_reg(s, cond, ARITH_MOV, ! 976: data_reg, 0, 0, SHIFT_IMM_LSL(0)); ! 977: break; ! 978: case 3: ! 979: if (data_reg != 0) ! 980: tcg_out_dat_reg(s, cond, ARITH_MOV, ! 981: data_reg, 0, 0, SHIFT_IMM_LSL(0)); ! 982: if (data_reg2 != 1) ! 983: tcg_out_dat_reg(s, cond, ARITH_MOV, ! 984: data_reg2, 0, 1, SHIFT_IMM_LSL(0)); ! 985: break; ! 986: } ! 987: ! 988: # ifdef SAVE_LR ! 989: tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, 8, SHIFT_IMM_LSL(0)); ! 990: # endif ! 991: ! 992: *label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2; ! 993: #else ! 994: switch (opc) { ! 995: case 0: ! 996: tcg_out_ld8_12(s, COND_AL, data_reg, addr_reg, 0); ! 997: break; ! 998: case 0 | 4: ! 999: tcg_out_ld8s_8(s, COND_AL, data_reg, addr_reg, 0); ! 1000: break; ! 1001: case 1: ! 1002: tcg_out_ld16u_8(s, COND_AL, data_reg, addr_reg, 0); ! 1003: break; ! 1004: case 1 | 4: ! 1005: tcg_out_ld16s_8(s, COND_AL, data_reg, addr_reg, 0); ! 1006: break; ! 1007: case 2: ! 1008: default: ! 1009: tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, 0); ! 1010: break; ! 1011: case 3: ! 1012: /* TODO: use block load - ! 1013: * check that data_reg2 > data_reg or the other way */ ! 1014: tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, 0); ! 1015: tcg_out_ld32_12(s, COND_AL, data_reg2, addr_reg, 4); ! 1016: break; ! 1017: } ! 1018: #endif ! 1019: } ! 1020: ! 1021: static inline void tcg_out_qemu_st(TCGContext *s, int cond, ! 1022: const TCGArg *args, int opc) ! 1023: { ! 1024: int addr_reg, data_reg, data_reg2; ! 1025: #ifdef CONFIG_SOFTMMU ! 1026: int mem_index, s_bits; ! 1027: # if TARGET_LONG_BITS == 64 ! 1028: int addr_reg2; ! 1029: # endif ! 1030: uint32_t *label_ptr; ! 1031: #endif ! 1032: ! 1033: data_reg = *args++; ! 1034: if (opc == 3) ! 1035: data_reg2 = *args++; ! 1036: else ! 1037: data_reg2 = 0; /* surpress warning */ ! 1038: addr_reg = *args++; ! 1039: #ifdef CONFIG_SOFTMMU ! 1040: # if TARGET_LONG_BITS == 64 ! 1041: addr_reg2 = *args++; ! 1042: # endif ! 1043: mem_index = *args; ! 1044: s_bits = opc & 3; ! 1045: ! 1046: /* Should generate something like the following: ! 1047: * shr r8, addr_reg, #TARGET_PAGE_BITS ! 1048: * and r0, r8, #(CPU_TLB_SIZE - 1) @ Assumption: CPU_TLB_BITS <= 8 ! 1049: * add r0, env, r0 lsl #CPU_TLB_ENTRY_BITS ! 1050: */ ! 1051: tcg_out_dat_reg(s, COND_AL, ARITH_MOV, ! 1052: 8, 0, addr_reg, SHIFT_IMM_LSR(TARGET_PAGE_BITS)); ! 1053: tcg_out_dat_imm(s, COND_AL, ARITH_AND, ! 1054: 0, 8, CPU_TLB_SIZE - 1); ! 1055: tcg_out_dat_reg(s, COND_AL, ARITH_ADD, ! 1056: 0, TCG_AREG0, 0, SHIFT_IMM_LSL(CPU_TLB_ENTRY_BITS)); ! 1057: /* In the ! 1058: * ldr r1 [r0, #(offsetof(CPUState, tlb_table[mem_index][0].addr_write))] ! 1059: * below, the offset is likely to exceed 12 bits if mem_index != 0 and ! 1060: * not exceed otherwise, so use an ! 1061: * add r0, r0, #(mem_index * sizeof *CPUState.tlb_table) ! 1062: * before. ! 1063: */ ! 1064: if (mem_index) ! 1065: tcg_out_dat_imm(s, COND_AL, ARITH_ADD, 0, 0, ! 1066: (mem_index << (TLB_SHIFT & 1)) | ! 1067: ((16 - (TLB_SHIFT >> 1)) << 8)); ! 1068: tcg_out_ld32_12(s, COND_AL, 1, 0, ! 1069: offsetof(CPUState, tlb_table[0][0].addr_write)); ! 1070: tcg_out_dat_reg(s, COND_AL, ARITH_CMP, ! 1071: 0, 1, 8, SHIFT_IMM_LSL(TARGET_PAGE_BITS)); ! 1072: /* Check alignment. */ ! 1073: if (s_bits) ! 1074: tcg_out_dat_imm(s, COND_EQ, ARITH_TST, ! 1075: 0, addr_reg, (1 << s_bits) - 1); ! 1076: # if TARGET_LONG_BITS == 64 ! 1077: /* XXX: possibly we could use a block data load or writeback in ! 1078: * the first access. */ ! 1079: tcg_out_ld32_12(s, COND_EQ, 1, 0, ! 1080: offsetof(CPUState, tlb_table[0][0].addr_write) ! 1081: + 4); ! 1082: tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, ! 1083: 0, 1, addr_reg2, SHIFT_IMM_LSL(0)); ! 1084: # endif ! 1085: tcg_out_ld32_12(s, COND_EQ, 1, 0, ! 1086: offsetof(CPUState, tlb_table[0][0].addend)); ! 1087: ! 1088: switch (opc) { ! 1089: case 0: ! 1090: tcg_out_st8_r(s, COND_EQ, data_reg, addr_reg, 1); ! 1091: break; ! 1092: case 0 | 4: ! 1093: tcg_out_st8s_r(s, COND_EQ, data_reg, addr_reg, 1); ! 1094: break; ! 1095: case 1: ! 1096: tcg_out_st16u_r(s, COND_EQ, data_reg, addr_reg, 1); ! 1097: break; ! 1098: case 1 | 4: ! 1099: tcg_out_st16s_r(s, COND_EQ, data_reg, addr_reg, 1); ! 1100: break; ! 1101: case 2: ! 1102: default: ! 1103: tcg_out_st32_r(s, COND_EQ, data_reg, addr_reg, 1); ! 1104: break; ! 1105: case 3: ! 1106: tcg_out_st32_rwb(s, COND_EQ, data_reg, 1, addr_reg); ! 1107: tcg_out_st32_12(s, COND_EQ, data_reg2, 1, 4); ! 1108: break; ! 1109: } ! 1110: ! 1111: label_ptr = (void *) s->code_ptr; ! 1112: tcg_out_b(s, COND_EQ, 8); ! 1113: ! 1114: /* TODO: move this code to where the constants pool will be */ ! 1115: if (addr_reg) ! 1116: tcg_out_dat_reg(s, cond, ARITH_MOV, ! 1117: 0, 0, addr_reg, SHIFT_IMM_LSL(0)); ! 1118: # if TARGET_LONG_BITS == 32 ! 1119: switch (opc) { ! 1120: case 0: ! 1121: tcg_out_dat_imm(s, cond, ARITH_AND, 1, data_reg, 0xff); ! 1122: tcg_out_dat_imm(s, cond, ARITH_MOV, 2, 0, mem_index); ! 1123: break; ! 1124: case 1: ! 1125: tcg_out_dat_reg(s, cond, ARITH_MOV, ! 1126: 1, 0, data_reg, SHIFT_IMM_LSL(16)); ! 1127: tcg_out_dat_reg(s, cond, ARITH_MOV, ! 1128: 1, 0, 1, SHIFT_IMM_LSR(16)); ! 1129: tcg_out_dat_imm(s, cond, ARITH_MOV, 2, 0, mem_index); ! 1130: break; ! 1131: case 2: ! 1132: if (data_reg != 1) ! 1133: tcg_out_dat_reg(s, cond, ARITH_MOV, ! 1134: 1, 0, data_reg, SHIFT_IMM_LSL(0)); ! 1135: tcg_out_dat_imm(s, cond, ARITH_MOV, 2, 0, mem_index); ! 1136: break; ! 1137: case 3: ! 1138: if (data_reg != 1) ! 1139: tcg_out_dat_reg(s, cond, ARITH_MOV, ! 1140: 1, 0, data_reg, SHIFT_IMM_LSL(0)); ! 1141: if (data_reg2 != 2) ! 1142: tcg_out_dat_reg(s, cond, ARITH_MOV, ! 1143: 2, 0, data_reg2, SHIFT_IMM_LSL(0)); ! 1144: tcg_out_dat_imm(s, cond, ARITH_MOV, 3, 0, mem_index); ! 1145: break; ! 1146: } ! 1147: # else ! 1148: if (addr_reg2 != 1) ! 1149: tcg_out_dat_reg(s, cond, ARITH_MOV, ! 1150: 1, 0, addr_reg2, SHIFT_IMM_LSL(0)); ! 1151: switch (opc) { ! 1152: case 0: ! 1153: tcg_out_dat_imm(s, cond, ARITH_AND, 2, data_reg, 0xff); ! 1154: tcg_out_dat_imm(s, cond, ARITH_MOV, 3, 0, mem_index); ! 1155: break; ! 1156: case 1: ! 1157: tcg_out_dat_reg(s, cond, ARITH_MOV, ! 1158: 2, 0, data_reg, SHIFT_IMM_LSL(16)); ! 1159: tcg_out_dat_reg(s, cond, ARITH_MOV, ! 1160: 2, 0, 2, SHIFT_IMM_LSR(16)); ! 1161: tcg_out_dat_imm(s, cond, ARITH_MOV, 3, 0, mem_index); ! 1162: break; ! 1163: case 2: ! 1164: if (data_reg != 2) ! 1165: tcg_out_dat_reg(s, cond, ARITH_MOV, ! 1166: 2, 0, data_reg, SHIFT_IMM_LSL(0)); ! 1167: tcg_out_dat_imm(s, cond, ARITH_MOV, 3, 0, mem_index); ! 1168: break; ! 1169: case 3: ! 1170: tcg_out_dat_imm(s, cond, ARITH_MOV, 8, 0, mem_index); ! 1171: tcg_out32(s, (cond << 28) | 0x052d8010); /* str r8, [sp, #-0x10]! */ ! 1172: if (data_reg != 2) ! 1173: tcg_out_dat_reg(s, cond, ARITH_MOV, ! 1174: 2, 0, data_reg, SHIFT_IMM_LSL(0)); ! 1175: if (data_reg2 != 3) ! 1176: tcg_out_dat_reg(s, cond, ARITH_MOV, ! 1177: 3, 0, data_reg2, SHIFT_IMM_LSL(0)); ! 1178: break; ! 1179: } ! 1180: # endif ! 1181: ! 1182: # ifdef SAVE_LR ! 1183: tcg_out_dat_reg(s, cond, ARITH_MOV, 8, 0, 14, SHIFT_IMM_LSL(0)); ! 1184: # endif ! 1185: ! 1186: tcg_out_bl(s, cond, (tcg_target_long) qemu_st_helpers[s_bits] - ! 1187: (tcg_target_long) s->code_ptr); ! 1188: # if TARGET_LONG_BITS == 64 ! 1189: if (opc == 3) ! 1190: tcg_out_dat_imm(s, cond, ARITH_ADD, 13, 13, 0x10); ! 1191: # endif ! 1192: ! 1193: # ifdef SAVE_LR ! 1194: tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, 8, SHIFT_IMM_LSL(0)); ! 1195: # endif ! 1196: ! 1197: *label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2; ! 1198: #else ! 1199: switch (opc) { ! 1200: case 0: ! 1201: tcg_out_st8_12(s, COND_AL, data_reg, addr_reg, 0); ! 1202: break; ! 1203: case 0 | 4: ! 1204: tcg_out_st8s_8(s, COND_AL, data_reg, addr_reg, 0); ! 1205: break; ! 1206: case 1: ! 1207: tcg_out_st16u_8(s, COND_AL, data_reg, addr_reg, 0); ! 1208: break; ! 1209: case 1 | 4: ! 1210: tcg_out_st16s_8(s, COND_AL, data_reg, addr_reg, 0); ! 1211: break; ! 1212: case 2: ! 1213: default: ! 1214: tcg_out_st32_12(s, COND_AL, data_reg, addr_reg, 0); ! 1215: break; ! 1216: case 3: ! 1217: /* TODO: use block store - ! 1218: * check that data_reg2 > data_reg or the other way */ ! 1219: tcg_out_st32_12(s, COND_AL, data_reg, addr_reg, 0); ! 1220: tcg_out_st32_12(s, COND_AL, data_reg2, addr_reg, 4); ! 1221: break; ! 1222: } ! 1223: #endif ! 1224: } ! 1225: ! 1226: static uint8_t *tb_ret_addr; ! 1227: ! 1228: static inline void tcg_out_op(TCGContext *s, int opc, ! 1229: const TCGArg *args, const int *const_args) ! 1230: { ! 1231: int c; ! 1232: ! 1233: switch (opc) { ! 1234: case INDEX_op_exit_tb: ! 1235: #ifdef SAVE_LR ! 1236: if (args[0] >> 8) ! 1237: tcg_out_ld32_12(s, COND_AL, TCG_REG_R0, 15, 0); ! 1238: else ! 1239: tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R0, 0, args[0]); ! 1240: tcg_out_dat_reg(s, COND_AL, ARITH_MOV, 15, 0, 14, SHIFT_IMM_LSL(0)); ! 1241: if (args[0] >> 8) ! 1242: tcg_out32(s, args[0]); ! 1243: #else ! 1244: { ! 1245: uint8_t *ld_ptr = s->code_ptr; ! 1246: if (args[0] >> 8) ! 1247: tcg_out_ld32_12(s, COND_AL, 0, 15, 0); ! 1248: else ! 1249: tcg_out_dat_imm(s, COND_AL, ARITH_MOV, 0, 0, args[0]); ! 1250: tcg_out_goto(s, COND_AL, (tcg_target_ulong) tb_ret_addr); ! 1251: if (args[0] >> 8) { ! 1252: *ld_ptr = (uint8_t) (s->code_ptr - ld_ptr) - 8; ! 1253: tcg_out32(s, args[0]); ! 1254: } ! 1255: } ! 1256: #endif ! 1257: break; ! 1258: case INDEX_op_goto_tb: ! 1259: if (s->tb_jmp_offset) { ! 1260: /* Direct jump method */ ! 1261: #if defined(USE_DIRECT_JUMP) ! 1262: s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; ! 1263: tcg_out_b(s, COND_AL, 8); ! 1264: #else ! 1265: tcg_out_ld32_12(s, COND_AL, 15, 15, -4); ! 1266: s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; ! 1267: tcg_out32(s, 0); ! 1268: #endif ! 1269: } else { ! 1270: /* Indirect jump method */ ! 1271: #if 1 ! 1272: c = (int) (s->tb_next + args[0]) - ((int) s->code_ptr + 8); ! 1273: if (c > 0xfff || c < -0xfff) { ! 1274: tcg_out_movi32(s, COND_AL, TCG_REG_R0, ! 1275: (tcg_target_long) (s->tb_next + args[0])); ! 1276: tcg_out_ld32_12(s, COND_AL, 15, TCG_REG_R0, 0); ! 1277: } else ! 1278: tcg_out_ld32_12(s, COND_AL, 15, 15, c); ! 1279: #else ! 1280: tcg_out_ld32_12(s, COND_AL, TCG_REG_R0, 15, 0); ! 1281: tcg_out_ld32_12(s, COND_AL, 15, TCG_REG_R0, 0); ! 1282: tcg_out32(s, (tcg_target_long) (s->tb_next + args[0])); ! 1283: #endif ! 1284: } ! 1285: s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; ! 1286: break; ! 1287: case INDEX_op_call: ! 1288: if (const_args[0]) ! 1289: tcg_out_call(s, COND_AL, args[0]); ! 1290: else ! 1291: tcg_out_callr(s, COND_AL, args[0]); ! 1292: break; ! 1293: case INDEX_op_jmp: ! 1294: if (const_args[0]) ! 1295: tcg_out_goto(s, COND_AL, args[0]); ! 1296: else ! 1297: tcg_out_bx(s, COND_AL, args[0]); ! 1298: break; ! 1299: case INDEX_op_br: ! 1300: tcg_out_goto_label(s, COND_AL, args[0]); ! 1301: break; ! 1302: ! 1303: case INDEX_op_ld8u_i32: ! 1304: tcg_out_ld8u(s, COND_AL, args[0], args[1], args[2]); ! 1305: break; ! 1306: case INDEX_op_ld8s_i32: ! 1307: tcg_out_ld8s(s, COND_AL, args[0], args[1], args[2]); ! 1308: break; ! 1309: case INDEX_op_ld16u_i32: ! 1310: tcg_out_ld16u(s, COND_AL, args[0], args[1], args[2]); ! 1311: break; ! 1312: case INDEX_op_ld16s_i32: ! 1313: tcg_out_ld16s(s, COND_AL, args[0], args[1], args[2]); ! 1314: break; ! 1315: case INDEX_op_ld_i32: ! 1316: tcg_out_ld32u(s, COND_AL, args[0], args[1], args[2]); ! 1317: break; ! 1318: case INDEX_op_st8_i32: ! 1319: tcg_out_st8u(s, COND_AL, args[0], args[1], args[2]); ! 1320: break; ! 1321: case INDEX_op_st16_i32: ! 1322: tcg_out_st16u(s, COND_AL, args[0], args[1], args[2]); ! 1323: break; ! 1324: case INDEX_op_st_i32: ! 1325: tcg_out_st32(s, COND_AL, args[0], args[1], args[2]); ! 1326: break; ! 1327: ! 1328: case INDEX_op_mov_i32: ! 1329: tcg_out_dat_reg(s, COND_AL, ARITH_MOV, ! 1330: args[0], 0, args[1], SHIFT_IMM_LSL(0)); ! 1331: break; ! 1332: case INDEX_op_movi_i32: ! 1333: tcg_out_movi32(s, COND_AL, args[0], args[1]); ! 1334: break; ! 1335: case INDEX_op_add_i32: ! 1336: c = ARITH_ADD; ! 1337: goto gen_arith; ! 1338: case INDEX_op_sub_i32: ! 1339: c = ARITH_SUB; ! 1340: goto gen_arith; ! 1341: case INDEX_op_and_i32: ! 1342: c = ARITH_AND; ! 1343: goto gen_arith; ! 1344: case INDEX_op_or_i32: ! 1345: c = ARITH_ORR; ! 1346: goto gen_arith; ! 1347: case INDEX_op_xor_i32: ! 1348: c = ARITH_EOR; ! 1349: /* Fall through. */ ! 1350: gen_arith: ! 1351: tcg_out_dat_reg(s, COND_AL, c, ! 1352: args[0], args[1], args[2], SHIFT_IMM_LSL(0)); ! 1353: break; ! 1354: case INDEX_op_add2_i32: ! 1355: tcg_out_dat_reg2(s, COND_AL, ARITH_ADD, ARITH_ADC, ! 1356: args[0], args[1], args[2], args[3], ! 1357: args[4], args[5], SHIFT_IMM_LSL(0)); ! 1358: break; ! 1359: case INDEX_op_sub2_i32: ! 1360: tcg_out_dat_reg2(s, COND_AL, ARITH_SUB, ARITH_SBC, ! 1361: args[0], args[1], args[2], args[3], ! 1362: args[4], args[5], SHIFT_IMM_LSL(0)); ! 1363: break; ! 1364: case INDEX_op_neg_i32: ! 1365: tcg_out_dat_imm(s, COND_AL, ARITH_RSB, args[0], args[1], 0); ! 1366: break; ! 1367: case INDEX_op_mul_i32: ! 1368: tcg_out_mul32(s, COND_AL, args[0], args[1], args[2]); ! 1369: break; ! 1370: case INDEX_op_mulu2_i32: ! 1371: tcg_out_umull32(s, COND_AL, args[0], args[1], args[2], args[3]); ! 1372: break; ! 1373: case INDEX_op_div2_i32: ! 1374: tcg_out_div_helper(s, COND_AL, args, ! 1375: tcg_helper_div_i64, tcg_helper_rem_i64, ! 1376: SHIFT_IMM_ASR(31)); ! 1377: break; ! 1378: case INDEX_op_divu2_i32: ! 1379: tcg_out_div_helper(s, COND_AL, args, ! 1380: tcg_helper_divu_i64, tcg_helper_remu_i64, ! 1381: SHIFT_IMM_LSR(31)); ! 1382: break; ! 1383: /* XXX: Perhaps args[2] & 0x1f is wrong */ ! 1384: case INDEX_op_shl_i32: ! 1385: c = const_args[2] ? ! 1386: SHIFT_IMM_LSL(args[2] & 0x1f) : SHIFT_REG_LSL(args[2]); ! 1387: goto gen_shift32; ! 1388: case INDEX_op_shr_i32: ! 1389: c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_LSR(args[2] & 0x1f) : ! 1390: SHIFT_IMM_LSL(0) : SHIFT_REG_LSR(args[2]); ! 1391: goto gen_shift32; ! 1392: case INDEX_op_sar_i32: ! 1393: c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_ASR(args[2] & 0x1f) : ! 1394: SHIFT_IMM_LSL(0) : SHIFT_REG_ASR(args[2]); ! 1395: /* Fall through. */ ! 1396: gen_shift32: ! 1397: tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1], c); ! 1398: break; ! 1399: ! 1400: case INDEX_op_brcond_i32: ! 1401: tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, ! 1402: args[0], args[1], SHIFT_IMM_LSL(0)); ! 1403: tcg_out_goto_label(s, tcg_cond_to_arm_cond[args[2]], args[3]); ! 1404: break; ! 1405: case INDEX_op_brcond2_i32: ! 1406: /* The resulting conditions are: ! 1407: * TCG_COND_EQ --> a0 == a2 && a1 == a3, ! 1408: * TCG_COND_NE --> (a0 != a2 && a1 == a3) || a1 != a3, ! 1409: * TCG_COND_LT(U) --> (a0 < a2 && a1 == a3) || a1 < a3, ! 1410: * TCG_COND_GE(U) --> (a0 >= a2 && a1 == a3) || (a1 >= a3 && a1 != a3), ! 1411: * TCG_COND_LE(U) --> (a0 <= a2 && a1 == a3) || (a1 <= a3 && a1 != a3), ! 1412: * TCG_COND_GT(U) --> (a0 > a2 && a1 == a3) || a1 > a3, ! 1413: */ ! 1414: tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, ! 1415: args[1], args[3], SHIFT_IMM_LSL(0)); ! 1416: tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0, ! 1417: args[0], args[2], SHIFT_IMM_LSL(0)); ! 1418: tcg_out_goto_label(s, tcg_cond_to_arm_cond[args[4]], args[5]); ! 1419: break; ! 1420: ! 1421: case INDEX_op_qemu_ld8u: ! 1422: tcg_out_qemu_ld(s, COND_AL, args, 0); ! 1423: break; ! 1424: case INDEX_op_qemu_ld8s: ! 1425: tcg_out_qemu_ld(s, COND_AL, args, 0 | 4); ! 1426: break; ! 1427: case INDEX_op_qemu_ld16u: ! 1428: tcg_out_qemu_ld(s, COND_AL, args, 1); ! 1429: break; ! 1430: case INDEX_op_qemu_ld16s: ! 1431: tcg_out_qemu_ld(s, COND_AL, args, 1 | 4); ! 1432: break; ! 1433: case INDEX_op_qemu_ld32u: ! 1434: tcg_out_qemu_ld(s, COND_AL, args, 2); ! 1435: break; ! 1436: case INDEX_op_qemu_ld64: ! 1437: tcg_out_qemu_ld(s, COND_AL, args, 3); ! 1438: break; ! 1439: ! 1440: case INDEX_op_qemu_st8: ! 1441: tcg_out_qemu_st(s, COND_AL, args, 0); ! 1442: break; ! 1443: case INDEX_op_qemu_st16: ! 1444: tcg_out_qemu_st(s, COND_AL, args, 1); ! 1445: break; ! 1446: case INDEX_op_qemu_st32: ! 1447: tcg_out_qemu_st(s, COND_AL, args, 2); ! 1448: break; ! 1449: case INDEX_op_qemu_st64: ! 1450: tcg_out_qemu_st(s, COND_AL, args, 3); ! 1451: break; ! 1452: ! 1453: case INDEX_op_ext8s_i32: ! 1454: tcg_out_dat_reg(s, COND_AL, ARITH_MOV, ! 1455: args[0], 0, args[1], SHIFT_IMM_LSL(24)); ! 1456: tcg_out_dat_reg(s, COND_AL, ARITH_MOV, ! 1457: args[0], 0, args[0], SHIFT_IMM_ASR(24)); ! 1458: break; ! 1459: case INDEX_op_ext16s_i32: ! 1460: tcg_out_dat_reg(s, COND_AL, ARITH_MOV, ! 1461: args[0], 0, args[1], SHIFT_IMM_LSL(16)); ! 1462: tcg_out_dat_reg(s, COND_AL, ARITH_MOV, ! 1463: args[0], 0, args[0], SHIFT_IMM_ASR(16)); ! 1464: break; ! 1465: ! 1466: default: ! 1467: tcg_abort(); ! 1468: } ! 1469: } ! 1470: ! 1471: static const TCGTargetOpDef arm_op_defs[] = { ! 1472: { INDEX_op_exit_tb, { } }, ! 1473: { INDEX_op_goto_tb, { } }, ! 1474: { INDEX_op_call, { "ri" } }, ! 1475: { INDEX_op_jmp, { "ri" } }, ! 1476: { INDEX_op_br, { } }, ! 1477: ! 1478: { INDEX_op_mov_i32, { "r", "r" } }, ! 1479: { INDEX_op_movi_i32, { "r" } }, ! 1480: ! 1481: { INDEX_op_ld8u_i32, { "r", "r" } }, ! 1482: { INDEX_op_ld8s_i32, { "r", "r" } }, ! 1483: { INDEX_op_ld16u_i32, { "r", "r" } }, ! 1484: { INDEX_op_ld16s_i32, { "r", "r" } }, ! 1485: { INDEX_op_ld_i32, { "r", "r" } }, ! 1486: { INDEX_op_st8_i32, { "r", "r" } }, ! 1487: { INDEX_op_st16_i32, { "r", "r" } }, ! 1488: { INDEX_op_st_i32, { "r", "r" } }, ! 1489: ! 1490: /* TODO: "r", "r", "ri" */ ! 1491: { INDEX_op_add_i32, { "r", "r", "r" } }, ! 1492: { INDEX_op_sub_i32, { "r", "r", "r" } }, ! 1493: { INDEX_op_mul_i32, { "r", "r", "r" } }, ! 1494: { INDEX_op_mulu2_i32, { "r", "r", "r", "r" } }, ! 1495: { INDEX_op_div2_i32, { "r", "r", "r", "1", "2" } }, ! 1496: { INDEX_op_divu2_i32, { "r", "r", "r", "1", "2" } }, ! 1497: { INDEX_op_and_i32, { "r", "r", "r" } }, ! 1498: { INDEX_op_or_i32, { "r", "r", "r" } }, ! 1499: { INDEX_op_xor_i32, { "r", "r", "r" } }, ! 1500: { INDEX_op_neg_i32, { "r", "r" } }, ! 1501: ! 1502: { INDEX_op_shl_i32, { "r", "r", "ri" } }, ! 1503: { INDEX_op_shr_i32, { "r", "r", "ri" } }, ! 1504: { INDEX_op_sar_i32, { "r", "r", "ri" } }, ! 1505: ! 1506: { INDEX_op_brcond_i32, { "r", "r" } }, ! 1507: ! 1508: /* TODO: "r", "r", "r", "r", "ri", "ri" */ ! 1509: { INDEX_op_add2_i32, { "r", "r", "r", "r", "r", "r" } }, ! 1510: { INDEX_op_sub2_i32, { "r", "r", "r", "r", "r", "r" } }, ! 1511: { INDEX_op_brcond2_i32, { "r", "r", "r", "r" } }, ! 1512: ! 1513: { INDEX_op_qemu_ld8u, { "r", "x", "X" } }, ! 1514: { INDEX_op_qemu_ld8s, { "r", "x", "X" } }, ! 1515: { INDEX_op_qemu_ld16u, { "r", "x", "X" } }, ! 1516: { INDEX_op_qemu_ld16s, { "r", "x", "X" } }, ! 1517: { INDEX_op_qemu_ld32u, { "r", "x", "X" } }, ! 1518: { INDEX_op_qemu_ld64, { "d", "r", "x", "X" } }, ! 1519: ! 1520: { INDEX_op_qemu_st8, { "x", "x", "X" } }, ! 1521: { INDEX_op_qemu_st16, { "x", "x", "X" } }, ! 1522: { INDEX_op_qemu_st32, { "x", "x", "X" } }, ! 1523: { INDEX_op_qemu_st64, { "x", "D", "x", "X" } }, ! 1524: ! 1525: { INDEX_op_ext8s_i32, { "r", "r" } }, ! 1526: { INDEX_op_ext16s_i32, { "r", "r" } }, ! 1527: ! 1528: { -1 }, ! 1529: }; ! 1530: ! 1531: void tcg_target_init(TCGContext *s) ! 1532: { ! 1533: /* fail safe */ ! 1534: if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry)) ! 1535: tcg_abort(); ! 1536: ! 1537: tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, ! 1538: ((2 << TCG_REG_R14) - 1) & ~(1 << TCG_REG_R8)); ! 1539: tcg_regset_set32(tcg_target_call_clobber_regs, 0, ! 1540: ((2 << TCG_REG_R3) - 1) | ! 1541: (1 << TCG_REG_R12) | (1 << TCG_REG_R14)); ! 1542: ! 1543: tcg_regset_clear(s->reserved_regs); ! 1544: #ifdef SAVE_LR ! 1545: tcg_regset_set_reg(s->reserved_regs, TCG_REG_R14); ! 1546: #endif ! 1547: tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK); ! 1548: tcg_regset_set_reg(s->reserved_regs, TCG_REG_R8); ! 1549: ! 1550: tcg_add_target_add_op_defs(arm_op_defs); ! 1551: } ! 1552: ! 1553: static inline void tcg_out_ld(TCGContext *s, TCGType type, int arg, ! 1554: int arg1, tcg_target_long arg2) ! 1555: { ! 1556: tcg_out_ld32u(s, COND_AL, arg, arg1, arg2); ! 1557: } ! 1558: ! 1559: static inline void tcg_out_st(TCGContext *s, TCGType type, int arg, ! 1560: int arg1, tcg_target_long arg2) ! 1561: { ! 1562: tcg_out_st32(s, COND_AL, arg, arg1, arg2); ! 1563: } ! 1564: ! 1565: void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) ! 1566: { ! 1567: if (val > 0) ! 1568: if (val < 0x100) ! 1569: tcg_out_dat_imm(s, COND_AL, ARITH_ADD, reg, reg, val); ! 1570: else ! 1571: tcg_abort(); ! 1572: else if (val < 0) { ! 1573: if (val > -0x100) ! 1574: tcg_out_dat_imm(s, COND_AL, ARITH_SUB, reg, reg, -val); ! 1575: else ! 1576: tcg_abort(); ! 1577: } ! 1578: } ! 1579: ! 1580: static inline void tcg_out_mov(TCGContext *s, int ret, int arg) ! 1581: { ! 1582: tcg_out_dat_reg(s, COND_AL, ARITH_MOV, ret, 0, arg, SHIFT_IMM_LSL(0)); ! 1583: } ! 1584: ! 1585: static inline void tcg_out_movi(TCGContext *s, TCGType type, ! 1586: int ret, tcg_target_long arg) ! 1587: { ! 1588: tcg_out_movi32(s, COND_AL, ret, arg); ! 1589: } ! 1590: ! 1591: void tcg_target_qemu_prologue(TCGContext *s) ! 1592: { ! 1593: /* stmdb sp!, { r9 - r11, lr } */ ! 1594: tcg_out32(s, (COND_AL << 28) | 0x092d4e00); ! 1595: ! 1596: tcg_out_bx(s, COND_AL, TCG_REG_R0); ! 1597: tb_ret_addr = s->code_ptr; ! 1598: ! 1599: /* ldmia sp!, { r9 - r11, pc } */ ! 1600: tcg_out32(s, (COND_AL << 28) | 0x08bd8e00); ! 1601: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.