blob: 1d04303980bcd2f17a34af8343b34b6ad0460385 [file] [log] [blame]
Alexander Graf14ade102013-09-03 20:12:10 +01001/*
2 * AArch64 translation
3 *
4 * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
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
Peter Maydell40f860c2013-12-17 19:42:31 +000031#include "exec/gen-icount.h"
32
Alexander Graf14ade102013-09-03 20:12:10 +010033#include "helper.h"
34#define GEN_HELPER 1
35#include "helper.h"
36
37static TCGv_i64 cpu_X[32];
38static TCGv_i64 cpu_pc;
39static TCGv_i32 pstate;
40
41static 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/* initialize TCG globals. */
49void a64_translate_init(void)
50{
51 int i;
52
53 cpu_pc = tcg_global_mem_new_i64(TCG_AREG0,
54 offsetof(CPUARMState, pc),
55 "pc");
56 for (i = 0; i < 32; i++) {
57 cpu_X[i] = tcg_global_mem_new_i64(TCG_AREG0,
58 offsetof(CPUARMState, xregs[i]),
59 regnames[i]);
60 }
61
62 pstate = tcg_global_mem_new_i32(TCG_AREG0,
63 offsetof(CPUARMState, pstate),
64 "pstate");
65}
66
67void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
68 fprintf_function cpu_fprintf, int flags)
69{
70 ARMCPU *cpu = ARM_CPU(cs);
71 CPUARMState *env = &cpu->env;
Peter Maydelld3563122013-12-17 19:42:30 +000072 uint32_t psr = pstate_read(env);
Alexander Graf14ade102013-09-03 20:12:10 +010073 int i;
74
75 cpu_fprintf(f, "PC=%016"PRIx64" SP=%016"PRIx64"\n",
76 env->pc, env->xregs[31]);
77 for (i = 0; i < 31; i++) {
78 cpu_fprintf(f, "X%02d=%016"PRIx64, i, env->xregs[i]);
79 if ((i % 4) == 3) {
80 cpu_fprintf(f, "\n");
81 } else {
82 cpu_fprintf(f, " ");
83 }
84 }
Peter Maydelld3563122013-12-17 19:42:30 +000085 cpu_fprintf(f, "PSTATE=%08x (flags %c%c%c%c)\n",
86 psr,
87 psr & PSTATE_N ? 'N' : '-',
88 psr & PSTATE_Z ? 'Z' : '-',
89 psr & PSTATE_C ? 'C' : '-',
90 psr & PSTATE_V ? 'V' : '-');
Alexander Graf14ade102013-09-03 20:12:10 +010091 cpu_fprintf(f, "\n");
92}
93
94void gen_a64_set_pc_im(uint64_t val)
95{
96 tcg_gen_movi_i64(cpu_pc, val);
97}
98
99static void gen_exception(int excp)
100{
101 TCGv_i32 tmp = tcg_temp_new_i32();
102 tcg_gen_movi_i32(tmp, excp);
103 gen_helper_exception(cpu_env, tmp);
104 tcg_temp_free_i32(tmp);
105}
106
107static void gen_exception_insn(DisasContext *s, int offset, int excp)
108{
109 gen_a64_set_pc_im(s->pc - offset);
110 gen_exception(excp);
Peter Maydell40f860c2013-12-17 19:42:31 +0000111 s->is_jmp = DISAS_EXC;
112}
113
114static inline bool use_goto_tb(DisasContext *s, int n, uint64_t dest)
115{
116 /* No direct tb linking with singlestep or deterministic io */
117 if (s->singlestep_enabled || (s->tb->cflags & CF_LAST_IO)) {
118 return false;
119 }
120
121 /* Only link tbs from inside the same guest page */
122 if ((s->tb->pc & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
123 return false;
124 }
125
126 return true;
127}
128
129static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
130{
131 TranslationBlock *tb;
132
133 tb = s->tb;
134 if (use_goto_tb(s, n, dest)) {
135 tcg_gen_goto_tb(n);
136 gen_a64_set_pc_im(dest);
137 tcg_gen_exit_tb((tcg_target_long)tb + n);
138 s->is_jmp = DISAS_TB_JUMP;
139 } else {
140 gen_a64_set_pc_im(dest);
141 if (s->singlestep_enabled) {
142 gen_exception(EXCP_DEBUG);
143 }
144 tcg_gen_exit_tb(0);
145 s->is_jmp = DISAS_JUMP;
146 }
Alexander Graf14ade102013-09-03 20:12:10 +0100147}
148
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000149static void unallocated_encoding(DisasContext *s)
Alexander Graf14ade102013-09-03 20:12:10 +0100150{
Alexander Graf14ade102013-09-03 20:12:10 +0100151 gen_exception_insn(s, 4, EXCP_UDEF);
152}
153
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000154#define unsupported_encoding(s, insn) \
155 do { \
156 qemu_log_mask(LOG_UNIMP, \
157 "%s:%d: unsupported instruction encoding 0x%08x " \
158 "at pc=%016" PRIx64 "\n", \
159 __FILE__, __LINE__, insn, s->pc - 4); \
160 unallocated_encoding(s); \
161 } while (0);
Alexander Graf14ade102013-09-03 20:12:10 +0100162
Alexander Graf11e169d2013-12-17 19:42:32 +0000163static void init_tmp_a64_array(DisasContext *s)
164{
165#ifdef CONFIG_DEBUG_TCG
166 int i;
167 for (i = 0; i < ARRAY_SIZE(s->tmp_a64); i++) {
168 TCGV_UNUSED_I64(s->tmp_a64[i]);
169 }
170#endif
171 s->tmp_a64_count = 0;
172}
173
174static void free_tmp_a64(DisasContext *s)
175{
176 int i;
177 for (i = 0; i < s->tmp_a64_count; i++) {
178 tcg_temp_free_i64(s->tmp_a64[i]);
179 }
180 init_tmp_a64_array(s);
181}
182
183static TCGv_i64 new_tmp_a64(DisasContext *s)
184{
185 assert(s->tmp_a64_count < TMP_A64_MAX);
186 return s->tmp_a64[s->tmp_a64_count++] = tcg_temp_new_i64();
187}
188
189static TCGv_i64 new_tmp_a64_zero(DisasContext *s)
190{
191 TCGv_i64 t = new_tmp_a64(s);
192 tcg_gen_movi_i64(t, 0);
193 return t;
194}
195
196static TCGv_i64 cpu_reg(DisasContext *s, int reg)
197{
198 if (reg == 31) {
199 return new_tmp_a64_zero(s);
200 } else {
201 return cpu_X[reg];
202 }
203}
204
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000205/*
206 * the instruction disassembly implemented here matches
207 * the instruction encoding classifications in chapter 3 (C3)
208 * of the ARM Architecture Reference Manual (DDI0487A_a)
209 */
210
Alexander Graf11e169d2013-12-17 19:42:32 +0000211/* C3.2.7 Unconditional branch (immediate)
212 * 31 30 26 25 0
213 * +----+-----------+-------------------------------------+
214 * | op | 0 0 1 0 1 | imm26 |
215 * +----+-----------+-------------------------------------+
216 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000217static void disas_uncond_b_imm(DisasContext *s, uint32_t insn)
218{
Alexander Graf11e169d2013-12-17 19:42:32 +0000219 uint64_t addr = s->pc + sextract32(insn, 0, 26) * 4 - 4;
220
221 if (insn & (1 << 31)) {
222 /* C5.6.26 BL Branch with link */
223 tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
224 }
225
226 /* C5.6.20 B Branch / C5.6.26 BL Branch with link */
227 gen_goto_tb(s, 0, addr);
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000228}
229
230/* Compare & branch (immediate) */
231static void disas_comp_b_imm(DisasContext *s, uint32_t insn)
232{
233 unsupported_encoding(s, insn);
234}
235
Alexander Grafdb0f7952013-12-17 19:42:33 +0000236/* C3.2.5 Test & branch (immediate)
237 * 31 30 25 24 23 19 18 5 4 0
238 * +----+-------------+----+-------+-------------+------+
239 * | b5 | 0 1 1 0 1 1 | op | b40 | imm14 | Rt |
240 * +----+-------------+----+-------+-------------+------+
241 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000242static void disas_test_b_imm(DisasContext *s, uint32_t insn)
243{
Alexander Grafdb0f7952013-12-17 19:42:33 +0000244 unsigned int bit_pos, op, rt;
245 uint64_t addr;
246 int label_match;
247 TCGv_i64 tcg_cmp;
248
249 bit_pos = (extract32(insn, 31, 1) << 5) | extract32(insn, 19, 5);
250 op = extract32(insn, 24, 1); /* 0: TBZ; 1: TBNZ */
251 addr = s->pc + sextract32(insn, 5, 14) * 4 - 4;
252 rt = extract32(insn, 0, 5);
253
254 tcg_cmp = tcg_temp_new_i64();
255 tcg_gen_andi_i64(tcg_cmp, cpu_reg(s, rt), (1ULL << bit_pos));
256 label_match = gen_new_label();
257 tcg_gen_brcondi_i64(op ? TCG_COND_NE : TCG_COND_EQ,
258 tcg_cmp, 0, label_match);
259 tcg_temp_free_i64(tcg_cmp);
260 gen_goto_tb(s, 0, s->pc);
261 gen_set_label(label_match);
262 gen_goto_tb(s, 1, addr);
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000263}
264
Alexander Graf39fb7302013-12-17 19:42:33 +0000265/* C3.2.2 / C5.6.19 Conditional branch (immediate)
266 * 31 25 24 23 5 4 3 0
267 * +---------------+----+---------------------+----+------+
268 * | 0 1 0 1 0 1 0 | o1 | imm19 | o0 | cond |
269 * +---------------+----+---------------------+----+------+
270 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000271static void disas_cond_b_imm(DisasContext *s, uint32_t insn)
272{
Alexander Graf39fb7302013-12-17 19:42:33 +0000273 unsigned int cond;
274 uint64_t addr;
275
276 if ((insn & (1 << 4)) || (insn & (1 << 24))) {
277 unallocated_encoding(s);
278 return;
279 }
280 addr = s->pc + sextract32(insn, 5, 19) * 4 - 4;
281 cond = extract32(insn, 0, 4);
282
283 if (cond < 0x0e) {
284 /* genuinely conditional branches */
285 int label_match = gen_new_label();
286 arm_gen_test_cc(cond, label_match);
287 gen_goto_tb(s, 0, s->pc);
288 gen_set_label(label_match);
289 gen_goto_tb(s, 1, addr);
290 } else {
291 /* 0xe and 0xf are both "always" conditions */
292 gen_goto_tb(s, 0, addr);
293 }
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000294}
295
Claudio Fontana87462e02013-12-17 19:42:32 +0000296/* C5.6.68 HINT */
297static void handle_hint(DisasContext *s, uint32_t insn,
298 unsigned int op1, unsigned int op2, unsigned int crm)
299{
300 unsigned int selector = crm << 3 | op2;
301
302 if (op1 != 3) {
303 unallocated_encoding(s);
304 return;
305 }
306
307 switch (selector) {
308 case 0: /* NOP */
309 return;
310 case 1: /* YIELD */
311 case 2: /* WFE */
312 case 3: /* WFI */
313 case 4: /* SEV */
314 case 5: /* SEVL */
315 /* we treat all as NOP at least for now */
316 return;
317 default:
318 /* default specified as NOP equivalent */
319 return;
320 }
321}
322
323/* CLREX, DSB, DMB, ISB */
324static void handle_sync(DisasContext *s, uint32_t insn,
325 unsigned int op1, unsigned int op2, unsigned int crm)
326{
327 if (op1 != 3) {
328 unallocated_encoding(s);
329 return;
330 }
331
332 switch (op2) {
333 case 2: /* CLREX */
334 unsupported_encoding(s, insn);
335 return;
336 case 4: /* DSB */
337 case 5: /* DMB */
338 case 6: /* ISB */
339 /* We don't emulate caches so barriers are no-ops */
340 return;
341 default:
342 unallocated_encoding(s);
343 return;
344 }
345}
346
347/* C5.6.130 MSR (immediate) - move immediate to processor state field */
348static void handle_msr_i(DisasContext *s, uint32_t insn,
349 unsigned int op1, unsigned int op2, unsigned int crm)
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000350{
351 unsupported_encoding(s, insn);
352}
353
Claudio Fontana87462e02013-12-17 19:42:32 +0000354/* C5.6.204 SYS */
355static void handle_sys(DisasContext *s, uint32_t insn, unsigned int l,
356 unsigned int op1, unsigned int op2,
357 unsigned int crn, unsigned int crm, unsigned int rt)
358{
359 unsupported_encoding(s, insn);
360}
361
362/* C5.6.129 MRS - move from system register */
363static void handle_mrs(DisasContext *s, uint32_t insn, unsigned int op0,
364 unsigned int op1, unsigned int op2,
365 unsigned int crn, unsigned int crm, unsigned int rt)
366{
367 unsupported_encoding(s, insn);
368}
369
370/* C5.6.131 MSR (register) - move to system register */
371static void handle_msr(DisasContext *s, uint32_t insn, unsigned int op0,
372 unsigned int op1, unsigned int op2,
373 unsigned int crn, unsigned int crm, unsigned int rt)
374{
375 unsupported_encoding(s, insn);
376}
377
378/* C3.2.4 System
379 * 31 22 21 20 19 18 16 15 12 11 8 7 5 4 0
380 * +---------------------+---+-----+-----+-------+-------+-----+------+
381 * | 1 1 0 1 0 1 0 1 0 0 | L | op0 | op1 | CRn | CRm | op2 | Rt |
382 * +---------------------+---+-----+-----+-------+-------+-----+------+
383 */
384static void disas_system(DisasContext *s, uint32_t insn)
385{
386 unsigned int l, op0, op1, crn, crm, op2, rt;
387 l = extract32(insn, 21, 1);
388 op0 = extract32(insn, 19, 2);
389 op1 = extract32(insn, 16, 3);
390 crn = extract32(insn, 12, 4);
391 crm = extract32(insn, 8, 4);
392 op2 = extract32(insn, 5, 3);
393 rt = extract32(insn, 0, 5);
394
395 if (op0 == 0) {
396 if (l || rt != 31) {
397 unallocated_encoding(s);
398 return;
399 }
400 switch (crn) {
401 case 2: /* C5.6.68 HINT */
402 handle_hint(s, insn, op1, op2, crm);
403 break;
404 case 3: /* CLREX, DSB, DMB, ISB */
405 handle_sync(s, insn, op1, op2, crm);
406 break;
407 case 4: /* C5.6.130 MSR (immediate) */
408 handle_msr_i(s, insn, op1, op2, crm);
409 break;
410 default:
411 unallocated_encoding(s);
412 break;
413 }
414 return;
415 }
416
417 if (op0 == 1) {
418 /* C5.6.204 SYS */
419 handle_sys(s, insn, l, op1, op2, crn, crm, rt);
420 } else if (l) { /* op0 > 1 */
421 /* C5.6.129 MRS - move from system register */
422 handle_mrs(s, insn, op0, op1, op2, crn, crm, rt);
423 } else {
424 /* C5.6.131 MSR (register) - move to system register */
425 handle_msr(s, insn, op0, op1, op2, crn, crm, rt);
426 }
427}
428
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000429/* Exception generation */
430static void disas_exc(DisasContext *s, uint32_t insn)
431{
432 unsupported_encoding(s, insn);
433}
434
Alexander Grafb001c8c2013-12-17 19:42:33 +0000435/* C3.2.7 Unconditional branch (register)
436 * 31 25 24 21 20 16 15 10 9 5 4 0
437 * +---------------+-------+-------+-------+------+-------+
438 * | 1 1 0 1 0 1 1 | opc | op2 | op3 | Rn | op4 |
439 * +---------------+-------+-------+-------+------+-------+
440 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000441static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
442{
Alexander Grafb001c8c2013-12-17 19:42:33 +0000443 unsigned int opc, op2, op3, rn, op4;
444
445 opc = extract32(insn, 21, 4);
446 op2 = extract32(insn, 16, 5);
447 op3 = extract32(insn, 10, 6);
448 rn = extract32(insn, 5, 5);
449 op4 = extract32(insn, 0, 5);
450
451 if (op4 != 0x0 || op3 != 0x0 || op2 != 0x1f) {
452 unallocated_encoding(s);
453 return;
454 }
455
456 switch (opc) {
457 case 0: /* BR */
458 case 2: /* RET */
459 break;
460 case 1: /* BLR */
461 tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
462 break;
463 case 4: /* ERET */
464 case 5: /* DRPS */
465 if (rn != 0x1f) {
466 unallocated_encoding(s);
467 } else {
468 unsupported_encoding(s, insn);
469 }
470 return;
471 default:
472 unallocated_encoding(s);
473 return;
474 }
475
476 tcg_gen_mov_i64(cpu_pc, cpu_reg(s, rn));
477 s->is_jmp = DISAS_JUMP;
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000478}
479
480/* C3.2 Branches, exception generating and system instructions */
481static void disas_b_exc_sys(DisasContext *s, uint32_t insn)
482{
483 switch (extract32(insn, 25, 7)) {
484 case 0x0a: case 0x0b:
485 case 0x4a: case 0x4b: /* Unconditional branch (immediate) */
486 disas_uncond_b_imm(s, insn);
487 break;
488 case 0x1a: case 0x5a: /* Compare & branch (immediate) */
489 disas_comp_b_imm(s, insn);
490 break;
491 case 0x1b: case 0x5b: /* Test & branch (immediate) */
492 disas_test_b_imm(s, insn);
493 break;
494 case 0x2a: /* Conditional branch (immediate) */
495 disas_cond_b_imm(s, insn);
496 break;
497 case 0x6a: /* Exception generation / System */
498 if (insn & (1 << 24)) {
499 disas_system(s, insn);
500 } else {
501 disas_exc(s, insn);
502 }
503 break;
504 case 0x6b: /* Unconditional branch (register) */
505 disas_uncond_b_reg(s, insn);
506 break;
507 default:
508 unallocated_encoding(s);
509 break;
510 }
511}
512
513/* Load/store exclusive */
514static void disas_ldst_excl(DisasContext *s, uint32_t insn)
515{
516 unsupported_encoding(s, insn);
517}
518
519/* Load register (literal) */
520static void disas_ld_lit(DisasContext *s, uint32_t insn)
521{
522 unsupported_encoding(s, insn);
523}
524
525/* Load/store pair (all forms) */
526static void disas_ldst_pair(DisasContext *s, uint32_t insn)
527{
528 unsupported_encoding(s, insn);
529}
530
531/* Load/store register (all forms) */
532static void disas_ldst_reg(DisasContext *s, uint32_t insn)
533{
534 unsupported_encoding(s, insn);
535}
536
537/* AdvSIMD load/store multiple structures */
538static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn)
539{
540 unsupported_encoding(s, insn);
541}
542
543/* AdvSIMD load/store single structure */
544static void disas_ldst_single_struct(DisasContext *s, uint32_t insn)
545{
546 unsupported_encoding(s, insn);
547}
548
549/* C3.3 Loads and stores */
550static void disas_ldst(DisasContext *s, uint32_t insn)
551{
552 switch (extract32(insn, 24, 6)) {
553 case 0x08: /* Load/store exclusive */
554 disas_ldst_excl(s, insn);
555 break;
556 case 0x18: case 0x1c: /* Load register (literal) */
557 disas_ld_lit(s, insn);
558 break;
559 case 0x28: case 0x29:
560 case 0x2c: case 0x2d: /* Load/store pair (all forms) */
561 disas_ldst_pair(s, insn);
562 break;
563 case 0x38: case 0x39:
564 case 0x3c: case 0x3d: /* Load/store register (all forms) */
565 disas_ldst_reg(s, insn);
566 break;
567 case 0x0c: /* AdvSIMD load/store multiple structures */
568 disas_ldst_multiple_struct(s, insn);
569 break;
570 case 0x0d: /* AdvSIMD load/store single structure */
571 disas_ldst_single_struct(s, insn);
572 break;
573 default:
574 unallocated_encoding(s);
575 break;
576 }
577}
578
579/* PC-rel. addressing */
580static void disas_pc_rel_adr(DisasContext *s, uint32_t insn)
581{
582 unsupported_encoding(s, insn);
583}
584
585/* Add/subtract (immediate) */
586static void disas_add_sub_imm(DisasContext *s, uint32_t insn)
587{
588 unsupported_encoding(s, insn);
589}
590
591/* Logical (immediate) */
592static void disas_logic_imm(DisasContext *s, uint32_t insn)
593{
594 unsupported_encoding(s, insn);
595}
596
597/* Move wide (immediate) */
598static void disas_movw_imm(DisasContext *s, uint32_t insn)
599{
600 unsupported_encoding(s, insn);
601}
602
603/* Bitfield */
604static void disas_bitfield(DisasContext *s, uint32_t insn)
605{
606 unsupported_encoding(s, insn);
607}
608
609/* Extract */
610static void disas_extract(DisasContext *s, uint32_t insn)
611{
612 unsupported_encoding(s, insn);
613}
614
615/* C3.4 Data processing - immediate */
616static void disas_data_proc_imm(DisasContext *s, uint32_t insn)
617{
618 switch (extract32(insn, 23, 6)) {
619 case 0x20: case 0x21: /* PC-rel. addressing */
620 disas_pc_rel_adr(s, insn);
621 break;
622 case 0x22: case 0x23: /* Add/subtract (immediate) */
623 disas_add_sub_imm(s, insn);
624 break;
625 case 0x24: /* Logical (immediate) */
626 disas_logic_imm(s, insn);
627 break;
628 case 0x25: /* Move wide (immediate) */
629 disas_movw_imm(s, insn);
630 break;
631 case 0x26: /* Bitfield */
632 disas_bitfield(s, insn);
633 break;
634 case 0x27: /* Extract */
635 disas_extract(s, insn);
636 break;
637 default:
638 unallocated_encoding(s);
639 break;
640 }
641}
642
643/* Logical (shifted register) */
644static void disas_logic_reg(DisasContext *s, uint32_t insn)
645{
646 unsupported_encoding(s, insn);
647}
648
649/* Add/subtract (extended register) */
650static void disas_add_sub_ext_reg(DisasContext *s, uint32_t insn)
651{
652 unsupported_encoding(s, insn);
653}
654
655/* Add/subtract (shifted register) */
656static void disas_add_sub_reg(DisasContext *s, uint32_t insn)
657{
658 unsupported_encoding(s, insn);
659}
660
661/* Data-processing (3 source) */
662static void disas_data_proc_3src(DisasContext *s, uint32_t insn)
663{
664 unsupported_encoding(s, insn);
665}
666
667/* Add/subtract (with carry) */
668static void disas_adc_sbc(DisasContext *s, uint32_t insn)
669{
670 unsupported_encoding(s, insn);
671}
672
673/* Conditional compare (immediate) */
674static void disas_cc_imm(DisasContext *s, uint32_t insn)
675{
676 unsupported_encoding(s, insn);
677}
678
679/* Conditional compare (register) */
680static void disas_cc_reg(DisasContext *s, uint32_t insn)
681{
682 unsupported_encoding(s, insn);
683}
684
685/* Conditional select */
686static void disas_cond_select(DisasContext *s, uint32_t insn)
687{
688 unsupported_encoding(s, insn);
689}
690
691/* Data-processing (1 source) */
692static void disas_data_proc_1src(DisasContext *s, uint32_t insn)
693{
694 unsupported_encoding(s, insn);
695}
696
697/* Data-processing (2 source) */
698static void disas_data_proc_2src(DisasContext *s, uint32_t insn)
699{
700 unsupported_encoding(s, insn);
701}
702
703/* C3.5 Data processing - register */
704static void disas_data_proc_reg(DisasContext *s, uint32_t insn)
705{
706 switch (extract32(insn, 24, 5)) {
707 case 0x0a: /* Logical (shifted register) */
708 disas_logic_reg(s, insn);
709 break;
710 case 0x0b: /* Add/subtract */
711 if (insn & (1 << 21)) { /* (extended register) */
712 disas_add_sub_ext_reg(s, insn);
713 } else {
714 disas_add_sub_reg(s, insn);
715 }
716 break;
717 case 0x1b: /* Data-processing (3 source) */
718 disas_data_proc_3src(s, insn);
719 break;
720 case 0x1a:
721 switch (extract32(insn, 21, 3)) {
722 case 0x0: /* Add/subtract (with carry) */
723 disas_adc_sbc(s, insn);
724 break;
725 case 0x2: /* Conditional compare */
726 if (insn & (1 << 11)) { /* (immediate) */
727 disas_cc_imm(s, insn);
728 } else { /* (register) */
729 disas_cc_reg(s, insn);
730 }
731 break;
732 case 0x4: /* Conditional select */
733 disas_cond_select(s, insn);
734 break;
735 case 0x6: /* Data-processing */
736 if (insn & (1 << 30)) { /* (1 source) */
737 disas_data_proc_1src(s, insn);
738 } else { /* (2 source) */
739 disas_data_proc_2src(s, insn);
740 }
741 break;
742 default:
743 unallocated_encoding(s);
744 break;
745 }
746 break;
747 default:
748 unallocated_encoding(s);
749 break;
750 }
751}
752
753/* C3.6 Data processing - SIMD and floating point */
754static void disas_data_proc_simd_fp(DisasContext *s, uint32_t insn)
755{
756 unsupported_encoding(s, insn);
757}
758
759/* C3.1 A64 instruction index by encoding */
Peter Maydell40f860c2013-12-17 19:42:31 +0000760static void disas_a64_insn(CPUARMState *env, DisasContext *s)
Alexander Graf14ade102013-09-03 20:12:10 +0100761{
762 uint32_t insn;
763
764 insn = arm_ldl_code(env, s->pc, s->bswap_code);
765 s->insn = insn;
766 s->pc += 4;
767
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000768 switch (extract32(insn, 25, 4)) {
769 case 0x0: case 0x1: case 0x2: case 0x3: /* UNALLOCATED */
Alexander Graf14ade102013-09-03 20:12:10 +0100770 unallocated_encoding(s);
771 break;
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000772 case 0x8: case 0x9: /* Data processing - immediate */
773 disas_data_proc_imm(s, insn);
774 break;
775 case 0xa: case 0xb: /* Branch, exception generation and system insns */
776 disas_b_exc_sys(s, insn);
777 break;
778 case 0x4:
779 case 0x6:
780 case 0xc:
781 case 0xe: /* Loads and stores */
782 disas_ldst(s, insn);
783 break;
784 case 0x5:
785 case 0xd: /* Data processing - register */
786 disas_data_proc_reg(s, insn);
787 break;
788 case 0x7:
789 case 0xf: /* Data processing - SIMD and floating point */
790 disas_data_proc_simd_fp(s, insn);
791 break;
792 default:
793 assert(FALSE); /* all 15 cases should be handled above */
794 break;
Alexander Graf14ade102013-09-03 20:12:10 +0100795 }
Alexander Graf11e169d2013-12-17 19:42:32 +0000796
797 /* if we allocated any temporaries, free them here */
798 free_tmp_a64(s);
Peter Maydell40f860c2013-12-17 19:42:31 +0000799}
Alexander Graf14ade102013-09-03 20:12:10 +0100800
Peter Maydell40f860c2013-12-17 19:42:31 +0000801void gen_intermediate_code_internal_a64(ARMCPU *cpu,
802 TranslationBlock *tb,
803 bool search_pc)
804{
805 CPUState *cs = CPU(cpu);
806 CPUARMState *env = &cpu->env;
807 DisasContext dc1, *dc = &dc1;
808 CPUBreakpoint *bp;
809 uint16_t *gen_opc_end;
810 int j, lj;
811 target_ulong pc_start;
812 target_ulong next_page_start;
813 int num_insns;
814 int max_insns;
815
816 pc_start = tb->pc;
817
818 dc->tb = tb;
819
820 gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE;
821
822 dc->is_jmp = DISAS_NEXT;
823 dc->pc = pc_start;
824 dc->singlestep_enabled = cs->singlestep_enabled;
825 dc->condjmp = 0;
826
827 dc->aarch64 = 1;
828 dc->thumb = 0;
829 dc->bswap_code = 0;
830 dc->condexec_mask = 0;
831 dc->condexec_cond = 0;
832#if !defined(CONFIG_USER_ONLY)
833 dc->user = 0;
834#endif
835 dc->vfp_enabled = 0;
836 dc->vec_len = 0;
837 dc->vec_stride = 0;
838
Alexander Graf11e169d2013-12-17 19:42:32 +0000839 init_tmp_a64_array(dc);
840
Peter Maydell40f860c2013-12-17 19:42:31 +0000841 next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
842 lj = -1;
843 num_insns = 0;
844 max_insns = tb->cflags & CF_COUNT_MASK;
845 if (max_insns == 0) {
846 max_insns = CF_COUNT_MASK;
847 }
848
849 gen_tb_start();
850
851 tcg_clear_temp_count();
852
853 do {
854 if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
855 QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
856 if (bp->pc == dc->pc) {
857 gen_exception_insn(dc, 0, EXCP_DEBUG);
858 /* Advance PC so that clearing the breakpoint will
859 invalidate this TB. */
860 dc->pc += 2;
861 goto done_generating;
862 }
863 }
864 }
865
866 if (search_pc) {
867 j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
868 if (lj < j) {
869 lj++;
870 while (lj < j) {
871 tcg_ctx.gen_opc_instr_start[lj++] = 0;
872 }
873 }
874 tcg_ctx.gen_opc_pc[lj] = dc->pc;
875 tcg_ctx.gen_opc_instr_start[lj] = 1;
876 tcg_ctx.gen_opc_icount[lj] = num_insns;
877 }
878
879 if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) {
880 gen_io_start();
881 }
882
883 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) {
884 tcg_gen_debug_insn_start(dc->pc);
885 }
886
887 disas_a64_insn(env, dc);
888
889 if (tcg_check_temp_count()) {
890 fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n",
891 dc->pc);
892 }
893
894 /* Translation stops when a conditional branch is encountered.
895 * Otherwise the subsequent code could get translated several times.
896 * Also stop translation when a page boundary is reached. This
897 * ensures prefetch aborts occur at the right place.
898 */
899 num_insns++;
900 } while (!dc->is_jmp && tcg_ctx.gen_opc_ptr < gen_opc_end &&
901 !cs->singlestep_enabled &&
902 !singlestep &&
903 dc->pc < next_page_start &&
904 num_insns < max_insns);
905
906 if (tb->cflags & CF_LAST_IO) {
907 gen_io_end();
908 }
909
910 if (unlikely(cs->singlestep_enabled) && dc->is_jmp != DISAS_EXC) {
911 /* Note that this means single stepping WFI doesn't halt the CPU.
912 * For conditional branch insns this is harmless unreachable code as
913 * gen_goto_tb() has already handled emitting the debug exception
914 * (and thus a tb-jump is not possible when singlestepping).
915 */
916 assert(dc->is_jmp != DISAS_TB_JUMP);
917 if (dc->is_jmp != DISAS_JUMP) {
918 gen_a64_set_pc_im(dc->pc);
919 }
920 gen_exception(EXCP_DEBUG);
921 } else {
922 switch (dc->is_jmp) {
923 case DISAS_NEXT:
924 gen_goto_tb(dc, 1, dc->pc);
925 break;
926 default:
927 case DISAS_JUMP:
928 case DISAS_UPDATE:
929 /* indicate that the hash table must be used to find the next TB */
930 tcg_gen_exit_tb(0);
931 break;
932 case DISAS_TB_JUMP:
933 case DISAS_EXC:
934 case DISAS_SWI:
935 break;
936 case DISAS_WFI:
937 /* This is a special case because we don't want to just halt the CPU
938 * if trying to debug across a WFI.
939 */
940 gen_helper_wfi(cpu_env);
941 break;
942 }
943 }
944
945done_generating:
946 gen_tb_end(tb, num_insns);
947 *tcg_ctx.gen_opc_ptr = INDEX_op_end;
948
949#ifdef DEBUG_DISAS
950 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
951 qemu_log("----------------\n");
952 qemu_log("IN: %s\n", lookup_symbol(pc_start));
953 log_target_disas(env, pc_start, dc->pc - pc_start,
954 dc->thumb | (dc->bswap_code << 1));
955 qemu_log("\n");
956 }
957#endif
958 if (search_pc) {
959 j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
960 lj++;
961 while (lj <= j) {
962 tcg_ctx.gen_opc_instr_start[lj++] = 0;
963 }
964 } else {
965 tb->size = dc->pc - pc_start;
966 tb->icount = num_insns;
Alexander Graf14ade102013-09-03 20:12:10 +0100967 }
968}