Introduce ARCv2 architecture related code 32/5332/13
authorEvgeniy Didin <didin@synopsys.com>
Mon, 27 Jan 2020 12:22:27 +0000 (15:22 +0300)
committerOleksij Rempel <linux@rempel-privat.de>
Thu, 27 Feb 2020 06:46:51 +0000 (06:46 +0000)
This patch is an initial bump of ARC-specific code
which implements the ARCv2 target(EMSK board) initializing
routine and some basic remote connection/load/continue
functionality.

Changes:
03.12.2019:
-Add return value checks.
-Using static code analizer next fixes were made:
        Mem leak in functions:
                arc_jtag_read_memory,arc_jtag_read_memory,
                arc_jtag_write_registers, arc_jtag_read_registers,
                jim_arc_add_reg_type_flags, jim_arc_add_reg_type_struct,
                arc_build_reg_cache, arc_mem_read.
        Dead code in "arc_mem_read";
        In arc_save_context, arc_restore_context correct arguments
        in"memset" calls.
        In "build_bcr_reg_cache", "arc_build_reg_cache" check
        if list is not empty.

29.12.2019
-Moved code from arc_v2.c to arc.c
-Added checks of the result of calloc/malloc calls
-Reworked arc_cmd.c: replaced spagetty code with functions
-Moved to one style in if statements - to "if(!bla)"
-Changed Licence headers

22.01.2020
-Removed unused variables in arc_common
-Renamed register operation functions
-Introduced arc_deinit_target function
-Fixed interrupt handling in halt/resume:
        * add irq_state field in arc_common
        * fix irq enable/disable calls ( now STATUS32 register is used)
-Switched from buf_set(get)_us32() usage to target_buffer_set(get)_u32()
-Made some cleanup

30.01.2020
-Removed redundant arc_register struct, moved target link to arc_reg_desc
-Introduced link to BCR reg cache in arc_common for freeing memory.
-Now arc_deinit_target frees all arc-related allocated memory.
Valgrind shows no memory leaks.
-Inroduced arch description in arc.c

01.02.2020
-Remove small memory allocations in arc_init_reg. Instead created reg_value
and feature fields in arc_reg_desc.
-Add return value for arc_init_reg() func.
-Replaced some integer constants(61,62,63) with defines.
-Removed redundant conversions in arc_reg_get_field().
-Moved iccm/dccm configuration code from arc_configure()
to separate functions.

19.02.2020
-Change sizeof(struct) to sizeof(*ptr) in allocations
-Changed if/while(ptr != NULL) to if/while(ptr)
-Removed unused variables from struct arc_jtag
-Add additional structs to arc_reg_data_type
 to reduce amount of memory allocations calls
 and simplifying memory freeing.
-Add helper arc_reg_bitfield_t struct which includes
 reg_data_type_bitfield object and char[] name. Reduces
 memory allocations calls.
-Add limit for reg_type/reg_type_field names(20 symbols).
-Add in jim_arc_add_reg_type*() functions additional
 argnument checks(amount of field/name size).
-In jim_arc_add_reg_type*() reduced amount of memory allocations.
-Cleanup of jim_arc_add_reg_type*() functions.
-For commands update ".usage" fields according docopt.
-Cleanup in arc_jtag.c
-Renamed functions which require jtag_exeutre_queue() to arc_jtag_enque_*()
-Add arc_jtag_enque_register_rw() function, which r/w to jtag ir/dr regs
 during regiter r/w.

24.02:
-Change include guards in arc* files according coding style
-Remove _t suffix in struct arc_reg_bitfield_t
-Some cleanup

Change-Id: I6ab0e82b12e6ddb683c9d13dfb7dd6f49a30cb9f
Signed-off-by: Evgeniy Didin <didin@synopsys.com>
Cc: Alexey Brodkin <abrodkin@synopsys.com>
Reviewed-on: http://openocd.zylin.com/5332
Tested-by: jenkins
Reviewed-by: Oleksij Rempel <linux@rempel-privat.de>
src/target/Makefile.am
src/target/arc.c [new file with mode: 0644]
src/target/arc.h [new file with mode: 0644]
src/target/arc_cmd.c [new file with mode: 0644]
src/target/arc_cmd.h [new file with mode: 0644]
src/target/arc_jtag.c [new file with mode: 0644]
src/target/arc_jtag.h [new file with mode: 0644]
src/target/arc_mem.c [new file with mode: 0644]
src/target/arc_mem.h [new file with mode: 0644]
src/target/target.c

index 5a16def55bcc923005c05f49b326ed2c092ad60f..30d2339bf4994ac55c6926b25d223487dca0d692 100644 (file)
@@ -24,6 +24,7 @@ noinst_LTLIBRARIES += %D%/libtarget.la
        $(STM8_SRC) \
        $(INTEL_IA32_SRC) \
        $(ESIRISC_SRC) \
        $(STM8_SRC) \
        $(INTEL_IA32_SRC) \
        $(ESIRISC_SRC) \
+        $(ARC_SRC) \
        %D%/avrt.c \
        %D%/dsp563xx.c \
        %D%/dsp563xx_once.c \
        %D%/avrt.c \
        %D%/dsp563xx.c \
        %D%/dsp563xx_once.c \
@@ -156,6 +157,12 @@ ESIRISC_SRC = \
        %D%/esirisc_jtag.c \
        %D%/esirisc_trace.c
 
        %D%/esirisc_jtag.c \
        %D%/esirisc_trace.c
 
+ARC_SRC = \
+        %D%/arc.c \
+        %D%/arc_cmd.c \
+        %D%/arc_jtag.c \
+        %D%/arc_mem.c
+
 %C%_libtarget_la_SOURCES += \
        %D%/algorithm.h \
        %D%/arm.h \
 %C%_libtarget_la_SOURCES += \
        %D%/algorithm.h \
        %D%/arm.h \
@@ -243,7 +250,11 @@ ESIRISC_SRC = \
        %D%/esirisc.h \
        %D%/esirisc_jtag.h \
        %D%/esirisc_regs.h \
        %D%/esirisc.h \
        %D%/esirisc_jtag.h \
        %D%/esirisc_regs.h \
-       %D%/esirisc_trace.h
+       %D%/esirisc_trace.h \
+       %D%/arc.h \
+       %D%/arc_cmd.h \
+       %D%/arc_jtag.h \
+       %D%/arc_mem.h
 
 include %D%/openrisc/Makefile.am
 include %D%/riscv/Makefile.am
 
 include %D%/openrisc/Makefile.am
 include %D%/riscv/Makefile.am
diff --git a/src/target/arc.c b/src/target/arc.c
new file mode 100644 (file)
index 0000000..45ef725
--- /dev/null
@@ -0,0 +1,1339 @@
+/***************************************************************************
+ *   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                             *
+ ***************************************************************************/
+
+
+#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 regiters 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.
+ */
+
+
+
+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;
+}
+
+
+/* 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;
+       }
+
+       /* 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%x, 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 == CORE_R61_NUM || desc->arch_num == CORE_R62_NUM) {
+                       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 == CORE_R61_NUM ||
+                       desc->arch_num == CORE_R62_NUM)) {
+               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;
+}
+
+const struct reg_arch_type arc_reg_type = {
+       .get = arc_get_register,
+       .set = arc_set_register,
+};
+
+/* GDB register groups. For now we suport 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 = &reg_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, &reg_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, &reg_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, &reg_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] =  &reg_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] =  &reg_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' doens'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 endiannes-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;
+}
+
+
+/* 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_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;
+                       core_cnt += 1;
+               }
+       }
+
+       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;
+                       aux_cnt += 1;
+               }
+       }
+
+       /* 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) {
+                       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) {
+                       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]);
+                       core_cnt += 1;
+                       reg->valid = true;
+                       reg->dirty = false;
+                       LOG_DEBUG("Get core register regnum=%" PRIu32 ", name=%s, value=0x%08" PRIx32,
+                               i, arc_reg->name, core_values[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]);
+                       aux_cnt += 1;
+                       reg->valid = true;
+                       reg->dirty = false;
+                       LOG_DEBUG("Get aux register regnum=%" PRIu32 ", name=%s, value=0x%08" PRIx32,
+                               i , arc_reg->name, aux_values[aux_cnt]);
+               }
+       }
+
+exit:
+       free(core_values);
+       free(core_addrs);
+       free(aux_values);
+       free(aux_addrs);
+
+       return retval;
+}
+
+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 {
+               /* TODO: Add Actionpoint check when AP support will be introduced*/
+               LOG_WARNING("Unknown debug reason");
+       }
+
+       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_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.");
+                       target->state = TARGET_HALTED;
+                       CHECK_RETVAL(arc_debug_entry(target));
+                       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 (ERROR_OK != retval) {
+                       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) {
+                       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(not supported yet):%i,"
+               " debug_execution:%i", current, address, handle_breakpoints, debug_execution);
+
+       if (target->state != TARGET_HALTED) {
+               LOG_WARNING("target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* 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;
+               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 == 1) && (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));
+       }
+
+       /* 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->data_type.reg_type_struct->fields);
+                       free(type->bitfields);
+                       free(type);
+               }       else if (type->data_type.type_class == REG_TYPE_CLASS_FLAGS) {
+                       free(type->data_type.reg_type_flags->fields);
+                       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);
+}
+
+
+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;
+}
+
+
+/* ARC v2 target */
+struct target_type arcv2_target = {
+       .name = "arcv2",
+
+       .poll = arc_poll,
+
+       .arch_state = arc_arch_state,
+
+       /* TODO That seems like something similiar to metaware hostlink, so perhaps
+        * we can exploit this in the future. */
+       .target_request_data = NULL,
+
+       .halt = arc_halt,
+       .resume = arc_resume,
+       .step = NULL,
+
+       .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 = NULL,
+       .add_context_breakpoint = NULL,
+       .add_hybrid_breakpoint = NULL,
+       .remove_breakpoint = NULL,
+       .add_watchpoint = NULL,
+       .remove_watchpoint = NULL,
+       .hit_watchpoint = NULL,
+
+       .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,
+};
diff --git a/src/target/arc.h b/src/target/arc.h
new file mode 100644 (file)
index 0000000..311648e
--- /dev/null
@@ -0,0 +1,212 @@
+/***************************************************************************
+ *   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                             *
+ ***************************************************************************/
+
+#ifndef OPENOCD_TARGET_ARC_H
+#define OPENOCD_TARGET_ARC_H
+
+#include <helper/time_support.h>
+#include <jtag/jtag.h>
+
+#include "algorithm.h"
+#include "breakpoints.h"
+#include "jtag/interface.h"
+#include "register.h"
+#include "target.h"
+#include "target_request.h"
+#include "target_type.h"
+#include "helper/bits.h"
+
+#include "arc_jtag.h"
+#include "arc_cmd.h"
+#include "arc_mem.h"
+
+#define ARC_COMMON_MAGIC       0xB32EB324  /* just a unique number */
+
+#define AUX_DEBUG_REG                   0x5
+#define AUX_PC_REG                      0x6
+#define AUX_STATUS32_REG                0xA
+
+#define SET_CORE_FORCE_HALT             BIT(1)
+#define SET_CORE_HALT_BIT               BIT(0)      /* STATUS32[0] = H field */
+#define SET_CORE_ENABLE_INTERRUPTS                     BIT(31)
+
+#define AUX_STATUS32_REG_HALT_BIT       BIT(0)
+#define AUX_STATUS32_REG_IE_BIT         BIT(31)    /* STATUS32[31] = IE field */
+
+/* Reserved core registers */
+#define CORE_R61_NUM                   (61)
+#define CORE_R62_NUM                   (62)
+
+#define CORE_REG_MAX_NUMBER            (63)
+
+/* Limit reg_type/reg_type_field  name to 20 symbols */
+#define REG_TYPE_MAX_NAME_LENGTH       20
+
+struct arc_reg_bitfield {
+       struct reg_data_type_bitfield bitfield;
+       char name[REG_TYPE_MAX_NAME_LENGTH];
+};
+/* Register data type */
+struct arc_reg_data_type {
+       struct list_head list;
+       struct reg_data_type data_type;
+       struct reg_data_type_flags data_type_flags;
+       struct reg_data_type_struct data_type_struct;
+       char data_type_id[REG_TYPE_MAX_NAME_LENGTH];
+       struct arc_reg_bitfield *bitfields;
+};
+
+
+
+/* Standard GDB register types */
+static const struct reg_data_type standard_gdb_types[] = {
+       { .type = REG_TYPE_INT,         .id = "int" },
+       { .type = REG_TYPE_INT8,        .id = "int8" },
+       { .type = REG_TYPE_INT16,       .id = "int16" },
+       { .type = REG_TYPE_INT32,       .id = "int32" },
+       { .type = REG_TYPE_INT64,       .id = "int64" },
+       { .type = REG_TYPE_INT128,      .id = "int128" },
+       { .type = REG_TYPE_UINT8,       .id = "uint8" },
+       { .type = REG_TYPE_UINT16,      .id = "uint16" },
+       { .type = REG_TYPE_UINT32,      .id = "uint32" },
+       { .type = REG_TYPE_UINT64,      .id = "uint64" },
+       { .type = REG_TYPE_UINT128,     .id = "uint128" },
+       { .type = REG_TYPE_CODE_PTR,    .id = "code_ptr" },
+       { .type = REG_TYPE_DATA_PTR,    .id = "data_ptr" },
+       { .type = REG_TYPE_FLOAT,       .id = "float" },
+       { .type = REG_TYPE_IEEE_SINGLE, .id = "ieee_single" },
+       { .type = REG_TYPE_IEEE_DOUBLE, .id = "ieee_double" },
+};
+
+
+struct arc_common {
+       uint32_t common_magic;
+
+       struct arc_jtag jtag_info;
+
+       struct reg_cache *core_and_aux_cache;
+       struct reg_cache *bcr_cache;
+
+       /* Indicate if cach was built (for deinit function) */
+       bool core_aux_cache_built;
+       bool bcr_cache_built;
+       /* Closely Coupled memory(CCM) regions for performance-critical
+        * code (optional). */
+       uint32_t iccm0_start;
+       uint32_t iccm0_end;
+       uint32_t iccm1_start;
+       uint32_t iccm1_end;
+       uint32_t dccm_start;
+       uint32_t dccm_end;
+
+       int irq_state;
+
+       /* Register descriptions */
+       struct list_head reg_data_types;
+       struct list_head core_reg_descriptions;
+       struct list_head aux_reg_descriptions;
+       struct list_head bcr_reg_descriptions;
+       unsigned long num_regs;
+       unsigned long num_core_regs;
+       unsigned long num_aux_regs;
+       unsigned long num_bcr_regs;
+       unsigned long last_general_reg;
+
+       /* PC register location in register cache. */
+       unsigned long pc_index_in_cache;
+       /* DEBUG register location in register cache. */
+       unsigned long debug_index_in_cache;
+};
+
+/* Borrowed from nds32.h */
+#define CHECK_RETVAL(action)                   \
+       do {                                    \
+               int __retval = (action);        \
+               if (__retval != ERROR_OK) {     \
+                       LOG_DEBUG("error while calling \"%s\"", \
+                               # action);     \
+                       return __retval;        \
+               }                               \
+       } while (0)
+
+#define JIM_CHECK_RETVAL(action)               \
+       do {                                    \
+               int __retval = (action);        \
+               if (__retval != JIM_OK) {       \
+                       LOG_DEBUG("error while calling \"%s\"", \
+                               # action);     \
+                       return __retval;        \
+               }                               \
+       } while (0)
+
+static inline struct arc_common *target_to_arc(struct target *target)
+{
+       return target->arch_info;
+}
+
+
+/* ARC Register description */
+struct arc_reg_desc {
+
+       struct target *target;
+
+       /* Register name */
+       char *name;
+
+       /* Actual place of storing reg_value */
+       uint8_t reg_value[4];
+
+       /* Actual place of storing register feature */
+       struct reg_feature feature;
+
+       /* GDB XML feature */
+       char *gdb_xml_feature;
+
+       /* Is this a register in g/G-packet? */
+       bool is_general;
+
+       /* Architectural number: core reg num or AUX reg num */
+       uint32_t arch_num;
+
+       /* Core or AUX register? */
+       bool is_core;
+
+       /* Build configuration register? */
+       bool is_bcr;
+
+       /* Data type */
+       struct reg_data_type *data_type;
+
+       struct list_head list;
+};
+
+/* Error codes */
+#define ERROR_ARC_REGISTER_NOT_FOUND       (-700)
+#define ERROR_ARC_REGISTER_FIELD_NOT_FOUND (-701)
+#define ERROR_ARC_REGISTER_IS_NOT_STRUCT   (-702)
+#define ERROR_ARC_FIELD_IS_NOT_BITFIELD    (-703)
+#define ERROR_ARC_REGTYPE_NOT_FOUND        (-704)
+
+void free_reg_desc(struct arc_reg_desc *r);
+
+
+void arc_reg_data_type_add(struct target *target,
+               struct arc_reg_data_type *data_type);
+
+int arc_reg_add(struct target *target, struct arc_reg_desc *arc_reg,
+               const char * const type_name, const size_t type_name_len);
+
+struct reg *arc_reg_get_by_name(struct reg_cache *first,
+                                       const char *name, bool search_all);
+
+int arc_reg_get_field(struct target *target, const char *reg_name,
+               const char *field_name, uint32_t *value_ptr);
+
+#endif /* OPENOCD_TARGET_ARC_H */
diff --git a/src/target/arc_cmd.c b/src/target/arc_cmd.c
new file mode 100644 (file)
index 0000000..3f6caf7
--- /dev/null
@@ -0,0 +1,977 @@
+/***************************************************************************
+ *   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                             *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "arc.h"
+
+/* --------------------------------------------------------------------------
+ *
+ *   ARC targets expose command interface.
+ *   It can be accessed via GDB through the (gdb) monitor command.
+ *
+ * ------------------------------------------------------------------------- */
+
+
+static int arc_cmd_jim_get_uint32(Jim_GetOptInfo *goi, uint32_t *value)
+{
+       jim_wide value_wide;
+       JIM_CHECK_RETVAL(Jim_GetOpt_Wide(goi, &value_wide));
+       *value = (uint32_t)value_wide;
+       return JIM_OK;
+}
+
+enum add_reg_types {
+       CFG_ADD_REG_TYPE_FLAG,
+       CFG_ADD_REG_TYPE_STRUCT,
+};
+/* Add flags register data type */
+enum add_reg_type_flags {
+       CFG_ADD_REG_TYPE_FLAGS_NAME,
+       CFG_ADD_REG_TYPE_FLAGS_FLAG,
+};
+
+static Jim_Nvp nvp_add_reg_type_flags_opts[] = {
+       { .name = "-name",  .value = CFG_ADD_REG_TYPE_FLAGS_NAME },
+       { .name = "-flag",  .value = CFG_ADD_REG_TYPE_FLAGS_FLAG },
+       { .name = NULL,     .value = -1 }
+};
+
+/* Helper function to check if all field required for register
+ * are set up */
+static const char *validate_register(const struct arc_reg_desc * const reg, bool arch_num_set)
+{
+       /* Check that required fields are set */
+       if (!reg->name)
+               return "-name option is required";
+       if (!reg->gdb_xml_feature)
+               return "-feature option is required";
+       if (!arch_num_set)
+               return "-num option is required";
+       if (reg->is_bcr && reg->is_core)
+               return "Register cannot be both -core and -bcr.";
+       return NULL;
+}
+
+/* Helper function to read the name of register type or register from
+ * configure files  */
+static int jim_arc_read_reg_name_field(Jim_GetOptInfo *goi,
+       const char **name, int *name_len)
+{
+       int e = JIM_OK;
+
+       if (!goi->argc) {
+               Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-name <name> ...");
+               return JIM_ERR;
+       }
+       e = Jim_GetOpt_String(goi, name, name_len);
+       return e;
+}
+
+/* Helper function to read bitfields/flags of register type. */
+static int jim_arc_read_reg_type_field(Jim_GetOptInfo *goi, const char **field_name, int *field_name_len,
+        struct arc_reg_bitfield *bitfields, int cur_field, int type)
+{
+               jim_wide start_pos, end_pos;
+
+               int e = JIM_OK;
+               if ((type == CFG_ADD_REG_TYPE_STRUCT && goi->argc < 3) ||
+                (type == CFG_ADD_REG_TYPE_FLAG && goi->argc < 2)) {
+                       Jim_SetResultFormatted(goi->interp, "Not enough argmunets after -flag/-bitfield");
+                       return JIM_ERR;
+               }
+
+               e = Jim_GetOpt_String(goi, field_name, field_name_len);
+               if (e != JIM_OK)
+                                       return e;
+
+               /* read start position of bitfield/flag */
+               e = Jim_GetOpt_Wide(goi, &start_pos);
+               if (e != JIM_OK)
+                                       return e;
+
+               end_pos = start_pos;
+
+               /* Check if any argnuments remain,
+                * set bitfields[cur_field].end if flag is multibit */
+               if (goi->argc > 0)
+                       /* Check current argv[0], if it is equal to "-flag",
+                        * than bitfields[cur_field].end remains start */
+                       if ((strcmp(Jim_String(goi->argv[0]), "-flag") && type == CFG_ADD_REG_TYPE_FLAG)
+                                       || (type == CFG_ADD_REG_TYPE_STRUCT)) {
+                                                               e = Jim_GetOpt_Wide(goi, &end_pos);
+                                                               if (e != JIM_OK) {
+                                                                       Jim_SetResultFormatted(goi->interp, "Error reading end position");
+                                                                       return e;
+                                                               }
+                                                       }
+
+               bitfields[cur_field].bitfield.start = start_pos;
+               bitfields[cur_field].bitfield.end = end_pos;
+               if ((end_pos != start_pos) || (type == CFG_ADD_REG_TYPE_STRUCT))
+                       bitfields[cur_field].bitfield.type = REG_TYPE_INT;
+       return e;
+}
+
+static int jim_arc_add_reg_type_flags(Jim_Interp *interp, int argc,
+       Jim_Obj * const *argv)
+{
+       Jim_GetOptInfo goi;
+       JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1));
+
+       LOG_DEBUG("-");
+
+       struct command_context *ctx;
+       struct target *target;
+
+       ctx = current_command_context(interp);
+       assert(ctx);
+       target = get_current_target(ctx);
+       if (!target) {
+               Jim_SetResultFormatted(goi.interp, "No current target");
+               return JIM_ERR;
+       }
+
+       int e = JIM_OK;
+
+       /* Check if the amount of argnuments is not zero */
+       if (goi.argc <= 0) {
+               Jim_SetResultFormatted(goi.interp, "The command has no argnuments");
+               return JIM_ERR;
+       }
+
+       /* Estimate number of registers as (argc - 2)/3 as each -flag option has 2
+        * arguments while -name is required. */
+       unsigned int fields_sz = (goi.argc - 2) / 3;
+       unsigned int cur_field = 0;
+
+       /* Tha maximum amount of bitfilds is 32 */
+       if (fields_sz > 32) {
+               Jim_SetResultFormatted(goi.interp, "The amount of bitfields exceed 32");
+               return JIM_ERR;
+       }
+
+       struct arc_reg_data_type *type = calloc(1, sizeof(*type));
+       struct reg_data_type_flags *flags = &type->data_type_flags;
+       struct reg_data_type_flags_field *fields = calloc(fields_sz, sizeof(*fields));
+       struct arc_reg_bitfield *bitfields = calloc(fields_sz, sizeof(*type));
+       if (!(type && fields && bitfields)) {
+               Jim_SetResultFormatted(goi.interp, "Failed to allocate memory.");
+               goto fail;
+       }
+
+       /* Initialize type */
+       type->bitfields = bitfields;
+       type->data_type.id = type->data_type_id;
+       type->data_type.type = REG_TYPE_ARCH_DEFINED;
+       type->data_type.type_class = REG_TYPE_CLASS_FLAGS;
+       type->data_type.reg_type_flags = flags;
+       flags->size = 4; /* For now ARC has only 32-bit registers */
+
+       while (goi.argc > 0 && e == JIM_OK) {
+               Jim_Nvp *n;
+               e = Jim_GetOpt_Nvp(&goi, nvp_add_reg_type_flags_opts, &n);
+               if (e != JIM_OK) {
+                       Jim_GetOpt_NvpUnknown(&goi, nvp_add_reg_type_flags_opts, 0);
+                       continue;
+               }
+
+               switch (n->value) {
+                       case CFG_ADD_REG_TYPE_FLAGS_NAME:
+                       {
+                               const char *name = NULL;
+                               int name_len = 0;
+
+                               e = jim_arc_read_reg_name_field(&goi, &name, &name_len);
+                               if (e != JIM_OK) {
+                                       Jim_SetResultFormatted(goi.interp, "Unable to read reg name.");
+                                       goto fail;
+                               }
+
+                               if (name_len > REG_TYPE_MAX_NAME_LENGTH) {
+                                       Jim_SetResultFormatted(goi.interp, "Reg type name is too big.");
+                                       goto fail;
+                               }
+
+                               strncpy((void *)type->data_type.id, name, name_len);
+                               if (!type->data_type.id) {
+                                       Jim_SetResultFormatted(goi.interp, "Unable to setup reg type name.");
+                                       goto fail;
+                               }
+
+                               break;
+                       }
+
+                       case CFG_ADD_REG_TYPE_FLAGS_FLAG:
+                       {
+                               const char *field_name = NULL;
+                               int field_name_len = 0;
+
+                               e = jim_arc_read_reg_type_field(&goi, &field_name, &field_name_len, bitfields,
+                                                                       cur_field, CFG_ADD_REG_TYPE_FLAG);
+                               if (e != JIM_OK) {
+                                       Jim_SetResultFormatted(goi.interp, "Unable to add reg_type_flag field.");
+                                       goto fail;
+                               }
+
+                               if (field_name_len > REG_TYPE_MAX_NAME_LENGTH) {
+                                       Jim_SetResultFormatted(goi.interp, "Reg type field_name_len is too big.");
+                                       goto fail;
+                               }
+
+                               fields[cur_field].name = bitfields[cur_field].name;
+                               strncpy(bitfields[cur_field].name, field_name, field_name_len);
+                               if (!fields[cur_field].name) {
+                                       Jim_SetResultFormatted(goi.interp, "Unable to setup field name. ");
+                                       goto fail;
+                               }
+
+                               fields[cur_field].bitfield = &(bitfields[cur_field].bitfield);
+                               if (cur_field > 0)
+                                       fields[cur_field - 1].next = &(fields[cur_field]);
+                               else
+                                       flags->fields = fields;
+
+                               cur_field += 1;
+                               break;
+                       }
+               }
+       }
+
+       if (!type->data_type.id) {
+               Jim_SetResultFormatted(goi.interp, "-name is a required option");
+               goto fail;
+       }
+
+       arc_reg_data_type_add(target, type);
+
+       LOG_DEBUG("added flags type {name=%s}", type->data_type.id);
+
+       return JIM_OK;
+fail:
+       free(type);
+       free(fields);
+       free(bitfields);
+
+       return JIM_ERR;
+}
+
+/* Add struct register data type */
+enum add_reg_type_struct {
+       CFG_ADD_REG_TYPE_STRUCT_NAME,
+       CFG_ADD_REG_TYPE_STRUCT_BITFIELD,
+};
+
+static Jim_Nvp nvp_add_reg_type_struct_opts[] = {
+       { .name = "-name",     .value = CFG_ADD_REG_TYPE_STRUCT_NAME },
+       { .name = "-bitfield", .value = CFG_ADD_REG_TYPE_STRUCT_BITFIELD },
+       { .name = NULL,     .value = -1 }
+};
+
+static int jim_arc_set_aux_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+{
+
+       struct command_context *context;
+       struct target *target;
+       uint32_t regnum;
+       uint32_t value;
+
+       Jim_GetOptInfo goi;
+       JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1));
+
+       if (goi.argc != 2) {
+               Jim_SetResultFormatted(goi.interp,
+                       "usage: %s <aux_reg_num> <aux_reg_value>", Jim_GetString(argv[0], NULL));
+               return JIM_ERR;
+       }
+
+       context = current_command_context(interp);
+       assert(context);
+
+       target = get_current_target(context);
+       if (!target) {
+               Jim_SetResultFormatted(goi.interp, "No current target");
+               return JIM_ERR;
+       }
+
+       /* Register number */
+       JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, &regnum));
+
+       /* Register value */
+       JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, &value));
+
+       struct arc_common *arc = target_to_arc(target);
+       assert(arc);
+
+       CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, regnum, value));
+
+       return ERROR_OK;
+}
+
+static int jim_arc_get_aux_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+{
+       struct command_context *context;
+       struct target *target;
+       uint32_t regnum;
+       uint32_t value;
+
+       Jim_GetOptInfo goi;
+       JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1));
+
+       if (goi.argc != 1) {
+               Jim_SetResultFormatted(goi.interp,
+                       "usage: %s <aux_reg_num>", Jim_GetString(argv[0], NULL));
+               return JIM_ERR;
+       }
+
+       context = current_command_context(interp);
+       assert(context);
+
+       target = get_current_target(context);
+       if (!target) {
+               Jim_SetResultFormatted(goi.interp, "No current target");
+               return JIM_ERR;
+       }
+
+       /* Register number */
+       JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, &regnum));
+
+       struct arc_common *arc = target_to_arc(target);
+       assert(arc);
+
+       CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, regnum, &value));
+       Jim_SetResultInt(interp, value);
+
+       return ERROR_OK;
+}
+
+static int jim_arc_get_core_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+{
+       struct command_context *context;
+       struct target *target;
+       uint32_t regnum;
+       uint32_t value;
+
+       Jim_GetOptInfo goi;
+       JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1));
+
+       if (goi.argc != 1) {
+               Jim_SetResultFormatted(goi.interp,
+                       "usage: %s <core_reg_num>", Jim_GetString(argv[0], NULL));
+               return JIM_ERR;
+       }
+
+       context = current_command_context(interp);
+       assert(context);
+
+       target = get_current_target(context);
+       if (!target) {
+               Jim_SetResultFormatted(goi.interp, "No current target");
+               return JIM_ERR;
+       }
+
+       /* Register number */
+       JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, &regnum));
+       if (regnum > CORE_REG_MAX_NUMBER || regnum == CORE_R61_NUM || regnum == CORE_R62_NUM) {
+               Jim_SetResultFormatted(goi.interp, "Core register number %i " \
+                       "is invalid. Must less then 64 and not 61 and 62.", regnum);
+               return JIM_ERR;
+       }
+
+       struct arc_common *arc = target_to_arc(target);
+       assert(arc);
+
+       /* Read value */
+       CHECK_RETVAL(arc_jtag_read_core_reg_one(&arc->jtag_info, regnum, &value));
+       Jim_SetResultInt(interp, value);
+
+       return ERROR_OK;
+}
+
+static int jim_arc_set_core_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+{
+       struct command_context *context;
+       struct target *target;
+       uint32_t regnum;
+       uint32_t value;
+
+       Jim_GetOptInfo goi;
+       JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1));
+
+       if (goi.argc != 2) {
+               Jim_SetResultFormatted(goi.interp,
+                       "usage: %s <core_reg_num> <core_reg_value>", Jim_GetString(argv[0], NULL));
+               return JIM_ERR;
+       }
+
+       context = current_command_context(interp);
+       assert(context);
+
+       target = get_current_target(context);
+       if (!target) {
+               Jim_SetResultFormatted(goi.interp, "No current target");
+               return JIM_ERR;
+       }
+
+       /* Register number */
+       JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, &regnum));
+       if (regnum > CORE_REG_MAX_NUMBER || regnum == CORE_R61_NUM || regnum == CORE_R62_NUM) {
+               Jim_SetResultFormatted(goi.interp, "Core register number %i " \
+                       "is invalid. Must less then 64 and not 61 and 62.", regnum);
+               return JIM_ERR;
+       }
+
+       /* Register value */
+       JIM_CHECK_RETVAL(arc_cmd_jim_get_uint32(&goi, &value));
+
+       struct arc_common *arc = target_to_arc(target);
+       assert(arc);
+
+       CHECK_RETVAL(arc_jtag_write_core_reg_one(&arc->jtag_info, regnum, value));
+
+       return ERROR_OK;
+}
+
+static const struct command_registration arc_jtag_command_group[] = {
+       {
+               .name = "get-aux-reg",
+               .jim_handler = jim_arc_get_aux_reg,
+               .mode = COMMAND_EXEC,
+               .help = "Get AUX register by number. This command does a " \
+                       "raw JTAG request that bypasses OpenOCD register cache "\
+                       "and thus is unsafe and can have unexpected consequences. "\
+                       "Use at your own risk.",
+               .usage = "arc jtag get-aux-reg <regnum>"
+       },
+       {
+               .name = "set-aux-reg",
+               .jim_handler = jim_arc_set_aux_reg,
+               .mode = COMMAND_EXEC,
+               .help = "Set AUX register by number. This command does a " \
+                       "raw JTAG request that bypasses OpenOCD register cache "\
+                       "and thus is unsafe and can have unexpected consequences. "\
+                       "Use at your own risk.",
+               .usage = "arc jtag set-aux-reg <regnum> <value>"
+       },
+       {
+               .name = "get-core-reg",
+               .jim_handler = jim_arc_get_core_reg,
+               .mode = COMMAND_EXEC,
+               .help = "Get/Set core register by number. This command does a " \
+                       "raw JTAG request that bypasses OpenOCD register cache "\
+                       "and thus is unsafe and can have unexpected consequences. "\
+                       "Use at your own risk.",
+               .usage = "arc jtag get-core-reg <regnum> [<value>]"
+       },
+       {
+               .name = "set-core-reg",
+               .jim_handler = jim_arc_set_core_reg,
+               .mode = COMMAND_EXEC,
+               .help = "Get/Set core register by number. This command does a " \
+                       "raw JTAG request that bypasses OpenOCD register cache "\
+                       "and thus is unsafe and can have unexpected consequences. "\
+                       "Use at your own risk.",
+               .usage = "arc jtag set-core-reg <regnum> [<value>]"
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+
+/* This function supports only bitfields. */
+static int jim_arc_add_reg_type_struct(Jim_Interp *interp, int argc,
+       Jim_Obj * const *argv)
+{
+       Jim_GetOptInfo goi;
+       JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1));
+
+       LOG_DEBUG("-");
+
+       struct command_context *ctx;
+       struct target *target;
+
+       ctx = current_command_context(interp);
+       assert(ctx);
+       target = get_current_target(ctx);
+       if (!target) {
+               Jim_SetResultFormatted(goi.interp, "No current target");
+               return JIM_ERR;
+       }
+
+       int e = JIM_OK;
+
+       /* Check if the amount of argnuments is not zero */
+       if (goi.argc <= 0) {
+               Jim_SetResultFormatted(goi.interp, "The command has no argnuments");
+               return JIM_ERR;
+       }
+
+       /* Estimate number of registers as (argc - 2)/4 as each -bitfield option has 3
+        * arguments while -name is required. */
+       unsigned int fields_sz = (goi.argc - 2) / 4;
+       unsigned int cur_field = 0;
+
+       /* Tha maximum amount of bitfilds is 32 */
+       if (fields_sz > 32) {
+                       Jim_SetResultFormatted(goi.interp, "The amount of bitfields exceed 32");
+                       return JIM_ERR;
+       }
+
+       struct arc_reg_data_type *type = calloc(1, sizeof(*type));
+       struct reg_data_type_struct *struct_type = &type->data_type_struct;
+       struct reg_data_type_struct_field *fields = calloc(fields_sz, sizeof(*fields));
+       struct arc_reg_bitfield *bitfields = calloc(fields_sz, sizeof(*type));
+       if (!(type && fields && bitfields)) {
+               Jim_SetResultFormatted(goi.interp, "Failed to allocate memory.");
+               goto fail;
+       }
+
+       /* Initialize type */
+       type->data_type.id = type->data_type_id;
+       type->bitfields = bitfields;
+       type->data_type.type = REG_TYPE_ARCH_DEFINED;
+       type->data_type.type_class = REG_TYPE_CLASS_STRUCT;
+       type->data_type.reg_type_struct = struct_type;
+       struct_type->size = 4; /* For now ARC has only 32-bit registers */
+
+       while (goi.argc > 0 && e == JIM_OK) {
+               Jim_Nvp *n;
+               e = Jim_GetOpt_Nvp(&goi, nvp_add_reg_type_struct_opts, &n);
+               if (e != JIM_OK) {
+                       Jim_GetOpt_NvpUnknown(&goi, nvp_add_reg_type_struct_opts, 0);
+                       continue;
+               }
+
+               switch (n->value) {
+                       case CFG_ADD_REG_TYPE_STRUCT_NAME:
+                       {
+                               const char *name = NULL;
+                               int name_len = 0;
+
+                               e = jim_arc_read_reg_name_field(&goi, &name, &name_len);
+                               if (e != JIM_OK) {
+                                       Jim_SetResultFormatted(goi.interp, "Unable to read reg name.");
+                                       goto fail;
+                               }
+
+                               if (name_len > REG_TYPE_MAX_NAME_LENGTH) {
+                                       Jim_SetResultFormatted(goi.interp, "Reg type name is too big.");
+                                       goto fail;
+                               }
+
+                               strncpy((void *)type->data_type.id, name, name_len);
+                               if (!type->data_type.id) {
+                                       Jim_SetResultFormatted(goi.interp, "Unable to setup reg type name.");
+                                       goto fail;
+                               }
+
+                               break;
+                       }
+                       case CFG_ADD_REG_TYPE_STRUCT_BITFIELD:
+                       {
+                               const char *field_name = NULL;
+                               int field_name_len = 0;
+                               e = jim_arc_read_reg_type_field(&goi, &field_name, &field_name_len, bitfields,
+                                                                       cur_field, CFG_ADD_REG_TYPE_STRUCT);
+                               if (e != JIM_OK) {
+                                       Jim_SetResultFormatted(goi.interp, "Unable to add reg_type_struct field.");
+                                       goto fail;
+                               }
+
+                               if (field_name_len > REG_TYPE_MAX_NAME_LENGTH) {
+                                       Jim_SetResultFormatted(goi.interp, "Reg type field_name_len is too big.");
+                                       goto fail;
+                               }
+
+                               fields[cur_field].name = bitfields[cur_field].name;
+                               strncpy(bitfields[cur_field].name, field_name, field_name_len);
+                               if (!fields[cur_field].name) {
+                                       Jim_SetResultFormatted(goi.interp, "Unable to setup field name. ");
+                                       goto fail;
+                               }
+
+                               fields[cur_field].bitfield = &(bitfields[cur_field].bitfield);
+                               fields[cur_field].use_bitfields = true;
+                               if (cur_field > 0)
+                                       fields[cur_field - 1].next = &(fields[cur_field]);
+                               else
+                                       struct_type->fields = fields;
+
+                               cur_field += 1;
+
+                               break;
+                       }
+               }
+       }
+
+       if (!type->data_type.id) {
+               Jim_SetResultFormatted(goi.interp, "-name is a required option");
+               goto fail;
+       }
+
+       arc_reg_data_type_add(target, type);
+       LOG_DEBUG("added struct type {name=%s}", type->data_type.id);
+       return JIM_OK;
+
+fail:
+                       free(type);
+                       free(fields);
+                       free(bitfields);
+
+                       return JIM_ERR;
+}
+
+/* Add register */
+enum opts_add_reg {
+       CFG_ADD_REG_NAME,
+       CFG_ADD_REG_ARCH_NUM,
+       CFG_ADD_REG_IS_CORE,
+       CFG_ADD_REG_IS_BCR,
+       CFG_ADD_REG_GDB_FEATURE,
+       CFG_ADD_REG_TYPE,
+       CFG_ADD_REG_GENERAL,
+};
+
+static Jim_Nvp opts_nvp_add_reg[] = {
+       { .name = "-name",    .value = CFG_ADD_REG_NAME },
+       { .name = "-num",     .value = CFG_ADD_REG_ARCH_NUM },
+       { .name = "-core",    .value = CFG_ADD_REG_IS_CORE },
+       { .name = "-bcr",     .value = CFG_ADD_REG_IS_BCR },
+       { .name = "-feature", .value = CFG_ADD_REG_GDB_FEATURE },
+       { .name = "-type",    .value = CFG_ADD_REG_TYPE },
+       { .name = "-g",       .value = CFG_ADD_REG_GENERAL },
+       { .name = NULL,       .value = -1 }
+};
+
+void free_reg_desc(struct arc_reg_desc *r)
+{
+       free(r->name);
+       free(r->gdb_xml_feature);
+       free(r);
+}
+
+static int jim_arc_add_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+{
+       Jim_GetOptInfo goi;
+       JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1));
+
+       struct arc_reg_desc *reg = calloc(1, sizeof(*reg));
+       if (!reg) {
+               Jim_SetResultFormatted(goi.interp, "Failed to allocate memory.");
+               return JIM_ERR;
+       }
+
+       /* There is no architecture number that we could treat as invalid, so
+        * separate variable requried to ensure that arch num has been set. */
+       bool arch_num_set = false;
+       const char *type_name = "int"; /* Default type */
+       int type_name_len = strlen(type_name);
+       int e = ERROR_OK;
+
+       /* At least we need to specify 4 parameters: name, number, type and gdb_feature,
+        * which means there should be 8 arguments */
+       if (goi.argc < 8) {
+               free_reg_desc(reg);
+               Jim_SetResultFormatted(goi.interp,
+                       "Should be at least 8 argnuments: -name <name> "
+                       "-num <num> -type <type> -feature <gdb_feature>.");
+               return JIM_ERR;
+       }
+
+       /* Parse options. */
+       while (goi.argc > 0) {
+               Jim_Nvp *n;
+               e = Jim_GetOpt_Nvp(&goi, opts_nvp_add_reg, &n);
+               if (e != JIM_OK) {
+                       Jim_GetOpt_NvpUnknown(&goi, opts_nvp_add_reg, 0);
+                       free_reg_desc(reg);
+                       return e;
+               }
+
+               switch (n->value) {
+                       case CFG_ADD_REG_NAME:
+                       {
+                               const char *reg_name = NULL;
+                               int reg_name_len = 0;
+
+                               e = jim_arc_read_reg_name_field(&goi, &reg_name, &reg_name_len);
+                               if (e != JIM_OK) {
+                                       Jim_SetResultFormatted(goi.interp, "Unable to read register name.");
+                                       free_reg_desc(reg);
+                                       return e;
+                               }
+
+                               reg->name = strndup(reg_name, reg_name_len);
+                               break;
+                       }
+                       case CFG_ADD_REG_IS_CORE:
+                               reg->is_core = true;
+                               break;
+                       case CFG_ADD_REG_IS_BCR:
+                               reg->is_bcr = true;
+                               break;
+                       case CFG_ADD_REG_ARCH_NUM:
+                       {
+                               jim_wide archnum;
+
+                               if (!goi.argc) {
+                                       free_reg_desc(reg);
+                                       Jim_WrongNumArgs(interp, goi.argc, goi.argv, "-num <int> ...");
+                                       return JIM_ERR;
+                               }
+
+                               e = Jim_GetOpt_Wide(&goi, &archnum);
+                               if (e != JIM_OK) {
+                                       free_reg_desc(reg);
+                                       return e;
+                               }
+
+                               reg->arch_num = archnum;
+                               arch_num_set = true;
+                               break;
+                       }
+                       case CFG_ADD_REG_GDB_FEATURE:
+                       {
+                               const char *feature = NULL;
+                               int feature_len = 0;
+
+                               e = jim_arc_read_reg_name_field(&goi, &feature, &feature_len);
+                               if (e != JIM_OK) {
+                                       Jim_SetResultFormatted(goi.interp, "Unable to read gdb_feature.");
+                                       free_reg_desc(reg);
+                                       return e;
+                               }
+
+                               reg->gdb_xml_feature = strndup(feature, feature_len);
+                               break;
+                       }
+                       case CFG_ADD_REG_TYPE:
+                               e = jim_arc_read_reg_name_field(&goi, &type_name, &type_name_len);
+                               if (e != JIM_OK) {
+                                       Jim_SetResultFormatted(goi.interp, "Unable to read register type.");
+                                       free_reg_desc(reg);
+                                       return e;
+                               }
+
+                               break;
+                       case CFG_ADD_REG_GENERAL:
+                               reg->is_general = true;
+                               break;
+                       default:
+                               LOG_DEBUG("Error: Unknown parameter");
+                               free_reg_desc(reg);
+                               return JIM_ERR;
+               }
+       }
+
+       /* Check that required fields are set */
+       const char * const errmsg = validate_register(reg, arch_num_set);
+       if (errmsg) {
+               Jim_SetResultFormatted(goi.interp, errmsg);
+               free_reg_desc(reg);
+               return JIM_ERR;
+       }
+
+       /* Add new register */
+       struct command_context *ctx;
+       struct target *target;
+
+       ctx = current_command_context(interp);
+       assert(ctx);
+       target = get_current_target(ctx);
+       if (!target) {
+               Jim_SetResultFormatted(goi.interp, "No current target");
+               return JIM_ERR;
+       }
+
+       reg->target = target;
+
+       e = arc_reg_add(target, reg, type_name, type_name_len);
+       if (e == ERROR_ARC_REGTYPE_NOT_FOUND) {
+               Jim_SetResultFormatted(goi.interp,
+                       "Cannot find type `%s' for register `%s'.",
+                       type_name, reg->name);
+               free_reg_desc(reg);
+               return JIM_ERR;
+       }
+
+       return e;
+}
+
+/* arc set-reg-exists ($reg_name)+
+ * Accepts any amount of register names - will set them as existing in a loop.*/
+COMMAND_HANDLER(arc_set_reg_exists)
+{
+       struct target * const target = get_current_target(CMD_CTX);
+       if (!target) {
+               command_print(CMD, "Unable to get current target.");
+               return JIM_ERR;
+       }
+
+       if (!CMD_ARGC) {
+               command_print(CMD, "At least one register name must be specified.");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       for (unsigned int i = 0; i < CMD_ARGC; i++) {
+               const char * const reg_name = CMD_ARGV[i];
+               struct reg * const r = arc_reg_get_by_name(target->reg_cache, reg_name, true);
+
+               if (!r) {
+                       command_print(CMD, "Register `%s' is not found.", reg_name);
+                       return ERROR_COMMAND_ARGUMENT_INVALID;
+               }
+
+               r->exist = true;
+       }
+
+       return JIM_OK;
+}
+
+/* arc reg-field  ($reg_name) ($reg_field)
+ * Reads struct type register field */
+static int jim_arc_get_reg_field(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+{
+       Jim_GetOptInfo goi;
+       const char *reg_name, *field_name;
+       uint32_t value;
+       int retval;
+
+       JIM_CHECK_RETVAL(Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1));
+
+       LOG_DEBUG("Reading register field");
+       if (goi.argc != 2) {
+               if (!goi.argc)
+                       Jim_WrongNumArgs(interp, goi.argc, goi.argv, "<regname> <fieldname>");
+               else if (goi.argc == 1)
+                       Jim_WrongNumArgs(interp, goi.argc, goi.argv, "<fieldname>");
+               else
+                       Jim_WrongNumArgs(interp, goi.argc, goi.argv, "<regname> <fieldname>");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       JIM_CHECK_RETVAL(Jim_GetOpt_String(&goi, &reg_name, NULL));
+       JIM_CHECK_RETVAL(Jim_GetOpt_String(&goi, &field_name, NULL));
+       assert(reg_name);
+       assert(field_name);
+
+       struct command_context * const ctx = current_command_context(interp);
+       assert(ctx);
+       struct target * const target = get_current_target(ctx);
+       if (!target) {
+               Jim_SetResultFormatted(goi.interp, "No current target");
+               return JIM_ERR;
+       }
+
+       retval = arc_reg_get_field(target, reg_name, field_name, &value);
+
+       switch (retval) {
+               case ERROR_OK:
+                       break;
+               case ERROR_ARC_REGISTER_NOT_FOUND:
+                       Jim_SetResultFormatted(goi.interp,
+                               "Register `%s' has not been found.", reg_name);
+                       return ERROR_COMMAND_ARGUMENT_INVALID;
+               case ERROR_ARC_REGISTER_IS_NOT_STRUCT:
+                       Jim_SetResultFormatted(goi.interp,
+                               "Register `%s' must have 'struct' type.", reg_name);
+                       return ERROR_COMMAND_ARGUMENT_INVALID;
+               case ERROR_ARC_REGISTER_FIELD_NOT_FOUND:
+                       Jim_SetResultFormatted(goi.interp,
+                               "Field `%s' has not been found in register `%s'.",
+                               field_name, reg_name);
+                       return ERROR_COMMAND_ARGUMENT_INVALID;
+               case ERROR_ARC_FIELD_IS_NOT_BITFIELD:
+                       Jim_SetResultFormatted(goi.interp,
+                               "Field `%s' is not a 'bitfield' field in a structure.",
+                               field_name);
+                       return ERROR_COMMAND_ARGUMENT_INVALID;
+               default:
+                       /* Pass through other errors. */
+                       return retval;
+       }
+
+       Jim_SetResultInt(interp, value);
+
+       return JIM_OK;
+}
+
+/* ----- Exported target commands ------------------------------------------ */
+
+static const struct command_registration arc_core_command_handlers[] = {
+{
+               .name = "add-reg-type-flags",
+               .jim_handler = jim_arc_add_reg_type_flags,
+               .mode = COMMAND_CONFIG,
+               .usage = "arc ardd-reg-type-flags -name <string> -flag <name> <position> "
+                       "[-flag <name> <position>]...",
+               .help = "Add new 'flags' register data type. Only single bit flags "
+                       "are supported. Type name is global. Bitsize of register is fixed "
+                       "at 32 bits.",
+       },
+       {
+               .name = "add-reg-type-struct",
+               .jim_handler = jim_arc_add_reg_type_struct,
+               .mode = COMMAND_CONFIG,
+               .usage = "arc add-reg-type-struct -name <string> -bitfield <name> <start> <end> "
+                       "[-bitfield <name> <start> <end>]...",
+               .help = "Add new 'struct' register data type. Only bit-fields are "
+                       "supported so far, which means that for each bitfield start and end "
+                       "position bits must be specified. GDB also support type-fields, "
+                       "where common type can be used instead. Type name is global. Bitsize of "
+                       "register is fixed at 32 bits.",
+       },
+       {
+               .name = "add-reg",
+               .jim_handler = jim_arc_add_reg,
+               .mode = COMMAND_CONFIG,
+               .usage = "arc add-reg -name <string> -num <int> -feature <string> [-gdbnum <int>] "
+                       "[-core|-bcr] [-type <type_name>] [-g]",
+               .help = "Add new register. Name, architectural number and feature name "
+                       "are requried options. GDB regnum will default to previous register "
+                       "(gdbnum + 1) and shouldn't be specified in most cases. Type "
+                       "defaults to default GDB 'int'.",
+       },
+       {
+               .name = "set-reg-exists",
+               .handler = arc_set_reg_exists,
+               .mode = COMMAND_ANY,
+               .usage = "arc set-reg-exists <register-name> [<register-name>]...",
+               .help = "Set that register exists. Accepts multiple register names as "
+                       "arguments.",
+       },
+       {
+               .name = "get-reg-field",
+               .jim_handler = jim_arc_get_reg_field,
+               .mode = COMMAND_ANY,
+               .usage = "arc get-reg-field <regname> <field_name>",
+               .help = "Returns value of field in a register with 'struct' type.",
+       },
+       {
+               .name = "jtag",
+               .mode = COMMAND_ANY,
+               .help = "ARC JTAG specific commands",
+               .usage = "",
+               .chain = arc_jtag_command_group,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+const struct command_registration arc_monitor_command_handlers[] = {
+       {
+               .name = "arc",
+               .mode = COMMAND_ANY,
+               .help = "ARC monitor command group",
+               .usage = "Help info ...",
+               .chain = arc_core_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
diff --git a/src/target/arc_cmd.h b/src/target/arc_cmd.h
new file mode 100644 (file)
index 0000000..b2264eb
--- /dev/null
@@ -0,0 +1,16 @@
+/***************************************************************************
+ *   Copyright (C) 2013-2014,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                             *
+ ***************************************************************************/
+
+#ifndef OPENOCD_TARGET_ARC_CMD_H
+#define OPENOCD_TARGET_ARC_CMD_H
+
+extern const struct command_registration arc_monitor_command_handlers[];
+
+#endif /* OPENOCD_TARGET_ARC_CMD_H */
diff --git a/src/target/arc_jtag.c b/src/target/arc_jtag.c
new file mode 100644 (file)
index 0000000..dd800a4
--- /dev/null
@@ -0,0 +1,542 @@
+/***************************************************************************
+ *   Copyright (C) 2013-2014,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                             *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "arc.h"
+
+/*
+ * This functions sets instruction register in TAP. TAP end state is always
+ * IRPAUSE.
+ *
+ * @param jtag_info
+ * @param new_instr    Instruction to write to instruction register.
+ */
+static void arc_jtag_enque_write_ir(struct arc_jtag *jtag_info, uint32_t
+               new_instr)
+{
+       uint32_t current_instr;
+       struct jtag_tap *tap;
+       uint8_t instr_buffer[sizeof(uint32_t)];
+
+       assert(jtag_info);
+       assert(jtag_info->tap);
+
+       tap = jtag_info->tap;
+
+       /* Do not set instruction if it is the same as current. */
+       current_instr = buf_get_u32(tap->cur_instr, 0, tap->ir_length);
+       if (current_instr == new_instr)
+               return;
+
+       struct scan_field field = {
+               .num_bits = tap->ir_length,
+               .out_value = instr_buffer
+       };
+       buf_set_u32(instr_buffer, 0, field.num_bits, new_instr);
+
+       /* From code in src/jtag/drivers/driver.c it look like that fields are
+        * copied so it is OK that field in this function is allocated in stack and
+        * thus this memory will be repurposed before jtag_execute_queue() will be
+        * invoked. */
+       jtag_add_ir_scan(tap, &field, TAP_IRPAUSE);
+}
+
+/**
+ * Read 4-byte word from data register.
+ *
+ * Unlike arc_jtag_write_data, this function returns byte-buffer, caller must
+ * convert this data to required format himself. This is done, because it is
+ * impossible to convert data before jtag_execute_queue() is invoked, so it
+ * cannot be done inside this function, so it has to operate with
+ * byte-buffers. Write function on the other hand can "write-and-forget", data
+ * is converted to byte-buffer before jtag_execute_queue().
+ *
+ * @param jtag_info
+ * @param data         Array of bytes to read into.
+ * @param end_state    End state after reading.
+ */
+static void arc_jtag_enque_read_dr(struct arc_jtag *jtag_info, uint8_t *data,
+               tap_state_t end_state)
+{
+
+       assert(jtag_info);
+       assert(jtag_info->tap);
+
+       struct scan_field field = {
+               .num_bits = 32,
+               .in_value = data
+       };
+
+       jtag_add_dr_scan(jtag_info->tap, 1, &field, end_state);
+}
+
+/**
+ * Write 4-byte word to data register.
+ *
+ * @param jtag_info
+ * @param data         4-byte word to write into data register.
+ * @param end_state    End state after writing.
+ */
+static void arc_jtag_enque_write_dr(struct arc_jtag *jtag_info, uint32_t data,
+               tap_state_t end_state)
+{
+       uint8_t out_value[sizeof(uint32_t)];
+
+       assert(jtag_info);
+       assert(jtag_info->tap);
+
+       buf_set_u32(out_value, 0, 32, data);
+
+       struct scan_field field = {
+               .num_bits = 32,
+               .out_value = out_value
+       };
+
+       jtag_add_dr_scan(jtag_info->tap, 1, &field, end_state);
+}
+
+
+/**
+ * Set transaction in command register. This function sets instruction register
+ * and then transaction register, there is no need to invoke write_ir before
+ * invoking this function.
+ *
+ * @param jtag_info
+ * @param new_trans    Transaction to write to transaction command register.
+ * @param end_state    End state after writing.
+ */
+static void arc_jtag_enque_set_transaction(struct arc_jtag *jtag_info,
+               uint32_t new_trans, tap_state_t end_state)
+{
+       uint8_t out_value[sizeof(uint32_t)];
+
+       assert(jtag_info);
+       assert(jtag_info->tap);
+
+       /* No need to do anything. */
+       if (jtag_info->cur_trans == new_trans)
+               return;
+
+       /* Set instruction. We used to call write_ir at upper levels, however
+        * write_ir-write_transaction were constantly in pair, so to avoid code
+        * duplication this function does it self. For this reasons it is "set"
+        * instead of "write". */
+       arc_jtag_enque_write_ir(jtag_info, ARC_TRANSACTION_CMD_REG);
+       buf_set_u32(out_value, 0, ARC_TRANSACTION_CMD_REG_LENGTH, new_trans);
+       struct scan_field field = {
+               .num_bits = ARC_TRANSACTION_CMD_REG_LENGTH,
+               .out_value = out_value
+       };
+
+       jtag_add_dr_scan(jtag_info->tap, 1, &field, end_state);
+       jtag_info->cur_trans = new_trans;
+}
+
+/**
+ * Run reset through transaction set. None of the previous
+ * settings/commands/etc. are used anymore (or no influence).
+ */
+static void arc_jtag_enque_reset_transaction(struct arc_jtag *jtag_info)
+{
+       arc_jtag_enque_set_transaction(jtag_info, ARC_JTAG_CMD_NOP, TAP_IDLE);
+}
+
+static void arc_jtag_enque_status_read(struct arc_jtag * const jtag_info,
+       uint8_t * const buffer)
+{
+       assert(jtag_info);
+       assert(jtag_info->tap);
+       assert(buffer);
+
+  /* first writin code(0x8) of jtag status register in IR */
+       arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_STATUS_REG);
+       /* Now reading dr performs jtag status register read */
+       arc_jtag_enque_read_dr(jtag_info, buffer, TAP_IDLE);
+}
+
+/* ----- Exported JTAG functions ------------------------------------------- */
+
+int arc_jtag_startup(struct arc_jtag *jtag_info)
+{
+       assert(jtag_info);
+
+       arc_jtag_enque_reset_transaction(jtag_info);
+
+       return jtag_execute_queue();
+}
+
+/** Read STATUS register. */
+int arc_jtag_status(struct arc_jtag * const jtag_info, uint32_t * const value)
+{
+       uint8_t buffer[sizeof(uint32_t)];
+
+       assert(jtag_info);
+       assert(jtag_info->tap);
+
+       /* Fill command queue. */
+       arc_jtag_enque_reset_transaction(jtag_info);
+       arc_jtag_enque_status_read(jtag_info, buffer);
+       arc_jtag_enque_reset_transaction(jtag_info);
+
+       /* Execute queue. */
+       CHECK_RETVAL(jtag_execute_queue());
+
+       /* Parse output. */
+       *value = buf_get_u32(buffer, 0, 32);
+
+       return ERROR_OK;
+}
+/* Helper function: Adding read/write register operation to queue */
+static void arc_jtag_enque_register_rw(struct arc_jtag *jtag_info, uint32_t *addr,
+       uint8_t *read_buffer, const uint32_t *write_buffer, uint32_t count)
+{
+       uint32_t i;
+
+       for (i = 0; i < count; i++) {
+               /* ARC jtag has optimization which is to increment ADDRESS_REG performing
+                * each transaction. Making sequential reads/writes we can set address for
+                * only first register in sequence, and than do read/write in cycle. */
+               if (i == 0 || (addr[i] != addr[i-1] + 1)) {
+                       arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_ADDRESS_REG);
+                       /* Going to TAP_IDLE state we initiate jtag transaction.
+                        * Reading data we must go to TAP_IDLE, because further
+                        * the data would be read. In case of write we go to TAP_DRPAUSE,
+                        * because we need to write data to Data register first. */
+                       if (write_buffer)
+                               arc_jtag_enque_write_dr(jtag_info, addr[i], TAP_DRPAUSE);
+                       else
+                               arc_jtag_enque_write_dr(jtag_info, addr[i], TAP_IDLE);
+                       arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_DATA_REG);
+               }
+               if (write_buffer)
+                       arc_jtag_enque_write_dr(jtag_info, *(write_buffer + i), TAP_IDLE);
+               else
+                       arc_jtag_enque_read_dr(jtag_info, read_buffer + i * 4, TAP_IDLE);
+       }
+       /* To prevent pollution of next regiter due to optimization it is necessary *
+        * to reset transaction */
+       arc_jtag_enque_reset_transaction(jtag_info);
+}
+
+/**
+ * Write registers. addr is an array of addresses, and those addresses can be
+ * in any order, though it is recommended that they are in sequential order
+ * where possible, as this reduces number of JTAG commands to transfer.
+ *
+ * @param jtag_info
+ * @param type         Type of registers to write: core or aux.
+ * @param addr         Array of registers numbers.
+ * @param count                Amount of registers in arrays.
+ * @param values       Array of register values.
+ */
+static int arc_jtag_write_registers(struct arc_jtag *jtag_info, uint32_t type,
+       uint32_t *addr, uint32_t count, const uint32_t *buffer)
+{
+       LOG_DEBUG("Writing to %s registers: addr[0]=0x%" PRIx32 ";count=%" PRIu32
+                         ";buffer[0]=0x%08" PRIx32,
+               (type == ARC_JTAG_CORE_REG ? "core" : "aux"), *addr, count, *buffer);
+
+       if (!count) {
+               LOG_ERROR("Trying to write 0 registers");
+               return ERROR_FAIL;
+       }
+
+       arc_jtag_enque_reset_transaction(jtag_info);
+
+       /* What registers are we writing to? */
+       const uint32_t transaction = (type == ARC_JTAG_CORE_REG ?
+                       ARC_JTAG_WRITE_TO_CORE_REG : ARC_JTAG_WRITE_TO_AUX_REG);
+       arc_jtag_enque_set_transaction(jtag_info, transaction, TAP_DRPAUSE);
+
+       arc_jtag_enque_register_rw(jtag_info, addr, NULL, buffer, count);
+
+       return jtag_execute_queue();
+}
+
+/**
+ * Read registers. addr is an array of addresses, and those addresses can be in
+ * any order, though it is recommended that they are in sequential order where
+ * possible, as this reduces number of JTAG commands to transfer.
+ *
+ * @param jtag_info
+ * @param type         Type of registers to read: core or aux.
+ * @param addr         Array of registers numbers.
+ * @param count                Amount of registers in arrays.
+ * @param values       Array of register values.
+ */
+static int arc_jtag_read_registers(struct arc_jtag *jtag_info, uint32_t type,
+               uint32_t *addr, uint32_t count, uint32_t *buffer)
+{
+       int retval;
+       uint32_t i;
+
+       assert(jtag_info);
+       assert(jtag_info->tap);
+
+       LOG_DEBUG("Reading %s registers: addr[0]=0x%" PRIx32 ";count=%" PRIu32,
+               (type == ARC_JTAG_CORE_REG ? "core" : "aux"), *addr, count);
+
+       if (!count) {
+               LOG_ERROR("Trying to read 0 registers");
+               return ERROR_FAIL;
+       }
+
+       arc_jtag_enque_reset_transaction(jtag_info);
+
+       /* What type of registers we are reading? */
+       const uint32_t transaction = (type == ARC_JTAG_CORE_REG ?
+                       ARC_JTAG_READ_FROM_CORE_REG : ARC_JTAG_READ_FROM_AUX_REG);
+       arc_jtag_enque_set_transaction(jtag_info, transaction, TAP_DRPAUSE);
+
+       uint8_t *data_buf = calloc(sizeof(uint8_t), count * 4);
+
+       arc_jtag_enque_register_rw(jtag_info, addr, data_buf, NULL, count);
+
+       retval = jtag_execute_queue();
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Failed to execute jtag queue: %d", retval);
+               retval = ERROR_FAIL;
+               goto exit;
+       }
+
+       /* Convert byte-buffers to host /presentation. */
+       for (i = 0; i < count; i++)
+               buffer[i] = buf_get_u32(data_buf + 4 * i, 0, 32);
+
+       LOG_DEBUG("Read from register: buf[0]=0x%" PRIx32, buffer[0]);
+
+exit:
+       free(data_buf);
+
+       return retval;
+}
+
+
+/** Wrapper function to ease writing of one core register. */
+int arc_jtag_write_core_reg_one(struct arc_jtag *jtag_info, uint32_t addr,
+       uint32_t value)
+{
+       return arc_jtag_write_core_reg(jtag_info, &addr, 1, &value);
+}
+
+/**
+ * Write core registers. addr is an array of addresses, and those addresses can
+ * be in any order, though it is recommended that they are in sequential order
+ * where possible, as this reduces number of JTAG commands to transfer.
+ *
+ * @param jtag_info
+ * @param addr         Array of registers numbers.
+ * @param count                Amount of registers in arrays.
+ * @param values       Array of register values.
+ */
+int arc_jtag_write_core_reg(struct arc_jtag *jtag_info, uint32_t *addr,
+       uint32_t count, const uint32_t *buffer)
+{
+       return arc_jtag_write_registers(jtag_info, ARC_JTAG_CORE_REG, addr, count,
+                       buffer);
+}
+
+/** Wrapper function to ease reading of one core register. */
+int arc_jtag_read_core_reg_one(struct arc_jtag *jtag_info, uint32_t addr,
+       uint32_t *value)
+{
+       return arc_jtag_read_core_reg(jtag_info, &addr, 1, value);
+}
+
+/**
+ * Read core registers. addr is an array of addresses, and those addresses can
+ * be in any order, though it is recommended that they are in sequential order
+ * where possible, as this reduces number of JTAG commands to transfer.
+ *
+ * @param jtag_info
+ * @param addr         Array of core register numbers.
+ * @param count                Amount of registers in arrays.
+ * @param values       Array of register values.
+ */
+int arc_jtag_read_core_reg(struct arc_jtag *jtag_info, uint32_t *addr,
+       uint32_t count, uint32_t *buffer)
+{
+       return arc_jtag_read_registers(jtag_info, ARC_JTAG_CORE_REG, addr, count,
+                       buffer);
+}
+
+/** Wrapper function to ease writing of one AUX register. */
+int arc_jtag_write_aux_reg_one(struct arc_jtag *jtag_info, uint32_t addr,
+       uint32_t value)
+{
+       return arc_jtag_write_aux_reg(jtag_info, &addr, 1, &value);
+}
+
+/**
+ * Write AUX registers. addr is an array of addresses, and those addresses can
+ * be in any order, though it is recommended that they are in sequential order
+ * where possible, as this reduces number of JTAG commands to transfer.
+ *
+ * @param jtag_info
+ * @param addr         Array of registers numbers.
+ * @param count                Amount of registers in arrays.
+ * @param values       Array of register values.
+ */
+int arc_jtag_write_aux_reg(struct arc_jtag *jtag_info, uint32_t *addr,
+       uint32_t count, const uint32_t *buffer)
+{
+       return arc_jtag_write_registers(jtag_info, ARC_JTAG_AUX_REG, addr, count,
+                       buffer);
+}
+
+/** Wrapper function to ease reading of one AUX register. */
+int arc_jtag_read_aux_reg_one(struct arc_jtag *jtag_info, uint32_t addr,
+       uint32_t *value)
+{
+       return arc_jtag_read_aux_reg(jtag_info, &addr, 1, value);
+}
+
+/**
+ * Read AUX registers. addr is an array of addresses, and those addresses can
+ * be in any order, though it is recommended that they are in sequential order
+ * where possible, as this reduces number of JTAG commands to transfer.
+ *
+ * @param jtag_info
+ * @param addr         Array of AUX register numbers.
+ * @param count                Amount of registers in arrays.
+ * @param values       Array of register values.
+ */
+int arc_jtag_read_aux_reg(struct arc_jtag *jtag_info, uint32_t *addr,
+       uint32_t count, uint32_t *buffer)
+{
+       return arc_jtag_read_registers(jtag_info, ARC_JTAG_AUX_REG, addr, count,
+                       buffer);
+}
+
+/**
+ * Write a sequence of 4-byte words into target memory.
+ *
+ * We can write only 4byte words via JTAG, so any non-word writes should be
+ * handled at higher levels by read-modify-write.
+ *
+ * This function writes directly to the memory, leaving any caches (if there
+ * are any) in inconsistent state. It is responsibility of upper level to
+ * resolve this.
+ *
+ * @param jtag_info
+ * @param addr         Address of first word to write into.
+ * @param count                Amount of word to write.
+ * @param buffer       Array to write into memory.
+ */
+int arc_jtag_write_memory(struct arc_jtag *jtag_info, uint32_t addr,
+               uint32_t count, const uint32_t *buffer)
+{
+       assert(jtag_info);
+       assert(buffer);
+
+       LOG_DEBUG("Writing to memory: addr=0x%08" PRIx32 ";count=%" PRIu32 ";buffer[0]=0x%08" PRIx32,
+               addr, count, *buffer);
+
+       /* No need to waste time on useless operations. */
+       if (!count)
+               return ERROR_OK;
+
+       /* We do not know where we come from. */
+       arc_jtag_enque_reset_transaction(jtag_info);
+
+       /* We want to write to memory. */
+       arc_jtag_enque_set_transaction(jtag_info, ARC_JTAG_WRITE_TO_MEMORY, TAP_DRPAUSE);
+
+       /* Set target memory address of the first word. */
+       arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_ADDRESS_REG);
+       arc_jtag_enque_write_dr(jtag_info, addr, TAP_DRPAUSE);
+
+       /* Start sending words. Address is auto-incremented on 4bytes by HW. */
+       arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_DATA_REG);
+
+       uint32_t i;
+       for (i = 0; i < count; i++)
+               arc_jtag_enque_write_dr(jtag_info, *(buffer + i), TAP_IDLE);
+
+       return jtag_execute_queue();
+}
+
+/**
+ * Read a sequence of 4-byte words from target memory.
+ *
+ * We can read only 4byte words via JTAG.
+ *
+ * This function read directly from the memory, so it can read invalid data if
+ * data cache hasn't been flushed before hand. It is responsibility of upper
+ * level to resolve this.
+ *
+ * @param jtag_info
+ * @param addr         Address of first word to read from.
+ * @param count                Amount of words to read.
+ * @param buffer       Array of words to read into.
+ * @param slow_memory  Whether this is a slow memory (DDR) or fast (CCM).
+ */
+int arc_jtag_read_memory(struct arc_jtag *jtag_info, uint32_t addr,
+       uint32_t count, uint32_t *buffer, bool slow_memory)
+{
+       uint8_t *data_buf;
+       uint32_t i;
+       int retval = ERROR_OK;
+
+
+       assert(jtag_info);
+       assert(jtag_info->tap);
+
+       LOG_DEBUG("Reading memory: addr=0x%" PRIx32 ";count=%" PRIu32 ";slow=%c",
+               addr, count, slow_memory ? 'Y' : 'N');
+
+       if (!count)
+               return ERROR_OK;
+
+       data_buf = calloc(sizeof(uint8_t), count * 4);
+       arc_jtag_enque_reset_transaction(jtag_info);
+
+       /* We are reading from memory. */
+       arc_jtag_enque_set_transaction(jtag_info, ARC_JTAG_READ_FROM_MEMORY, TAP_DRPAUSE);
+
+       /* Read data */
+       for (i = 0; i < count; i++) {
+               /* When several words are read at consequent addresses we can
+                * rely on ARC JTAG auto-incrementing address. That means that
+                * address can be set only once, for a first word. However it
+                * has been noted that at least in some cases when reading from
+                * DDR, JTAG returns 0 instead of a real value. To workaround
+                * this issue we need to do totally non-required address
+                * writes, which however resolve a problem by introducing
+                * delay. See STAR 9000832538... */
+               if (slow_memory || i == 0) {
+                   /* Set address */
+                   arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_ADDRESS_REG);
+                   arc_jtag_enque_write_dr(jtag_info, addr + i * 4, TAP_IDLE);
+
+                   arc_jtag_enque_write_ir(jtag_info, ARC_JTAG_DATA_REG);
+               }
+               arc_jtag_enque_read_dr(jtag_info, data_buf + i * 4, TAP_IDLE);
+       }
+       retval = jtag_execute_queue();
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Failed to execute jtag queue: %d", retval);
+               retval = ERROR_FAIL;
+               goto exit;
+       }
+
+       /* Convert byte-buffers to host presentation. */
+       for (i = 0; i < count; i++)
+               buffer[i] = buf_get_u32(data_buf + 4*i, 0, 32);
+
+exit:
+       free(data_buf);
+
+       return retval;
+}
+
diff --git a/src/target/arc_jtag.h b/src/target/arc_jtag.h
new file mode 100644 (file)
index 0000000..99795f5
--- /dev/null
@@ -0,0 +1,70 @@
+/***************************************************************************
+ *   Copyright (C) 2013-2014,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                             *
+ ***************************************************************************/
+
+#ifndef OPENOCD_TARGET_ARC_JTAG_H
+#define OPENOCD_TARGET_ARC_JTAG_H
+
+#define ARC_TRANSACTION_CMD_REG                0x9 /* Command to perform */
+#define ARC_TRANSACTION_CMD_REG_LENGTH 4
+
+/* Jtag status register, value is placed in IR to read jtag status register */
+#define ARC_JTAG_STATUS_REG            0x8
+#define ARC_JTAG_ADDRESS_REG           0xA /* SoC address to access */
+#define ARC_JTAG_DATA_REG              0xB /* Data read/written from SoC */
+
+/* Jtag status register field */
+#define ARC_JTAG_STAT_RU               0x10
+
+/* ARC Jtag transactions */
+#define ARC_JTAG_WRITE_TO_MEMORY       0x0
+#define ARC_JTAG_WRITE_TO_CORE_REG     0x1
+#define ARC_JTAG_WRITE_TO_AUX_REG      0x2
+#define ARC_JTAG_CMD_NOP               0x3
+#define ARC_JTAG_READ_FROM_MEMORY      0x4
+#define ARC_JTAG_READ_FROM_CORE_REG    0x5
+#define ARC_JTAG_READ_FROM_AUX_REG     0x6
+
+#define ARC_JTAG_CORE_REG              0x0
+#define ARC_JTAG_AUX_REG               0x1
+
+
+struct arc_jtag {
+       struct jtag_tap *tap;
+       uint32_t cur_trans;
+};
+
+/* ----- Exported JTAG functions ------------------------------------------- */
+
+int arc_jtag_startup(struct arc_jtag *jtag_info);
+int arc_jtag_status(struct arc_jtag *const jtag_info, uint32_t *const value);
+
+int arc_jtag_write_core_reg(struct arc_jtag *jtag_info, uint32_t *addr,
+       uint32_t count, const uint32_t *buffer);
+int arc_jtag_read_core_reg(struct arc_jtag *jtag_info, uint32_t *addr,
+       uint32_t count, uint32_t *buffer);
+int arc_jtag_write_core_reg_one(struct arc_jtag *jtag_info, uint32_t addr,
+       const uint32_t buffer);
+int arc_jtag_read_core_reg_one(struct arc_jtag *jtag_info, uint32_t addr,
+       uint32_t *buffer);
+
+int arc_jtag_write_aux_reg(struct arc_jtag *jtag_info, uint32_t *addr,
+       uint32_t count, const uint32_t *buffer);
+int arc_jtag_write_aux_reg_one(struct arc_jtag *jtag_info, uint32_t addr,
+       uint32_t value);
+int arc_jtag_read_aux_reg(struct arc_jtag *jtag_info, uint32_t *addr,
+       uint32_t count, uint32_t *buffer);
+int arc_jtag_read_aux_reg_one(struct arc_jtag *jtag_info, uint32_t addr,
+       uint32_t *value);
+
+int arc_jtag_write_memory(struct arc_jtag *jtag_info, uint32_t addr,
+               uint32_t count, const uint32_t *buffer);
+int arc_jtag_read_memory(struct arc_jtag *jtag_info, uint32_t addr,
+       uint32_t count, uint32_t *buffer, bool slow_memory);
+#endif /* OPENOCD_TARGET_ARC_JTAG_H */
diff --git a/src/target/arc_mem.c b/src/target/arc_mem.c
new file mode 100644 (file)
index 0000000..e80bfb4
--- /dev/null
@@ -0,0 +1,287 @@
+/***************************************************************************
+ *   Copyright (C) 2013-2014,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                             *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "arc.h"
+
+/* ----- Supporting functions ---------------------------------------------- */
+static bool arc_mem_is_slow_memory(struct arc_common *arc, uint32_t addr,
+       uint32_t size, uint32_t count)
+{
+       uint32_t addr_end = addr + size * count;
+       /* `_end` field can overflow - it points to the first byte after the end,
+        * therefore if DCCM is right at the end of memory address space, then
+        * dccm_end will be 0. */
+       assert(addr_end >= addr || addr_end == 0);
+
+       return !((addr >= arc->dccm_start && addr_end <= arc->dccm_end) ||
+               (addr >= arc->iccm0_start && addr_end <= arc->iccm0_end) ||
+               (addr >= arc->iccm1_start && addr_end <= arc->iccm1_end));
+}
+
+/* Write word at word-aligned address */
+static int arc_mem_write_block32(struct target *target, uint32_t addr,
+       uint32_t count, void *buf)
+{
+       struct arc_common *arc = target_to_arc(target);
+
+       LOG_DEBUG("Write 4-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32,
+                       addr, count);
+
+       /* Check arguments */
+       assert(!(addr & 3));
+
+       /* No need to flush cache, because we don't read values from memory. */
+       CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info, addr, count,
+                               (uint32_t *)buf));
+
+       return ERROR_OK;
+}
+
+/* Write half-word at half-word-aligned address */
+static int arc_mem_write_block16(struct target *target, uint32_t addr,
+       uint32_t count, void *buf)
+{
+       struct arc_common *arc = target_to_arc(target);
+       uint32_t i;
+       uint32_t buffer_he;
+       uint8_t buffer_te[sizeof(uint32_t)];
+       uint8_t halfword_te[sizeof(uint16_t)];
+
+       LOG_DEBUG("Write 2-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32,
+                       addr, count);
+
+       /* Check arguments */
+       assert(!(addr & 1));
+
+       /* non-word writes are less common, than 4-byte writes, so I suppose we can
+        * allowe ourselves to write this in a cycle, instead of calling arc_jtag
+        * with count > 1. */
+       for (i = 0; i < count; i++) {
+               /* We can read only word at word-aligned address. Also *jtag_read_memory
+                * functions return data in host endianness, so host endianness !=
+                * target endianness we have to convert data back to target endianness,
+                * or bytes will be at the wrong places.So:
+                *   1) read word
+                *   2) convert to target endianness
+                *   3) make changes
+                *   4) convert back to host endianness
+                *   5) write word back to target.
+                */
+               bool is_slow_memory = arc_mem_is_slow_memory(arc,
+                       (addr + i * sizeof(uint16_t)) & ~3u, 4, 1);
+               CHECK_RETVAL(arc_jtag_read_memory(&arc->jtag_info,
+                               (addr + i * sizeof(uint16_t)) & ~3u, 1, &buffer_he,
+                               is_slow_memory));
+               target_buffer_set_u32(target, buffer_te, buffer_he);
+
+               /* buf is in host endianness, convert to target */
+               target_buffer_set_u16(target, halfword_te, ((uint16_t *)buf)[i]);
+
+               memcpy(buffer_te  + ((addr + i * sizeof(uint16_t)) & 3u),
+                       halfword_te, sizeof(uint16_t));
+
+               buffer_he = target_buffer_get_u32(target, buffer_te);
+
+               CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info,
+                       (addr + i * sizeof(uint16_t)) & ~3u, 1, &buffer_he));
+       }
+
+       return ERROR_OK;
+}
+
+/* Write byte at address */
+static int arc_mem_write_block8(struct target *target, uint32_t addr,
+       uint32_t count, void *buf)
+{
+       struct arc_common *arc = target_to_arc(target);
+       uint32_t i;
+       uint32_t buffer_he;
+       uint8_t buffer_te[sizeof(uint32_t)];
+
+
+       LOG_DEBUG("Write 1-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32,
+                       addr, count);
+
+       /* non-word writes are less common, than 4-byte writes, so I suppose we can
+        * allowe ourselves to write this in a cycle, instead of calling arc_jtag
+        * with count > 1. */
+       for (i = 0; i < count; i++) {
+               /* See comment in arc_mem_write_block16 for details. Since it is a byte
+                * there is not need to convert write buffer to target endianness, but
+                * we still have to convert read buffer. */
+               CHECK_RETVAL(arc_jtag_read_memory(&arc->jtag_info, (addr + i) & ~3, 1, &buffer_he,
+                           arc_mem_is_slow_memory(arc, (addr + i) & ~3, 4, 1)));
+               target_buffer_set_u32(target, buffer_te, buffer_he);
+               memcpy(buffer_te  + ((addr + i) & 3), (uint8_t *)buf + i, 1);
+               buffer_he = target_buffer_get_u32(target, buffer_te);
+               CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info, (addr + i) & ~3, 1, &buffer_he));
+       }
+
+       return ERROR_OK;
+}
+
+/* ----- Exported functions ------------------------------------------------ */
+int arc_mem_write(struct target *target, target_addr_t address, uint32_t size,
+       uint32_t count, const uint8_t *buffer)
+{
+       int retval = ERROR_OK;
+       void *tunnel = NULL;
+
+       LOG_DEBUG("address: 0x%08" TARGET_PRIxADDR ", size: %" PRIu32 ", count: %" PRIu32,
+               address, size, count);
+
+       if (target->state != TARGET_HALTED) {
+               LOG_WARNING("target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* sanitize arguments */
+       if (((size != 4) && (size != 2) && (size != 1)) || !(count) || !(buffer))
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
+               return ERROR_TARGET_UNALIGNED_ACCESS;
+
+       /* correct endianess if we have word or hword access */
+       if (size > 1) {
+               /*
+                * arc_..._write_mem with size 4/2 requires uint32_t/uint16_t
+                * in host endianness, but byte array represents target endianness.
+                */
+               tunnel = calloc(1, count * size * sizeof(uint8_t));
+
+               if (!tunnel) {
+                       LOG_ERROR("Unable to allocate memory");
+                       return ERROR_FAIL;
+               }
+
+               switch (size) {
+               case 4:
+                       target_buffer_get_u32_array(target, buffer, count,
+                               (uint32_t *)tunnel);
+                       break;
+               case 2:
+                       target_buffer_get_u16_array(target, buffer, count,
+                               (uint16_t *)tunnel);
+                       break;
+               }
+               buffer = tunnel;
+       }
+
+       if (size == 4) {
+               retval = arc_mem_write_block32(target, address, count, (void *)buffer);
+       } else if (size == 2) {
+               /* We convert buffer from host endianness to target. But then in
+                * write_block16, we do the reverse. Is there a way to avoid this without
+                * breaking other cases? */
+               retval = arc_mem_write_block16(target, address, count, (void *)buffer);
+       } else {
+               retval = arc_mem_write_block8(target, address, count, (void *)buffer);
+       }
+
+       free(tunnel);
+
+       return retval;
+}
+
+static int arc_mem_read_block(struct target *target, target_addr_t addr,
+       uint32_t size, uint32_t count, void *buf)
+{
+       struct arc_common *arc = target_to_arc(target);
+
+       LOG_DEBUG("Read memory: addr=0x%08" TARGET_PRIxADDR ", size=%" PRIu32
+                       ", count=%" PRIu32, addr, size, count);
+       assert(!(addr & 3));
+       assert(size == 4);
+
+       CHECK_RETVAL(arc_jtag_read_memory(&arc->jtag_info, addr, count, buf,
+                   arc_mem_is_slow_memory(arc, addr, size, count)));
+
+       return ERROR_OK;
+}
+
+int arc_mem_read(struct target *target, target_addr_t address, uint32_t size,
+       uint32_t count, uint8_t *buffer)
+{
+       int retval = ERROR_OK;
+       void *tunnel_he;
+       uint8_t *tunnel_te;
+       uint32_t words_to_read, bytes_to_read;
+
+
+       LOG_DEBUG("Read memory: addr=0x%08" TARGET_PRIxADDR ", size=%" PRIu32
+                       ", count=%" PRIu32, address, size, count);
+
+       if (target->state != TARGET_HALTED) {
+               LOG_WARNING("target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* Sanitize arguments */
+       if (((size != 4) && (size != 2) && (size != 1)) || !(count) || !(buffer))
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
+           return ERROR_TARGET_UNALIGNED_ACCESS;
+
+       /* Reads are word-aligned, so padding might be required if count > 1.
+        * NB: +3 is a padding for the last word (in case it's not aligned;
+        * addr&3 is a padding for the first word (since address can be
+        * unaligned as well).  */
+       bytes_to_read = (count * size + 3 + (address & 3u)) & ~3u;
+       words_to_read = bytes_to_read >> 2;
+       tunnel_he = calloc(1, bytes_to_read);
+       tunnel_te = calloc(1, bytes_to_read);
+
+       if (!tunnel_he || !tunnel_te) {
+               LOG_ERROR("Unable to allocate memory");
+               free(tunnel_he);
+               free(tunnel_te);
+               return ERROR_FAIL;
+       }
+
+       /* We can read only word-aligned words. */
+       retval = arc_mem_read_block(target, address & ~3u, sizeof(uint32_t),
+               words_to_read, tunnel_he);
+
+       /* arc_..._read_mem with size 4/2 returns uint32_t/uint16_t in host */
+       /* endianness, but byte array should represent target endianness      */
+
+       if (ERROR_OK == retval) {
+               switch (size) {
+               case 4:
+                       target_buffer_set_u32_array(target, buffer, count,
+                               tunnel_he);
+                       break;
+               case 2:
+                       target_buffer_set_u32_array(target, tunnel_te,
+                               words_to_read, tunnel_he);
+                       /* Will that work properly with count > 1 and big endian? */
+                       memcpy(buffer, tunnel_te + (address & 3u),
+                               count * sizeof(uint16_t));
+                       break;
+               case 1:
+                       target_buffer_set_u32_array(target, tunnel_te,
+                               words_to_read, tunnel_he);
+                       /* Will that work properly with count > 1 and big endian? */
+                       memcpy(buffer, tunnel_te + (address & 3u), count);
+                       break;
+               }
+       }
+
+       free(tunnel_he);
+       free(tunnel_te);
+
+       return retval;
+}
diff --git a/src/target/arc_mem.h b/src/target/arc_mem.h
new file mode 100644 (file)
index 0000000..06e1c88
--- /dev/null
@@ -0,0 +1,21 @@
+/***************************************************************************
+ *   Copyright (C) 2013-2014,2019-2020 Synopsys, Inc.                      *
+ *   Frank Dols <frank.dols@synopsys.com>                                  *
+ *   Anton Kolesov <anton.kolesov@synopsys.com>                            *
+ *   Evgeniy Didin <didin@synopsys.com>                                    *
+ *                                                                         *
+ *   SPDX-License-Identifier: GPL-2.0-or-later                             *
+ ***************************************************************************/
+
+#ifndef OPENOCD_TARGET_ARC_MEM_H
+#define OPENOCD_TARGET_ARC_MEM_H
+
+/* ----- Exported functions ------------------------------------------------ */
+
+int arc_mem_read(struct target *target, target_addr_t address, uint32_t size,
+       uint32_t count, uint8_t *buffer);
+int arc_mem_write(struct target *target, target_addr_t address, uint32_t size,
+       uint32_t count, const uint8_t *buffer);
+
+
+#endif /* OPENOCD_TARGET_ARC_MEM_H */
index 688d31890360841aafcd5e13cc37ee3f561a7d92..1ba4e09878ee35fa4ccccde0740be292944c07f6 100644 (file)
@@ -111,6 +111,7 @@ extern struct target_type stm8_target;
 extern struct target_type riscv_target;
 extern struct target_type mem_ap_target;
 extern struct target_type esirisc_target;
 extern struct target_type riscv_target;
 extern struct target_type mem_ap_target;
 extern struct target_type esirisc_target;
+extern struct target_type arcv2_target;
 
 static struct target_type *target_types[] = {
        &arm7tdmi_target,
 
 static struct target_type *target_types[] = {
        &arm7tdmi_target,
@@ -146,6 +147,7 @@ static struct target_type *target_types[] = {
        &riscv_target,
        &mem_ap_target,
        &esirisc_target,
        &riscv_target,
        &mem_ap_target,
        &esirisc_target,
+       &arcv2_target,
 #if BUILD_TARGET64
        &aarch64_target,
        &mips_mips64_target,
 #if BUILD_TARGET64
        &aarch64_target,
        &mips_mips64_target,

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)