From 332023fb23aefb30d20b0d7f48d12ed9facdba40 Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Wed, 25 Nov 2015 12:02:32 +0100 Subject: [PATCH] cortex_a: fix fast-mode memory reads cortex_a_read_apb_ab_memory_fast() uses the wrong order of ITR and DSCR writes when setting up the transfer. ARM DDI0406C says in C8.2 regarding "Fast mode" operation to first switch to fast mode and then latch the instruction in ITR. Current implementation first wrote ITR, causing the instruction to be executed immediately, then switched to fast mode without an instruction latched. Repeated reading of DTRTX didn't execute LDC and thus replicated its current content into the whole buffer. This patch uses the following, revised algorithm: 1) switch to non-blocking mode and issue the LDC for the first word 2) if more than one word is to be read: - switch to fast mode - latch the LDC instruction into ITR (it is _not_ executed) - issue (count-1) reads of DTRTX register, each read returns the current content of DTRTX and re-issues the latched instruction -> now the second-to-last word is in the buffer and the LDC for the last word has been issued. 3) wait for the last instruction to complete 4) switch back to non-blocking mode 5) Read DTRTX for the last (or: only) word and put it into the buffer Change-Id: I44f5c585962ffa5af257c3d5a2a802c122b6b1e4 Signed-off-by: Matthias Welwarsky Reviewed-on: http://openocd.zylin.com/3122 Tested-by: jenkins Reviewed-by: Christopher Head Reviewed-by: Paul Fertser --- src/target/cortex_a.c | 48 +++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 325e22e53..8ec870b5d 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -2451,7 +2451,7 @@ static int cortex_a_read_apb_ab_memory_fast(struct target *target, */ struct armv7a_common *armv7a = target_to_armv7a(target); struct adiv5_dap *swjdp = armv7a->arm.dap; - uint32_t new_dscr, u32; + uint32_t u32; int retval; /* Switch to non-blocking mode if not already in that mode. */ @@ -2459,19 +2459,24 @@ static int cortex_a_read_apb_ab_memory_fast(struct target *target, if (retval != ERROR_OK) return retval; - if (count > 1) { - /* Consecutively issue the LDC instruction via a write to ITR and - * change to fast mode, in a single bulk copy since DSCR == ITR + 4. - * The instruction is issued into the core before the mode switch. */ - uint8_t command[8]; - target_buffer_set_u32(target, command, ARMV4_5_LDC(0, 1, 0, 1, 14, 5, 0, 4)); - new_dscr = (*dscr & ~DSCR_EXT_DCC_MASK) | DSCR_EXT_DCC_FAST_MODE; - target_buffer_set_u32(target, command + 4, new_dscr); - retval = mem_ap_sel_write_buf(swjdp, armv7a->debug_ap, command, 4, 2, - armv7a->debug_base + CPUDBG_ITR); + /* Issue the LDC instruction via a write to ITR. */ + retval = cortex_a_exec_opcode(target, ARMV4_5_LDC(0, 1, 0, 1, 14, 5, 0, 4), dscr); + if (retval != ERROR_OK) + return retval; + + count--; + + if (count > 0) { + /* Switch to fast mode if not already in that mode. */ + retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_FAST_MODE, dscr); + if (retval != ERROR_OK) + return retval; + + /* Latch LDC instruction. */ + retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, + armv7a->debug_base + CPUDBG_ITR, ARMV4_5_LDC(0, 1, 0, 1, 14, 5, 0, 4)); if (retval != ERROR_OK) return retval; - *dscr = new_dscr; /* Read the value transferred to DTRTX into the buffer. Due to fast * mode rules, this blocks until the instruction finishes executing and @@ -2480,29 +2485,24 @@ static int cortex_a_read_apb_ab_memory_fast(struct target *target, * word from memory and issues the read instruction for the last word. */ retval = mem_ap_sel_read_buf_noincr(swjdp, armv7a->debug_ap, buffer, - 4, count - 1, armv7a->debug_base + CPUDBG_DTRTX); + 4, count, armv7a->debug_base + CPUDBG_DTRTX); if (retval != ERROR_OK) return retval; /* Advance. */ - buffer += (count - 1) * 4; - } else { - /* Issue the LDC instruction via a write to ITR. */ - retval = cortex_a_exec_opcode(target, ARMV4_5_LDC(0, 1, 0, 1, 14, 5, 0, 4), dscr); - if (retval != ERROR_OK) - return retval; + buffer += count * 4; } - /* Switch to non-blocking mode if not already in that mode. */ - retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_NON_BLOCKING, dscr); - if (retval != ERROR_OK) - return retval; - /* Wait for last issued instruction to complete. */ retval = cortex_a_wait_instrcmpl(target, dscr, false); if (retval != ERROR_OK) return retval; + /* Switch to non-blocking mode if not already in that mode. */ + retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_NON_BLOCKING, dscr); + if (retval != ERROR_OK) + return retval; + /* Check for faults and return early. */ if (*dscr & (DSCR_STICKY_ABORT_PRECISE | DSCR_STICKY_ABORT_IMPRECISE)) return ERROR_OK; /* A data fault is not considered a system failure. */