This is an automated email from Gerrit.

Evgeniy Didin ([email protected]) just uploaded a new patch set to Gerrit, 
which you can find at http://openocd.zylin.com/5349

-- gerrit

commit 2eb4b09c8928ba0996d645bb0df4c034de8e99fb
Author: Evgeniy Didin <[email protected]>
Date:   Mon Dec 2 08:48:20 2019 +0300

    Introduce ARCv2 architecture related code
    
    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.
    
    Change-Id: I602777148cabea5161421f3306037d47e33bfde0
    Signed-off-by: Evgeniy Didin <[email protected]>
    Cc: Alexey Brodkin <[email protected]>

diff --git a/src/target/Makefile.am b/src/target/Makefile.am
index 08a4b96..b557384 100644
--- a/src/target/Makefile.am
+++ b/src/target/Makefile.am
@@ -24,6 +24,7 @@ noinst_LTLIBRARIES += %D%/libtarget.la
        $(STM8_SRC) \
        $(INTEL_IA32_SRC) \
        $(ESIRISC_SRC) \
+        $(ARC_SRC) \
        %D%/avrt.c \
        %D%/dsp563xx.c \
        %D%/dsp563xx_once.c \
@@ -155,6 +156,13 @@ ESIRISC_SRC = \
        %D%/esirisc_jtag.c \
        %D%/esirisc_trace.c
 
+ARC_SRC = \
+        %D%/arc.c \
+        %D%/arc_v2.c \
+        %D%/arc_cmd.c \
+        %D%/arc_jtag.c \
+        %D%/arc_mem.c
+
 %C%_libtarget_la_SOURCES += \
        %D%/algorithm.h \
        %D%/arm.h \
@@ -242,7 +250,11 @@ ESIRISC_SRC = \
        %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
diff --git a/src/target/arc.c b/src/target/arc.c
new file mode 100644
index 0000000..fcd2eb1
--- /dev/null
+++ b/src/target/arc.c
@@ -0,0 +1,1191 @@
+/***************************************************************************
+ *   Copyright (C) 2013-2015,2019 Synopsys, Inc.                           *
+ *   Frank Dols <[email protected]>                                  *
+ *   Mischa Jonker <[email protected]>                            *
+ *   Anton Kolesov <[email protected]>                            *
+ *   Evgeniy Didin <[email protected]>
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ ***************************************************************************/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "arc.h"
+
+void arc_add_reg_data_type(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);
+}
+
+/* ----- Exported functions ------------------------------------------------ */
+
+/**
+ * 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_register_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) == 0)
+                               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 */
+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->fast_data_area = NULL;
+
+       arc->jtag_info.tap = tap;
+       arc->jtag_info.scann_size = 4;
+
+       /* has breakpoint/watchpoint unit been scanned */
+       arc->bp_scanned = 0;
+
+       /* We don't know how many actionpoints are in the core yet. */
+       arc->actionpoints_num_avail = 0;
+       arc->actionpoints_num = 0;
+       arc->actionpoints_list = NULL;
+
+       /* Flush D$ by default. It is safe to assume that D$ is present,
+        * because if it isn't, there will be no error, just a slight
+        * performance penalty from unnecessary JTAG operations. */
+       arc->has_dcache = true;
+
+       /* TODO: uncomment this as this function be introduced */
+       /*arc_reset_caches_states(target);*/
+
+       /* Add standard GDB data types */
+       INIT_LIST_HEAD(&arc->reg_data_types);
+       struct arc_reg_data_type *std_types = 
calloc(ARRAY_SIZE(standard_gdb_types),
+               sizeof(struct arc_reg_data_type));
+       if (!std_types) {
+               LOG_ERROR("Cannot 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_add_reg_data_type(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_add_reg(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) == 0) {
+                               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;
+}
+
+/* Common code to initialize `struct reg` for different registers: core, aux, 
bcr. */
+static void arc_init_reg(
+               struct target *target,
+               struct reg *reg,
+               struct arc_reg_t *arc_reg,
+               struct arc_reg_desc *reg_desc,
+               unsigned long number)
+{
+       assert(target);
+       assert(reg);
+       assert(arc_reg);
+       assert(reg_desc);
+
+       struct arc_common *arc = target_to_arc(target);
+
+       /* Initialize struct arc_reg_t */
+       arc_reg->desc = reg_desc;
+       arc_reg->target = target;
+       arc_reg->arc_common = arc;
+
+       /* Initialize struct reg */
+       reg->name = reg_desc->name;
+       reg->size = 32; /* All register in ARC are 32-bit */
+       reg->value = calloc(1, 4);
+       reg->type = &arc_reg_type;
+       reg->arch_info = arc_reg;
+       reg->caller_save = true; /* @todo should be configurable. */
+       reg->reg_data_type = reg_desc->data_type;
+
+       reg->feature = calloc(1, sizeof(struct reg_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;
+       }
+}
+
+/* Building aux/core reg_cache */
+int arc_build_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_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(struct reg_cache));
+       struct reg *reg_list = calloc(num_regs, sizeof(struct reg));
+       struct arc_reg_t *reg_arch_info = calloc(num_regs, sizeof(struct 
arc_reg_t));
+
+       /* Build the process context cache */
+       cache->name = "arc registers";
+       cache->next = NULL;
+       cache->reg_list = reg_list;
+       cache->num_regs = num_regs;
+       arc->core_cache = cache;
+       (*cache_p) = cache;
+
+       struct arc_reg_desc *reg_desc;
+       unsigned long i = 0;
+       if (!list_empty(&arc->core_reg_descriptions)) {
+               list_for_each_entry(reg_desc, &arc->core_reg_descriptions, 
list) {
+                       arc_init_reg(target, &reg_list[i], &reg_arch_info[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;
+               }
+       } else {
+               LOG_ERROR("No core registers were defined");
+               goto fail;
+       }
+
+       if (!list_empty(&arc->aux_reg_descriptions)) {
+               list_for_each_entry(reg_desc, &arc->aux_reg_descriptions, list) 
{
+                       arc_init_reg(target, &reg_list[i], &reg_arch_info[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 (arc->pc_index_in_cache == ULONG_MAX && strcmp("pc", 
reg_desc->name) == 0)
+                               arc->pc_index_in_cache = i;
+                       else if (arc->debug_index_in_cache == ULONG_MAX
+                                       && strcmp("debug", reg_desc->name) == 0)
+                               arc->debug_index_in_cache = i;
+
+                       i += 1;
+               }
+       } else {
+               LOG_ERROR("No aux registers were defined");
+               goto fail;
+       }
+
+       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));
+
+       return ERROR_OK;
+
+fail:
+       free(cache);
+       free(reg_list);
+       free(reg_arch_info);
+
+       return ERROR_FAIL;
+}
+
+/* This function must be called only after arc_build_reg_cache */
+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(struct reg_cache));
+       struct reg *reg_list = calloc(num_regs, sizeof(struct reg));
+       struct arc_reg_t *reg_arch_info = calloc(num_regs, sizeof(struct 
arc_reg_t));
+
+
+       /* Build the process context cache */
+       cache->name = "arc.bcr";
+       cache->next = NULL;
+       cache->reg_list = reg_list;
+       cache->num_regs = num_regs;
+       (*cache_p) = cache;
+
+
+       struct arc_reg_desc *reg_desc;
+       unsigned long i = 0;
+       unsigned long gdb_regnum = arc->core_cache->num_regs;
+
+       if (!list_empty(&arc->bcr_reg_descriptions)) {
+               list_for_each_entry(reg_desc, &arc->bcr_reg_descriptions, list) 
{
+                       arc_init_reg(target, &reg_list[i], &reg_arch_info[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;
+               }
+       } else {
+               LOG_ERROR("No BCR registers are defined");
+               free(reg_arch_info);
+       }
+
+       assert(i == arc->num_bcr_regs);
+
+       return ERROR_OK;
+}
+
+
+static int arc_regs_get_core_reg(struct reg *reg)
+{
+       assert(reg != NULL);
+
+       struct arc_reg_t *arc_reg = reg->arch_info;
+       struct target *target = arc_reg->target;
+       struct arc_common *arc = target_to_arc(target);
+
+       if (reg->valid) {
+               LOG_DEBUG("Get register (cached) gdb_num=%" PRIu32 ", name=%s, 
value=0x%" PRIx32,
+                               reg->number, arc_reg->desc->name, 
arc_reg->value);
+               return ERROR_OK;
+       }
+
+       if (arc_reg->desc->is_core) {
+               if (arc_reg->desc->arch_num == 61 || arc_reg->desc->arch_num == 
62) {
+                       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, 
arc_reg->desc->arch_num,
+                       &arc_reg->value));
+       } else {
+               CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, 
arc_reg->desc->arch_num,
+                       &arc_reg->value));
+       }
+
+       buf_set_u32(reg->value, 0, 32, arc_reg->value);
+
+       /* In general it is preferable that target is halted, so its state 
doesn't
+        * change in ways unknown to OpenOCD, and there used to be a check in 
this
+        * function - it would work only if target is halted.  However there is 
a
+        * twist - arc_configure is called from arc_examine_target.
+        * arc_configure will read registers via this function, but target may 
be
+        * still run at this point - if it was running when OpenOCD connected 
to it.
+        * ARC initialization scripts would do a "force halt" of target, but 
that
+        * happens only after target is examined, so this function wouldn't 
work if
+        * it would require target to be halted.  It is possible to do a force 
halt
+        * of target from arc_ocd_examine_target, but then if we look at this
+        * problem longterm - this is not a solution, as it would prevent 
non-stop
+        * debugging.  Preferable way seems to allow register reading from 
nonhalted
+        * target, but those reads should be uncached.  Therefore "valid" bit 
is set
+        * only when target is halted.
+        *
+        * The same is not done for register setter - for now it will continue 
to
+        * support only halted targets, untill there will be a real need for 
async
+        * writes there as well.
+        */
+       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 , arc_reg->desc->name, arc_reg->value);
+
+       return ERROR_OK;
+}
+
+static int arc_regs_set_core_reg(struct reg *reg, uint8_t *buf)
+{
+       struct arc_reg_t *arc_reg = reg->arch_info;
+       struct target *target = arc_reg->target;
+       uint32_t value = buf_get_u32(buf, 0, 32);
+
+       if (target->state != TARGET_HALTED)
+               return ERROR_TARGET_NOT_HALTED;
+
+       if (arc_reg->desc->is_core && (arc_reg->desc->arch_num == 61 ||
+                       arc_reg->desc->arch_num == 62)) {
+               LOG_ERROR("It is forbidden to write core registers 61 and 62.");
+               return ERROR_FAIL;
+       }
+
+       buf_set_u32(reg->value, 0, 32, value);
+       arc_reg->value = value;
+
+       LOG_DEBUG("Set register gdb_num=%" PRIu32 ", name=%s, value=0x%08" 
PRIx32,
+                       reg->number, arc_reg->desc->name, value);
+
+       reg->valid = true;
+       reg->dirty = true;
+
+       return ERROR_OK;
+}
+
+const struct reg_arch_type arc_reg_type = {
+       .get = arc_regs_get_core_reg,
+       .set = arc_regs_set_core_reg,
+};
+
+/* */
+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 *));
+
+       /* 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 != NULL) {
+                       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 != NULL) {
+                       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_get_register_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_register_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 != NULL;
+            field = field->next) {
+               if (strcmp(field->name, field_name) == 0)
+                       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));
+
+       *value_ptr = buf_get_u32(reg->value, field->bitfield->start,
+                       field->bitfield->end - field->bitfield->start + 1);
+
+       LOG_DEBUG("return (value=0x%" PRIx32 ")", *value_ptr);
+
+       return ERROR_OK;
+}
+
+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_register_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));
+
+       const struct arc_reg_t * const arc_r = reg->arch_info;
+       *value_ptr = arc_r->value;
+
+       LOG_DEBUG("return %s=0x%08" PRIx32, reg_name, *value_ptr);
+
+       return ERROR_OK;
+}
+
+/* Set value of 32-bit register. */
+int arc_set_register_value(struct target *target, const char *reg_name,
+               uint32_t value)
+{
+       uint8_t value_buf[4];
+
+       LOG_DEBUG("reg_name=%s value=0x%08" PRIx32, reg_name, value);
+
+       struct reg *reg = arc_register_get_by_name(target->reg_cache, reg_name, 
true);
+
+       if (!reg)
+               return ERROR_ARC_REGISTER_NOT_FOUND;
+
+       buf_set_u32(value_buf, 0, 32, value);
+       CHECK_RETVAL(reg->type->set(reg, value_buf));
+
+       return ERROR_OK;
+}
+
+/* Configure some core features, depending on BCRs. */
+int arc_configure(struct target *target)
+{
+       LOG_DEBUG("Configuring ARC ICCM and DCCM");
+       struct arc_common *arc = target_to_arc(target);
+
+       /* DCCM. But only if DCCM_BUILD and AUX_DCCM are known registers. */
+       arc->dccm_start = 0;
+       arc->dccm_end = 0;
+       if (arc_register_get_by_name(target->reg_cache, "dccm_build", true) &&
+           arc_register_get_by_name(target->reg_cache, "aux_dccm", true)) {
+
+               uint32_t dccm_build_version, dccm_build_size0, dccm_build_size1;
+               CHECK_RETVAL(arc_get_register_field(target, "dccm_build", 
"version",
+                       &dccm_build_version));
+               CHECK_RETVAL(arc_get_register_field(target, "dccm_build", 
"size0",
+                       &dccm_build_size0));
+               CHECK_RETVAL(arc_get_register_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);
+               }
+       }
+
+       /* Only if ICCM_BUILD and AUX_ICCM are known registers. */
+       arc->iccm0_start = 0;
+       arc->iccm0_end = 0;
+       if (arc_register_get_by_name(target->reg_cache, "iccm_build", true) &&
+           arc_register_get_by_name(target->reg_cache, "aux_iccm", true)) {
+
+               /* ICCM0 */
+               uint32_t iccm_build_version, iccm_build_size00, 
iccm_build_size01;
+               uint32_t aux_iccm = 0;
+               CHECK_RETVAL(arc_get_register_field(target, "iccm_build", 
"version",
+                       &iccm_build_version));
+               CHECK_RETVAL(arc_get_register_field(target, "iccm_build", 
"iccm0_size0",
+                       &iccm_build_size00));
+               CHECK_RETVAL(arc_get_register_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_get_register_field(target, "iccm_build", 
"iccm1_size0",
+                       &iccm_build_size10));
+               CHECK_RETVAL(arc_get_register_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;
+}
+
+/* arc_examine is function, which is used for all arc targets*/
+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;
+}
+
+int arc_halt(struct target *target)
+{
+       uint32_t value;
+       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);
+
+       /* update state and notify gdb*/
+       target->state = TARGET_HALTED;
+       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_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("Not enough 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_t *arc_reg = reg->arch_info;
+               if (!reg->valid && reg->exist) {
+                       core_addrs[core_cnt] = arc_reg->desc->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_t *arc_reg = reg->arch_info;
+               if (!reg->valid && reg->exist) {
+                       aux_addrs[aux_cnt] = arc_reg->desc->arch_num;
+                       aux_cnt += 1;
+               }
+       }
+
+       /* Read data from target. */
+       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;
+       }
+       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_t *arc_reg = reg->arch_info;
+               if (!reg->valid && reg->exist) {
+                       arc_reg->value = core_values[core_cnt];
+                       core_cnt += 1;
+                       buf_set_u32(reg->value, 0, 32, arc_reg->value);
+                       reg->valid = true;
+                       reg->dirty = false;
+                       LOG_DEBUG("Get core register regnum=%" PRIu32 ", 
name=%s, value=0x%08" PRIx32,
+                               i , arc_reg->desc->name, arc_reg->value);
+               }
+       }
+
+       /* 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_t *arc_reg = reg->arch_info;
+               if (!reg->valid && reg->exist) {
+                       arc_reg->value = aux_values[aux_cnt];
+                       aux_cnt += 1;
+                       buf_set_u32(reg->value, 0, 32, arc_reg->value);
+                       reg->valid = true;
+                       reg->dirty = false;
+                       LOG_DEBUG("Get aux register regnum=%" PRIu32 ", 
name=%s, value=0x%08" PRIx32,
+                               i , arc_reg->desc->name, arc_reg->value);
+               }
+       }
+
+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_get_register_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)
+{
+       uint32_t dpc;
+       struct arc_common *arc = target_to_arc(target);
+
+       /* save current PC */
+       CHECK_RETVAL(arc_get_register_value(target, "pc", &dpc));
+       arc->jtag_info.dpc = dpc;
+       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;
+}
+
+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;
+               }
+       } else {
+               /* 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));
+                               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;
+}
+
+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_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_cache);
+
+       if (target->reset_halt)
+               CHECK_RETVAL(target_halt(target));
+
+       return ERROR_OK;
+}
+
+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;
+}
+
+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_cache->reg_list;
+
+       LOG_DEBUG("Restoring registers values");
+       assert(reg_list);
+
+       /* It is assumed that there is at least one AUX register in the 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("Not enough 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_t *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->desc->arch_num;
+                       core_values[core_cnt] = arc_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_t *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->desc->arch_num;
+                       aux_values[aux_cnt] = arc_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;
+}
+
+int arc_enable_interrupts(struct target *target, int enable)
+{
+       uint32_t value;
+
+       struct arc_common *arc = target_to_arc(target);
+
+       if (enable) {
+               /* enable interrupts */
+               value = SET_CORE_ENABLE_INTERRUPTS;
+               CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, 
AUX_IRQ_ENABLE_REG, value));
+               LOG_DEBUG("interrupts enabled");
+       } else {
+               /* disable interrupts */
+               value = SET_CORE_DISABLE_INTERRUPTS;
+               CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, 
AUX_IRQ_ENABLE_REG, value));
+               LOG_DEBUG("interrupts disabled");
+       }
+
+       return ERROR_OK;
+}
+
+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_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) {
+               buf_set_u32(pc->value, 0, 32, 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 = buf_get_u32(pc->value,
+                       0, 32);
+
+       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 == buf_get_u32(pc->value, 0, 32))) {
+               value = buf_get_u32(pc->value, 0, 32);
+               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));
+       }
+
+       /* enable interrupts if we are running */
+       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_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;
+}
diff --git a/src/target/arc.h b/src/target/arc.h
new file mode 100644
index 0000000..6e919c7
--- /dev/null
+++ b/src/target/arc.h
@@ -0,0 +1,258 @@
+/***************************************************************************
+ *   Copyright (C) 2013-2015,2019 Synopsys, Inc.                           *
+ *   Frank Dols <[email protected]>                                  *
+ *   Mischa Jonker <[email protected]>                            *
+ *   Anton Kolesov <[email protected]>                            *
+ *   Evgeniy Didin <[email protected]>
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ ***************************************************************************/
+
+#ifndef ARC_H
+#define 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 "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             (1 << 1)
+#define SET_CORE_HALT_BIT               (1)      /* STATUS32[0] = H field */
+
+
+#define AUX_STATUS32_REG_HALT_BIT       (1)
+
+#define AUX_IRQ_ENABLE_REG                     0x40C
+#define SET_CORE_DISABLE_INTERRUPTS            0x0
+#define SET_CORE_ENABLE_INTERRUPTS             0x1
+
+/* Register data type */
+struct arc_reg_data_type {
+       struct list_head list;
+       struct reg_data_type data_type;
+};
+
+/* 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;
+       void *arch_info;
+
+       struct arc_jtag jtag_info;
+
+       struct reg_cache *core_cache;
+
+       /* working area for fastdata access */
+       struct working_area *fast_data_area;
+
+       int bp_scanned;
+
+       /* Actionpoints */
+       unsigned int actionpoints_num;
+       unsigned int actionpoints_num_avail;
+       struct arc_comparator *actionpoints_list;
+
+       /* Cache control */
+       bool has_dcache;
+       /* If true, then D$ has been already flushed since core has been
+        * halted. */
+       bool dcache_flushed;
+       /* If true, then caches have been already flushed since core has been
+        * halted. */
+       bool cache_invalidated;
+
+       /* Whether DEBUG.SS bit is present. This is a unique feature of ARC 
600. */
+       bool has_debug_ss;
+
+       /* Workaround for a problem with ARC 600 - writing RA | IS | SS will not
+        * step an instruction - it must be only a (IS | SS). However RA is set 
by
+        * the processor itself and since OpenOCD does read-modify-write of 
DEBUG
+        * register when stepping, it is required to explicitly disable RA 
before
+        * stepping. */
+       bool on_step_reset_debug_ra;
+
+       /* CCM memory regions (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;
+
+       /* 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 {
+       /* Register name */
+       char *name;
+
+       /* 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;
+};
+
+struct arc_reg_t {
+       struct arc_reg_desc *desc;
+       struct target *target;
+       struct arc_common *arc_common;
+       uint32_t value;
+};
+
+const struct reg_arch_type arc_reg_type;
+
+/* 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 = "";
+
+/* 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)
+
+/* ----- Exported functions ------------------------------------------------ */
+int arc_init_arch_info(struct target *target, struct arc_common *arc,
+               struct jtag_tap *tap);
+
+/* Configurable registers functions */
+void arc_add_reg_data_type(struct target *target,
+               struct arc_reg_data_type *data_type);
+
+int arc_add_reg(struct target *target, struct arc_reg_desc *arc_reg,
+               const char * const type_name, const size_t type_name_len);
+
+int arc_build_reg_cache(struct target *target);
+int arc_build_bcr_reg_cache(struct target *target);
+
+struct reg *arc_register_get_by_name(struct reg_cache *first,
+                                       const char *name, bool search_all);
+
+/* Get value of field in struct register */
+int arc_get_register_field(struct target *target, const char *reg_name,
+               const char *field_name, uint32_t *value_ptr);
+/* Get value of 32-bit register. */
+int arc_get_register_value(struct target *target, const char *reg_name,
+               uint32_t *value_ptr);
+/* Set value of 32-bit register. */
+int arc_set_register_value(struct target *target, const char *reg_name,
+               uint32_t value);
+
+int arc_examine(struct target *target);
+int arc_halt(struct target *target);
+int arc_poll(struct target *target);
+int arc_assert_reset(struct target *target);
+int arc_deassert_reset(struct target *target);
+int arc_arch_state(struct target *target);
+int arc_enable_interrupts(struct target *target, int enable);
+int arc_resume(struct target *target, int current, target_addr_t address,
+       int handle_breakpoints, int debug_execution);
+
+int arc_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
+       int *reg_list_size, enum target_register_class reg_class);
+
+#endif /* ARC_H */
diff --git a/src/target/arc_cmd.c b/src/target/arc_cmd.c
new file mode 100644
index 0000000..a3f1303
--- /dev/null
+++ b/src/target/arc_cmd.c
@@ -0,0 +1,980 @@
+/***************************************************************************
+ *   Copyright (C) 2013-2015,2019 Synopsys, Inc.                           *
+ *   Frank Dols <[email protected]>                                  *
+ *   Mischa Jonker <[email protected]>                            *
+ *   Anton Kolesov <[email protected]>                            *
+ *   Evgeniy Didin <[email protected]>
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ ***************************************************************************/
+
+#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;
+}
+
+/* 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;
+}
+
+int jim_arc_add_reg_type_flags(Jim_Interp *interp, int argc,
+       Jim_Obj * const *argv)
+{
+       Jim_GetOptInfo goi;
+       Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1);
+
+       LOG_DEBUG("-");
+
+       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;
+
+       struct arc_reg_data_type *type = calloc(1, sizeof(struct 
arc_reg_data_type));
+       struct reg_data_type_flags *flags =
+               calloc(1, sizeof(struct reg_data_type_flags));
+       struct reg_data_type_flags_field *fields = calloc(fields_sz,
+                       sizeof(struct reg_data_type_flags_field));
+       struct reg_data_type_bitfield *bitfields = calloc(fields_sz,
+                       sizeof(struct reg_data_type_bitfield));
+
+       if (!(type && flags && fields && bitfields)) {
+               free(type);
+               free(flags);
+               free(fields);
+               free(bitfields);
+               Jim_SetResultFormatted(goi.interp, "Failed to allocate 
memory.");
+               return JIM_ERR;
+       }
+
+       /* Initialize type */
+       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;
+                               int name_len;
+                               if (goi.argc == 0) {
+                                       Jim_WrongNumArgs(interp, goi.argc, 
goi.argv, "-name ?name? ...");
+                                       e = JIM_ERR;
+                                       break;
+                               }
+
+                               e = Jim_GetOpt_String(&goi, &name, &name_len);
+                               if (e == JIM_OK) {
+                                       type->data_type.id = strndup(name, 
name_len);
+                                       if (!type->data_type.id)
+                                               e = JIM_ERR;
+                               }
+                               break;
+                       }
+
+                       case CFG_ADD_REG_TYPE_FLAGS_FLAG:
+                       {
+                               const char *field_name;
+                               int field_name_len;
+                               jim_wide start_position, end_position;
+
+                               if (goi.argc < 2) {
+                                       Jim_WrongNumArgs(interp, goi.argc, 
goi.argv,
+                                               "-flag ?name? ?position? ...");
+                                       e = JIM_ERR;
+                                       break;
+                               }
+
+                               /* Field name */
+                               e = Jim_GetOpt_String(&goi, &field_name, 
&field_name_len);
+                               if (e != JIM_OK)
+                                       break;
+
+                               /* Field position. start == end, because flags
+                                * are one-bit fields.  */
+
+                               fields[cur_field].name = strndup(field_name, 
field_name_len);
+                               if (!fields[cur_field].name) {
+                                       e = JIM_ERR;
+                                       break;
+                               }
+                               /* read start position */
+                               e = Jim_GetOpt_Wide(&goi, &start_position);
+                               if (e != JIM_OK)
+                                       break;
+
+                               bitfields[cur_field].start = start_position;
+                               bitfields[cur_field].end = start_position;
+
+                               /* 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")) {
+                                               e = Jim_GetOpt_Wide(&goi, 
&end_position);
+                                               if (e != JIM_OK)
+                                                       break;
+                                               bitfields[cur_field].end = 
end_position;
+                                               bitfields[cur_field].type = 
REG_TYPE_INT;
+                                       }
+
+                               fields[cur_field].bitfield = 
&(bitfields[cur_field]);
+                               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");
+               e = JIM_ERR;
+       }
+
+       if (e == JIM_OK) {
+               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");
+                       e = JIM_ERR;
+               } else {
+                       arc_add_reg_data_type(target, type);
+               }
+       }
+
+       if (e != JIM_OK) {
+               free((void *)type->data_type.id);
+               free(type);
+               free(flags);
+               /* `fields` is zeroed, so for uninitialized fields "name" is 
NULL. */
+               for (unsigned int i = 0; i < fields_sz; i++)
+                       free((void *)fields[i].name);
+               free(fields);
+               free(bitfields);
+               return e;
+       }
+
+       LOG_DEBUG("added flags type {name=%s}", type->data_type.id);
+
+       return JIM_OK;
+}
+
+/* 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_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_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_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 > 63 || regnum == 61 || regnum == 62) {
+               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_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 > 63 || regnum == 61 || regnum == 62) {
+               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 = "<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 = "<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 = "<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 = "<regnum> [<value>]"
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+
+/* This function supports only bitfields. */
+int jim_arc_add_reg_type_struct(Jim_Interp *interp, int argc,
+       Jim_Obj * const *argv)
+{
+       Jim_GetOptInfo goi;
+       Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1);
+
+       LOG_DEBUG("-");
+
+       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;
+
+       struct arc_reg_data_type *type = calloc(1, sizeof(struct 
arc_reg_data_type));
+       struct reg_data_type_struct *struct_type =
+               calloc(1, sizeof(struct reg_data_type_struct));
+       struct reg_data_type_struct_field *fields =
+               calloc(fields_sz, sizeof(struct reg_data_type_struct_field));
+       struct reg_data_type_bitfield *bitfields =
+               calloc(fields_sz, sizeof(struct reg_data_type_bitfield));
+
+       if (!(type && struct_type && fields && bitfields)) {
+               free(type);
+               free(struct_type);
+               free(fields);
+               free(bitfields);
+               Jim_SetResultFormatted(goi.interp, "Failed to allocate 
memory.");
+               return JIM_ERR;
+       }
+
+       /* Initialize type */
+       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;
+                               int name_len;
+                               if (goi.argc == 0) {
+                                       Jim_WrongNumArgs(interp, goi.argc, 
goi.argv, "-name ?name? ...");
+                                       e = JIM_ERR;
+                                       break;
+                               }
+
+                               e = Jim_GetOpt_String(&goi, &name, &name_len);
+                               if (e == JIM_OK) {
+                                       type->data_type.id = strndup(name, 
name_len);
+                                       if (!type->data_type.id)
+                                               e = JIM_ERR;
+                               }
+
+                               break;
+                       }
+                       case CFG_ADD_REG_TYPE_STRUCT_BITFIELD:
+                       {
+                               const char *field_name;
+                               int field_name_len;
+                               jim_wide start, end;
+
+                               if (goi.argc < 3) {
+                                       Jim_WrongNumArgs(interp, goi.argc, 
goi.argv,
+                                               "-bitfield ?name? ?start? ?end? 
...");
+                                       e = JIM_ERR;
+                                       break;
+                               }
+
+                               /* Field name */
+                               e = Jim_GetOpt_String(&goi, &field_name, 
&field_name_len);
+                               if (e != JIM_OK)
+                                       break;
+
+                               /* Bit-field start */
+                               e = Jim_GetOpt_Wide(&goi, &start);
+                               if (e != JIM_OK)
+                                       break;
+
+                               /* Bit-field end */
+                               e = Jim_GetOpt_Wide(&goi, &end);
+                               if (e != JIM_OK)
+                                       break;
+
+                               fields[cur_field].name = strndup(field_name, 
field_name_len);
+                               if (!fields[cur_field].name) {
+                                       e = JIM_ERR;
+                                       break;
+                               }
+                               bitfields[cur_field].start = start;
+                               bitfields[cur_field].end = end;
+                               bitfields[cur_field].type = REG_TYPE_INT;
+                               fields[cur_field].bitfield = 
&(bitfields[cur_field]);
+                               /* Only bitfields are supported so far. */
+                               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");
+               e = JIM_ERR;
+       }
+
+       if (e == JIM_OK) {
+               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");
+                       e = JIM_ERR;
+               } else {
+                       arc_add_reg_data_type(target, type);
+               }
+       }
+
+       if (e != JIM_OK) {
+               free((void *)type->data_type.id);
+               free(type);
+               free(struct_type);
+               /* `fields` is zeroed, so for uninitialized fields "name" is 
NULL. */
+               for (unsigned int i = 0; i < fields_sz; i++)
+                       free((void *)fields[i].name);
+               free(fields);
+               free(bitfields);
+               return e;
+       }
+
+       LOG_DEBUG("added struct type {name=%s}", type->data_type.id);
+
+       return JIM_OK;
+}
+
+/* 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 }
+};
+
+static void free_reg_desc(struct arc_reg_desc *r)
+{
+       if (r) {
+               if (r->name)
+                       free(r->name);
+               if (r->gdb_xml_feature)
+                       free(r->gdb_xml_feature);
+               free(r);
+       }
+}
+
+int jim_arc_add_reg(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+{
+       Jim_GetOptInfo goi;
+       Jim_GetOpt_Setup(&goi, interp, argc-1, argv+1);
+
+       LOG_DEBUG("-");
+
+       struct arc_reg_desc *reg = calloc(1, sizeof(struct arc_reg_desc));
+       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;
+                               int reg_name_len;
+
+                               if (goi.argc == 0) {
+                                       free_reg_desc(reg);
+                                       Jim_WrongNumArgs(interp, goi.argc, 
goi.argv, "-name ?name? ...");
+                                       return JIM_ERR;
+                               }
+
+                               e = Jim_GetOpt_String(&goi, &reg_name, 
&reg_name_len);
+                               if (e != JIM_OK) {
+                                       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 == 0) {
+                                       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;
+                               int feature_len;
+
+                               if (goi.argc == 0) {
+                                       free_reg_desc(reg);
+                                       Jim_WrongNumArgs(interp, goi.argc, 
goi.argv, "-feature ?name? ...");
+                                       return JIM_ERR;
+                               }
+
+                               e = Jim_GetOpt_String(&goi, &feature, 
&feature_len);
+                               if (e != JIM_OK) {
+                                       free_reg_desc(reg);
+                                       return e;
+                               }
+
+                               reg->gdb_xml_feature = strndup(feature, 
feature_len);
+                               break;
+                       }
+                       case CFG_ADD_REG_TYPE:
+                               if (goi.argc == 0) {
+                                       free_reg_desc(reg);
+                                       Jim_WrongNumArgs(interp, goi.argc, 
goi.argv, "-type ?type? ...");
+                                       return JIM_ERR;
+                               }
+
+                               e = Jim_GetOpt_String(&goi, &type_name, 
&type_name_len);
+                               if (e != JIM_OK) {
+                                       free_reg_desc(reg);
+                                       return e;
+                               }
+
+                               break;
+                       case CFG_ADD_REG_GENERAL:
+                               reg->is_general = true;
+                               break;
+                       default:
+                               LOG_DEBUG("Error: Unknown parameter");
+                               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;
+       }
+
+       e = arc_add_reg(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 (CMD_ARGC == 0) {
+               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_register_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 */
+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_GetOpt_Setup(&goi, interp, argc-1, argv+1);
+
+       LOG_DEBUG("Reading register field");
+       if (goi.argc != 2) {
+               if (goi.argc == 0)
+                       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_get_register_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 = "-name ?string? (-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 = "-name ?string? (-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 = "-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?+",
+               .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 = "?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
index 0000000..b8d58f8
--- /dev/null
+++ b/src/target/arc_cmd.h
@@ -0,0 +1,27 @@
+/***************************************************************************
+ *   Copyright (C) 2013-2014,2019 Synopsys, Inc.                           *
+ *   Frank Dols <[email protected]>                                  *
+ *   Mischa Jonker <[email protected]>                            *
+ *   Anton Kolesov <[email protected]>                            *
+ *   Evgeniy Didin <[email protected]>
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ ***************************************************************************/
+
+#ifndef ARC_CMD_H
+#define ARC_CMD_H
+
+extern const struct command_registration arc_monitor_command_handlers[];
+
+#endif /* ARC_CMD_H */
diff --git a/src/target/arc_jtag.c b/src/target/arc_jtag.c
new file mode 100644
index 0000000..dad4b14
--- /dev/null
+++ b/src/target/arc_jtag.c
@@ -0,0 +1,624 @@
+/***************************************************************************
+ *   Copyright (C) 2013-2014,2019 Synopsys, Inc.                           *
+ *   Frank Dols <[email protected]>                                  *
+ *   Mischa Jonker <[email protected]>                            *
+ *   Anton Kolesov <[email protected]>                            *
+ *   Evgeniy Didin <[email protected]>
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "arc.h"
+
+/* ----- Supporting functions ---------------------------------------------- */
+typedef enum arc_jtag_reg_type {
+       ARC_JTAG_CORE_REG,
+       ARC_JTAG_AUX_REG
+} reg_type_t;
+
+/* Declare functions */
+static void arc_jtag_write_ir(struct arc_jtag *jtag_info, uint32_t
+       new_instr);
+static void arc_jtag_read_dr(struct arc_jtag *jtag_info, uint8_t *data,
+       tap_state_t end_state);
+static void arc_jtag_write_dr(struct arc_jtag *jtag_info, uint32_t data,
+       tap_state_t end_state);
+
+static void arc_jtag_set_transaction(struct arc_jtag *jtag_info,
+       arc_jtag_transaction_t new_trans, tap_state_t end_state);
+static void arc_jtag_reset_transaction(struct arc_jtag *jtag_info);
+
+static int arc_jtag_write_registers(struct arc_jtag *jtag_info, reg_type_t 
type,
+       uint32_t *addr, uint32_t count, const uint32_t *buffer);
+static int arc_jtag_read_registers(struct arc_jtag *jtag_info, reg_type_t type,
+       uint32_t *addr, uint32_t count, uint32_t *buffer);
+/**
+ * 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_write_ir(struct arc_jtag *jtag_info, uint32_t
+               new_instr)
+{
+       uint32_t current_instr;
+       struct jtag_tap *tap;
+       /* Create scan field to output new instruction. */
+       struct scan_field field;
+       uint8_t instr_buffer[4];
+
+       assert(jtag_info != NULL);
+       assert(jtag_info->tap != NULL);
+
+       tap = jtag_info->tap;
+
+       /* Set end state */
+       jtag_info->tap_end_state = TAP_IRPAUSE;
+
+       /* 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;
+
+       field.num_bits = tap->ir_length;
+       field.in_value = NULL;
+       buf_set_u32(instr_buffer, 0, field.num_bits, new_instr);
+       field.out_value = instr_buffer;
+
+       /* 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, jtag_info->tap_end_state);
+}
+
+/**
+ * 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_read_dr(struct arc_jtag *jtag_info, uint8_t *data,
+               tap_state_t end_state)
+{
+       struct scan_field field;
+
+       assert(jtag_info != NULL);
+       assert(jtag_info->tap != NULL);
+
+       jtag_info->tap_end_state = end_state;
+       field.num_bits = 32;
+       field.in_value = data;
+       field.out_value = NULL;
+       jtag_add_dr_scan(jtag_info->tap, 1, &field, jtag_info->tap_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_write_dr(struct arc_jtag *jtag_info, uint32_t data,
+               tap_state_t end_state)
+{
+       uint8_t out_value[4];
+       struct scan_field field;
+
+       assert(jtag_info != NULL);
+       assert(jtag_info->tap != NULL);
+
+       jtag_info->tap_end_state = end_state;
+       buf_set_u32(out_value, 0, 32, data);
+       field.num_bits = 32;
+       field.out_value = out_value;
+       field.in_value = NULL;
+       jtag_add_dr_scan(jtag_info->tap, 1, &field, jtag_info->tap_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_set_transaction(struct arc_jtag *jtag_info,
+               arc_jtag_transaction_t new_trans, tap_state_t end_state)
+{
+       uint8_t out_value[4];
+       struct scan_field field;
+
+       assert(jtag_info != NULL);
+       assert(jtag_info->tap != NULL);
+
+       /* 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_write_ir(jtag_info, ARC_TRANSACTION_CMD_REG);
+       buf_set_u32(out_value, 0, ARC_TRANSACTION_CMD_REG_LENGTH, new_trans);
+       field.num_bits = ARC_TRANSACTION_CMD_REG_LENGTH;
+       field.out_value = out_value;
+       field.in_value = NULL;
+
+       jtag_info->tap_end_state = end_state;
+       jtag_add_dr_scan(jtag_info->tap, 1, &field, jtag_info->tap_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_reset_transaction(struct arc_jtag *jtag_info)
+{
+       arc_jtag_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_write_ir(jtag_info, ARC_JTAG_STATUS_REG);
+       /* Now reading dr performs jtag status register read */
+       arc_jtag_read_dr(jtag_info, buffer, TAP_IDLE);
+}
+
+/* ----- Exported JTAG functions ------------------------------------------- */
+
+int arc_jtag_startup(struct arc_jtag *jtag_info)
+{
+       assert(jtag_info);
+
+       arc_jtag_reset_transaction(jtag_info);
+       CHECK_RETVAL(jtag_execute_queue());
+
+       return ERROR_OK;
+}
+
+int arc_jtag_shutdown(struct arc_jtag *jtag_info)
+{
+       LOG_WARNING("arc_jtag_shutdown not implemented");
+       return ERROR_OK;
+}
+
+/** Read STATUS register. */
+int arc_jtag_status(struct arc_jtag * const jtag_info, uint32_t * const value)
+{
+       uint8_t buffer[4];
+
+       assert(jtag_info != NULL);
+       assert(jtag_info->tap != NULL);
+
+       /* Fill command queue. */
+       arc_jtag_reset_transaction(jtag_info);
+       arc_jtag_enque_status_read(jtag_info, buffer);
+       arc_jtag_reset_transaction(jtag_info);
+
+       /* Execute queue. */
+       CHECK_RETVAL(jtag_execute_queue());
+
+       /* Parse output. */
+       *value = buf_get_u32(buffer, 0, 32);
+
+       return ERROR_OK;
+}
+
+/** Read IDCODE register. */
+int arc_jtag_idcode(struct arc_jtag * const jtag_info, uint32_t * const value)
+{
+       uint8_t buffer[4];
+
+       assert(jtag_info != NULL);
+       assert(jtag_info->tap != NULL);
+
+       LOG_DEBUG("Reading IDCODE register.");
+
+       /* Fill command queue. */
+       arc_jtag_reset_transaction(jtag_info);
+       arc_jtag_write_ir(jtag_info, ARC_IDCODE_REG);
+       arc_jtag_read_dr(jtag_info, buffer, TAP_IDLE);
+       arc_jtag_reset_transaction(jtag_info);
+
+       /* Execute queue. */
+       CHECK_RETVAL(jtag_execute_queue());
+
+       /* Parse output. */
+       *value = buf_get_u32(buffer, 0, 32);
+       LOG_DEBUG("IDCODE register=0x%08" PRIx32, *value);
+
+       return ERROR_OK;
+}
+
+
+/**
+ * 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, reg_type_t 
type,
+       uint32_t *addr, uint32_t count, const uint32_t *buffer)
+{
+       unsigned int i;
+
+       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 == 0) {
+               LOG_WARNING("Trying to read 0 registers");
+               return ERROR_OK;
+       }
+
+       arc_jtag_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_set_transaction(jtag_info, transaction, TAP_DRPAUSE);
+
+       for (i = 0; i < count; i++) {
+               /* Some of AUX registers are sequential, so we need to set 
address only
+                * for the first one in sequence. */
+               if (i == 0 || (addr[i] != addr[i-1] + 1)) {
+                       arc_jtag_write_ir(jtag_info, ARC_ADDRESS_REG);
+                       arc_jtag_write_dr(jtag_info, addr[i], TAP_DRPAUSE);
+                       /* No need to set ir each time, but only if current ir 
is
+                        * different. It is safe to put it into the if body, 
because this
+                        * if is always executed in first iteration. */
+                       arc_jtag_write_ir(jtag_info, ARC_DATA_REG);
+               }
+               arc_jtag_write_dr(jtag_info, *(buffer + i), TAP_IDLE);
+       }
+
+       arc_jtag_reset_transaction(jtag_info);
+
+       /* Execute queue. */
+       CHECK_RETVAL(jtag_execute_queue());
+       return ERROR_OK;
+}
+
+/**
+ * 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, reg_type_t type,
+               uint32_t *addr, uint32_t count, uint32_t *buffer)
+{
+       int retval = ERROR_OK;
+       uint32_t i;
+
+       assert(jtag_info != NULL);
+       assert(jtag_info->tap != NULL);
+
+       LOG_DEBUG("Reading %s registers: addr[0]=0x%" PRIx32 ";count=%" PRIu32,
+               (type == ARC_JTAG_CORE_REG ? "core" : "aux"), *addr, count);
+
+       if (count == 0) {
+               LOG_WARNING("Trying to read 0 registers");
+               return ERROR_OK;
+       }
+
+       arc_jtag_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_set_transaction(jtag_info, transaction, TAP_DRPAUSE);
+
+       struct scan_field *fields = calloc(sizeof(struct scan_field), count);
+       uint8_t *data_buf = calloc(sizeof(uint8_t), count * 4);
+
+       for (i = 0; i < count; i++) {
+               /* Some of registers are sequential, so we need to set address 
only
+                * for the first one in sequence. */
+               if (i == 0 || (addr[i] != addr[i-1] + 1)) {
+                       /* Set address of register */
+                       arc_jtag_write_ir(jtag_info, ARC_ADDRESS_REG);
+                       arc_jtag_write_dr(jtag_info, addr[i], TAP_IDLE);  /* 
TAP_IDLE or TAP_DRPAUSE? ?*/
+                       arc_jtag_write_ir(jtag_info, ARC_DATA_REG);
+               }
+
+               arc_jtag_read_dr(jtag_info, data_buf + i * 4, TAP_IDLE);
+       }
+
+       /* Resetting transaction after reads or
+        * writes is not really required, it is done more as a sanity check.
+        * That is however done in a separate JTAG queue flush, since time
+        * since the previous queue flush should be practically enough to do
+        * any pending operations, if there were. That seems like not a very
+        * reliable approach and might be reconsidered in future. */
+       arc_jtag_reset_transaction(jtag_info);
+       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);
+       free(fields);
+
+       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 != NULL);
+       assert(buffer != NULL);
+
+       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 == 0)
+               return ERROR_OK;
+
+       /* We do not know where we come from. */
+       arc_jtag_reset_transaction(jtag_info);
+
+       /* We want to write to memory. */
+       arc_jtag_set_transaction(jtag_info, ARC_JTAG_WRITE_TO_MEMORY, 
TAP_DRPAUSE);
+
+       /* Set target memory address of the first word. */
+       arc_jtag_write_ir(jtag_info, ARC_ADDRESS_REG);
+       arc_jtag_write_dr(jtag_info, addr, TAP_DRPAUSE);
+
+       /* Start sending words. Address is auto-incremented on 4bytes by HW. */
+       arc_jtag_write_ir(jtag_info, ARC_DATA_REG);
+
+       uint32_t i;
+       for (i = 0; i < count; i++)
+               arc_jtag_write_dr(jtag_info, *(buffer + i), TAP_IDLE);
+
+       CHECK_RETVAL(jtag_execute_queue());
+
+       return ERROR_OK;
+}
+
+/**
+ * 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 != NULL);
+       assert(jtag_info->tap != NULL);
+
+       LOG_DEBUG("Reading memory: addr=0x%" PRIx32 ";count=%" PRIu32 
";slow=%c",
+               addr, count, slow_memory ? 'Y' : 'N');
+
+       if (count == 0)
+               return ERROR_OK;
+
+       data_buf = calloc(sizeof(uint8_t), count * 4);
+       arc_jtag_reset_transaction(jtag_info);
+
+       /* We are reading from memory. */
+       arc_jtag_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_write_ir(jtag_info, ARC_ADDRESS_REG);
+                   arc_jtag_write_dr(jtag_info, addr + i * 4, TAP_IDLE);
+
+                   arc_jtag_write_ir(jtag_info, ARC_DATA_REG);
+               }
+               arc_jtag_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
index 0000000..8c2a940
--- /dev/null
+++ b/src/target/arc_jtag.h
@@ -0,0 +1,101 @@
+/***************************************************************************
+ *   Copyright (C) 2013-2014,2019 Synopsys, Inc.                           *
+ *   Frank Dols <[email protected]>                                  *
+ *   Mischa Jonker <[email protected]>                            *
+ *   Anton Kolesov <[email protected]>                            *
+ *   Evgeniy Didin <[email protected]>
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ ***************************************************************************/
+
+#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
+/* Jtag status register field */
+#define ARC_JTAG_STAT_ST               0x1
+#define ARC_JTAG_STAT_FL               0x2
+#define ARC_JTAG_STAT_RD               0x4
+#define ARC_JTAG_STAT_NIU              0x8 /* Not in use */
+#define ARC_JTAG_STAT_RU               0x10
+#define ARC_JTAG_STAT_RA               0x20
+
+#define ARC_IDCODE_REG        0xC /* ARC core type information */
+#define ARC_ADDRESS_REG                                0xA /* SoC address to 
access */
+#define ARC_DATA_REG                           0xB /* Data read/written from 
SoC */
+
+
+
+typedef enum arc_jtag_transaction {
+       ARC_JTAG_WRITE_TO_MEMORY = 0x0,
+       ARC_JTAG_WRITE_TO_CORE_REG = 0x1,
+       ARC_JTAG_WRITE_TO_AUX_REG = 0x2,
+       ARC_JTAG_CMD_NOP = 0x3,
+       ARC_JTAG_READ_FROM_MEMORY = 0x4,
+       ARC_JTAG_READ_FROM_CORE_REG = 0x5,
+       ARC_JTAG_READ_FROM_AUX_REG = 0x6,
+} arc_jtag_transaction_t;
+
+#ifndef ARC_JTAG_H
+#define ARC_JTAG_H
+
+struct arc_jtag {
+       struct jtag_tap *tap;
+       uint32_t tap_end_state;
+       uint32_t intest_instr;
+       uint32_t cur_trans;
+
+       uint32_t scann_size;
+       uint32_t scann_instr;
+       uint32_t cur_scan_chain;
+
+       uint32_t dpc; /* Debug PC value */
+
+       int fast_access_save;
+       bool always_check_status_rd;
+       bool check_status_fl;
+       bool wait_until_write_finished;
+};
+
+/* ----- Exported JTAG functions ------------------------------------------- */
+
+int arc_jtag_startup(struct arc_jtag *jtag_info);
+int arc_jtag_shutdown(struct arc_jtag *jtag_info);
+int arc_jtag_status(struct arc_jtag *const jtag_info, uint32_t *const value);
+int arc_jtag_idcode(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 /* ARC_JTAG_H */
diff --git a/src/target/arc_mem.c b/src/target/arc_mem.c
new file mode 100644
index 0000000..8368482
--- /dev/null
+++ b/src/target/arc_mem.c
@@ -0,0 +1,314 @@
+/***************************************************************************
+ *   Copyright (C) 2013-2014,2019 Synopsys, Inc.                           *
+ *   Frank Dols <[email protected]>                                  *
+ *   Mischa Jonker <[email protected]>                            *
+ *   Anton Kolesov <[email protected]>                            *
+ *   Evgeniy Didin <[email protected]>                                    *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ ***************************************************************************/
+
+#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));
+       /* Invalidate caches. */
+       /*CHECK_RETVAL(arc_cache_invalidate(target));*/
+
+       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));
+
+       /* We will read data from memory, so we need to flush D$. */
+       /*CHECK_RETVAL(arc_dcache_flush(target));*/
+
+       /* 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));
+       }
+
+       /* Invalidate caches. */
+       /* CHECK_RETVAL(arc_cache_invalidate(target)); */
+
+       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);
+
+       /* We will read data from memory, so we need to flush D$. */
+       /* CHECK_RETVAL(arc_dcache_flush(target)); */
+
+       /* 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));
+       }
+
+       /* Invalidate caches. */
+       /* CHECK_RETVAL(arc_cache_invalidate(target)); */
+
+       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 == 0) || 
!(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 = malloc(count * size * sizeof(uint8_t));
+               if (tunnel == NULL) {
+                       LOG_ERROR("Out of 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);
+       }
+
+       if (tunnel != NULL)
+               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);
+
+       /* Always call D$ flush, it will decide whether to perform actual
+        * flush.  */
+       /* TODO: introduce arc_dcache_flush function */
+       /* CHECK_RETVAL(arc32_dcache_flush(target)); */
+       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 == 0) || 
!(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 = malloc(bytes_to_read);
+       tunnel_te = malloc(bytes_to_read);
+       if (!tunnel_he || !tunnel_te) {
+               LOG_ERROR("Out of 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
index 0000000..88a1dbc
--- /dev/null
+++ b/src/target/arc_mem.h
@@ -0,0 +1,32 @@
+/***************************************************************************
+ *   Copyright (C) 2013-2014,2019 Synopsys, Inc.                           *
+ *   Frank Dols <[email protected]>                                  *
+ *   Anton Kolesov <[email protected]>                            *
+ *   Evgeniy Didin <[email protected]>                                    *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ ***************************************************************************/
+
+#ifndef ARC_MEM_H
+#define 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 /* ARC_MEM_H */
diff --git a/src/target/arc_v2.c b/src/target/arc_v2.c
new file mode 100644
index 0000000..6459297
--- /dev/null
+++ b/src/target/arc_v2.c
@@ -0,0 +1,99 @@
+/***************************************************************************
+ *   Copyright (C) 2013-2015,2019 Synopsys, Inc.                           *
+ *   Frank Dols <[email protected]>                                  *
+ *   Mischa Jonker <[email protected]>                            *
+ *   Anton Kolesov <[email protected]>                            *
+ *   Evgeniy Didin <[email protected]>
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "arc.h"
+
+static int arc_v2_init_target(struct command_context *cmd_ctx, struct target 
*target)
+{
+  /* Will be uncommented in register introdution patch. */
+       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 int arc_v2_target_create(struct target *target, Jim_Interp *interp)
+{
+       struct arc_common *arc = calloc(1, sizeof(struct arc_common));
+
+       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_v2_target_create,
+       .init_target = arc_v2_init_target,
+       .examine = arc_examine,
+
+       .virt2phys = NULL,
+       .read_phys_memory = NULL,
+       .write_phys_memory = NULL,
+       .mmu = NULL,
+};
diff --git a/src/target/target.c b/src/target/target.c
index 2bfbd57..e35ad0d 100644
--- a/src/target/target.c
+++ b/src/target/target.c
@@ -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 arcv2_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,
+       &arcv2_target,
 #if BUILD_TARGET64
        &aarch64_target,
        &mips_mips64_target,

-- 


_______________________________________________
OpenOCD-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to