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