]> git.sur5r.net Git - openocd/blobdiff - src/target/xscale.c
arm_dpm: -Wshadow warning fix
[openocd] / src / target / xscale.c
index ddc73d20cd6538ae858718b65b849c2fc5aeb648..d5c212999b8a6bf239d7038b8747d2e4d5b91ef8 100644 (file)
@@ -2266,7 +2266,7 @@ static int xscale_set_watchpoint(struct target *target,
                struct watchpoint *watchpoint)
 {
        struct xscale_common *xscale = target_to_xscale(target);
-       uint8_t enable = 0;
+       uint32_t enable = 0;
        struct reg *dbcon = &xscale->reg_cache->reg_list[XSCALE_DBCON];
        uint32_t dbcon_value = buf_get_u32(dbcon->value, 0, 32);
 
@@ -2276,8 +2276,6 @@ static int xscale_set_watchpoint(struct target *target,
                return ERROR_TARGET_NOT_HALTED;
        }
 
-       xscale_get_reg(dbcon);
-
        switch (watchpoint->rw)
        {
                case WPT_READ:
@@ -2293,6 +2291,24 @@ static int xscale_set_watchpoint(struct target *target,
                        LOG_ERROR("BUG: watchpoint->rw neither read, write nor access");
        }
 
+       /* For watchpoint across more than one word, both DBR registers must
+          be enlisted, with the second used as a mask. */
+       if (watchpoint->length > 4)
+       {
+          if (xscale->dbr0_used || xscale->dbr1_used) 
+          {
+                 LOG_ERROR("BUG: sufficient hardware comparators unavailable");
+                 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+          }
+
+          /* Write mask value to DBR1, based on the length argument.
+               * Address bits ignored by the comparator are those set in mask. */
+          xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR1],
+                                                 watchpoint->length - 1);
+          xscale->dbr1_used = 1;
+          enable |= 0x100;                     /* DBCON[M] */
+       }
+
        if (!xscale->dbr0_used)
        {
                xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR0], watchpoint->address);
@@ -2312,7 +2328,7 @@ static int xscale_set_watchpoint(struct target *target,
        else
        {
                LOG_ERROR("BUG: no hardware comparator available");
-               return ERROR_OK;
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
        }
 
        return ERROR_OK;
@@ -2328,13 +2344,30 @@ static int xscale_add_watchpoint(struct target *target,
                return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
        }
 
-       if ((watchpoint->length != 1) && (watchpoint->length != 2) && (watchpoint->length != 4))
+       if (watchpoint->value)
+          LOG_WARNING("xscale does not support value, mask arguments; ignoring");
+
+       /* check that length is a power of two */
+       for (uint32_t len = watchpoint->length; len != 1; len /= 2)
        {
-               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+          if (len % 2)
+          {
+                 LOG_ERROR("xscale requires that watchpoint length is a power of two");
+                 return ERROR_COMMAND_ARGUMENT_INVALID;
+          }
        }
 
-       xscale->dbr_available--;
+       if (watchpoint->length == 4) /* single word watchpoint */
+       {
+          xscale->dbr_available--; /* one DBR reg used */
+          return ERROR_OK;
+       }
 
+       /* watchpoints across multiple words require both DBR registers */
+       if (xscale->dbr_available < 2)
+          return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       
+       xscale->dbr_available = 0;
        return ERROR_OK;
 }
 
@@ -2359,7 +2392,14 @@ static int xscale_unset_watchpoint(struct target *target,
 
        if (watchpoint->set == 1)
        {
-               dbcon_value &= ~0x3;
+          if (watchpoint->length > 4)
+          {
+                 dbcon_value &= ~0x103; /* clear DBCON[M] as well */
+                 xscale->dbr1_used = 0; /* DBR1 was used for mask */
+          }
+          else
+                 dbcon_value &= ~0x3;
+
                xscale_set_reg_u32(dbcon, dbcon_value);
                xscale->dbr0_used = 0;
        }
@@ -2389,6 +2429,9 @@ static int xscale_remove_watchpoint(struct target *target, struct watchpoint *wa
                xscale_unset_watchpoint(target, watchpoint);
        }
 
+       if (watchpoint->length > 4)
+          xscale->dbr_available++;     /* both DBR regs now available */
+       
        xscale->dbr_available++;
 
        return ERROR_OK;
@@ -3173,21 +3216,18 @@ static int xscale_virt2phys(struct target *target,
                uint32_t virtual, uint32_t *physical)
 {
        struct xscale_common *xscale = target_to_xscale(target);
-       int type;
        uint32_t cb;
-       int domain;
-       uint32_t ap;
 
        if (xscale->common_magic != XSCALE_COMMON_MAGIC) {
                LOG_ERROR(xscale_not);
                return ERROR_TARGET_INVALID;
        }
 
-       uint32_t ret = armv4_5_mmu_translate_va(target, &xscale->armv4_5_mmu, virtual, &type, &cb, &domain, &ap);
-       if (type == -1)
-       {
-               return ret;
-       }
+       uint32_t ret;
+       int retval = armv4_5_mmu_translate_va(target, &xscale->armv4_5_mmu,
+                       virtual, &cb, &ret);
+       if (retval != ERROR_OK)
+               return retval;
        *physical = ret;
        return ERROR_OK;
 }