]> git.proxmox.com Git - qemu.git/blame - target-xtensa/translate.c
target-xtensa: implement disas_xtensa_insn
[qemu.git] / target-xtensa / translate.c
CommitLineData
2328826b
MF
1/*
2 * Xtensa ISA:
3 * http://www.tensilica.com/products/literature-docs/documentation/xtensa-isa-databook.htm
4 *
5 * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
6 * All rights reserved.
7 *
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.
18 *
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.
29 */
30
31#include <stdio.h>
32
33#include "cpu.h"
34#include "exec-all.h"
35#include "disas.h"
36#include "tcg-op.h"
37#include "qemu-log.h"
38
dedc5eae
MF
39#include "helpers.h"
40#define GEN_HELPER 1
41#include "helpers.h"
42
43typedef 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;
51
52static TCGv_ptr cpu_env;
53static TCGv_i32 cpu_pc;
54static TCGv_i32 cpu_R[16];
55
56#include "gen-icount.h"
2328826b
MF
57
58void xtensa_translate_init(void)
59{
dedc5eae
MF
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",
65 };
66 int i;
67
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");
71
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]);
76 }
77#define GEN_HELPER 2
78#include "helpers.h"
79}
80
81static inline bool option_enabled(DisasContext *dc, int opt)
82{
83 return xtensa_option_enabled(dc->config, opt);
84}
85
86static void gen_exception(int excp)
87{
88 TCGv_i32 tmp = tcg_const_i32(excp);
89 gen_helper_exception(tmp);
90 tcg_temp_free(tmp);
91}
92
93static void gen_jump_slot(DisasContext *dc, TCGv dest, int slot)
94{
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);
104 }
105 }
106 dc->is_jmp = DISAS_UPDATE;
107}
108
109static void gen_jumpi(DisasContext *dc, uint32_t dest, int slot)
110{
111 TCGv_i32 tmp = tcg_const_i32(dest);
112 if (((dc->pc ^ dest) & TARGET_PAGE_MASK) != 0) {
113 slot = -1;
114 }
115 gen_jump_slot(dc, tmp, slot);
116 tcg_temp_free(tmp);
117}
118
119static void disas_xtensa_insn(DisasContext *dc)
120{
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; \
126 } \
127 } while (0)
128
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
144
145#define RRRN_R RRR_R
146#define RRRN_S RRR_S
147#define RRRN_T RRR_T
148
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)
154
155#ifdef TARGET_WORDS_BIGENDIAN
156#define RI16_IMM16 (((b1) << 8) | (b2))
157#else
158#define RI16_IMM16 (((b2) << 8) | (b1))
159#endif
160
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)
170
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
178
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)
187
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
193
194#define RSR_SR (b1)
195
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);
199
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;
205 }
206
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);
215 }
216
217 switch (RRR_R) {
218 case 0: /*SNM0*/
219 break;
220
221 case 1: /*MOVSPw*/
222 HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
223 break;
224
225 case 2: /*SYNC*/
226 break;
227
228 case 3:
229 break;
230
231 }
232 break;
233
234 case 1: /*AND*/
235 tcg_gen_and_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
236 break;
237
238 case 2: /*OR*/
239 tcg_gen_or_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
240 break;
241
242 case 3: /*XOR*/
243 tcg_gen_xor_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
244 break;
245
246 case 4: /*ST1*/
247 break;
248
249 case 5: /*TLB*/
250 break;
251
252 case 6: /*RT0*/
253 break;
254
255 case 7: /*reserved*/
256 break;
257
258 case 8: /*ADD*/
259 tcg_gen_add_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
260 break;
261
262 case 9: /*ADD**/
263 case 10:
264 case 11:
265 {
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);
270 }
271 break;
272
273 case 12: /*SUB*/
274 tcg_gen_sub_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]);
275 break;
276
277 case 13: /*SUB**/
278 case 14:
279 case 15:
280 {
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);
285 }
286 break;
287 }
288 break;
289
290 case 1: /*RST1*/
291 break;
292
293 case 2: /*RST2*/
294 break;
295
296 case 3: /*RST3*/
297 break;
298
299 case 4: /*EXTUI*/
300 case 5:
301 break;
302
303 case 6: /*CUST0*/
304 break;
305
306 case 7: /*CUST1*/
307 break;
308
309 case 8: /*LSCXp*/
310 HAS_OPTION(XTENSA_OPTION_COPROCESSOR);
311 break;
312
313 case 9: /*LSC4*/
314 break;
315
316 case 10: /*FP0*/
317 HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR);
318 break;
319
320 case 11: /*FP1*/
321 HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR);
322 break;
323
324 default: /*reserved*/
325 break;
326 }
327 break;
328
329 case 1: /*L32R*/
330 {
331 TCGv_i32 tmp = tcg_const_i32(
332 (0xfffc0000 | (RI16_IMM16 << 2)) +
333 ((dc->pc + 3) & ~3));
334
335 /* no ext L32R */
336
337 tcg_gen_qemu_ld32u(cpu_R[RRR_T], tmp, 0);
338 tcg_temp_free(tmp);
339 }
340 break;
341
342 case 2: /*LSAI*/
343 break;
344
345 case 3: /*LSCIp*/
346 HAS_OPTION(XTENSA_OPTION_COPROCESSOR);
347 break;
348
349 case 4: /*MAC16d*/
350 HAS_OPTION(XTENSA_OPTION_MAC16);
351 break;
352
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;
359
360 case 1: /*CALL4w*/
361 case 2: /*CALL8w*/
362 case 3: /*CALL12w*/
363 HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
364 break;
365 }
366 break;
367
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;
373
374 }
375 break;
376
377 case 7: /*B*/
378 break;
379
380 case 8: /*L32I.Nn*/
381 break;
382
383 case 9: /*S32I.Nn*/
384 break;
385
386 case 10: /*ADD.Nn*/
387 break;
388
389 case 11: /*ADDI.Nn*/
390 break;
391
392 case 12: /*ST2n*/
393 break;
394
395 case 13: /*ST3n*/
396 break;
397
398 default: /*reserved*/
399 break;
400 }
401
402 dc->pc = dc->next_pc;
403 return;
404
405invalid_opcode:
406 qemu_log("INVALID(pc = %08x)\n", dc->pc);
407 dc->pc = dc->next_pc;
408#undef HAS_OPTION
409}
410
411static void check_breakpoint(CPUState *env, DisasContext *dc)
412{
413 CPUBreakpoint *bp;
414
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;
421 }
422 }
423 }
424}
425
426static void gen_intermediate_code_internal(
427 CPUState *env, TranslationBlock *tb, int search_pc)
428{
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;
437
438 if (max_insns == 0) {
439 max_insns = CF_COUNT_MASK;
440 }
441
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;
447
448 gen_icount_start();
449
450 do {
451 check_breakpoint(env, &dc);
452
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;
459 }
460 }
461 gen_opc_pc[lj] = dc.pc;
462 gen_opc_instr_start[lj] = 1;
463 gen_opc_icount[lj] = insn_count;
464 }
465
466 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) {
467 tcg_gen_debug_insn_start(dc.pc);
468 }
469
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;
476 }
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);
481
482 if (dc.is_jmp == DISAS_NEXT) {
483 gen_jumpi(&dc, dc.pc, 0);
484 }
485 gen_icount_end(tb, insn_count);
486 *gen_opc_ptr = INDEX_op_end;
487
488 if (!search_pc) {
489 tb->size = dc.pc - pc_start;
490 tb->icount = insn_count;
491 }
2328826b
MF
492}
493
494void gen_intermediate_code(CPUState *env, TranslationBlock *tb)
495{
dedc5eae 496 gen_intermediate_code_internal(env, tb, 0);
2328826b
MF
497}
498
499void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
500{
dedc5eae 501 gen_intermediate_code_internal(env, tb, 1);
2328826b
MF
502}
503
504void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
505 int flags)
506{
507 int i;
508
509 cpu_fprintf(f, "PC=%08x\n", env->pc);
510
511 for (i = 0; i < 16; ++i) {
512 cpu_fprintf(f, "A%02d=%08x%c", i, env->regs[i],
513 (i % 4) == 3 ? '\n' : ' ');
514 }
515}
516
517void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
518{
519 env->pc = gen_opc_pc[pc_pos];
520}