]> git.sur5r.net Git - openocd/commitdiff
cortex_a: fix fast-mode memory reads
authorMatthias Welwarsky <matthias@welwarsky.de>
Wed, 25 Nov 2015 11:02:32 +0000 (12:02 +0100)
committerPaul Fertser <fercerpav@gmail.com>
Tue, 1 Dec 2015 06:52:01 +0000 (06:52 +0000)
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 <matthias@welwarsky.de>
Reviewed-on: http://openocd.zylin.com/3122
Tested-by: jenkins
Reviewed-by: Christopher Head <chead@zaber.com>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
src/target/cortex_a.c

index 325e22e53990215eb32295f620028867b65485d6..8ec870b5d38e4a4aa907cadf81ad4642115cc1b6 100644 (file)
@@ -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,26 +2485,21 @@ 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);
+       /* Wait for last issued instruction to complete. */
+       retval = cortex_a_wait_instrcmpl(target, dscr, false);
        if (retval != ERROR_OK)
                return retval;
 
-       /* Wait for last issued instruction to complete. */
-       retval = cortex_a_wait_instrcmpl(target, dscr, false);
+       /* 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;