|
|
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:
845: static inline void tcg_out_goto(TCGContext *s, int cond, uint32_t addr)
846: {
847: int32_t val;
848:
1.1.1.7 root 849: if (addr & 1) {
850: /* goto to a Thumb destination isn't supported */
851: tcg_abort();
852: }
853:
1.1 root 854: val = addr - (tcg_target_long) s->code_ptr;
855: if (val - 8 < 0x01fffffd && val - 8 > -0x01fffffd)
856: tcg_out_b(s, cond, val);
857: else {
858: #if 1
859: tcg_abort();
860: #else
861: if (cond == COND_AL) {
1.1.1.5 root 862: tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_PC, -4);
1.1 root 863: tcg_out32(s, addr); /* XXX: This is l->u.value, can we use it? */
864: } else {
865: tcg_out_movi32(s, cond, TCG_REG_R8, val - 8);
866: tcg_out_dat_reg(s, cond, ARITH_ADD,
1.1.1.5 root 867: TCG_REG_PC, TCG_REG_PC,
868: TCG_REG_R8, SHIFT_IMM_LSL(0));
1.1 root 869: }
870: #endif
871: }
872: }
873:
1.1.1.7 root 874: static inline void tcg_out_call(TCGContext *s, uint32_t addr)
1.1 root 875: {
876: int32_t val;
877:
878: val = addr - (tcg_target_long) s->code_ptr;
1.1.1.7 root 879: if (val - 8 < 0x02000000 && val - 8 >= -0x02000000) {
880: if (addr & 1) {
881: /* Use BLX if the target is in Thumb mode */
882: if (!use_armv5_instructions) {
883: tcg_abort();
884: }
885: tcg_out_blx_imm(s, val);
886: } else {
887: tcg_out_bl(s, COND_AL, val);
888: }
889: } else {
1.1 root 890: #if 1
891: tcg_abort();
892: #else
893: if (cond == COND_AL) {
1.1.1.5 root 894: tcg_out_dat_imm(s, cond, ARITH_ADD, TCG_REG_R14, TCG_REG_PC, 4);
895: tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_PC, -4);
1.1 root 896: tcg_out32(s, addr); /* XXX: This is l->u.value, can we use it? */
897: } else {
898: tcg_out_movi32(s, cond, TCG_REG_R9, addr);
1.1.1.5 root 899: tcg_out_dat_reg(s, cond, ARITH_MOV, TCG_REG_R14, 0,
900: TCG_REG_PC, SHIFT_IMM_LSL(0));
1.1 root 901: tcg_out_bx(s, cond, TCG_REG_R9);
902: }
903: #endif
904: }
905: }
906:
907: static inline void tcg_out_callr(TCGContext *s, int cond, int arg)
908: {
1.1.1.5 root 909: if (use_armv5_instructions) {
910: tcg_out_blx(s, cond, arg);
911: } else {
912: tcg_out_dat_reg(s, cond, ARITH_MOV, TCG_REG_R14, 0,
913: TCG_REG_PC, SHIFT_IMM_LSL(0));
914: tcg_out_bx(s, cond, arg);
915: }
1.1 root 916: }
917:
918: static inline void tcg_out_goto_label(TCGContext *s, int cond, int label_index)
919: {
920: TCGLabel *l = &s->labels[label_index];
921:
922: if (l->has_value)
923: tcg_out_goto(s, cond, l->u.value);
924: else if (cond == COND_AL) {
1.1.1.5 root 925: tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_PC, -4);
1.1 root 926: tcg_out_reloc(s, s->code_ptr, R_ARM_ABS32, label_index, 31337);
927: s->code_ptr += 4;
928: } else {
929: /* Probably this should be preferred even for COND_AL... */
930: tcg_out_reloc(s, s->code_ptr, R_ARM_PC24, label_index, 31337);
931: tcg_out_b_noaddr(s, cond);
932: }
933: }
934:
935: #ifdef CONFIG_SOFTMMU
936:
937: #include "../../softmmu_defs.h"
938:
939: static void *qemu_ld_helpers[4] = {
940: __ldb_mmu,
941: __ldw_mmu,
942: __ldl_mmu,
943: __ldq_mmu,
944: };
945:
946: static void *qemu_st_helpers[4] = {
947: __stb_mmu,
948: __stw_mmu,
949: __stl_mmu,
950: __stq_mmu,
951: };
952: #endif
953:
954: #define TLB_SHIFT (CPU_TLB_ENTRY_BITS + CPU_TLB_BITS)
955:
1.1.1.5 root 956: static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
1.1 root 957: {
1.1.1.5 root 958: int addr_reg, data_reg, data_reg2, bswap;
1.1 root 959: #ifdef CONFIG_SOFTMMU
960: int mem_index, s_bits;
961: # if TARGET_LONG_BITS == 64
962: int addr_reg2;
963: # endif
964: uint32_t *label_ptr;
965: #endif
966:
1.1.1.5 root 967: #ifdef TARGET_WORDS_BIGENDIAN
968: bswap = 1;
969: #else
970: bswap = 0;
971: #endif
1.1 root 972: data_reg = *args++;
973: if (opc == 3)
974: data_reg2 = *args++;
975: else
1.1.1.3 root 976: data_reg2 = 0; /* suppress warning */
1.1 root 977: addr_reg = *args++;
978: #ifdef CONFIG_SOFTMMU
979: # if TARGET_LONG_BITS == 64
980: addr_reg2 = *args++;
981: # endif
982: mem_index = *args;
983: s_bits = opc & 3;
984:
985: /* Should generate something like the following:
986: * shr r8, addr_reg, #TARGET_PAGE_BITS
987: * and r0, r8, #(CPU_TLB_SIZE - 1) @ Assumption: CPU_TLB_BITS <= 8
988: * add r0, env, r0 lsl #CPU_TLB_ENTRY_BITS
989: */
990: # if CPU_TLB_BITS > 8
991: # error
992: # endif
1.1.1.5 root 993: tcg_out_dat_reg(s, COND_AL, ARITH_MOV, TCG_REG_R8,
994: 0, addr_reg, SHIFT_IMM_LSR(TARGET_PAGE_BITS));
1.1 root 995: tcg_out_dat_imm(s, COND_AL, ARITH_AND,
1.1.1.5 root 996: TCG_REG_R0, TCG_REG_R8, CPU_TLB_SIZE - 1);
997: tcg_out_dat_reg(s, COND_AL, ARITH_ADD, TCG_REG_R0, TCG_AREG0,
998: TCG_REG_R0, SHIFT_IMM_LSL(CPU_TLB_ENTRY_BITS));
1.1 root 999: /* In the
1000: * ldr r1 [r0, #(offsetof(CPUState, tlb_table[mem_index][0].addr_read))]
1001: * below, the offset is likely to exceed 12 bits if mem_index != 0 and
1002: * not exceed otherwise, so use an
1003: * add r0, r0, #(mem_index * sizeof *CPUState.tlb_table)
1004: * before.
1005: */
1006: if (mem_index)
1.1.1.5 root 1007: tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R0, TCG_REG_R0,
1.1 root 1008: (mem_index << (TLB_SHIFT & 1)) |
1009: ((16 - (TLB_SHIFT >> 1)) << 8));
1.1.1.5 root 1010: tcg_out_ld32_12(s, COND_AL, TCG_REG_R1, TCG_REG_R0,
1.1 root 1011: offsetof(CPUState, tlb_table[0][0].addr_read));
1.1.1.5 root 1012: tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, TCG_REG_R1,
1013: TCG_REG_R8, SHIFT_IMM_LSL(TARGET_PAGE_BITS));
1.1 root 1014: /* Check alignment. */
1015: if (s_bits)
1016: tcg_out_dat_imm(s, COND_EQ, ARITH_TST,
1017: 0, addr_reg, (1 << s_bits) - 1);
1018: # if TARGET_LONG_BITS == 64
1019: /* XXX: possibly we could use a block data load or writeback in
1020: * the first access. */
1.1.1.5 root 1021: tcg_out_ld32_12(s, COND_EQ, TCG_REG_R1, TCG_REG_R0,
1.1 root 1022: offsetof(CPUState, tlb_table[0][0].addr_read) + 4);
1.1.1.5 root 1023: tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0,
1024: TCG_REG_R1, addr_reg2, SHIFT_IMM_LSL(0));
1.1 root 1025: # endif
1.1.1.5 root 1026: tcg_out_ld32_12(s, COND_EQ, TCG_REG_R1, TCG_REG_R0,
1.1 root 1027: offsetof(CPUState, tlb_table[0][0].addend));
1028:
1029: switch (opc) {
1030: case 0:
1.1.1.5 root 1031: tcg_out_ld8_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
1.1 root 1032: break;
1033: case 0 | 4:
1.1.1.5 root 1034: tcg_out_ld8s_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
1.1 root 1035: break;
1036: case 1:
1.1.1.5 root 1037: tcg_out_ld16u_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
1038: if (bswap) {
1039: tcg_out_bswap16(s, COND_EQ, data_reg, data_reg);
1040: }
1.1 root 1041: break;
1042: case 1 | 4:
1.1.1.5 root 1043: if (bswap) {
1044: tcg_out_ld16u_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
1045: tcg_out_bswap16s(s, COND_EQ, data_reg, data_reg);
1046: } else {
1047: tcg_out_ld16s_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
1048: }
1.1 root 1049: break;
1050: case 2:
1051: default:
1.1.1.5 root 1052: tcg_out_ld32_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
1053: if (bswap) {
1054: tcg_out_bswap32(s, COND_EQ, data_reg, data_reg);
1055: }
1.1 root 1056: break;
1057: case 3:
1.1.1.5 root 1058: if (bswap) {
1059: tcg_out_ld32_rwb(s, COND_EQ, data_reg2, TCG_REG_R1, addr_reg);
1060: tcg_out_ld32_12(s, COND_EQ, data_reg, TCG_REG_R1, 4);
1061: tcg_out_bswap32(s, COND_EQ, data_reg2, data_reg2);
1062: tcg_out_bswap32(s, COND_EQ, data_reg, data_reg);
1063: } else {
1064: tcg_out_ld32_rwb(s, COND_EQ, data_reg, TCG_REG_R1, addr_reg);
1065: tcg_out_ld32_12(s, COND_EQ, data_reg2, TCG_REG_R1, 4);
1066: }
1.1 root 1067: break;
1068: }
1069:
1070: label_ptr = (void *) s->code_ptr;
1.1.1.6 root 1071: tcg_out_b_noaddr(s, COND_EQ);
1.1 root 1072:
1073: /* TODO: move this code to where the constants pool will be */
1.1.1.5 root 1074: if (addr_reg != TCG_REG_R0) {
1075: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1076: TCG_REG_R0, 0, addr_reg, SHIFT_IMM_LSL(0));
1077: }
1.1 root 1078: # if TARGET_LONG_BITS == 32
1.1.1.5 root 1079: tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R1, 0, mem_index);
1.1 root 1080: # else
1.1.1.5 root 1081: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1082: TCG_REG_R1, 0, addr_reg2, SHIFT_IMM_LSL(0));
1083: tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
1.1 root 1084: # endif
1.1.1.7 root 1085: tcg_out_call(s, (tcg_target_long) qemu_ld_helpers[s_bits]);
1.1 root 1086:
1087: switch (opc) {
1088: case 0 | 4:
1.1.1.5 root 1089: tcg_out_ext8s(s, COND_AL, data_reg, TCG_REG_R0);
1.1 root 1090: break;
1091: case 1 | 4:
1.1.1.5 root 1092: tcg_out_ext16s(s, COND_AL, data_reg, TCG_REG_R0);
1.1 root 1093: break;
1094: case 0:
1095: case 1:
1096: case 2:
1097: default:
1.1.1.5 root 1098: if (data_reg != TCG_REG_R0) {
1099: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1100: data_reg, 0, TCG_REG_R0, SHIFT_IMM_LSL(0));
1101: }
1.1 root 1102: break;
1103: case 3:
1.1.1.5 root 1104: if (data_reg != TCG_REG_R0) {
1105: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1106: data_reg, 0, TCG_REG_R0, SHIFT_IMM_LSL(0));
1107: }
1108: if (data_reg2 != TCG_REG_R1) {
1109: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1110: data_reg2, 0, TCG_REG_R1, SHIFT_IMM_LSL(0));
1111: }
1.1 root 1112: break;
1113: }
1114:
1.1.1.6 root 1115: reloc_pc24(label_ptr, (tcg_target_long)s->code_ptr);
1.1.1.3 root 1116: #else /* !CONFIG_SOFTMMU */
1117: if (GUEST_BASE) {
1118: uint32_t offset = GUEST_BASE;
1119: int i;
1120: int rot;
1121:
1122: while (offset) {
1123: i = ctz32(offset) & ~1;
1124: rot = ((32 - i) << 7) & 0xf00;
1125:
1.1.1.5 root 1126: tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R8, addr_reg,
1.1.1.3 root 1127: ((offset >> i) & 0xff) | rot);
1.1.1.5 root 1128: addr_reg = TCG_REG_R8;
1.1.1.3 root 1129: offset &= ~(0xff << i);
1130: }
1131: }
1.1 root 1132: switch (opc) {
1133: case 0:
1134: tcg_out_ld8_12(s, COND_AL, data_reg, addr_reg, 0);
1135: break;
1136: case 0 | 4:
1137: tcg_out_ld8s_8(s, COND_AL, data_reg, addr_reg, 0);
1138: break;
1139: case 1:
1140: tcg_out_ld16u_8(s, COND_AL, data_reg, addr_reg, 0);
1.1.1.5 root 1141: if (bswap) {
1142: tcg_out_bswap16(s, COND_AL, data_reg, data_reg);
1143: }
1.1 root 1144: break;
1145: case 1 | 4:
1.1.1.5 root 1146: if (bswap) {
1147: tcg_out_ld16u_8(s, COND_AL, data_reg, addr_reg, 0);
1148: tcg_out_bswap16s(s, COND_AL, data_reg, data_reg);
1149: } else {
1150: tcg_out_ld16s_8(s, COND_AL, data_reg, addr_reg, 0);
1151: }
1.1 root 1152: break;
1153: case 2:
1154: default:
1155: tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, 0);
1.1.1.5 root 1156: if (bswap) {
1157: tcg_out_bswap32(s, COND_AL, data_reg, data_reg);
1158: }
1.1 root 1159: break;
1160: case 3:
1161: /* TODO: use block load -
1162: * check that data_reg2 > data_reg or the other way */
1.1.1.2 root 1163: if (data_reg == addr_reg) {
1.1.1.5 root 1164: tcg_out_ld32_12(s, COND_AL, data_reg2, addr_reg, bswap ? 0 : 4);
1165: tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, bswap ? 4 : 0);
1.1.1.2 root 1166: } else {
1.1.1.5 root 1167: tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, bswap ? 4 : 0);
1168: tcg_out_ld32_12(s, COND_AL, data_reg2, addr_reg, bswap ? 0 : 4);
1169: }
1170: if (bswap) {
1171: tcg_out_bswap32(s, COND_AL, data_reg, data_reg);
1172: tcg_out_bswap32(s, COND_AL, data_reg2, data_reg2);
1.1.1.2 root 1173: }
1.1 root 1174: break;
1175: }
1176: #endif
1177: }
1178:
1.1.1.5 root 1179: static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
1.1 root 1180: {
1.1.1.5 root 1181: int addr_reg, data_reg, data_reg2, bswap;
1.1 root 1182: #ifdef CONFIG_SOFTMMU
1183: int mem_index, s_bits;
1184: # if TARGET_LONG_BITS == 64
1185: int addr_reg2;
1186: # endif
1187: uint32_t *label_ptr;
1188: #endif
1189:
1.1.1.5 root 1190: #ifdef TARGET_WORDS_BIGENDIAN
1191: bswap = 1;
1192: #else
1193: bswap = 0;
1194: #endif
1.1 root 1195: data_reg = *args++;
1196: if (opc == 3)
1197: data_reg2 = *args++;
1198: else
1.1.1.3 root 1199: data_reg2 = 0; /* suppress warning */
1.1 root 1200: addr_reg = *args++;
1201: #ifdef CONFIG_SOFTMMU
1202: # if TARGET_LONG_BITS == 64
1203: addr_reg2 = *args++;
1204: # endif
1205: mem_index = *args;
1206: s_bits = opc & 3;
1207:
1208: /* Should generate something like the following:
1209: * shr r8, addr_reg, #TARGET_PAGE_BITS
1210: * and r0, r8, #(CPU_TLB_SIZE - 1) @ Assumption: CPU_TLB_BITS <= 8
1211: * add r0, env, r0 lsl #CPU_TLB_ENTRY_BITS
1212: */
1213: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1.1.1.5 root 1214: TCG_REG_R8, 0, addr_reg, SHIFT_IMM_LSR(TARGET_PAGE_BITS));
1.1 root 1215: tcg_out_dat_imm(s, COND_AL, ARITH_AND,
1.1.1.5 root 1216: TCG_REG_R0, TCG_REG_R8, CPU_TLB_SIZE - 1);
1217: tcg_out_dat_reg(s, COND_AL, ARITH_ADD, TCG_REG_R0,
1218: TCG_AREG0, TCG_REG_R0, SHIFT_IMM_LSL(CPU_TLB_ENTRY_BITS));
1.1 root 1219: /* In the
1220: * ldr r1 [r0, #(offsetof(CPUState, tlb_table[mem_index][0].addr_write))]
1221: * below, the offset is likely to exceed 12 bits if mem_index != 0 and
1222: * not exceed otherwise, so use an
1223: * add r0, r0, #(mem_index * sizeof *CPUState.tlb_table)
1224: * before.
1225: */
1226: if (mem_index)
1.1.1.5 root 1227: tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R0, TCG_REG_R0,
1.1 root 1228: (mem_index << (TLB_SHIFT & 1)) |
1229: ((16 - (TLB_SHIFT >> 1)) << 8));
1.1.1.5 root 1230: tcg_out_ld32_12(s, COND_AL, TCG_REG_R1, TCG_REG_R0,
1.1 root 1231: offsetof(CPUState, tlb_table[0][0].addr_write));
1.1.1.5 root 1232: tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, TCG_REG_R1,
1233: TCG_REG_R8, SHIFT_IMM_LSL(TARGET_PAGE_BITS));
1.1 root 1234: /* Check alignment. */
1235: if (s_bits)
1236: tcg_out_dat_imm(s, COND_EQ, ARITH_TST,
1237: 0, addr_reg, (1 << s_bits) - 1);
1238: # if TARGET_LONG_BITS == 64
1239: /* XXX: possibly we could use a block data load or writeback in
1240: * the first access. */
1.1.1.5 root 1241: tcg_out_ld32_12(s, COND_EQ, TCG_REG_R1, TCG_REG_R0,
1242: offsetof(CPUState, tlb_table[0][0].addr_write) + 4);
1243: tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0,
1244: TCG_REG_R1, addr_reg2, SHIFT_IMM_LSL(0));
1.1 root 1245: # endif
1.1.1.5 root 1246: tcg_out_ld32_12(s, COND_EQ, TCG_REG_R1, TCG_REG_R0,
1.1 root 1247: offsetof(CPUState, tlb_table[0][0].addend));
1248:
1249: switch (opc) {
1250: case 0:
1.1.1.5 root 1251: tcg_out_st8_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
1.1 root 1252: break;
1253: case 1:
1.1.1.5 root 1254: if (bswap) {
1255: tcg_out_bswap16(s, COND_EQ, TCG_REG_R0, data_reg);
1256: tcg_out_st16_r(s, COND_EQ, TCG_REG_R0, addr_reg, TCG_REG_R1);
1257: } else {
1258: tcg_out_st16_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
1259: }
1.1 root 1260: break;
1261: case 2:
1262: default:
1.1.1.5 root 1263: if (bswap) {
1264: tcg_out_bswap32(s, COND_EQ, TCG_REG_R0, data_reg);
1265: tcg_out_st32_r(s, COND_EQ, TCG_REG_R0, addr_reg, TCG_REG_R1);
1266: } else {
1267: tcg_out_st32_r(s, COND_EQ, data_reg, addr_reg, TCG_REG_R1);
1268: }
1.1 root 1269: break;
1270: case 3:
1.1.1.5 root 1271: if (bswap) {
1272: tcg_out_bswap32(s, COND_EQ, TCG_REG_R0, data_reg2);
1273: tcg_out_st32_rwb(s, COND_EQ, TCG_REG_R0, TCG_REG_R1, addr_reg);
1274: tcg_out_bswap32(s, COND_EQ, TCG_REG_R0, data_reg);
1.1.1.6 root 1275: tcg_out_st32_12(s, COND_EQ, TCG_REG_R0, TCG_REG_R1, 4);
1.1.1.5 root 1276: } else {
1277: tcg_out_st32_rwb(s, COND_EQ, data_reg, TCG_REG_R1, addr_reg);
1278: tcg_out_st32_12(s, COND_EQ, data_reg2, TCG_REG_R1, 4);
1279: }
1.1 root 1280: break;
1281: }
1282:
1283: label_ptr = (void *) s->code_ptr;
1.1.1.6 root 1284: tcg_out_b_noaddr(s, COND_EQ);
1.1 root 1285:
1286: /* TODO: move this code to where the constants pool will be */
1.1.1.5 root 1287: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1288: TCG_REG_R0, 0, addr_reg, SHIFT_IMM_LSL(0));
1.1 root 1289: # if TARGET_LONG_BITS == 32
1290: switch (opc) {
1291: case 0:
1.1.1.5 root 1292: tcg_out_ext8u(s, COND_AL, TCG_REG_R1, data_reg);
1293: tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
1.1 root 1294: break;
1295: case 1:
1.1.1.5 root 1296: tcg_out_ext16u(s, COND_AL, TCG_REG_R1, data_reg);
1297: tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
1.1 root 1298: break;
1299: case 2:
1.1.1.5 root 1300: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1301: TCG_REG_R1, 0, data_reg, SHIFT_IMM_LSL(0));
1302: tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
1.1 root 1303: break;
1304: case 3:
1.1.1.5 root 1305: tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R8, 0, mem_index);
1306: tcg_out32(s, (COND_AL << 28) | 0x052d8010); /* str r8, [sp, #-0x10]! */
1307: if (data_reg != TCG_REG_R2) {
1308: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1309: TCG_REG_R2, 0, data_reg, SHIFT_IMM_LSL(0));
1310: }
1311: if (data_reg2 != TCG_REG_R3) {
1312: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1313: TCG_REG_R3, 0, data_reg2, SHIFT_IMM_LSL(0));
1314: }
1.1 root 1315: break;
1316: }
1317: # else
1.1.1.5 root 1318: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1319: TCG_REG_R1, 0, addr_reg2, SHIFT_IMM_LSL(0));
1.1 root 1320: switch (opc) {
1321: case 0:
1.1.1.5 root 1322: tcg_out_ext8u(s, COND_AL, TCG_REG_R2, data_reg);
1323: tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R3, 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_R2, data_reg);
1327: tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R3, 0, mem_index);
1.1 root 1328: break;
1329: case 2:
1.1.1.5 root 1330: if (data_reg != TCG_REG_R2) {
1331: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1332: TCG_REG_R2, 0, data_reg, SHIFT_IMM_LSL(0));
1333: }
1334: tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R3, 0, mem_index);
1.1 root 1335: break;
1336: case 3:
1.1.1.5 root 1337: tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R8, 0, mem_index);
1338: tcg_out32(s, (COND_AL << 28) | 0x052d8010); /* str r8, [sp, #-0x10]! */
1339: if (data_reg != TCG_REG_R2) {
1340: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1341: TCG_REG_R2, 0, data_reg, SHIFT_IMM_LSL(0));
1342: }
1343: if (data_reg2 != TCG_REG_R3) {
1344: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1345: TCG_REG_R3, 0, data_reg2, SHIFT_IMM_LSL(0));
1346: }
1.1 root 1347: break;
1348: }
1349: # endif
1350:
1.1.1.7 root 1351: tcg_out_call(s, (tcg_target_long) qemu_st_helpers[s_bits]);
1.1 root 1352: if (opc == 3)
1.1.1.5 root 1353: tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R13, TCG_REG_R13, 0x10);
1.1 root 1354:
1.1.1.6 root 1355: reloc_pc24(label_ptr, (tcg_target_long)s->code_ptr);
1.1.1.3 root 1356: #else /* !CONFIG_SOFTMMU */
1357: if (GUEST_BASE) {
1358: uint32_t offset = GUEST_BASE;
1359: int i;
1360: int rot;
1361:
1362: while (offset) {
1363: i = ctz32(offset) & ~1;
1364: rot = ((32 - i) << 7) & 0xf00;
1365:
1.1.1.5 root 1366: tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R1, addr_reg,
1.1.1.3 root 1367: ((offset >> i) & 0xff) | rot);
1.1.1.5 root 1368: addr_reg = TCG_REG_R1;
1.1.1.3 root 1369: offset &= ~(0xff << i);
1370: }
1371: }
1.1 root 1372: switch (opc) {
1373: case 0:
1374: tcg_out_st8_12(s, COND_AL, data_reg, addr_reg, 0);
1375: break;
1376: case 1:
1.1.1.5 root 1377: if (bswap) {
1378: tcg_out_bswap16(s, COND_AL, TCG_REG_R0, data_reg);
1379: tcg_out_st16_8(s, COND_AL, TCG_REG_R0, addr_reg, 0);
1380: } else {
1381: tcg_out_st16_8(s, COND_AL, data_reg, addr_reg, 0);
1382: }
1.1 root 1383: break;
1384: case 2:
1385: default:
1.1.1.5 root 1386: if (bswap) {
1387: tcg_out_bswap32(s, COND_AL, TCG_REG_R0, data_reg);
1388: tcg_out_st32_12(s, COND_AL, TCG_REG_R0, addr_reg, 0);
1389: } else {
1390: tcg_out_st32_12(s, COND_AL, data_reg, addr_reg, 0);
1391: }
1.1 root 1392: break;
1393: case 3:
1394: /* TODO: use block store -
1395: * check that data_reg2 > data_reg or the other way */
1.1.1.5 root 1396: if (bswap) {
1397: tcg_out_bswap32(s, COND_AL, TCG_REG_R0, data_reg2);
1398: tcg_out_st32_12(s, COND_AL, TCG_REG_R0, addr_reg, 0);
1399: tcg_out_bswap32(s, COND_AL, TCG_REG_R0, data_reg);
1400: tcg_out_st32_12(s, COND_AL, TCG_REG_R0, addr_reg, 4);
1401: } else {
1402: tcg_out_st32_12(s, COND_AL, data_reg, addr_reg, 0);
1403: tcg_out_st32_12(s, COND_AL, data_reg2, addr_reg, 4);
1404: }
1.1 root 1405: break;
1406: }
1407: #endif
1408: }
1409:
1410: static uint8_t *tb_ret_addr;
1411:
1.1.1.5 root 1412: static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
1.1 root 1413: const TCGArg *args, const int *const_args)
1414: {
1415: int c;
1416:
1417: switch (opc) {
1418: case INDEX_op_exit_tb:
1419: {
1420: uint8_t *ld_ptr = s->code_ptr;
1421: if (args[0] >> 8)
1.1.1.5 root 1422: tcg_out_ld32_12(s, COND_AL, TCG_REG_R0, TCG_REG_PC, 0);
1.1 root 1423: else
1.1.1.5 root 1424: tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R0, 0, args[0]);
1.1 root 1425: tcg_out_goto(s, COND_AL, (tcg_target_ulong) tb_ret_addr);
1426: if (args[0] >> 8) {
1427: *ld_ptr = (uint8_t) (s->code_ptr - ld_ptr) - 8;
1428: tcg_out32(s, args[0]);
1429: }
1430: }
1431: break;
1432: case INDEX_op_goto_tb:
1433: if (s->tb_jmp_offset) {
1434: /* Direct jump method */
1435: #if defined(USE_DIRECT_JUMP)
1436: s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
1.1.1.6 root 1437: tcg_out_b_noaddr(s, COND_AL);
1.1 root 1438: #else
1.1.1.5 root 1439: tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_PC, -4);
1.1 root 1440: s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
1441: tcg_out32(s, 0);
1442: #endif
1443: } else {
1444: /* Indirect jump method */
1445: #if 1
1446: c = (int) (s->tb_next + args[0]) - ((int) s->code_ptr + 8);
1447: if (c > 0xfff || c < -0xfff) {
1448: tcg_out_movi32(s, COND_AL, TCG_REG_R0,
1449: (tcg_target_long) (s->tb_next + args[0]));
1.1.1.5 root 1450: tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_R0, 0);
1.1 root 1451: } else
1.1.1.5 root 1452: tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_PC, c);
1.1 root 1453: #else
1.1.1.5 root 1454: tcg_out_ld32_12(s, COND_AL, TCG_REG_R0, TCG_REG_PC, 0);
1455: tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, TCG_REG_R0, 0);
1.1 root 1456: tcg_out32(s, (tcg_target_long) (s->tb_next + args[0]));
1457: #endif
1458: }
1459: s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
1460: break;
1461: case INDEX_op_call:
1462: if (const_args[0])
1.1.1.7 root 1463: tcg_out_call(s, args[0]);
1.1 root 1464: else
1465: tcg_out_callr(s, COND_AL, args[0]);
1466: break;
1467: case INDEX_op_jmp:
1468: if (const_args[0])
1469: tcg_out_goto(s, COND_AL, args[0]);
1470: else
1471: tcg_out_bx(s, COND_AL, args[0]);
1472: break;
1473: case INDEX_op_br:
1474: tcg_out_goto_label(s, COND_AL, args[0]);
1475: break;
1476:
1477: case INDEX_op_ld8u_i32:
1478: tcg_out_ld8u(s, COND_AL, args[0], args[1], args[2]);
1479: break;
1480: case INDEX_op_ld8s_i32:
1481: tcg_out_ld8s(s, COND_AL, args[0], args[1], args[2]);
1482: break;
1483: case INDEX_op_ld16u_i32:
1484: tcg_out_ld16u(s, COND_AL, args[0], args[1], args[2]);
1485: break;
1486: case INDEX_op_ld16s_i32:
1487: tcg_out_ld16s(s, COND_AL, args[0], args[1], args[2]);
1488: break;
1489: case INDEX_op_ld_i32:
1490: tcg_out_ld32u(s, COND_AL, args[0], args[1], args[2]);
1491: break;
1492: case INDEX_op_st8_i32:
1.1.1.5 root 1493: tcg_out_st8(s, COND_AL, args[0], args[1], args[2]);
1.1 root 1494: break;
1495: case INDEX_op_st16_i32:
1.1.1.5 root 1496: tcg_out_st16(s, COND_AL, args[0], args[1], args[2]);
1.1 root 1497: break;
1498: case INDEX_op_st_i32:
1499: tcg_out_st32(s, COND_AL, args[0], args[1], args[2]);
1500: break;
1501:
1502: case INDEX_op_mov_i32:
1503: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1504: args[0], 0, args[1], SHIFT_IMM_LSL(0));
1505: break;
1506: case INDEX_op_movi_i32:
1507: tcg_out_movi32(s, COND_AL, args[0], args[1]);
1508: break;
1509: case INDEX_op_add_i32:
1510: c = ARITH_ADD;
1511: goto gen_arith;
1512: case INDEX_op_sub_i32:
1513: c = ARITH_SUB;
1514: goto gen_arith;
1515: case INDEX_op_and_i32:
1516: c = ARITH_AND;
1517: goto gen_arith;
1.1.1.5 root 1518: case INDEX_op_andc_i32:
1519: c = ARITH_BIC;
1520: goto gen_arith;
1.1 root 1521: case INDEX_op_or_i32:
1522: c = ARITH_ORR;
1523: goto gen_arith;
1524: case INDEX_op_xor_i32:
1525: c = ARITH_EOR;
1526: /* Fall through. */
1527: gen_arith:
1.1.1.3 root 1528: if (const_args[2]) {
1529: int rot;
1530: rot = encode_imm(args[2]);
1531: tcg_out_dat_imm(s, COND_AL, c,
1532: args[0], args[1], rotl(args[2], rot) | (rot << 7));
1533: } else
1534: tcg_out_dat_reg(s, COND_AL, c,
1535: args[0], args[1], args[2], SHIFT_IMM_LSL(0));
1.1 root 1536: break;
1537: case INDEX_op_add2_i32:
1538: tcg_out_dat_reg2(s, COND_AL, ARITH_ADD, ARITH_ADC,
1539: args[0], args[1], args[2], args[3],
1540: args[4], args[5], SHIFT_IMM_LSL(0));
1541: break;
1542: case INDEX_op_sub2_i32:
1543: tcg_out_dat_reg2(s, COND_AL, ARITH_SUB, ARITH_SBC,
1544: args[0], args[1], args[2], args[3],
1545: args[4], args[5], SHIFT_IMM_LSL(0));
1546: break;
1547: case INDEX_op_neg_i32:
1548: tcg_out_dat_imm(s, COND_AL, ARITH_RSB, args[0], args[1], 0);
1549: break;
1.1.1.3 root 1550: case INDEX_op_not_i32:
1551: tcg_out_dat_reg(s, COND_AL,
1552: ARITH_MVN, args[0], 0, args[1], SHIFT_IMM_LSL(0));
1553: break;
1.1 root 1554: case INDEX_op_mul_i32:
1555: tcg_out_mul32(s, COND_AL, args[0], args[1], args[2]);
1556: break;
1557: case INDEX_op_mulu2_i32:
1558: tcg_out_umull32(s, COND_AL, args[0], args[1], args[2], args[3]);
1559: break;
1560: /* XXX: Perhaps args[2] & 0x1f is wrong */
1561: case INDEX_op_shl_i32:
1562: c = const_args[2] ?
1563: SHIFT_IMM_LSL(args[2] & 0x1f) : SHIFT_REG_LSL(args[2]);
1564: goto gen_shift32;
1565: case INDEX_op_shr_i32:
1566: c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_LSR(args[2] & 0x1f) :
1567: SHIFT_IMM_LSL(0) : SHIFT_REG_LSR(args[2]);
1568: goto gen_shift32;
1569: case INDEX_op_sar_i32:
1570: c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_ASR(args[2] & 0x1f) :
1571: SHIFT_IMM_LSL(0) : SHIFT_REG_ASR(args[2]);
1.1.1.5 root 1572: goto gen_shift32;
1573: case INDEX_op_rotr_i32:
1574: c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_ROR(args[2] & 0x1f) :
1575: SHIFT_IMM_LSL(0) : SHIFT_REG_ROR(args[2]);
1.1 root 1576: /* Fall through. */
1577: gen_shift32:
1578: tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1], c);
1579: break;
1580:
1.1.1.5 root 1581: case INDEX_op_rotl_i32:
1582: if (const_args[2]) {
1583: tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1],
1584: ((0x20 - args[2]) & 0x1f) ?
1585: SHIFT_IMM_ROR((0x20 - args[2]) & 0x1f) :
1586: SHIFT_IMM_LSL(0));
1587: } else {
1588: tcg_out_dat_imm(s, COND_AL, ARITH_RSB, TCG_REG_R8, args[1], 0x20);
1589: tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1],
1590: SHIFT_REG_ROR(TCG_REG_R8));
1591: }
1592: break;
1593:
1.1 root 1594: case INDEX_op_brcond_i32:
1.1.1.5 root 1595: if (const_args[1]) {
1596: int rot;
1597: rot = encode_imm(args[1]);
1598: tcg_out_dat_imm(s, COND_AL, ARITH_CMP, 0,
1599: args[0], rotl(args[1], rot) | (rot << 7));
1600: } else {
1601: tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0,
1602: args[0], args[1], SHIFT_IMM_LSL(0));
1603: }
1.1 root 1604: tcg_out_goto_label(s, tcg_cond_to_arm_cond[args[2]], args[3]);
1605: break;
1606: case INDEX_op_brcond2_i32:
1607: /* The resulting conditions are:
1608: * TCG_COND_EQ --> a0 == a2 && a1 == a3,
1609: * TCG_COND_NE --> (a0 != a2 && a1 == a3) || a1 != a3,
1610: * TCG_COND_LT(U) --> (a0 < a2 && a1 == a3) || a1 < a3,
1611: * TCG_COND_GE(U) --> (a0 >= a2 && a1 == a3) || (a1 >= a3 && a1 != a3),
1612: * TCG_COND_LE(U) --> (a0 <= a2 && a1 == a3) || (a1 <= a3 && a1 != a3),
1613: * TCG_COND_GT(U) --> (a0 > a2 && a1 == a3) || a1 > a3,
1614: */
1615: tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0,
1616: args[1], args[3], SHIFT_IMM_LSL(0));
1617: tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0,
1618: args[0], args[2], SHIFT_IMM_LSL(0));
1619: tcg_out_goto_label(s, tcg_cond_to_arm_cond[args[4]], args[5]);
1620: break;
1.1.1.5 root 1621: case INDEX_op_setcond_i32:
1622: if (const_args[2]) {
1623: int rot;
1624: rot = encode_imm(args[2]);
1625: tcg_out_dat_imm(s, COND_AL, ARITH_CMP, 0,
1626: args[1], rotl(args[2], rot) | (rot << 7));
1627: } else {
1628: tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0,
1629: args[1], args[2], SHIFT_IMM_LSL(0));
1630: }
1631: tcg_out_dat_imm(s, tcg_cond_to_arm_cond[args[3]],
1632: ARITH_MOV, args[0], 0, 1);
1633: tcg_out_dat_imm(s, tcg_cond_to_arm_cond[tcg_invert_cond(args[3])],
1634: ARITH_MOV, args[0], 0, 0);
1635: break;
1636: case INDEX_op_setcond2_i32:
1637: /* See brcond2_i32 comment */
1638: tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0,
1639: args[2], args[4], SHIFT_IMM_LSL(0));
1640: tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0,
1641: args[1], args[3], SHIFT_IMM_LSL(0));
1642: tcg_out_dat_imm(s, tcg_cond_to_arm_cond[args[5]],
1643: ARITH_MOV, args[0], 0, 1);
1644: tcg_out_dat_imm(s, tcg_cond_to_arm_cond[tcg_invert_cond(args[5])],
1645: ARITH_MOV, args[0], 0, 0);
1646: break;
1.1 root 1647:
1648: case INDEX_op_qemu_ld8u:
1.1.1.5 root 1649: tcg_out_qemu_ld(s, args, 0);
1.1 root 1650: break;
1651: case INDEX_op_qemu_ld8s:
1.1.1.5 root 1652: tcg_out_qemu_ld(s, args, 0 | 4);
1.1 root 1653: break;
1654: case INDEX_op_qemu_ld16u:
1.1.1.5 root 1655: tcg_out_qemu_ld(s, args, 1);
1.1 root 1656: break;
1657: case INDEX_op_qemu_ld16s:
1.1.1.5 root 1658: tcg_out_qemu_ld(s, args, 1 | 4);
1.1 root 1659: break;
1.1.1.5 root 1660: case INDEX_op_qemu_ld32:
1661: tcg_out_qemu_ld(s, args, 2);
1.1 root 1662: break;
1663: case INDEX_op_qemu_ld64:
1.1.1.5 root 1664: tcg_out_qemu_ld(s, args, 3);
1.1 root 1665: break;
1666:
1667: case INDEX_op_qemu_st8:
1.1.1.5 root 1668: tcg_out_qemu_st(s, args, 0);
1.1 root 1669: break;
1670: case INDEX_op_qemu_st16:
1.1.1.5 root 1671: tcg_out_qemu_st(s, args, 1);
1.1 root 1672: break;
1673: case INDEX_op_qemu_st32:
1.1.1.5 root 1674: tcg_out_qemu_st(s, args, 2);
1.1 root 1675: break;
1676: case INDEX_op_qemu_st64:
1.1.1.5 root 1677: tcg_out_qemu_st(s, args, 3);
1678: break;
1679:
1680: case INDEX_op_bswap16_i32:
1681: tcg_out_bswap16(s, COND_AL, args[0], args[1]);
1682: break;
1683: case INDEX_op_bswap32_i32:
1684: tcg_out_bswap32(s, COND_AL, args[0], args[1]);
1.1 root 1685: break;
1686:
1687: case INDEX_op_ext8s_i32:
1.1.1.5 root 1688: tcg_out_ext8s(s, COND_AL, args[0], args[1]);
1.1 root 1689: break;
1690: case INDEX_op_ext16s_i32:
1.1.1.5 root 1691: tcg_out_ext16s(s, COND_AL, args[0], args[1]);
1692: break;
1693: case INDEX_op_ext16u_i32:
1694: tcg_out_ext16u(s, COND_AL, args[0], args[1]);
1.1 root 1695: break;
1696:
1697: default:
1698: tcg_abort();
1699: }
1700: }
1701:
1702: static const TCGTargetOpDef arm_op_defs[] = {
1703: { INDEX_op_exit_tb, { } },
1704: { INDEX_op_goto_tb, { } },
1705: { INDEX_op_call, { "ri" } },
1706: { INDEX_op_jmp, { "ri" } },
1707: { INDEX_op_br, { } },
1708:
1709: { INDEX_op_mov_i32, { "r", "r" } },
1710: { INDEX_op_movi_i32, { "r" } },
1711:
1712: { INDEX_op_ld8u_i32, { "r", "r" } },
1713: { INDEX_op_ld8s_i32, { "r", "r" } },
1714: { INDEX_op_ld16u_i32, { "r", "r" } },
1715: { INDEX_op_ld16s_i32, { "r", "r" } },
1716: { INDEX_op_ld_i32, { "r", "r" } },
1717: { INDEX_op_st8_i32, { "r", "r" } },
1718: { INDEX_op_st16_i32, { "r", "r" } },
1719: { INDEX_op_st_i32, { "r", "r" } },
1720:
1721: /* TODO: "r", "r", "ri" */
1.1.1.3 root 1722: { INDEX_op_add_i32, { "r", "r", "rI" } },
1723: { INDEX_op_sub_i32, { "r", "r", "rI" } },
1.1 root 1724: { INDEX_op_mul_i32, { "r", "r", "r" } },
1725: { INDEX_op_mulu2_i32, { "r", "r", "r", "r" } },
1.1.1.3 root 1726: { INDEX_op_and_i32, { "r", "r", "rI" } },
1.1.1.5 root 1727: { INDEX_op_andc_i32, { "r", "r", "rI" } },
1.1.1.3 root 1728: { INDEX_op_or_i32, { "r", "r", "rI" } },
1729: { INDEX_op_xor_i32, { "r", "r", "rI" } },
1.1 root 1730: { INDEX_op_neg_i32, { "r", "r" } },
1.1.1.3 root 1731: { INDEX_op_not_i32, { "r", "r" } },
1.1 root 1732:
1733: { INDEX_op_shl_i32, { "r", "r", "ri" } },
1734: { INDEX_op_shr_i32, { "r", "r", "ri" } },
1735: { INDEX_op_sar_i32, { "r", "r", "ri" } },
1.1.1.5 root 1736: { INDEX_op_rotl_i32, { "r", "r", "ri" } },
1737: { INDEX_op_rotr_i32, { "r", "r", "ri" } },
1.1 root 1738:
1.1.1.5 root 1739: { INDEX_op_brcond_i32, { "r", "rI" } },
1740: { INDEX_op_setcond_i32, { "r", "r", "rI" } },
1.1 root 1741:
1742: /* TODO: "r", "r", "r", "r", "ri", "ri" */
1743: { INDEX_op_add2_i32, { "r", "r", "r", "r", "r", "r" } },
1744: { INDEX_op_sub2_i32, { "r", "r", "r", "r", "r", "r" } },
1745: { INDEX_op_brcond2_i32, { "r", "r", "r", "r" } },
1.1.1.5 root 1746: { INDEX_op_setcond2_i32, { "r", "r", "r", "r", "r" } },
1747:
1748: #if TARGET_LONG_BITS == 32
1749: { INDEX_op_qemu_ld8u, { "r", "l" } },
1750: { INDEX_op_qemu_ld8s, { "r", "l" } },
1751: { INDEX_op_qemu_ld16u, { "r", "l" } },
1752: { INDEX_op_qemu_ld16s, { "r", "l" } },
1753: { INDEX_op_qemu_ld32, { "r", "l" } },
1754: { INDEX_op_qemu_ld64, { "L", "L", "l" } },
1755:
1756: { INDEX_op_qemu_st8, { "s", "s" } },
1757: { INDEX_op_qemu_st16, { "s", "s" } },
1758: { INDEX_op_qemu_st32, { "s", "s" } },
1759: { INDEX_op_qemu_st64, { "S", "S", "s" } },
1760: #else
1761: { INDEX_op_qemu_ld8u, { "r", "l", "l" } },
1762: { INDEX_op_qemu_ld8s, { "r", "l", "l" } },
1763: { INDEX_op_qemu_ld16u, { "r", "l", "l" } },
1764: { INDEX_op_qemu_ld16s, { "r", "l", "l" } },
1765: { INDEX_op_qemu_ld32, { "r", "l", "l" } },
1766: { INDEX_op_qemu_ld64, { "L", "L", "l", "l" } },
1767:
1768: { INDEX_op_qemu_st8, { "s", "s", "s" } },
1769: { INDEX_op_qemu_st16, { "s", "s", "s" } },
1770: { INDEX_op_qemu_st32, { "s", "s", "s" } },
1771: { INDEX_op_qemu_st64, { "S", "S", "s", "s" } },
1772: #endif
1.1 root 1773:
1.1.1.5 root 1774: { INDEX_op_bswap16_i32, { "r", "r" } },
1775: { INDEX_op_bswap32_i32, { "r", "r" } },
1.1 root 1776:
1777: { INDEX_op_ext8s_i32, { "r", "r" } },
1778: { INDEX_op_ext16s_i32, { "r", "r" } },
1.1.1.5 root 1779: { INDEX_op_ext16u_i32, { "r", "r" } },
1.1 root 1780:
1781: { -1 },
1782: };
1783:
1.1.1.5 root 1784: static void tcg_target_init(TCGContext *s)
1.1 root 1785: {
1.1.1.5 root 1786: #if !defined(CONFIG_USER_ONLY)
1.1 root 1787: /* fail safe */
1788: if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry))
1789: tcg_abort();
1.1.1.5 root 1790: #endif
1.1 root 1791:
1.1.1.5 root 1792: tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffff);
1.1 root 1793: tcg_regset_set32(tcg_target_call_clobber_regs, 0,
1.1.1.5 root 1794: (1 << TCG_REG_R0) |
1795: (1 << TCG_REG_R1) |
1796: (1 << TCG_REG_R2) |
1797: (1 << TCG_REG_R3) |
1798: (1 << TCG_REG_R12) |
1799: (1 << TCG_REG_R14));
1.1 root 1800:
1801: tcg_regset_clear(s->reserved_regs);
1802: tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK);
1803: tcg_regset_set_reg(s->reserved_regs, TCG_REG_R8);
1.1.1.5 root 1804: tcg_regset_set_reg(s->reserved_regs, TCG_REG_PC);
1.1 root 1805:
1806: tcg_add_target_add_op_defs(arm_op_defs);
1.1.1.7 root 1807: tcg_set_frame(s, TCG_AREG0, offsetof(CPUState, temp_buf),
1808: CPU_TEMP_BUF_NLONGS * sizeof(long));
1.1 root 1809: }
1810:
1.1.1.8 ! root 1811: static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGReg arg,
! 1812: TCGReg arg1, tcg_target_long arg2)
1.1 root 1813: {
1814: tcg_out_ld32u(s, COND_AL, arg, arg1, arg2);
1815: }
1816:
1.1.1.8 ! root 1817: static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg,
! 1818: TCGReg arg1, tcg_target_long arg2)
1.1 root 1819: {
1820: tcg_out_st32(s, COND_AL, arg, arg1, arg2);
1821: }
1822:
1.1.1.8 ! root 1823: static inline void tcg_out_mov(TCGContext *s, TCGType type,
! 1824: TCGReg ret, TCGReg arg)
1.1 root 1825: {
1826: tcg_out_dat_reg(s, COND_AL, ARITH_MOV, ret, 0, arg, SHIFT_IMM_LSL(0));
1827: }
1828:
1829: static inline void tcg_out_movi(TCGContext *s, TCGType type,
1.1.1.8 ! root 1830: TCGReg ret, tcg_target_long arg)
1.1 root 1831: {
1832: tcg_out_movi32(s, COND_AL, ret, arg);
1833: }
1834:
1.1.1.5 root 1835: static void tcg_target_qemu_prologue(TCGContext *s)
1.1 root 1836: {
1.1.1.7 root 1837: /* Calling convention requires us to save r4-r11 and lr;
1838: * save also r12 to maintain stack 8-alignment.
1839: */
1840:
1841: /* stmdb sp!, { r4 - r12, lr } */
1842: tcg_out32(s, (COND_AL << 28) | 0x092d5ff0);
1.1.1.4 root 1843:
1.1.1.7 root 1844: tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
1.1 root 1845:
1.1.1.7 root 1846: tcg_out_bx(s, COND_AL, tcg_target_call_iarg_regs[1]);
1.1 root 1847: tb_ret_addr = s->code_ptr;
1848:
1.1.1.7 root 1849: /* ldmia sp!, { r4 - r12, pc } */
1850: tcg_out32(s, (COND_AL << 28) | 0x08bd9ff0);
1.1 root 1851: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.