#include "qemu-log.h"
#include "sysemu.h"
-#include "helpers.h"
+#include "helper.h"
#define GEN_HELPER 1
-#include "helpers.h"
+#include "helper.h"
typedef struct DisasContext {
const XtensaConfig *config;
uint32_t ccount_delta;
unsigned used_window;
+
+ bool debug;
+ bool icount;
+ TCGv_i32 next_icount;
} DisasContext;
static TCGv_ptr cpu_env;
[RASID] = "RASID",
[ITLBCFG] = "ITLBCFG",
[DTLBCFG] = "DTLBCFG",
+ [IBREAKENABLE] = "IBREAKENABLE",
+ [IBREAKA] = "IBREAKA0",
+ [IBREAKA + 1] = "IBREAKA1",
+ [DBREAKA] = "DBREAKA0",
+ [DBREAKA + 1] = "DBREAKA1",
+ [DBREAKC] = "DBREAKC0",
+ [DBREAKC + 1] = "DBREAKC1",
[EPC1] = "EPC1",
[EPC1 + 1] = "EPC2",
[EPC1 + 2] = "EPC3",
[PS] = "PS",
[VECBASE] = "VECBASE",
[EXCCAUSE] = "EXCCAUSE",
+ [DEBUGCAUSE] = "DEBUGCAUSE",
[CCOUNT] = "CCOUNT",
[PRID] = "PRID",
+ [ICOUNT] = "ICOUNT",
+ [ICOUNTLEVEL] = "ICOUNTLEVEL",
[EXCVADDR] = "EXCVADDR",
[CCOMPARE] = "CCOMPARE0",
[CCOMPARE + 1] = "CCOMPARE1",
cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
cpu_pc = tcg_global_mem_new_i32(TCG_AREG0,
- offsetof(CPUState, pc), "pc");
+ offsetof(CPUXtensaState, pc), "pc");
for (i = 0; i < 16; i++) {
cpu_R[i] = tcg_global_mem_new_i32(TCG_AREG0,
- offsetof(CPUState, regs[i]),
+ offsetof(CPUXtensaState, regs[i]),
regnames[i]);
}
for (i = 0; i < 256; ++i) {
if (sregnames[i]) {
cpu_SR[i] = tcg_global_mem_new_i32(TCG_AREG0,
- offsetof(CPUState, sregs[i]),
+ offsetof(CPUXtensaState, sregs[i]),
sregnames[i]);
}
}
for (i = 0; i < 256; ++i) {
if (uregnames[i]) {
cpu_UR[i] = tcg_global_mem_new_i32(TCG_AREG0,
- offsetof(CPUState, uregs[i]),
+ offsetof(CPUXtensaState, uregs[i]),
uregnames[i]);
}
}
#define GEN_HELPER 2
-#include "helpers.h"
+#include "helper.h"
}
static inline bool option_bits_enabled(DisasContext *dc, uint64_t opt)
if (dc->ccount_delta > 0) {
TCGv_i32 tmp = tcg_const_i32(dc->ccount_delta);
dc->ccount_delta = 0;
- gen_helper_advance_ccount(tmp);
+ gen_helper_advance_ccount(cpu_env, tmp);
tcg_temp_free(tmp);
}
}
{
TCGv_i32 tmp = tcg_const_i32(excp);
gen_advance_ccount(dc);
- gen_helper_exception(tmp);
+ gen_helper_exception(cpu_env, tmp);
tcg_temp_free(tmp);
}
TCGv_i32 tpc = tcg_const_i32(dc->pc);
TCGv_i32 tcause = tcg_const_i32(cause);
gen_advance_ccount(dc);
- gen_helper_exception_cause(tpc, tcause);
+ gen_helper_exception_cause(cpu_env, tpc, tcause);
tcg_temp_free(tpc);
tcg_temp_free(tcause);
+ if (cause == ILLEGAL_INSTRUCTION_CAUSE ||
+ cause == SYSCALL_CAUSE) {
+ dc->is_jmp = DISAS_UPDATE;
+ }
}
static void gen_exception_cause_vaddr(DisasContext *dc, uint32_t cause,
TCGv_i32 tpc = tcg_const_i32(dc->pc);
TCGv_i32 tcause = tcg_const_i32(cause);
gen_advance_ccount(dc);
- gen_helper_exception_cause_vaddr(tpc, tcause, vaddr);
+ gen_helper_exception_cause_vaddr(cpu_env, tpc, tcause, vaddr);
+ tcg_temp_free(tpc);
+ tcg_temp_free(tcause);
+}
+
+static void gen_debug_exception(DisasContext *dc, uint32_t cause)
+{
+ TCGv_i32 tpc = tcg_const_i32(dc->pc);
+ TCGv_i32 tcause = tcg_const_i32(cause);
+ gen_advance_ccount(dc);
+ gen_helper_debug_exception(cpu_env, tpc, tcause);
tcg_temp_free(tpc);
tcg_temp_free(tcause);
+ if (cause & (DEBUGCAUSE_IB | DEBUGCAUSE_BI | DEBUGCAUSE_BN)) {
+ dc->is_jmp = DISAS_UPDATE;
+ }
}
static void gen_check_privilege(DisasContext *dc)
{
if (dc->cring) {
gen_exception_cause(dc, PRIVILEGED_CAUSE);
+ dc->is_jmp = DISAS_UPDATE;
}
}
static void gen_jump_slot(DisasContext *dc, TCGv dest, int slot)
{
tcg_gen_mov_i32(cpu_pc, dest);
+ gen_advance_ccount(dc);
+ if (dc->icount) {
+ tcg_gen_mov_i32(cpu_SR[ICOUNT], dc->next_icount);
+ }
if (dc->singlestep_enabled) {
gen_exception(dc, EXCP_DEBUG);
} else {
- gen_advance_ccount(dc);
if (slot >= 0) {
tcg_gen_goto_tb(slot);
tcg_gen_exit_tb((tcg_target_long)dc->tb + slot);
dc->next_pc == dc->lend) {
int label = gen_new_label();
+ gen_advance_ccount(dc);
tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_SR[LCOUNT], 0, label);
tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_SR[LCOUNT], 1);
gen_jumpi(dc, dc->lbeg, slot);
{
int label = gen_new_label();
+ gen_advance_ccount(dc);
tcg_gen_brcond_i32(cond, t0, t1, label);
gen_jumpi_check_loop_end(dc, 0);
gen_set_label(label);
static void gen_wsr_lbeg(DisasContext *dc, uint32_t sr, TCGv_i32 s)
{
- gen_helper_wsr_lbeg(s);
+ gen_helper_wsr_lbeg(cpu_env, s);
+ gen_jumpi_check_loop_end(dc, 0);
}
static void gen_wsr_lend(DisasContext *dc, uint32_t sr, TCGv_i32 s)
{
- gen_helper_wsr_lend(s);
+ gen_helper_wsr_lend(cpu_env, s);
+ gen_jumpi_check_loop_end(dc, 0);
}
static void gen_wsr_sar(DisasContext *dc, uint32_t sr, TCGv_i32 s)
static void gen_wsr_windowbase(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
- gen_helper_wsr_windowbase(v);
+ gen_helper_wsr_windowbase(cpu_env, v);
reset_used_window(dc);
}
static void gen_wsr_windowstart(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
- tcg_gen_mov_i32(cpu_SR[sr], v);
+ tcg_gen_andi_i32(cpu_SR[sr], v, (1 << dc->config->nareg / 4) - 1);
reset_used_window(dc);
}
static void gen_wsr_rasid(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
- gen_helper_wsr_rasid(v);
+ gen_helper_wsr_rasid(cpu_env, v);
/* This can change tb->flags, so exit tb */
gen_jumpi_check_loop_end(dc, -1);
}
tcg_gen_andi_i32(cpu_SR[sr], v, 0x01130000);
}
+static void gen_wsr_ibreakenable(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+ gen_helper_wsr_ibreakenable(cpu_env, v);
+ gen_jumpi_check_loop_end(dc, 0);
+}
+
+static void gen_wsr_ibreaka(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+ unsigned id = sr - IBREAKA;
+
+ if (id < dc->config->nibreak) {
+ TCGv_i32 tmp = tcg_const_i32(id);
+ gen_helper_wsr_ibreaka(cpu_env, tmp, v);
+ tcg_temp_free(tmp);
+ gen_jumpi_check_loop_end(dc, 0);
+ }
+}
+
+static void gen_wsr_dbreaka(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+ unsigned id = sr - DBREAKA;
+
+ if (id < dc->config->ndbreak) {
+ TCGv_i32 tmp = tcg_const_i32(id);
+ gen_helper_wsr_dbreaka(cpu_env, tmp, v);
+ tcg_temp_free(tmp);
+ }
+}
+
+static void gen_wsr_dbreakc(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+ unsigned id = sr - DBREAKC;
+
+ if (id < dc->config->ndbreak) {
+ TCGv_i32 tmp = tcg_const_i32(id);
+ gen_helper_wsr_dbreakc(cpu_env, tmp, v);
+ tcg_temp_free(tmp);
+ }
+}
+
static void gen_wsr_intset(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
tcg_gen_andi_i32(cpu_SR[sr], v,
gen_jumpi_check_loop_end(dc, -1);
}
+static void gen_wsr_debugcause(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+}
+
static void gen_wsr_prid(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
}
+static void gen_wsr_icount(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+ if (dc->icount) {
+ tcg_gen_mov_i32(dc->next_icount, v);
+ } else {
+ tcg_gen_mov_i32(cpu_SR[sr], v);
+ }
+}
+
+static void gen_wsr_icountlevel(DisasContext *dc, uint32_t sr, TCGv_i32 v)
+{
+ tcg_gen_andi_i32(cpu_SR[sr], v, 0xf);
+ /* This can change tb->flags, so exit tb */
+ gen_jumpi_check_loop_end(dc, -1);
+}
+
static void gen_wsr_ccompare(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
uint32_t id = sr - CCOMPARE;
[RASID] = gen_wsr_rasid,
[ITLBCFG] = gen_wsr_tlbcfg,
[DTLBCFG] = gen_wsr_tlbcfg,
+ [IBREAKENABLE] = gen_wsr_ibreakenable,
+ [IBREAKA] = gen_wsr_ibreaka,
+ [IBREAKA + 1] = gen_wsr_ibreaka,
+ [DBREAKA] = gen_wsr_dbreaka,
+ [DBREAKA + 1] = gen_wsr_dbreaka,
+ [DBREAKC] = gen_wsr_dbreakc,
+ [DBREAKC + 1] = gen_wsr_dbreakc,
[INTSET] = gen_wsr_intset,
[INTCLEAR] = gen_wsr_intclear,
[INTENABLE] = gen_wsr_intenable,
[PS] = gen_wsr_ps,
+ [DEBUGCAUSE] = gen_wsr_debugcause,
[PRID] = gen_wsr_prid,
+ [ICOUNT] = gen_wsr_icount,
+ [ICOUNTLEVEL] = gen_wsr_icountlevel,
[CCOMPARE] = gen_wsr_ccompare,
[CCOMPARE + 1] = gen_wsr_ccompare,
[CCOMPARE + 2] = gen_wsr_ccompare,
TCGv_i32 pc = tcg_const_i32(dc->next_pc);
TCGv_i32 intlevel = tcg_const_i32(imm4);
gen_advance_ccount(dc);
- gen_helper_waiti(pc, intlevel);
+ gen_helper_waiti(cpu_env, pc, intlevel);
tcg_temp_free(pc);
tcg_temp_free(intlevel);
}
dc->used_window = r1 / 4;
gen_advance_ccount(dc);
- gen_helper_window_check(pc, w);
+ gen_helper_window_check(cpu_env, pc, w);
tcg_temp_free(w);
tcg_temp_free(pc);
#define RSR_SR (b1)
- uint8_t b0 = ldub_code(dc->pc);
- uint8_t b1 = ldub_code(dc->pc + 1);
- uint8_t b2 = ldub_code(dc->pc + 2);
+ uint8_t b0 = cpu_ldub_code(cpu_single_env, dc->pc);
+ uint8_t b1 = cpu_ldub_code(cpu_single_env, dc->pc + 1);
+ uint8_t b2 = 0;
static const uint32_t B4CONST[] = {
0xffffffff, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256
HAS_OPTION(XTENSA_OPTION_CODE_DENSITY);
} else {
dc->next_pc = dc->pc + 3;
+ b2 = cpu_ldub_code(cpu_single_env, dc->pc + 2);
}
switch (OP0) {
{
TCGv_i32 tmp = tcg_const_i32(dc->pc);
gen_advance_ccount(dc);
- gen_helper_retw(tmp, tmp);
+ gen_helper_retw(tmp, cpu_env, tmp);
gen_jump(dc, tmp);
tcg_temp_free(tmp);
}
{
TCGv_i32 pc = tcg_const_i32(dc->pc);
gen_advance_ccount(dc);
- gen_helper_movsp(pc);
+ gen_helper_movsp(cpu_env, pc);
tcg_gen_mov_i32(cpu_R[RRR_T], cpu_R[RRR_S]);
tcg_temp_free(pc);
}
cpu_SR[WINDOW_START], tmp);
}
- gen_helper_restore_owb();
+ gen_helper_restore_owb(cpu_env);
gen_helper_check_interrupts(cpu_env);
gen_jump(dc, cpu_SR[EPC1]);
break;
case 4: /*BREAKx*/
- HAS_OPTION(XTENSA_OPTION_EXCEPTION);
- TBD();
+ HAS_OPTION(XTENSA_OPTION_DEBUG);
+ if (dc->debug) {
+ gen_debug_exception(dc, DEBUGCAUSE_BI);
+ }
break;
case 5: /*SYSCALLx*/
{
TCGv_i32 tmp = tcg_const_i32(
RRR_T | ((RRR_T & 8) ? 0xfffffff0 : 0));
- gen_helper_rotw(tmp);
+ gen_helper_rotw(cpu_env, tmp);
tcg_temp_free(tmp);
reset_used_window(dc);
}
break;
case 14: /*NSAu*/
- HAS_OPTION(XTENSA_OPTION_MISC_OP);
+ HAS_OPTION(XTENSA_OPTION_MISC_OP_NSA);
gen_window_check2(dc, RRR_S, RRR_T);
gen_helper_nsa(cpu_R[RRR_T], cpu_R[RRR_S]);
break;
case 15: /*NSAUu*/
- HAS_OPTION(XTENSA_OPTION_MISC_OP);
+ HAS_OPTION(XTENSA_OPTION_MISC_OP_NSA);
gen_window_check2(dc, RRR_S, RRR_T);
gen_helper_nsau(cpu_R[RRR_T], cpu_R[RRR_S]);
break;
switch (RRR_R & 7) {
case 3: /*RITLB0*/ /*RDTLB0*/
- gen_helper_rtlb0(cpu_R[RRR_T], cpu_R[RRR_S], dtlb);
+ gen_helper_rtlb0(cpu_R[RRR_T],
+ cpu_env, cpu_R[RRR_S], dtlb);
break;
case 4: /*IITLB*/ /*IDTLB*/
- gen_helper_itlb(cpu_R[RRR_S], dtlb);
+ gen_helper_itlb(cpu_env, cpu_R[RRR_S], dtlb);
/* This could change memory mapping, so exit tb */
gen_jumpi_check_loop_end(dc, -1);
break;
case 5: /*PITLB*/ /*PDTLB*/
tcg_gen_movi_i32(cpu_pc, dc->pc);
- gen_helper_ptlb(cpu_R[RRR_T], cpu_R[RRR_S], dtlb);
+ gen_helper_ptlb(cpu_R[RRR_T],
+ cpu_env, cpu_R[RRR_S], dtlb);
break;
case 6: /*WITLB*/ /*WDTLB*/
- gen_helper_wtlb(cpu_R[RRR_T], cpu_R[RRR_S], dtlb);
+ gen_helper_wtlb(
+ cpu_env, cpu_R[RRR_T], cpu_R[RRR_S], dtlb);
/* This could change memory mapping, so exit tb */
gen_jumpi_check_loop_end(dc, -1);
break;
case 7: /*RITLB1*/ /*RDTLB1*/
- gen_helper_rtlb1(cpu_R[RRR_T], cpu_R[RRR_S], dtlb);
+ gen_helper_rtlb1(cpu_R[RRR_T],
+ cpu_env, cpu_R[RRR_S], dtlb);
break;
default:
case 10: /*MULUHi*/
case 11: /*MULSHi*/
- HAS_OPTION(XTENSA_OPTION_32_BIT_IMUL);
+ HAS_OPTION(XTENSA_OPTION_32_BIT_IMUL_HIGH);
{
TCGv_i64 r = tcg_temp_new_i64();
TCGv_i64 s = tcg_temp_new_i64();
break;
case 2: /*SEXTu*/
- HAS_OPTION(XTENSA_OPTION_MISC_OP);
+ HAS_OPTION(XTENSA_OPTION_MISC_OP_SEXT);
gen_window_check2(dc, RRR_R, RRR_S);
{
int shift = 24 - RRR_T;
break;
case 3: /*CLAMPSu*/
- HAS_OPTION(XTENSA_OPTION_MISC_OP);
+ HAS_OPTION(XTENSA_OPTION_MISC_OP_CLAMPS);
gen_window_check2(dc, RRR_R, RRR_S);
{
TCGv_i32 tmp1 = tcg_temp_new_i32();
case 5: /*MAXu*/
case 6: /*MINUu*/
case 7: /*MAXUu*/
- HAS_OPTION(XTENSA_OPTION_MISC_OP);
+ HAS_OPTION(XTENSA_OPTION_MISC_OP_MINMAX);
gen_window_check3(dc, RRR_R, RRR_S, RRR_T);
{
static const TCGCond cond[] = {
break;
case 14: /*S32C1Iy*/
- HAS_OPTION(XTENSA_OPTION_MP_SYNCHRO);
+ HAS_OPTION(XTENSA_OPTION_CONDITIONAL_STORE);
gen_window_check2(dc, RRI8_S, RRI8_T);
{
int label = gen_new_label();
TCGv_i32 s = tcg_const_i32(BRI12_S);
TCGv_i32 imm = tcg_const_i32(BRI12_IMM12);
gen_advance_ccount(dc);
- gen_helper_entry(pc, s, imm);
+ gen_helper_entry(cpu_env, pc, s, imm);
tcg_temp_free(imm);
tcg_temp_free(s);
tcg_temp_free(pc);
tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_R[RRI8_S], 1);
tcg_gen_movi_i32(cpu_SR[LBEG], dc->next_pc);
- gen_wsr_lend(dc, LEND, tmp);
+ gen_helper_wsr_lend(cpu_env, tmp);
tcg_temp_free(tmp);
if (BRI8_R > 8) {
{
TCGv_i32 tmp = tcg_const_i32(dc->pc);
gen_advance_ccount(dc);
- gen_helper_retw(tmp, tmp);
+ gen_helper_retw(tmp, cpu_env, tmp);
gen_jump(dc, tmp);
tcg_temp_free(tmp);
}
break;
case 2: /*BREAK.Nn*/
- TBD();
+ HAS_OPTION(XTENSA_OPTION_DEBUG);
+ if (dc->debug) {
+ gen_debug_exception(dc, DEBUGCAUSE_BN);
+ }
break;
case 3: /*NOP.Nn*/
invalid_opcode:
qemu_log("INVALID(pc = %08x)\n", dc->pc);
- dc->pc = dc->next_pc;
+ gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE);
#undef HAS_OPTION
}
-static void check_breakpoint(CPUState *env, DisasContext *dc)
+static void check_breakpoint(CPUXtensaState *env, DisasContext *dc)
{
CPUBreakpoint *bp;
}
}
+static void gen_ibreak_check(CPUXtensaState *env, DisasContext *dc)
+{
+ unsigned i;
+
+ for (i = 0; i < dc->config->nibreak; ++i) {
+ if ((env->sregs[IBREAKENABLE] & (1 << i)) &&
+ env->sregs[IBREAKA + i] == dc->pc) {
+ gen_debug_exception(dc, DEBUGCAUSE_IB);
+ break;
+ }
+ }
+}
+
static void gen_intermediate_code_internal(
- CPUState *env, TranslationBlock *tb, int search_pc)
+ CPUXtensaState *env, TranslationBlock *tb, int search_pc)
{
DisasContext dc;
int insn_count = 0;
dc.lend = env->sregs[LEND];
dc.is_jmp = DISAS_NEXT;
dc.ccount_delta = 0;
+ dc.debug = tb->flags & XTENSA_TBFLAG_DEBUG;
+ dc.icount = tb->flags & XTENSA_TBFLAG_ICOUNT;
init_litbase(&dc);
init_sar_tracker(&dc);
reset_used_window(&dc);
+ if (dc.icount) {
+ dc.next_icount = tcg_temp_local_new_i32();
+ }
gen_icount_start();
gen_io_start();
}
+ if (dc.icount) {
+ int label = gen_new_label();
+
+ tcg_gen_addi_i32(dc.next_icount, cpu_SR[ICOUNT], 1);
+ tcg_gen_brcondi_i32(TCG_COND_NE, dc.next_icount, 0, label);
+ tcg_gen_mov_i32(dc.next_icount, cpu_SR[ICOUNT]);
+ if (dc.debug) {
+ gen_debug_exception(&dc, DEBUGCAUSE_IC);
+ }
+ gen_set_label(label);
+ }
+
+ if (dc.debug) {
+ gen_ibreak_check(env, &dc);
+ }
+
disas_xtensa_insn(&dc);
++insn_count;
+ if (dc.icount) {
+ tcg_gen_mov_i32(cpu_SR[ICOUNT], dc.next_icount);
+ }
if (env->singlestep_enabled) {
tcg_gen_movi_i32(cpu_pc, dc.pc);
gen_exception(&dc, EXCP_DEBUG);
reset_litbase(&dc);
reset_sar_tracker(&dc);
+ if (dc.icount) {
+ tcg_temp_free(dc.next_icount);
+ }
if (tb->cflags & CF_LAST_IO) {
gen_io_end();
}
}
-void gen_intermediate_code(CPUState *env, TranslationBlock *tb)
+void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb)
{
gen_intermediate_code_internal(env, tb, 0);
}
-void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
+void gen_intermediate_code_pc(CPUXtensaState *env, TranslationBlock *tb)
{
gen_intermediate_code_internal(env, tb, 1);
}
-void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
+void cpu_dump_state(CPUXtensaState *env, FILE *f, fprintf_function cpu_fprintf,
int flags)
{
int i, j;
}
}
-void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
+void restore_state_to_opc(CPUXtensaState *env, TranslationBlock *tb, int pc_pos)
{
env->pc = gen_opc_pc[pc_pos];
}