blob: c2ad810b7b69d0c3fa4b50e0b1b4ada1b584cf6a [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 Maydell089a8d92013-12-03 15:26:18 +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 Maydell6cd096b2013-11-26 17:21:48 +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 Maydell6cd096b2013-11-26 17:21:48 +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 Maydell089a8d92013-12-03 15:26:18 +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 Fontanaea5ca532013-12-03 15:12:18 +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 Fontanaea5ca532013-12-03 15:12:18 +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 Grafeeed5002013-12-03 15:12:18 +0000163static void free_tmp_a64(DisasContext *s)
164{
165 int i;
166 for (i = 0; i < s->tmp_a64_count; i++) {
167 tcg_temp_free_i64(s->tmp_a64[i]);
168 }
169 s->tmp_a64_count = 0;
170}
171
172static TCGv_i64 new_tmp_a64_zero(DisasContext *s)
173{
174 assert(s->tmp_a64_count < TMP_A64_MAX);
175 return s->tmp_a64[s->tmp_a64_count++] = tcg_const_i64(0);
176}
177
178static TCGv_i64 cpu_reg(DisasContext *s, int reg)
179{
180 if (reg == 31) {
181 return new_tmp_a64_zero(s);
182 } else {
183 return cpu_X[reg];
184 }
185}
186
Alexander Graf06905b52013-12-03 15:12:19 +0000187/* read a cpu register in 32bit/64bit mode to dst */
188static void read_cpu_reg(DisasContext *s, TCGv_i64 dst, int reg, int sf)
189{
190 if (reg == 31) {
191 tcg_gen_movi_i64(dst, 0);
192 } else if (sf) {
193 tcg_gen_mov_i64(dst, cpu_X[reg]);
194 } else { /* (!sf) */
195 tcg_gen_ext32u_i64(dst, cpu_X[reg]);
196 }
197}
198
Claudio Fontanaea5ca532013-12-03 15:12:18 +0000199/*
200 * the instruction disassembly implemented here matches
201 * the instruction encoding classifications in chapter 3 (C3)
202 * of the ARM Architecture Reference Manual (DDI0487A_a)
203 */
204
Alexander Grafeeed5002013-12-03 15:12:18 +0000205/* C3.2.7 Unconditional branch (immediate)
206 * 31 30 26 25 0
207 * +----+-----------+-------------------------------------+
208 * | op | 0 0 1 0 1 | imm26 |
209 * +----+-----------+-------------------------------------+
210 */
Claudio Fontanaea5ca532013-12-03 15:12:18 +0000211static void disas_uncond_b_imm(DisasContext *s, uint32_t insn)
212{
Alexander Grafeeed5002013-12-03 15:12:18 +0000213 uint64_t addr = s->pc + sextract32(insn, 0, 26) * 4 - 4;
214
215 if (insn & (1 << 31)) {
216 /* C5.6.26 BL Branch with link */
217 tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
218 }
219
220 /* C5.6.20 B Branch / C5.6.26 BL Branch with link */
221 gen_goto_tb(s, 0, addr);
Claudio Fontanaea5ca532013-12-03 15:12:18 +0000222}
223
Alexander Graf06905b52013-12-03 15:12:19 +0000224/* C3.2.1 Compare & branch (immediate)
225 * 31 30 25 24 23 5 4 0
226 * +----+-------------+----+---------------------+--------+
227 * | sf | 0 1 1 0 1 0 | op | imm19 | Rt |
228 * +----+-------------+----+---------------------+--------+
229 */
Claudio Fontanaea5ca532013-12-03 15:12:18 +0000230static void disas_comp_b_imm(DisasContext *s, uint32_t insn)
231{
Alexander Graf06905b52013-12-03 15:12:19 +0000232 unsigned int sf, op, rt;
233 uint64_t addr;
234 int label_nomatch;
235 TCGv_i64 tcg_cmp;
236
237 sf = extract32(insn, 31, 1);
238 op = extract32(insn, 24, 1);
239 rt = extract32(insn, 0, 5);
240 addr = s->pc + sextract32(insn, 5, 19) * 4 - 4;
241
242 tcg_cmp = tcg_temp_new_i64();
243 read_cpu_reg(s, tcg_cmp, rt, sf);
244 label_nomatch = gen_new_label();
245
246 if (op) { /* CBNZ */
247 tcg_gen_brcondi_i64(TCG_COND_EQ, tcg_cmp, 0, label_nomatch);
248 } else { /* CBZ */
249 tcg_gen_brcondi_i64(TCG_COND_NE, tcg_cmp, 0, label_nomatch);
250 }
251
252 tcg_temp_free_i64(tcg_cmp);
253
254 gen_goto_tb(s, 0, addr);
255 gen_set_label(label_nomatch);
256 gen_goto_tb(s, 1, s->pc);
Claudio Fontanaea5ca532013-12-03 15:12:18 +0000257}
258
Alexander Grafee52d8c2013-12-03 15:12:19 +0000259/* C3.2.5 Test & branch (immediate)
260 * 31 30 25 24 23 19 18 5 4 0
261 * +----+-------------+----+-------+-------------+------+
262 * | b5 | 0 1 1 0 1 1 | op | b40 | imm14 | Rt |
263 * +----+-------------+----+-------+-------------+------+
264 */
Claudio Fontanaea5ca532013-12-03 15:12:18 +0000265static void disas_test_b_imm(DisasContext *s, uint32_t insn)
266{
Alexander Grafee52d8c2013-12-03 15:12:19 +0000267 unsigned int bit_pos, op, rt;
268 uint64_t addr;
269 int label_nomatch;
270 TCGv_i64 tcg_cmp;
271
272 bit_pos = (extract32(insn, 31, 1) << 5) | extract32(insn, 19, 5);
273 op = extract32(insn, 24, 1);
274 addr = s->pc + sextract32(insn, 5, 14) * 4 - 4;
275 rt = extract32(insn, 0, 5);
276
277 tcg_cmp = tcg_temp_new_i64();
278 tcg_gen_andi_i64(tcg_cmp, cpu_reg(s, rt), (1ULL << bit_pos));
279 label_nomatch = gen_new_label();
280 if (op) { /* TBNZ */
281 tcg_gen_brcondi_i64(TCG_COND_EQ, tcg_cmp, 0, label_nomatch);
282 } else { /* TBZ */
283 tcg_gen_brcondi_i64(TCG_COND_NE, tcg_cmp, 0, label_nomatch);
284 }
285 tcg_temp_free_i64(tcg_cmp);
286 gen_goto_tb(s, 0, addr);
287 gen_set_label(label_nomatch);
288 gen_goto_tb(s, 1, s->pc);
Claudio Fontanaea5ca532013-12-03 15:12:18 +0000289}
290
Alexander Grafd0deb6c2013-12-03 15:12:18 +0000291/* C3.2.2 / C5.6.19 Conditional branch (immediate)
292 * 31 25 24 23 5 4 3 0
293 * +---------------+----+---------------------+----+------+
294 * | 0 1 0 1 0 1 0 | o1 | imm19 | o0 | cond |
295 * +---------------+----+---------------------+----+------+
296 */
Claudio Fontanaea5ca532013-12-03 15:12:18 +0000297static void disas_cond_b_imm(DisasContext *s, uint32_t insn)
298{
Alexander Grafd0deb6c2013-12-03 15:12:18 +0000299 unsigned int cond;
300 uint64_t addr;
301
302 if ((insn & (1 << 4)) || (insn & (1 << 24))) {
303 unallocated_encoding(s);
304 return;
305 }
306 addr = s->pc + sextract32(insn, 5, 19) * 4 - 4;
307 cond = extract32(insn, 0, 4);
308
309 if (cond < 0x0e) {
310 /* genuinely conditional branches */
311 int label_nomatch = gen_new_label();
312 arm_gen_test_cc(cond ^ 1, label_nomatch);
313 gen_goto_tb(s, 0, addr);
314 gen_set_label(label_nomatch);
315 gen_goto_tb(s, 1, s->pc);
316 } else {
317 /* 0xe and 0xf are both "always" conditions */
318 gen_goto_tb(s, 0, addr);
319 }
Claudio Fontanaea5ca532013-12-03 15:12:18 +0000320}
321
Claudio Fontana20b3f312013-12-03 15:12:18 +0000322/* C5.6.68 HINT */
323static void handle_hint(DisasContext *s, uint32_t insn,
324 unsigned int op1, unsigned int op2, unsigned int crm)
325{
326 unsigned int selector = crm << 3 | op2;
327
328 if (op1 != 3) {
329 unallocated_encoding(s);
330 return;
331 }
332
333 switch (selector) {
334 case 0: /* NOP */
335 return;
336 case 1: /* YIELD */
337 case 2: /* WFE */
338 case 3: /* WFI */
339 case 4: /* SEV */
340 case 5: /* SEVL */
341 /* we treat all as NOP at least for now */
342 return;
343 default:
344 /* default specified as NOP equivalent */
345 return;
346 }
347}
348
349/* CLREX, DSB, DMB, ISB */
350static void handle_sync(DisasContext *s, uint32_t insn,
351 unsigned int op1, unsigned int op2, unsigned int crm)
352{
353 if (op1 != 3) {
354 unallocated_encoding(s);
355 return;
356 }
357
358 switch (op2) {
359 case 2: /* CLREX */
360 unsupported_encoding(s, insn);
361 return;
362 case 4: /* DSB */
363 case 5: /* DMB */
364 case 6: /* ISB */
365 /* We don't emulate caches so barriers are no-ops */
366 return;
367 default:
368 unallocated_encoding(s);
369 return;
370 }
371}
372
373/* C5.6.130 MSR (immediate) - move immediate to processor state field */
374static void handle_msr_i(DisasContext *s, uint32_t insn,
375 unsigned int op1, unsigned int op2, unsigned int crm)
Claudio Fontanaea5ca532013-12-03 15:12:18 +0000376{
377 unsupported_encoding(s, insn);
378}
379
Claudio Fontana20b3f312013-12-03 15:12:18 +0000380/* C5.6.204 SYS */
381static void handle_sys(DisasContext *s, uint32_t insn, unsigned int l,
382 unsigned int op1, unsigned int op2,
383 unsigned int crn, unsigned int crm, unsigned int rt)
384{
385 unsupported_encoding(s, insn);
386}
387
388/* C5.6.129 MRS - move from system register */
389static void handle_mrs(DisasContext *s, uint32_t insn, unsigned int op0,
390 unsigned int op1, unsigned int op2,
391 unsigned int crn, unsigned int crm, unsigned int rt)
392{
393 unsupported_encoding(s, insn);
394}
395
396/* C5.6.131 MSR (register) - move to system register */
397static void handle_msr(DisasContext *s, uint32_t insn, unsigned int op0,
398 unsigned int op1, unsigned int op2,
399 unsigned int crn, unsigned int crm, unsigned int rt)
400{
401 unsupported_encoding(s, insn);
402}
403
404/* C3.2.4 System */
405static void disas_system(DisasContext *s, uint32_t insn)
406{
407 /*
408 * 31 30 29 28 27 26 25 24 23 22 21 20 19 18 16 15 12 11 8 7 5 4 0
409 * 1 1 0 1 0 1 0 1 0 0 L op0 op1 CRn CRm op2 Rt
410 */
411 unsigned int l, op0, op1, crn, crm, op2, rt;
412 l = extract32(insn, 21, 1);
413 op0 = extract32(insn, 19, 2);
414 op1 = extract32(insn, 16, 3);
415 crn = extract32(insn, 12, 4);
416 crm = extract32(insn, 8, 4);
417 op2 = extract32(insn, 5, 3);
418 rt = extract32(insn, 0, 5);
419
420 if (op0 == 0) {
421 if (l || rt != 31) {
422 unallocated_encoding(s);
423 return;
424 }
425 switch (crn) {
426 case 2: /* C5.6.68 HINT */
427 handle_hint(s, insn, op1, op2, crm);
428 break;
429 case 3: /* CLREX, DSB, DMB, ISB */
430 handle_sync(s, insn, op1, op2, crm);
431 break;
432 case 4: /* C5.6.130 MSR (immediate) */
433 handle_msr_i(s, insn, op1, op2, crm);
434 break;
435 default:
436 unallocated_encoding(s);
437 break;
438 }
439 return;
440 }
441
442 if (op0 == 1) {
443 /* C5.6.204 SYS */
444 handle_sys(s, insn, l, op1, op2, crn, crm, rt);
445 } else if (l) { /* op0 > 1 */
446 /* C5.6.129 MRS - move from system register */
447 handle_mrs(s, insn, op0, op1, op2, crn, crm, rt);
448 } else {
449 /* C5.6.131 MSR (register) - move to system register */
450 handle_msr(s, insn, op0, op1, op2, crn, crm, rt);
451 }
452}
453
Claudio Fontanaea5ca532013-12-03 15:12:18 +0000454/* Exception generation */
455static void disas_exc(DisasContext *s, uint32_t insn)
456{
457 unsupported_encoding(s, insn);
458}
459
Alexander Graf37699832013-12-03 15:12:18 +0000460/* C3.2.7 Unconditional branch (register)
461 * 31 25 24 21 20 16 15 10 9 5 4 0
462 * +---------------+-------+-------+-------+------+-------+
463 * | 1 1 0 1 0 1 1 | opc | op2 | op3 | Rn | op4 |
464 * +---------------+-------+-------+-------+------+-------+
465 */
Claudio Fontanaea5ca532013-12-03 15:12:18 +0000466static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
467{
Alexander Graf37699832013-12-03 15:12:18 +0000468 unsigned int opc, op2, op3, rn, op4;
469
470 opc = extract32(insn, 21, 4);
471 op2 = extract32(insn, 16, 5);
472 op3 = extract32(insn, 10, 6);
473 rn = extract32(insn, 5, 5);
474 op4 = extract32(insn, 0, 5);
475
476 if (op4 != 0x0 || op3 != 0x0 || op2 != 0x1f) {
477 unallocated_encoding(s);
478 return;
479 }
480
481 switch (opc) {
482 case 0: /* BR */
483 case 2: /* RET */
484 break;
485 case 1: /* BLR */
486 tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
487 break;
488 case 4: /* ERET */
489 case 5: /* DRPS */
490 if (rn != 0x1f) {
491 unallocated_encoding(s);
492 } else {
493 unsupported_encoding(s, insn);
494 }
495 return;
496 default:
497 unallocated_encoding(s);
498 return;
499 }
500
501 tcg_gen_mov_i64(cpu_pc, cpu_reg(s, rn));
502 s->is_jmp = DISAS_JUMP;
Claudio Fontanaea5ca532013-12-03 15:12:18 +0000503}
504
505/* C3.2 Branches, exception generating and system instructions */
506static void disas_b_exc_sys(DisasContext *s, uint32_t insn)
507{
508 switch (extract32(insn, 25, 7)) {
509 case 0x0a: case 0x0b:
510 case 0x4a: case 0x4b: /* Unconditional branch (immediate) */
511 disas_uncond_b_imm(s, insn);
512 break;
513 case 0x1a: case 0x5a: /* Compare & branch (immediate) */
514 disas_comp_b_imm(s, insn);
515 break;
516 case 0x1b: case 0x5b: /* Test & branch (immediate) */
517 disas_test_b_imm(s, insn);
518 break;
519 case 0x2a: /* Conditional branch (immediate) */
520 disas_cond_b_imm(s, insn);
521 break;
522 case 0x6a: /* Exception generation / System */
523 if (insn & (1 << 24)) {
524 disas_system(s, insn);
525 } else {
526 disas_exc(s, insn);
527 }
528 break;
529 case 0x6b: /* Unconditional branch (register) */
530 disas_uncond_b_reg(s, insn);
531 break;
532 default:
533 unallocated_encoding(s);
534 break;
535 }
536}
537
538/* Load/store exclusive */
539static void disas_ldst_excl(DisasContext *s, uint32_t insn)
540{
541 unsupported_encoding(s, insn);
542}
543
544/* Load register (literal) */
545static void disas_ld_lit(DisasContext *s, uint32_t insn)
546{
547 unsupported_encoding(s, insn);
548}
549
550/* Load/store pair (all forms) */
551static void disas_ldst_pair(DisasContext *s, uint32_t insn)
552{
553 unsupported_encoding(s, insn);
554}
555
556/* Load/store register (all forms) */
557static void disas_ldst_reg(DisasContext *s, uint32_t insn)
558{
559 unsupported_encoding(s, insn);
560}
561
562/* AdvSIMD load/store multiple structures */
563static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn)
564{
565 unsupported_encoding(s, insn);
566}
567
568/* AdvSIMD load/store single structure */
569static void disas_ldst_single_struct(DisasContext *s, uint32_t insn)
570{
571 unsupported_encoding(s, insn);
572}
573
574/* C3.3 Loads and stores */
575static void disas_ldst(DisasContext *s, uint32_t insn)
576{
577 switch (extract32(insn, 24, 6)) {
578 case 0x08: /* Load/store exclusive */
579 disas_ldst_excl(s, insn);
580 break;
581 case 0x18: case 0x1c: /* Load register (literal) */
582 disas_ld_lit(s, insn);
583 break;
584 case 0x28: case 0x29:
585 case 0x2c: case 0x2d: /* Load/store pair (all forms) */
586 disas_ldst_pair(s, insn);
587 break;
588 case 0x38: case 0x39:
589 case 0x3c: case 0x3d: /* Load/store register (all forms) */
590 disas_ldst_reg(s, insn);
591 break;
592 case 0x0c: /* AdvSIMD load/store multiple structures */
593 disas_ldst_multiple_struct(s, insn);
594 break;
595 case 0x0d: /* AdvSIMD load/store single structure */
596 disas_ldst_single_struct(s, insn);
597 break;
598 default:
599 unallocated_encoding(s);
600 break;
601 }
602}
603
604/* PC-rel. addressing */
605static void disas_pc_rel_adr(DisasContext *s, uint32_t insn)
606{
607 unsupported_encoding(s, insn);
608}
609
610/* Add/subtract (immediate) */
611static void disas_add_sub_imm(DisasContext *s, uint32_t insn)
612{
613 unsupported_encoding(s, insn);
614}
615
616/* Logical (immediate) */
617static void disas_logic_imm(DisasContext *s, uint32_t insn)
618{
619 unsupported_encoding(s, insn);
620}
621
622/* Move wide (immediate) */
623static void disas_movw_imm(DisasContext *s, uint32_t insn)
624{
625 unsupported_encoding(s, insn);
626}
627
628/* Bitfield */
629static void disas_bitfield(DisasContext *s, uint32_t insn)
630{
631 unsupported_encoding(s, insn);
632}
633
634/* Extract */
635static void disas_extract(DisasContext *s, uint32_t insn)
636{
637 unsupported_encoding(s, insn);
638}
639
640/* C3.4 Data processing - immediate */
641static void disas_data_proc_imm(DisasContext *s, uint32_t insn)
642{
643 switch (extract32(insn, 23, 6)) {
644 case 0x20: case 0x21: /* PC-rel. addressing */
645 disas_pc_rel_adr(s, insn);
646 break;
647 case 0x22: case 0x23: /* Add/subtract (immediate) */
648 disas_add_sub_imm(s, insn);
649 break;
650 case 0x24: /* Logical (immediate) */
651 disas_logic_imm(s, insn);
652 break;
653 case 0x25: /* Move wide (immediate) */
654 disas_movw_imm(s, insn);
655 break;
656 case 0x26: /* Bitfield */
657 disas_bitfield(s, insn);
658 break;
659 case 0x27: /* Extract */
660 disas_extract(s, insn);
661 break;
662 default:
663 unallocated_encoding(s);
664 break;
665 }
666}
667
668/* Logical (shifted register) */
669static void disas_logic_reg(DisasContext *s, uint32_t insn)
670{
671 unsupported_encoding(s, insn);
672}
673
674/* Add/subtract (extended register) */
675static void disas_add_sub_ext_reg(DisasContext *s, uint32_t insn)
676{
677 unsupported_encoding(s, insn);
678}
679
680/* Add/subtract (shifted register) */
681static void disas_add_sub_reg(DisasContext *s, uint32_t insn)
682{
683 unsupported_encoding(s, insn);
684}
685
686/* Data-processing (3 source) */
687static void disas_data_proc_3src(DisasContext *s, uint32_t insn)
688{
689 unsupported_encoding(s, insn);
690}
691
692/* Add/subtract (with carry) */
693static void disas_adc_sbc(DisasContext *s, uint32_t insn)
694{
695 unsupported_encoding(s, insn);
696}
697
698/* Conditional compare (immediate) */
699static void disas_cc_imm(DisasContext *s, uint32_t insn)
700{
701 unsupported_encoding(s, insn);
702}
703
704/* Conditional compare (register) */
705static void disas_cc_reg(DisasContext *s, uint32_t insn)
706{
707 unsupported_encoding(s, insn);
708}
709
Claudio Fontana926f3f32013-12-03 15:12:19 +0000710/* C3.5.6 Conditional select */
Claudio Fontanaea5ca532013-12-03 15:12:18 +0000711static void disas_cond_select(DisasContext *s, uint32_t insn)
712{
Claudio Fontana926f3f32013-12-03 15:12:19 +0000713 /*
714 * 31 30 29 28 27 26 25 24 23 22 21 20 16 15 12 11 10 9 5 4 0
715 * sf op S 1 1 0 1 0 1 0 0 Rm cond op2 Rn Rd
716 * [0]
717 * op -> else_inv, op2 -> else_inc
718 */
719 unsigned int sf, else_inv, rm, cond, else_inc, rn, rd;
720 TCGv_i64 tcg_rd;
721 if (extract32(insn, 21, 9) != 0x0d4 || (insn & (1 << 11))) {
722 unallocated_encoding(s);
723 return;
724 }
725 sf = (insn & (1 << 31)) ? 1 : 0;
726 else_inv = extract32(insn, 30, 1);
727 rm = extract32(insn, 16, 5);
728 cond = extract32(insn, 12, 4);
729 else_inc = extract32(insn, 10, 1);
730 rn = extract32(insn, 5, 5);
731 rd = extract32(insn, 0, 5);
732 tcg_rd = cpu_reg(s, rd);
733
734 if (cond >= 0x0e) { /* condition "always" */
735 read_cpu_reg(s, tcg_rd, rn, sf);
736 } else {
737 int label_nomatch, label_continue;
738 label_nomatch = gen_new_label();
739 label_continue = gen_new_label();
740
741 arm_gen_test_cc(cond ^ 1, label_nomatch);
742 /* match: */
743 read_cpu_reg(s, tcg_rd, rn, sf);
744 tcg_gen_br(label_continue);
745 /* nomatch: */
746 gen_set_label(label_nomatch);
747 read_cpu_reg(s, tcg_rd, rm, sf);
748 if (else_inv) {
749 tcg_gen_not_i64(tcg_rd, tcg_rd);
750 }
751 if (else_inc) {
752 tcg_gen_addi_i64(tcg_rd, tcg_rd, 1);
753 }
754 if (!sf) {
755 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
756 }
757 /* continue: */
758 gen_set_label(label_continue);
759 }
Claudio Fontanaea5ca532013-12-03 15:12:18 +0000760}
761
762/* Data-processing (1 source) */
763static void disas_data_proc_1src(DisasContext *s, uint32_t insn)
764{
765 unsupported_encoding(s, insn);
766}
767
768/* Data-processing (2 source) */
769static void disas_data_proc_2src(DisasContext *s, uint32_t insn)
770{
771 unsupported_encoding(s, insn);
772}
773
774/* C3.5 Data processing - register */
775static void disas_data_proc_reg(DisasContext *s, uint32_t insn)
776{
777 switch (extract32(insn, 24, 5)) {
778 case 0x0a: /* Logical (shifted register) */
779 disas_logic_reg(s, insn);
780 break;
781 case 0x0b: /* Add/subtract */
782 if (insn & (1 << 21)) { /* (extended register) */
783 disas_add_sub_ext_reg(s, insn);
784 } else {
785 disas_add_sub_reg(s, insn);
786 }
787 break;
788 case 0x1b: /* Data-processing (3 source) */
789 disas_data_proc_3src(s, insn);
790 break;
791 case 0x1a:
792 switch (extract32(insn, 21, 3)) {
793 case 0x0: /* Add/subtract (with carry) */
794 disas_adc_sbc(s, insn);
795 break;
796 case 0x2: /* Conditional compare */
797 if (insn & (1 << 11)) { /* (immediate) */
798 disas_cc_imm(s, insn);
799 } else { /* (register) */
800 disas_cc_reg(s, insn);
801 }
802 break;
803 case 0x4: /* Conditional select */
804 disas_cond_select(s, insn);
805 break;
806 case 0x6: /* Data-processing */
807 if (insn & (1 << 30)) { /* (1 source) */
808 disas_data_proc_1src(s, insn);
809 } else { /* (2 source) */
810 disas_data_proc_2src(s, insn);
811 }
812 break;
813 default:
814 unallocated_encoding(s);
815 break;
816 }
817 break;
818 default:
819 unallocated_encoding(s);
820 break;
821 }
822}
823
824/* C3.6 Data processing - SIMD and floating point */
825static void disas_data_proc_simd_fp(DisasContext *s, uint32_t insn)
826{
827 unsupported_encoding(s, insn);
828}
829
830/* C3.1 A64 instruction index by encoding */
Peter Maydell089a8d92013-12-03 15:26:18 +0000831static void disas_a64_insn(CPUARMState *env, DisasContext *s)
Alexander Graf14ade102013-09-03 20:12:10 +0100832{
833 uint32_t insn;
834
835 insn = arm_ldl_code(env, s->pc, s->bswap_code);
836 s->insn = insn;
837 s->pc += 4;
838
Claudio Fontanaea5ca532013-12-03 15:12:18 +0000839 switch (extract32(insn, 25, 4)) {
840 case 0x0: case 0x1: case 0x2: case 0x3: /* UNALLOCATED */
Alexander Graf14ade102013-09-03 20:12:10 +0100841 unallocated_encoding(s);
842 break;
Claudio Fontanaea5ca532013-12-03 15:12:18 +0000843 case 0x8: case 0x9: /* Data processing - immediate */
844 disas_data_proc_imm(s, insn);
845 break;
846 case 0xa: case 0xb: /* Branch, exception generation and system insns */
847 disas_b_exc_sys(s, insn);
848 break;
849 case 0x4:
850 case 0x6:
851 case 0xc:
852 case 0xe: /* Loads and stores */
853 disas_ldst(s, insn);
854 break;
855 case 0x5:
856 case 0xd: /* Data processing - register */
857 disas_data_proc_reg(s, insn);
858 break;
859 case 0x7:
860 case 0xf: /* Data processing - SIMD and floating point */
861 disas_data_proc_simd_fp(s, insn);
862 break;
863 default:
864 assert(FALSE); /* all 15 cases should be handled above */
865 break;
Alexander Graf14ade102013-09-03 20:12:10 +0100866 }
Alexander Grafeeed5002013-12-03 15:12:18 +0000867
868 /* if we allocated any temporaries, free them here */
869 free_tmp_a64(s);
Peter Maydell089a8d92013-12-03 15:26:18 +0000870}
Alexander Graf14ade102013-09-03 20:12:10 +0100871
Peter Maydell089a8d92013-12-03 15:26:18 +0000872void gen_intermediate_code_internal_a64(ARMCPU *cpu,
873 TranslationBlock *tb,
874 bool search_pc)
875{
876 CPUState *cs = CPU(cpu);
877 CPUARMState *env = &cpu->env;
878 DisasContext dc1, *dc = &dc1;
879 CPUBreakpoint *bp;
880 uint16_t *gen_opc_end;
881 int j, lj;
882 target_ulong pc_start;
883 target_ulong next_page_start;
884 int num_insns;
885 int max_insns;
886
887 pc_start = tb->pc;
888
889 dc->tb = tb;
890
891 gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE;
892
893 dc->is_jmp = DISAS_NEXT;
894 dc->pc = pc_start;
895 dc->singlestep_enabled = cs->singlestep_enabled;
896 dc->condjmp = 0;
897
898 dc->aarch64 = 1;
Alexander Grafeeed5002013-12-03 15:12:18 +0000899 dc->tmp_a64_count = 0;
Peter Maydell089a8d92013-12-03 15:26:18 +0000900 dc->thumb = 0;
901 dc->bswap_code = 0;
902 dc->condexec_mask = 0;
903 dc->condexec_cond = 0;
904#if !defined(CONFIG_USER_ONLY)
905 dc->user = 0;
906#endif
907 dc->vfp_enabled = 0;
908 dc->vec_len = 0;
909 dc->vec_stride = 0;
910
911 next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
912 lj = -1;
913 num_insns = 0;
914 max_insns = tb->cflags & CF_COUNT_MASK;
915 if (max_insns == 0) {
916 max_insns = CF_COUNT_MASK;
917 }
918
919 gen_tb_start();
920
921 tcg_clear_temp_count();
922
923 do {
924 if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
925 QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
926 if (bp->pc == dc->pc) {
927 gen_exception_insn(dc, 0, EXCP_DEBUG);
928 /* Advance PC so that clearing the breakpoint will
929 invalidate this TB. */
930 dc->pc += 2;
931 goto done_generating;
932 }
933 }
934 }
935
936 if (search_pc) {
937 j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
938 if (lj < j) {
939 lj++;
940 while (lj < j) {
941 tcg_ctx.gen_opc_instr_start[lj++] = 0;
942 }
943 }
944 tcg_ctx.gen_opc_pc[lj] = dc->pc;
945 tcg_ctx.gen_opc_instr_start[lj] = 1;
946 tcg_ctx.gen_opc_icount[lj] = num_insns;
947 }
948
949 if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) {
950 gen_io_start();
951 }
952
953 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) {
954 tcg_gen_debug_insn_start(dc->pc);
955 }
956
957 disas_a64_insn(env, dc);
958
959 if (tcg_check_temp_count()) {
960 fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n",
961 dc->pc);
962 }
963
964 /* Translation stops when a conditional branch is encountered.
965 * Otherwise the subsequent code could get translated several times.
966 * Also stop translation when a page boundary is reached. This
967 * ensures prefetch aborts occur at the right place.
968 */
969 num_insns++;
970 } while (!dc->is_jmp && tcg_ctx.gen_opc_ptr < gen_opc_end &&
971 !cs->singlestep_enabled &&
972 !singlestep &&
973 dc->pc < next_page_start &&
974 num_insns < max_insns);
975
976 if (tb->cflags & CF_LAST_IO) {
977 gen_io_end();
978 }
979
980 if (unlikely(cs->singlestep_enabled) && dc->is_jmp != DISAS_EXC) {
981 /* Note that this means single stepping WFI doesn't halt the CPU.
982 * For conditional branch insns this is harmless unreachable code as
983 * gen_goto_tb() has already handled emitting the debug exception
984 * (and thus a tb-jump is not possible when singlestepping).
985 */
986 assert(dc->is_jmp != DISAS_TB_JUMP);
987 if (dc->is_jmp != DISAS_JUMP) {
988 gen_a64_set_pc_im(dc->pc);
989 }
990 gen_exception(EXCP_DEBUG);
991 } else {
992 switch (dc->is_jmp) {
993 case DISAS_NEXT:
994 gen_goto_tb(dc, 1, dc->pc);
995 break;
996 default:
997 case DISAS_JUMP:
998 case DISAS_UPDATE:
999 /* indicate that the hash table must be used to find the next TB */
1000 tcg_gen_exit_tb(0);
1001 break;
1002 case DISAS_TB_JUMP:
1003 case DISAS_EXC:
1004 case DISAS_SWI:
1005 break;
1006 case DISAS_WFI:
1007 /* This is a special case because we don't want to just halt the CPU
1008 * if trying to debug across a WFI.
1009 */
1010 gen_helper_wfi(cpu_env);
1011 break;
1012 }
1013 }
1014
1015done_generating:
1016 gen_tb_end(tb, num_insns);
1017 *tcg_ctx.gen_opc_ptr = INDEX_op_end;
1018
1019#ifdef DEBUG_DISAS
1020 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
1021 qemu_log("----------------\n");
1022 qemu_log("IN: %s\n", lookup_symbol(pc_start));
1023 log_target_disas(env, pc_start, dc->pc - pc_start,
1024 dc->thumb | (dc->bswap_code << 1));
1025 qemu_log("\n");
1026 }
1027#endif
1028 if (search_pc) {
1029 j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
1030 lj++;
1031 while (lj <= j) {
1032 tcg_ctx.gen_opc_instr_start[lj++] = 0;
1033 }
1034 } else {
1035 tb->size = dc->pc - pc_start;
1036 tb->icount = num_insns;
Alexander Graf14ade102013-09-03 20:12:10 +01001037 }
1038}