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