]> Git Repo - qemu.git/blob - target-arm/translate-a64.c
target-arm: A64: add support for logical (shifted register)
[qemu.git] / target-arm / translate-a64.c
1 /*
2  *  AArch64 translation
3  *
4  *  Copyright (c) 2013 Alexander Graf <[email protected]>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  */
19 #include <stdarg.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <inttypes.h>
24
25 #include "cpu.h"
26 #include "tcg-op.h"
27 #include "qemu/log.h"
28 #include "translate.h"
29 #include "qemu/host-utils.h"
30
31 #include "exec/gen-icount.h"
32
33 #include "helper.h"
34 #define GEN_HELPER 1
35 #include "helper.h"
36
37 static TCGv_i64 cpu_X[32];
38 static TCGv_i64 cpu_pc;
39 static TCGv_i32 cpu_NF, cpu_ZF, cpu_CF, cpu_VF;
40
41 static const char *regnames[] = {
42     "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
43     "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
44     "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
45     "x24", "x25", "x26", "x27", "x28", "x29", "lr", "sp"
46 };
47
48 enum a64_shift_type {
49     A64_SHIFT_TYPE_LSL = 0,
50     A64_SHIFT_TYPE_LSR = 1,
51     A64_SHIFT_TYPE_ASR = 2,
52     A64_SHIFT_TYPE_ROR = 3
53 };
54
55 /* initialize TCG globals.  */
56 void a64_translate_init(void)
57 {
58     int i;
59
60     cpu_pc = tcg_global_mem_new_i64(TCG_AREG0,
61                                     offsetof(CPUARMState, pc),
62                                     "pc");
63     for (i = 0; i < 32; i++) {
64         cpu_X[i] = tcg_global_mem_new_i64(TCG_AREG0,
65                                           offsetof(CPUARMState, xregs[i]),
66                                           regnames[i]);
67     }
68
69     cpu_NF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, NF), "NF");
70     cpu_ZF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, ZF), "ZF");
71     cpu_CF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, CF), "CF");
72     cpu_VF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, VF), "VF");
73 }
74
75 void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
76                             fprintf_function cpu_fprintf, int flags)
77 {
78     ARMCPU *cpu = ARM_CPU(cs);
79     CPUARMState *env = &cpu->env;
80     uint32_t psr = pstate_read(env);
81     int i;
82
83     cpu_fprintf(f, "PC=%016"PRIx64"  SP=%016"PRIx64"\n",
84             env->pc, env->xregs[31]);
85     for (i = 0; i < 31; i++) {
86         cpu_fprintf(f, "X%02d=%016"PRIx64, i, env->xregs[i]);
87         if ((i % 4) == 3) {
88             cpu_fprintf(f, "\n");
89         } else {
90             cpu_fprintf(f, " ");
91         }
92     }
93     cpu_fprintf(f, "PSTATE=%08x (flags %c%c%c%c)\n",
94                 psr,
95                 psr & PSTATE_N ? 'N' : '-',
96                 psr & PSTATE_Z ? 'Z' : '-',
97                 psr & PSTATE_C ? 'C' : '-',
98                 psr & PSTATE_V ? 'V' : '-');
99     cpu_fprintf(f, "\n");
100 }
101
102 void gen_a64_set_pc_im(uint64_t val)
103 {
104     tcg_gen_movi_i64(cpu_pc, val);
105 }
106
107 static void gen_exception(int excp)
108 {
109     TCGv_i32 tmp = tcg_temp_new_i32();
110     tcg_gen_movi_i32(tmp, excp);
111     gen_helper_exception(cpu_env, tmp);
112     tcg_temp_free_i32(tmp);
113 }
114
115 static void gen_exception_insn(DisasContext *s, int offset, int excp)
116 {
117     gen_a64_set_pc_im(s->pc - offset);
118     gen_exception(excp);
119     s->is_jmp = DISAS_EXC;
120 }
121
122 static inline bool use_goto_tb(DisasContext *s, int n, uint64_t dest)
123 {
124     /* No direct tb linking with singlestep or deterministic io */
125     if (s->singlestep_enabled || (s->tb->cflags & CF_LAST_IO)) {
126         return false;
127     }
128
129     /* Only link tbs from inside the same guest page */
130     if ((s->tb->pc & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
131         return false;
132     }
133
134     return true;
135 }
136
137 static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
138 {
139     TranslationBlock *tb;
140
141     tb = s->tb;
142     if (use_goto_tb(s, n, dest)) {
143         tcg_gen_goto_tb(n);
144         gen_a64_set_pc_im(dest);
145         tcg_gen_exit_tb((tcg_target_long)tb + n);
146         s->is_jmp = DISAS_TB_JUMP;
147     } else {
148         gen_a64_set_pc_im(dest);
149         if (s->singlestep_enabled) {
150             gen_exception(EXCP_DEBUG);
151         }
152         tcg_gen_exit_tb(0);
153         s->is_jmp = DISAS_JUMP;
154     }
155 }
156
157 static void unallocated_encoding(DisasContext *s)
158 {
159     gen_exception_insn(s, 4, EXCP_UDEF);
160 }
161
162 #define unsupported_encoding(s, insn)                                    \
163     do {                                                                 \
164         qemu_log_mask(LOG_UNIMP,                                         \
165                       "%s:%d: unsupported instruction encoding 0x%08x "  \
166                       "at pc=%016" PRIx64 "\n",                          \
167                       __FILE__, __LINE__, insn, s->pc - 4);              \
168         unallocated_encoding(s);                                         \
169     } while (0);
170
171 static void init_tmp_a64_array(DisasContext *s)
172 {
173 #ifdef CONFIG_DEBUG_TCG
174     int i;
175     for (i = 0; i < ARRAY_SIZE(s->tmp_a64); i++) {
176         TCGV_UNUSED_I64(s->tmp_a64[i]);
177     }
178 #endif
179     s->tmp_a64_count = 0;
180 }
181
182 static void free_tmp_a64(DisasContext *s)
183 {
184     int i;
185     for (i = 0; i < s->tmp_a64_count; i++) {
186         tcg_temp_free_i64(s->tmp_a64[i]);
187     }
188     init_tmp_a64_array(s);
189 }
190
191 static TCGv_i64 new_tmp_a64(DisasContext *s)
192 {
193     assert(s->tmp_a64_count < TMP_A64_MAX);
194     return s->tmp_a64[s->tmp_a64_count++] = tcg_temp_new_i64();
195 }
196
197 static TCGv_i64 new_tmp_a64_zero(DisasContext *s)
198 {
199     TCGv_i64 t = new_tmp_a64(s);
200     tcg_gen_movi_i64(t, 0);
201     return t;
202 }
203
204 static TCGv_i64 cpu_reg(DisasContext *s, int reg)
205 {
206     if (reg == 31) {
207         return new_tmp_a64_zero(s);
208     } else {
209         return cpu_X[reg];
210     }
211 }
212
213 /* read a cpu register in 32bit/64bit mode. Returns a TCGv_i64
214  * representing the register contents. This TCGv is an auto-freed
215  * temporary so it need not be explicitly freed, and may be modified.
216  */
217 static TCGv_i64 read_cpu_reg(DisasContext *s, int reg, int sf)
218 {
219     TCGv_i64 v = new_tmp_a64(s);
220     if (reg != 31) {
221         if (sf) {
222             tcg_gen_mov_i64(v, cpu_X[reg]);
223         } else {
224             tcg_gen_ext32u_i64(v, cpu_X[reg]);
225         }
226     } else {
227         tcg_gen_movi_i64(v, 0);
228     }
229     return v;
230 }
231
232 /* Set ZF and NF based on a 64 bit result. This is alas fiddlier
233  * than the 32 bit equivalent.
234  */
235 static inline void gen_set_NZ64(TCGv_i64 result)
236 {
237     TCGv_i64 flag = tcg_temp_new_i64();
238
239     tcg_gen_setcondi_i64(TCG_COND_NE, flag, result, 0);
240     tcg_gen_trunc_i64_i32(cpu_ZF, flag);
241     tcg_gen_shri_i64(flag, result, 32);
242     tcg_gen_trunc_i64_i32(cpu_NF, flag);
243     tcg_temp_free_i64(flag);
244 }
245
246 /* Set NZCV as for a logical operation: NZ as per result, CV cleared. */
247 static inline void gen_logic_CC(int sf, TCGv_i64 result)
248 {
249     if (sf) {
250         gen_set_NZ64(result);
251     } else {
252         tcg_gen_trunc_i64_i32(cpu_ZF, result);
253         tcg_gen_trunc_i64_i32(cpu_NF, result);
254     }
255     tcg_gen_movi_i32(cpu_CF, 0);
256     tcg_gen_movi_i32(cpu_VF, 0);
257 }
258
259 /*
260  * the instruction disassembly implemented here matches
261  * the instruction encoding classifications in chapter 3 (C3)
262  * of the ARM Architecture Reference Manual (DDI0487A_a)
263  */
264
265 /* C3.2.7 Unconditional branch (immediate)
266  *   31  30       26 25                                  0
267  * +----+-----------+-------------------------------------+
268  * | op | 0 0 1 0 1 |                 imm26               |
269  * +----+-----------+-------------------------------------+
270  */
271 static void disas_uncond_b_imm(DisasContext *s, uint32_t insn)
272 {
273     uint64_t addr = s->pc + sextract32(insn, 0, 26) * 4 - 4;
274
275     if (insn & (1 << 31)) {
276         /* C5.6.26 BL Branch with link */
277         tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
278     }
279
280     /* C5.6.20 B Branch / C5.6.26 BL Branch with link */
281     gen_goto_tb(s, 0, addr);
282 }
283
284 /* C3.2.1 Compare & branch (immediate)
285  *   31  30         25  24  23                  5 4      0
286  * +----+-------------+----+---------------------+--------+
287  * | sf | 0 1 1 0 1 0 | op |         imm19       |   Rt   |
288  * +----+-------------+----+---------------------+--------+
289  */
290 static void disas_comp_b_imm(DisasContext *s, uint32_t insn)
291 {
292     unsigned int sf, op, rt;
293     uint64_t addr;
294     int label_match;
295     TCGv_i64 tcg_cmp;
296
297     sf = extract32(insn, 31, 1);
298     op = extract32(insn, 24, 1); /* 0: CBZ; 1: CBNZ */
299     rt = extract32(insn, 0, 5);
300     addr = s->pc + sextract32(insn, 5, 19) * 4 - 4;
301
302     tcg_cmp = read_cpu_reg(s, rt, sf);
303     label_match = gen_new_label();
304
305     tcg_gen_brcondi_i64(op ? TCG_COND_NE : TCG_COND_EQ,
306                         tcg_cmp, 0, label_match);
307
308     gen_goto_tb(s, 0, s->pc);
309     gen_set_label(label_match);
310     gen_goto_tb(s, 1, addr);
311 }
312
313 /* C3.2.5 Test & branch (immediate)
314  *   31  30         25  24  23   19 18          5 4    0
315  * +----+-------------+----+-------+-------------+------+
316  * | b5 | 0 1 1 0 1 1 | op |  b40  |    imm14    |  Rt  |
317  * +----+-------------+----+-------+-------------+------+
318  */
319 static void disas_test_b_imm(DisasContext *s, uint32_t insn)
320 {
321     unsigned int bit_pos, op, rt;
322     uint64_t addr;
323     int label_match;
324     TCGv_i64 tcg_cmp;
325
326     bit_pos = (extract32(insn, 31, 1) << 5) | extract32(insn, 19, 5);
327     op = extract32(insn, 24, 1); /* 0: TBZ; 1: TBNZ */
328     addr = s->pc + sextract32(insn, 5, 14) * 4 - 4;
329     rt = extract32(insn, 0, 5);
330
331     tcg_cmp = tcg_temp_new_i64();
332     tcg_gen_andi_i64(tcg_cmp, cpu_reg(s, rt), (1ULL << bit_pos));
333     label_match = gen_new_label();
334     tcg_gen_brcondi_i64(op ? TCG_COND_NE : TCG_COND_EQ,
335                         tcg_cmp, 0, label_match);
336     tcg_temp_free_i64(tcg_cmp);
337     gen_goto_tb(s, 0, s->pc);
338     gen_set_label(label_match);
339     gen_goto_tb(s, 1, addr);
340 }
341
342 /* C3.2.2 / C5.6.19 Conditional branch (immediate)
343  *  31           25  24  23                  5   4  3    0
344  * +---------------+----+---------------------+----+------+
345  * | 0 1 0 1 0 1 0 | o1 |         imm19       | o0 | cond |
346  * +---------------+----+---------------------+----+------+
347  */
348 static void disas_cond_b_imm(DisasContext *s, uint32_t insn)
349 {
350     unsigned int cond;
351     uint64_t addr;
352
353     if ((insn & (1 << 4)) || (insn & (1 << 24))) {
354         unallocated_encoding(s);
355         return;
356     }
357     addr = s->pc + sextract32(insn, 5, 19) * 4 - 4;
358     cond = extract32(insn, 0, 4);
359
360     if (cond < 0x0e) {
361         /* genuinely conditional branches */
362         int label_match = gen_new_label();
363         arm_gen_test_cc(cond, label_match);
364         gen_goto_tb(s, 0, s->pc);
365         gen_set_label(label_match);
366         gen_goto_tb(s, 1, addr);
367     } else {
368         /* 0xe and 0xf are both "always" conditions */
369         gen_goto_tb(s, 0, addr);
370     }
371 }
372
373 /* C5.6.68 HINT */
374 static void handle_hint(DisasContext *s, uint32_t insn,
375                         unsigned int op1, unsigned int op2, unsigned int crm)
376 {
377     unsigned int selector = crm << 3 | op2;
378
379     if (op1 != 3) {
380         unallocated_encoding(s);
381         return;
382     }
383
384     switch (selector) {
385     case 0: /* NOP */
386         return;
387     case 1: /* YIELD */
388     case 2: /* WFE */
389     case 3: /* WFI */
390     case 4: /* SEV */
391     case 5: /* SEVL */
392         /* we treat all as NOP at least for now */
393         return;
394     default:
395         /* default specified as NOP equivalent */
396         return;
397     }
398 }
399
400 /* CLREX, DSB, DMB, ISB */
401 static void handle_sync(DisasContext *s, uint32_t insn,
402                         unsigned int op1, unsigned int op2, unsigned int crm)
403 {
404     if (op1 != 3) {
405         unallocated_encoding(s);
406         return;
407     }
408
409     switch (op2) {
410     case 2: /* CLREX */
411         unsupported_encoding(s, insn);
412         return;
413     case 4: /* DSB */
414     case 5: /* DMB */
415     case 6: /* ISB */
416         /* We don't emulate caches so barriers are no-ops */
417         return;
418     default:
419         unallocated_encoding(s);
420         return;
421     }
422 }
423
424 /* C5.6.130 MSR (immediate) - move immediate to processor state field */
425 static void handle_msr_i(DisasContext *s, uint32_t insn,
426                          unsigned int op1, unsigned int op2, unsigned int crm)
427 {
428     unsupported_encoding(s, insn);
429 }
430
431 /* C5.6.204 SYS */
432 static void handle_sys(DisasContext *s, uint32_t insn, unsigned int l,
433                        unsigned int op1, unsigned int op2,
434                        unsigned int crn, unsigned int crm, unsigned int rt)
435 {
436     unsupported_encoding(s, insn);
437 }
438
439 /* C5.6.129 MRS - move from system register */
440 static void handle_mrs(DisasContext *s, uint32_t insn, unsigned int op0,
441                        unsigned int op1, unsigned int op2,
442                        unsigned int crn, unsigned int crm, unsigned int rt)
443 {
444     unsupported_encoding(s, insn);
445 }
446
447 /* C5.6.131 MSR (register) - move to system register */
448 static void handle_msr(DisasContext *s, uint32_t insn, unsigned int op0,
449                        unsigned int op1, unsigned int op2,
450                        unsigned int crn, unsigned int crm, unsigned int rt)
451 {
452     unsupported_encoding(s, insn);
453 }
454
455 /* C3.2.4 System
456  *  31                 22 21  20 19 18 16 15   12 11    8 7   5 4    0
457  * +---------------------+---+-----+-----+-------+-------+-----+------+
458  * | 1 1 0 1 0 1 0 1 0 0 | L | op0 | op1 |  CRn  |  CRm  | op2 |  Rt  |
459  * +---------------------+---+-----+-----+-------+-------+-----+------+
460  */
461 static void disas_system(DisasContext *s, uint32_t insn)
462 {
463     unsigned int l, op0, op1, crn, crm, op2, rt;
464     l = extract32(insn, 21, 1);
465     op0 = extract32(insn, 19, 2);
466     op1 = extract32(insn, 16, 3);
467     crn = extract32(insn, 12, 4);
468     crm = extract32(insn, 8, 4);
469     op2 = extract32(insn, 5, 3);
470     rt = extract32(insn, 0, 5);
471
472     if (op0 == 0) {
473         if (l || rt != 31) {
474             unallocated_encoding(s);
475             return;
476         }
477         switch (crn) {
478         case 2: /* C5.6.68 HINT */
479             handle_hint(s, insn, op1, op2, crm);
480             break;
481         case 3: /* CLREX, DSB, DMB, ISB */
482             handle_sync(s, insn, op1, op2, crm);
483             break;
484         case 4: /* C5.6.130 MSR (immediate) */
485             handle_msr_i(s, insn, op1, op2, crm);
486             break;
487         default:
488             unallocated_encoding(s);
489             break;
490         }
491         return;
492     }
493
494     if (op0 == 1) {
495         /* C5.6.204 SYS */
496         handle_sys(s, insn, l, op1, op2, crn, crm, rt);
497     } else if (l) { /* op0 > 1 */
498         /* C5.6.129 MRS - move from system register */
499         handle_mrs(s, insn, op0, op1, op2, crn, crm, rt);
500     } else {
501         /* C5.6.131 MSR (register) - move to system register */
502         handle_msr(s, insn, op0, op1, op2, crn, crm, rt);
503     }
504 }
505
506 /* Exception generation */
507 static void disas_exc(DisasContext *s, uint32_t insn)
508 {
509     unsupported_encoding(s, insn);
510 }
511
512 /* C3.2.7 Unconditional branch (register)
513  *  31           25 24   21 20   16 15   10 9    5 4     0
514  * +---------------+-------+-------+-------+------+-------+
515  * | 1 1 0 1 0 1 1 |  opc  |  op2  |  op3  |  Rn  |  op4  |
516  * +---------------+-------+-------+-------+------+-------+
517  */
518 static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
519 {
520     unsigned int opc, op2, op3, rn, op4;
521
522     opc = extract32(insn, 21, 4);
523     op2 = extract32(insn, 16, 5);
524     op3 = extract32(insn, 10, 6);
525     rn = extract32(insn, 5, 5);
526     op4 = extract32(insn, 0, 5);
527
528     if (op4 != 0x0 || op3 != 0x0 || op2 != 0x1f) {
529         unallocated_encoding(s);
530         return;
531     }
532
533     switch (opc) {
534     case 0: /* BR */
535     case 2: /* RET */
536         break;
537     case 1: /* BLR */
538         tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
539         break;
540     case 4: /* ERET */
541     case 5: /* DRPS */
542         if (rn != 0x1f) {
543             unallocated_encoding(s);
544         } else {
545             unsupported_encoding(s, insn);
546         }
547         return;
548     default:
549         unallocated_encoding(s);
550         return;
551     }
552
553     tcg_gen_mov_i64(cpu_pc, cpu_reg(s, rn));
554     s->is_jmp = DISAS_JUMP;
555 }
556
557 /* C3.2 Branches, exception generating and system instructions */
558 static void disas_b_exc_sys(DisasContext *s, uint32_t insn)
559 {
560     switch (extract32(insn, 25, 7)) {
561     case 0x0a: case 0x0b:
562     case 0x4a: case 0x4b: /* Unconditional branch (immediate) */
563         disas_uncond_b_imm(s, insn);
564         break;
565     case 0x1a: case 0x5a: /* Compare & branch (immediate) */
566         disas_comp_b_imm(s, insn);
567         break;
568     case 0x1b: case 0x5b: /* Test & branch (immediate) */
569         disas_test_b_imm(s, insn);
570         break;
571     case 0x2a: /* Conditional branch (immediate) */
572         disas_cond_b_imm(s, insn);
573         break;
574     case 0x6a: /* Exception generation / System */
575         if (insn & (1 << 24)) {
576             disas_system(s, insn);
577         } else {
578             disas_exc(s, insn);
579         }
580         break;
581     case 0x6b: /* Unconditional branch (register) */
582         disas_uncond_b_reg(s, insn);
583         break;
584     default:
585         unallocated_encoding(s);
586         break;
587     }
588 }
589
590 /* Load/store exclusive */
591 static void disas_ldst_excl(DisasContext *s, uint32_t insn)
592 {
593     unsupported_encoding(s, insn);
594 }
595
596 /* Load register (literal) */
597 static void disas_ld_lit(DisasContext *s, uint32_t insn)
598 {
599     unsupported_encoding(s, insn);
600 }
601
602 /* Load/store pair (all forms) */
603 static void disas_ldst_pair(DisasContext *s, uint32_t insn)
604 {
605     unsupported_encoding(s, insn);
606 }
607
608 /* Load/store register (all forms) */
609 static void disas_ldst_reg(DisasContext *s, uint32_t insn)
610 {
611     unsupported_encoding(s, insn);
612 }
613
614 /* AdvSIMD load/store multiple structures */
615 static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn)
616 {
617     unsupported_encoding(s, insn);
618 }
619
620 /* AdvSIMD load/store single structure */
621 static void disas_ldst_single_struct(DisasContext *s, uint32_t insn)
622 {
623     unsupported_encoding(s, insn);
624 }
625
626 /* C3.3 Loads and stores */
627 static void disas_ldst(DisasContext *s, uint32_t insn)
628 {
629     switch (extract32(insn, 24, 6)) {
630     case 0x08: /* Load/store exclusive */
631         disas_ldst_excl(s, insn);
632         break;
633     case 0x18: case 0x1c: /* Load register (literal) */
634         disas_ld_lit(s, insn);
635         break;
636     case 0x28: case 0x29:
637     case 0x2c: case 0x2d: /* Load/store pair (all forms) */
638         disas_ldst_pair(s, insn);
639         break;
640     case 0x38: case 0x39:
641     case 0x3c: case 0x3d: /* Load/store register (all forms) */
642         disas_ldst_reg(s, insn);
643         break;
644     case 0x0c: /* AdvSIMD load/store multiple structures */
645         disas_ldst_multiple_struct(s, insn);
646         break;
647     case 0x0d: /* AdvSIMD load/store single structure */
648         disas_ldst_single_struct(s, insn);
649         break;
650     default:
651         unallocated_encoding(s);
652         break;
653     }
654 }
655
656 /* PC-rel. addressing */
657 static void disas_pc_rel_adr(DisasContext *s, uint32_t insn)
658 {
659     unsupported_encoding(s, insn);
660 }
661
662 /* Add/subtract (immediate) */
663 static void disas_add_sub_imm(DisasContext *s, uint32_t insn)
664 {
665     unsupported_encoding(s, insn);
666 }
667
668 /* Logical (immediate) */
669 static void disas_logic_imm(DisasContext *s, uint32_t insn)
670 {
671     unsupported_encoding(s, insn);
672 }
673
674 /* Move wide (immediate) */
675 static void disas_movw_imm(DisasContext *s, uint32_t insn)
676 {
677     unsupported_encoding(s, insn);
678 }
679
680 /* Bitfield */
681 static void disas_bitfield(DisasContext *s, uint32_t insn)
682 {
683     unsupported_encoding(s, insn);
684 }
685
686 /* Extract */
687 static void disas_extract(DisasContext *s, uint32_t insn)
688 {
689     unsupported_encoding(s, insn);
690 }
691
692 /* C3.4 Data processing - immediate */
693 static void disas_data_proc_imm(DisasContext *s, uint32_t insn)
694 {
695     switch (extract32(insn, 23, 6)) {
696     case 0x20: case 0x21: /* PC-rel. addressing */
697         disas_pc_rel_adr(s, insn);
698         break;
699     case 0x22: case 0x23: /* Add/subtract (immediate) */
700         disas_add_sub_imm(s, insn);
701         break;
702     case 0x24: /* Logical (immediate) */
703         disas_logic_imm(s, insn);
704         break;
705     case 0x25: /* Move wide (immediate) */
706         disas_movw_imm(s, insn);
707         break;
708     case 0x26: /* Bitfield */
709         disas_bitfield(s, insn);
710         break;
711     case 0x27: /* Extract */
712         disas_extract(s, insn);
713         break;
714     default:
715         unallocated_encoding(s);
716         break;
717     }
718 }
719
720 /* Shift a TCGv src by TCGv shift_amount, put result in dst.
721  * Note that it is the caller's responsibility to ensure that the
722  * shift amount is in range (ie 0..31 or 0..63) and provide the ARM
723  * mandated semantics for out of range shifts.
724  */
725 static void shift_reg(TCGv_i64 dst, TCGv_i64 src, int sf,
726                       enum a64_shift_type shift_type, TCGv_i64 shift_amount)
727 {
728     switch (shift_type) {
729     case A64_SHIFT_TYPE_LSL:
730         tcg_gen_shl_i64(dst, src, shift_amount);
731         break;
732     case A64_SHIFT_TYPE_LSR:
733         tcg_gen_shr_i64(dst, src, shift_amount);
734         break;
735     case A64_SHIFT_TYPE_ASR:
736         if (!sf) {
737             tcg_gen_ext32s_i64(dst, src);
738         }
739         tcg_gen_sar_i64(dst, sf ? src : dst, shift_amount);
740         break;
741     case A64_SHIFT_TYPE_ROR:
742         if (sf) {
743             tcg_gen_rotr_i64(dst, src, shift_amount);
744         } else {
745             TCGv_i32 t0, t1;
746             t0 = tcg_temp_new_i32();
747             t1 = tcg_temp_new_i32();
748             tcg_gen_trunc_i64_i32(t0, src);
749             tcg_gen_trunc_i64_i32(t1, shift_amount);
750             tcg_gen_rotr_i32(t0, t0, t1);
751             tcg_gen_extu_i32_i64(dst, t0);
752             tcg_temp_free_i32(t0);
753             tcg_temp_free_i32(t1);
754         }
755         break;
756     default:
757         assert(FALSE); /* all shift types should be handled */
758         break;
759     }
760
761     if (!sf) { /* zero extend final result */
762         tcg_gen_ext32u_i64(dst, dst);
763     }
764 }
765
766 /* Shift a TCGv src by immediate, put result in dst.
767  * The shift amount must be in range (this should always be true as the
768  * relevant instructions will UNDEF on bad shift immediates).
769  */
770 static void shift_reg_imm(TCGv_i64 dst, TCGv_i64 src, int sf,
771                           enum a64_shift_type shift_type, unsigned int shift_i)
772 {
773     assert(shift_i < (sf ? 64 : 32));
774
775     if (shift_i == 0) {
776         tcg_gen_mov_i64(dst, src);
777     } else {
778         TCGv_i64 shift_const;
779
780         shift_const = tcg_const_i64(shift_i);
781         shift_reg(dst, src, sf, shift_type, shift_const);
782         tcg_temp_free_i64(shift_const);
783     }
784 }
785
786 /* C3.5.10 Logical (shifted register)
787  *   31  30 29 28       24 23   22 21  20  16 15    10 9    5 4    0
788  * +----+-----+-----------+-------+---+------+--------+------+------+
789  * | sf | opc | 0 1 0 1 0 | shift | N |  Rm  |  imm6  |  Rn  |  Rd  |
790  * +----+-----+-----------+-------+---+------+--------+------+------+
791  */
792 static void disas_logic_reg(DisasContext *s, uint32_t insn)
793 {
794     TCGv_i64 tcg_rd, tcg_rn, tcg_rm;
795     unsigned int sf, opc, shift_type, invert, rm, shift_amount, rn, rd;
796
797     sf = extract32(insn, 31, 1);
798     opc = extract32(insn, 29, 2);
799     shift_type = extract32(insn, 22, 2);
800     invert = extract32(insn, 21, 1);
801     rm = extract32(insn, 16, 5);
802     shift_amount = extract32(insn, 10, 6);
803     rn = extract32(insn, 5, 5);
804     rd = extract32(insn, 0, 5);
805
806     if (!sf && (shift_amount & (1 << 5))) {
807         unallocated_encoding(s);
808         return;
809     }
810
811     tcg_rd = cpu_reg(s, rd);
812
813     if (opc == 1 && shift_amount == 0 && shift_type == 0 && rn == 31) {
814         /* Unshifted ORR and ORN with WZR/XZR is the standard encoding for
815          * register-register MOV and MVN, so it is worth special casing.
816          */
817         tcg_rm = cpu_reg(s, rm);
818         if (invert) {
819             tcg_gen_not_i64(tcg_rd, tcg_rm);
820             if (!sf) {
821                 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
822             }
823         } else {
824             if (sf) {
825                 tcg_gen_mov_i64(tcg_rd, tcg_rm);
826             } else {
827                 tcg_gen_ext32u_i64(tcg_rd, tcg_rm);
828             }
829         }
830         return;
831     }
832
833     tcg_rm = read_cpu_reg(s, rm, sf);
834
835     if (shift_amount) {
836         shift_reg_imm(tcg_rm, tcg_rm, sf, shift_type, shift_amount);
837     }
838
839     tcg_rn = cpu_reg(s, rn);
840
841     switch (opc | (invert << 2)) {
842     case 0: /* AND */
843     case 3: /* ANDS */
844         tcg_gen_and_i64(tcg_rd, tcg_rn, tcg_rm);
845         break;
846     case 1: /* ORR */
847         tcg_gen_or_i64(tcg_rd, tcg_rn, tcg_rm);
848         break;
849     case 2: /* EOR */
850         tcg_gen_xor_i64(tcg_rd, tcg_rn, tcg_rm);
851         break;
852     case 4: /* BIC */
853     case 7: /* BICS */
854         tcg_gen_andc_i64(tcg_rd, tcg_rn, tcg_rm);
855         break;
856     case 5: /* ORN */
857         tcg_gen_orc_i64(tcg_rd, tcg_rn, tcg_rm);
858         break;
859     case 6: /* EON */
860         tcg_gen_eqv_i64(tcg_rd, tcg_rn, tcg_rm);
861         break;
862     default:
863         assert(FALSE);
864         break;
865     }
866
867     if (!sf) {
868         tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
869     }
870
871     if (opc == 3) {
872         gen_logic_CC(sf, tcg_rd);
873     }
874 }
875
876 /* Add/subtract (extended register) */
877 static void disas_add_sub_ext_reg(DisasContext *s, uint32_t insn)
878 {
879     unsupported_encoding(s, insn);
880 }
881
882 /* Add/subtract (shifted register) */
883 static void disas_add_sub_reg(DisasContext *s, uint32_t insn)
884 {
885     unsupported_encoding(s, insn);
886 }
887
888 /* Data-processing (3 source) */
889 static void disas_data_proc_3src(DisasContext *s, uint32_t insn)
890 {
891     unsupported_encoding(s, insn);
892 }
893
894 /* Add/subtract (with carry) */
895 static void disas_adc_sbc(DisasContext *s, uint32_t insn)
896 {
897     unsupported_encoding(s, insn);
898 }
899
900 /* Conditional compare (immediate) */
901 static void disas_cc_imm(DisasContext *s, uint32_t insn)
902 {
903     unsupported_encoding(s, insn);
904 }
905
906 /* Conditional compare (register) */
907 static void disas_cc_reg(DisasContext *s, uint32_t insn)
908 {
909     unsupported_encoding(s, insn);
910 }
911
912 /* C3.5.6 Conditional select
913  *   31   30  29  28             21 20  16 15  12 11 10 9    5 4    0
914  * +----+----+---+-----------------+------+------+-----+------+------+
915  * | sf | op | S | 1 1 0 1 0 1 0 0 |  Rm  | cond | op2 |  Rn  |  Rd  |
916  * +----+----+---+-----------------+------+------+-----+------+------+
917  */
918 static void disas_cond_select(DisasContext *s, uint32_t insn)
919 {
920     unsigned int sf, else_inv, rm, cond, else_inc, rn, rd;
921     TCGv_i64 tcg_rd, tcg_src;
922
923     if (extract32(insn, 29, 1) || extract32(insn, 11, 1)) {
924         /* S == 1 or op2<1> == 1 */
925         unallocated_encoding(s);
926         return;
927     }
928     sf = extract32(insn, 31, 1);
929     else_inv = extract32(insn, 30, 1);
930     rm = extract32(insn, 16, 5);
931     cond = extract32(insn, 12, 4);
932     else_inc = extract32(insn, 10, 1);
933     rn = extract32(insn, 5, 5);
934     rd = extract32(insn, 0, 5);
935
936     if (rd == 31) {
937         /* silly no-op write; until we use movcond we must special-case
938          * this to avoid a dead temporary across basic blocks.
939          */
940         return;
941     }
942
943     tcg_rd = cpu_reg(s, rd);
944
945     if (cond >= 0x0e) { /* condition "always" */
946         tcg_src = read_cpu_reg(s, rn, sf);
947         tcg_gen_mov_i64(tcg_rd, tcg_src);
948     } else {
949         /* OPTME: we could use movcond here, at the cost of duplicating
950          * a lot of the arm_gen_test_cc() logic.
951          */
952         int label_match = gen_new_label();
953         int label_continue = gen_new_label();
954
955         arm_gen_test_cc(cond, label_match);
956         /* nomatch: */
957         tcg_src = cpu_reg(s, rm);
958
959         if (else_inv && else_inc) {
960             tcg_gen_neg_i64(tcg_rd, tcg_src);
961         } else if (else_inv) {
962             tcg_gen_not_i64(tcg_rd, tcg_src);
963         } else if (else_inc) {
964             tcg_gen_addi_i64(tcg_rd, tcg_src, 1);
965         } else {
966             tcg_gen_mov_i64(tcg_rd, tcg_src);
967         }
968         if (!sf) {
969             tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
970         }
971         tcg_gen_br(label_continue);
972         /* match: */
973         gen_set_label(label_match);
974         tcg_src = read_cpu_reg(s, rn, sf);
975         tcg_gen_mov_i64(tcg_rd, tcg_src);
976         /* continue: */
977         gen_set_label(label_continue);
978     }
979 }
980
981 /* Data-processing (1 source) */
982 static void disas_data_proc_1src(DisasContext *s, uint32_t insn)
983 {
984     unsupported_encoding(s, insn);
985 }
986
987 /* Data-processing (2 source) */
988 static void disas_data_proc_2src(DisasContext *s, uint32_t insn)
989 {
990     unsupported_encoding(s, insn);
991 }
992
993 /* C3.5 Data processing - register */
994 static void disas_data_proc_reg(DisasContext *s, uint32_t insn)
995 {
996     switch (extract32(insn, 24, 5)) {
997     case 0x0a: /* Logical (shifted register) */
998         disas_logic_reg(s, insn);
999         break;
1000     case 0x0b: /* Add/subtract */
1001         if (insn & (1 << 21)) { /* (extended register) */
1002             disas_add_sub_ext_reg(s, insn);
1003         } else {
1004             disas_add_sub_reg(s, insn);
1005         }
1006         break;
1007     case 0x1b: /* Data-processing (3 source) */
1008         disas_data_proc_3src(s, insn);
1009         break;
1010     case 0x1a:
1011         switch (extract32(insn, 21, 3)) {
1012         case 0x0: /* Add/subtract (with carry) */
1013             disas_adc_sbc(s, insn);
1014             break;
1015         case 0x2: /* Conditional compare */
1016             if (insn & (1 << 11)) { /* (immediate) */
1017                 disas_cc_imm(s, insn);
1018             } else {            /* (register) */
1019                 disas_cc_reg(s, insn);
1020             }
1021             break;
1022         case 0x4: /* Conditional select */
1023             disas_cond_select(s, insn);
1024             break;
1025         case 0x6: /* Data-processing */
1026             if (insn & (1 << 30)) { /* (1 source) */
1027                 disas_data_proc_1src(s, insn);
1028             } else {            /* (2 source) */
1029                 disas_data_proc_2src(s, insn);
1030             }
1031             break;
1032         default:
1033             unallocated_encoding(s);
1034             break;
1035         }
1036         break;
1037     default:
1038         unallocated_encoding(s);
1039         break;
1040     }
1041 }
1042
1043 /* C3.6 Data processing - SIMD and floating point */
1044 static void disas_data_proc_simd_fp(DisasContext *s, uint32_t insn)
1045 {
1046     unsupported_encoding(s, insn);
1047 }
1048
1049 /* C3.1 A64 instruction index by encoding */
1050 static void disas_a64_insn(CPUARMState *env, DisasContext *s)
1051 {
1052     uint32_t insn;
1053
1054     insn = arm_ldl_code(env, s->pc, s->bswap_code);
1055     s->insn = insn;
1056     s->pc += 4;
1057
1058     switch (extract32(insn, 25, 4)) {
1059     case 0x0: case 0x1: case 0x2: case 0x3: /* UNALLOCATED */
1060         unallocated_encoding(s);
1061         break;
1062     case 0x8: case 0x9: /* Data processing - immediate */
1063         disas_data_proc_imm(s, insn);
1064         break;
1065     case 0xa: case 0xb: /* Branch, exception generation and system insns */
1066         disas_b_exc_sys(s, insn);
1067         break;
1068     case 0x4:
1069     case 0x6:
1070     case 0xc:
1071     case 0xe:      /* Loads and stores */
1072         disas_ldst(s, insn);
1073         break;
1074     case 0x5:
1075     case 0xd:      /* Data processing - register */
1076         disas_data_proc_reg(s, insn);
1077         break;
1078     case 0x7:
1079     case 0xf:      /* Data processing - SIMD and floating point */
1080         disas_data_proc_simd_fp(s, insn);
1081         break;
1082     default:
1083         assert(FALSE); /* all 15 cases should be handled above */
1084         break;
1085     }
1086
1087     /* if we allocated any temporaries, free them here */
1088     free_tmp_a64(s);
1089 }
1090
1091 void gen_intermediate_code_internal_a64(ARMCPU *cpu,
1092                                         TranslationBlock *tb,
1093                                         bool search_pc)
1094 {
1095     CPUState *cs = CPU(cpu);
1096     CPUARMState *env = &cpu->env;
1097     DisasContext dc1, *dc = &dc1;
1098     CPUBreakpoint *bp;
1099     uint16_t *gen_opc_end;
1100     int j, lj;
1101     target_ulong pc_start;
1102     target_ulong next_page_start;
1103     int num_insns;
1104     int max_insns;
1105
1106     pc_start = tb->pc;
1107
1108     dc->tb = tb;
1109
1110     gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE;
1111
1112     dc->is_jmp = DISAS_NEXT;
1113     dc->pc = pc_start;
1114     dc->singlestep_enabled = cs->singlestep_enabled;
1115     dc->condjmp = 0;
1116
1117     dc->aarch64 = 1;
1118     dc->thumb = 0;
1119     dc->bswap_code = 0;
1120     dc->condexec_mask = 0;
1121     dc->condexec_cond = 0;
1122 #if !defined(CONFIG_USER_ONLY)
1123     dc->user = 0;
1124 #endif
1125     dc->vfp_enabled = 0;
1126     dc->vec_len = 0;
1127     dc->vec_stride = 0;
1128
1129     init_tmp_a64_array(dc);
1130
1131     next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
1132     lj = -1;
1133     num_insns = 0;
1134     max_insns = tb->cflags & CF_COUNT_MASK;
1135     if (max_insns == 0) {
1136         max_insns = CF_COUNT_MASK;
1137     }
1138
1139     gen_tb_start();
1140
1141     tcg_clear_temp_count();
1142
1143     do {
1144         if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
1145             QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
1146                 if (bp->pc == dc->pc) {
1147                     gen_exception_insn(dc, 0, EXCP_DEBUG);
1148                     /* Advance PC so that clearing the breakpoint will
1149                        invalidate this TB.  */
1150                     dc->pc += 2;
1151                     goto done_generating;
1152                 }
1153             }
1154         }
1155
1156         if (search_pc) {
1157             j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
1158             if (lj < j) {
1159                 lj++;
1160                 while (lj < j) {
1161                     tcg_ctx.gen_opc_instr_start[lj++] = 0;
1162                 }
1163             }
1164             tcg_ctx.gen_opc_pc[lj] = dc->pc;
1165             tcg_ctx.gen_opc_instr_start[lj] = 1;
1166             tcg_ctx.gen_opc_icount[lj] = num_insns;
1167         }
1168
1169         if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) {
1170             gen_io_start();
1171         }
1172
1173         if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) {
1174             tcg_gen_debug_insn_start(dc->pc);
1175         }
1176
1177         disas_a64_insn(env, dc);
1178
1179         if (tcg_check_temp_count()) {
1180             fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n",
1181                     dc->pc);
1182         }
1183
1184         /* Translation stops when a conditional branch is encountered.
1185          * Otherwise the subsequent code could get translated several times.
1186          * Also stop translation when a page boundary is reached.  This
1187          * ensures prefetch aborts occur at the right place.
1188          */
1189         num_insns++;
1190     } while (!dc->is_jmp && tcg_ctx.gen_opc_ptr < gen_opc_end &&
1191              !cs->singlestep_enabled &&
1192              !singlestep &&
1193              dc->pc < next_page_start &&
1194              num_insns < max_insns);
1195
1196     if (tb->cflags & CF_LAST_IO) {
1197         gen_io_end();
1198     }
1199
1200     if (unlikely(cs->singlestep_enabled) && dc->is_jmp != DISAS_EXC) {
1201         /* Note that this means single stepping WFI doesn't halt the CPU.
1202          * For conditional branch insns this is harmless unreachable code as
1203          * gen_goto_tb() has already handled emitting the debug exception
1204          * (and thus a tb-jump is not possible when singlestepping).
1205          */
1206         assert(dc->is_jmp != DISAS_TB_JUMP);
1207         if (dc->is_jmp != DISAS_JUMP) {
1208             gen_a64_set_pc_im(dc->pc);
1209         }
1210         gen_exception(EXCP_DEBUG);
1211     } else {
1212         switch (dc->is_jmp) {
1213         case DISAS_NEXT:
1214             gen_goto_tb(dc, 1, dc->pc);
1215             break;
1216         default:
1217         case DISAS_JUMP:
1218         case DISAS_UPDATE:
1219             /* indicate that the hash table must be used to find the next TB */
1220             tcg_gen_exit_tb(0);
1221             break;
1222         case DISAS_TB_JUMP:
1223         case DISAS_EXC:
1224         case DISAS_SWI:
1225             break;
1226         case DISAS_WFI:
1227             /* This is a special case because we don't want to just halt the CPU
1228              * if trying to debug across a WFI.
1229              */
1230             gen_helper_wfi(cpu_env);
1231             break;
1232         }
1233     }
1234
1235 done_generating:
1236     gen_tb_end(tb, num_insns);
1237     *tcg_ctx.gen_opc_ptr = INDEX_op_end;
1238
1239 #ifdef DEBUG_DISAS
1240     if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
1241         qemu_log("----------------\n");
1242         qemu_log("IN: %s\n", lookup_symbol(pc_start));
1243         log_target_disas(env, pc_start, dc->pc - pc_start,
1244                          dc->thumb | (dc->bswap_code << 1));
1245         qemu_log("\n");
1246     }
1247 #endif
1248     if (search_pc) {
1249         j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
1250         lj++;
1251         while (lj <= j) {
1252             tcg_ctx.gen_opc_instr_start[lj++] = 0;
1253         }
1254     } else {
1255         tb->size = dc->pc - pc_start;
1256         tb->icount = num_insns;
1257     }
1258 }
This page took 0.092356 seconds and 4 git commands to generate.