target/register: Minor code cleanup
[fw/openocd] / src / target / arc.c
index db338031f704d03a23102b66cf217f0968045fbe..e11cd7d795efe19cdd566a827d592be2e254839f 100644 (file)
@@ -33,7 +33,7 @@
  * unexisting register is safe RAZ, rather then an error.
  * Note, core registers cannot be BCR.
  *
- * In arc/cpu/ tcl files all regiters are defined as core, non-BCR aux
+ * In arc/cpu/ tcl files all registers are defined as core, non-BCR aux
  * and BCR aux, in "add-reg" command they are passed to three lists
  * respectively:  core_reg_descriptions, aux_reg_descriptions,
  * bcr_reg_descriptions.
@@ -48,6 +48,8 @@
  */
 
 
+static int arc_remove_watchpoint(struct target *target,
+       struct watchpoint *watchpoint);
 
 void arc_reg_data_type_add(struct target *target,
                struct arc_reg_data_type *data_type)
@@ -197,7 +199,7 @@ int arc_reg_add(struct target *target, struct arc_reg_desc *arc_reg,
        arc->num_regs += 1;
 
        LOG_DEBUG(
-                       "added register {name=%s, num=0x%x, type=%s%s%s%s}",
+                       "added register {name=%s, num=0x%" PRIx32 ", type=%s%s%s%s}",
                        arc_reg->name, arc_reg->arch_num, arc_reg->data_type->id,
                        arc_reg->is_core ? ", core" : "",  arc_reg->is_bcr ? ", bcr" : "",
                        arc_reg->is_general ? ", general" : ""
@@ -225,7 +227,7 @@ static int arc_get_register(struct reg *reg)
 
        if (desc->is_core) {
                /* Accessing to R61/R62 registers causes Jtag hang */
-               if (desc->arch_num == CORE_R61_NUM || desc->arch_num == CORE_R62_NUM) {
+               if (desc->arch_num == ARC_R61 || desc->arch_num == ARC_R62) {
                        LOG_ERROR("It is forbidden to read core registers 61 and 62.");
                        return ERROR_FAIL;
                }
@@ -265,8 +267,8 @@ static int arc_set_register(struct reg *reg, uint8_t *buf)
                return ERROR_TARGET_NOT_HALTED;
 
        /* Accessing to R61/R62 registers causes Jtag hang */
-       if (desc->is_core && (desc->arch_num == CORE_R61_NUM ||
-                       desc->arch_num == CORE_R62_NUM)) {
+       if (desc->is_core && (desc->arch_num == ARC_R61 ||
+                       desc->arch_num == ARC_R62)) {
                LOG_ERROR("It is forbidden to write core registers 61 and 62.");
                return ERROR_FAIL;
        }
@@ -286,7 +288,7 @@ const struct reg_arch_type arc_reg_type = {
        .set = arc_set_register,
 };
 
-/* GDB register groups. For now we suport only general and "empty" */
+/* GDB register groups. For now we support only general and "empty" */
 static const char * const reg_group_general = "general";
 static const char * const reg_group_other = "";
 
@@ -303,7 +305,7 @@ static int arc_init_reg(struct target *target, struct reg *reg,
        /* Initialize struct reg */
        reg->name = reg_desc->name;
        reg->size = 32; /* All register in ARC are 32-bit */
-       reg->value = &reg_desc->reg_value;
+       reg->value = reg_desc->reg_value;
        reg->type = &arc_reg_type;
        reg->arch_info = reg_desc;
        reg->caller_save = true; /* @todo should be configurable. */
@@ -548,7 +550,7 @@ int arc_reg_get_field(struct target *target, const char *reg_name,
        struct reg *reg = arc_reg_get_by_name(target->reg_cache, reg_name, true);
 
        if (!reg) {
-               LOG_ERROR("Requested register `%s' doens't exist.", reg_name);
+               LOG_ERROR("Requested register `%s' doesn't exist.", reg_name);
                return ERROR_ARC_REGISTER_NOT_FOUND;
        }
 
@@ -575,7 +577,7 @@ int arc_reg_get_field(struct target *target, const char *reg_name,
        if (!reg->valid)
                CHECK_RETVAL(reg->type->get(reg));
 
-       /* First do endiannes-safe read of register value
+       /* First do endianness-safe read of register value
         * then convert it to binary buffer for further
         * field extraction */
 
@@ -889,7 +891,7 @@ static int arc_save_context(struct target *target)
                        core_cnt += 1;
                        reg->valid = true;
                        reg->dirty = false;
-                       LOG_DEBUG("Get core register regnum=%" PRIu32 ", name=%s, value=0x%08" PRIx32,
+                       LOG_DEBUG("Get core register regnum=%u, name=%s, value=0x%08" PRIx32,
                                i, arc_reg->name, core_values[core_cnt]);
                }
        }
@@ -904,7 +906,7 @@ static int arc_save_context(struct target *target)
                        aux_cnt += 1;
                        reg->valid = true;
                        reg->dirty = false;
-                       LOG_DEBUG("Get aux register regnum=%" PRIu32 ", name=%s, value=0x%08" PRIx32,
+                       LOG_DEBUG("Get aux register regnum=%u, name=%s, value=0x%08" PRIx32,
                                i, arc_reg->name, aux_values[aux_cnt]);
                }
        }
@@ -922,6 +924,7 @@ exit:
  * Finds an actionpoint that triggered last actionpoint event, as specified by
  * DEBUG.ASR.
  *
+ * @param target
  * @param actionpoint Pointer to be set to last active actionpoint. Pointer
  *                    will be set to NULL if DEBUG.AH is 0.
  */
@@ -1396,7 +1399,7 @@ static int arc_target_create(struct target *target, Jim_Interp *interp)
  * Write 4-byte instruction to memory. This is like target_write_u32, however
  * in case of little endian ARC instructions are in middle endian format, not
  * little endian, so different type of conversion should be done.
- * Middle endinan: instruction "aabbccdd", stored as "bbaaddcc"
+ * Middle endian: instruction "aabbccdd", stored as "bbaaddcc"
  */
 int arc_write_instruction_u32(struct target *target, uint32_t address,
        uint32_t instr)
@@ -1464,7 +1467,7 @@ static int arc_configure_actionpoint(struct target *target, uint32_t ap_num,
        if (control_tt != AP_AC_TT_DISABLE) {
 
                if (arc->actionpoints_num_avail < 1) {
-                       LOG_ERROR("No free actionpoints, maximim amount is %" PRIu32,
+                       LOG_ERROR("No free actionpoints, maximum amount is %u",
                                        arc->actionpoints_num);
                        return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
                }
@@ -1551,7 +1554,7 @@ static int arc_set_breakpoint(struct target *target,
                }
 
                if (bp_num >= arc->actionpoints_num) {
-                       LOG_ERROR("No free actionpoints, maximum amount is %" PRIu32,
+                       LOG_ERROR("No free actionpoints, maximum amount is %u",
                                        arc->actionpoints_num);
                        return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
                }
@@ -1607,7 +1610,7 @@ static int arc_unset_breakpoint(struct target *target,
                        } else {
                                LOG_WARNING("Software breakpoint @0x%" TARGET_PRIxADDR
                                        " has been overwritten outside of debugger."
-                                       "Expected: @0x%" PRIx32 ", got: @0x%" PRIx32,
+                                       "Expected: @0x%x, got: @0x%" PRIx32,
                                        breakpoint->address, ARC_SDBBP_32, current_instr);
                        }
                } else if (breakpoint->length == 2) {
@@ -1696,6 +1699,7 @@ void arc_reset_actionpoints(struct target *target)
        struct arc_common *arc = target_to_arc(target);
        struct arc_actionpoint *ap_list = arc->actionpoints_list;
        struct breakpoint *next_b;
+       struct watchpoint *next_w;
 
        while (target->breakpoints) {
                next_b = target->breakpoints->next;
@@ -1704,6 +1708,12 @@ void arc_reset_actionpoints(struct target *target)
                free(target->breakpoints);
                target->breakpoints = next_b;
        }
+       while (target->watchpoints) {
+               next_w = target->watchpoints->next;
+               arc_remove_watchpoint(target, target->watchpoints);
+               free(target->watchpoints);
+               target->watchpoints = next_w;
+       }
        for (unsigned int i = 0; i < arc->actionpoints_num; i++) {
                if ((ap_list[i].used) && (ap_list[i].reg_address))
                        arc_remove_auxreg_actionpoint(target, ap_list[i].reg_address);
@@ -1800,7 +1810,160 @@ int arc_remove_auxreg_actionpoint(struct target *target, uint32_t auxreg_addr)
        return retval;
 }
 
-/* Helper function which swiches core to single_step mode by
+
+static int arc_set_watchpoint(struct target *target,
+               struct watchpoint *watchpoint)
+{
+       unsigned int wp_num;
+       struct arc_common *arc = target_to_arc(target);
+       struct arc_actionpoint *ap_list = arc->actionpoints_list;
+
+       if (watchpoint->set) {
+               LOG_WARNING("watchpoint already set");
+               return ERROR_OK;
+       }
+
+       for (wp_num = 0; wp_num < arc->actionpoints_num; wp_num++) {
+               if (!ap_list[wp_num].used)
+                       break;
+       }
+
+       if (wp_num >= arc->actionpoints_num) {
+               LOG_ERROR("No free actionpoints, maximum amount is %u",
+                               arc->actionpoints_num);
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+
+       if (watchpoint->length != 4) {
+               LOG_ERROR("Only watchpoints of length 4 are supported");
+               return ERROR_TARGET_UNALIGNED_ACCESS;
+       }
+
+       int enable = AP_AC_TT_DISABLE;
+       switch (watchpoint->rw) {
+               case WPT_READ:
+                       enable = AP_AC_TT_READ;
+                       break;
+               case WPT_WRITE:
+                       enable = AP_AC_TT_WRITE;
+                       break;
+               case WPT_ACCESS:
+                       enable = AP_AC_TT_READWRITE;
+                       break;
+               default:
+                       LOG_ERROR("BUG: watchpoint->rw neither read, write nor access");
+                       return ERROR_FAIL;
+       }
+
+       int retval =  arc_configure_actionpoint(target, wp_num,
+                                       watchpoint->address, enable, AP_AC_AT_MEMORY_ADDR);
+
+       if (retval == ERROR_OK) {
+               watchpoint->set = wp_num + 1;
+               ap_list[wp_num].used = 1;
+               ap_list[wp_num].bp_value = watchpoint->address;
+               ap_list[wp_num].type = ARC_AP_WATCHPOINT;
+
+               LOG_DEBUG("wpid: %" PRIu32 ", wp_num %u wp_value 0x%" PRIx32,
+                               watchpoint->unique_id, wp_num, ap_list[wp_num].bp_value);
+       }
+
+       return retval;
+}
+
+static int arc_unset_watchpoint(struct target *target,
+               struct watchpoint *watchpoint)
+{
+       /* get pointers to arch-specific information */
+       struct arc_common *arc = target_to_arc(target);
+       struct arc_actionpoint *ap_list = arc->actionpoints_list;
+
+       if (!watchpoint->set) {
+               LOG_WARNING("watchpoint not set");
+               return ERROR_OK;
+       }
+
+       unsigned int wp_num = watchpoint->set - 1;
+       if ((watchpoint->set == 0) || (wp_num >= arc->actionpoints_num)) {
+               LOG_DEBUG("Invalid actionpoint ID: %u in watchpoint: %" PRIu32,
+                               wp_num, watchpoint->unique_id);
+               return ERROR_OK;
+       }
+
+       int retval =  arc_configure_actionpoint(target, wp_num,
+                               watchpoint->address, AP_AC_TT_DISABLE, AP_AC_AT_MEMORY_ADDR);
+
+       if (retval == ERROR_OK) {
+               watchpoint->set = 0;
+               ap_list[wp_num].used = 0;
+               ap_list[wp_num].bp_value = 0;
+
+               LOG_DEBUG("wpid: %" PRIu32 " - releasing actionpoint ID: %u",
+                               watchpoint->unique_id, wp_num);
+       }
+
+       return retval;
+}
+
+static int arc_add_watchpoint(struct target *target,
+       struct watchpoint *watchpoint)
+{
+       if (target->state != TARGET_HALTED) {
+               LOG_WARNING("target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       CHECK_RETVAL(arc_set_watchpoint(target, watchpoint));
+
+       return ERROR_OK;
+}
+
+static int arc_remove_watchpoint(struct target *target,
+       struct watchpoint *watchpoint)
+{
+       if (target->state != TARGET_HALTED) {
+               LOG_WARNING("target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (watchpoint->set)
+               CHECK_RETVAL(arc_unset_watchpoint(target, watchpoint));
+
+       return ERROR_OK;
+}
+
+static int arc_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint)
+{
+       assert(target);
+       assert(hit_watchpoint);
+
+       struct arc_actionpoint *actionpoint = NULL;
+       CHECK_RETVAL(get_current_actionpoint(target, &actionpoint));
+
+       if (actionpoint != NULL) {
+               if (!actionpoint->used)
+                       LOG_WARNING("Target halted by unused actionpoint.");
+
+               /* If this check fails - that is some sort of an error in OpenOCD. */
+               if (actionpoint->type != ARC_AP_WATCHPOINT)
+                       LOG_WARNING("Target halted by breakpoint, but is treated as a watchpoint.");
+
+               for (struct watchpoint *watchpoint = target->watchpoints;
+                               watchpoint != NULL;
+                               watchpoint = watchpoint->next) {
+                       if (actionpoint->bp_value == watchpoint->address) {
+                               *hit_watchpoint = watchpoint;
+                               LOG_DEBUG("Hit watchpoint, wpid: %" PRIu32 ", watchpoint num: %i",
+                                                       watchpoint->unique_id, watchpoint->set - 1);
+                               return ERROR_OK;
+                       }
+               }
+       }
+
+       return ERROR_FAIL;
+}
+
+/* Helper function which switches core to single_step mode by
  * doing aux r/w operations.  */
 int arc_config_step(struct target *target, int enable_step)
 {
@@ -2081,7 +2244,7 @@ struct target_type arcv2_target = {
 
        .arch_state = arc_arch_state,
 
-       /* TODO That seems like something similiar to metaware hostlink, so perhaps
+       /* TODO That seems like something similar to metaware hostlink, so perhaps
         * we can exploit this in the future. */
        .target_request_data = NULL,
 
@@ -2106,9 +2269,9 @@ struct target_type arcv2_target = {
        .add_context_breakpoint = NULL,
        .add_hybrid_breakpoint = NULL,
        .remove_breakpoint = arc_remove_breakpoint,
-       .add_watchpoint = NULL,
-       .remove_watchpoint = NULL,
-       .hit_watchpoint = NULL,
+       .add_watchpoint = arc_add_watchpoint,
+       .remove_watchpoint = arc_remove_watchpoint,
+       .hit_watchpoint = arc_hit_watchpoint,
 
        .run_algorithm = NULL,
        .start_algorithm = NULL,