X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Ftarget%2Farm11_dbgtap.c;h=9ad566222bf5f14a1089af963825ab6ed8d5530f;hp=7e1e9cba7493055852d19e1fd7189027e6758e6a;hb=a0edb8a328ceea23186ab74c941454fb146c9a48;hpb=f0c3e7011f9a829b518770247d143b1ac612f0f1 diff --git a/src/target/arm11_dbgtap.c b/src/target/arm11_dbgtap.c index 7e1e9cba74..9ad566222b 100644 --- a/src/target/arm11_dbgtap.c +++ b/src/target/arm11_dbgtap.c @@ -27,7 +27,7 @@ #include "arm_jtag.h" #include "arm11_dbgtap.h" -#include "time_support.h" +#include #if 0 #define JTAG_DEBUG(expr ...) do { if (1) LOG_DEBUG(expr); } while (0) @@ -91,6 +91,38 @@ void arm11_setup_field(struct arm11_common * arm11, int num_bits, void * out_dat field->in_value = in_data; } +static const char *arm11_ir_to_string(uint8_t ir) +{ + const char *s = "unknown"; + + switch (ir) { + case ARM11_EXTEST: + s = "EXTEST"; + break; + case ARM11_SCAN_N: + s = "SCAN_N"; + break; + case ARM11_RESTART: + s = "RESTART"; + break; + case ARM11_HALT: + s = "HALT"; + break; + case ARM11_INTEST: + s = "INTEST"; + break; + case ARM11_ITRSEL: + s = "ITRSEL"; + break; + case ARM11_IDCODE: + s = "IDCODE"; + break; + case ARM11_BYPASS: + s = "BYPASS"; + break; + } + return s; +} /** Write JTAG instruction register * @@ -110,7 +142,7 @@ void arm11_add_IR(struct arm11_common * arm11, uint8_t instr, tap_state_t state) return; } - JTAG_DEBUG("IR <= 0x%02x", instr); + JTAG_DEBUG("IR <= %s (0x%02x)", arm11_ir_to_string(instr), instr); struct scan_field field; @@ -135,7 +167,8 @@ static void arm11_in_handler_SCAN_N(uint8_t *in_value) jtag_set_error(ERROR_FAIL); } - JTAG_DEBUG("SCREG SCAN OUT 0x%02x", v); + if (v != 0x10) + JTAG_DEBUG("SCREG SCAN OUT 0x%02x", v); } /** Select and write to Scan Chain Register (SCREG) @@ -150,6 +183,9 @@ static void arm11_in_handler_SCAN_N(uint8_t *in_value) * \param state Pass the final TAP state or ARM11_TAP_DEFAULT for the default * value (Pause-DR). * + * Changes the current scan chain if needed, transitions to the specified + * TAP state, and leaves the IR undefined. + * * The chain takes effect when Update-DR is passed (usually when subsequently * the INTEXT/EXTEST instructions are written). * @@ -162,9 +198,19 @@ static void arm11_in_handler_SCAN_N(uint8_t *in_value) * \remarks This adds to the JTAG command queue but does \em not execute it. */ -int arm11_add_debug_SCAN_N(struct arm11_common * arm11, uint8_t chain, tap_state_t state) +int arm11_add_debug_SCAN_N(struct arm11_common *arm11, + uint8_t chain, tap_state_t state) { - JTAG_DEBUG("SCREG <= 0x%02x", chain); + /* Don't needlessly switch the scan chain. + * NOTE: the ITRSEL instruction fakes SCREG changing; + * but leaves its actual value unchanged. + */ + if (arm11->jtag_info.cur_scan_chain == chain) { + JTAG_DEBUG("SCREG <= %d SKIPPED", chain); + return jtag_add_statemove((state == ARM11_TAP_DEFAULT) + ? TAP_DRPAUSE : state); + } + JTAG_DEBUG("SCREG <= %d", chain); arm11_add_IR(arm11, ARM11_SCAN_N, ARM11_TAP_DEFAULT); @@ -288,50 +334,6 @@ int arm11_write_DSCR(struct arm11_common * arm11, uint32_t dscr) 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 * from the arm11_run_instr... group of functions. * @@ -835,30 +837,31 @@ int arm11_sc7_run(struct arm11_common * arm11, struct arm11_sc7_action * actions } else { - nRW = 0; + nRW = 1; DataOut = 0; AddressOut = 0; } do { - JTAG_DEBUG("SC7 <= Address %02x Data %08x nRW %d", + JTAG_DEBUG("SC7 <= c%-3d Data %08x %s", (unsigned) AddressOut, (unsigned) DataOut, - nRW); + nRW ? "write" : "read"); arm11_add_dr_scan_vc(ARRAY_SIZE(chain7_fields), chain7_fields, TAP_DRPAUSE); CHECK_RETVAL(jtag_execute_queue()); - JTAG_DEBUG("SC7 => Address %02x Data %08x Ready %d", - (unsigned) AddressIn, - (unsigned) DataIn, - Ready); + if (!Ready) + JTAG_DEBUG("SC7 => !ready"); } while (!Ready); /* 'nRW' is 'Ready' on read out */ + if (!nRW) + JTAG_DEBUG("SC7 => Data %08x", (unsigned) DataIn); + if (i > 0) { if (actions[i - 1].address != AddressIn) @@ -879,15 +882,6 @@ int arm11_sc7_run(struct arm11_common * arm11, struct arm11_sc7_action * actions } } } - - for (size_t i = 0; i < count; i++) - { - JTAG_DEBUG("SC7 %02d: %02x %s %08x", - (unsigned) i, actions[i].address, - actions[i].write ? "<=" : "=>", - (unsigned) actions[i].value); - } - return ERROR_OK; } @@ -898,7 +892,7 @@ int arm11_sc7_run(struct arm11_common * arm11, struct arm11_sc7_action * actions */ void arm11_sc7_clear_vbw(struct arm11_common * arm11) { - size_t clear_bw_size = arm11->brp + arm11->wrp + 1; + size_t clear_bw_size = arm11->brp + 1; struct arm11_sc7_action *clear_bw = malloc(sizeof(struct arm11_sc7_action) * clear_bw_size); struct arm11_sc7_action * pos = clear_bw; @@ -911,11 +905,6 @@ void arm11_sc7_clear_vbw(struct arm11_common * arm11) for (size_t i = 0; i < arm11->brp; i++) (pos++)->address = ARM11_SC7_BCR0 + i; - - for (size_t i = 0; i < arm11->wrp; i++) - (pos++)->address = ARM11_SC7_WCR0 + i; - - (pos++)->address = ARM11_SC7_VCR; arm11_sc7_run(arm11, clear_bw, clear_bw_size); @@ -936,7 +925,6 @@ void arm11_sc7_set_vcr(struct arm11_common * arm11, uint32_t value) set_vcr.address = ARM11_SC7_VCR; set_vcr.value = value; - arm11_sc7_run(arm11, &set_vcr, 1); } @@ -1020,6 +1008,88 @@ static int arm11_dpm_instr_read_data_r0(struct arm_dpm *dpm, opcode, data); } +/* Because arm11_sc7_run() takes a vector of actions, we batch breakpoint + * and watchpoint operations instead of running them right away. Since we + * pre-allocated our vector, we don't need to worry about space. + */ +static int arm11_bpwp_enable(struct arm_dpm *dpm, unsigned index, + uint32_t addr, uint32_t control) +{ + struct arm11_common *arm11 = dpm_to_arm11(dpm); + struct arm11_sc7_action *action; + + action = arm11->bpwp_actions + arm11->bpwp_n; + + /* Invariant: this bp/wp is disabled. + * It also happens that the core is halted here, but for + * DPM-based cores we don't actually care about that. + */ + + action[0].write = action[1].write = true; + + action[0].value = addr; + action[1].value = control; + + switch (index) { + case 0 ... 15: + action[0].address = ARM11_SC7_BVR0 + index; + action[1].address = ARM11_SC7_BCR0 + index; + break; + case 16 ... 32: + index -= 16; + action[0].address = ARM11_SC7_WVR0 + index; + action[1].address = ARM11_SC7_WCR0 + index; + break; + default: + return ERROR_FAIL; + } + + arm11->bpwp_n += 2; + + return ERROR_OK; +} + +static int arm11_bpwp_disable(struct arm_dpm *dpm, unsigned index) +{ + struct arm11_common *arm11 = dpm_to_arm11(dpm); + struct arm11_sc7_action *action; + + action = arm11->bpwp_actions + arm11->bpwp_n; + + action[0].write = true; + action[0].value = 0; + + switch (index) { + case 0 ... 15: + action[0].address = ARM11_SC7_BCR0 + index; + break; + case 16 ... 32: + index -= 16; + action[0].address = ARM11_SC7_WCR0 + index; + break; + default: + return ERROR_FAIL; + } + + arm11->bpwp_n += 1; + + return ERROR_OK; +} + +/** Flush any pending breakpoint and watchpoint updates. */ +int arm11_bpwp_flush(struct arm11_common *arm11) +{ + int retval; + + if (!arm11->bpwp_n) + return ERROR_OK; + + retval = arm11_sc7_run(arm11, arm11->bpwp_actions, arm11->bpwp_n); + arm11->bpwp_n = 0; + + return retval; +} + /** Set up high-level debug module utilities */ int arm11_dpm_init(struct arm11_common *arm11, uint32_t didr) { @@ -1039,11 +1109,22 @@ int arm11_dpm_init(struct arm11_common *arm11, uint32_t didr) dpm->instr_read_data_dcc = arm11_dpm_instr_read_data_dcc; dpm->instr_read_data_r0 = arm11_dpm_instr_read_data_r0; + dpm->bpwp_enable = arm11_bpwp_enable; + dpm->bpwp_disable = arm11_bpwp_disable; + retval = arm_dpm_setup(dpm); if (retval != ERROR_OK) return retval; + /* alloc enough to enable all breakpoints and watchpoints at once */ + arm11->bpwp_actions = calloc(2 * (dpm->nbp + dpm->nwp), + sizeof *arm11->bpwp_actions); + if (!arm11->bpwp_actions) + return ERROR_FAIL; + retval = arm_dpm_initialize(dpm); + if (retval != ERROR_OK) + return retval; - return retval; + return arm11_bpwp_flush(arm11); }