aboutsummaryrefslogtreecommitdiff
path: root/target-xtensa/translate.c
diff options
context:
space:
mode:
authorMax Filippov <jcmvbkbc@gmail.com>2012-01-13 09:21:32 +0400
committerMax Filippov <jcmvbkbc@gmail.com>2012-02-18 14:55:51 +0400
commite61dc8f72c096e084106d5e97101d9d88f642d0e (patch)
tree9f1040d377372c4771d9f061bd163fac5ea7e41b /target-xtensa/translate.c
parentab58c5b4fd07fbe94950ff459ef51d43cfb5b8c8 (diff)
target-xtensa: implement instruction breakpoints
Add IBREAKA/IBREAKENABLE SRs and implement debug exception, BREAK and BREAK.N instructions and IBREAK breakpoints. IBREAK breakpoint address is considered constant for TB lifetime. On IBREAKA/IBREAKENABLE change corresponding TBs are invalidated. Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Diffstat (limited to 'target-xtensa/translate.c')
-rw-r--r--target-xtensa/translate.c68
1 files changed, 65 insertions, 3 deletions
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index da5fdb5817..a438474b47 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -61,6 +61,8 @@ typedef struct DisasContext {
uint32_t ccount_delta;
unsigned used_window;
+
+ bool debug;
} DisasContext;
static TCGv_ptr cpu_env;
@@ -91,6 +93,9 @@ static const char * const sregnames[256] = {
[RASID] = "RASID",
[ITLBCFG] = "ITLBCFG",
[DTLBCFG] = "DTLBCFG",
+ [IBREAKENABLE] = "IBREAKENABLE",
+ [IBREAKA] = "IBREAKA0",
+ [IBREAKA + 1] = "IBREAKA1",
[EPC1] = "EPC1",
[EPC1 + 1] = "EPC2",
[EPC1 + 2] = "EPC3",
@@ -284,6 +289,19 @@ static void gen_exception_cause_vaddr(DisasContext *dc, uint32_t cause,
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(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) {
@@ -493,6 +511,24 @@ static void gen_wsr_tlbcfg(DisasContext *dc, uint32_t sr, TCGv_i32 v)
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(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(tmp, v);
+ tcg_temp_free(tmp);
+ gen_jumpi_check_loop_end(dc, 0);
+ }
+}
+
static void gen_wsr_intset(DisasContext *dc, uint32_t sr, TCGv_i32 v)
{
tcg_gen_andi_i32(cpu_SR[sr], v,
@@ -572,6 +608,9 @@ static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
[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,
[INTSET] = gen_wsr_intset,
[INTCLEAR] = gen_wsr_intclear,
[INTENABLE] = gen_wsr_intenable,
@@ -975,8 +1014,10 @@ static void disas_xtensa_insn(DisasContext *dc)
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*/
@@ -2356,7 +2397,10 @@ static void disas_xtensa_insn(DisasContext *dc)
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*/
@@ -2409,6 +2453,19 @@ static void check_breakpoint(CPUState *env, DisasContext *dc)
}
}
+static void gen_ibreak_check(CPUState *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)
{
@@ -2435,6 +2492,7 @@ static void gen_intermediate_code_internal(
dc.lend = env->sregs[LEND];
dc.is_jmp = DISAS_NEXT;
dc.ccount_delta = 0;
+ dc.debug = tb->flags & XTENSA_TBFLAG_DEBUG;
init_litbase(&dc);
init_sar_tracker(&dc);
@@ -2474,6 +2532,10 @@ static void gen_intermediate_code_internal(
gen_io_start();
}
+ if (dc.debug) {
+ gen_ibreak_check(env, &dc);
+ }
+
disas_xtensa_insn(&dc);
++insn_count;
if (env->singlestep_enabled) {