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];
55 static TCGv_i32 cpu_SR
[256];
56 static TCGv_i32 cpu_UR
[256];
58 #include "gen-icount.h"
60 static const char * const sregnames
[256] = {
63 static const char * const uregnames
[256] = {
64 [THREADPTR
] = "THREADPTR",
69 void xtensa_translate_init(void)
71 static const char * const regnames
[] = {
72 "ar0", "ar1", "ar2", "ar3",
73 "ar4", "ar5", "ar6", "ar7",
74 "ar8", "ar9", "ar10", "ar11",
75 "ar12", "ar13", "ar14", "ar15",
79 cpu_env
= tcg_global_reg_new_ptr(TCG_AREG0
, "env");
80 cpu_pc
= tcg_global_mem_new_i32(TCG_AREG0
,
81 offsetof(CPUState
, pc
), "pc");
83 for (i
= 0; i
< 16; i
++) {
84 cpu_R
[i
] = tcg_global_mem_new_i32(TCG_AREG0
,
85 offsetof(CPUState
, regs
[i
]),
89 for (i
= 0; i
< 256; ++i
) {
91 cpu_SR
[i
] = tcg_global_mem_new_i32(TCG_AREG0
,
92 offsetof(CPUState
, sregs
[i
]),
97 for (i
= 0; i
< 256; ++i
) {
99 cpu_UR
[i
] = tcg_global_mem_new_i32(TCG_AREG0
,
100 offsetof(CPUState
, uregs
[i
]),
108 static inline bool option_enabled(DisasContext
*dc
, int opt
)
110 return xtensa_option_enabled(dc
->config
, opt
);
113 static void gen_exception(int excp
)
115 TCGv_i32 tmp
= tcg_const_i32(excp
);
116 gen_helper_exception(tmp
);
120 static void gen_jump_slot(DisasContext
*dc
, TCGv dest
, int slot
)
122 tcg_gen_mov_i32(cpu_pc
, dest
);
123 if (dc
->singlestep_enabled
) {
124 gen_exception(EXCP_DEBUG
);
127 tcg_gen_goto_tb(slot
);
128 tcg_gen_exit_tb((tcg_target_long
)dc
->tb
+ slot
);
133 dc
->is_jmp
= DISAS_UPDATE
;
136 static void gen_jump(DisasContext
*dc
, TCGv dest
)
138 gen_jump_slot(dc
, dest
, -1);
141 static void gen_jumpi(DisasContext
*dc
, uint32_t dest
, int slot
)
143 TCGv_i32 tmp
= tcg_const_i32(dest
);
144 if (((dc
->pc
^ dest
) & TARGET_PAGE_MASK
) != 0) {
147 gen_jump_slot(dc
, tmp
, slot
);
151 static void gen_brcond(DisasContext
*dc
, TCGCond cond
,
152 TCGv_i32 t0
, TCGv_i32 t1
, uint32_t offset
)
154 int label
= gen_new_label();
156 tcg_gen_brcond_i32(cond
, t0
, t1
, label
);
157 gen_jumpi(dc
, dc
->next_pc
, 0);
158 gen_set_label(label
);
159 gen_jumpi(dc
, dc
->pc
+ offset
, 1);
162 static void gen_brcondi(DisasContext
*dc
, TCGCond cond
,
163 TCGv_i32 t0
, uint32_t t1
, uint32_t offset
)
165 TCGv_i32 tmp
= tcg_const_i32(t1
);
166 gen_brcond(dc
, cond
, t0
, tmp
, offset
);
170 static void disas_xtensa_insn(DisasContext
*dc
)
172 #define HAS_OPTION(opt) do { \
173 if (!option_enabled(dc, opt)) { \
174 qemu_log("Option %d is not enabled %s:%d\n", \
175 (opt), __FILE__, __LINE__); \
176 goto invalid_opcode; \
180 #ifdef TARGET_WORDS_BIGENDIAN
181 #define OP0 (((b0) & 0xf0) >> 4)
182 #define OP1 (((b2) & 0xf0) >> 4)
183 #define OP2 ((b2) & 0xf)
184 #define RRR_R ((b1) & 0xf)
185 #define RRR_S (((b1) & 0xf0) >> 4)
186 #define RRR_T ((b0) & 0xf)
188 #define OP0 (((b0) & 0xf))
189 #define OP1 (((b2) & 0xf))
190 #define OP2 (((b2) & 0xf0) >> 4)
191 #define RRR_R (((b1) & 0xf0) >> 4)
192 #define RRR_S (((b1) & 0xf))
193 #define RRR_T (((b0) & 0xf0) >> 4)
203 #define RRI8_IMM8 (b2)
204 #define RRI8_IMM8_SE ((((b2) & 0x80) ? 0xffffff00 : 0) | RRI8_IMM8)
206 #ifdef TARGET_WORDS_BIGENDIAN
207 #define RI16_IMM16 (((b1) << 8) | (b2))
209 #define RI16_IMM16 (((b2) << 8) | (b1))
212 #ifdef TARGET_WORDS_BIGENDIAN
213 #define CALL_N (((b0) & 0xc) >> 2)
214 #define CALL_OFFSET ((((b0) & 0x3) << 16) | ((b1) << 8) | (b2))
216 #define CALL_N (((b0) & 0x30) >> 4)
217 #define CALL_OFFSET ((((b0) & 0xc0) >> 6) | ((b1) << 2) | ((b2) << 10))
219 #define CALL_OFFSET_SE \
220 (((CALL_OFFSET & 0x20000) ? 0xfffc0000 : 0) | CALL_OFFSET)
222 #define CALLX_N CALL_N
223 #ifdef TARGET_WORDS_BIGENDIAN
224 #define CALLX_M ((b0) & 0x3)
226 #define CALLX_M (((b0) & 0xc0) >> 6)
228 #define CALLX_S RRR_S
230 #define BRI12_M CALLX_M
231 #define BRI12_S RRR_S
232 #ifdef TARGET_WORDS_BIGENDIAN
233 #define BRI12_IMM12 ((((b1) & 0xf) << 8) | (b2))
235 #define BRI12_IMM12 ((((b1) & 0xf0) >> 4) | ((b2) << 4))
237 #define BRI12_IMM12_SE (((BRI12_IMM12 & 0x800) ? 0xfffff000 : 0) | BRI12_IMM12)
239 #define BRI8_M BRI12_M
240 #define BRI8_R RRI8_R
241 #define BRI8_S RRI8_S
242 #define BRI8_IMM8 RRI8_IMM8
243 #define BRI8_IMM8_SE RRI8_IMM8_SE
247 uint8_t b0
= ldub_code(dc
->pc
);
248 uint8_t b1
= ldub_code(dc
->pc
+ 1);
249 uint8_t b2
= ldub_code(dc
->pc
+ 2);
251 static const uint32_t B4CONST
[] = {
252 0xffffffff, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256
255 static const uint32_t B4CONSTU
[] = {
256 32768, 65536, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256
260 dc
->next_pc
= dc
->pc
+ 2;
261 HAS_OPTION(XTENSA_OPTION_CODE_DENSITY
);
263 dc
->next_pc
= dc
->pc
+ 3;
272 if ((RRR_R
& 0xc) == 0x8) {
273 HAS_OPTION(XTENSA_OPTION_BOOLEAN
);
289 gen_jump(dc
, cpu_R
[CALLX_S
]);
293 HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER
);
305 TCGv_i32 tmp
= tcg_temp_new_i32();
306 tcg_gen_mov_i32(tmp
, cpu_R
[CALLX_S
]);
307 tcg_gen_movi_i32(cpu_R
[0], dc
->next_pc
);
316 HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER
);
324 HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER
);
337 tcg_gen_and_i32(cpu_R
[RRR_R
], cpu_R
[RRR_S
], cpu_R
[RRR_T
]);
341 tcg_gen_or_i32(cpu_R
[RRR_R
], cpu_R
[RRR_S
], cpu_R
[RRR_T
]);
345 tcg_gen_xor_i32(cpu_R
[RRR_R
], cpu_R
[RRR_S
], cpu_R
[RRR_T
]);
357 tcg_gen_neg_i32(cpu_R
[RRR_R
], cpu_R
[RRR_T
]);
362 int label
= gen_new_label();
363 tcg_gen_mov_i32(cpu_R
[RRR_R
], cpu_R
[RRR_T
]);
365 TCG_COND_GE
, cpu_R
[RRR_R
], 0, label
);
366 tcg_gen_neg_i32(cpu_R
[RRR_R
], cpu_R
[RRR_T
]);
367 gen_set_label(label
);
371 default: /*reserved*/
380 tcg_gen_add_i32(cpu_R
[RRR_R
], cpu_R
[RRR_S
], cpu_R
[RRR_T
]);
387 TCGv_i32 tmp
= tcg_temp_new_i32();
388 tcg_gen_shli_i32(tmp
, cpu_R
[RRR_S
], OP2
- 8);
389 tcg_gen_add_i32(cpu_R
[RRR_R
], tmp
, cpu_R
[RRR_T
]);
395 tcg_gen_sub_i32(cpu_R
[RRR_R
], cpu_R
[RRR_S
], cpu_R
[RRR_T
]);
402 TCGv_i32 tmp
= tcg_temp_new_i32();
403 tcg_gen_shli_i32(tmp
, cpu_R
[RRR_S
], OP2
- 12);
404 tcg_gen_sub_i32(cpu_R
[RRR_R
], tmp
, cpu_R
[RRR_T
]);
431 HAS_OPTION(XTENSA_OPTION_COPROCESSOR
);
438 HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR
);
442 HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR
);
445 default: /*reserved*/
452 TCGv_i32 tmp
= tcg_const_i32(
453 (0xfffc0000 | (RI16_IMM16
<< 2)) +
454 ((dc
->pc
+ 3) & ~3));
458 tcg_gen_qemu_ld32u(cpu_R
[RRR_T
], tmp
, 0);
467 HAS_OPTION(XTENSA_OPTION_COPROCESSOR
);
471 HAS_OPTION(XTENSA_OPTION_MAC16
);
477 tcg_gen_movi_i32(cpu_R
[0], dc
->next_pc
);
478 gen_jumpi(dc
, (dc
->pc
& ~3) + (CALL_OFFSET_SE
<< 2) + 4, 0);
484 HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER
);
492 gen_jumpi(dc
, dc
->pc
+ 4 + CALL_OFFSET_SE
, 0);
497 static const TCGCond cond
[] = {
498 TCG_COND_EQ
, /*BEQZ*/
499 TCG_COND_NE
, /*BNEZ*/
500 TCG_COND_LT
, /*BLTZ*/
501 TCG_COND_GE
, /*BGEZ*/
504 gen_brcondi(dc
, cond
[BRI12_M
& 3], cpu_R
[BRI12_S
], 0,
511 static const TCGCond cond
[] = {
512 TCG_COND_EQ
, /*BEQI*/
513 TCG_COND_NE
, /*BNEI*/
514 TCG_COND_LT
, /*BLTI*/
515 TCG_COND_GE
, /*BGEI*/
518 gen_brcondi(dc
, cond
[BRI8_M
& 3],
519 cpu_R
[BRI8_S
], B4CONST
[BRI8_R
], 4 + BRI8_IMM8_SE
);
526 HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER
);
532 HAS_OPTION(XTENSA_OPTION_BOOLEAN
);
536 HAS_OPTION(XTENSA_OPTION_BOOLEAN
);
548 default: /*reserved*/
556 gen_brcondi(dc
, BRI8_M
== 2 ? TCG_COND_LTU
: TCG_COND_GEU
,
557 cpu_R
[BRI8_S
], B4CONSTU
[BRI8_R
], 4 + BRI8_IMM8_SE
);
567 TCGCond eq_ne
= (RRI8_R
& 8) ? TCG_COND_NE
: TCG_COND_EQ
;
569 switch (RRI8_R
& 7) {
570 case 0: /*BNONE*/ /*BANY*/
572 TCGv_i32 tmp
= tcg_temp_new_i32();
573 tcg_gen_and_i32(tmp
, cpu_R
[RRI8_S
], cpu_R
[RRI8_T
]);
574 gen_brcondi(dc
, eq_ne
, tmp
, 0, 4 + RRI8_IMM8_SE
);
579 case 1: /*BEQ*/ /*BNE*/
580 case 2: /*BLT*/ /*BGE*/
581 case 3: /*BLTU*/ /*BGEU*/
583 static const TCGCond cond
[] = {
591 gen_brcond(dc
, cond
[RRI8_R
], cpu_R
[RRI8_S
], cpu_R
[RRI8_T
],
596 case 4: /*BALL*/ /*BNALL*/
598 TCGv_i32 tmp
= tcg_temp_new_i32();
599 tcg_gen_and_i32(tmp
, cpu_R
[RRI8_S
], cpu_R
[RRI8_T
]);
600 gen_brcond(dc
, eq_ne
, tmp
, cpu_R
[RRI8_T
],
606 case 5: /*BBC*/ /*BBS*/
608 TCGv_i32 bit
= tcg_const_i32(1);
609 TCGv_i32 tmp
= tcg_temp_new_i32();
610 tcg_gen_andi_i32(tmp
, cpu_R
[RRI8_T
], 0x1f);
611 tcg_gen_shl_i32(bit
, bit
, tmp
);
612 tcg_gen_and_i32(tmp
, cpu_R
[RRI8_S
], bit
);
613 gen_brcondi(dc
, eq_ne
, tmp
, 0, 4 + RRI8_IMM8_SE
);
619 case 6: /*BBCI*/ /*BBSI*/
622 TCGv_i32 tmp
= tcg_temp_new_i32();
623 tcg_gen_andi_i32(tmp
, cpu_R
[RRI8_S
],
624 1 << (((RRI8_R
& 1) << 4) | RRI8_T
));
625 gen_brcondi(dc
, eq_ne
, tmp
, 0, 4 + RRI8_IMM8_SE
);
634 #define gen_narrow_load_store(type) do { \
635 TCGv_i32 addr = tcg_temp_new_i32(); \
636 tcg_gen_addi_i32(addr, cpu_R[RRRN_S], RRRN_R << 2); \
637 tcg_gen_qemu_##type(cpu_R[RRRN_T], addr, 0); \
638 tcg_temp_free(addr); \
642 gen_narrow_load_store(ld32u
);
646 gen_narrow_load_store(st32
);
648 #undef gen_narrow_load_store
651 tcg_gen_add_i32(cpu_R
[RRRN_R
], cpu_R
[RRRN_S
], cpu_R
[RRRN_T
]);
655 tcg_gen_addi_i32(cpu_R
[RRRN_R
], cpu_R
[RRRN_S
], RRRN_T
? RRRN_T
: -1);
659 if (RRRN_T
< 8) { /*MOVI.Nn*/
660 tcg_gen_movi_i32(cpu_R
[RRRN_S
],
661 RRRN_R
| (RRRN_T
<< 4) |
662 ((RRRN_T
& 6) == 6 ? 0xffffff80 : 0));
663 } else { /*BEQZ.Nn*/ /*BNEZ.Nn*/
664 TCGCond eq_ne
= (RRRN_T
& 4) ? TCG_COND_NE
: TCG_COND_EQ
;
666 gen_brcondi(dc
, eq_ne
, cpu_R
[RRRN_S
], 0,
667 4 + (RRRN_R
| ((RRRN_T
& 3) << 4)));
674 tcg_gen_mov_i32(cpu_R
[RRRN_T
], cpu_R
[RRRN_S
]);
680 gen_jump(dc
, cpu_R
[0]);
695 default: /*reserved*/
700 default: /*reserved*/
705 default: /*reserved*/
709 dc
->pc
= dc
->next_pc
;
713 qemu_log("INVALID(pc = %08x)\n", dc
->pc
);
714 dc
->pc
= dc
->next_pc
;
718 static void check_breakpoint(CPUState
*env
, DisasContext
*dc
)
722 if (unlikely(!QTAILQ_EMPTY(&env
->breakpoints
))) {
723 QTAILQ_FOREACH(bp
, &env
->breakpoints
, entry
) {
724 if (bp
->pc
== dc
->pc
) {
725 tcg_gen_movi_i32(cpu_pc
, dc
->pc
);
726 gen_exception(EXCP_DEBUG
);
727 dc
->is_jmp
= DISAS_UPDATE
;
733 static void gen_intermediate_code_internal(
734 CPUState
*env
, TranslationBlock
*tb
, int search_pc
)
739 uint16_t *gen_opc_end
= gen_opc_buf
+ OPC_MAX_SIZE
;
740 int max_insns
= tb
->cflags
& CF_COUNT_MASK
;
741 uint32_t pc_start
= tb
->pc
;
742 uint32_t next_page_start
=
743 (pc_start
& TARGET_PAGE_MASK
) + TARGET_PAGE_SIZE
;
745 if (max_insns
== 0) {
746 max_insns
= CF_COUNT_MASK
;
749 dc
.config
= env
->config
;
750 dc
.singlestep_enabled
= env
->singlestep_enabled
;
753 dc
.is_jmp
= DISAS_NEXT
;
758 check_breakpoint(env
, &dc
);
761 j
= gen_opc_ptr
- gen_opc_buf
;
765 gen_opc_instr_start
[lj
++] = 0;
768 gen_opc_pc
[lj
] = dc
.pc
;
769 gen_opc_instr_start
[lj
] = 1;
770 gen_opc_icount
[lj
] = insn_count
;
773 if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP
))) {
774 tcg_gen_debug_insn_start(dc
.pc
);
777 disas_xtensa_insn(&dc
);
779 if (env
->singlestep_enabled
) {
780 tcg_gen_movi_i32(cpu_pc
, dc
.pc
);
781 gen_exception(EXCP_DEBUG
);
784 } while (dc
.is_jmp
== DISAS_NEXT
&&
785 insn_count
< max_insns
&&
786 dc
.pc
< next_page_start
&&
787 gen_opc_ptr
< gen_opc_end
);
789 if (dc
.is_jmp
== DISAS_NEXT
) {
790 gen_jumpi(&dc
, dc
.pc
, 0);
792 gen_icount_end(tb
, insn_count
);
793 *gen_opc_ptr
= INDEX_op_end
;
796 tb
->size
= dc
.pc
- pc_start
;
797 tb
->icount
= insn_count
;
801 void gen_intermediate_code(CPUState
*env
, TranslationBlock
*tb
)
803 gen_intermediate_code_internal(env
, tb
, 0);
806 void gen_intermediate_code_pc(CPUState
*env
, TranslationBlock
*tb
)
808 gen_intermediate_code_internal(env
, tb
, 1);
811 void cpu_dump_state(CPUState
*env
, FILE *f
, fprintf_function cpu_fprintf
,
816 cpu_fprintf(f
, "PC=%08x\n\n", env
->pc
);
818 for (i
= j
= 0; i
< 256; ++i
) {
820 cpu_fprintf(f
, "%s=%08x%c", sregnames
[i
], env
->sregs
[i
],
821 (j
++ % 4) == 3 ? '\n' : ' ');
825 cpu_fprintf(f
, (j
% 4) == 0 ? "\n" : "\n\n");
827 for (i
= j
= 0; i
< 256; ++i
) {
829 cpu_fprintf(f
, "%s=%08x%c", uregnames
[i
], env
->uregs
[i
],
830 (j
++ % 4) == 3 ? '\n' : ' ');
834 cpu_fprintf(f
, (j
% 4) == 0 ? "\n" : "\n\n");
836 for (i
= 0; i
< 16; ++i
) {
837 cpu_fprintf(f
, "A%02d=%08x%c", i
, env
->regs
[i
],
838 (i
% 4) == 3 ? '\n' : ' ');
842 void restore_state_to_opc(CPUState
*env
, TranslationBlock
*tb
, int pc_pos
)
844 env
->pc
= gen_opc_pc
[pc_pos
];