+// SPDX-License-Identifier: GPL-2.0-or-later
+
/***************************************************************************
* Copyright (C) 2013-2015,2019-2020 Synopsys, Inc. *
* Frank Dols <frank.dols@synopsys.com> *
* Mischa Jonker <mischa.jonker@synopsys.com> *
* Anton Kolesov <anton.kolesov@synopsys.com> *
* Evgeniy Didin <didin@synopsys.com> *
- * *
- * SPDX-License-Identifier: GPL-2.0-or-later *
***************************************************************************/
static int arc_remove_watchpoint(struct target *target,
struct watchpoint *watchpoint);
+static int arc_enable_watchpoints(struct target *target);
+static int arc_enable_breakpoints(struct target *target);
+static int arc_unset_breakpoint(struct target *target,
+ struct breakpoint *breakpoint);
+static int arc_set_breakpoint(struct target *target,
+ struct breakpoint *breakpoint);
+static int arc_single_step_core(struct target *target);
void arc_reg_data_type_add(struct target *target,
struct arc_reg_data_type *data_type)
*
* @param target Target for which to reset caches states.
*/
-int arc_reset_caches_states(struct target *target)
+static int arc_reset_caches_states(struct target *target)
{
struct arc_common *arc = target_to_arc(target);
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;
}
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;
}
return ERROR_OK;
}
-const struct reg_arch_type arc_reg_type = {
+static const struct reg_arch_type arc_reg_type = {
.get = arc_get_register,
.set = arc_set_register,
};
return ERROR_OK;
}
+static int arc_exit_debug(struct target *target)
+{
+ uint32_t value;
+ struct arc_common *arc = target_to_arc(target);
+
+ /* Do read-modify-write sequence, or DEBUG.UB will be reset unintentionally. */
+ CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, &value));
+ value |= SET_CORE_FORCE_HALT; /* set the HALT bit */
+ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, value));
+ alive_sleep(1);
+
+ target->state = TARGET_HALTED;
+ CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED));
+
+ if (debug_level >= LOG_LVL_DEBUG) {
+ LOG_DEBUG("core stopped (halted) debug-reg: 0x%08" PRIx32, value);
+ CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, &value));
+ LOG_DEBUG("core STATUS32: 0x%08" PRIx32, value);
+ }
+
+ return ERROR_OK;
+}
+
static int arc_halt(struct target *target)
{
uint32_t value, irq_state;
memset(aux_addrs, 0xff, aux_regs_size);
for (i = 0; i < MIN(arc->num_core_regs, regs_to_scan); i++) {
- struct reg *reg = &(reg_list[i]);
+ struct reg *reg = reg_list + i;
struct arc_reg_desc *arc_reg = reg->arch_info;
- if (!reg->valid && reg->exist) {
- core_addrs[core_cnt] = arc_reg->arch_num;
- core_cnt += 1;
- }
+ if (!reg->valid && reg->exist)
+ core_addrs[core_cnt++] = arc_reg->arch_num;
}
for (i = arc->num_core_regs; i < regs_to_scan; i++) {
- struct reg *reg = &(reg_list[i]);
+ struct reg *reg = reg_list + i;
struct arc_reg_desc *arc_reg = reg->arch_info;
- if (!reg->valid && reg->exist) {
- aux_addrs[aux_cnt] = arc_reg->arch_num;
- aux_cnt += 1;
- }
+ if (!reg->valid && reg->exist)
+ aux_addrs[aux_cnt++] = arc_reg->arch_num;
}
/* Read data from target. */
if (core_cnt > 0) {
retval = arc_jtag_read_core_reg(&arc->jtag_info, core_addrs, core_cnt, core_values);
- if (ERROR_OK != retval) {
+ if (retval != ERROR_OK) {
LOG_ERROR("Attempt to read core registers failed.");
retval = ERROR_FAIL;
goto exit;
}
if (aux_cnt > 0) {
retval = arc_jtag_read_aux_reg(&arc->jtag_info, aux_addrs, aux_cnt, aux_values);
- if (ERROR_OK != retval) {
+ if (retval != ERROR_OK) {
LOG_ERROR("Attempt to read aux registers failed.");
retval = ERROR_FAIL;
goto exit;
/* Parse core regs */
core_cnt = 0;
for (i = 0; i < MIN(arc->num_core_regs, regs_to_scan); i++) {
- struct reg *reg = &(reg_list[i]);
+ struct reg *reg = reg_list + i;
struct arc_reg_desc *arc_reg = reg->arch_info;
if (!reg->valid && reg->exist) {
target_buffer_set_u32(target, reg->value, core_values[core_cnt]);
- core_cnt += 1;
reg->valid = true;
reg->dirty = false;
LOG_DEBUG("Get core register regnum=%u, name=%s, value=0x%08" PRIx32,
i, arc_reg->name, core_values[core_cnt]);
+ core_cnt++;
}
}
/* Parse aux regs */
aux_cnt = 0;
for (i = arc->num_core_regs; i < regs_to_scan; i++) {
- struct reg *reg = &(reg_list[i]);
+ struct reg *reg = reg_list + i;
struct arc_reg_desc *arc_reg = reg->arch_info;
if (!reg->valid && reg->exist) {
target_buffer_set_u32(target, reg->value, aux_values[aux_cnt]);
- aux_cnt += 1;
reg->valid = true;
reg->dirty = false;
LOG_DEBUG("Get aux register regnum=%u, name=%s, value=0x%08" PRIx32,
i, arc_reg->name, aux_values[aux_cnt]);
+ aux_cnt++;
}
}
static int get_current_actionpoint(struct target *target,
struct arc_actionpoint **actionpoint)
{
- assert(target != NULL);
- assert(actionpoint != NULL);
+ assert(target);
+ assert(actionpoint);
uint32_t debug_ah;
/* Check if actionpoint caused halt */
struct arc_actionpoint *actionpoint = NULL;
CHECK_RETVAL(get_current_actionpoint(target, &actionpoint));
- if (actionpoint != NULL) {
+ if (actionpoint) {
if (!actionpoint->used)
LOG_WARNING("Target halted by an unused actionpoint.");
* Check before write, if aux and core count is greater than 0. */
if (core_cnt > 0) {
retval = arc_jtag_write_core_reg(&arc->jtag_info, core_addrs, core_cnt, core_values);
- if (ERROR_OK != retval) {
+ if (retval != ERROR_OK) {
LOG_ERROR("Attempt to write to core registers failed.");
retval = ERROR_FAIL;
goto exit;
if (aux_cnt > 0) {
retval = arc_jtag_write_aux_reg(&arc->jtag_info, aux_addrs, aux_cnt, aux_values);
- if (ERROR_OK != retval) {
+ if (retval != ERROR_OK) {
LOG_ERROR("Attempt to write to aux registers failed.");
retval = ERROR_FAIL;
goto exit;
uint32_t value;
struct reg *pc = &arc->core_and_aux_cache->reg_list[arc->pc_index_in_cache];
- LOG_DEBUG("current:%i, address:0x%08" TARGET_PRIxADDR ", handle_breakpoints(not supported yet):%i,"
+ LOG_DEBUG("current:%i, address:0x%08" TARGET_PRIxADDR ", handle_breakpoints:%i,"
" debug_execution:%i", current, address, handle_breakpoints, debug_execution);
/* We need to reset ARC cache variables so caches
CHECK_RETVAL(arc_reset_caches_states(target));
if (target->state != TARGET_HALTED) {
- LOG_WARNING("target not halted");
+ LOG_TARGET_ERROR(target, "not halted");
return ERROR_TARGET_NOT_HALTED;
}
+ if (!debug_execution) {
+ /* (gdb) continue = execute until we hit break/watch-point */
+ target_free_all_working_areas(target);
+ CHECK_RETVAL(arc_enable_breakpoints(target));
+ CHECK_RETVAL(arc_enable_watchpoints(target));
+ }
+
/* current = 1: continue on current PC, otherwise continue at <address> */
if (!current) {
target_buffer_set_u32(target, pc->value, address);
- pc->dirty = 1;
- pc->valid = 1;
+ pc->dirty = true;
+ pc->valid = true;
LOG_DEBUG("Changing the value of current PC to 0x%08" TARGET_PRIxADDR, address);
}
resume_pc, pc->dirty, pc->valid);
/* check if GDB tells to set our PC where to continue from */
- if ((pc->valid == 1) && (resume_pc == target_buffer_get_u32(target, pc->value))) {
+ if (pc->valid && resume_pc == target_buffer_get_u32(target, pc->value)) {
value = target_buffer_get_u32(target, pc->value);
LOG_DEBUG("resume Core (when start-core) with PC @:0x%08" PRIx32, value);
CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_PC_REG, value));
}
+ /* the front-end may request us not to handle breakpoints here */
+ if (handle_breakpoints) {
+ /* Single step past breakpoint at current address */
+ struct breakpoint *breakpoint = breakpoint_find(target, resume_pc);
+ if (breakpoint) {
+ LOG_DEBUG("skipping past breakpoint at 0x%08" TARGET_PRIxADDR,
+ breakpoint->address);
+ CHECK_RETVAL(arc_unset_breakpoint(target, breakpoint));
+ CHECK_RETVAL(arc_single_step_core(target));
+ CHECK_RETVAL(arc_set_breakpoint(target, breakpoint));
+ }
+ }
+
/* Restore IRQ state if not in debug_execution*/
if (!debug_execution)
CHECK_RETVAL(arc_enable_interrupts(target, arc->irq_state));
* little endian, so different type of conversion should be done.
* Middle endian: instruction "aabbccdd", stored as "bbaaddcc"
*/
-int arc_write_instruction_u32(struct target *target, uint32_t address,
+static int arc_write_instruction_u32(struct target *target, uint32_t address,
uint32_t instr)
{
uint8_t value_buf[4];
* case of little endian ARC instructions are in middle endian format, so
* different type of conversion should be done.
*/
-int arc_read_instruction_u32(struct target *target, uint32_t address,
+static int arc_read_instruction_u32(struct target *target, uint32_t address,
uint32_t *value)
{
uint8_t value_buf[4];
if (control_tt != AP_AC_TT_DISABLE) {
if (arc->actionpoints_num_avail < 1) {
- LOG_ERROR("No free actionpoints, maximim amount is %u",
+ LOG_ERROR("No free actionpoints, maximum amount is %u",
arc->actionpoints_num);
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
static int arc_set_breakpoint(struct target *target,
struct breakpoint *breakpoint)
{
- if (breakpoint->set) {
+ if (breakpoint->is_set) {
LOG_WARNING("breakpoint already set");
return ERROR_OK;
}
return ERROR_COMMAND_ARGUMENT_INVALID;
}
- breakpoint->set = 64; /* Any nice value but 0 */
+ breakpoint->is_set = true;
} else if (breakpoint->type == BKPT_HARD) {
struct arc_common *arc = target_to_arc(target);
struct arc_actionpoint *ap_list = arc->actionpoints_list;
breakpoint->address, AP_AC_TT_READWRITE, AP_AC_AT_INST_ADDR);
if (retval == ERROR_OK) {
- breakpoint->set = bp_num + 1;
+ breakpoint_hw_set(breakpoint, bp_num);
ap_list[bp_num].used = 1;
ap_list[bp_num].bp_value = breakpoint->address;
ap_list[bp_num].type = ARC_AP_BREAKPOINT;
return ERROR_FAIL;
}
- /* core instruction cache is now invalid. */
- CHECK_RETVAL(arc_cache_invalidate(target));
-
return ERROR_OK;
}
{
int retval = ERROR_OK;
- if (!breakpoint->set) {
+ if (!breakpoint->is_set) {
LOG_WARNING("breakpoint not set");
return ERROR_OK;
}
LOG_ERROR("Invalid breakpoint length: target supports only 2 or 4");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
- breakpoint->set = 0;
+ breakpoint->is_set = false;
} else if (breakpoint->type == BKPT_HARD) {
struct arc_common *arc = target_to_arc(target);
struct arc_actionpoint *ap_list = arc->actionpoints_list;
- unsigned int bp_num = breakpoint->set - 1;
+ unsigned int bp_num = breakpoint->number;
- if ((breakpoint->set == 0) || (bp_num >= arc->actionpoints_num)) {
+ if (bp_num >= arc->actionpoints_num) {
LOG_DEBUG("Invalid actionpoint ID: %u in breakpoint: %" PRIu32,
bp_num, breakpoint->unique_id);
return ERROR_OK;
breakpoint->address, AP_AC_TT_DISABLE, AP_AC_AT_INST_ADDR);
if (retval == ERROR_OK) {
- breakpoint->set = 0;
+ breakpoint->is_set = false;
ap_list[bp_num].used = 0;
ap_list[bp_num].bp_value = 0;
- LOG_DEBUG("bpid: %" PRIu32 " - released actionpoint ID: %i",
+ LOG_DEBUG("bpid: %" PRIu32 " - released actionpoint ID: %u",
breakpoint->unique_id, bp_num);
}
} else {
return ERROR_FAIL;
}
- /* core instruction cache is now invalid. */
- CHECK_RETVAL(arc_cache_invalidate(target));
-
return retval;
}
+static int arc_enable_breakpoints(struct target *target)
+{
+ struct breakpoint *breakpoint = target->breakpoints;
+
+ /* set any pending breakpoints */
+ while (breakpoint) {
+ if (!breakpoint->is_set)
+ CHECK_RETVAL(arc_set_breakpoint(target, breakpoint));
+ breakpoint = breakpoint->next;
+ }
+
+ return ERROR_OK;
+}
static int arc_add_breakpoint(struct target *target, struct breakpoint *breakpoint)
{
return arc_set_breakpoint(target, breakpoint);
} else {
- LOG_WARNING(" > core was not halted, please try again.");
+ LOG_TARGET_ERROR(target, "not halted (add breakpoint)");
return ERROR_TARGET_NOT_HALTED;
}
}
struct breakpoint *breakpoint)
{
if (target->state == TARGET_HALTED) {
- if (breakpoint->set)
+ if (breakpoint->is_set)
CHECK_RETVAL(arc_unset_breakpoint(target, breakpoint));
} else {
- LOG_WARNING("target not halted");
+ LOG_TARGET_ERROR(target, "not halted (remove breakpoint)");
return ERROR_TARGET_NOT_HALTED;
}
return ERROR_OK;
}
-void arc_reset_actionpoints(struct target *target)
+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 arc_common *arc = target_to_arc(target);
struct arc_actionpoint *ap_list = arc->actionpoints_list;
- if (watchpoint->set) {
+ if (watchpoint->is_set) {
LOG_WARNING("watchpoint already set");
return ERROR_OK;
}
watchpoint->address, enable, AP_AC_AT_MEMORY_ADDR);
if (retval == ERROR_OK) {
- watchpoint->set = wp_num + 1;
+ 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;
struct arc_common *arc = target_to_arc(target);
struct arc_actionpoint *ap_list = arc->actionpoints_list;
- if (!watchpoint->set) {
+ if (!watchpoint->is_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)) {
+ 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;
watchpoint->address, AP_AC_TT_DISABLE, AP_AC_AT_MEMORY_ADDR);
if (retval == ERROR_OK) {
- watchpoint->set = 0;
+ watchpoint->is_set = false;
ap_list[wp_num].used = 0;
ap_list[wp_num].bp_value = 0;
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_WARNING("target not halted");
+ LOG_TARGET_ERROR(target, "not halted");
return ERROR_TARGET_NOT_HALTED;
}
struct watchpoint *watchpoint)
{
if (target->state != TARGET_HALTED) {
- LOG_WARNING("target not halted");
+ LOG_TARGET_ERROR(target, "not halted");
return ERROR_TARGET_NOT_HALTED;
}
- if (watchpoint->set)
+ if (watchpoint->is_set)
CHECK_RETVAL(arc_unset_watchpoint(target, watchpoint));
return ERROR_OK;
struct arc_actionpoint *actionpoint = NULL;
CHECK_RETVAL(get_current_actionpoint(target, &actionpoint));
- if (actionpoint != NULL) {
+ if (actionpoint) {
if (!actionpoint->used)
LOG_WARNING("Target halted by unused actionpoint.");
LOG_WARNING("Target halted by breakpoint, but is treated as a watchpoint.");
for (struct watchpoint *watchpoint = target->watchpoints;
- watchpoint != NULL;
+ watchpoint;
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);
+ LOG_DEBUG("Hit watchpoint, wpid: %" PRIu32 ", watchpoint num: %u",
+ watchpoint->unique_id, watchpoint->number);
return ERROR_OK;
}
}
/* 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)
+static int arc_config_step(struct target *target, int enable_step)
{
uint32_t value;
return ERROR_OK;
}
-int arc_step(struct target *target, int current, target_addr_t address,
+static int arc_single_step_core(struct target *target)
+{
+ CHECK_RETVAL(arc_debug_entry(target));
+
+ /* disable interrupts while stepping */
+ CHECK_RETVAL(arc_enable_interrupts(target, 0));
+
+ /* configure single step mode */
+ CHECK_RETVAL(arc_config_step(target, 1));
+
+ /* exit debug mode */
+ CHECK_RETVAL(arc_exit_debug(target));
+
+ return ERROR_OK;
+}
+
+static int arc_step(struct target *target, int current, target_addr_t address,
int handle_breakpoints)
{
/* get pointers to arch-specific information */
struct reg *pc = &(arc->core_and_aux_cache->reg_list[arc->pc_index_in_cache]);
if (target->state != TARGET_HALTED) {
- LOG_WARNING("target not halted");
+ LOG_TARGET_ERROR(target, "not halted");
return ERROR_TARGET_NOT_HALTED;
}
/* current = 1: continue on current pc, otherwise continue at <address> */
if (!current) {
buf_set_u32(pc->value, 0, 32, address);
- pc->dirty = 1;
- pc->valid = 1;
+ pc->dirty = true;
+ pc->valid = true;
}
LOG_DEBUG("Target steps one instruction from PC=0x%" PRIx32,
* values directly from memory, bypassing cache, so if there are unflushed
* lines debugger will read invalid values, which will cause a lot of troubles.
* */
-int arc_dcache_flush(struct target *target)
+static int arc_dcache_flush(struct target *target)
{
uint32_t value, dc_ctrl_value;
bool has_to_set_dc_ctrl_im;