+ LOG_TARGET_ERROR(target, "not halted (remove breakpoint)");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ return ERROR_OK;
+}
+
+static 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;
+ arc_remove_breakpoint(target, target->breakpoints);
+ free(target->breakpoints->orig_instr);
+ 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);
+ }
+}
+
+int arc_set_actionpoints_num(struct target *target, uint32_t ap_num)
+{
+ LOG_DEBUG("target=%s actionpoints=%" PRIu32, target_name(target), ap_num);
+ struct arc_common *arc = target_to_arc(target);
+
+ /* Make sure that there are no enabled actionpoints in target. */
+ arc_reset_actionpoints(target);
+
+ /* Assume that all points have been removed from target. */
+ free(arc->actionpoints_list);
+
+ arc->actionpoints_num_avail = ap_num;
+ arc->actionpoints_num = ap_num;
+ /* calloc can be safely called when ncount == 0. */
+ arc->actionpoints_list = calloc(ap_num, sizeof(struct arc_actionpoint));
+
+ if (!arc->actionpoints_list) {
+ LOG_ERROR("Unable to allocate memory");
+ return ERROR_FAIL;
+ }
+ return ERROR_OK;
+}
+
+
+int arc_add_auxreg_actionpoint(struct target *target,
+ uint32_t auxreg_addr, uint32_t transaction)
+{
+ unsigned int ap_num = 0;
+ int retval = ERROR_OK;
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ struct arc_common *arc = target_to_arc(target);
+ struct arc_actionpoint *ap_list = arc->actionpoints_list;
+
+ while (ap_list[ap_num].used)
+ ap_num++;
+
+ if (ap_num >= arc->actionpoints_num) {
+ LOG_ERROR("No actionpoint free, maximum amount is %u",
+ arc->actionpoints_num);
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ retval = arc_configure_actionpoint(target, ap_num,
+ auxreg_addr, transaction, AP_AC_AT_AUXREG_ADDR);
+
+ if (retval == ERROR_OK) {
+ ap_list[ap_num].used = 1;
+ ap_list[ap_num].reg_address = auxreg_addr;
+ }
+
+ return retval;
+}
+
+int arc_remove_auxreg_actionpoint(struct target *target, uint32_t auxreg_addr)
+{
+ int retval = ERROR_OK;
+ bool ap_found = false;
+ unsigned int ap_num = 0;
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ struct arc_common *arc = target_to_arc(target);
+ struct arc_actionpoint *ap_list = arc->actionpoints_list;
+
+ while ((ap_list[ap_num].used) && (ap_num < arc->actionpoints_num)) {
+ if (ap_list[ap_num].reg_address == auxreg_addr) {
+ ap_found = true;
+ break;
+ }
+ ap_num++;
+ }
+
+ if (ap_found) {
+ retval = arc_configure_actionpoint(target, ap_num,
+ auxreg_addr, AP_AC_TT_DISABLE, AP_AC_AT_AUXREG_ADDR);
+
+ if (retval == ERROR_OK) {
+ ap_list[ap_num].used = 0;
+ ap_list[ap_num].bp_value = 0;
+ }
+ } else {
+ LOG_ERROR("Register actionpoint not found");
+ }
+ return retval;
+}
+
+
+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->is_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(watchpoint, wp_num);
+ 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->is_set) {
+ LOG_WARNING("watchpoint not set");
+ return ERROR_OK;
+ }
+
+ unsigned int wp_num = watchpoint->number;
+ if (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->is_set = false;
+ 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_enable_watchpoints(struct target *target)
+{
+ struct watchpoint *watchpoint = target->watchpoints;
+
+ /* set any pending watchpoints */
+ while (watchpoint) {
+ if (!watchpoint->is_set)
+ CHECK_RETVAL(arc_set_watchpoint(target, watchpoint));
+ watchpoint = watchpoint->next;
+ }
+
+ return ERROR_OK;
+}
+
+static int arc_add_watchpoint(struct target *target,
+ struct watchpoint *watchpoint)
+{
+ if (target->state != TARGET_HALTED) {
+ LOG_TARGET_ERROR(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_TARGET_ERROR(target, "not halted");