sim-card
/
qemu
Archived
10
0
Fork 0

Merge branch 'xtensa' of git://jcmvbkbc.spb.ru/dumb/qemu-xtensa

* 'xtensa' of git://jcmvbkbc.spb.ru/dumb/qemu-xtensa:
  target-xtensa: add breakpoint tests
  target-xtensa: add DEBUG_SECTION to overlay tool
  target-xtensa: add DBREAK data breakpoints
  exec: let cpu_watchpoint_insert accept larger watchpoints
  exec: fix check_watchpoint exiting cpu_loop
  exec: add missing breaks to the watch_mem_write
  target-xtensa: add ICOUNT SR and debug exception
  target-xtensa: implement instruction breakpoints
  target-xtensa: add DEBUGCAUSE SR and configuration
  target-xtensa: fetch 3rd opcode byte only when needed
  target-xtensa: implement info tlb monitor command
  target-xtensa: define TLB_TEMPLATE for MMU-less cores
This commit is contained in:
Blue Swirl 2012-03-03 17:53:41 +00:00
commit b3e54c689c
13 changed files with 674 additions and 15 deletions

18
exec.c
View File

@ -1504,7 +1504,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;
@ -3331,11 +3332,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;
@ -3363,9 +3365,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();
}
}

View File

@ -1355,7 +1355,7 @@ show i8259 (PIC) state
@item info pci
show emulated PCI device info
@item info tlb
show virtual to physical memory mappings (i386, SH4, SPARC, and PPC only)
show virtual to physical memory mappings (i386, SH4, SPARC, PPC, and Xtensa only)
@item info mem
show the active virtual memory mappings (i386 only)
@item info jit

View File

@ -1949,7 +1949,7 @@ static void tlb_info(Monitor *mon)
#endif
#if defined(TARGET_SPARC) || defined(TARGET_PPC)
#if defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_XTENSA)
static void tlb_info(Monitor *mon)
{
CPUState *env1 = mon_get_cpu();
@ -2396,7 +2396,7 @@ static mon_cmd_t info_cmds[] = {
.mhandler.info = hmp_info_pci,
},
#if defined(TARGET_I386) || defined(TARGET_SH4) || defined(TARGET_SPARC) || \
defined(TARGET_PPC)
defined(TARGET_PPC) || defined(TARGET_XTENSA)
{
.name = "tlb",
.args_type = "",

View File

@ -22,6 +22,7 @@ static const XtensaConfig dc232b = {
EXCEPTIONS_SECTION,
INTERRUPTS_SECTION,
TLB_SECTION,
DEBUG_SECTION,
.clock_freq_khz = 10000,
};

View File

@ -16,6 +16,7 @@ static const XtensaConfig fsf = {
EXCEPTIONS_SECTION,
INTERRUPTS_SECTION,
TLB_SECTION,
DEBUG_SECTION,
.clock_freq_khz = 10000,
};

View File

@ -126,6 +126,10 @@ enum {
RASID = 90,
ITLBCFG = 91,
DTLBCFG = 92,
IBREAKENABLE = 96,
IBREAKA = 128,
DBREAKA = 144,
DBREAKC = 160,
EPC1 = 177,
DEPC = 192,
EPS2 = 194,
@ -137,8 +141,11 @@ enum {
PS = 230,
VECBASE = 231,
EXCCAUSE = 232,
DEBUGCAUSE = 233,
CCOUNT = 234,
PRID = 235,
ICOUNT = 236,
ICOUNTLEVEL = 237,
EXCVADDR = 238,
CCOMPARE = 240,
};
@ -161,12 +168,27 @@ 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 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
@ -186,6 +208,7 @@ enum {
EXC_KERNEL,
EXC_USER,
EXC_DOUBLE,
EXC_DEBUG,
EXC_MAX
};
@ -279,6 +302,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;
@ -310,6 +338,9 @@ typedef struct CPUXtensaState {
int exception_taken;
/* Watchpoints for DBREAK registers */
CPUWatchpoint *cpu_watchpoint[MAX_NDBREAK];
CPU_COMMON
} CPUXtensaState;
@ -344,6 +375,8 @@ 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 dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env);
void debug_exception_env(CPUState *new_env, uint32_t cause);
#define XTENSA_OPTION_BIT(opt) (((uint64_t)1) << (opt))
@ -409,6 +442,8 @@ 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
#define XTENSA_TBFLAG_ICOUNT 0x20
static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
target_ulong *cs_base, int *flags)
@ -424,6 +459,14 @@ 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;
}
if (xtensa_get_cintlevel(env) < env->sregs[ICOUNTLEVEL]) {
*flags |= XTENSA_TBFLAG_ICOUNT;
}
}
}
#include "cpu-all.h"

View File

@ -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);
@ -57,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;
@ -83,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;
@ -193,6 +235,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,
@ -540,3 +583,70 @@ int xtensa_get_physical_addr(CPUState *env,
return 0;
}
}
static void dump_tlb(FILE *f, fprintf_function cpu_fprintf,
CPUState *env, bool dtlb)
{
unsigned wi, ei;
const xtensa_tlb *conf =
dtlb ? &env->config->dtlb : &env->config->itlb;
unsigned (*attr_to_access)(uint32_t) =
xtensa_option_enabled(env->config, XTENSA_OPTION_MMU) ?
mmu_attr_to_access : region_attr_to_access;
for (wi = 0; wi < conf->nways; ++wi) {
uint32_t sz = ~xtensa_tlb_get_addr_mask(env, dtlb, wi) + 1;
const char *sz_text;
bool print_header = true;
if (sz >= 0x100000) {
sz >>= 20;
sz_text = "MB";
} else {
sz >>= 10;
sz_text = "KB";
}
for (ei = 0; ei < conf->way_size[wi]; ++ei) {
const xtensa_tlb_entry *entry =
xtensa_tlb_get_entry(env, dtlb, wi, ei);
if (entry->asid) {
unsigned access = attr_to_access(entry->attr);
if (print_header) {
print_header = false;
cpu_fprintf(f, "Way %u (%d %s)\n", wi, sz, sz_text);
cpu_fprintf(f,
"\tVaddr Paddr ASID Attr RWX\n"
"\t---------- ---------- ---- ---- ---\n");
}
cpu_fprintf(f,
"\t0x%08x 0x%08x 0x%02x 0x%02x %c%c%c\n",
entry->vaddr,
entry->paddr,
entry->asid,
entry->attr,
(access & PAGE_READ) ? 'R' : '-',
(access & PAGE_WRITE) ? 'W' : '-',
(access & PAGE_EXEC) ? 'X' : '-');
}
}
}
}
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
{
if (xtensa_option_bits_enabled(env->config,
XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION) |
XTENSA_OPTION_BIT(XTENSA_OPTION_MMU))) {
cpu_fprintf(f, "ITLB:\n");
dump_tlb(f, cpu_fprintf, env, false);
cpu_fprintf(f, "\nDTLB:\n");
dump_tlb(f, cpu_fprintf, env, true);
} else {
cpu_fprintf(f, "No TLB for this CPU core\n");
}
}

View File

@ -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,9 @@ 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)
DEF_HELPER_2(wsr_dbreaka, void, i32, i32)
DEF_HELPER_2(wsr_dbreakc, void, i32, i32)
#include "def-helper.h"

View File

@ -134,6 +134,27 @@ 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;
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 +683,82 @@ 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;
}
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;
}

View File

@ -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 { \
@ -251,6 +252,8 @@
.nextint = XCHAL_NUM_EXTINTERRUPTS, \
.extint = EXTINTS
#if XCHAL_HAVE_PTP_MMU
#define TLB_TEMPLATE(ways, refill_way_size, way56) { \
.nways = ways, \
.way_size = { \
@ -268,11 +271,23 @@
#define DTLB(varway56) \
TLB_TEMPLATE(10, 1 << XCHAL_DTLB_ARF_ENTRIES_LOG2, varway56)
#if XCHAL_HAVE_PTP_MMU
#define TLB_SECTION \
.itlb = ITLB(XCHAL_HAVE_SPANNING_WAY), \
.dtlb = DTLB(XCHAL_HAVE_SPANNING_WAY)
#else
#elif XCHAL_HAVE_XLT_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR
#define TLB_TEMPLATE { \
.nways = 1, \
.way_size = { \
8, \
} \
}
#define TLB_SECTION \
.itlb = TLB_TEMPLATE, \
.dtlb = TLB_TEMPLATE
#endif
#if (defined(TARGET_WORDS_BIGENDIAN) != 0) == (XCHAL_HAVE_BE != 0)
@ -288,6 +303,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

View File

@ -61,6 +61,10 @@ typedef struct DisasContext {
uint32_t ccount_delta;
unsigned used_window;
bool debug;
bool icount;
TCGv_i32 next_icount;
} DisasContext;
static TCGv_ptr cpu_env;
@ -91,6 +95,13 @@ static const char * const sregnames[256] = {
[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",
@ -119,8 +130,11 @@ static const char * const sregnames[256] = {
[PS] = "PS",
[VECBASE] = "VECBASE",
[EXCCAUSE] = "EXCCAUSE",
[DEBUGCAUSE] = "DEBUGCAUSE",
[CCOUNT] = "CCOUNT",
[PRID] = "PRID",
[ICOUNT] = "ICOUNT",
[ICOUNTLEVEL] = "ICOUNTLEVEL",
[EXCVADDR] = "EXCVADDR",
[CCOMPARE] = "CCOMPARE0",
[CCOMPARE + 1] = "CCOMPARE1",
@ -283,6 +297,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) {
@ -294,10 +321,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);
@ -492,6 +522,46 @@ 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_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,
@ -535,10 +605,30 @@ 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)
{
}
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;
@ -567,11 +657,21 @@ 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,
[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,
@ -749,7 +849,7 @@ static void disas_xtensa_insn(DisasContext *dc)
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 b2 = 0;
static const uint32_t B4CONST[] = {
0xffffffff, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256
@ -764,6 +864,7 @@ static void disas_xtensa_insn(DisasContext *dc)
HAS_OPTION(XTENSA_OPTION_CODE_DENSITY);
} else {
dc->next_pc = dc->pc + 3;
b2 = ldub_code(dc->pc + 2);
}
switch (OP0) {
@ -968,8 +1069,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*/
@ -2349,7 +2452,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*/
@ -2402,6 +2508,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)
{
@ -2428,10 +2547,15 @@ 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;
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();
@ -2467,8 +2591,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);
@ -2481,6 +2624,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();

View File

@ -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

View File

@ -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