* [Qemu-devel] [RFC 1/9] target-xtensa: add DEBUGCAUSE SR and configuration
2012-01-29 2:19 [Qemu-devel] [RFC 0/9] target-xtensa: implement debug option Max Filippov
@ 2012-01-29 2:19 ` Max Filippov
2012-01-29 2:19 ` [Qemu-devel] [RFC 2/9] target-xtensa: implement instruction breakpoints Max Filippov
` (7 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Max Filippov @ 2012-01-29 2:19 UTC (permalink / raw)
To: qemu-devel; +Cc: jcmvbkbc
DEBUGCAUSE SR holds information about the most recent debug exception.
See ISA, 4.7.7 for more details.
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
target-xtensa/cpu.h | 15 +++++++++++++++
target-xtensa/translate.c | 6 ++++++
2 files changed, 21 insertions(+), 0 deletions(-)
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index 0db83a6..25245d8 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -137,6 +137,7 @@ enum {
PS = 230,
VECBASE = 231,
EXCCAUSE = 232,
+ DEBUGCAUSE = 233,
CCOUNT = 234,
PRID = 235,
EXCVADDR = 238,
@@ -161,6 +162,15 @@ enum {
#define PS_WOE 0x40000
+#define DEBUGCAUSE_IC 0x1
+#define DEBUGCAUSE_IB 0x2
+#define DEBUGCAUSE_DB 0x4
+#define DEBUGCAUSE_BI 0x8
+#define DEBUGCAUSE_BN 0x10
+#define DEBUGCAUSE_DI 0x20
+#define DEBUGCAUSE_DBNUM 0xf00
+#define DEBUGCAUSE_DBNUM_SHIFT 8
+
#define MAX_NAREG 64
#define MAX_NINTERRUPT 32
#define MAX_NLEVEL 6
@@ -279,6 +289,11 @@ typedef struct XtensaConfig {
uint32_t timerint[MAX_NCCOMPARE];
unsigned nextint;
unsigned extint[MAX_NINTERRUPT];
+
+ unsigned debug_level;
+ unsigned nibreak;
+ unsigned ndbreak;
+
uint32_t clock_freq_khz;
xtensa_tlb itlb;
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index c81450d..0786dd1 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -119,6 +119,7 @@ static const char * const sregnames[256] = {
[PS] = "PS",
[VECBASE] = "VECBASE",
[EXCCAUSE] = "EXCCAUSE",
+ [DEBUGCAUSE] = "DEBUGCAUSE",
[CCOUNT] = "CCOUNT",
[PRID] = "PRID",
[EXCVADDR] = "EXCVADDR",
@@ -535,6 +536,10 @@ static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 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)
{
}
@@ -571,6 +576,7 @@ static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
[INTCLEAR] = gen_wsr_intclear,
[INTENABLE] = gen_wsr_intenable,
[PS] = gen_wsr_ps,
+ [DEBUGCAUSE] = gen_wsr_debugcause,
[PRID] = gen_wsr_prid,
[CCOMPARE] = gen_wsr_ccompare,
[CCOMPARE + 1] = gen_wsr_ccompare,
--
1.7.7.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [RFC 2/9] target-xtensa: implement instruction breakpoints
2012-01-29 2:19 [Qemu-devel] [RFC 0/9] target-xtensa: implement debug option Max Filippov
2012-01-29 2:19 ` [Qemu-devel] [RFC 1/9] target-xtensa: add DEBUGCAUSE SR and configuration Max Filippov
@ 2012-01-29 2:19 ` Max Filippov
2012-01-29 2:19 ` [Qemu-devel] [RFC 3/9] target-xtensa: add ICOUNT SR and debug exception Max Filippov
` (6 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Max Filippov @ 2012-01-29 2:19 UTC (permalink / raw)
To: qemu-devel; +Cc: jcmvbkbc
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>
---
target-xtensa/cpu.h | 9 ++++++
target-xtensa/helper.c | 2 +
target-xtensa/helpers.h | 5 +++
target-xtensa/op_helper.c | 38 +++++++++++++++++++++++++
target-xtensa/translate.c | 68 +++++++++++++++++++++++++++++++++++++++++++--
5 files changed, 119 insertions(+), 3 deletions(-)
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index 25245d8..2875197 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -126,6 +126,8 @@ enum {
RASID = 90,
ITLBCFG = 91,
DTLBCFG = 92,
+ IBREAKENABLE = 96,
+ IBREAKA = 128,
EPC1 = 177,
DEPC = 192,
EPS2 = 194,
@@ -196,6 +198,7 @@ enum {
EXC_KERNEL,
EXC_USER,
EXC_DOUBLE,
+ EXC_DEBUG,
EXC_MAX
};
@@ -424,6 +427,7 @@ static inline int cpu_mmu_index(CPUState *env)
#define XTENSA_TBFLAG_RING_MASK 0x3
#define XTENSA_TBFLAG_EXCM 0x4
#define XTENSA_TBFLAG_LITBASE 0x8
+#define XTENSA_TBFLAG_DEBUG 0x10
static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
target_ulong *cs_base, int *flags)
@@ -439,6 +443,11 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
(env->sregs[LITBASE] & 1)) {
*flags |= XTENSA_TBFLAG_LITBASE;
}
+ if (xtensa_option_enabled(env->config, XTENSA_OPTION_DEBUG)) {
+ if (xtensa_get_cintlevel(env) < env->config->debug_level) {
+ *flags |= XTENSA_TBFLAG_DEBUG;
+ }
+ }
}
#include "cpu-all.h"
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index 2a0cb1a..b7e67b7 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -44,6 +44,7 @@ void cpu_reset(CPUXtensaState *env)
env->sregs[PS] = xtensa_option_enabled(env->config,
XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10;
env->sregs[VECBASE] = env->config->vecbase;
+ env->sregs[IBREAKENABLE] = 0;
env->pending_irq_level = 0;
reset_mmu(env);
@@ -193,6 +194,7 @@ void do_interrupt(CPUState *env)
case EXC_KERNEL:
case EXC_USER:
case EXC_DOUBLE:
+ case EXC_DEBUG:
qemu_log_mask(CPU_LOG_INT, "%s(%d) "
"pc = %08x, a0 = %08x, ps = %08x, ccount = %08x\n",
__func__, env->exception_index,
diff --git a/target-xtensa/helpers.h b/target-xtensa/helpers.h
index 09ab332..afe39d4 100644
--- a/target-xtensa/helpers.h
+++ b/target-xtensa/helpers.h
@@ -3,6 +3,8 @@
DEF_HELPER_1(exception, void, i32)
DEF_HELPER_2(exception_cause, void, i32, i32)
DEF_HELPER_3(exception_cause_vaddr, void, i32, i32, i32)
+DEF_HELPER_2(debug_exception, void, i32, i32)
+
DEF_HELPER_1(nsa, i32, i32)
DEF_HELPER_1(nsau, i32, i32)
DEF_HELPER_1(wsr_windowbase, void, i32)
@@ -29,4 +31,7 @@ DEF_HELPER_2(itlb, void, i32, i32)
DEF_HELPER_2(ptlb, i32, i32, i32)
DEF_HELPER_3(wtlb, void, i32, i32, i32)
+DEF_HELPER_1(wsr_ibreakenable, void, i32)
+DEF_HELPER_2(wsr_ibreaka, void, i32, i32)
+
#include "def-helper.h"
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
index 0605611..1feaaee 100644
--- a/target-xtensa/op_helper.c
+++ b/target-xtensa/op_helper.c
@@ -134,6 +134,19 @@ void HELPER(exception_cause_vaddr)(uint32_t pc, uint32_t cause, uint32_t vaddr)
HELPER(exception_cause)(pc, cause);
}
+void HELPER(debug_exception)(uint32_t pc, uint32_t cause)
+{
+ unsigned level = env->config->debug_level;
+
+ env->pc = pc;
+ env->sregs[DEBUGCAUSE] = cause;
+ env->sregs[EPC1 + level - 1] = pc;
+ env->sregs[EPS2 + level - 2] = env->sregs[PS];
+ env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) | PS_EXCM |
+ (level << PS_INTLEVEL_SHIFT);
+ HELPER(exception)(EXC_DEBUG);
+}
+
uint32_t HELPER(nsa)(uint32_t v)
{
if (v & 0x80000000) {
@@ -662,3 +675,28 @@ void HELPER(wtlb)(uint32_t p, uint32_t v, uint32_t dtlb)
split_tlb_entry_spec(v, dtlb, &vpn, &wi, &ei);
xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, p);
}
+
+
+void HELPER(wsr_ibreakenable)(uint32_t v)
+{
+ uint32_t change = v ^ env->sregs[IBREAKENABLE];
+ unsigned i;
+
+ for (i = 0; i < env->config->nibreak; ++i) {
+ if (change & (1 << i)) {
+ tb_invalidate_phys_page_range(
+ env->sregs[IBREAKA + i], env->sregs[IBREAKA + i] + 1, 0);
+ }
+ }
+ env->sregs[IBREAKENABLE] = v & ((1 << env->config->nibreak) - 1);
+}
+
+void HELPER(wsr_ibreaka)(uint32_t i, uint32_t v)
+{
+ if (env->sregs[IBREAKENABLE] & (1 << i) && env->sregs[IBREAKA + i] != v) {
+ tb_invalidate_phys_page_range(
+ env->sregs[IBREAKA + i], env->sregs[IBREAKA + i] + 1, 0);
+ tb_invalidate_phys_page_range(v, v + 1, 0);
+ }
+ env->sregs[IBREAKA + i] = v;
+}
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 0786dd1..71fbf34 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,
@@ -974,8 +1013,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*/
@@ -2355,7 +2396,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*/
@@ -2408,6 +2452,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)
{
@@ -2434,6 +2491,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);
@@ -2473,6 +2531,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) {
--
1.7.7.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [RFC 3/9] target-xtensa: add ICOUNT SR and debug exception
2012-01-29 2:19 [Qemu-devel] [RFC 0/9] target-xtensa: implement debug option Max Filippov
2012-01-29 2:19 ` [Qemu-devel] [RFC 1/9] target-xtensa: add DEBUGCAUSE SR and configuration Max Filippov
2012-01-29 2:19 ` [Qemu-devel] [RFC 2/9] target-xtensa: implement instruction breakpoints Max Filippov
@ 2012-01-29 2:19 ` Max Filippov
2012-01-29 2:19 ` [Qemu-devel] [RFC 4/9] exec: add missing breaks to the watch_mem_write Max Filippov
` (5 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Max Filippov @ 2012-01-29 2:19 UTC (permalink / raw)
To: qemu-devel; +Cc: jcmvbkbc
ICOUNT SR gets incremented on every instruction completion provided that
CINTLEVEL at the beginning of the instruction execution is lower than
ICOUNTLEVEL.
When ICOUNT would increment to 0 a debug exception is raised if
CINTLEVEL is lower than DEBUGLEVEL.
See ISA, 4.7.7.5 for more details.
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
target-xtensa/cpu.h | 6 +++++
target-xtensa/translate.c | 49 ++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 54 insertions(+), 1 deletions(-)
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index 2875197..fbe5d15 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -142,6 +142,8 @@ enum {
DEBUGCAUSE = 233,
CCOUNT = 234,
PRID = 235,
+ ICOUNT = 236,
+ ICOUNTLEVEL = 237,
EXCVADDR = 238,
CCOMPARE = 240,
};
@@ -428,6 +430,7 @@ static inline int cpu_mmu_index(CPUState *env)
#define XTENSA_TBFLAG_EXCM 0x4
#define XTENSA_TBFLAG_LITBASE 0x8
#define XTENSA_TBFLAG_DEBUG 0x10
+#define XTENSA_TBFLAG_ICOUNT 0x20
static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
target_ulong *cs_base, int *flags)
@@ -447,6 +450,9 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
if (xtensa_get_cintlevel(env) < env->config->debug_level) {
*flags |= XTENSA_TBFLAG_DEBUG;
}
+ if (xtensa_get_cintlevel(env) < env->sregs[ICOUNTLEVEL]) {
+ *flags |= XTENSA_TBFLAG_ICOUNT;
+ }
}
}
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 71fbf34..85f41a7 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -63,6 +63,8 @@ typedef struct DisasContext {
unsigned used_window;
bool debug;
+ bool icount;
+ TCGv_i32 next_icount;
} DisasContext;
static TCGv_ptr cpu_env;
@@ -127,6 +129,8 @@ static const char * const sregnames[256] = {
[DEBUGCAUSE] = "DEBUGCAUSE",
[CCOUNT] = "CCOUNT",
[PRID] = "PRID",
+ [ICOUNT] = "ICOUNT",
+ [ICOUNTLEVEL] = "ICOUNTLEVEL",
[EXCVADDR] = "EXCVADDR",
[CCOMPARE] = "CCOMPARE0",
[CCOMPARE + 1] = "CCOMPARE1",
@@ -313,10 +317,13 @@ static void gen_check_privilege(DisasContext *dc)
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);
@@ -580,6 +587,22 @@ 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;
@@ -617,6 +640,8 @@ static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
[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,
@@ -2492,10 +2517,14 @@ static void gen_intermediate_code_internal(
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();
@@ -2531,12 +2560,27 @@ static void gen_intermediate_code_internal(
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);
@@ -2549,6 +2593,9 @@ static void gen_intermediate_code_internal(
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();
--
1.7.7.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [RFC 4/9] exec: add missing breaks to the watch_mem_write
2012-01-29 2:19 [Qemu-devel] [RFC 0/9] target-xtensa: implement debug option Max Filippov
` (2 preceding siblings ...)
2012-01-29 2:19 ` [Qemu-devel] [RFC 3/9] target-xtensa: add ICOUNT SR and debug exception Max Filippov
@ 2012-01-29 2:19 ` Max Filippov
2012-01-29 9:49 ` Andreas Färber
2012-01-29 2:19 ` [Qemu-devel] [RFC 5/9] exec: fix check_watchpoint exiting cpu_loop Max Filippov
` (4 subsequent siblings)
8 siblings, 1 reply; 11+ messages in thread
From: Max Filippov @ 2012-01-29 2:19 UTC (permalink / raw)
To: qemu-devel; +Cc: jcmvbkbc
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
exec.c | 12 +++++++++---
1 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/exec.c b/exec.c
index 5b9eb9a..0e93e0e 100644
--- a/exec.c
+++ b/exec.c
@@ -3279,9 +3279,15 @@ static void watch_mem_write(void *opaque, target_phys_addr_t addr,
{
check_watchpoint(addr & ~TARGET_PAGE_MASK, ~(size - 1), BP_MEM_WRITE);
switch (size) {
- case 1: stb_phys(addr, val);
- case 2: stw_phys(addr, val);
- case 4: stl_phys(addr, val);
+ case 1:
+ stb_phys(addr, val);
+ break;
+ case 2:
+ stw_phys(addr, val);
+ break;
+ case 4:
+ stl_phys(addr, val);
+ break;
default: abort();
}
}
--
1.7.7.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [RFC 4/9] exec: add missing breaks to the watch_mem_write
2012-01-29 2:19 ` [Qemu-devel] [RFC 4/9] exec: add missing breaks to the watch_mem_write Max Filippov
@ 2012-01-29 9:49 ` Andreas Färber
0 siblings, 0 replies; 11+ messages in thread
From: Andreas Färber @ 2012-01-29 9:49 UTC (permalink / raw)
To: Max Filippov; +Cc: qemu-devel
Am 29.01.2012 03:19, schrieb Max Filippov:
> Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Reviewed-by: Andreas Färber <afaerber@suse.de>
Good catch!
Andreas
> ---
> exec.c | 12 +++++++++---
> 1 files changed, 9 insertions(+), 3 deletions(-)
>
> diff --git a/exec.c b/exec.c
> index 5b9eb9a..0e93e0e 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -3279,9 +3279,15 @@ static void watch_mem_write(void *opaque, target_phys_addr_t addr,
> {
> check_watchpoint(addr & ~TARGET_PAGE_MASK, ~(size - 1), BP_MEM_WRITE);
> switch (size) {
> - case 1: stb_phys(addr, val);
> - case 2: stw_phys(addr, val);
> - case 4: stl_phys(addr, val);
> + case 1:
> + stb_phys(addr, val);
> + break;
> + case 2:
> + stw_phys(addr, val);
> + break;
> + case 4:
> + stl_phys(addr, val);
> + break;
> default: abort();
> }
> }
--
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Qemu-devel] [RFC 5/9] exec: fix check_watchpoint exiting cpu_loop
2012-01-29 2:19 [Qemu-devel] [RFC 0/9] target-xtensa: implement debug option Max Filippov
` (3 preceding siblings ...)
2012-01-29 2:19 ` [Qemu-devel] [RFC 4/9] exec: add missing breaks to the watch_mem_write Max Filippov
@ 2012-01-29 2:19 ` Max Filippov
2012-01-29 2:19 ` [Qemu-devel] [RFC 6/9] exec: let cpu_watchpoint_insert accept larger watchpoints Max Filippov
` (3 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Max Filippov @ 2012-01-29 2:19 UTC (permalink / raw)
To: qemu-devel; +Cc: jcmvbkbc
In case of BP_STOP_BEFORE_ACCESS watchpoint check_watchpoint intends to
signal EXCP_DEBUG exception on exit from cpu loop, but later overwrites
exception code by the cpu_resume_from_signal call.
Use cpu_loop_exit with BP_STOP_BEFORE_ACCESS watchpoints.
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
exec.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/exec.c b/exec.c
index 0e93e0e..bc6c185 100644
--- a/exec.c
+++ b/exec.c
@@ -3247,11 +3247,12 @@ static void check_watchpoint(int offset, int len_mask, int flags)
tb_phys_invalidate(tb, -1);
if (wp->flags & BP_STOP_BEFORE_ACCESS) {
env->exception_index = EXCP_DEBUG;
+ cpu_loop_exit(env);
} else {
cpu_get_tb_cpu_state(env, &pc, &cs_base, &cpu_flags);
tb_gen_code(env, pc, cs_base, cpu_flags, 1);
+ cpu_resume_from_signal(env, NULL);
}
- cpu_resume_from_signal(env, NULL);
}
} else {
wp->flags &= ~BP_WATCHPOINT_HIT;
--
1.7.7.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [RFC 6/9] exec: let cpu_watchpoint_insert accept larger watchpoints
2012-01-29 2:19 [Qemu-devel] [RFC 0/9] target-xtensa: implement debug option Max Filippov
` (4 preceding siblings ...)
2012-01-29 2:19 ` [Qemu-devel] [RFC 5/9] exec: fix check_watchpoint exiting cpu_loop Max Filippov
@ 2012-01-29 2:19 ` Max Filippov
2012-01-29 2:19 ` [Qemu-devel] [RFC 7/9] target-xtensa: add DBREAK data breakpoints Max Filippov
` (2 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Max Filippov @ 2012-01-29 2:19 UTC (permalink / raw)
To: qemu-devel; +Cc: jcmvbkbc
Make cpu_watchpoint_insert accept watchpoints of any power-of-two size
up to the target page size.
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
exec.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/exec.c b/exec.c
index bc6c185..39a5497 100644
--- a/exec.c
+++ b/exec.c
@@ -1443,7 +1443,8 @@ int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len,
CPUWatchpoint *wp;
/* sanity checks: allow power-of-2 lengths, deny unaligned watchpoints */
- if ((len != 1 && len != 2 && len != 4 && len != 8) || (addr & ~len_mask)) {
+ if ((len & (len - 1)) || (addr & ~len_mask) ||
+ len == 0 || len > TARGET_PAGE_SIZE) {
fprintf(stderr, "qemu: tried to set invalid watchpoint at "
TARGET_FMT_lx ", len=" TARGET_FMT_lu "\n", addr, len);
return -EINVAL;
--
1.7.7.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [RFC 7/9] target-xtensa: add DBREAK data breakpoints
2012-01-29 2:19 [Qemu-devel] [RFC 0/9] target-xtensa: implement debug option Max Filippov
` (5 preceding siblings ...)
2012-01-29 2:19 ` [Qemu-devel] [RFC 6/9] exec: let cpu_watchpoint_insert accept larger watchpoints Max Filippov
@ 2012-01-29 2:19 ` Max Filippov
2012-01-29 2:19 ` [Qemu-devel] [RFC 8/9] target-xtensa: add DEBUG_SECTION to overlay tool Max Filippov
2012-01-29 2:19 ` [Qemu-devel] [RFC 9/9] target-xtensa: add breakpoint tests Max Filippov
8 siblings, 0 replies; 11+ messages in thread
From: Max Filippov @ 2012-01-29 2:19 UTC (permalink / raw)
To: qemu-devel; +Cc: jcmvbkbc
Add DBREAKA/DBREAKC SRs and implement DBREAK breakpoints as debug
watchpoints.
This implementation is not fully compliant to ISA: when a breakpoint is
set to an unmapped/inaccessible memory address it generates TLB/memory
protection exception instead of debug exception.
See ISA, 4.7.7.3, 4.7.7.6 for more details.
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
target-xtensa/cpu.h | 12 ++++++++
target-xtensa/helper.c | 41 +++++++++++++++++++++++++++++
target-xtensa/helpers.h | 2 +
target-xtensa/op_helper.c | 62 +++++++++++++++++++++++++++++++++++++++++++++
target-xtensa/translate.c | 30 +++++++++++++++++++++
5 files changed, 147 insertions(+), 0 deletions(-)
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index fbe5d15..4dbd7b7 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -128,6 +128,8 @@ enum {
DTLBCFG = 92,
IBREAKENABLE = 96,
IBREAKA = 128,
+ DBREAKA = 144,
+ DBREAKC = 160,
EPC1 = 177,
DEPC = 192,
EPS2 = 194,
@@ -175,12 +177,18 @@ enum {
#define DEBUGCAUSE_DBNUM 0xf00
#define DEBUGCAUSE_DBNUM_SHIFT 8
+#define DBREAKC_SB 0x80000000
+#define DBREAKC_LB 0x40000000
+#define DBREAKC_SB_LB (DBREAKC_SB | DBREAKC_LB)
+#define DBREAKC_MASK 0x3f
+
#define MAX_NAREG 64
#define MAX_NINTERRUPT 32
#define MAX_NLEVEL 6
#define MAX_NNMI 1
#define MAX_NCCOMPARE 3
#define MAX_TLB_WAY_SIZE 8
+#define MAX_NDBREAK 2
#define REGION_PAGE_MASK 0xe0000000
@@ -330,6 +338,9 @@ typedef struct CPUXtensaState {
int exception_taken;
+ /* Watchpoints for DBREAK registers */
+ CPUWatchpoint *cpu_watchpoint[MAX_NDBREAK];
+
CPU_COMMON
} CPUXtensaState;
@@ -364,6 +375,7 @@ void xtensa_tlb_set_entry(CPUState *env, bool dtlb,
int xtensa_get_physical_addr(CPUState *env,
uint32_t vaddr, int is_write, int mmu_idx,
uint32_t *paddr, uint32_t *page_size, unsigned *access);
+void debug_exception_env(CPUState *new_env, uint32_t cause);
#define XTENSA_OPTION_BIT(opt) (((uint64_t)1) << (opt))
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index b7e67b7..a0bf697 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -58,9 +58,44 @@ void xtensa_register_core(XtensaConfigList *node)
xtensa_cores = node;
}
+static uint32_t check_hw_breakpoints(CPUState *env)
+{
+ unsigned i;
+
+ for (i = 0; i < env->config->ndbreak; ++i) {
+ if (env->cpu_watchpoint[i] &&
+ env->cpu_watchpoint[i]->flags & BP_WATCHPOINT_HIT) {
+ return DEBUGCAUSE_DB | (i << DEBUGCAUSE_DBNUM_SHIFT);
+ }
+ }
+ return 0;
+}
+
+static CPUDebugExcpHandler *prev_debug_excp_handler;
+
+static void breakpoint_handler(CPUState *env)
+{
+ if (env->watchpoint_hit) {
+ if (env->watchpoint_hit->flags & BP_CPU) {
+ uint32_t cause;
+
+ env->watchpoint_hit = NULL;
+ cause = check_hw_breakpoints(env);
+ if (cause) {
+ debug_exception_env(env, cause);
+ }
+ cpu_resume_from_signal(env, NULL);
+ }
+ }
+ if (prev_debug_excp_handler) {
+ prev_debug_excp_handler(env);
+ }
+}
+
CPUXtensaState *cpu_xtensa_init(const char *cpu_model)
{
static int tcg_inited;
+ static int debug_handler_inited;
CPUXtensaState *env;
const XtensaConfig *config = NULL;
XtensaConfigList *core = xtensa_cores;
@@ -84,6 +119,12 @@ CPUXtensaState *cpu_xtensa_init(const char *cpu_model)
xtensa_translate_init();
}
+ if (!debug_handler_inited && tcg_enabled()) {
+ debug_handler_inited = 1;
+ prev_debug_excp_handler =
+ cpu_set_debug_excp_handler(breakpoint_handler);
+ }
+
xtensa_irq_init(env);
qemu_init_vcpu(env);
return env;
diff --git a/target-xtensa/helpers.h b/target-xtensa/helpers.h
index afe39d4..48a741e 100644
--- a/target-xtensa/helpers.h
+++ b/target-xtensa/helpers.h
@@ -33,5 +33,7 @@ DEF_HELPER_3(wtlb, void, i32, i32, i32)
DEF_HELPER_1(wsr_ibreakenable, void, i32)
DEF_HELPER_2(wsr_ibreaka, void, i32, i32)
+DEF_HELPER_2(wsr_dbreaka, void, i32, i32)
+DEF_HELPER_2(wsr_dbreakc, void, i32, i32)
#include "def-helper.h"
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
index 1feaaee..e184cf6 100644
--- a/target-xtensa/op_helper.c
+++ b/target-xtensa/op_helper.c
@@ -134,6 +134,14 @@ void HELPER(exception_cause_vaddr)(uint32_t pc, uint32_t cause, uint32_t vaddr)
HELPER(exception_cause)(pc, cause);
}
+void debug_exception_env(CPUState *new_env, uint32_t cause)
+{
+ if (xtensa_get_cintlevel(new_env) < new_env->config->debug_level) {
+ env = new_env;
+ HELPER(debug_exception)(env->pc, cause);
+ }
+}
+
void HELPER(debug_exception)(uint32_t pc, uint32_t cause)
{
unsigned level = env->config->debug_level;
@@ -700,3 +708,57 @@ void HELPER(wsr_ibreaka)(uint32_t i, uint32_t v)
}
env->sregs[IBREAKA + i] = v;
}
+
+static void set_dbreak(unsigned i, uint32_t dbreaka, uint32_t dbreakc)
+{
+ int flags = BP_CPU | BP_STOP_BEFORE_ACCESS;
+ uint32_t mask = dbreakc | ~DBREAKC_MASK;
+
+ if (env->cpu_watchpoint[i]) {
+ cpu_watchpoint_remove_by_ref(env, env->cpu_watchpoint[i]);
+ }
+ if (dbreakc & DBREAKC_SB) {
+ flags |= BP_MEM_WRITE;
+ }
+ if (dbreakc & DBREAKC_LB) {
+ flags |= BP_MEM_READ;
+ }
+ /* contiguous mask after inversion is one less than some power of 2 */
+ if ((~mask + 1) & ~mask) {
+ qemu_log("DBREAKC mask is not contiguous: 0x%08x\n", dbreakc);
+ /* cut mask after the first zero bit */
+ mask = 0xffffffff << (32 - clo32(mask));
+ }
+ if (cpu_watchpoint_insert(env, dbreaka & mask, ~mask + 1,
+ flags, &env->cpu_watchpoint[i])) {
+ env->cpu_watchpoint[i] = NULL;
+ qemu_log("Failed to set data breakpoint at 0x%08x/%d\n",
+ dbreaka & mask, ~mask + 1);
+ }
+}
+
+void HELPER(wsr_dbreaka)(uint32_t i, uint32_t v)
+{
+ uint32_t dbreakc = env->sregs[DBREAKC + i];
+
+ if ((dbreakc & DBREAKC_SB_LB) &&
+ env->sregs[DBREAKA + i] != v) {
+ set_dbreak(i, v, dbreakc);
+ }
+ env->sregs[DBREAKA + i] = v;
+}
+
+void HELPER(wsr_dbreakc)(uint32_t i, uint32_t v)
+{
+ if ((env->sregs[DBREAKC + i] ^ v) & (DBREAKC_SB_LB | DBREAKC_MASK)) {
+ if (v & DBREAKC_SB_LB) {
+ set_dbreak(i, env->sregs[DBREAKA + i], v);
+ } else {
+ if (env->cpu_watchpoint[i]) {
+ cpu_watchpoint_remove_by_ref(env, env->cpu_watchpoint[i]);
+ env->cpu_watchpoint[i] = NULL;
+ }
+ }
+ }
+ env->sregs[DBREAKC + i] = v;
+}
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 85f41a7..0a68f54 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -98,6 +98,10 @@ static const char * const sregnames[256] = {
[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",
@@ -536,6 +540,28 @@ static void gen_wsr_ibreaka(DisasContext *dc, uint32_t sr, TCGv_i32 v)
}
}
+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(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(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,
@@ -634,6 +660,10 @@ static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s)
[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,
--
1.7.7.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [RFC 8/9] target-xtensa: add DEBUG_SECTION to overlay tool
2012-01-29 2:19 [Qemu-devel] [RFC 0/9] target-xtensa: implement debug option Max Filippov
` (6 preceding siblings ...)
2012-01-29 2:19 ` [Qemu-devel] [RFC 7/9] target-xtensa: add DBREAK data breakpoints Max Filippov
@ 2012-01-29 2:19 ` Max Filippov
2012-01-29 2:19 ` [Qemu-devel] [RFC 9/9] target-xtensa: add breakpoint tests Max Filippov
8 siblings, 0 replies; 11+ messages in thread
From: Max Filippov @ 2012-01-29 2:19 UTC (permalink / raw)
To: qemu-devel; +Cc: jcmvbkbc
Fill debug configuration from overlay definitions in the DEBUG_SECTION.
Add DEBUG_SECTION to DC232B and FSF cores.
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
target-xtensa/core-dc232b.c | 1 +
target-xtensa/core-fsf.c | 1 +
target-xtensa/overlay_tool.h | 5 +++++
3 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/target-xtensa/core-dc232b.c b/target-xtensa/core-dc232b.c
index 4d9bd55..b723c4c 100644
--- a/target-xtensa/core-dc232b.c
+++ b/target-xtensa/core-dc232b.c
@@ -22,6 +22,7 @@ static const XtensaConfig dc232b = {
EXCEPTIONS_SECTION,
INTERRUPTS_SECTION,
TLB_SECTION,
+ DEBUG_SECTION,
.clock_freq_khz = 10000,
};
diff --git a/target-xtensa/core-fsf.c b/target-xtensa/core-fsf.c
index 7650462..88de4dd 100644
--- a/target-xtensa/core-fsf.c
+++ b/target-xtensa/core-fsf.c
@@ -16,6 +16,7 @@ static const XtensaConfig fsf = {
EXCEPTIONS_SECTION,
INTERRUPTS_SECTION,
TLB_SECTION,
+ DEBUG_SECTION,
.clock_freq_khz = 10000,
};
diff --git a/target-xtensa/overlay_tool.h b/target-xtensa/overlay_tool.h
index df19cc9..cbb4aa6 100644
--- a/target-xtensa/overlay_tool.h
+++ b/target-xtensa/overlay_tool.h
@@ -114,6 +114,7 @@
[EXC_KERNEL] = XCHAL_KERNEL_VECTOR_VADDR, \
[EXC_USER] = XCHAL_USER_VECTOR_VADDR, \
[EXC_DOUBLE] = XCHAL_DOUBLEEXC_VECTOR_VADDR, \
+ [EXC_DEBUG] = XCHAL_DEBUG_VECTOR_VADDR, \
}
#define INTERRUPT_VECTORS { \
@@ -288,6 +289,10 @@
#define REGISTER_CORE(core)
#endif
+#define DEBUG_SECTION \
+ .debug_level = XCHAL_DEBUGLEVEL, \
+ .nibreak = XCHAL_NUM_IBREAK, \
+ .ndbreak = XCHAL_NUM_DBREAK
#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI + 1 <= 2
#define XCHAL_INTLEVEL2_VECTOR_VADDR 0
--
1.7.7.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [RFC 9/9] target-xtensa: add breakpoint tests
2012-01-29 2:19 [Qemu-devel] [RFC 0/9] target-xtensa: implement debug option Max Filippov
` (7 preceding siblings ...)
2012-01-29 2:19 ` [Qemu-devel] [RFC 8/9] target-xtensa: add DEBUG_SECTION to overlay tool Max Filippov
@ 2012-01-29 2:19 ` Max Filippov
8 siblings, 0 replies; 11+ messages in thread
From: Max Filippov @ 2012-01-29 2:19 UTC (permalink / raw)
To: qemu-devel; +Cc: jcmvbkbc
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
tests/tcg/xtensa/Makefile | 1 +
tests/tcg/xtensa/test_break.S | 223 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 224 insertions(+), 0 deletions(-)
create mode 100644 tests/tcg/xtensa/test_break.S
diff --git a/tests/tcg/xtensa/Makefile b/tests/tcg/xtensa/Makefile
index 8713af1..7e1e619 100644
--- a/tests/tcg/xtensa/Makefile
+++ b/tests/tcg/xtensa/Makefile
@@ -23,6 +23,7 @@ CRT = crt.o vectors.o
TESTCASES += test_b.tst
TESTCASES += test_bi.tst
#TESTCASES += test_boolean.tst
+TESTCASES += test_break.tst
TESTCASES += test_bz.tst
TESTCASES += test_clamps.tst
TESTCASES += test_fail.tst
diff --git a/tests/tcg/xtensa/test_break.S b/tests/tcg/xtensa/test_break.S
new file mode 100644
index 0000000..8a8db80
--- /dev/null
+++ b/tests/tcg/xtensa/test_break.S
@@ -0,0 +1,223 @@
+.include "macros.inc"
+
+#define debug_level 6
+#define debug_vector level6
+
+test_suite break
+
+test break
+ set_vector debug_vector, 0
+ rsil a2, debug_level
+ _break 0, 0
+
+ set_vector debug_vector, 2f
+ rsil a2, debug_level - 1
+1:
+ _break 0, 0
+ test_fail
+2:
+ rsr a2, ps
+ movi a3, 0x1f
+ and a2, a2, a3
+ movi a3, 0x10 | debug_level
+ assert eq, a2, a3
+ rsr a2, epc6
+ movi a3, 1b
+ assert eq, a2, a3
+ rsr a2, debugcause
+ movi a3, 0x8
+ assert eq, a2, a3
+test_end
+
+test breakn
+ set_vector debug_vector, 0
+ rsil a2, debug_level
+ _break.n 0
+
+ set_vector debug_vector, 2f
+ rsil a2, debug_level - 1
+1:
+ _break.n 0
+ test_fail
+2:
+ rsr a2, ps
+ movi a3, 0x1f
+ and a2, a2, a3
+ movi a3, 0x10 | debug_level
+ assert eq, a2, a3
+ rsr a2, epc6
+ movi a3, 1b
+ assert eq, a2, a3
+ rsr a2, debugcause
+ movi a3, 0x10
+ assert eq, a2, a3
+test_end
+
+test ibreak
+ set_vector debug_vector, 0
+ rsil a2, debug_level
+ movi a2, 1f
+ wsr a2, ibreaka0
+ movi a2, 1
+ wsr a2, ibreakenable
+ isync
+1:
+ rsil a2, debug_level - 1
+ movi a2, 1f
+ wsr a2, ibreaka0
+ movi a2, 0
+ wsr a2, ibreakenable
+ isync
+1:
+ set_vector debug_vector, 2f
+ movi a2, 1f
+ wsr a2, ibreaka0
+ movi a2, 1
+ wsr a2, ibreakenable
+ isync
+1:
+ test_fail
+2:
+ rsr a2, ps
+ movi a3, 0x1f
+ and a2, a2, a3
+ movi a3, 0x10 | debug_level
+ assert eq, a2, a3
+ rsr a2, epc6
+ movi a3, 1b
+ assert eq, a2, a3
+ rsr a2, debugcause
+ movi a3, 0x2
+ assert eq, a2, a3
+test_end
+
+test ibreak_priority
+ set_vector debug_vector, 2f
+ rsil a2, debug_level - 1
+ movi a2, 1f
+ wsr a2, ibreaka0
+ movi a2, 1
+ wsr a2, ibreakenable
+ isync
+1:
+ break 0, 0
+ test_fail
+2:
+ rsr a2, debugcause
+ movi a3, 0x2
+ assert eq, a2, a3
+test_end
+
+test icount
+ set_vector debug_vector, 2f
+ rsil a2, debug_level - 1
+ movi a2, -2
+ wsr a2, icount
+ movi a2, 1
+ wsr a2, icountlevel
+ isync
+ rsil a2, 0
+ nop
+1:
+ break 0, 0
+ test_fail
+2:
+ movi a2, 0
+ wsr a2, icountlevel
+ rsr a2, epc6
+ movi a3, 1b
+ assert eq, a2, a3
+ rsr a2, debugcause
+ movi a3, 0x1
+ assert eq, a2, a3
+test_end
+
+.macro check_dbreak dr
+ rsr a2, epc6
+ movi a3, 1b
+ assert eq, a2, a3
+ rsr a2, debugcause
+ movi a3, 0x4 | (\dr << 8)
+ assert eq, a2, a3
+ movi a2, 0
+ wsr a2, dbreakc\dr
+.endm
+
+.macro dbreak_test dr, ctl, break, access, op
+ set_vector debug_vector, 2f
+ rsil a2, debug_level - 1
+ movi a2, \ctl
+ wsr a2, dbreakc\dr
+ movi a2, \break
+ wsr a2, dbreaka\dr
+ movi a2, \access
+ isync
+1:
+ \op a3, a2, 0
+ test_fail
+2:
+ check_dbreak \dr
+ reset_ps
+.endm
+
+test dbreak_exact
+ dbreak_test 0, 0x4000003f, 0xd000007f, 0xd000007f, l8ui
+ dbreak_test 1, 0x4000003e, 0xd000007e, 0xd000007e, l16ui
+ dbreak_test 0, 0x4000003c, 0xd000007c, 0xd000007c, l32i
+
+ dbreak_test 1, 0x8000003f, 0xd000007f, 0xd000007f, s8i
+ dbreak_test 0, 0x8000003e, 0xd000007e, 0xd000007e, s16i
+ dbreak_test 1, 0x8000003c, 0xd000007c, 0xd000007c, s32i
+test_end
+
+test dbreak_overlap
+ dbreak_test 0, 0x4000003f, 0xd000007d, 0xd000007c, l16ui
+ dbreak_test 1, 0x4000003f, 0xd000007d, 0xd000007c, l32i
+
+ dbreak_test 0, 0x4000003e, 0xd000007e, 0xd000007f, l8ui
+ dbreak_test 1, 0x4000003e, 0xd000007e, 0xd000007c, l32i
+
+ dbreak_test 0, 0x4000003c, 0xd000007c, 0xd000007d, l8ui
+ dbreak_test 1, 0x4000003c, 0xd000007c, 0xd000007c, l16ui
+
+ dbreak_test 0, 0x40000038, 0xd0000078, 0xd000007b, l8ui
+ dbreak_test 1, 0x40000038, 0xd0000078, 0xd000007a, l16ui
+ dbreak_test 0, 0x40000038, 0xd0000078, 0xd000007c, l32i
+
+ dbreak_test 1, 0x40000030, 0xd0000070, 0xd0000075, l8ui
+ dbreak_test 0, 0x40000030, 0xd0000070, 0xd0000076, l16ui
+ dbreak_test 1, 0x40000030, 0xd0000070, 0xd0000078, l32i
+
+ dbreak_test 0, 0x40000020, 0xd0000060, 0xd000006f, l8ui
+ dbreak_test 1, 0x40000020, 0xd0000060, 0xd0000070, l16ui
+ dbreak_test 0, 0x40000020, 0xd0000060, 0xd0000074, l32i
+
+
+ dbreak_test 0, 0x8000003f, 0xd000007d, 0xd000007c, s16i
+ dbreak_test 1, 0x8000003f, 0xd000007d, 0xd000007c, s32i
+
+ dbreak_test 0, 0x8000003e, 0xd000007e, 0xd000007f, s8i
+ dbreak_test 1, 0x8000003e, 0xd000007e, 0xd000007c, s32i
+
+ dbreak_test 0, 0x8000003c, 0xd000007c, 0xd000007d, s8i
+ dbreak_test 1, 0x8000003c, 0xd000007c, 0xd000007c, s16i
+
+ dbreak_test 0, 0x80000038, 0xd0000078, 0xd000007b, s8i
+ dbreak_test 1, 0x80000038, 0xd0000078, 0xd000007a, s16i
+ dbreak_test 0, 0x80000038, 0xd0000078, 0xd000007c, s32i
+
+ dbreak_test 1, 0x80000030, 0xd0000070, 0xd0000075, s8i
+ dbreak_test 0, 0x80000030, 0xd0000070, 0xd0000076, s16i
+ dbreak_test 1, 0x80000030, 0xd0000070, 0xd0000078, s32i
+
+ dbreak_test 0, 0x80000020, 0xd0000060, 0xd000006f, s8i
+ dbreak_test 1, 0x80000020, 0xd0000060, 0xd0000070, s16i
+ dbreak_test 0, 0x80000020, 0xd0000060, 0xd0000074, s32i
+test_end
+
+test dbreak_invalid
+ dbreak_test 0, 0x40000030, 0xd0000071, 0xd0000070, l16ui
+ dbreak_test 1, 0x40000035, 0xd0000072, 0xd0000070, l32i
+test_end
+
+test_suite_end
--
1.7.7.6
^ permalink raw reply related [flat|nested] 11+ messages in thread