No point in both ARM11 and Cortex-A8 having private copies of the logic sorting out e.g. DBG_REASON_WATCHPOINT. Add and use a shared routine for this ... there's actually a bunch more debug entry logic that could be shared, this is just a start on that. Note that this routine fixes a bug observed in the ARM11 code, where some abort mode quirks were displayed as being an unknown debug reason; and also silences needless ARM11 chatter. Likewise with private copies of DSCR ... add one to the DPM struct. Save it as part of setting DBG_REASON_* so later patches can switch over to using that copy. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>tags/v0.4.0-rc1
@@ -83,8 +83,7 @@ static int arm11_check_init(struct arm11_common *arm11) | |||||
*/ | */ | ||||
arm11->arm.target->state = TARGET_HALTED; | arm11->arm.target->state = TARGET_HALTED; | ||||
arm11->arm.target->debug_reason = | |||||
arm11_get_DSCR_debug_reason(arm11->dscr); | |||||
arm_dpm_report_dscr(arm11->arm.dpm, arm11->dscr); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
@@ -108,8 +107,7 @@ static int arm11_debug_entry(struct arm11_common *arm11) | |||||
int retval; | int retval; | ||||
arm11->arm.target->state = TARGET_HALTED; | arm11->arm.target->state = TARGET_HALTED; | ||||
arm11->arm.target->debug_reason = | |||||
arm11_get_DSCR_debug_reason(arm11->dscr); | |||||
arm_dpm_report_dscr(arm11->arm.dpm, arm11->dscr); | |||||
/* REVISIT entire cache should already be invalid !!! */ | /* REVISIT entire cache should already be invalid !!! */ | ||||
register_cache_invalidate(arm11->arm.core_cache); | register_cache_invalidate(arm11->arm.core_cache); | ||||
@@ -551,20 +549,12 @@ static int arm11_resume(struct target *target, int current, | |||||
i++; | i++; | ||||
} | } | ||||
target->debug_reason = DBG_REASON_NOTHALTED; | |||||
if (!debug_execution) | if (!debug_execution) | ||||
{ | |||||
target->state = TARGET_RUNNING; | |||||
target->debug_reason = DBG_REASON_NOTHALTED; | |||||
CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED)); | |||||
} | |||||
target->state = TARGET_RUNNING; | |||||
else | else | ||||
{ | |||||
target->state = TARGET_DEBUG_RUNNING; | |||||
target->debug_reason = DBG_REASON_NOTHALTED; | |||||
CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED)); | |||||
} | |||||
target->state = TARGET_DEBUG_RUNNING; | |||||
CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED)); | |||||
return ERROR_OK; | return ERROR_OK; | ||||
} | } | ||||
@@ -728,7 +718,7 @@ static int arm11_step(struct target *target, int current, | |||||
} | } | ||||
target->debug_reason = DBG_REASON_SINGLESTEP; | |||||
target->debug_reason = DBG_REASON_SINGLESTEP; | |||||
CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED)); | CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED)); | ||||
@@ -94,18 +94,6 @@ enum arm11_instructions | |||||
ARM11_BYPASS = 0x1F, | ARM11_BYPASS = 0x1F, | ||||
}; | }; | ||||
enum arm11_dscr | |||||
{ | |||||
ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_MASK = 0x0F << 2, | |||||
ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_HALT = 0x00 << 2, | |||||
ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BREAKPOINT = 0x01 << 2, | |||||
ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_WATCHPOINT = 0x02 << 2, | |||||
ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BKPT_INSTRUCTION = 0x03 << 2, | |||||
ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_EDBGRQ = 0x04 << 2, | |||||
ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_VECTOR_CATCH = 0x05 << 2, | |||||
}; | |||||
enum arm11_sc7 | enum arm11_sc7 | ||||
{ | { | ||||
ARM11_SC7_NULL = 0, | ARM11_SC7_NULL = 0, | ||||
@@ -288,50 +288,6 @@ int arm11_write_DSCR(struct arm11_common * arm11, uint32_t dscr) | |||||
return ERROR_OK; | return ERROR_OK; | ||||
} | } | ||||
/** Get the debug reason from Debug Status and Control Register (DSCR) | |||||
* | |||||
* \param dscr DSCR value to analyze | |||||
* \return Debug reason | |||||
* | |||||
*/ | |||||
enum target_debug_reason arm11_get_DSCR_debug_reason(uint32_t dscr) | |||||
{ | |||||
switch (dscr & ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_MASK) | |||||
{ | |||||
case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_HALT: | |||||
LOG_INFO("Debug entry: JTAG HALT"); | |||||
return DBG_REASON_DBGRQ; | |||||
case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BREAKPOINT: | |||||
LOG_INFO("Debug entry: breakpoint"); | |||||
return DBG_REASON_BREAKPOINT; | |||||
case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_WATCHPOINT: | |||||
LOG_INFO("Debug entry: watchpoint"); | |||||
return DBG_REASON_WATCHPOINT; | |||||
case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_BKPT_INSTRUCTION: | |||||
LOG_INFO("Debug entry: BKPT instruction"); | |||||
return DBG_REASON_BREAKPOINT; | |||||
case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_EDBGRQ: | |||||
LOG_INFO("Debug entry: EDBGRQ signal"); | |||||
return DBG_REASON_DBGRQ; | |||||
case ARM11_DSCR_METHOD_OF_DEBUG_ENTRY_VECTOR_CATCH: | |||||
LOG_INFO("Debug entry: VCR vector catch"); | |||||
return DBG_REASON_BREAKPOINT; | |||||
default: | |||||
LOG_INFO("Debug entry: unknown"); | |||||
return DBG_REASON_DBGRQ; | |||||
} | |||||
}; | |||||
/** Prepare the stage for ITR/DTR operations | /** Prepare the stage for ITR/DTR operations | ||||
* from the arm11_run_instr... group of functions. | * from the arm11_run_instr... group of functions. | ||||
* | * | ||||
@@ -14,8 +14,6 @@ int arm11_add_debug_SCAN_N(struct arm11_common *arm11, | |||||
int arm11_read_DSCR(struct arm11_common *arm11); | int arm11_read_DSCR(struct arm11_common *arm11); | ||||
int arm11_write_DSCR(struct arm11_common *arm11, uint32_t dscr); | int arm11_write_DSCR(struct arm11_common *arm11, uint32_t dscr); | ||||
enum target_debug_reason arm11_get_DSCR_debug_reason(uint32_t dscr); | |||||
int arm11_run_instr_data_prepare(struct arm11_common *arm11); | int arm11_run_instr_data_prepare(struct arm11_common *arm11); | ||||
int arm11_run_instr_data_finish(struct arm11_common *arm11); | int arm11_run_instr_data_finish(struct arm11_common *arm11); | ||||
int arm11_run_instr_no_data1(struct arm11_common *arm11, uint32_t opcode); | int arm11_run_instr_no_data1(struct arm11_common *arm11, uint32_t opcode); | ||||
@@ -755,6 +755,42 @@ void arm_dpm_report_wfar(struct arm_dpm *dpm, uint32_t addr) | |||||
/*----------------------------------------------------------------------*/ | /*----------------------------------------------------------------------*/ | ||||
/* | |||||
* Other debug and support utilities | |||||
*/ | |||||
void arm_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dscr) | |||||
{ | |||||
struct target *target = dpm->arm->target; | |||||
dpm->dscr = dscr; | |||||
/* Examine debug reason */ | |||||
switch (DSCR_ENTRY(dscr)) { | |||||
case 6: /* Data abort (v6 only) */ | |||||
case 7: /* Prefetch abort (v6 only) */ | |||||
/* FALL THROUGH -- assume a v6 core in abort mode */ | |||||
case 0: /* HALT request from debugger */ | |||||
case 4: /* EDBGRQ */ | |||||
target->debug_reason = DBG_REASON_DBGRQ; | |||||
break; | |||||
case 1: /* HW breakpoint */ | |||||
case 3: /* SW BKPT */ | |||||
case 5: /* vector catch */ | |||||
target->debug_reason = DBG_REASON_BREAKPOINT; | |||||
break; | |||||
case 2: /* asynch watchpoint */ | |||||
case 10: /* precise watchpoint */ | |||||
target->debug_reason = DBG_REASON_WATCHPOINT; | |||||
break; | |||||
default: | |||||
target->debug_reason = DBG_REASON_UNDEFINED; | |||||
break; | |||||
} | |||||
} | |||||
/*----------------------------------------------------------------------*/ | |||||
/* | /* | ||||
* Setup and management support. | * Setup and management support. | ||||
*/ | */ | ||||
@@ -125,6 +125,9 @@ struct arm_dpm { | |||||
/** Address of the instruction which triggered a watchpoint. */ | /** Address of the instruction which triggered a watchpoint. */ | ||||
uint32_t wp_pc; | uint32_t wp_pc; | ||||
/** Recent value of DSCR. */ | |||||
uint32_t dscr; | |||||
// FIXME -- read/write DCSR methods and symbols | // FIXME -- read/write DCSR methods and symbols | ||||
}; | }; | ||||
@@ -151,4 +154,6 @@ void arm_dpm_report_wfar(struct arm_dpm *, uint32_t wfar); | |||||
#define DSCR_ENTRY(dscr) (((dscr) >> 2) & 0xf) | #define DSCR_ENTRY(dscr) (((dscr) >> 2) & 0xf) | ||||
void arm_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dcsr); | |||||
#endif /* __ARM_DPM_H */ | #endif /* __ARM_DPM_H */ |
@@ -782,7 +782,7 @@ static int cortex_a8_resume(struct target *target, int current, | |||||
static int cortex_a8_debug_entry(struct target *target) | static int cortex_a8_debug_entry(struct target *target) | ||||
{ | { | ||||
int i; | int i; | ||||
uint32_t regfile[16], wfar, cpsr, dscr; | |||||
uint32_t regfile[16], cpsr, dscr; | |||||
int retval = ERROR_OK; | int retval = ERROR_OK; | ||||
struct working_area *regfile_working_area = NULL; | struct working_area *regfile_working_area = NULL; | ||||
struct cortex_a8_common *cortex_a8 = target_to_cortex_a8(target); | struct cortex_a8_common *cortex_a8 = target_to_cortex_a8(target); | ||||
@@ -793,6 +793,7 @@ static int cortex_a8_debug_entry(struct target *target) | |||||
LOG_DEBUG("dscr = 0x%08" PRIx32, cortex_a8->cpudbg_dscr); | LOG_DEBUG("dscr = 0x%08" PRIx32, cortex_a8->cpudbg_dscr); | ||||
/* REVISIT surely we should not re-read DSCR !! */ | |||||
mem_ap_read_atomic_u32(swjdp, | mem_ap_read_atomic_u32(swjdp, | ||||
armv7a->debug_base + CPUDBG_DSCR, &dscr); | armv7a->debug_base + CPUDBG_DSCR, &dscr); | ||||
@@ -807,30 +808,16 @@ static int cortex_a8_debug_entry(struct target *target) | |||||
armv7a->debug_base + CPUDBG_DSCR, dscr); | armv7a->debug_base + CPUDBG_DSCR, dscr); | ||||
/* Examine debug reason */ | /* Examine debug reason */ | ||||
switch (DSCR_ENTRY(cortex_a8->cpudbg_dscr)) | |||||
{ | |||||
case 0: /* DRCR[0] write */ | |||||
case 4: /* EDBGRQ */ | |||||
target->debug_reason = DBG_REASON_DBGRQ; | |||||
break; | |||||
case 1: /* HW breakpoint */ | |||||
case 3: /* SW BKPT */ | |||||
case 5: /* vector catch */ | |||||
target->debug_reason = DBG_REASON_BREAKPOINT; | |||||
break; | |||||
case 2: /* asynch watchpoint */ | |||||
case 10: /* precise watchpoint */ | |||||
target->debug_reason = DBG_REASON_WATCHPOINT; | |||||
/* save address of faulting instruction */ | |||||
retval = mem_ap_read_atomic_u32(swjdp, | |||||
armv7a->debug_base + CPUDBG_WFAR, | |||||
&wfar); | |||||
arm_dpm_report_wfar(&armv7a->dpm, wfar); | |||||
break; | |||||
default: | |||||
target->debug_reason = DBG_REASON_UNDEFINED; | |||||
break; | |||||
arm_dpm_report_dscr(&armv7a->dpm, cortex_a8->cpudbg_dscr); | |||||
/* save address of instruction that triggered the watchpoint? */ | |||||
if (target->debug_reason == DBG_REASON_WATCHPOINT) { | |||||
uint32_t wfar; | |||||
retval = mem_ap_read_atomic_u32(swjdp, | |||||
armv7a->debug_base + CPUDBG_WFAR, | |||||
&wfar); | |||||
arm_dpm_report_wfar(&armv7a->dpm, wfar); | |||||
} | } | ||||
/* REVISIT fast_reg_read is never set ... */ | /* REVISIT fast_reg_read is never set ... */ | ||||