// SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2013-2015,2019-2020 Synopsys, Inc. * * Frank Dols * * Mischa Jonker * * Anton Kolesov * * Evgeniy Didin * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arc.h" /* * ARC architecture specific details. * * ARC has two types of registers: * 1) core registers(e.g. r0,r1..) [is_core = true] * 2) Auxiliary registers [is_core = false].. * * Auxiliary registers at the same time can be divided into * read-only BCR(build configuration regs, e.g. isa_config, mpu_build) and * R/RW non-BCR ("control" register, e.g. pc, status32_t, debug). * * The way of accessing to Core and AUX registers differs on Jtag level. * BCR/non-BCR describes if the register is immutable and that reading * unexisting register is safe RAZ, rather then an error. * Note, core registers cannot be BCR. * * 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. * * Due to the specifics of accessing to BCR/non-BCR registers there are two * register caches: * 1) core_and_aux_cache - includes registers described in * core_reg_descriptions and aux_reg_descriptions lists. * Used during save/restore context step. * 2) bcr_cache - includes registers described bcr_reg_descriptions. * Currently used internally during configure step. */ 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) { LOG_DEBUG("Adding %s reg_data_type", data_type->data_type.id); struct arc_common *arc = target_to_arc(target); assert(arc); list_add_tail(&data_type->list, &arc->reg_data_types); } /** * Private implementation of register_get_by_name() for ARC that * doesn't skip not [yet] existing registers. Used in many places * for iteration through registers and even for marking required registers as * existing. */ struct reg *arc_reg_get_by_name(struct reg_cache *first, const char *name, bool search_all) { unsigned int i; struct reg_cache *cache = first; while (cache) { for (i = 0; i < cache->num_regs; i++) { if (!strcmp(cache->reg_list[i].name, name)) return &(cache->reg_list[i]); } if (search_all) cache = cache->next; else break; } return NULL; } /** * Reset internal states of caches. Must be called when entering debugging. * * @param target Target for which to reset caches states. */ static int arc_reset_caches_states(struct target *target) { struct arc_common *arc = target_to_arc(target); LOG_DEBUG("Resetting internal variables of caches states"); /* Reset caches states. */ arc->dcache_flushed = false; arc->l2cache_flushed = false; arc->icache_invalidated = false; arc->dcache_invalidated = false; arc->l2cache_invalidated = false; return ERROR_OK; } /* Initialize arc_common structure, which passes to openocd target instance */ static int arc_init_arch_info(struct target *target, struct arc_common *arc, struct jtag_tap *tap) { arc->common_magic = ARC_COMMON_MAGIC; target->arch_info = arc; arc->jtag_info.tap = tap; /* The only allowed ir_length is 4 for ARC jtag. */ if (tap->ir_length != 4) { LOG_ERROR("ARC jtag instruction length should be equal to 4"); return ERROR_FAIL; } /* On most ARC targets there is a dcache, so we enable its flushing * by default. If there no dcache, there will be no error, just a slight * performance penalty from unnecessary JTAG operations. */ arc->has_dcache = true; arc->has_icache = true; /* L2$ is not available in a target by default. */ arc->has_l2cache = false; arc_reset_caches_states(target); /* Add standard GDB data types */ INIT_LIST_HEAD(&arc->reg_data_types); struct arc_reg_data_type *std_types = calloc(ARRAY_SIZE(standard_gdb_types), sizeof(*std_types)); if (!std_types) { LOG_ERROR("Unable to allocate memory"); return ERROR_FAIL; } for (unsigned int i = 0; i < ARRAY_SIZE(standard_gdb_types); i++) { std_types[i].data_type.type = standard_gdb_types[i].type; std_types[i].data_type.id = standard_gdb_types[i].id; arc_reg_data_type_add(target, &(std_types[i])); } /* Fields related to target descriptions */ INIT_LIST_HEAD(&arc->core_reg_descriptions); INIT_LIST_HEAD(&arc->aux_reg_descriptions); INIT_LIST_HEAD(&arc->bcr_reg_descriptions); arc->num_regs = 0; arc->num_core_regs = 0; arc->num_aux_regs = 0; arc->num_bcr_regs = 0; arc->last_general_reg = ULONG_MAX; arc->pc_index_in_cache = ULONG_MAX; arc->debug_index_in_cache = ULONG_MAX; return ERROR_OK; } int arc_reg_add(struct target *target, struct arc_reg_desc *arc_reg, const char * const type_name, const size_t type_name_len) { assert(target); assert(arc_reg); struct arc_common *arc = target_to_arc(target); assert(arc); /* Find register type */ { struct arc_reg_data_type *type; list_for_each_entry(type, &arc->reg_data_types, list) if (!strncmp(type->data_type.id, type_name, type_name_len)) { arc_reg->data_type = &(type->data_type); break; } if (!arc_reg->data_type) return ERROR_ARC_REGTYPE_NOT_FOUND; } if (arc_reg->is_core) { list_add_tail(&arc_reg->list, &arc->core_reg_descriptions); arc->num_core_regs += 1; } else if (arc_reg->is_bcr) { list_add_tail(&arc_reg->list, &arc->bcr_reg_descriptions); arc->num_bcr_regs += 1; } else { list_add_tail(&arc_reg->list, &arc->aux_reg_descriptions); arc->num_aux_regs += 1; } arc->num_regs += 1; LOG_DEBUG( "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" : "" ); return ERROR_OK; } /* Reading core or aux register */ static int arc_get_register(struct reg *reg) { assert(reg); struct arc_reg_desc *desc = reg->arch_info; struct target *target = desc->target; struct arc_common *arc = target_to_arc(target); uint32_t value; if (reg->valid) { LOG_DEBUG("Get register (cached) gdb_num=%" PRIu32 ", name=%s, value=0x%" PRIx32, reg->number, desc->name, target_buffer_get_u32(target, reg->value)); return ERROR_OK; } if (desc->is_core) { /* Accessing to R61/R62 registers causes Jtag hang */ 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; } CHECK_RETVAL(arc_jtag_read_core_reg_one(&arc->jtag_info, desc->arch_num, &value)); } else { CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, desc->arch_num, &value)); } target_buffer_set_u32(target, reg->value, value); /* If target is unhalted all register reads should be uncached. */ if (target->state == TARGET_HALTED) reg->valid = true; else reg->valid = false; reg->dirty = false; LOG_DEBUG("Get register gdb_num=%" PRIu32 ", name=%s, value=0x%" PRIx32, reg->number, desc->name, value); return ERROR_OK; } /* Writing core or aux register */ static int arc_set_register(struct reg *reg, uint8_t *buf) { struct arc_reg_desc *desc = reg->arch_info; struct target *target = desc->target; uint32_t value = target_buffer_get_u32(target, buf); /* Unlike "get" function "set" is supported only if target * is in halt mode. Async writes are not supported yet. */ if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; /* Accessing to R61/R62 registers causes Jtag hang */ 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; } target_buffer_set_u32(target, reg->value, value); LOG_DEBUG("Set register gdb_num=%" PRIu32 ", name=%s, value=0x%08" PRIx32, reg->number, desc->name, value); reg->valid = true; reg->dirty = true; return ERROR_OK; } static const struct reg_arch_type arc_reg_type = { .get = arc_get_register, .set = arc_set_register, }; /* 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 = ""; /* Common code to initialize `struct reg` for different registers: core, aux, bcr. */ static int arc_init_reg(struct target *target, struct reg *reg, struct arc_reg_desc *reg_desc, unsigned long number) { assert(target); assert(reg); assert(reg_desc); struct arc_common *arc = target_to_arc(target); /* 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->type = &arc_reg_type; reg->arch_info = reg_desc; reg->caller_save = true; /* @todo should be configurable. */ reg->reg_data_type = reg_desc->data_type; reg->feature = ®_desc->feature; reg->feature->name = reg_desc->gdb_xml_feature; /* reg->number is used by OpenOCD as value for @regnum. Thus when setting * value of a register GDB will use it as a number of register in * P-packet. OpenOCD gdbserver will then use number of register in * P-packet as an array index in the reg_list returned by * arc_regs_get_gdb_reg_list. So to ensure that registers are assigned * correctly it would be required to either sort registers in * arc_regs_get_gdb_reg_list or to assign numbers sequentially here and * according to how registers will be sorted in * arc_regs_get_gdb_reg_list. Second options is much more simpler. */ reg->number = number; if (reg_desc->is_general) { arc->last_general_reg = reg->number; reg->group = reg_group_general; } else { reg->group = reg_group_other; } return ERROR_OK; } /* Building aux/core reg_cache */ static int arc_build_reg_cache(struct target *target) { unsigned long i = 0; struct arc_reg_desc *reg_desc; /* get pointers to arch-specific information */ struct arc_common *arc = target_to_arc(target); const unsigned long num_regs = arc->num_core_regs + arc->num_aux_regs; struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct reg_cache *cache = calloc(1, sizeof(*cache)); struct reg *reg_list = calloc(num_regs, sizeof(*reg_list)); if (!cache || !reg_list) { LOG_ERROR("Not enough memory"); goto fail; } /* Build the process context cache */ cache->name = "arc registers"; cache->next = NULL; cache->reg_list = reg_list; cache->num_regs = num_regs; arc->core_and_aux_cache = cache; (*cache_p) = cache; if (list_empty(&arc->core_reg_descriptions)) { LOG_ERROR("No core registers were defined"); goto fail; } list_for_each_entry(reg_desc, &arc->core_reg_descriptions, list) { CHECK_RETVAL(arc_init_reg(target, ®_list[i], reg_desc, i)); LOG_DEBUG("reg n=%3li name=%3s group=%s feature=%s", i, reg_list[i].name, reg_list[i].group, reg_list[i].feature->name); i += 1; } if (list_empty(&arc->aux_reg_descriptions)) { LOG_ERROR("No aux registers were defined"); goto fail; } list_for_each_entry(reg_desc, &arc->aux_reg_descriptions, list) { CHECK_RETVAL(arc_init_reg(target, ®_list[i], reg_desc, i)); LOG_DEBUG("reg n=%3li name=%3s group=%s feature=%s", i, reg_list[i].name, reg_list[i].group, reg_list[i].feature->name); /* PC and DEBUG are essential so we search for them. */ if (!strcmp("pc", reg_desc->name)) { if (arc->pc_index_in_cache != ULONG_MAX) { LOG_ERROR("Double definition of PC in configuration"); goto fail; } arc->pc_index_in_cache = i; } else if (!strcmp("debug", reg_desc->name)) { if (arc->debug_index_in_cache != ULONG_MAX) { LOG_ERROR("Double definition of DEBUG in configuration"); goto fail; } arc->debug_index_in_cache = i; } i += 1; } if (arc->pc_index_in_cache == ULONG_MAX || arc->debug_index_in_cache == ULONG_MAX) { LOG_ERROR("`pc' and `debug' registers must be present in target description."); goto fail; } assert(i == (arc->num_core_regs + arc->num_aux_regs)); arc->core_aux_cache_built = true; return ERROR_OK; fail: free(cache); free(reg_list); return ERROR_FAIL; } /* Build bcr reg_cache. * This function must be called only after arc_build_reg_cache */ static int arc_build_bcr_reg_cache(struct target *target) { /* get pointers to arch-specific information */ struct arc_common *arc = target_to_arc(target); const unsigned long num_regs = arc->num_bcr_regs; struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct reg_cache *cache = malloc(sizeof(*cache)); struct reg *reg_list = calloc(num_regs, sizeof(*reg_list)); struct arc_reg_desc *reg_desc; unsigned long i = 0; unsigned long gdb_regnum = arc->core_and_aux_cache->num_regs; if (!cache || !reg_list) { LOG_ERROR("Unable to allocate memory"); goto fail; } /* Build the process context cache */ cache->name = "arc.bcr"; cache->next = NULL; cache->reg_list = reg_list; cache->num_regs = num_regs; arc->bcr_cache = cache; (*cache_p) = cache; if (list_empty(&arc->bcr_reg_descriptions)) { LOG_ERROR("No BCR registers are defined"); goto fail; } list_for_each_entry(reg_desc, &arc->bcr_reg_descriptions, list) { CHECK_RETVAL(arc_init_reg(target, ®_list[i], reg_desc, gdb_regnum)); /* BCRs always semantically, they are just read-as-zero, if there is * not real register. */ reg_list[i].exist = true; LOG_DEBUG("reg n=%3li name=%3s group=%s feature=%s", i, reg_list[i].name, reg_list[i].group, reg_list[i].feature->name); i += 1; gdb_regnum += 1; } assert(i == arc->num_bcr_regs); arc->bcr_cache_built = true; return ERROR_OK; fail: free(cache); free(reg_list); return ERROR_FAIL; } static int arc_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { assert(target->reg_cache); struct arc_common *arc = target_to_arc(target); /* get pointers to arch-specific information storage */ *reg_list_size = arc->num_regs; *reg_list = calloc(*reg_list_size, sizeof(struct reg *)); if (!*reg_list) { LOG_ERROR("Unable to allocate memory"); return ERROR_FAIL; } /* OpenOCD gdb_server API seems to be inconsistent here: when it generates * XML tdesc it filters out !exist registers, however when creating a * g-packet it doesn't do so. REG_CLASS_ALL is used in first case, and * REG_CLASS_GENERAL used in the latter one. Due to this we had to filter * out !exist register for "general", but not for "all". Attempts to filter out * !exist for "all" as well will cause a failed check in OpenOCD GDB * server. */ if (reg_class == REG_CLASS_ALL) { unsigned long i = 0; struct reg_cache *reg_cache = target->reg_cache; while (reg_cache) { for (unsigned j = 0; j < reg_cache->num_regs; j++, i++) (*reg_list)[i] = ®_cache->reg_list[j]; reg_cache = reg_cache->next; } assert(i == arc->num_regs); LOG_DEBUG("REG_CLASS_ALL: number of regs=%i", *reg_list_size); } else { unsigned long i = 0; unsigned long gdb_reg_number = 0; struct reg_cache *reg_cache = target->reg_cache; while (reg_cache) { for (unsigned j = 0; j < reg_cache->num_regs && gdb_reg_number <= arc->last_general_reg; j++) { if (reg_cache->reg_list[j].exist) { (*reg_list)[i] = ®_cache->reg_list[j]; i++; } gdb_reg_number += 1; } reg_cache = reg_cache->next; } *reg_list_size = i; LOG_DEBUG("REG_CLASS_GENERAL: number of regs=%i", *reg_list_size); } return ERROR_OK; } /* Reading field of struct_type register */ int arc_reg_get_field(struct target *target, const char *reg_name, const char *field_name, uint32_t *value_ptr) { struct reg_data_type_struct_field *field; LOG_DEBUG("getting register field (reg_name=%s, field_name=%s)", reg_name, field_name); /* Get register */ struct reg *reg = arc_reg_get_by_name(target->reg_cache, reg_name, true); if (!reg) { LOG_ERROR("Requested register `%s' doesn't exist.", reg_name); return ERROR_ARC_REGISTER_NOT_FOUND; } if (reg->reg_data_type->type != REG_TYPE_ARCH_DEFINED || reg->reg_data_type->type_class != REG_TYPE_CLASS_STRUCT) return ERROR_ARC_REGISTER_IS_NOT_STRUCT; /* Get field in a register */ struct reg_data_type_struct *reg_struct = reg->reg_data_type->reg_type_struct; for (field = reg_struct->fields; field; field = field->next) { if (!strcmp(field->name, field_name)) break; } if (!field) return ERROR_ARC_REGISTER_FIELD_NOT_FOUND; if (!field->use_bitfields) return ERROR_ARC_FIELD_IS_NOT_BITFIELD; if (!reg->valid) CHECK_RETVAL(reg->type->get(reg)); /* First do endianness-safe read of register value * then convert it to binary buffer for further * field extraction */ *value_ptr = buf_get_u32(reg->value, field->bitfield->start, field->bitfield->end - field->bitfield->start + 1); return ERROR_OK; } static int arc_get_register_value(struct target *target, const char *reg_name, uint32_t *value_ptr) { LOG_DEBUG("reg_name=%s", reg_name); struct reg *reg = arc_reg_get_by_name(target->reg_cache, reg_name, true); if (!reg) return ERROR_ARC_REGISTER_NOT_FOUND; if (!reg->valid) CHECK_RETVAL(reg->type->get(reg)); *value_ptr = target_buffer_get_u32(target, reg->value); return ERROR_OK; } static int arc_set_register_value(struct target *target, const char *reg_name, uint32_t value) { LOG_DEBUG("reg_name=%s value=0x%08" PRIx32, reg_name, value); if (!(target && reg_name)) { LOG_ERROR("Arguments cannot be NULL."); return ERROR_FAIL; } struct reg *reg = arc_reg_get_by_name(target->reg_cache, reg_name, true); if (!reg) return ERROR_ARC_REGISTER_NOT_FOUND; uint8_t value_buf[4]; buf_set_u32(value_buf, 0, 32, value); CHECK_RETVAL(reg->type->set(reg, value_buf)); return ERROR_OK; } /* Configure DCCM's */ static int arc_configure_dccm(struct target *target) { struct arc_common *arc = target_to_arc(target); uint32_t dccm_build_version, dccm_build_size0, dccm_build_size1; CHECK_RETVAL(arc_reg_get_field(target, "dccm_build", "version", &dccm_build_version)); CHECK_RETVAL(arc_reg_get_field(target, "dccm_build", "size0", &dccm_build_size0)); CHECK_RETVAL(arc_reg_get_field(target, "dccm_build", "size1", &dccm_build_size1)); /* There is no yet support of configurable number of cycles, * So there is no difference between v3 and v4 */ if ((dccm_build_version == 3 || dccm_build_version == 4) && dccm_build_size0 > 0) { CHECK_RETVAL(arc_get_register_value(target, "aux_dccm", &(arc->dccm_start))); uint32_t dccm_size = 0x100; dccm_size <<= dccm_build_size0; if (dccm_build_size0 == 0xF) dccm_size <<= dccm_build_size1; arc->dccm_end = arc->dccm_start + dccm_size; LOG_DEBUG("DCCM detected start=0x%" PRIx32 " end=0x%" PRIx32, arc->dccm_start, arc->dccm_end); } return ERROR_OK; } /* Configure ICCM's */ static int arc_configure_iccm(struct target *target) { struct arc_common *arc = target_to_arc(target); /* ICCM0 */ uint32_t iccm_build_version, iccm_build_size00, iccm_build_size01; uint32_t aux_iccm = 0; CHECK_RETVAL(arc_reg_get_field(target, "iccm_build", "version", &iccm_build_version)); CHECK_RETVAL(arc_reg_get_field(target, "iccm_build", "iccm0_size0", &iccm_build_size00)); CHECK_RETVAL(arc_reg_get_field(target, "iccm_build", "iccm0_size1", &iccm_build_size01)); if (iccm_build_version == 4 && iccm_build_size00 > 0) { CHECK_RETVAL(arc_get_register_value(target, "aux_iccm", &aux_iccm)); uint32_t iccm0_size = 0x100; iccm0_size <<= iccm_build_size00; if (iccm_build_size00 == 0xF) iccm0_size <<= iccm_build_size01; /* iccm0 start is located in highest 4 bits of aux_iccm */ arc->iccm0_start = aux_iccm & 0xF0000000; arc->iccm0_end = arc->iccm0_start + iccm0_size; LOG_DEBUG("ICCM0 detected start=0x%" PRIx32 " end=0x%" PRIx32, arc->iccm0_start, arc->iccm0_end); } /* ICCM1 */ uint32_t iccm_build_size10, iccm_build_size11; CHECK_RETVAL(arc_reg_get_field(target, "iccm_build", "iccm1_size0", &iccm_build_size10)); CHECK_RETVAL(arc_reg_get_field(target, "iccm_build", "iccm1_size1", &iccm_build_size11)); if (iccm_build_version == 4 && iccm_build_size10 > 0) { /* Use value read for ICCM0 */ if (!aux_iccm) CHECK_RETVAL(arc_get_register_value(target, "aux_iccm", &aux_iccm)); uint32_t iccm1_size = 0x100; iccm1_size <<= iccm_build_size10; if (iccm_build_size10 == 0xF) iccm1_size <<= iccm_build_size11; arc->iccm1_start = aux_iccm & 0x0F000000; arc->iccm1_end = arc->iccm1_start + iccm1_size; LOG_DEBUG("ICCM1 detected start=0x%" PRIx32 " end=0x%" PRIx32, arc->iccm1_start, arc->iccm1_end); } return ERROR_OK; } /* Configure some core features, depending on BCRs. */ static int arc_configure(struct target *target) { LOG_DEBUG("Configuring ARC ICCM and DCCM"); /* Configuring DCCM if DCCM_BUILD and AUX_DCCM are known registers. */ if (arc_reg_get_by_name(target->reg_cache, "dccm_build", true) && arc_reg_get_by_name(target->reg_cache, "aux_dccm", true)) CHECK_RETVAL(arc_configure_dccm(target)); /* Configuring ICCM if ICCM_BUILD and AUX_ICCM are known registers. */ if (arc_reg_get_by_name(target->reg_cache, "iccm_build", true) && arc_reg_get_by_name(target->reg_cache, "aux_iccm", true)) CHECK_RETVAL(arc_configure_iccm(target)); return ERROR_OK; } /* arc_examine is function, which is used for all arc targets*/ static int arc_examine(struct target *target) { uint32_t status; struct arc_common *arc = target_to_arc(target); CHECK_RETVAL(arc_jtag_startup(&arc->jtag_info)); if (!target_was_examined(target)) { CHECK_RETVAL(arc_jtag_status(&arc->jtag_info, &status)); if (status & ARC_JTAG_STAT_RU) target->state = TARGET_RUNNING; else target->state = TARGET_HALTED; /* Read BCRs and configure optional registers. */ CHECK_RETVAL(arc_configure(target)); target_set_examined(target); } 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; struct arc_common *arc = target_to_arc(target); LOG_DEBUG("target->state: %s", target_state_name(target)); if (target->state == TARGET_HALTED) { LOG_DEBUG("target was already halted"); return ERROR_OK; } if (target->state == TARGET_UNKNOWN) LOG_WARNING("target was in unknown state when halt was requested"); if (target->state == TARGET_RESET) { if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && jtag_get_srst()) { LOG_ERROR("can't request a halt while in reset if nSRST pulls nTRST"); return ERROR_TARGET_FAILURE; } else { target->debug_reason = DBG_REASON_DBGRQ; } } /* Break (stop) processor. * Do read-modify-write sequence, or DEBUG.UB will be reset unintentionally. * We do not use here arc_get/set_core_reg functions here because they imply * that the processor is already halted. */ 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); /* Save current IRQ state */ CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, &irq_state)); if (irq_state & AUX_STATUS32_REG_IE_BIT) arc->irq_state = 1; else arc->irq_state = 0; /* update state and notify gdb*/ target->state = TARGET_HALTED; CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED)); /* some more debug information */ if (debug_level >= LOG_LVL_DEBUG) { LOG_DEBUG("core stopped (halted) DEGUB-REG: 0x%08" PRIx32, value); CHECK_RETVAL(arc_get_register_value(target, "status32", &value)); LOG_DEBUG("core STATUS32: 0x%08" PRIx32, value); } return ERROR_OK; } /** * Read registers that are used in GDB g-packet. We don't read them one-by-one, * but do that in one batch operation to improve speed. Calls to JTAG layer are * expensive so it is better to make one big call that reads all necessary * registers, instead of many calls, one for one register. */ static int arc_save_context(struct target *target) { int retval = ERROR_OK; unsigned int i; struct arc_common *arc = target_to_arc(target); struct reg *reg_list = arc->core_and_aux_cache->reg_list; LOG_DEBUG("Saving aux and core registers values"); assert(reg_list); /* It is assumed that there is at least one AUX register in the list, for * example PC. */ const uint32_t core_regs_size = arc->num_core_regs * sizeof(uint32_t); /* last_general_reg is inclusive number. To get count of registers it is * required to do +1. */ const uint32_t regs_to_scan = MIN(arc->last_general_reg + 1, arc->num_regs); const uint32_t aux_regs_size = arc->num_aux_regs * sizeof(uint32_t); uint32_t *core_values = malloc(core_regs_size); uint32_t *aux_values = malloc(aux_regs_size); uint32_t *core_addrs = malloc(core_regs_size); uint32_t *aux_addrs = malloc(aux_regs_size); unsigned int core_cnt = 0; unsigned int aux_cnt = 0; if (!core_values || !core_addrs || !aux_values || !aux_addrs) { LOG_ERROR("Unable to allocate memory"); retval = ERROR_FAIL; goto exit; } memset(core_values, 0xff, core_regs_size); memset(core_addrs, 0xff, core_regs_size); memset(aux_values, 0xff, aux_regs_size); 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 arc_reg_desc *arc_reg = reg->arch_info; 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 arc_reg_desc *arc_reg = reg->arch_info; 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 (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 (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 arc_reg_desc *arc_reg = reg->arch_info; if (!reg->valid && reg->exist) { target_buffer_set_u32(target, reg->value, core_values[core_cnt]); 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 arc_reg_desc *arc_reg = reg->arch_info; if (!reg->valid && reg->exist) { target_buffer_set_u32(target, reg->value, aux_values[aux_cnt]); 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++; } } exit: free(core_values); free(core_addrs); free(aux_values); free(aux_addrs); return retval; } /** * 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. */ static int get_current_actionpoint(struct target *target, struct arc_actionpoint **actionpoint) { assert(target); assert(actionpoint); uint32_t debug_ah; /* Check if actionpoint caused halt */ CHECK_RETVAL(arc_reg_get_field(target, "debug", "ah", &debug_ah)); if (debug_ah) { struct arc_common *arc = target_to_arc(target); unsigned int ap; uint32_t debug_asr; CHECK_RETVAL(arc_reg_get_field(target, "debug", "asr", &debug_asr)); for (ap = 0; debug_asr > 1; debug_asr >>= 1) ap += 1; assert(ap < arc->actionpoints_num); *actionpoint = &(arc->actionpoints_list[ap]); } else { *actionpoint = NULL; } return ERROR_OK; } static int arc_examine_debug_reason(struct target *target) { uint32_t debug_bh; /* Only check for reason if don't know it already. */ /* BTW After singlestep at this point core is not marked as halted, so * reading from memory to get current instruction wouldn't work anyway. */ if (target->debug_reason == DBG_REASON_DBGRQ || target->debug_reason == DBG_REASON_SINGLESTEP) { return ERROR_OK; } CHECK_RETVAL(arc_reg_get_field(target, "debug", "bh", &debug_bh)); if (debug_bh) { /* DEBUG.BH is set if core halted due to BRK instruction. */ target->debug_reason = DBG_REASON_BREAKPOINT; } else { struct arc_actionpoint *actionpoint = NULL; CHECK_RETVAL(get_current_actionpoint(target, &actionpoint)); if (actionpoint) { if (!actionpoint->used) LOG_WARNING("Target halted by an unused actionpoint."); if (actionpoint->type == ARC_AP_BREAKPOINT) target->debug_reason = DBG_REASON_BREAKPOINT; else if (actionpoint->type == ARC_AP_WATCHPOINT) target->debug_reason = DBG_REASON_WATCHPOINT; else LOG_WARNING("Unknown type of actionpoint."); } } return ERROR_OK; } static int arc_debug_entry(struct target *target) { CHECK_RETVAL(arc_save_context(target)); /* TODO: reset internal indicators of caches states, otherwise D$/I$ * will not be flushed/invalidated when required. */ CHECK_RETVAL(arc_reset_caches_states(target)); CHECK_RETVAL(arc_examine_debug_reason(target)); return ERROR_OK; } static int arc_poll(struct target *target) { uint32_t status, value; struct arc_common *arc = target_to_arc(target); /* gdb calls continuously through this arc_poll() function */ CHECK_RETVAL(arc_jtag_status(&arc->jtag_info, &status)); /* check for processor halted */ if (status & ARC_JTAG_STAT_RU) { if (target->state != TARGET_RUNNING) { LOG_WARNING("target is still running!"); target->state = TARGET_RUNNING; } return ERROR_OK; } /* In some cases JTAG status register indicates that * processor is in halt mode, but processor is still running. * We check halt bit of AUX STATUS32 register for setting correct state. */ if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET)) { CHECK_RETVAL(arc_get_register_value(target, "status32", &value)); if (value & AUX_STATUS32_REG_HALT_BIT) { LOG_DEBUG("ARC core in halt or reset state."); /* Save context if target was not in reset state */ if (target->state == TARGET_RUNNING) CHECK_RETVAL(arc_debug_entry(target)); target->state = TARGET_HALTED; CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED)); } else { LOG_DEBUG("Discrepancy of STATUS32[0] HALT bit and ARC_JTAG_STAT_RU, " "target is still running"); } } else if (target->state == TARGET_DEBUG_RUNNING) { target->state = TARGET_HALTED; LOG_DEBUG("ARC core is in debug running mode"); CHECK_RETVAL(arc_debug_entry(target)); CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED)); } return ERROR_OK; } static int arc_assert_reset(struct target *target) { struct arc_common *arc = target_to_arc(target); enum reset_types jtag_reset_config = jtag_get_reset_config(); bool srst_asserted = false; LOG_DEBUG("target->state: %s", target_state_name(target)); if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) { /* allow scripts to override the reset event */ target_handle_event(target, TARGET_EVENT_RESET_ASSERT); register_cache_invalidate(arc->core_and_aux_cache); /* An ARC target might be in halt state after reset, so * if script requested processor to resume, then it must * be manually started to ensure that this request * is satisfied. */ if (target->state == TARGET_HALTED && !target->reset_halt) { /* Resume the target and continue from the current * PC register value. */ LOG_DEBUG("Starting CPU execution after reset"); CHECK_RETVAL(target_resume(target, 1, 0, 0, 0)); } target->state = TARGET_RESET; return ERROR_OK; } /* some cores support connecting while srst is asserted * use that mode if it has been configured */ if (!(jtag_reset_config & RESET_SRST_PULLS_TRST) && (jtag_reset_config & RESET_SRST_NO_GATING)) { jtag_add_reset(0, 1); srst_asserted = true; } if (jtag_reset_config & RESET_HAS_SRST) { /* should issue a srst only, but we may have to assert trst as well */ if (jtag_reset_config & RESET_SRST_PULLS_TRST) jtag_add_reset(1, 1); else if (!srst_asserted) jtag_add_reset(0, 1); } target->state = TARGET_RESET; jtag_add_sleep(50000); register_cache_invalidate(arc->core_and_aux_cache); if (target->reset_halt) CHECK_RETVAL(target_halt(target)); return ERROR_OK; } static int arc_deassert_reset(struct target *target) { LOG_DEBUG("target->state: %s", target_state_name(target)); /* deassert reset lines */ jtag_add_reset(0, 0); return ERROR_OK; } static int arc_arch_state(struct target *target) { uint32_t pc_value; if (debug_level < LOG_LVL_DEBUG) return ERROR_OK; CHECK_RETVAL(arc_get_register_value(target, "pc", &pc_value)); LOG_DEBUG("target state: %s; PC at: 0x%08" PRIx32, target_state_name(target), pc_value); return ERROR_OK; } /** * See arc_save_context() for reason why we want to dump all regs at once. * This however means that if there are dependencies between registers they * will not be observable until target will be resumed. */ static int arc_restore_context(struct target *target) { int retval = ERROR_OK; unsigned int i; struct arc_common *arc = target_to_arc(target); struct reg *reg_list = arc->core_and_aux_cache->reg_list; LOG_DEBUG("Restoring registers values"); assert(reg_list); const uint32_t core_regs_size = arc->num_core_regs * sizeof(uint32_t); const uint32_t aux_regs_size = arc->num_aux_regs * sizeof(uint32_t); uint32_t *core_values = malloc(core_regs_size); uint32_t *aux_values = malloc(aux_regs_size); uint32_t *core_addrs = malloc(core_regs_size); uint32_t *aux_addrs = malloc(aux_regs_size); unsigned int core_cnt = 0; unsigned int aux_cnt = 0; if (!core_values || !core_addrs || !aux_values || !aux_addrs) { LOG_ERROR("Unable to allocate memory"); retval = ERROR_FAIL; goto exit; } memset(core_values, 0xff, core_regs_size); memset(core_addrs, 0xff, core_regs_size); memset(aux_values, 0xff, aux_regs_size); memset(aux_addrs, 0xff, aux_regs_size); for (i = 0; i < arc->num_core_regs; i++) { struct reg *reg = &(reg_list[i]); struct arc_reg_desc *arc_reg = reg->arch_info; if (reg->valid && reg->exist && reg->dirty) { LOG_DEBUG("Will write regnum=%u", i); core_addrs[core_cnt] = arc_reg->arch_num; core_values[core_cnt] = target_buffer_get_u32(target, reg->value); core_cnt += 1; } } for (i = 0; i < arc->num_aux_regs; i++) { struct reg *reg = &(reg_list[arc->num_core_regs + i]); struct arc_reg_desc *arc_reg = reg->arch_info; if (reg->valid && reg->exist && reg->dirty) { LOG_DEBUG("Will write regnum=%lu", arc->num_core_regs + i); aux_addrs[aux_cnt] = arc_reg->arch_num; aux_values[aux_cnt] = target_buffer_get_u32(target, reg->value); aux_cnt += 1; } } /* Write data to target. * 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 (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 (retval != ERROR_OK) { LOG_ERROR("Attempt to write to aux registers failed."); retval = ERROR_FAIL; goto exit; } } exit: free(core_values); free(core_addrs); free(aux_values); free(aux_addrs); return retval; } static int arc_enable_interrupts(struct target *target, int enable) { uint32_t value; struct arc_common *arc = target_to_arc(target); CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, &value)); if (enable) { /* enable interrupts */ value |= SET_CORE_ENABLE_INTERRUPTS; CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, value)); LOG_DEBUG("interrupts enabled"); } else { /* disable interrupts */ value &= ~SET_CORE_ENABLE_INTERRUPTS; CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, value)); LOG_DEBUG("interrupts disabled"); } return ERROR_OK; } static int arc_resume(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution) { struct arc_common *arc = target_to_arc(target); uint32_t resume_pc = 0; 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:%i," " debug_execution:%i", current, address, handle_breakpoints, debug_execution); /* We need to reset ARC cache variables so caches * would be invalidated and actual data * would be fetched from memory. */ CHECK_RETVAL(arc_reset_caches_states(target)); if (target->state != TARGET_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
*/ if (!current) { target_buffer_set_u32(target, pc->value, address); pc->dirty = true; pc->valid = true; LOG_DEBUG("Changing the value of current PC to 0x%08" TARGET_PRIxADDR, address); } if (!current) resume_pc = address; else resume_pc = target_buffer_get_u32(target, pc->value); CHECK_RETVAL(arc_restore_context(target)); LOG_DEBUG("Target resumes from PC=0x%" PRIx32 ", pc.dirty=%i, pc.valid=%i", resume_pc, pc->dirty, pc->valid); /* check if GDB tells to set our PC where to continue from */ 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)); else CHECK_RETVAL(arc_enable_interrupts(target, !debug_execution)); target->debug_reason = DBG_REASON_NOTHALTED; /* ready to get us going again */ target->state = TARGET_RUNNING; CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, &value)); value &= ~SET_CORE_HALT_BIT; /* clear the HALT bit */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, value)); LOG_DEBUG("Core started to run"); /* registers are now invalid */ register_cache_invalidate(arc->core_and_aux_cache); if (!debug_execution) { target->state = TARGET_RUNNING; CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED)); LOG_DEBUG("target resumed at 0x%08" PRIx32, resume_pc); } else { target->state = TARGET_DEBUG_RUNNING; CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED)); LOG_DEBUG("target debug resumed at 0x%08" PRIx32, resume_pc); } return ERROR_OK; } static int arc_init_target(struct command_context *cmd_ctx, struct target *target) { CHECK_RETVAL(arc_build_reg_cache(target)); CHECK_RETVAL(arc_build_bcr_reg_cache(target)); target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } static void arc_free_reg_cache(struct reg_cache *cache) { free(cache->reg_list); free(cache); } static void arc_deinit_target(struct target *target) { struct arc_common *arc = target_to_arc(target); LOG_DEBUG("deinitialization of target"); if (arc->core_aux_cache_built) arc_free_reg_cache(arc->core_and_aux_cache); if (arc->bcr_cache_built) arc_free_reg_cache(arc->bcr_cache); struct arc_reg_data_type *type, *n; struct arc_reg_desc *desc, *k; /* Free arc-specific reg_data_types allocations*/ list_for_each_entry_safe_reverse(type, n, &arc->reg_data_types, list) { if (type->data_type.type_class == REG_TYPE_CLASS_STRUCT) { free(type->reg_type_struct_field); free(type->bitfields); free(type); } else if (type->data_type.type_class == REG_TYPE_CLASS_FLAGS) { free(type->reg_type_flags_field); free(type->bitfields); free(type); } } /* Free standard_gdb_types reg_data_types allocations */ type = list_first_entry(&arc->reg_data_types, struct arc_reg_data_type, list); free(type); list_for_each_entry_safe(desc, k, &arc->aux_reg_descriptions, list) free_reg_desc(desc); list_for_each_entry_safe(desc, k, &arc->core_reg_descriptions, list) free_reg_desc(desc); list_for_each_entry_safe(desc, k, &arc->bcr_reg_descriptions, list) free_reg_desc(desc); free(arc->actionpoints_list); free(arc); } static int arc_target_create(struct target *target, Jim_Interp *interp) { struct arc_common *arc = calloc(1, sizeof(*arc)); if (!arc) { LOG_ERROR("Unable to allocate memory"); return ERROR_FAIL; } LOG_DEBUG("Entering"); CHECK_RETVAL(arc_init_arch_info(target, arc, target->tap)); return ERROR_OK; } /** * 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 endian: instruction "aabbccdd", stored as "bbaaddcc" */ static int arc_write_instruction_u32(struct target *target, uint32_t address, uint32_t instr) { uint8_t value_buf[4]; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } LOG_DEBUG("Address: 0x%08" PRIx32 ", value: 0x%08" PRIx32, address, instr); if (target->endianness == TARGET_LITTLE_ENDIAN) arc_h_u32_to_me(value_buf, instr); else h_u32_to_be(value_buf, instr); CHECK_RETVAL(target_write_buffer(target, address, 4, value_buf)); return ERROR_OK; } /** * Read 32-bit instruction from memory. It is like target_read_u32, however in * case of little endian ARC instructions are in middle endian format, so * different type of conversion should be done. */ static int arc_read_instruction_u32(struct target *target, uint32_t address, uint32_t *value) { uint8_t value_buf[4]; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } *value = 0; CHECK_RETVAL(target_read_buffer(target, address, 4, value_buf)); if (target->endianness == TARGET_LITTLE_ENDIAN) *value = arc_me_to_h_u32(value_buf); else *value = be_to_h_u32(value_buf); LOG_DEBUG("Address: 0x%08" PRIx32 ", value: 0x%08" PRIx32, address, *value); return ERROR_OK; } /* Actionpoint mechanism allows to setup HW breakpoints * and watchpoints. Each actionpoint is controlled by * 3 aux registers: Actionpoint(AP) match mask(AP_AMM), AP match value(AP_AMV) * and AP control(AC). * This function is for setting/unsetting actionpoints: * at - actionpoint target: trigger on mem/reg access * tt - transaction type : trigger on r/w. */ static int arc_configure_actionpoint(struct target *target, uint32_t ap_num, uint32_t match_value, uint32_t control_tt, uint32_t control_at) { struct arc_common *arc = target_to_arc(target); if (control_tt != AP_AC_TT_DISABLE) { if (arc->actionpoints_num_avail < 1) { LOG_ERROR("No free actionpoints, maximum amount is %u", arc->actionpoints_num); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* Names of register to set - 24 chars should be enough. Looks a little * bit out-of-place for C code, but makes it aligned to the bigger * concept of "ARC registers are defined in TCL" as far as possible. */ char ap_amv_reg_name[24], ap_amm_reg_name[24], ap_ac_reg_name[24]; snprintf(ap_amv_reg_name, 24, "ap_amv%" PRIu32, ap_num); snprintf(ap_amm_reg_name, 24, "ap_amm%" PRIu32, ap_num); snprintf(ap_ac_reg_name, 24, "ap_ac%" PRIu32, ap_num); CHECK_RETVAL(arc_set_register_value(target, ap_amv_reg_name, match_value)); CHECK_RETVAL(arc_set_register_value(target, ap_amm_reg_name, 0)); CHECK_RETVAL(arc_set_register_value(target, ap_ac_reg_name, control_tt | control_at)); arc->actionpoints_num_avail--; } else { char ap_ac_reg_name[24]; snprintf(ap_ac_reg_name, 24, "ap_ac%" PRIu32, ap_num); CHECK_RETVAL(arc_set_register_value(target, ap_ac_reg_name, AP_AC_TT_DISABLE)); arc->actionpoints_num_avail++; } return ERROR_OK; } static int arc_set_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } if (breakpoint->type == BKPT_SOFT) { LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id); if (breakpoint->length == 4) { uint32_t verify = 0xffffffff; CHECK_RETVAL(target_read_buffer(target, breakpoint->address, breakpoint->length, breakpoint->orig_instr)); CHECK_RETVAL(arc_write_instruction_u32(target, breakpoint->address, ARC_SDBBP_32)); CHECK_RETVAL(arc_read_instruction_u32(target, breakpoint->address, &verify)); if (verify != ARC_SDBBP_32) { LOG_ERROR("Unable to set 32bit breakpoint at address @0x%" TARGET_PRIxADDR " - check that memory is read/writable", breakpoint->address); return ERROR_FAIL; } } else if (breakpoint->length == 2) { uint16_t verify = 0xffff; CHECK_RETVAL(target_read_buffer(target, breakpoint->address, breakpoint->length, breakpoint->orig_instr)); CHECK_RETVAL(target_write_u16(target, breakpoint->address, ARC_SDBBP_16)); CHECK_RETVAL(target_read_u16(target, breakpoint->address, &verify)); if (verify != ARC_SDBBP_16) { LOG_ERROR("Unable to set 16bit breakpoint at address @0x%" TARGET_PRIxADDR " - check that memory is read/writable", breakpoint->address); return ERROR_FAIL; } } else { LOG_ERROR("Invalid breakpoint length: target supports only 2 or 4"); return ERROR_COMMAND_ARGUMENT_INVALID; } 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; unsigned int bp_num; for (bp_num = 0; bp_num < arc->actionpoints_num; bp_num++) { if (!ap_list[bp_num].used) break; } if (bp_num >= arc->actionpoints_num) { LOG_ERROR("No free actionpoints, maximum amount is %u", arc->actionpoints_num); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } int retval = arc_configure_actionpoint(target, bp_num, breakpoint->address, AP_AC_TT_READWRITE, AP_AC_AT_INST_ADDR); if (retval == ERROR_OK) { 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; LOG_DEBUG("bpid: %" PRIu32 ", bp_num %u bp_value 0x%" PRIx32, breakpoint->unique_id, bp_num, ap_list[bp_num].bp_value); } } else { LOG_DEBUG("ERROR: setting unknown breakpoint type"); return ERROR_FAIL; } return ERROR_OK; } static int arc_unset_breakpoint(struct target *target, struct breakpoint *breakpoint) { int retval = ERROR_OK; if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_SOFT) { /* restore original instruction (kept in target endianness) */ LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id); if (breakpoint->length == 4) { uint32_t current_instr; /* check that user program has not modified breakpoint instruction */ CHECK_RETVAL(arc_read_instruction_u32(target, breakpoint->address, ¤t_instr)); if (current_instr == ARC_SDBBP_32) { retval = target_write_buffer(target, breakpoint->address, breakpoint->length, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } else { LOG_WARNING("Software breakpoint @0x%" TARGET_PRIxADDR " has been overwritten outside of debugger." "Expected: @0x%x, got: @0x%" PRIx32, breakpoint->address, ARC_SDBBP_32, current_instr); } } else if (breakpoint->length == 2) { uint16_t current_instr; /* check that user program has not modified breakpoint instruction */ CHECK_RETVAL(target_read_u16(target, breakpoint->address, ¤t_instr)); if (current_instr == ARC_SDBBP_16) { retval = target_write_buffer(target, breakpoint->address, breakpoint->length, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } else { LOG_WARNING("Software breakpoint @0x%" TARGET_PRIxADDR " has been overwritten outside of debugger. " "Expected: 0x%04x, got: 0x%04" PRIx16, breakpoint->address, ARC_SDBBP_16, current_instr); } } else { LOG_ERROR("Invalid breakpoint length: target supports only 2 or 4"); return ERROR_COMMAND_ARGUMENT_INVALID; } 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->number; if (bp_num >= arc->actionpoints_num) { LOG_DEBUG("Invalid actionpoint ID: %u in breakpoint: %" PRIu32, bp_num, breakpoint->unique_id); return ERROR_OK; } retval = arc_configure_actionpoint(target, bp_num, breakpoint->address, AP_AC_TT_DISABLE, AP_AC_AT_INST_ADDR); if (retval == ERROR_OK) { breakpoint->is_set = false; ap_list[bp_num].used = 0; ap_list[bp_num].bp_value = 0; LOG_DEBUG("bpid: %" PRIu32 " - released actionpoint ID: %u", breakpoint->unique_id, bp_num); } } else { LOG_DEBUG("ERROR: unsetting unknown breakpoint type"); return ERROR_FAIL; } 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) { if (target->state == TARGET_HALTED) { return arc_set_breakpoint(target, breakpoint); } else { LOG_TARGET_ERROR(target, "not halted (add breakpoint)"); return ERROR_TARGET_NOT_HALTED; } } static int arc_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (target->state == TARGET_HALTED) { if (breakpoint->is_set) CHECK_RETVAL(arc_unset_breakpoint(target, breakpoint)); } else { 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"); return ERROR_TARGET_NOT_HALTED; } if (watchpoint->is_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) { 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; watchpoint = watchpoint->next) { if (actionpoint->bp_value == watchpoint->address) { *hit_watchpoint = watchpoint; LOG_DEBUG("Hit watchpoint, wpid: %" PRIu32 ", watchpoint num: %u", watchpoint->unique_id, watchpoint->number); return ERROR_OK; } } } return ERROR_FAIL; } /* Helper function which switches core to single_step mode by * doing aux r/w operations. */ static int arc_config_step(struct target *target, int enable_step) { uint32_t value; struct arc_common *arc = target_to_arc(target); /* enable core debug step mode */ if (enable_step) { CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, &value)); value &= ~SET_CORE_AE_BIT; /* clear the AE bit */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, value)); LOG_DEBUG(" [status32:0x%08" PRIx32 "]", value); /* Doing read-modify-write, because DEBUG might contain manually set * bits like UB or ED, which should be preserved. */ CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, &value)); value |= SET_CORE_SINGLE_INSTR_STEP; /* set the IS bit */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, value)); LOG_DEBUG("core debug step mode enabled [debug-reg:0x%08" PRIx32 "]", value); } else { /* disable core debug step mode */ CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, &value)); value &= ~SET_CORE_SINGLE_INSTR_STEP; /* clear the IS bit */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, value)); LOG_DEBUG("core debug step mode disabled"); } return ERROR_OK; } 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 arc_common *arc = target_to_arc(target); struct breakpoint *breakpoint = NULL; struct reg *pc = &(arc->core_and_aux_cache->reg_list[arc->pc_index_in_cache]); if (target->state != TARGET_HALTED) { LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } /* current = 1: continue on current pc, otherwise continue at
*/ if (!current) { buf_set_u32(pc->value, 0, 32, address); pc->dirty = true; pc->valid = true; } LOG_DEBUG("Target steps one instruction from PC=0x%" PRIx32, buf_get_u32(pc->value, 0, 32)); /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { breakpoint = breakpoint_find(target, buf_get_u32(pc->value, 0, 32)); if (breakpoint) CHECK_RETVAL(arc_unset_breakpoint(target, breakpoint)); } /* restore context */ CHECK_RETVAL(arc_restore_context(target)); target->debug_reason = DBG_REASON_SINGLESTEP; CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED)); /* disable interrupts while stepping */ CHECK_RETVAL(arc_enable_interrupts(target, 0)); /* do a single step */ CHECK_RETVAL(arc_config_step(target, 1)); /* make sure we done our step */ alive_sleep(1); /* registers are now invalid */ register_cache_invalidate(arc->core_and_aux_cache); if (breakpoint) CHECK_RETVAL(arc_set_breakpoint(target, breakpoint)); LOG_DEBUG("target stepped "); target->state = TARGET_HALTED; /* Saving context */ CHECK_RETVAL(arc_debug_entry(target)); CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED)); return ERROR_OK; } /* This function invalidates icache. */ static int arc_icache_invalidate(struct target *target) { uint32_t value; struct arc_common *arc = target_to_arc(target); /* Don't waste time if already done. */ if (!arc->has_icache || arc->icache_invalidated) return ERROR_OK; LOG_DEBUG("Invalidating I$."); value = IC_IVIC_INVALIDATE; /* invalidate I$ */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_IC_IVIC_REG, value)); arc->icache_invalidated = true; return ERROR_OK; } /* This function invalidates dcache */ static int arc_dcache_invalidate(struct target *target) { uint32_t value, dc_ctrl_value; struct arc_common *arc = target_to_arc(target); if (!arc->has_dcache || arc->dcache_invalidated) return ERROR_OK; LOG_DEBUG("Invalidating D$."); CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_DC_CTRL_REG, &value)); dc_ctrl_value = value; value &= ~DC_CTRL_IM; /* set DC_CTRL invalidate mode to invalidate-only (no flushing!!) */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DC_CTRL_REG, value)); value = DC_IVDC_INVALIDATE; /* invalidate D$ */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DC_IVDC_REG, value)); /* restore DC_CTRL invalidate mode */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DC_CTRL_REG, dc_ctrl_value)); arc->dcache_invalidated = true; return ERROR_OK; } /* This function invalidates l2 cache. */ static int arc_l2cache_invalidate(struct target *target) { uint32_t value, slc_ctrl_value; struct arc_common *arc = target_to_arc(target); if (!arc->has_l2cache || arc->l2cache_invalidated) return ERROR_OK; LOG_DEBUG("Invalidating L2$."); CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, SLC_AUX_CACHE_CTRL, &value)); slc_ctrl_value = value; value &= ~L2_CTRL_IM; /* set L2_CTRL invalidate mode to invalidate-only (no flushing!!) */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, SLC_AUX_CACHE_CTRL, value)); /* invalidate L2$ */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, SLC_AUX_CACHE_INV, L2_INV_IV)); /* Wait until invalidate operation ends */ do { LOG_DEBUG("Waiting for invalidation end."); CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, SLC_AUX_CACHE_CTRL, &value)); } while (value & L2_CTRL_BS); /* restore L2_CTRL invalidate mode */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, SLC_AUX_CACHE_CTRL, slc_ctrl_value)); arc->l2cache_invalidated = true; return ERROR_OK; } int arc_cache_invalidate(struct target *target) { CHECK_RETVAL(arc_icache_invalidate(target)); CHECK_RETVAL(arc_dcache_invalidate(target)); CHECK_RETVAL(arc_l2cache_invalidate(target)); return ERROR_OK; } /* Flush data cache. This function is cheap to call and return quickly if D$ * already has been flushed since target had been halted. JTAG debugger reads * values directly from memory, bypassing cache, so if there are unflushed * lines debugger will read invalid values, which will cause a lot of troubles. * */ static int arc_dcache_flush(struct target *target) { uint32_t value, dc_ctrl_value; bool has_to_set_dc_ctrl_im; struct arc_common *arc = target_to_arc(target); /* Don't waste time if already done. */ if (!arc->has_dcache || arc->dcache_flushed) return ERROR_OK; LOG_DEBUG("Flushing D$."); /* Store current value of DC_CTRL */ CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_DC_CTRL_REG, &dc_ctrl_value)); /* Set DC_CTRL invalidate mode to flush (if not already set) */ has_to_set_dc_ctrl_im = (dc_ctrl_value & DC_CTRL_IM) == 0; if (has_to_set_dc_ctrl_im) { value = dc_ctrl_value | DC_CTRL_IM; CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DC_CTRL_REG, value)); } /* Flush D$ */ value = DC_IVDC_INVALIDATE; CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DC_IVDC_REG, value)); /* Restore DC_CTRL invalidate mode (even of flush failed) */ if (has_to_set_dc_ctrl_im) CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DC_CTRL_REG, dc_ctrl_value)); arc->dcache_flushed = true; return ERROR_OK; } /* This function flushes l2cache. */ static int arc_l2cache_flush(struct target *target) { uint32_t value; struct arc_common *arc = target_to_arc(target); /* Don't waste time if already done. */ if (!arc->has_l2cache || arc->l2cache_flushed) return ERROR_OK; LOG_DEBUG("Flushing L2$."); /* Flush L2 cache */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, SLC_AUX_CACHE_FLUSH, L2_FLUSH_FL)); /* Wait until flush operation ends */ do { LOG_DEBUG("Waiting for flushing end."); CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, SLC_AUX_CACHE_CTRL, &value)); } while (value & L2_CTRL_BS); arc->l2cache_flushed = true; return ERROR_OK; } int arc_cache_flush(struct target *target) { CHECK_RETVAL(arc_dcache_flush(target)); CHECK_RETVAL(arc_l2cache_flush(target)); return ERROR_OK; } /* ARC v2 target */ struct target_type arcv2_target = { .name = "arcv2", .poll = arc_poll, .arch_state = arc_arch_state, /* TODO That seems like something similar to metaware hostlink, so perhaps * we can exploit this in the future. */ .target_request_data = NULL, .halt = arc_halt, .resume = arc_resume, .step = arc_step, .assert_reset = arc_assert_reset, .deassert_reset = arc_deassert_reset, /* TODO Implement soft_reset_halt */ .soft_reset_halt = NULL, .get_gdb_reg_list = arc_get_gdb_reg_list, .read_memory = arc_mem_read, .write_memory = arc_mem_write, .checksum_memory = NULL, .blank_check_memory = NULL, .add_breakpoint = arc_add_breakpoint, .add_context_breakpoint = NULL, .add_hybrid_breakpoint = NULL, .remove_breakpoint = arc_remove_breakpoint, .add_watchpoint = arc_add_watchpoint, .remove_watchpoint = arc_remove_watchpoint, .hit_watchpoint = arc_hit_watchpoint, .run_algorithm = NULL, .start_algorithm = NULL, .wait_algorithm = NULL, .commands = arc_monitor_command_handlers, .target_create = arc_target_create, .init_target = arc_init_target, .deinit_target = arc_deinit_target, .examine = arc_examine, .virt2phys = NULL, .read_phys_memory = NULL, .write_phys_memory = NULL, .mmu = NULL, };