target-xtensa: implement disas_xtensa_insn
[qemu.git] / target-xtensa / translate.c
blob0524dc7f5245f84c0d0474a7ad259e41edeb4476
1 /*
2 * Xtensa ISA:
3 * http://www.tensilica.com/products/literature-docs/documentation/xtensa-isa-databook.htm
5 * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of the Open Source and Linux Lab nor the
16 * names of its contributors may be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <stdio.h>
33 #include "cpu.h"
34 #include "exec-all.h"
35 #include "disas.h"
36 #include "tcg-op.h"
37 #include "qemu-log.h"
39 #include "helpers.h"
40 #define GEN_HELPER 1
41 #include "helpers.h"
43 typedef struct DisasContext {
44 const XtensaConfig *config;
45 TranslationBlock *tb;
46 uint32_t pc;
47 uint32_t next_pc;
48 int is_jmp;
49 int singlestep_enabled;
50 } DisasContext;
52 static TCGv_ptr cpu_env;
53 static TCGv_i32 cpu_pc;
54 static TCGv_i32 cpu_R[16];
56 #include "gen-icount.h"
58 void xtensa_translate_init(void)
60 static const char * const regnames[] = {
61 "ar0", "ar1", "ar2", "ar3",
62 "ar4", "ar5", "ar6", "ar7",
63 "ar8", "ar9", "ar10", "ar11",
64 "ar12", "ar13", "ar14", "ar15",
66 int i;
68 cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
69 cpu_pc = tcg_global_mem_new_i32(TCG_AREG0,
70 offsetof(CPUState, pc), "pc");
72 for (i = 0; i < 16; i++) {
73 cpu_R[i] = tcg_global_mem_new_i32(TCG_AREG0,
74 offsetof(CPUState, regs[i]),
75 regnames[i]);
77 #define GEN_HELPER 2
78 #include "helpers.h"
81 static inline bool option_enabled(DisasContext *dc, int opt)
83 return xtensa_option_enabled(dc->config, opt);
86 static void gen_exception(int excp)
88 TCGv_i32 tmp = tcg_const_i32(excp);
89 gen_helper_exception(tmp);
90 tcg_temp_free(tmp);
93 static void gen_jump_slot(DisasContext *dc, TCGv dest, int slot)
95 tcg_gen_mov_i32(cpu_pc, dest);
96 if (dc->singlestep_enabled) {
97 gen_exception(EXCP_DEBUG);
98 } else {
99 if (slot >= 0) {
100 tcg_gen_goto_tb(slot);
101 tcg_gen_exit_tb((tcg_target_long)dc->tb + slot);
102 } else {
103 tcg_gen_exit_tb(0);
106 dc->is_jmp = DISAS_UPDATE;
109 static void gen_jumpi(DisasContext *dc, uint32_t dest, int slot)
111 TCGv_i32 tmp = tcg_const_i32(dest);
112 if (((dc->pc ^ dest) & TARGET_PAGE_MASK) != 0) {
113 slot = -1;
115 gen_jump_slot(dc, tmp, slot);
116 tcg_temp_free(tmp);
119 static void disas_xtensa_insn(DisasContext *dc)
121 #define HAS_OPTION(opt) do { \
122 if (!option_enabled(dc, opt)) { \
123 qemu_log("Option %d is not enabled %s:%d\n", \
124 (opt), __FILE__, __LINE__); \
125 goto invalid_opcode; \
127 } while (0)
129 #ifdef TARGET_WORDS_BIGENDIAN
130 #define OP0 (((b0) & 0xf0) >> 4)
131 #define OP1 (((b2) & 0xf0) >> 4)
132 #define OP2 ((b2) & 0xf)
133 #define RRR_R ((b1) & 0xf)
134 #define RRR_S (((b1) & 0xf0) >> 4)
135 #define RRR_T ((b0) & 0xf)
136 #else
137 #define OP0 (((b0) & 0xf))
138 #define OP1 (((b2) & 0xf))
139 #define OP2 (((b2) & 0xf0) >> 4)
140 #define RRR_R (((b1) & 0xf0) >> 4)
141 #define RRR_S (((b1) & 0xf))
142 #define RRR_T (((b0) & 0xf0) >> 4)
143 #endif
145 #define RRRN_R RRR_R
146 #define RRRN_S RRR_S
147 #define RRRN_T RRR_T
149 #define RRI8_R RRR_R
150 #define RRI8_S RRR_S
151 #define RRI8_T RRR_T
152 #define RRI8_IMM8 (b2)
153 #define RRI8_IMM8_SE ((((b2) & 0x80) ? 0xffffff00 : 0) | RRI8_IMM8)
155 #ifdef TARGET_WORDS_BIGENDIAN
156 #define RI16_IMM16 (((b1) << 8) | (b2))
157 #else
158 #define RI16_IMM16 (((b2) << 8) | (b1))
159 #endif
161 #ifdef TARGET_WORDS_BIGENDIAN
162 #define CALL_N (((b0) & 0xc) >> 2)
163 #define CALL_OFFSET ((((b0) & 0x3) << 16) | ((b1) << 8) | (b2))
164 #else
165 #define CALL_N (((b0) & 0x30) >> 4)
166 #define CALL_OFFSET ((((b0) & 0xc0) >> 6) | ((b1) << 2) | ((b2) << 10))
167 #endif
168 #define CALL_OFFSET_SE \
169 (((CALL_OFFSET & 0x20000) ? 0xfffc0000 : 0) | CALL_OFFSET)
171 #define CALLX_N CALL_N
172 #ifdef TARGET_WORDS_BIGENDIAN
173 #define CALLX_M ((b0) & 0x3)
174 #else
175 #define CALLX_M (((b0) & 0xc0) >> 6)
176 #endif
177 #define CALLX_S RRR_S
179 #define BRI12_M CALLX_M
180 #define BRI12_S RRR_S
181 #ifdef TARGET_WORDS_BIGENDIAN
182 #define BRI12_IMM12 ((((b1) & 0xf) << 8) | (b2))
183 #else
184 #define BRI12_IMM12 ((((b1) & 0xf0) >> 4) | ((b2) << 4))
185 #endif
186 #define BRI12_IMM12_SE (((BRI12_IMM12 & 0x800) ? 0xfffff000 : 0) | BRI12_IMM12)
188 #define BRI8_M BRI12_M
189 #define BRI8_R RRI8_R
190 #define BRI8_S RRI8_S
191 #define BRI8_IMM8 RRI8_IMM8
192 #define BRI8_IMM8_SE RRI8_IMM8_SE
194 #define RSR_SR (b1)
196 uint8_t b0 = ldub_code(dc->pc);
197 uint8_t b1 = ldub_code(dc->pc + 1);
198 uint8_t b2 = ldub_code(dc->pc + 2);
200 if (OP0 >= 8) {
201 dc->next_pc = dc->pc + 2;
202 HAS_OPTION(XTENSA_OPTION_CODE_DENSITY);
203 } else {
204 dc->next_pc = dc->pc + 3;
207 switch (OP0) {
208 case 0: /*QRST*/
209 switch (OP1) {
210 case 0: /*RST0*/
211 switch (OP2) {
212 case 0: /*ST0*/
213 if ((RRR_R & 0xc) == 0x8) {
214 HAS_OPTION(XTENSA_OPTION_BOOLEAN);
217 switch (RRR_R) {
218 case 0: /*SNM0*/
219 break;
221 case 1: /*MOVSPw*/
222 HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
223 break;
225 case 2: /*SYNC*/
226 break;
228 case 3:
229 break;
232 break;
234 case 1: /*AND*/
235 tcg_gen_and_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
236 break;
238 case 2: /*OR*/
239 tcg_gen_or_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
240 break;
242 case 3: /*XOR*/
243 tcg_gen_xor_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
244 break;
246 case 4: /*ST1*/
247 break;
249 case 5: /*TLB*/
250 break;
252 case 6: /*RT0*/
253 break;
255 case 7: /*reserved*/
256 break;
258 case 8: /*ADD*/
259 tcg_gen_add_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
260 break;
262 case 9: /*ADD**/
263 case 10:
264 case 11:
266 TCGv_i32 tmp = tcg_temp_new_i32();
267 tcg_gen_shli_i32(tmp, cpu_R[RRR_S], OP2 - 8);
268 tcg_gen_add_i32(cpu_R[RRR_R], tmp, cpu_R[RRR_T]);
269 tcg_temp_free(tmp);
271 break;
273 case 12: /*SUB*/
274 tcg_gen_sub_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
275 break;
277 case 13: /*SUB**/
278 case 14:
279 case 15:
281 TCGv_i32 tmp = tcg_temp_new_i32();
282 tcg_gen_shli_i32(tmp, cpu_R[RRR_S], OP2 - 12);
283 tcg_gen_sub_i32(cpu_R[RRR_R], tmp, cpu_R[RRR_T]);
284 tcg_temp_free(tmp);
286 break;
288 break;
290 case 1: /*RST1*/
291 break;
293 case 2: /*RST2*/
294 break;
296 case 3: /*RST3*/
297 break;
299 case 4: /*EXTUI*/
300 case 5:
301 break;
303 case 6: /*CUST0*/
304 break;
306 case 7: /*CUST1*/
307 break;
309 case 8: /*LSCXp*/
310 HAS_OPTION(XTENSA_OPTION_COPROCESSOR);
311 break;
313 case 9: /*LSC4*/
314 break;
316 case 10: /*FP0*/
317 HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR);
318 break;
320 case 11: /*FP1*/
321 HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR);
322 break;
324 default: /*reserved*/
325 break;
327 break;
329 case 1: /*L32R*/
331 TCGv_i32 tmp = tcg_const_i32(
332 (0xfffc0000 | (RI16_IMM16 << 2)) +
333 ((dc->pc + 3) & ~3));
335 /* no ext L32R */
337 tcg_gen_qemu_ld32u(cpu_R[RRR_T], tmp, 0);
338 tcg_temp_free(tmp);
340 break;
342 case 2: /*LSAI*/
343 break;
345 case 3: /*LSCIp*/
346 HAS_OPTION(XTENSA_OPTION_COPROCESSOR);
347 break;
349 case 4: /*MAC16d*/
350 HAS_OPTION(XTENSA_OPTION_MAC16);
351 break;
353 case 5: /*CALLN*/
354 switch (CALL_N) {
355 case 0: /*CALL0*/
356 tcg_gen_movi_i32(cpu_R[0], dc->next_pc);
357 gen_jumpi(dc, (dc->pc & ~3) + (CALL_OFFSET_SE << 2) + 4, 0);
358 break;
360 case 1: /*CALL4w*/
361 case 2: /*CALL8w*/
362 case 3: /*CALL12w*/
363 HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
364 break;
366 break;
368 case 6: /*SI*/
369 switch (CALL_N) {
370 case 0: /*J*/
371 gen_jumpi(dc, dc->pc + 4 + CALL_OFFSET_SE, 0);
372 break;
375 break;
377 case 7: /*B*/
378 break;
380 case 8: /*L32I.Nn*/
381 break;
383 case 9: /*S32I.Nn*/
384 break;
386 case 10: /*ADD.Nn*/
387 break;
389 case 11: /*ADDI.Nn*/
390 break;
392 case 12: /*ST2n*/
393 break;
395 case 13: /*ST3n*/
396 break;
398 default: /*reserved*/
399 break;
402 dc->pc = dc->next_pc;
403 return;
405 invalid_opcode:
406 qemu_log("INVALID(pc = %08x)\n", dc->pc);
407 dc->pc = dc->next_pc;
408 #undef HAS_OPTION
411 static void check_breakpoint(CPUState *env, DisasContext *dc)
413 CPUBreakpoint *bp;
415 if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
416 QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
417 if (bp->pc == dc->pc) {
418 tcg_gen_movi_i32(cpu_pc, dc->pc);
419 gen_exception(EXCP_DEBUG);
420 dc->is_jmp = DISAS_UPDATE;
426 static void gen_intermediate_code_internal(
427 CPUState *env, TranslationBlock *tb, int search_pc)
429 DisasContext dc;
430 int insn_count = 0;
431 int j, lj = -1;
432 uint16_t *gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
433 int max_insns = tb->cflags & CF_COUNT_MASK;
434 uint32_t pc_start = tb->pc;
435 uint32_t next_page_start =
436 (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
438 if (max_insns == 0) {
439 max_insns = CF_COUNT_MASK;
442 dc.config = env->config;
443 dc.singlestep_enabled = env->singlestep_enabled;
444 dc.tb = tb;
445 dc.pc = pc_start;
446 dc.is_jmp = DISAS_NEXT;
448 gen_icount_start();
450 do {
451 check_breakpoint(env, &dc);
453 if (search_pc) {
454 j = gen_opc_ptr - gen_opc_buf;
455 if (lj < j) {
456 lj++;
457 while (lj < j) {
458 gen_opc_instr_start[lj++] = 0;
461 gen_opc_pc[lj] = dc.pc;
462 gen_opc_instr_start[lj] = 1;
463 gen_opc_icount[lj] = insn_count;
466 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
467 tcg_gen_debug_insn_start(dc.pc);
470 disas_xtensa_insn(&dc);
471 ++insn_count;
472 if (env->singlestep_enabled) {
473 tcg_gen_movi_i32(cpu_pc, dc.pc);
474 gen_exception(EXCP_DEBUG);
475 break;
477 } while (dc.is_jmp == DISAS_NEXT &&
478 insn_count < max_insns &&
479 dc.pc < next_page_start &&
480 gen_opc_ptr < gen_opc_end);
482 if (dc.is_jmp == DISAS_NEXT) {
483 gen_jumpi(&dc, dc.pc, 0);
485 gen_icount_end(tb, insn_count);
486 *gen_opc_ptr = INDEX_op_end;
488 if (!search_pc) {
489 tb->size = dc.pc - pc_start;
490 tb->icount = insn_count;
494 void gen_intermediate_code(CPUState *env, TranslationBlock *tb)
496 gen_intermediate_code_internal(env, tb, 0);
499 void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
501 gen_intermediate_code_internal(env, tb, 1);
504 void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
505 int flags)
507 int i;
509 cpu_fprintf(f, "PC=%08x\n", env->pc);
511 for (i = 0; i < 16; ++i) {
512 cpu_fprintf(f, "A%02d=%08x%c", i, env->regs[i],
513 (i % 4) == 3 ? '\n' : ' ');
517 void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
519 env->pc = gen_opc_pc[pc_pos];