This is an automated email from Gerrit.

Seth LaForge ([email protected]) just uploaded a new patch set to Gerrit, which 
you can find at http://openocd.zylin.com/2064

-- gerrit

commit cf4d222abecb81275654c23e313b44448c0273de
Author: Seth LaForge <[email protected]>
Date:   Tue Mar 25 17:06:41 2014 -0700

    cortex_a: fix big-endian Cortex-A/R targets (TI TMS570)
    
    With the TI TMS570LS3137, which is a big-endian Cortex-R4F processor,
    OpenOCD was not handling endianness properly, when doing byte or
    halfword reads was looking at the wrong part of the DRW register
    resulting in stale data, and for byte and halfword writes was writing
    to the wrong addresses. In my testing, this change fixes these
    problems.
    
    The address munging on writes is really bizarre, and I have no idea if
    it's a TMS570 quirk or generic to Cortex-R4 or Cortex-A. However, I
    don't know of any other big-endian Cortex-R/Cortex-A processors to
    test against and big-endian handling seemed pretty broken before, so
    this should be a strict improvement.
    
    Change-Id: I21dd30f4b9003f20fcc85f674ab833407bb61f74
    Signed-off-by: Seth LaForge <[email protected]>

diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c
index 4a1e42c..8cf8c04 100644
--- a/src/target/arm_adi_v5.c
+++ b/src/target/arm_adi_v5.c
@@ -287,26 +287,43 @@ int mem_ap_write_atomic_u32(struct adiv5_dap *dap, 
uint32_t address,
  * @param address Address to be written; it must be writable by the currently 
selected MEM-AP.
  * @param addrinc Whether the target address should be increased for each 
write or not. This
  *  should normally be true, except when writing to e.g. a FIFO.
+ * @param be Is this big-endian memory.
  * @return ERROR_OK on success, otherwise an error code.
  */
-int mem_ap_write(struct adiv5_dap *dap, const uint8_t *buffer, uint32_t size, 
uint32_t count,
-               uint32_t address, bool addrinc)
+int mem_ap_write_endian(struct adiv5_dap *dap, const uint8_t *buffer, uint32_t 
size,
+               uint32_t count, uint32_t address, bool addrinc, bool be)
 {
        size_t nbytes = size * count;
        const uint32_t csw_addrincr = addrinc ? CSW_ADDRINC_SINGLE : 
CSW_ADDRINC_OFF;
        uint32_t csw_size;
+       uint32_t addr_xor = 0;
        int retval;
 
-       if (size == 4)
+       /* Writes on big-endian TMS570LS3137 behave very strangely. Observed 
behavior:
+        *   size   write address   bytes written in order
+        *   4      TAR ^ 0         (val >> 24), (val >> 16), (val >> 8), (val)
+        *   2      TAR ^ 2         (val >> 8), (val)
+        *   1      TAR ^ 3         (val)
+        * For example, if you attempt to write a single byte to address 0, the 
processor
+        * will actually write a byte to address 3.
+        *
+        * To make writes of size < 4 work as expected, we xor a value with the 
address before
+        * setting the TAP, and we set the TAP after every transfer rather then 
relying on
+        * address increment. */
+
+       if (size == 4) {
                csw_size = CSW_32BIT;
-       else if (size == 2)
+               addr_xor = 0;
+       } else if (size == 2) {
                csw_size = CSW_16BIT;
-       else if (size == 1)
+               addr_xor = be ? 2 : 0;
+       } else if (size == 1) {
                csw_size = CSW_8BIT;
-       else
+               addr_xor = be ? 3 : 0;
+       } else
                return ERROR_TARGET_UNALIGNED_ACCESS;
 
-       retval = dap_setup_accessport_tar(dap, address);
+       retval = dap_setup_accessport_tar(dap, address ^ addr_xor);
        if (retval != ERROR_OK)
                return retval;
 
@@ -314,7 +331,7 @@ int mem_ap_write(struct adiv5_dap *dap, const uint8_t 
*buffer, uint32_t size, ui
                uint32_t this_size = size;
 
                /* Select packed transfer if possible */
-               if (addrinc && dap->packed_transfers && nbytes >= 4
+               if (!addr_xor && addrinc && dap->packed_transfers && nbytes >= 4
                                && max_tar_block_size(dap->tar_autoincr_block, 
address) >= 4) {
                        this_size = 4;
                        retval = dap_setup_accessport_csw(dap, csw_size | 
CSW_ADDRINC_PACKED);
@@ -328,14 +345,32 @@ int mem_ap_write(struct adiv5_dap *dap, const uint8_t 
*buffer, uint32_t size, ui
                /* How many source bytes each transfer will consume, and their 
location in the DRW,
                 * depends on the type of transfer and alignment. See ARM 
document IHI0031C. */
                uint32_t outvalue = 0;
-               switch (this_size) {
-               case 4:
-                       outvalue |= (uint32_t)*buffer++ << 8 * (address++ & 3);
-                       outvalue |= (uint32_t)*buffer++ << 8 * (address++ & 3);
-               case 2:
-                       outvalue |= (uint32_t)*buffer++ << 8 * (address++ & 3);
-               case 1:
-                       outvalue |= (uint32_t)*buffer++ << 8 * (address++ & 3);
+               if (be) {
+                       switch (this_size) {
+                       case 4:
+                               outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ 
(address++ & 3) ^ addr_xor);
+                               outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ 
(address++ & 3) ^ addr_xor);
+                               outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ 
(address++ & 3) ^ addr_xor);
+                               outvalue |= (uint32_t)*buffer++ << 8 * (3 ^ 
(address++ & 3) ^ addr_xor);
+                               break;
+                       case 2:
+                               outvalue |= (uint32_t)*buffer++ << 8 * (1 ^ 
(address++ & 3) ^ addr_xor);
+                               outvalue |= (uint32_t)*buffer++ << 8 * (1 ^ 
(address++ & 3) ^ addr_xor);
+                               break;
+                       case 1:
+                               outvalue |= (uint32_t)*buffer++ << 8 * (0 ^ 
(address++ & 3) ^ addr_xor);
+                               break;
+                       }
+               } else {
+                       switch (this_size) {
+                       case 4:
+                               outvalue |= (uint32_t)*buffer++ << 8 * 
(address++ & 3);
+                               outvalue |= (uint32_t)*buffer++ << 8 * 
(address++ & 3);
+                       case 2:
+                               outvalue |= (uint32_t)*buffer++ << 8 * 
(address++ & 3);
+                       case 1:
+                               outvalue |= (uint32_t)*buffer++ << 8 * 
(address++ & 3);
+                       }
                }
 
                nbytes -= this_size;
@@ -344,9 +379,9 @@ int mem_ap_write(struct adiv5_dap *dap, const uint8_t 
*buffer, uint32_t size, ui
                if (retval != ERROR_OK)
                        break;
 
-               /* Rewrite TAR if it wrapped */
-               if (addrinc && address % dap->tar_autoincr_block < size && 
nbytes > 0) {
-                       retval = dap_setup_accessport_tar(dap, address);
+               /* Rewrite TAR if it wrapped or we're xoring addresses */
+               if (addrinc && (addr_xor || (address % dap->tar_autoincr_block 
< size && nbytes > 0))) {
+                       retval = dap_setup_accessport_tar(dap, address ^ 
addr_xor);
                        if (retval != ERROR_OK)
                                break;
                }
@@ -378,10 +413,11 @@ int mem_ap_write(struct adiv5_dap *dap, const uint8_t 
*buffer, uint32_t size, ui
  * @param address Address to be read; it must be readable by the currently 
selected MEM-AP.
  * @param addrinc Whether the target address should be increased after each 
read or not. This
  *  should normally be true, except when reading from e.g. a FIFO.
+ * @param be Is this big-endian memory.
  * @return ERROR_OK on success, otherwise an error code.
  */
-int mem_ap_read(struct adiv5_dap *dap, uint8_t *buffer, uint32_t size, 
uint32_t count,
-               uint32_t adr, bool addrinc)
+int mem_ap_read_endian(struct adiv5_dap *dap, uint8_t *buffer, uint32_t size, 
uint32_t count,
+               uint32_t adr, bool addrinc, bool be)
 {
        size_t nbytes = size * count;
        const uint32_t csw_addrincr = addrinc ? CSW_ADDRINC_SINGLE : 
CSW_ADDRINC_OFF;
@@ -389,6 +425,10 @@ int mem_ap_read(struct adiv5_dap *dap, uint8_t *buffer, 
uint32_t size, uint32_t
        uint32_t address = adr;
        int retval;
 
+       /* Reads on big-endian TMS570LS3137 behave strangely differently than 
writes.
+        * They read from the physical address requested, but with DRW 
byte-reversed.
+        * For example, a byte read from address 0 will place the result in the 
high bytes of DRW. */
+
        if (size == 4)
                csw_size = CSW_32BIT;
        else if (size == 2)
@@ -476,14 +516,26 @@ int mem_ap_read(struct adiv5_dap *dap, uint8_t *buffer, 
uint32_t size, uint32_t
                        this_size = 4;
                }
 
-               switch (this_size) {
-               case 4:
-                       *buffer++ = *read_ptr >> 8 * (address++ & 3);
-                       *buffer++ = *read_ptr >> 8 * (address++ & 3);
-               case 2:
-                       *buffer++ = *read_ptr >> 8 * (address++ & 3);
-               case 1:
-                       *buffer++ = *read_ptr >> 8 * (address++ & 3);
+               if (be) {
+                       switch (this_size) {
+                       case 4:
+                               *buffer++ = *read_ptr >> 8 * (3 - (address++ & 
3));
+                               *buffer++ = *read_ptr >> 8 * (3 - (address++ & 
3));
+                       case 2:
+                               *buffer++ = *read_ptr >> 8 * (3 - (address++ & 
3));
+                       case 1:
+                               *buffer++ = *read_ptr >> 8 * (3 - (address++ & 
3));
+                       }
+               } else {
+                       switch (this_size) {
+                       case 4:
+                               *buffer++ = *read_ptr >> 8 * (address++ & 3);
+                               *buffer++ = *read_ptr >> 8 * (address++ & 3);
+                       case 2:
+                               *buffer++ = *read_ptr >> 8 * (address++ & 3);
+                       case 1:
+                               *buffer++ = *read_ptr >> 8 * (address++ & 3);
+                       }
                }
 
                read_ptr++;
@@ -525,18 +577,18 @@ int mem_ap_sel_write_atomic_u32(struct adiv5_dap *swjdp, 
uint8_t ap,
        return mem_ap_write_atomic_u32(swjdp, address, value);
 }
 
-int mem_ap_sel_read_buf(struct adiv5_dap *swjdp, uint8_t ap,
-               uint8_t *buffer, uint32_t size, uint32_t count, uint32_t 
address)
+int mem_ap_sel_read_buf_endian(struct adiv5_dap *swjdp, uint8_t ap,
+               uint8_t *buffer, uint32_t size, uint32_t count, uint32_t 
address, bool be)
 {
        dap_ap_select(swjdp, ap);
-       return mem_ap_read(swjdp, buffer, size, count, address, true);
+       return mem_ap_read_endian(swjdp, buffer, size, count, address, true, 
be);
 }
 
-int mem_ap_sel_write_buf(struct adiv5_dap *swjdp, uint8_t ap,
-               const uint8_t *buffer, uint32_t size, uint32_t count, uint32_t 
address)
+int mem_ap_sel_write_buf_endian(struct adiv5_dap *swjdp, uint8_t ap,
+               const uint8_t *buffer, uint32_t size, uint32_t count, uint32_t 
address, bool be)
 {
        dap_ap_select(swjdp, ap);
-       return mem_ap_write(swjdp, buffer, size, count, address, true);
+       return mem_ap_write_endian(swjdp, buffer, size, count, address, true, 
be);
 }
 
 int mem_ap_sel_read_buf_noincr(struct adiv5_dap *swjdp, uint8_t ap,
@@ -843,7 +895,7 @@ int ahbap_debugport_init(struct adiv5_dap *dap)
        dap_syssec(dap);
 
        /* check that we support packed transfers */
-       uint32_t csw;
+       uint32_t csw, cfg;
 
        retval = dap_setup_accessport(dap, CSW_8BIT | CSW_ADDRINC_PACKED, 0);
        if (retval != ERROR_OK)
@@ -853,6 +905,10 @@ int ahbap_debugport_init(struct adiv5_dap *dap)
        if (retval != ERROR_OK)
                return retval;
 
+       retval = dap_queue_ap_read(dap, AP_REG_CFG, &cfg);
+       if (retval != ERROR_OK)
+               return retval;
+
        retval = dap_run(dap);
        if (retval != ERROR_OK)
                return retval;
@@ -865,6 +921,9 @@ int ahbap_debugport_init(struct adiv5_dap *dap)
        LOG_DEBUG("MEM_AP Packed Transfers: %s",
                        dap->packed_transfers ? "enabled" : "disabled");
 
+       LOG_DEBUG("MEM_AP CFG: large data %d, long address %d, big-endian %d",
+                       !!(cfg & 0x04), !!(cfg & 0x02), !!(cfg & 0x01));
+
        return ERROR_OK;
 }
 
diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h
index cdcf928..8638e4b 100644
--- a/src/target/arm_adi_v5.h
+++ b/src/target/arm_adi_v5.h
@@ -409,23 +409,48 @@ int mem_ap_sel_read_u32(struct adiv5_dap *swjdp, uint8_t 
ap,
 int mem_ap_sel_write_u32(struct adiv5_dap *swjdp, uint8_t ap,
                uint32_t address, uint32_t value);
 
-/* Synchronous MEM-AP memory mapped single word transfers with selection of ap 
*/
+/* Synchronous MEM-AP memory mapped single word transfers with selection of ap
+ * and endianness support */
 int mem_ap_sel_read_atomic_u32(struct adiv5_dap *swjdp, uint8_t ap,
                uint32_t address, uint32_t *value);
 int mem_ap_sel_write_atomic_u32(struct adiv5_dap *swjdp, uint8_t ap,
                uint32_t address, uint32_t value);
 
+/* Synchronous MEM-AP memory mapped bus block transfers with endianness 
support */
+int mem_ap_read_endian(struct adiv5_dap *dap, uint8_t *buffer, uint32_t size,
+               uint32_t count, uint32_t address, bool addrinc, bool be);
+int mem_ap_write_endian(struct adiv5_dap *dap, const uint8_t *buffer, uint32_t 
size,
+               uint32_t count, uint32_t address, bool addrinc, bool be);
+
 /* Synchronous MEM-AP memory mapped bus block transfers */
-int mem_ap_read(struct adiv5_dap *dap, uint8_t *buffer, uint32_t size,
-               uint32_t count, uint32_t address, bool addrinc);
-int mem_ap_write(struct adiv5_dap *dap, const uint8_t *buffer, uint32_t size,
-               uint32_t count, uint32_t address, bool addrinc);
+static inline int mem_ap_read(struct adiv5_dap *dap, uint8_t *buffer, uint32_t 
size,
+               uint32_t count, uint32_t address, bool addrinc)
+{
+       return mem_ap_read_endian(dap, buffer, size, count, addrinc, addrinc, 
false);
+}
+static inline int mem_ap_write(struct adiv5_dap *dap, const uint8_t *buffer, 
uint32_t size,
+               uint32_t count, uint32_t address, bool addrinc)
+{
+       return mem_ap_write_endian(dap, buffer, size, count, address, addrinc, 
false);
+}
 
 /* Synchronous MEM-AP memory mapped bus block transfers with selection of ap */
-int mem_ap_sel_read_buf(struct adiv5_dap *swjdp, uint8_t ap,
-               uint8_t *buffer, uint32_t size, uint32_t count, uint32_t 
address);
-int mem_ap_sel_write_buf(struct adiv5_dap *swjdp, uint8_t ap,
-               const uint8_t *buffer, uint32_t size, uint32_t count, uint32_t 
address);
+int mem_ap_sel_read_buf_endian(struct adiv5_dap *swjdp, uint8_t ap,
+               uint8_t *buffer, uint32_t size, uint32_t count, uint32_t 
address, bool be);
+int mem_ap_sel_write_buf_endian(struct adiv5_dap *swjdp, uint8_t ap,
+               const uint8_t *buffer, uint32_t size, uint32_t count, uint32_t 
address, bool be);
+
+/* Synchronous MEM-AP memory mapped bus block transfers with selection of ap */
+static inline int mem_ap_sel_read_buf(struct adiv5_dap *swjdp, uint8_t ap,
+               uint8_t *buffer, uint32_t size, uint32_t count, uint32_t 
address)
+{
+       return mem_ap_sel_read_buf_endian(swjdp, ap, buffer, size, count, 
address, false);
+}
+static inline int mem_ap_sel_write_buf(struct adiv5_dap *swjdp, uint8_t ap,
+               const uint8_t *buffer, uint32_t size, uint32_t count, uint32_t 
address)
+{
+       return mem_ap_sel_write_buf_endian(swjdp, ap, buffer, size, count, 
address, false);
+}
 
 /* Synchronous, non-incrementing buffer functions for accessing fifos, with
  * selection of ap */
diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c
index e95297c..649ec36 100644
--- a/src/target/cortex_a.c
+++ b/src/target/cortex_a.c
@@ -2036,9 +2036,9 @@ static int cortex_a8_read_apb_ab_memory(struct target 
*target,
         * This data is read in aligned to 32 bit boundary.
         */
        retval = mem_ap_sel_read_buf_noincr(swjdp, armv7a->debug_ap, u8buf_ptr, 
4, total_u32,
-                                                                       
armv7a->debug_base + CPUDBG_DTRTX);
+                       armv7a->debug_base + CPUDBG_DTRTX);
        if (retval != ERROR_OK)
-                       goto error_unset_dtr_r;
+               goto error_unset_dtr_r;
 
        /* set DTR access mode back to non blocking b00  */
        dscr = (dscr & ~DSCR_EXT_DCC_MASK) | DSCR_EXT_DCC_NON_BLOCKING;
@@ -2114,7 +2114,8 @@ static int cortex_a8_read_phys_memory(struct target 
*target,
                if (armv7a->memory_ap_available && (apsel == 
armv7a->memory_ap)) {
 
                        /* read memory through AHB-AP */
-                       retval = mem_ap_sel_read_buf(swjdp, armv7a->memory_ap, 
buffer, size, count, address);
+                       retval = mem_ap_sel_read_buf_endian(swjdp, 
armv7a->memory_ap, buffer, size, count, address,
+                                       target->endianness == 
TARGET_BIG_ENDIAN);
                } else {
 
                        /* read memory through APB-AP */
@@ -2195,7 +2196,8 @@ static int cortex_a8_write_phys_memory(struct target 
*target,
                if (armv7a->memory_ap_available && (apsel == 
armv7a->memory_ap)) {
 
                        /* write memory through AHB-AP */
-                       retval = mem_ap_sel_write_buf(swjdp, armv7a->memory_ap, 
buffer, size, count, address);
+                       retval = mem_ap_sel_write_buf_endian(swjdp, 
armv7a->memory_ap, buffer, size, count, address,
+                                       target->endianness == 
TARGET_BIG_ENDIAN);
                } else {
 
                        /* write memory through APB-AP */

-- 

------------------------------------------------------------------------------
Learn Graph Databases - Download FREE O'Reilly Book
"Graph Databases" is the definitive new guide to graph databases and their
applications. Written by three acclaimed leaders in the field,
this first edition is now available. Download your free book today!
http://p.sf.net/sfu/13534_NeoTech
_______________________________________________
OpenOCD-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to