3 * http://www.tensilica.com/products/literature-docs/documentation/xtensa-isa-databook.htm
5 * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
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.
43 typedef struct DisasContext
{
44 const XtensaConfig
*config
;
49 int singlestep_enabled
;
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",
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
]),
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
);
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
);
100 tcg_gen_goto_tb(slot
);
101 tcg_gen_exit_tb((tcg_target_long
)dc
->tb
+ slot
);
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) {
115 gen_jump_slot(dc
, tmp
, slot
);
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; \
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)
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)
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))
158 #define RI16_IMM16 (((b2) << 8) | (b1))
161 #ifdef TARGET_WORDS_BIGENDIAN
162 #define CALL_N (((b0) & 0xc) >> 2)
163 #define CALL_OFFSET ((((b0) & 0x3) << 16) | ((b1) << 8) | (b2))
165 #define CALL_N (((b0) & 0x30) >> 4)
166 #define CALL_OFFSET ((((b0) & 0xc0) >> 6) | ((b1) << 2) | ((b2) << 10))
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)
175 #define CALLX_M (((b0) & 0xc0) >> 6)
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))
184 #define BRI12_IMM12 ((((b1) & 0xf0) >> 4) | ((b2) << 4))
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
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);
201 dc
->next_pc
= dc
->pc
+ 2;
202 HAS_OPTION(XTENSA_OPTION_CODE_DENSITY
);
204 dc
->next_pc
= dc
->pc
+ 3;
213 if ((RRR_R
& 0xc) == 0x8) {
214 HAS_OPTION(XTENSA_OPTION_BOOLEAN
);
222 HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER
);
235 tcg_gen_and_i32(cpu_R
[RRR_R
], cpu_R
[RRR_S
], cpu_R
[RRR_T
]);
239 tcg_gen_or_i32(cpu_R
[RRR_R
], cpu_R
[RRR_S
], cpu_R
[RRR_T
]);
243 tcg_gen_xor_i32(cpu_R
[RRR_R
], cpu_R
[RRR_S
], cpu_R
[RRR_T
]);
259 tcg_gen_add_i32(cpu_R
[RRR_R
], cpu_R
[RRR_S
], cpu_R
[RRR_T
]);
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
]);
274 tcg_gen_sub_i32(cpu_R
[RRR_R
], cpu_R
[RRR_S
], cpu_R
[RRR_T
]);
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
]);
310 HAS_OPTION(XTENSA_OPTION_COPROCESSOR
);
317 HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR
);
321 HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR
);
324 default: /*reserved*/
331 TCGv_i32 tmp
= tcg_const_i32(
332 (0xfffc0000 | (RI16_IMM16
<< 2)) +
333 ((dc
->pc
+ 3) & ~3));
337 tcg_gen_qemu_ld32u(cpu_R
[RRR_T
], tmp
, 0);
346 HAS_OPTION(XTENSA_OPTION_COPROCESSOR
);
350 HAS_OPTION(XTENSA_OPTION_MAC16
);
356 tcg_gen_movi_i32(cpu_R
[0], dc
->next_pc
);
357 gen_jumpi(dc
, (dc
->pc
& ~3) + (CALL_OFFSET_SE
<< 2) + 4, 0);
363 HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER
);
371 gen_jumpi(dc
, dc
->pc
+ 4 + CALL_OFFSET_SE
, 0);
398 default: /*reserved*/
402 dc
->pc
= dc
->next_pc
;
406 qemu_log("INVALID(pc = %08x)\n", dc
->pc
);
407 dc
->pc
= dc
->next_pc
;
411 static void check_breakpoint(CPUState
*env
, DisasContext
*dc
)
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
)
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
;
446 dc
.is_jmp
= DISAS_NEXT
;
451 check_breakpoint(env
, &dc
);
454 j
= gen_opc_ptr
- gen_opc_buf
;
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
);
472 if (env
->singlestep_enabled
) {
473 tcg_gen_movi_i32(cpu_pc
, dc
.pc
);
474 gen_exception(EXCP_DEBUG
);
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
;
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
,
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
];