blob: b69466585f7db3c4944d23ee265d34cab5ab7df7 [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
236/* Test & branch (immediate) */
237static void disas_test_b_imm(DisasContext *s, uint32_t insn)
238{
239 unsupported_encoding(s, insn);
240}
241
242/* Conditional branch (immediate) */
243static void disas_cond_b_imm(DisasContext *s, uint32_t insn)
244{
245 unsupported_encoding(s, insn);
246}
247
Claudio Fontana87462e02013-12-17 19:42:32 +0000248/* C5.6.68 HINT */
249static void handle_hint(DisasContext *s, uint32_t insn,
250 unsigned int op1, unsigned int op2, unsigned int crm)
251{
252 unsigned int selector = crm << 3 | op2;
253
254 if (op1 != 3) {
255 unallocated_encoding(s);
256 return;
257 }
258
259 switch (selector) {
260 case 0: /* NOP */
261 return;
262 case 1: /* YIELD */
263 case 2: /* WFE */
264 case 3: /* WFI */
265 case 4: /* SEV */
266 case 5: /* SEVL */
267 /* we treat all as NOP at least for now */
268 return;
269 default:
270 /* default specified as NOP equivalent */
271 return;
272 }
273}
274
275/* CLREX, DSB, DMB, ISB */
276static void handle_sync(DisasContext *s, uint32_t insn,
277 unsigned int op1, unsigned int op2, unsigned int crm)
278{
279 if (op1 != 3) {
280 unallocated_encoding(s);
281 return;
282 }
283
284 switch (op2) {
285 case 2: /* CLREX */
286 unsupported_encoding(s, insn);
287 return;
288 case 4: /* DSB */
289 case 5: /* DMB */
290 case 6: /* ISB */
291 /* We don't emulate caches so barriers are no-ops */
292 return;
293 default:
294 unallocated_encoding(s);
295 return;
296 }
297}
298
299/* C5.6.130 MSR (immediate) - move immediate to processor state field */
300static void handle_msr_i(DisasContext *s, uint32_t insn,
301 unsigned int op1, unsigned int op2, unsigned int crm)
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000302{
303 unsupported_encoding(s, insn);
304}
305
Claudio Fontana87462e02013-12-17 19:42:32 +0000306/* C5.6.204 SYS */
307static void handle_sys(DisasContext *s, uint32_t insn, unsigned int l,
308 unsigned int op1, unsigned int op2,
309 unsigned int crn, unsigned int crm, unsigned int rt)
310{
311 unsupported_encoding(s, insn);
312}
313
314/* C5.6.129 MRS - move from system register */
315static void handle_mrs(DisasContext *s, uint32_t insn, unsigned int op0,
316 unsigned int op1, unsigned int op2,
317 unsigned int crn, unsigned int crm, unsigned int rt)
318{
319 unsupported_encoding(s, insn);
320}
321
322/* C5.6.131 MSR (register) - move to system register */
323static void handle_msr(DisasContext *s, uint32_t insn, unsigned int op0,
324 unsigned int op1, unsigned int op2,
325 unsigned int crn, unsigned int crm, unsigned int rt)
326{
327 unsupported_encoding(s, insn);
328}
329
330/* C3.2.4 System
331 * 31 22 21 20 19 18 16 15 12 11 8 7 5 4 0
332 * +---------------------+---+-----+-----+-------+-------+-----+------+
333 * | 1 1 0 1 0 1 0 1 0 0 | L | op0 | op1 | CRn | CRm | op2 | Rt |
334 * +---------------------+---+-----+-----+-------+-------+-----+------+
335 */
336static void disas_system(DisasContext *s, uint32_t insn)
337{
338 unsigned int l, op0, op1, crn, crm, op2, rt;
339 l = extract32(insn, 21, 1);
340 op0 = extract32(insn, 19, 2);
341 op1 = extract32(insn, 16, 3);
342 crn = extract32(insn, 12, 4);
343 crm = extract32(insn, 8, 4);
344 op2 = extract32(insn, 5, 3);
345 rt = extract32(insn, 0, 5);
346
347 if (op0 == 0) {
348 if (l || rt != 31) {
349 unallocated_encoding(s);
350 return;
351 }
352 switch (crn) {
353 case 2: /* C5.6.68 HINT */
354 handle_hint(s, insn, op1, op2, crm);
355 break;
356 case 3: /* CLREX, DSB, DMB, ISB */
357 handle_sync(s, insn, op1, op2, crm);
358 break;
359 case 4: /* C5.6.130 MSR (immediate) */
360 handle_msr_i(s, insn, op1, op2, crm);
361 break;
362 default:
363 unallocated_encoding(s);
364 break;
365 }
366 return;
367 }
368
369 if (op0 == 1) {
370 /* C5.6.204 SYS */
371 handle_sys(s, insn, l, op1, op2, crn, crm, rt);
372 } else if (l) { /* op0 > 1 */
373 /* C5.6.129 MRS - move from system register */
374 handle_mrs(s, insn, op0, op1, op2, crn, crm, rt);
375 } else {
376 /* C5.6.131 MSR (register) - move to system register */
377 handle_msr(s, insn, op0, op1, op2, crn, crm, rt);
378 }
379}
380
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000381/* Exception generation */
382static void disas_exc(DisasContext *s, uint32_t insn)
383{
384 unsupported_encoding(s, insn);
385}
386
Alexander Grafb001c8c2013-12-17 19:42:33 +0000387/* C3.2.7 Unconditional branch (register)
388 * 31 25 24 21 20 16 15 10 9 5 4 0
389 * +---------------+-------+-------+-------+------+-------+
390 * | 1 1 0 1 0 1 1 | opc | op2 | op3 | Rn | op4 |
391 * +---------------+-------+-------+-------+------+-------+
392 */
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000393static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
394{
Alexander Grafb001c8c2013-12-17 19:42:33 +0000395 unsigned int opc, op2, op3, rn, op4;
396
397 opc = extract32(insn, 21, 4);
398 op2 = extract32(insn, 16, 5);
399 op3 = extract32(insn, 10, 6);
400 rn = extract32(insn, 5, 5);
401 op4 = extract32(insn, 0, 5);
402
403 if (op4 != 0x0 || op3 != 0x0 || op2 != 0x1f) {
404 unallocated_encoding(s);
405 return;
406 }
407
408 switch (opc) {
409 case 0: /* BR */
410 case 2: /* RET */
411 break;
412 case 1: /* BLR */
413 tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
414 break;
415 case 4: /* ERET */
416 case 5: /* DRPS */
417 if (rn != 0x1f) {
418 unallocated_encoding(s);
419 } else {
420 unsupported_encoding(s, insn);
421 }
422 return;
423 default:
424 unallocated_encoding(s);
425 return;
426 }
427
428 tcg_gen_mov_i64(cpu_pc, cpu_reg(s, rn));
429 s->is_jmp = DISAS_JUMP;
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000430}
431
432/* C3.2 Branches, exception generating and system instructions */
433static void disas_b_exc_sys(DisasContext *s, uint32_t insn)
434{
435 switch (extract32(insn, 25, 7)) {
436 case 0x0a: case 0x0b:
437 case 0x4a: case 0x4b: /* Unconditional branch (immediate) */
438 disas_uncond_b_imm(s, insn);
439 break;
440 case 0x1a: case 0x5a: /* Compare & branch (immediate) */
441 disas_comp_b_imm(s, insn);
442 break;
443 case 0x1b: case 0x5b: /* Test & branch (immediate) */
444 disas_test_b_imm(s, insn);
445 break;
446 case 0x2a: /* Conditional branch (immediate) */
447 disas_cond_b_imm(s, insn);
448 break;
449 case 0x6a: /* Exception generation / System */
450 if (insn & (1 << 24)) {
451 disas_system(s, insn);
452 } else {
453 disas_exc(s, insn);
454 }
455 break;
456 case 0x6b: /* Unconditional branch (register) */
457 disas_uncond_b_reg(s, insn);
458 break;
459 default:
460 unallocated_encoding(s);
461 break;
462 }
463}
464
465/* Load/store exclusive */
466static void disas_ldst_excl(DisasContext *s, uint32_t insn)
467{
468 unsupported_encoding(s, insn);
469}
470
471/* Load register (literal) */
472static void disas_ld_lit(DisasContext *s, uint32_t insn)
473{
474 unsupported_encoding(s, insn);
475}
476
477/* Load/store pair (all forms) */
478static void disas_ldst_pair(DisasContext *s, uint32_t insn)
479{
480 unsupported_encoding(s, insn);
481}
482
483/* Load/store register (all forms) */
484static void disas_ldst_reg(DisasContext *s, uint32_t insn)
485{
486 unsupported_encoding(s, insn);
487}
488
489/* AdvSIMD load/store multiple structures */
490static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn)
491{
492 unsupported_encoding(s, insn);
493}
494
495/* AdvSIMD load/store single structure */
496static void disas_ldst_single_struct(DisasContext *s, uint32_t insn)
497{
498 unsupported_encoding(s, insn);
499}
500
501/* C3.3 Loads and stores */
502static void disas_ldst(DisasContext *s, uint32_t insn)
503{
504 switch (extract32(insn, 24, 6)) {
505 case 0x08: /* Load/store exclusive */
506 disas_ldst_excl(s, insn);
507 break;
508 case 0x18: case 0x1c: /* Load register (literal) */
509 disas_ld_lit(s, insn);
510 break;
511 case 0x28: case 0x29:
512 case 0x2c: case 0x2d: /* Load/store pair (all forms) */
513 disas_ldst_pair(s, insn);
514 break;
515 case 0x38: case 0x39:
516 case 0x3c: case 0x3d: /* Load/store register (all forms) */
517 disas_ldst_reg(s, insn);
518 break;
519 case 0x0c: /* AdvSIMD load/store multiple structures */
520 disas_ldst_multiple_struct(s, insn);
521 break;
522 case 0x0d: /* AdvSIMD load/store single structure */
523 disas_ldst_single_struct(s, insn);
524 break;
525 default:
526 unallocated_encoding(s);
527 break;
528 }
529}
530
531/* PC-rel. addressing */
532static void disas_pc_rel_adr(DisasContext *s, uint32_t insn)
533{
534 unsupported_encoding(s, insn);
535}
536
537/* Add/subtract (immediate) */
538static void disas_add_sub_imm(DisasContext *s, uint32_t insn)
539{
540 unsupported_encoding(s, insn);
541}
542
543/* Logical (immediate) */
544static void disas_logic_imm(DisasContext *s, uint32_t insn)
545{
546 unsupported_encoding(s, insn);
547}
548
549/* Move wide (immediate) */
550static void disas_movw_imm(DisasContext *s, uint32_t insn)
551{
552 unsupported_encoding(s, insn);
553}
554
555/* Bitfield */
556static void disas_bitfield(DisasContext *s, uint32_t insn)
557{
558 unsupported_encoding(s, insn);
559}
560
561/* Extract */
562static void disas_extract(DisasContext *s, uint32_t insn)
563{
564 unsupported_encoding(s, insn);
565}
566
567/* C3.4 Data processing - immediate */
568static void disas_data_proc_imm(DisasContext *s, uint32_t insn)
569{
570 switch (extract32(insn, 23, 6)) {
571 case 0x20: case 0x21: /* PC-rel. addressing */
572 disas_pc_rel_adr(s, insn);
573 break;
574 case 0x22: case 0x23: /* Add/subtract (immediate) */
575 disas_add_sub_imm(s, insn);
576 break;
577 case 0x24: /* Logical (immediate) */
578 disas_logic_imm(s, insn);
579 break;
580 case 0x25: /* Move wide (immediate) */
581 disas_movw_imm(s, insn);
582 break;
583 case 0x26: /* Bitfield */
584 disas_bitfield(s, insn);
585 break;
586 case 0x27: /* Extract */
587 disas_extract(s, insn);
588 break;
589 default:
590 unallocated_encoding(s);
591 break;
592 }
593}
594
595/* Logical (shifted register) */
596static void disas_logic_reg(DisasContext *s, uint32_t insn)
597{
598 unsupported_encoding(s, insn);
599}
600
601/* Add/subtract (extended register) */
602static void disas_add_sub_ext_reg(DisasContext *s, uint32_t insn)
603{
604 unsupported_encoding(s, insn);
605}
606
607/* Add/subtract (shifted register) */
608static void disas_add_sub_reg(DisasContext *s, uint32_t insn)
609{
610 unsupported_encoding(s, insn);
611}
612
613/* Data-processing (3 source) */
614static void disas_data_proc_3src(DisasContext *s, uint32_t insn)
615{
616 unsupported_encoding(s, insn);
617}
618
619/* Add/subtract (with carry) */
620static void disas_adc_sbc(DisasContext *s, uint32_t insn)
621{
622 unsupported_encoding(s, insn);
623}
624
625/* Conditional compare (immediate) */
626static void disas_cc_imm(DisasContext *s, uint32_t insn)
627{
628 unsupported_encoding(s, insn);
629}
630
631/* Conditional compare (register) */
632static void disas_cc_reg(DisasContext *s, uint32_t insn)
633{
634 unsupported_encoding(s, insn);
635}
636
637/* Conditional select */
638static void disas_cond_select(DisasContext *s, uint32_t insn)
639{
640 unsupported_encoding(s, insn);
641}
642
643/* Data-processing (1 source) */
644static void disas_data_proc_1src(DisasContext *s, uint32_t insn)
645{
646 unsupported_encoding(s, insn);
647}
648
649/* Data-processing (2 source) */
650static void disas_data_proc_2src(DisasContext *s, uint32_t insn)
651{
652 unsupported_encoding(s, insn);
653}
654
655/* C3.5 Data processing - register */
656static void disas_data_proc_reg(DisasContext *s, uint32_t insn)
657{
658 switch (extract32(insn, 24, 5)) {
659 case 0x0a: /* Logical (shifted register) */
660 disas_logic_reg(s, insn);
661 break;
662 case 0x0b: /* Add/subtract */
663 if (insn & (1 << 21)) { /* (extended register) */
664 disas_add_sub_ext_reg(s, insn);
665 } else {
666 disas_add_sub_reg(s, insn);
667 }
668 break;
669 case 0x1b: /* Data-processing (3 source) */
670 disas_data_proc_3src(s, insn);
671 break;
672 case 0x1a:
673 switch (extract32(insn, 21, 3)) {
674 case 0x0: /* Add/subtract (with carry) */
675 disas_adc_sbc(s, insn);
676 break;
677 case 0x2: /* Conditional compare */
678 if (insn & (1 << 11)) { /* (immediate) */
679 disas_cc_imm(s, insn);
680 } else { /* (register) */
681 disas_cc_reg(s, insn);
682 }
683 break;
684 case 0x4: /* Conditional select */
685 disas_cond_select(s, insn);
686 break;
687 case 0x6: /* Data-processing */
688 if (insn & (1 << 30)) { /* (1 source) */
689 disas_data_proc_1src(s, insn);
690 } else { /* (2 source) */
691 disas_data_proc_2src(s, insn);
692 }
693 break;
694 default:
695 unallocated_encoding(s);
696 break;
697 }
698 break;
699 default:
700 unallocated_encoding(s);
701 break;
702 }
703}
704
705/* C3.6 Data processing - SIMD and floating point */
706static void disas_data_proc_simd_fp(DisasContext *s, uint32_t insn)
707{
708 unsupported_encoding(s, insn);
709}
710
711/* C3.1 A64 instruction index by encoding */
Peter Maydell40f860c2013-12-17 19:42:31 +0000712static void disas_a64_insn(CPUARMState *env, DisasContext *s)
Alexander Graf14ade102013-09-03 20:12:10 +0100713{
714 uint32_t insn;
715
716 insn = arm_ldl_code(env, s->pc, s->bswap_code);
717 s->insn = insn;
718 s->pc += 4;
719
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000720 switch (extract32(insn, 25, 4)) {
721 case 0x0: case 0x1: case 0x2: case 0x3: /* UNALLOCATED */
Alexander Graf14ade102013-09-03 20:12:10 +0100722 unallocated_encoding(s);
723 break;
Claudio Fontanaad7ee8a2013-12-17 19:42:32 +0000724 case 0x8: case 0x9: /* Data processing - immediate */
725 disas_data_proc_imm(s, insn);
726 break;
727 case 0xa: case 0xb: /* Branch, exception generation and system insns */
728 disas_b_exc_sys(s, insn);
729 break;
730 case 0x4:
731 case 0x6:
732 case 0xc:
733 case 0xe: /* Loads and stores */
734 disas_ldst(s, insn);
735 break;
736 case 0x5:
737 case 0xd: /* Data processing - register */
738 disas_data_proc_reg(s, insn);
739 break;
740 case 0x7:
741 case 0xf: /* Data processing - SIMD and floating point */
742 disas_data_proc_simd_fp(s, insn);
743 break;
744 default:
745 assert(FALSE); /* all 15 cases should be handled above */
746 break;
Alexander Graf14ade102013-09-03 20:12:10 +0100747 }
Alexander Graf11e169d2013-12-17 19:42:32 +0000748
749 /* if we allocated any temporaries, free them here */
750 free_tmp_a64(s);
Peter Maydell40f860c2013-12-17 19:42:31 +0000751}
Alexander Graf14ade102013-09-03 20:12:10 +0100752
Peter Maydell40f860c2013-12-17 19:42:31 +0000753void gen_intermediate_code_internal_a64(ARMCPU *cpu,
754 TranslationBlock *tb,
755 bool search_pc)
756{
757 CPUState *cs = CPU(cpu);
758 CPUARMState *env = &cpu->env;
759 DisasContext dc1, *dc = &dc1;
760 CPUBreakpoint *bp;
761 uint16_t *gen_opc_end;
762 int j, lj;
763 target_ulong pc_start;
764 target_ulong next_page_start;
765 int num_insns;
766 int max_insns;
767
768 pc_start = tb->pc;
769
770 dc->tb = tb;
771
772 gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE;
773
774 dc->is_jmp = DISAS_NEXT;
775 dc->pc = pc_start;
776 dc->singlestep_enabled = cs->singlestep_enabled;
777 dc->condjmp = 0;
778
779 dc->aarch64 = 1;
780 dc->thumb = 0;
781 dc->bswap_code = 0;
782 dc->condexec_mask = 0;
783 dc->condexec_cond = 0;
784#if !defined(CONFIG_USER_ONLY)
785 dc->user = 0;
786#endif
787 dc->vfp_enabled = 0;
788 dc->vec_len = 0;
789 dc->vec_stride = 0;
790
Alexander Graf11e169d2013-12-17 19:42:32 +0000791 init_tmp_a64_array(dc);
792
Peter Maydell40f860c2013-12-17 19:42:31 +0000793 next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
794 lj = -1;
795 num_insns = 0;
796 max_insns = tb->cflags & CF_COUNT_MASK;
797 if (max_insns == 0) {
798 max_insns = CF_COUNT_MASK;
799 }
800
801 gen_tb_start();
802
803 tcg_clear_temp_count();
804
805 do {
806 if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
807 QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
808 if (bp->pc == dc->pc) {
809 gen_exception_insn(dc, 0, EXCP_DEBUG);
810 /* Advance PC so that clearing the breakpoint will
811 invalidate this TB. */
812 dc->pc += 2;
813 goto done_generating;
814 }
815 }
816 }
817
818 if (search_pc) {
819 j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
820 if (lj < j) {
821 lj++;
822 while (lj < j) {
823 tcg_ctx.gen_opc_instr_start[lj++] = 0;
824 }
825 }
826 tcg_ctx.gen_opc_pc[lj] = dc->pc;
827 tcg_ctx.gen_opc_instr_start[lj] = 1;
828 tcg_ctx.gen_opc_icount[lj] = num_insns;
829 }
830
831 if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) {
832 gen_io_start();
833 }
834
835 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) {
836 tcg_gen_debug_insn_start(dc->pc);
837 }
838
839 disas_a64_insn(env, dc);
840
841 if (tcg_check_temp_count()) {
842 fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n",
843 dc->pc);
844 }
845
846 /* Translation stops when a conditional branch is encountered.
847 * Otherwise the subsequent code could get translated several times.
848 * Also stop translation when a page boundary is reached. This
849 * ensures prefetch aborts occur at the right place.
850 */
851 num_insns++;
852 } while (!dc->is_jmp && tcg_ctx.gen_opc_ptr < gen_opc_end &&
853 !cs->singlestep_enabled &&
854 !singlestep &&
855 dc->pc < next_page_start &&
856 num_insns < max_insns);
857
858 if (tb->cflags & CF_LAST_IO) {
859 gen_io_end();
860 }
861
862 if (unlikely(cs->singlestep_enabled) && dc->is_jmp != DISAS_EXC) {
863 /* Note that this means single stepping WFI doesn't halt the CPU.
864 * For conditional branch insns this is harmless unreachable code as
865 * gen_goto_tb() has already handled emitting the debug exception
866 * (and thus a tb-jump is not possible when singlestepping).
867 */
868 assert(dc->is_jmp != DISAS_TB_JUMP);
869 if (dc->is_jmp != DISAS_JUMP) {
870 gen_a64_set_pc_im(dc->pc);
871 }
872 gen_exception(EXCP_DEBUG);
873 } else {
874 switch (dc->is_jmp) {
875 case DISAS_NEXT:
876 gen_goto_tb(dc, 1, dc->pc);
877 break;
878 default:
879 case DISAS_JUMP:
880 case DISAS_UPDATE:
881 /* indicate that the hash table must be used to find the next TB */
882 tcg_gen_exit_tb(0);
883 break;
884 case DISAS_TB_JUMP:
885 case DISAS_EXC:
886 case DISAS_SWI:
887 break;
888 case DISAS_WFI:
889 /* This is a special case because we don't want to just halt the CPU
890 * if trying to debug across a WFI.
891 */
892 gen_helper_wfi(cpu_env);
893 break;
894 }
895 }
896
897done_generating:
898 gen_tb_end(tb, num_insns);
899 *tcg_ctx.gen_opc_ptr = INDEX_op_end;
900
901#ifdef DEBUG_DISAS
902 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
903 qemu_log("----------------\n");
904 qemu_log("IN: %s\n", lookup_symbol(pc_start));
905 log_target_disas(env, pc_start, dc->pc - pc_start,
906 dc->thumb | (dc->bswap_code << 1));
907 qemu_log("\n");
908 }
909#endif
910 if (search_pc) {
911 j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
912 lj++;
913 while (lj <= j) {
914 tcg_ctx.gen_opc_instr_start[lj++] = 0;
915 }
916 } else {
917 tb->size = dc->pc - pc_start;
918 tb->icount = num_insns;
Alexander Graf14ade102013-09-03 20:12:10 +0100919 }
920}