]> git.sur5r.net Git - openocd/commitdiff
nds32: add new target type nds32_v2, nds32_v3, nds32_v3m
authorHsiangkai Wang <hsiangkai@gmail.com>
Tue, 5 Feb 2013 03:55:37 +0000 (11:55 +0800)
committerSpencer Oliver <spen@spen-soft.co.uk>
Wed, 5 Jun 2013 19:27:35 +0000 (19:27 +0000)
Add target code for Andes targets.

Change-Id: Ibf0e1b61b06127ca7d9ed502d98d7e2aeebbbe82
Signed-off-by: Hsiangkai Wang <hsiangkai@gmail.com>
Reviewed-on: http://openocd.zylin.com/1259
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
28 files changed:
src/target/Makefile.am
src/target/nds32.c [new file with mode: 0644]
src/target/nds32.h
src/target/nds32_aice.c [new file with mode: 0644]
src/target/nds32_aice.h [new file with mode: 0644]
src/target/nds32_cmd.c [new file with mode: 0644]
src/target/nds32_cmd.h [new file with mode: 0644]
src/target/nds32_disassembler.c [new file with mode: 0644]
src/target/nds32_disassembler.h [new file with mode: 0644]
src/target/nds32_edm.h
src/target/nds32_insn.h
src/target/nds32_reg.c
src/target/nds32_reg.h
src/target/nds32_tlb.c [new file with mode: 0644]
src/target/nds32_tlb.h [new file with mode: 0644]
src/target/nds32_v2.c [new file with mode: 0644]
src/target/nds32_v2.h [new file with mode: 0644]
src/target/nds32_v3.c [new file with mode: 0644]
src/target/nds32_v3.h [new file with mode: 0644]
src/target/nds32_v3_common.c [new file with mode: 0644]
src/target/nds32_v3_common.h [new file with mode: 0644]
src/target/nds32_v3m.c [new file with mode: 0644]
src/target/nds32_v3m.h [new file with mode: 0644]
src/target/target.c
tcl/board/nds32_xc5.cfg [new file with mode: 0644]
tcl/target/nds32v2.cfg [new file with mode: 0644]
tcl/target/nds32v3.cfg [new file with mode: 0644]
tcl/target/nds32v3m.cfg [new file with mode: 0644]

index 8e9dfb6d21e38fadbe7760c3356a83ee3993ea54..027cc8e7308389c5710ae75306a48f2bba3a1dda 100644 (file)
@@ -109,7 +109,16 @@ MIPS32_SRC = \
        mips_ejtag.c
 
 NDS32_SRC = \
-       nds32_reg.c
+       nds32.c \
+       nds32_reg.c \
+       nds32_cmd.c \
+       nds32_disassembler.c \
+       nds32_tlb.c \
+       nds32_v2.c \
+       nds32_v3_common.c \
+       nds32_v3.c \
+       nds32_v3m.c \
+       nds32_aice.c
 
 
 noinst_HEADERS = \
@@ -168,9 +177,17 @@ noinst_HEADERS = \
        avr32_mem.h \
        avr32_regs.h \
        nds32.h \
+       nds32_cmd.h \
+       nds32_disassembler.h \
        nds32_edm.h \
        nds32_insn.h \
-       nds32_reg.h
+       nds32_reg.h \
+       nds32_tlb.h \
+       nds32_v2.h \
+       nds32_v3_common.h \
+       nds32_v3.h \
+       nds32_v3m.h \
+       nds32_aice.h
 
 ocddatadir = $(pkglibdir)
 nobase_dist_ocddata_DATA =
diff --git a/src/target/nds32.c b/src/target/nds32.c
new file mode 100644 (file)
index 0000000..2d47709
--- /dev/null
@@ -0,0 +1,2156 @@
+/***************************************************************************
+ *   Copyright (C) 2013 Andes Technology                                   *
+ *   Hsiangkai Wang <hkwang@andestech.com>                                 *
+ *                                                                         *
+ *   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                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <helper/log.h>
+#include <helper/binarybuffer.h>
+#include "nds32.h"
+#include "nds32_aice.h"
+#include "nds32_tlb.h"
+#include "nds32_disassembler.h"
+
+const int NDS32_BREAK_16 = 0x00EA;      /* 0xEA00 */
+const int NDS32_BREAK_32 = 0x0A000064;  /* 0x6400000A */
+
+struct nds32_edm_operation nds32_edm_ops[NDS32_EDM_OPERATION_MAX_NUM];
+uint32_t nds32_edm_ops_num;
+
+const char *nds32_debug_type_name[11] = {
+       "SOFTWARE BREAK",
+       "SOFTWARE BREAK_16",
+       "HARDWARE BREAKPOINT",
+       "DATA ADDR WATCHPOINT PRECISE",
+       "DATA VALUE WATCHPOINT PRECISE",
+       "DATA VALUE WATCHPOINT IMPRECISE",
+       "DEBUG INTERRUPT",
+       "HARDWARE SINGLE STEP",
+       "DATA ADDR WATCHPOINT NEXT PRECISE",
+       "DATA VALUE WATCHPOINT NEXT PRECISE",
+       "LOAD STORE GLOBAL STOP",
+};
+
+static const int NDS32_LM_SIZE_TABLE[16] = {
+       4 * 1024,
+       8 * 1024,
+       16 * 1024,
+       32 * 1024,
+       64 * 1024,
+       128 * 1024,
+       256 * 1024,
+       512 * 1024,
+       1024 * 1024,
+       1 * 1024,
+       2 * 1024,
+};
+
+static const int NDS32_LINE_SIZE_TABLE[6] = {
+       0,
+       8,
+       16,
+       32,
+       64,
+       128,
+};
+
+static int nds32_get_core_reg(struct reg *reg)
+{
+       int retval;
+       struct nds32_reg *reg_arch_info = reg->arch_info;
+       struct target *target = reg_arch_info->target;
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct aice_port_s *aice = target_to_aice(target);
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (reg->valid) {
+               LOG_DEBUG("reading register(cached) %i(%s), value: 0x%8.8" PRIx32,
+                               reg_arch_info->num, reg->name, reg_arch_info->value);
+               return ERROR_OK;
+       }
+
+       if (reg_arch_info->enable == false) {
+               reg_arch_info->value = NDS32_REGISTER_DISABLE;
+               retval = ERROR_FAIL;
+       } else {
+               if ((nds32->fpu_enable == false) &&
+                       (NDS32_REG_TYPE_FPU == nds32_reg_type(reg_arch_info->num))) {
+                       reg_arch_info->value = 0;
+                       retval = ERROR_OK;
+               } else if ((nds32->audio_enable == false) &&
+                       (NDS32_REG_TYPE_AUMR == nds32_reg_type(reg_arch_info->num))) {
+                       reg_arch_info->value = 0;
+                       retval = ERROR_OK;
+               } else {
+                       retval = aice_read_register(aice,
+                                       reg_arch_info->num, &(reg_arch_info->value));
+               }
+
+               LOG_DEBUG("reading register %i(%s), value: 0x%8.8" PRIx32,
+                               reg_arch_info->num, reg->name, reg_arch_info->value);
+       }
+
+       if (retval == ERROR_OK) {
+               reg->valid = true;
+               reg->dirty = false;
+       }
+
+       return retval;
+}
+
+static int nds32_get_core_reg_64(struct reg *reg)
+{
+       int retval;
+       struct nds32_reg *reg_arch_info = reg->arch_info;
+       struct target *target = reg_arch_info->target;
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct aice_port_s *aice = target_to_aice(target);
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if (reg->valid)
+               return ERROR_OK;
+
+       if (reg_arch_info->enable == false) {
+               reg_arch_info->value_64 = NDS32_REGISTER_DISABLE;
+               retval = ERROR_FAIL;
+       } else {
+               if ((nds32->fpu_enable == false) &&
+                       ((FD0 <= reg_arch_info->num) && (reg_arch_info->num <= FD31))) {
+                       reg_arch_info->value_64 = 0;
+                       retval = ERROR_OK;
+               } else {
+                       retval = aice_read_reg_64(aice, reg_arch_info->num,
+                                       &(reg_arch_info->value_64));
+               }
+       }
+
+       if (retval == ERROR_OK) {
+               reg->valid = true;
+               reg->dirty = false;
+       }
+
+       return retval;
+}
+
+static int nds32_update_psw(struct nds32 *nds32)
+{
+       uint32_t value_ir0;
+       struct aice_port_s *aice = target_to_aice(nds32->target);
+
+       nds32_get_mapped_reg(nds32, IR0, &value_ir0);
+
+       /* Save data memory endian */
+       if ((value_ir0 >> 5) & 0x1) {
+               nds32->data_endian = TARGET_BIG_ENDIAN;
+               aice_set_data_endian(aice, AICE_BIG_ENDIAN);
+       } else {
+               nds32->data_endian = TARGET_LITTLE_ENDIAN;
+               aice_set_data_endian(aice, AICE_LITTLE_ENDIAN);
+       }
+
+       /* Save translation status */
+       nds32->memory.address_translation = ((value_ir0 >> 7) & 0x1) ? true : false;
+
+       return ERROR_OK;
+}
+
+static int nds32_update_mmu_info(struct nds32 *nds32)
+{
+       uint32_t value;
+
+       /* Update MMU control status */
+       nds32_get_mapped_reg(nds32, MR0, &value);
+       nds32->mmu_config.default_min_page_size = value & 0x1;
+       nds32->mmu_config.multiple_page_size_in_use = (value >> 10) & 0x1;
+
+       return ERROR_OK;
+}
+
+static int nds32_update_cache_info(struct nds32 *nds32)
+{
+       uint32_t value;
+
+       if (ERROR_OK == nds32_get_mapped_reg(nds32, MR8, &value)) {
+               if (value & 0x1)
+                       nds32->memory.icache.enable = true;
+               else
+                       nds32->memory.icache.enable = false;
+
+               if (value & 0x2)
+                       nds32->memory.dcache.enable = true;
+               else
+                       nds32->memory.dcache.enable = false;
+       } else {
+               nds32->memory.icache.enable = false;
+               nds32->memory.dcache.enable = false;
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_update_lm_info(struct nds32 *nds32)
+{
+       struct nds32_memory *memory = &(nds32->memory);
+       uint32_t value_mr6;
+       uint32_t value_mr7;
+
+       nds32_get_mapped_reg(nds32, MR6, &value_mr6);
+       if (value_mr6 & 0x1)
+               memory->ilm_enable = true;
+       else
+               memory->ilm_enable = false;
+
+       if (memory->ilm_align_ver == 0) { /* 1MB aligned */
+               memory->ilm_start = value_mr6 & 0xFFF00000;
+               memory->ilm_end = memory->ilm_start + memory->ilm_size;
+       } else if (memory->ilm_align_ver == 1) { /* aligned to local memory size */
+               memory->ilm_start = value_mr6 & 0xFFFFFC00;
+               memory->ilm_end = memory->ilm_start + memory->ilm_size;
+       } else {
+               memory->ilm_start = -1;
+               memory->ilm_end = -1;
+       }
+
+       nds32_get_mapped_reg(nds32, MR7, &value_mr7);
+       if (value_mr7 & 0x1)
+               memory->dlm_enable = true;
+       else
+               memory->dlm_enable = false;
+
+       if (memory->dlm_align_ver == 0) { /* 1MB aligned */
+               memory->dlm_start = value_mr7 & 0xFFF00000;
+               memory->dlm_end = memory->dlm_start + memory->dlm_size;
+       } else if (memory->dlm_align_ver == 1) { /* aligned to local memory size */
+               memory->dlm_start = value_mr7 & 0xFFFFFC00;
+               memory->dlm_end = memory->dlm_start + memory->dlm_size;
+       } else {
+               memory->dlm_start = -1;
+               memory->dlm_end = -1;
+       }
+
+       return ERROR_OK;
+}
+
+/**
+ * If fpu/audio is disabled, to access fpu/audio registers will cause
+ * exceptions. So, we need to check if fpu/audio is enabled or not as
+ * target is halted. If fpu/audio is disabled, as users access fpu/audio
+ * registers, OpenOCD will return fake value 0 instead of accessing
+ * registers through DIM.
+ */
+static int nds32_check_extension(struct nds32 *nds32)
+{
+       uint32_t value;
+
+       nds32_get_mapped_reg(nds32, FUCPR, &value);
+       if (value == NDS32_REGISTER_DISABLE) {
+               nds32->fpu_enable = false;
+               nds32->audio_enable = false;
+               return ERROR_OK;
+       }
+
+       if (value & 0x1)
+               nds32->fpu_enable = true;
+       else
+               nds32->fpu_enable = false;
+
+       if (value & 0x80000000)
+               nds32->audio_enable = true;
+       else
+               nds32->audio_enable = false;
+
+       return ERROR_OK;
+}
+
+static int nds32_set_core_reg(struct reg *reg, uint8_t *buf)
+{
+       struct nds32_reg *reg_arch_info = reg->arch_info;
+       struct target *target = reg_arch_info->target;
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct aice_port_s *aice = target_to_aice(target);
+       uint32_t value = buf_get_u32(buf, 0, 32);
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* ignore values that will generate exception */
+       if (nds32_reg_exception(reg_arch_info->num, value))
+               return ERROR_OK;
+
+       LOG_DEBUG("writing register %i(%s) with value 0x%8.8" PRIx32,
+                       reg_arch_info->num, reg->name, value);
+
+       if ((nds32->fpu_enable == false) &&
+               (NDS32_REG_TYPE_FPU == nds32_reg_type(reg_arch_info->num))) {
+
+               buf_set_u32(reg->value, 0, 32, 0);
+       } else if ((nds32->audio_enable == false) &&
+               (NDS32_REG_TYPE_AUMR == nds32_reg_type(reg_arch_info->num))) {
+
+               buf_set_u32(reg->value, 0, 32, 0);
+       } else {
+               buf_set_u32(reg->value, 0, 32, value);
+               aice_write_register(aice, reg_arch_info->num, reg_arch_info->value);
+
+               /* After set value to registers, read the value from target
+                * to avoid W1C inconsistency. */
+               aice_read_register(aice, reg_arch_info->num, &(reg_arch_info->value));
+       }
+
+       reg->valid = true;
+       reg->dirty = false;
+
+       /* update registers to take effect right now */
+       if (IR0 == reg_arch_info->num) {
+               nds32_update_psw(nds32);
+       } else if (MR0 == reg_arch_info->num) {
+               nds32_update_mmu_info(nds32);
+       } else if ((MR6 == reg_arch_info->num) || (MR7 == reg_arch_info->num)) {
+               /* update lm information */
+               nds32_update_lm_info(nds32);
+       } else if (MR8 == reg_arch_info->num) {
+               nds32_update_cache_info(nds32);
+       } else if (FUCPR == reg_arch_info->num) {
+               /* update audio/fpu setting */
+               nds32_check_extension(nds32);
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_set_core_reg_64(struct reg *reg, uint8_t *buf)
+{
+       struct nds32_reg *reg_arch_info = reg->arch_info;
+       struct target *target = reg_arch_info->target;
+       struct nds32 *nds32 = target_to_nds32(target);
+       uint32_t low_part = buf_get_u32(buf, 0, 32);
+       uint32_t high_part = buf_get_u32(buf, 32, 32);
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       if ((nds32->fpu_enable == false) &&
+               ((FD0 <= reg_arch_info->num) && (reg_arch_info->num <= FD31))) {
+
+               buf_set_u32(reg->value, 0, 32, 0);
+               buf_set_u32(reg->value, 32, 32, 0);
+
+               reg->valid = true;
+               reg->dirty = false;
+       } else {
+               buf_set_u32(reg->value, 0, 32, low_part);
+               buf_set_u32(reg->value, 32, 32, high_part);
+
+               reg->valid = true;
+               reg->dirty = true;
+       }
+
+       return ERROR_OK;
+}
+
+static const struct reg_arch_type nds32_reg_access_type = {
+       .get = nds32_get_core_reg,
+       .set = nds32_set_core_reg,
+};
+
+static const struct reg_arch_type nds32_reg_access_type_64 = {
+       .get = nds32_get_core_reg_64,
+       .set = nds32_set_core_reg_64,
+};
+
+static struct reg_cache *nds32_build_reg_cache(struct target *target,
+               struct nds32 *nds32)
+{
+       struct reg_cache *cache = malloc(sizeof(struct reg_cache));
+       struct reg *reg_list = calloc(TOTAL_REG_NUM, sizeof(struct reg));
+       struct nds32_reg *reg_arch_info = calloc(TOTAL_REG_NUM, sizeof(struct nds32_reg));
+       int i;
+
+       if (!cache || !reg_list || !reg_arch_info) {
+               free(cache);
+               free(reg_list);
+               free(reg_arch_info);
+               return NULL;
+       }
+
+       cache->name = "Andes registers";
+       cache->next = NULL;
+       cache->reg_list = reg_list;
+       cache->num_regs = 0;
+
+       for (i = 0; i < TOTAL_REG_NUM; i++) {
+               reg_arch_info[i].num = i;
+               reg_arch_info[i].target = target;
+               reg_arch_info[i].nds32 = nds32;
+               reg_arch_info[i].enable = false;
+
+               reg_list[i].name = nds32_reg_simple_name(i);
+               reg_list[i].size = nds32_reg_size(i);
+               reg_list[i].arch_info = &reg_arch_info[i];
+
+               if (FD0 <= reg_arch_info[i].num && reg_arch_info[i].num <= FD31) {
+                       reg_list[i].value = &(reg_arch_info[i].value_64);
+                       reg_list[i].type = &nds32_reg_access_type_64;
+               } else {
+                       reg_list[i].value = &(reg_arch_info[i].value);
+                       reg_list[i].type = &nds32_reg_access_type;
+               }
+
+               cache->num_regs++;
+       }
+
+       nds32->core_cache = cache;
+
+       return cache;
+}
+
+static int nds32_reg_cache_init(struct target *target, struct nds32 *nds32)
+{
+       struct reg_cache *cache;
+
+       cache = nds32_build_reg_cache(target, nds32);
+       if (!cache)
+               return ERROR_FAIL;
+
+       *register_get_last_cache_p(&target->reg_cache) = cache;
+
+       return ERROR_OK;
+}
+
+static struct reg *nds32_reg_current(struct nds32 *nds32, unsigned regnum)
+{
+       struct reg *r;
+
+       /* Register mapping, pass user-view registers to gdb */
+       int mapped_regnum = nds32->register_map(nds32, regnum);
+       r = nds32->core_cache->reg_list + mapped_regnum;
+
+       return r;
+}
+
+int nds32_full_context(struct nds32 *nds32)
+{
+       uint32_t value, value_ir0;
+
+       /* save $pc & $psw */
+       nds32_get_mapped_reg(nds32, PC, &value);
+       nds32_get_mapped_reg(nds32, IR0, &value_ir0);
+
+       nds32_update_psw(nds32);
+       nds32_update_mmu_info(nds32);
+       nds32_update_cache_info(nds32);
+       nds32_update_lm_info(nds32);
+
+       nds32_check_extension(nds32);
+
+       return ERROR_OK;
+}
+
+/* get register value internally */
+int nds32_get_mapped_reg(struct nds32 *nds32, unsigned regnum, uint32_t *value)
+{
+       struct reg_cache *reg_cache = nds32->core_cache;
+       struct reg *r;
+
+       if (regnum > reg_cache->num_regs)
+               return ERROR_FAIL;
+
+       r = nds32_reg_current(nds32, regnum);
+
+       if (ERROR_OK != r->type->get(r))
+               return ERROR_FAIL;
+
+       *value = buf_get_u32(r->value, 0, 32);
+
+       return ERROR_OK;
+}
+
+/** set register internally */
+int nds32_set_mapped_reg(struct nds32 *nds32, unsigned regnum, uint32_t value)
+{
+       struct reg_cache *reg_cache = nds32->core_cache;
+       struct reg *r;
+       uint8_t set_value[4];
+
+       if (regnum > reg_cache->num_regs)
+               return ERROR_FAIL;
+
+       r = nds32_reg_current(nds32, regnum);
+
+       buf_set_u32(set_value, 0, 32, value);
+
+       return r->type->set(r, set_value);
+}
+
+/** get all register list */
+int nds32_get_gdb_reg_list(struct target *target,
+               struct reg **reg_list[], int *reg_list_size)
+{
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct reg_cache *reg_cache = nds32->core_cache;
+       unsigned int i;
+
+       *reg_list_size = reg_cache->num_regs;
+
+       /** freed in gdb_server.c */
+       *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
+
+       for (i = 0; i < reg_cache->num_regs; i++)
+               (*reg_list)[i] = nds32_reg_current(nds32, i);
+
+       return ERROR_OK;
+}
+
+static int nds32_select_memory_mode(struct target *target, uint32_t address,
+               uint32_t length, uint32_t *end_address)
+{
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct aice_port_s *aice = target_to_aice(target);
+       struct nds32_memory *memory = &(nds32->memory);
+       struct nds32_edm *edm = &(nds32->edm);
+       uint32_t dlm_start, dlm_end;
+       uint32_t ilm_start, ilm_end;
+       uint32_t address_end = address + length;
+
+       /* init end_address */
+       *end_address = address_end;
+
+       if (NDS_MEMORY_ACC_CPU == memory->access_channel)
+               return ERROR_OK;
+
+       if (edm->access_control == false) {
+               LOG_DEBUG("EDM does not support ACC_CTL");
+               return ERROR_OK;
+       }
+
+       if (edm->direct_access_local_memory == false) {
+               LOG_DEBUG("EDM does not support DALM");
+               aice_memory_mode(aice, NDS_MEMORY_SELECT_MEM);
+               return ERROR_OK;
+       }
+
+       if (NDS_MEMORY_SELECT_AUTO != memory->mode) {
+               LOG_DEBUG("Memory mode is not AUTO");
+               return ERROR_OK;
+       }
+
+       /* set default mode */
+       aice_memory_mode(aice, NDS_MEMORY_SELECT_MEM);
+
+       if ((memory->ilm_base != 0) && (memory->ilm_enable == true)) {
+               ilm_start = memory->ilm_start;
+               ilm_end = memory->ilm_end;
+
+               /* case 1, address < ilm_start */
+               if (address < ilm_start) {
+                       if (ilm_start < address_end) {
+                               /* update end_address to split non-ILM from ILM */
+                               *end_address = ilm_start;
+                       }
+                       /* MEM mode */
+                       aice_memory_mode(aice, NDS_MEMORY_SELECT_MEM);
+               } else if ((ilm_start <= address) && (address < ilm_end)) {
+                       /* case 2, ilm_start <= address < ilm_end */
+                       if (ilm_end < address_end) {
+                               /* update end_address to split non-ILM from ILM */
+                               *end_address = ilm_end;
+                       }
+                       /* ILM mode */
+                       aice_memory_mode(aice, NDS_MEMORY_SELECT_ILM);
+               } else { /* case 3, ilm_end <= address */
+                       /* MEM mode */
+                       aice_memory_mode(aice, NDS_MEMORY_SELECT_MEM);
+               }
+
+               return ERROR_OK;
+       } else {
+               LOG_DEBUG("ILM is not enabled");
+       }
+
+       if ((memory->dlm_base != 0) && (memory->dlm_enable == true)) {
+               dlm_start = memory->dlm_start;
+               dlm_end = memory->dlm_end;
+
+               /* case 1, address < dlm_start */
+               if (address < dlm_start) {
+                       if (dlm_start < address_end) {
+                               /* update end_address to split non-DLM from DLM */
+                               *end_address = dlm_start;
+                       }
+                       /* MEM mode */
+                       aice_memory_mode(aice, NDS_MEMORY_SELECT_MEM);
+               } else if ((dlm_start <= address) && (address < dlm_end)) {
+                       /* case 2, dlm_start <= address < dlm_end */
+                       if (dlm_end < address_end) {
+                               /* update end_address to split non-DLM from DLM */
+                               *end_address = dlm_end;
+                       }
+                       /* DLM mode */
+                       aice_memory_mode(aice, NDS_MEMORY_SELECT_DLM);
+               } else { /* case 3, dlm_end <= address */
+                       /* MEM mode */
+                       aice_memory_mode(aice, NDS_MEMORY_SELECT_MEM);
+               }
+
+               return ERROR_OK;
+       } else {
+               LOG_DEBUG("DLM is not enabled");
+       }
+
+       return ERROR_OK;
+}
+
+int nds32_read_buffer(struct target *target, uint32_t address,
+               uint32_t size, uint8_t *buffer)
+{
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct nds32_memory *memory = &(nds32->memory);
+
+       if ((NDS_MEMORY_ACC_CPU == memory->access_channel) &&
+                       (target->state != TARGET_HALTED)) {
+               LOG_WARNING("target was not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       LOG_DEBUG("READ BUFFER: ADDR %08" PRIx32 "  SIZE %08" PRIx32,
+                       address,
+                       size);
+
+       int retval = ERROR_OK;
+       struct aice_port_s *aice = target_to_aice(target);
+       uint32_t end_address;
+
+       if (((address % 2) == 0) && (size == 2)) {
+               nds32_select_memory_mode(target, address, 2, &end_address);
+               return aice_read_mem_unit(aice, address, 2, 1, buffer);
+       }
+
+       /* handle unaligned head bytes */
+       if (address % 4) {
+               uint32_t unaligned = 4 - (address % 4);
+
+               if (unaligned > size)
+                       unaligned = size;
+
+               nds32_select_memory_mode(target, address, unaligned, &end_address);
+               retval = aice_read_mem_unit(aice, address, 1, unaligned, buffer);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               buffer += unaligned;
+               address += unaligned;
+               size -= unaligned;
+       }
+
+       /* handle aligned words */
+       if (size >= 4) {
+               int aligned = size - (size % 4);
+               int read_len;
+
+               do {
+                       nds32_select_memory_mode(target, address, aligned, &end_address);
+
+                       read_len = end_address - address;
+
+                       if (read_len > 8)
+                               retval = aice_read_mem_bulk(aice, address, read_len, buffer);
+                       else
+                               retval = aice_read_mem_unit(aice, address, 4, read_len / 4, buffer);
+
+                       if (retval != ERROR_OK)
+                               return retval;
+
+                       buffer += read_len;
+                       address += read_len;
+                       size -= read_len;
+                       aligned -= read_len;
+
+               } while (aligned != 0);
+       }
+
+       /*prevent byte access when possible (avoid AHB access limitations in some cases)*/
+       if (size >= 2) {
+               int aligned = size - (size % 2);
+               nds32_select_memory_mode(target, address, aligned, &end_address);
+               retval = aice_read_mem_unit(aice, address, 2, aligned / 2, buffer);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               buffer += aligned;
+               address += aligned;
+               size -= aligned;
+       }
+       /* handle tail writes of less than 4 bytes */
+       if (size > 0) {
+               nds32_select_memory_mode(target, address, size, &end_address);
+               retval = aice_read_mem_unit(aice, address, 1, size, buffer);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       return ERROR_OK;
+}
+
+int nds32_read_memory(struct target *target, uint32_t address,
+               uint32_t size, uint32_t count, uint8_t *buffer)
+{
+       struct aice_port_s *aice = target_to_aice(target);
+
+       return aice_read_mem_unit(aice, address, size, count, buffer);
+}
+
+int nds32_read_phys_memory(struct target *target, uint32_t address,
+               uint32_t size, uint32_t count, uint8_t *buffer)
+{
+       struct aice_port_s *aice = target_to_aice(target);
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct nds32_memory *memory = &(nds32->memory);
+       enum nds_memory_access orig_channel;
+       int result;
+
+       /* switch to BUS access mode to skip MMU */
+       orig_channel = memory->access_channel;
+       memory->access_channel = NDS_MEMORY_ACC_BUS;
+       aice_memory_access(aice, memory->access_channel);
+
+       /* The input address is physical address.  No need to do address translation. */
+       result = aice_read_mem_unit(aice, address, size, count, buffer);
+
+       /* restore to origin access mode */
+       memory->access_channel = orig_channel;
+       aice_memory_access(aice, memory->access_channel);
+
+       return result;
+}
+
+int nds32_write_buffer(struct target *target, uint32_t address,
+               uint32_t size, const uint8_t *buffer)
+{
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct nds32_memory *memory = &(nds32->memory);
+
+       if ((NDS_MEMORY_ACC_CPU == memory->access_channel) &&
+                       (target->state != TARGET_HALTED)) {
+               LOG_WARNING("target was not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       LOG_DEBUG("WRITE BUFFER: ADDR %08" PRIx32 "  SIZE %08" PRIx32,
+                       address,
+                       size);
+
+       struct aice_port_s *aice = target_to_aice(target);
+       int retval = ERROR_OK;
+       uint32_t end_address;
+
+       if (((address % 2) == 0) && (size == 2)) {
+               nds32_select_memory_mode(target, address, 2, &end_address);
+               return aice_write_mem_unit(aice, address, 2, 1, buffer);
+       }
+
+       /* handle unaligned head bytes */
+       if (address % 4) {
+               uint32_t unaligned = 4 - (address % 4);
+
+               if (unaligned > size)
+                       unaligned = size;
+
+               nds32_select_memory_mode(target, address, unaligned, &end_address);
+               retval = aice_write_mem_unit(aice, address, 1, unaligned, buffer);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               buffer += unaligned;
+               address += unaligned;
+               size -= unaligned;
+       }
+
+       /* handle aligned words */
+       if (size >= 4) {
+               int aligned = size - (size % 4);
+               int write_len;
+
+               do {
+                       nds32_select_memory_mode(target, address, aligned, &end_address);
+
+                       write_len = end_address - address;
+                       if (write_len > 8)
+                               retval = aice_write_mem_bulk(aice, address, write_len, buffer);
+                       else
+                               retval = aice_write_mem_unit(aice, address, 4, write_len / 4, buffer);
+                       if (retval != ERROR_OK)
+                               return retval;
+
+                       buffer += write_len;
+                       address += write_len;
+                       size -= write_len;
+                       aligned -= write_len;
+
+               } while (aligned != 0);
+       }
+
+       /* handle tail writes of less than 4 bytes */
+       if (size > 0) {
+               nds32_select_memory_mode(target, address, size, &end_address);
+               retval = aice_write_mem_unit(aice, address, 1, size, buffer);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       return retval;
+}
+
+int nds32_write_memory(struct target *target, uint32_t address,
+               uint32_t size, uint32_t count, const uint8_t *buffer)
+{
+       struct aice_port_s *aice = target_to_aice(target);
+
+       return aice_write_mem_unit(aice, address, size, count, buffer);
+}
+
+int nds32_write_phys_memory(struct target *target, uint32_t address,
+               uint32_t size, uint32_t count, const uint8_t *buffer)
+{
+       struct aice_port_s *aice = target_to_aice(target);
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct nds32_memory *memory = &(nds32->memory);
+       enum nds_memory_access orig_channel;
+       int result;
+
+       /* switch to BUS access mode to skip MMU */
+       orig_channel = memory->access_channel;
+       memory->access_channel = NDS_MEMORY_ACC_BUS;
+       aice_memory_access(aice, memory->access_channel);
+
+       /* The input address is physical address.  No need to do address translation. */
+       result = aice_write_mem_unit(aice, address, size, count, buffer);
+
+       /* restore to origin access mode */
+       memory->access_channel = orig_channel;
+       aice_memory_access(aice, memory->access_channel);
+
+       return result;
+}
+
+int nds32_mmu(struct target *target, int *enabled)
+{
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("%s: target not halted", __func__);
+               return ERROR_TARGET_INVALID;
+       }
+
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct nds32_memory *memory = &(nds32->memory);
+       struct nds32_mmu_config *mmu_config = &(nds32->mmu_config);
+
+       if ((mmu_config->memory_protection == 2) && (memory->address_translation == true))
+               *enabled = 1;
+       else
+               *enabled = 0;
+
+       return ERROR_OK;
+}
+
+int nds32_arch_state(struct target *target)
+{
+       struct nds32 *nds32 = target_to_nds32(target);
+
+       if (nds32->common_magic != NDS32_COMMON_MAGIC) {
+               LOG_ERROR("BUG: called for a non-Andes target");
+               return ERROR_FAIL;
+       }
+
+       uint32_t value_pc, value_psw;
+
+       nds32_get_mapped_reg(nds32, PC, &value_pc);
+       nds32_get_mapped_reg(nds32, IR0, &value_psw);
+
+       LOG_USER("target halted due to %s\n"
+                       "psw: 0x%8.8" PRIx32 " pc: 0x%8.8" PRIx32 "%s",
+                       debug_reason_name(target),
+                       value_psw,
+                       value_pc,
+                       nds32->virtual_hosting ? ", virtual hosting" : "");
+
+       /* save pc value to pseudo register pc */
+       struct reg *reg = register_get_by_name(target->reg_cache, "pc", 1);
+       buf_set_u32(reg->value, 0, 32, value_pc);
+
+       return ERROR_OK;
+}
+
+static void nds32_init_must_have_registers(struct nds32 *nds32)
+{
+       struct reg_cache *reg_cache = nds32->core_cache;
+
+       /** MUST have general registers */
+       ((struct nds32_reg *)reg_cache->reg_list[R0].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[R1].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[R2].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[R3].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[R4].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[R5].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[R6].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[R7].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[R8].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[R9].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[R10].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[R15].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[R28].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[R29].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[R30].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[R31].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[PC].arch_info)->enable = true;
+
+       /** MUST have configuration system registers */
+       ((struct nds32_reg *)reg_cache->reg_list[CR0].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[CR1].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[CR2].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[CR3].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[CR4].arch_info)->enable = true;
+
+       /** MUST have interrupt system registers */
+       ((struct nds32_reg *)reg_cache->reg_list[IR0].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[IR1].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[IR3].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[IR4].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[IR6].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[IR9].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[IR11].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[IR14].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[IR15].arch_info)->enable = true;
+
+       /** MUST have MMU system registers */
+       ((struct nds32_reg *)reg_cache->reg_list[MR0].arch_info)->enable = true;
+
+       /** MUST have EDM system registers */
+       ((struct nds32_reg *)reg_cache->reg_list[DR40].arch_info)->enable = true;
+       ((struct nds32_reg *)reg_cache->reg_list[DR42].arch_info)->enable = true;
+}
+
+static int nds32_init_memory_config(struct nds32 *nds32)
+{
+       uint32_t value_cr1; /* ICM_CFG */
+       uint32_t value_cr2; /* DCM_CFG */
+       struct nds32_memory *memory = &(nds32->memory);
+
+       /* read $cr1 to init instruction memory information */
+       nds32_get_mapped_reg(nds32, CR1, &value_cr1);
+       memory->icache.set = value_cr1 & 0x7;
+       memory->icache.way = (value_cr1 >> 3) & 0x7;
+       memory->icache.line_size = (value_cr1 >> 6) & 0x7;
+       memory->icache.lock_support = (value_cr1 >> 9) & 0x1;
+
+       memory->ilm_base = (value_cr1 >> 10) & 0x7;
+       memory->ilm_align_ver = (value_cr1 >> 13) & 0x3;
+
+       /* read $cr2 to init data memory information */
+       nds32_get_mapped_reg(nds32, CR2, &value_cr2);
+       memory->dcache.set = value_cr2 & 0x7;
+       memory->dcache.way = (value_cr2 >> 3) & 0x7;
+       memory->dcache.line_size = (value_cr2 >> 6) & 0x7;
+       memory->dcache.lock_support = (value_cr2 >> 9) & 0x1;
+
+       memory->dlm_base = (value_cr2 >> 10) & 0x7;
+       memory->dlm_align_ver = (value_cr2 >> 13) & 0x3;
+
+       return ERROR_OK;
+}
+
+static void nds32_init_config(struct nds32 *nds32)
+{
+       uint32_t value_cr0;
+       uint32_t value_cr3;
+       uint32_t value_cr4;
+       struct nds32_cpu_version *cpu_version = &(nds32->cpu_version);
+       struct nds32_mmu_config *mmu_config = &(nds32->mmu_config);
+       struct nds32_misc_config *misc_config = &(nds32->misc_config);
+
+       nds32_get_mapped_reg(nds32, CR0, &value_cr0);
+       nds32_get_mapped_reg(nds32, CR3, &value_cr3);
+       nds32_get_mapped_reg(nds32, CR4, &value_cr4);
+
+       /* config cpu version */
+       cpu_version->performance_extension = value_cr0 & 0x1;
+       cpu_version->_16bit_extension = (value_cr0 >> 1) & 0x1;
+       cpu_version->performance_extension_2 = (value_cr0 >> 2) & 0x1;
+       cpu_version->cop_fpu_extension = (value_cr0 >> 3) & 0x1;
+       cpu_version->string_extension = (value_cr0 >> 4) & 0x1;
+       cpu_version->revision = (value_cr0 >> 16) & 0xFF;
+       cpu_version->cpu_id_family = (value_cr0 >> 24) & 0xF;
+       cpu_version->cpu_id_version = (value_cr0 >> 28) & 0xF;
+
+       /* config MMU */
+       mmu_config->memory_protection = value_cr3 & 0x3;
+       mmu_config->memory_protection_version = (value_cr3 >> 2) & 0x1F;
+       mmu_config->fully_associative_tlb = (value_cr3 >> 7) & 0x1;
+       if (mmu_config->fully_associative_tlb) {
+               mmu_config->tlb_size = (value_cr3 >> 8) & 0x7F;
+       } else {
+               mmu_config->tlb_ways = (value_cr3 >> 8) & 0x7;
+               mmu_config->tlb_sets = (value_cr3 >> 11) & 0x7;
+       }
+       mmu_config->_8k_page_support = (value_cr3 >> 15) & 0x1;
+       mmu_config->extra_page_size_support = (value_cr3 >> 16) & 0xFF;
+       mmu_config->tlb_lock = (value_cr3 >> 24) & 0x1;
+       mmu_config->hardware_page_table_walker = (value_cr3 >> 25) & 0x1;
+       mmu_config->default_endian = (value_cr3 >> 26) & 0x1;
+       mmu_config->partition_num = (value_cr3 >> 27) & 0x1;
+       mmu_config->invisible_tlb = (value_cr3 >> 28) & 0x1;
+       mmu_config->vlpt = (value_cr3 >> 29) & 0x1;
+       mmu_config->ntme = (value_cr3 >> 30) & 0x1;
+       mmu_config->drde = (value_cr3 >> 31) & 0x1;
+
+       /* config misc */
+       misc_config->edm = value_cr4 & 0x1;
+       misc_config->local_memory_dma = (value_cr4 >> 1) & 0x1;
+       misc_config->performance_monitor = (value_cr4 >> 2) & 0x1;
+       misc_config->high_speed_memory_port = (value_cr4 >> 3) & 0x1;
+       misc_config->debug_tracer = (value_cr4 >> 4) & 0x1;
+       misc_config->div_instruction = (value_cr4 >> 5) & 0x1;
+       misc_config->mac_instruction = (value_cr4 >> 6) & 0x1;
+       misc_config->audio_isa = (value_cr4 >> 7) & 0x3;
+       misc_config->L2_cache = (value_cr4 >> 9) & 0x1;
+       misc_config->reduce_register = (value_cr4 >> 10) & 0x1;
+       misc_config->addr_24 = (value_cr4 >> 11) & 0x1;
+       misc_config->interruption_level = (value_cr4 >> 12) & 0x1;
+       misc_config->baseline_instruction = (value_cr4 >> 13) & 0x7;
+       misc_config->no_dx_register = (value_cr4 >> 16) & 0x1;
+       misc_config->implement_dependant_register = (value_cr4 >> 17) & 0x1;
+       misc_config->implement_dependant_sr_encoding = (value_cr4 >> 18) & 0x1;
+       misc_config->ifc = (value_cr4 >> 19) & 0x1;
+       misc_config->mcu = (value_cr4 >> 20) & 0x1;
+       misc_config->shadow = (value_cr4 >> 21) & 0x7;
+       misc_config->ex9 = (value_cr4 >> 24) & 0x1;
+
+       nds32_init_memory_config(nds32);
+}
+
+static int nds32_init_option_registers(struct nds32 *nds32)
+{
+       struct reg_cache *reg_cache = nds32->core_cache;
+       struct nds32_cpu_version *cpu_version = &(nds32->cpu_version);
+       struct nds32_mmu_config *mmu_config = &(nds32->mmu_config);
+       struct nds32_misc_config *misc_config = &(nds32->misc_config);
+       struct nds32_memory *memory_config = &(nds32->memory);
+
+       bool no_cr5;
+       bool mr10_exist;
+       bool no_racr0;
+
+       if (((cpu_version->cpu_id_family == 0xC) || (cpu_version->cpu_id_family == 0xD)) &&
+                       ((cpu_version->revision & 0xFC) == 0)) {
+               no_cr5 = true;
+               mr10_exist = true;
+               no_racr0 = true;
+       } else {
+               no_cr5 = false;
+               mr10_exist = false;
+               no_racr0 = false;
+       }
+
+       if (misc_config->reduce_register == false) {
+               ((struct nds32_reg *)reg_cache->reg_list[R11].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[R12].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[R13].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[R14].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[R16].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[R17].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[R18].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[R19].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[R20].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[R21].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[R22].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[R23].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[R24].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[R25].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[R26].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[R27].arch_info)->enable = true;
+       }
+
+       if (misc_config->no_dx_register == false) {
+               ((struct nds32_reg *)reg_cache->reg_list[D0LO].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[D0HI].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[D1LO].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[D1HI].arch_info)->enable = true;
+       }
+
+       if (misc_config->ex9)
+               ((struct nds32_reg *)reg_cache->reg_list[ITB].arch_info)->enable = true;
+
+       if (no_cr5 == false)
+               ((struct nds32_reg *)reg_cache->reg_list[CR5].arch_info)->enable = true;
+
+       if (cpu_version->cop_fpu_extension) {
+               ((struct nds32_reg *)reg_cache->reg_list[CR6].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[FPCSR].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[FPCFG].arch_info)->enable = true;
+       }
+
+       if (mmu_config->memory_protection == 1) {
+               /* Secure MPU has no IPC, IPSW, P_ITYPE */
+               ((struct nds32_reg *)reg_cache->reg_list[IR1].arch_info)->enable = false;
+               ((struct nds32_reg *)reg_cache->reg_list[IR9].arch_info)->enable = false;
+       }
+
+       if (nds32->privilege_level != 0)
+               ((struct nds32_reg *)reg_cache->reg_list[IR3].arch_info)->enable = false;
+
+       if (misc_config->mcu == true)
+               ((struct nds32_reg *)reg_cache->reg_list[IR4].arch_info)->enable = false;
+
+       if (misc_config->interruption_level == false) {
+               ((struct nds32_reg *)reg_cache->reg_list[IR2].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[IR5].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[IR10].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[IR12].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[IR13].arch_info)->enable = true;
+
+               /* Secure MPU has no IPC, IPSW, P_ITYPE */
+               if (mmu_config->memory_protection != 1)
+                       ((struct nds32_reg *)reg_cache->reg_list[IR7].arch_info)->enable = true;
+       }
+
+       if ((cpu_version->cpu_id_family == 0x9) ||
+                       (cpu_version->cpu_id_family == 0xA) ||
+                       (cpu_version->cpu_id_family == 0xC) ||
+                       (cpu_version->cpu_id_family == 0xD))
+               ((struct nds32_reg *)reg_cache->reg_list[IR8].arch_info)->enable = true;
+
+       if (misc_config->shadow == 1) {
+               ((struct nds32_reg *)reg_cache->reg_list[IR16].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[IR17].arch_info)->enable = true;
+       }
+
+       if (misc_config->ifc)
+               ((struct nds32_reg *)reg_cache->reg_list[IFC_LP].arch_info)->enable = true;
+
+       if (nds32->privilege_level != 0)
+               ((struct nds32_reg *)reg_cache->reg_list[MR0].arch_info)->enable = false;
+
+       if (mmu_config->memory_protection == 1) {
+               if (mmu_config->memory_protection_version == 24)
+                       ((struct nds32_reg *)reg_cache->reg_list[MR4].arch_info)->enable = true;
+
+               if (nds32->privilege_level == 0) {
+                       if ((mmu_config->memory_protection_version == 16) ||
+                               (mmu_config->memory_protection_version == 24)) {
+                               ((struct nds32_reg *)reg_cache->reg_list[MR11].arch_info)->enable = true;
+                               ((struct nds32_reg *)reg_cache->reg_list[SECUR0].arch_info)->enable = true;
+                               ((struct nds32_reg *)reg_cache->reg_list[IR20].arch_info)->enable = true;
+                               ((struct nds32_reg *)reg_cache->reg_list[IR22].arch_info)->enable = true;
+                               ((struct nds32_reg *)reg_cache->reg_list[IR24].arch_info)->enable = true;
+                               ((struct nds32_reg *)reg_cache->reg_list[IR30].arch_info)->enable = true;
+
+                               if (misc_config->shadow == 1) {
+                                       ((struct nds32_reg *)reg_cache->reg_list[IR21].arch_info)->enable = true;
+                                       ((struct nds32_reg *)reg_cache->reg_list[IR23].arch_info)->enable = true;
+                                       ((struct nds32_reg *)reg_cache->reg_list[IR25].arch_info)->enable = true;
+                               }
+                       }
+               }
+       } else if (mmu_config->memory_protection == 2) {
+               ((struct nds32_reg *)reg_cache->reg_list[MR1].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[MR4].arch_info)->enable = true;
+
+               if ((cpu_version->cpu_id_family != 0xA) && (cpu_version->cpu_id_family != 0xC) &&
+                               (cpu_version->cpu_id_family != 0xD))
+                       ((struct nds32_reg *)reg_cache->reg_list[MR5].arch_info)->enable = true;
+       }
+
+       if (mmu_config->memory_protection > 0) {
+               ((struct nds32_reg *)reg_cache->reg_list[MR2].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[MR3].arch_info)->enable = true;
+       }
+
+       if (memory_config->ilm_base != 0)
+               if (nds32->privilege_level == 0)
+                       ((struct nds32_reg *)reg_cache->reg_list[MR6].arch_info)->enable = true;
+
+       if (memory_config->dlm_base != 0)
+               if (nds32->privilege_level == 0)
+                       ((struct nds32_reg *)reg_cache->reg_list[MR7].arch_info)->enable = true;
+
+       if ((memory_config->icache.line_size != 0) && (memory_config->dcache.line_size != 0))
+               ((struct nds32_reg *)reg_cache->reg_list[MR8].arch_info)->enable = true;
+
+       if (misc_config->high_speed_memory_port)
+               ((struct nds32_reg *)reg_cache->reg_list[MR9].arch_info)->enable = true;
+
+       if (mr10_exist)
+               ((struct nds32_reg *)reg_cache->reg_list[MR10].arch_info)->enable = true;
+
+       if (misc_config->edm) {
+               int dr_reg_n = nds32->edm.breakpoint_num * 5;
+
+               for (int i = 0 ; i < dr_reg_n ; i++)
+                       ((struct nds32_reg *)reg_cache->reg_list[DR0 + i].arch_info)->enable = true;
+
+               ((struct nds32_reg *)reg_cache->reg_list[DR41].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[DR43].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[DR44].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[DR45].arch_info)->enable = true;
+       }
+
+       if (misc_config->debug_tracer) {
+               ((struct nds32_reg *)reg_cache->reg_list[DR46].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[DR47].arch_info)->enable = true;
+       }
+
+       if (misc_config->performance_monitor) {
+               ((struct nds32_reg *)reg_cache->reg_list[PFR0].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[PFR1].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[PFR2].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[PFR3].arch_info)->enable = true;
+       }
+
+       if (misc_config->local_memory_dma) {
+               ((struct nds32_reg *)reg_cache->reg_list[DMAR0].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[DMAR1].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[DMAR2].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[DMAR3].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[DMAR4].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[DMAR5].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[DMAR6].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[DMAR7].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[DMAR8].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[DMAR9].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[DMAR10].arch_info)->enable = true;
+       }
+
+       if ((misc_config->local_memory_dma || misc_config->performance_monitor) &&
+                       (no_racr0 == false))
+               ((struct nds32_reg *)reg_cache->reg_list[RACR].arch_info)->enable = true;
+
+       if (cpu_version->cop_fpu_extension || (misc_config->audio_isa != 0))
+               ((struct nds32_reg *)reg_cache->reg_list[FUCPR].arch_info)->enable = true;
+
+       if (misc_config->audio_isa != 0) {
+               if (misc_config->audio_isa > 1) {
+                       ((struct nds32_reg *)reg_cache->reg_list[D0L24].arch_info)->enable = true;
+                       ((struct nds32_reg *)reg_cache->reg_list[D1L24].arch_info)->enable = true;
+               }
+
+               ((struct nds32_reg *)reg_cache->reg_list[I0].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[I1].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[I2].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[I3].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[I4].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[I5].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[I6].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[I7].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[M1].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[M2].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[M3].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[M5].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[M6].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[M7].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[MOD].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[LBE].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[LE].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[LC].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[ADM_VBASE].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[SHFT_CTL0].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[SHFT_CTL1].arch_info)->enable = true;
+
+               uint32_t value_mod;
+               uint32_t fucpr_backup;
+               /* enable fpu and get configuration */
+               nds32_get_mapped_reg(nds32, FUCPR, &fucpr_backup);
+               if ((fucpr_backup & 0x80000000) == 0)
+                       nds32_set_mapped_reg(nds32, FUCPR, fucpr_backup | 0x80000000);
+               nds32_get_mapped_reg(nds32, MOD, &value_mod);
+               /* restore origin fucpr value */
+               if ((fucpr_backup & 0x80000000) == 0)
+                       nds32_set_mapped_reg(nds32, FUCPR, fucpr_backup);
+
+               if ((value_mod >> 6) & 0x1) {
+                       ((struct nds32_reg *)reg_cache->reg_list[CB_CTL].arch_info)->enable = true;
+                       ((struct nds32_reg *)reg_cache->reg_list[CBB0].arch_info)->enable = true;
+                       ((struct nds32_reg *)reg_cache->reg_list[CBB1].arch_info)->enable = true;
+                       ((struct nds32_reg *)reg_cache->reg_list[CBB2].arch_info)->enable = true;
+                       ((struct nds32_reg *)reg_cache->reg_list[CBB3].arch_info)->enable = true;
+                       ((struct nds32_reg *)reg_cache->reg_list[CBE0].arch_info)->enable = true;
+                       ((struct nds32_reg *)reg_cache->reg_list[CBE1].arch_info)->enable = true;
+                       ((struct nds32_reg *)reg_cache->reg_list[CBE2].arch_info)->enable = true;
+                       ((struct nds32_reg *)reg_cache->reg_list[CBE3].arch_info)->enable = true;
+               }
+       }
+
+       if ((cpu_version->cpu_id_family == 0x9) ||
+                       (cpu_version->cpu_id_family == 0xA) ||
+                       (cpu_version->cpu_id_family == 0xC)) {
+
+               ((struct nds32_reg *)reg_cache->reg_list[IDR0].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[IDR1].arch_info)->enable = true;
+
+               if ((cpu_version->cpu_id_family == 0xC) && (cpu_version->revision == 0x0C))
+                       ((struct nds32_reg *)reg_cache->reg_list[IDR0].arch_info)->enable = false;
+       }
+
+       uint32_t ir3_value;
+       uint32_t ivb_prog_pri_lvl;
+       uint32_t ivb_ivic_ver;
+
+       nds32_get_mapped_reg(nds32, IR3, &ir3_value);
+       ivb_prog_pri_lvl = ir3_value & 0x1;
+       ivb_ivic_ver = (ir3_value >> 11) & 0x3;
+
+       if ((ivb_prog_pri_lvl == 1) || (ivb_ivic_ver >= 1)) {
+               ((struct nds32_reg *)reg_cache->reg_list[IR18].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[IR19].arch_info)->enable = true;
+       }
+
+       if (ivb_ivic_ver >= 1) {
+               ((struct nds32_reg *)reg_cache->reg_list[IR26].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[IR27].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[IR28].arch_info)->enable = true;
+               ((struct nds32_reg *)reg_cache->reg_list[IR29].arch_info)->enable = true;
+       }
+
+       return ERROR_OK;
+}
+
+int nds32_init_register_table(struct nds32 *nds32)
+{
+       nds32_init_must_have_registers(nds32);
+
+       return ERROR_OK;
+}
+
+int nds32_add_software_breakpoint(struct target *target,
+               struct breakpoint *breakpoint)
+{
+       uint32_t data;
+       uint32_t check_data;
+       uint32_t break_insn;
+
+       /* check the breakpoint size */
+       target->type->read_buffer(target, breakpoint->address, 4, (uint8_t *)&data);
+
+       /* backup origin instruction
+        * instruction is big-endian */
+       if (*(char *)&data & 0x80) { /* 16-bits instruction */
+               breakpoint->length = 2;
+               break_insn = NDS32_BREAK_16;
+       } else { /* 32-bits instruction */
+               breakpoint->length = 4;
+               break_insn = NDS32_BREAK_32;
+       }
+
+       if (breakpoint->orig_instr != NULL)
+               free(breakpoint->orig_instr);
+
+       breakpoint->orig_instr = malloc(breakpoint->length);
+       memcpy(breakpoint->orig_instr, &data, breakpoint->length);
+
+       /* self-modified code */
+       target->type->write_buffer(target, breakpoint->address, breakpoint->length, (const uint8_t *)&break_insn);
+       /* write_back & invalidate dcache & invalidate icache */
+       nds32_cache_sync(target, breakpoint->address, breakpoint->length);
+
+       /* read back to check */
+       target->type->read_buffer(target, breakpoint->address, breakpoint->length, (uint8_t *)&check_data);
+       if (memcmp(&check_data, &break_insn, breakpoint->length) == 0)
+               return ERROR_OK;
+
+       return ERROR_FAIL;
+}
+
+int nds32_remove_software_breakpoint(struct target *target,
+               struct breakpoint *breakpoint)
+{
+       uint32_t check_data;
+       uint32_t break_insn;
+
+       if (breakpoint->length == 2)
+               break_insn = NDS32_BREAK_16;
+       else if (breakpoint->length == 4)
+               break_insn = NDS32_BREAK_32;
+       else
+               return ERROR_FAIL;
+
+       target->type->read_buffer(target, breakpoint->address, breakpoint->length,
+                       (uint8_t *)&check_data);
+
+       /* break instruction is modified */
+       if (memcmp(&check_data, &break_insn, breakpoint->length) != 0)
+               return ERROR_FAIL;
+
+       /* self-modified code */
+       target->type->write_buffer(target, breakpoint->address, breakpoint->length,
+                       breakpoint->orig_instr);
+
+       /* write_back & invalidate dcache & invalidate icache */
+       nds32_cache_sync(target, breakpoint->address, breakpoint->length);
+
+       return ERROR_OK;
+}
+
+/**
+ * Restore the processor context on an Andes target.  The full processor
+ * context is analyzed to see if any of the registers are dirty on this end, but
+ * have a valid new value.  If this is the case, the processor is changed to the
+ * appropriate mode and the new register values are written out to the
+ * processor.  If there happens to be a dirty register with an invalid value, an
+ * error will be logged.
+ *
+ * @param target Pointer to the Andes target to have its context restored
+ * @return Error status if the target is not halted.
+ */
+int nds32_restore_context(struct target *target)
+{
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct aice_port_s *aice = target_to_aice(target);
+       struct reg_cache *reg_cache = nds32->core_cache;
+       struct reg *reg;
+       struct nds32_reg *reg_arch_info;
+       unsigned int i;
+
+       LOG_DEBUG("-");
+
+       if (target->state != TARGET_HALTED) {
+               LOG_WARNING("target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* check if there are dirty registers */
+       for (i = 0; i < reg_cache->num_regs; i++) {
+               reg = &(reg_cache->reg_list[i]);
+               if (reg->dirty == true) {
+                       if (reg->valid == true) {
+
+                               LOG_DEBUG("examining dirty reg: %s", reg->name);
+                               LOG_DEBUG("writing register %i "
+                                               "with value 0x%8.8" PRIx32, i, buf_get_u32(reg->value, 0, 32));
+
+                               reg_arch_info = reg->arch_info;
+                               if (FD0 <= reg_arch_info->num && reg_arch_info->num <= FD31)
+                                       aice_write_reg_64(aice, reg_arch_info->num, reg_arch_info->value_64);
+                               else
+                                       aice_write_register(aice, reg_arch_info->num, reg_arch_info->value);
+                               reg->valid = true;
+                               reg->dirty = false;
+                       }
+               }
+       }
+
+       return ERROR_OK;
+}
+
+int nds32_edm_config(struct nds32 *nds32)
+{
+       struct target *target = nds32->target;
+       struct aice_port_s *aice = target_to_aice(target);
+       uint32_t edm_cfg;
+       uint32_t edm_ctl;
+
+       aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg);
+
+       nds32->edm.version = (edm_cfg >> 16) & 0xFFFF;
+       LOG_INFO("EDM version 0x%04" PRIx32, nds32->edm.version);
+
+       nds32->edm.breakpoint_num = (edm_cfg & 0x7) + 1;
+
+       if ((nds32->edm.version & 0x1000) || (0x60 <= nds32->edm.version))
+               nds32->edm.access_control = true;
+       else
+               nds32->edm.access_control = false;
+
+       if ((edm_cfg >> 4) & 0x1)
+               nds32->edm.direct_access_local_memory = true;
+       else
+               nds32->edm.direct_access_local_memory = false;
+
+       if (nds32->edm.version <= 0x20)
+               nds32->edm.direct_access_local_memory = false;
+
+       aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
+       if (edm_ctl & (0x1 << 29))
+               nds32->edm.support_max_stop = true;
+       else
+               nds32->edm.support_max_stop = false;
+
+       /* set passcode for secure MCU */
+       nds32_login(nds32);
+
+       return ERROR_OK;
+}
+
+int nds32_config(struct nds32 *nds32)
+{
+       nds32_init_config(nds32);
+
+       /* init optional system registers according to config registers */
+       nds32_init_option_registers(nds32);
+
+       /* get max interrupt level */
+       if (nds32->misc_config.interruption_level)
+               nds32->max_interrupt_level = 2;
+       else
+               nds32->max_interrupt_level = 3;
+
+       /* get ILM/DLM size from MR6/MR7 */
+       uint32_t value_mr6, value_mr7;
+       uint32_t size_index;
+       nds32_get_mapped_reg(nds32, MR6, &value_mr6);
+       size_index = (value_mr6 >> 1) & 0xF;
+       nds32->memory.ilm_size = NDS32_LM_SIZE_TABLE[size_index];
+
+       nds32_get_mapped_reg(nds32, MR7, &value_mr7);
+       size_index = (value_mr7 >> 1) & 0xF;
+       nds32->memory.dlm_size = NDS32_LM_SIZE_TABLE[size_index];
+
+       return ERROR_OK;
+}
+
+int nds32_init_arch_info(struct target *target, struct nds32 *nds32)
+{
+       target->arch_info = nds32;
+       nds32->target = target;
+
+       nds32->common_magic = NDS32_COMMON_MAGIC;
+       nds32->init_arch_info_after_halted = false;
+       nds32->auto_convert_hw_bp = true;
+       nds32->global_stop = false;
+       nds32->soft_reset_halt = false;
+       nds32->edm_passcode = NULL;
+       nds32->privilege_level = 0;
+       nds32->boot_time = 1500;
+       nds32->reset_halt_as_examine = false;
+       nds32->keep_target_edm_ctl = false;
+       nds32->word_access_mem = false;
+       nds32->virtual_hosting = false;
+
+       nds32_reg_init();
+
+       if (ERROR_FAIL == nds32_reg_cache_init(target, nds32))
+               return ERROR_FAIL;
+
+       if (ERROR_OK != nds32_init_register_table(nds32))
+               return ERROR_FAIL;
+
+       return ERROR_OK;
+}
+
+int nds32_virtual_to_physical(struct target *target, uint32_t address, uint32_t *physical)
+{
+       struct nds32 *nds32 = target_to_nds32(target);
+
+       if (nds32->memory.address_translation == false) {
+               *physical = address;
+               return ERROR_OK;
+       }
+
+       if (ERROR_OK == nds32_probe_tlb(nds32, address, physical))
+               return ERROR_OK;
+
+       if (ERROR_OK == nds32_walk_page_table(nds32, address, physical))
+               return ERROR_OK;
+
+       return ERROR_FAIL;
+}
+
+int nds32_cache_sync(struct target *target, uint32_t address, uint32_t length)
+{
+       struct aice_port_s *aice = target_to_aice(target);
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct nds32_cache *dcache = &(nds32->memory.dcache);
+       struct nds32_cache *icache = &(nds32->memory.icache);
+       uint32_t dcache_line_size = NDS32_LINE_SIZE_TABLE[dcache->line_size];
+       uint32_t icache_line_size = NDS32_LINE_SIZE_TABLE[icache->line_size];
+       uint32_t cur_address;
+       int result;
+       uint32_t start_line, end_line;
+       uint32_t cur_line;
+
+       if ((dcache->line_size != 0) && (dcache->enable == true)) {
+               /* address / dcache_line_size */
+               start_line = address >> (dcache->line_size + 2);
+               /* (address + length - 1) / dcache_line_size */
+               end_line = (address + length - 1) >> (dcache->line_size + 2);
+
+               for (cur_address = address, cur_line = start_line ;
+                               cur_line <= end_line ;
+                               cur_address += dcache_line_size, cur_line++) {
+                       /* D$ write back */
+                       result = aice_cache_ctl(aice, AICE_CACHE_CTL_L1D_VA_WB, cur_address);
+                       if (result != ERROR_OK)
+                               return result;
+
+                       /* D$ invalidate */
+                       result = aice_cache_ctl(aice, AICE_CACHE_CTL_L1D_VA_INVAL, cur_address);
+                       if (result != ERROR_OK)
+                               return result;
+               }
+       }
+
+       if ((icache->line_size != 0) && (icache->enable == true)) {
+               /*  address / icache_line_size */
+               start_line = address >> (icache->line_size + 2);
+               /* (address + length - 1) / icache_line_size */
+               end_line = (address + length - 1) >> (icache->line_size + 2);
+
+               for (cur_address = address, cur_line = start_line ;
+                               cur_line <= end_line ;
+                               cur_address += icache_line_size, cur_line++) {
+                       /* Because PSW.IT is turned off under debug exception, address MUST
+                        * be physical address.  L1I_VA_INVALIDATE uses PSW.IT to decide
+                        * address translation or not. */
+                       uint32_t physical_addr;
+                       if (ERROR_FAIL == target->type->virt2phys(target, cur_address,
+                                               &physical_addr))
+                               return ERROR_FAIL;
+
+                       /* I$ invalidate */
+                       result = aice_cache_ctl(aice, AICE_CACHE_CTL_L1I_VA_INVAL, physical_addr);
+                       if (result != ERROR_OK)
+                               return result;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+uint32_t nds32_nextpc(struct nds32 *nds32, int current, uint32_t address)
+{
+       if (!current)
+               nds32_set_mapped_reg(nds32, PC, address);
+       else
+               nds32_get_mapped_reg(nds32, PC, &address);
+
+       return address;
+}
+
+int nds32_step(struct target *target, int current,
+               uint32_t address, int handle_breakpoints)
+{
+       LOG_DEBUG("target->state: %s",
+                       target_state_name(target));
+
+       if (target->state != TARGET_HALTED) {
+               LOG_WARNING("target was not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       struct nds32 *nds32 = target_to_nds32(target);
+
+       address = nds32_nextpc(nds32, current, address);
+
+       LOG_DEBUG("STEP PC %08" PRIx32 "%s", address, !current ? "!" : "");
+
+       /** set DSSIM */
+       uint32_t ir14_value;
+       nds32_get_mapped_reg(nds32, IR14, &ir14_value);
+       if (nds32->step_isr_enable)
+               ir14_value |= (0x1 << 31);
+       else
+               ir14_value &= ~(0x1 << 31);
+       nds32_set_mapped_reg(nds32, IR14, ir14_value);
+
+       /********* TODO: maybe create another function to handle this part */
+       CHECK_RETVAL(nds32->leave_debug_state(nds32, true));
+       CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED));
+
+       struct aice_port_s *aice = target_to_aice(target);
+       if (ERROR_OK != aice_step(aice))
+               return ERROR_FAIL;
+
+       /* save state */
+       CHECK_RETVAL(nds32->enter_debug_state(nds32, true));
+       /********* TODO: maybe create another function to handle this part */
+
+       /* restore DSSIM */
+       if (nds32->step_isr_enable) {
+               nds32_get_mapped_reg(nds32, IR14, &ir14_value);
+               ir14_value &= ~(0x1 << 31);
+               nds32_set_mapped_reg(nds32, IR14, ir14_value);
+       }
+
+       CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED));
+
+       return ERROR_OK;
+}
+
+static int nds32_step_without_watchpoint(struct nds32 *nds32)
+{
+       struct target *target = nds32->target;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_WARNING("target was not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /** set DSSIM */
+       uint32_t ir14_value;
+       nds32_get_mapped_reg(nds32, IR14, &ir14_value);
+       if (nds32->step_isr_enable)
+               ir14_value |= (0x1 << 31);
+       else
+               ir14_value &= ~(0x1 << 31);
+       nds32_set_mapped_reg(nds32, IR14, ir14_value);
+
+       /********* TODO: maybe create another function to handle this part */
+       CHECK_RETVAL(nds32->leave_debug_state(nds32, false));
+
+       struct aice_port_s *aice = target_to_aice(target);
+
+       if (ERROR_OK != aice_step(aice))
+               return ERROR_FAIL;
+
+       /* save state */
+       CHECK_RETVAL(nds32->enter_debug_state(nds32, false));
+       /********* TODO: maybe create another function to handle this part */
+
+       /* restore DSSIM */
+       if (nds32->step_isr_enable) {
+               nds32_get_mapped_reg(nds32, IR14, &ir14_value);
+               ir14_value &= ~(0x1 << 31);
+               nds32_set_mapped_reg(nds32, IR14, ir14_value);
+       }
+
+       return ERROR_OK;
+}
+
+int nds32_target_state(struct nds32 *nds32, enum target_state *state)
+{
+       struct aice_port_s *aice = target_to_aice(nds32->target);
+       enum aice_target_state_s nds32_state;
+
+       if (aice_state(aice, &nds32_state) != ERROR_OK)
+               return ERROR_FAIL;
+
+       switch (nds32_state) {
+               case AICE_DISCONNECT:
+                       LOG_INFO("USB is disconnected");
+                       return ERROR_FAIL;
+               case AICE_TARGET_DETACH:
+                       LOG_INFO("Target is disconnected");
+                       return ERROR_FAIL;
+               case AICE_TARGET_UNKNOWN:
+                       *state = TARGET_UNKNOWN;
+                       break;
+               case AICE_TARGET_RUNNING:
+                       *state = TARGET_RUNNING;
+                       break;
+               case AICE_TARGET_HALTED:
+                       *state = TARGET_HALTED;
+                       break;
+               case AICE_TARGET_RESET:
+                       *state = TARGET_RESET;
+                       break;
+               case AICE_TARGET_DEBUG_RUNNING:
+                       *state = TARGET_DEBUG_RUNNING;
+                       break;
+               default:
+                       return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+int nds32_examine_debug_reason(struct nds32 *nds32)
+{
+       uint32_t reason;
+       struct target *target = nds32->target;
+
+       nds32->get_debug_reason(nds32, &reason);
+
+       LOG_DEBUG("nds32 examines debug reason: %s", nds32_debug_type_name[reason]);
+
+       /* Examine debug reason */
+       switch (reason) {
+               case NDS32_DEBUG_BREAK:
+               case NDS32_DEBUG_BREAK_16:
+               case NDS32_DEBUG_INST_BREAK:
+                       {
+                               uint32_t value_pc;
+                               uint32_t opcode;
+                               struct nds32_instruction instruction;
+
+                               nds32_get_mapped_reg(nds32, PC, &value_pc);
+
+                               if (ERROR_OK != nds32_read_opcode(nds32, value_pc, &opcode))
+                                       return ERROR_FAIL;
+                               if (ERROR_OK != nds32_evaluate_opcode(nds32, opcode, value_pc,
+                                                       &instruction))
+                                       return ERROR_FAIL;
+
+                               target->debug_reason = DBG_REASON_BREAKPOINT;
+                       }
+                       break;
+               case NDS32_DEBUG_DATA_ADDR_WATCHPOINT_PRECISE:
+               case NDS32_DEBUG_DATA_VALUE_WATCHPOINT_PRECISE:
+               case NDS32_DEBUG_LOAD_STORE_GLOBAL_STOP: /* GLOBAL_STOP is precise exception */
+                       {
+                               int result;
+
+                               result = nds32->get_watched_address(nds32,
+                                               &(nds32->watched_address), reason);
+                               /* do single step(without watchpoints) to skip the "watched" instruction */
+                               nds32_step_without_watchpoint(nds32);
+
+                               /* before single_step, save exception address */
+                               if (ERROR_OK != result)
+                                       return ERROR_FAIL;
+
+                               target->debug_reason = DBG_REASON_WATCHPOINT;
+                       }
+                       break;
+               case NDS32_DEBUG_DEBUG_INTERRUPT:
+                       target->debug_reason = DBG_REASON_DBGRQ;
+                       break;
+               case NDS32_DEBUG_HARDWARE_SINGLE_STEP:
+                       target->debug_reason = DBG_REASON_SINGLESTEP;
+                       break;
+               case NDS32_DEBUG_DATA_VALUE_WATCHPOINT_IMPRECISE:
+               case NDS32_DEBUG_DATA_ADDR_WATCHPOINT_NEXT_PRECISE:
+               case NDS32_DEBUG_DATA_VALUE_WATCHPOINT_NEXT_PRECISE:
+                       if (ERROR_OK != nds32->get_watched_address(nds32,
+                                               &(nds32->watched_address), reason))
+                               return ERROR_FAIL;
+
+                       target->debug_reason = DBG_REASON_WATCHPOINT;
+                       break;
+               default:
+                       target->debug_reason = DBG_REASON_UNDEFINED;
+                       break;
+       }
+
+       return ERROR_OK;
+}
+
+int nds32_login(struct nds32 *nds32)
+{
+       struct target *target = nds32->target;
+       struct aice_port_s *aice = target_to_aice(target);
+       uint32_t passcode_length;
+       char command_sequence[129];
+       char command_str[33];
+       char code_str[9];
+       uint32_t copy_length;
+       uint32_t code;
+       uint32_t i;
+
+       LOG_DEBUG("nds32_login");
+
+       if (nds32->edm_passcode != NULL) {
+               /* convert EDM passcode to command sequences */
+               passcode_length = strlen(nds32->edm_passcode);
+               command_sequence[0] = '\0';
+               for (i = 0; i < passcode_length; i += 8) {
+                       if (passcode_length - i < 8)
+                               copy_length = passcode_length - i;
+                       else
+                               copy_length = 8;
+
+                       strncpy(code_str, nds32->edm_passcode + i, copy_length);
+                       code_str[copy_length] = '\0';
+                       code = strtoul(code_str, NULL, 16);
+
+                       sprintf(command_str, "write_misc gen_port0 0x%x;", code);
+                       strcat(command_sequence, command_str);
+               }
+
+               if (ERROR_OK != aice_program_edm(aice, command_sequence))
+                       return ERROR_FAIL;
+
+               /* get current privilege level */
+               uint32_t value_edmsw;
+               aice_read_debug_reg(aice, NDS_EDM_SR_EDMSW, &value_edmsw);
+               nds32->privilege_level = (value_edmsw >> 16) & 0x3;
+               LOG_INFO("Current privilege level: %d", nds32->privilege_level);
+       }
+
+       if (nds32_edm_ops_num > 0) {
+               const char *reg_name;
+               for (i = 0 ; i < nds32_edm_ops_num ; i++) {
+                       code = nds32_edm_ops[i].value;
+                       if (nds32_edm_ops[i].reg_no == 6)
+                               reg_name = "gen_port0";
+                       else if (nds32_edm_ops[i].reg_no == 7)
+                               reg_name = "gen_port1";
+                       else
+                               return ERROR_FAIL;
+
+                       sprintf(command_str, "write_misc %s 0x%x;", reg_name, code);
+                       if (ERROR_OK != aice_program_edm(aice, command_str))
+                               return ERROR_FAIL;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+int nds32_halt(struct target *target)
+{
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct aice_port_s *aice = target_to_aice(target);
+       enum target_state state;
+
+       LOG_DEBUG("target->state: %s",
+                       target_state_name(target));
+
+       if (target->state == TARGET_HALTED) {
+               LOG_DEBUG("target was already halted");
+               return ERROR_OK;
+       }
+
+       if (nds32_target_state(nds32, &state) != ERROR_OK)
+               return ERROR_FAIL;
+
+       if (TARGET_HALTED != state)
+               /* TODO: if state == TARGET_HALTED, check ETYPE is DBGI or not */
+               if (ERROR_OK != aice_halt(aice))
+                       return ERROR_FAIL;
+
+       CHECK_RETVAL(nds32->enter_debug_state(nds32, true));
+
+       CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED));
+
+       return ERROR_OK;
+}
+
+/* poll current target status */
+int nds32_poll(struct target *target)
+{
+       struct nds32 *nds32 = target_to_nds32(target);
+       enum target_state state;
+
+       if (nds32_target_state(nds32, &state) != ERROR_OK)
+               return ERROR_FAIL;
+
+       if (state == TARGET_HALTED) {
+               if (target->state != TARGET_HALTED) {
+                       /* if false_hit, continue free_run */
+                       if (ERROR_OK != nds32->enter_debug_state(nds32, true)) {
+                               struct aice_port_s *aice = target_to_aice(target);
+                               aice_run(aice);
+                               return ERROR_OK;
+                       }
+
+                       LOG_DEBUG("Change target state to TARGET_HALTED.");
+
+                       target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+               }
+       } else if (state == TARGET_RESET) {
+               if (target->state == TARGET_HALTED) {
+                       /* similar to assert srst */
+                       register_cache_invalidate(nds32->core_cache);
+                       target->state = TARGET_RESET;
+
+                       /* TODO: deassert srst */
+               } else if (target->state == TARGET_RUNNING) {
+                       /* reset as running */
+                       LOG_WARNING("<-- TARGET WARNING! The debug target has been reset. -->");
+               }
+       } else {
+               if (target->state != TARGET_RUNNING && target->state != TARGET_DEBUG_RUNNING) {
+                       LOG_DEBUG("Change target state to TARGET_RUNNING.");
+                       target->state = TARGET_RUNNING;
+                       target->debug_reason = DBG_REASON_NOTHALTED;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+int nds32_resume(struct target *target, int current,
+               uint32_t address, int handle_breakpoints, int debug_execution)
+{
+       LOG_DEBUG("current %d  address %08x  handle_breakpoints %d  debug_execution %d",
+                       current, address, handle_breakpoints, debug_execution);
+
+       struct nds32 *nds32 = target_to_nds32(target);
+
+       if (target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       address = nds32_nextpc(nds32, current, address);
+
+       LOG_DEBUG("RESUME PC %08" PRIx32 "%s", address, !current ? "!" : "");
+
+       if (!debug_execution)
+               target_free_all_working_areas(target);
+
+       /* Disable HSS to avoid users misuse HSS */
+       if (nds32_reach_max_interrupt_level(nds32) == false) {
+               uint32_t value_ir0;
+               nds32_get_mapped_reg(nds32, IR0, &value_ir0);
+               value_ir0 &= ~(0x1 << 11);
+               nds32_set_mapped_reg(nds32, IR0, value_ir0);
+       }
+
+       CHECK_RETVAL(nds32->leave_debug_state(nds32, true));
+       CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED));
+
+       struct aice_port_s *aice = target_to_aice(target);
+       aice_run(aice);
+
+       target->debug_reason = DBG_REASON_NOTHALTED;
+       if (!debug_execution)
+               target->state = TARGET_RUNNING;
+       else
+               target->state = TARGET_DEBUG_RUNNING;
+
+       LOG_DEBUG("target->state: %s",
+                       target_state_name(target));
+
+       return ERROR_OK;
+}
+
+int nds32_assert_reset(struct target *target)
+{
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct aice_port_s *aice = target_to_aice(target);
+
+       jtag_poll_set_enabled(true);
+
+       if (target->reset_halt) {
+               if (nds32->soft_reset_halt)
+                       target->type->soft_reset_halt(target);
+               else
+                       aice_assert_srst(aice, AICE_RESET_HOLD);
+       } else {
+               aice_assert_srst(aice, AICE_SRST);
+               alive_sleep(nds32->boot_time);
+       }
+
+       /* set passcode for secure MCU after core reset */
+       nds32_login(nds32);
+
+       /* registers are now invalid */
+       register_cache_invalidate(nds32->core_cache);
+
+       target->state = TARGET_RESET;
+
+       return ERROR_OK;
+}
+
+static uint32_t nds32_backup_edm_ctl;
+static bool gdb_attached;
+
+static int nds32_gdb_attach(struct nds32 *nds32)
+{
+       LOG_DEBUG("nds32_gdb_attach");
+
+       if (gdb_attached == false) {
+
+               if (nds32->keep_target_edm_ctl) {
+                       /* backup target EDM_CTL */
+                       struct aice_port_s *aice = target_to_aice(nds32->target);
+                       aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &nds32_backup_edm_ctl);
+               }
+
+               target_halt(nds32->target);
+               target_poll(nds32->target);
+
+               gdb_attached = true;
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_gdb_detach(struct nds32 *nds32)
+{
+       LOG_DEBUG("nds32_gdb_detach");
+       bool backup_virtual_hosting_setting;
+
+       if (gdb_attached) {
+
+               backup_virtual_hosting_setting = nds32->virtual_hosting;
+               /* turn off virtual hosting before resume as gdb-detach */
+               nds32->virtual_hosting = false;
+               target_resume(nds32->target, 1, 0, 0, 0);
+               nds32->virtual_hosting = backup_virtual_hosting_setting;
+
+               if (nds32->keep_target_edm_ctl) {
+                       /* restore target EDM_CTL */
+                       struct aice_port_s *aice = target_to_aice(nds32->target);
+                       aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, nds32_backup_edm_ctl);
+               }
+
+               /* turn off polling */
+               jtag_poll_set_enabled(false);
+
+               gdb_attached = false;
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_callback_event_handler(struct target *target,
+               enum target_event event, void *priv)
+{
+       int retval = ERROR_OK;
+       struct nds32 *nds32 = priv;
+
+       switch (event) {
+               case TARGET_EVENT_GDB_ATTACH:
+                       retval = nds32_gdb_attach(nds32);
+                       break;
+               case TARGET_EVENT_GDB_DETACH:
+                       retval = nds32_gdb_detach(nds32);
+                       break;
+               default:
+                       break;
+       }
+
+       return retval;
+}
+
+int nds32_init(struct nds32 *nds32)
+{
+       /* Initialize anything we can set up without talking to the target */
+       nds32->memory.access_channel = NDS_MEMORY_ACC_CPU;
+
+       /* turn off polling by default */
+       jtag_poll_set_enabled(false);
+
+       /* register event callback */
+       target_register_event_callback(nds32_callback_event_handler, nds32);
+
+       return ERROR_OK;
+}
+
+int nds32_reset_halt(struct nds32 *nds32)
+{
+       LOG_INFO("reset halt as init");
+
+       struct aice_port_s *aice = target_to_aice(nds32->target);
+       aice_assert_srst(aice, AICE_RESET_HOLD);
+
+       return ERROR_OK;
+}
index cec8ae0e5b0ae779c895632c53de547684966e90..f585c2d30539b18fd24fcf0df22e98b24629d01a 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2013 by Andes Technology                                *
+ *   Copyright (C) 2013 Andes Technology                                   *
  *   Hsiangkai Wang <hkwang@andestech.com>                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
@@ -22,7 +22,6 @@
 #define __NDS32_H__
 
 #include <jtag/jtag.h>
-#include <jtag/aice/aice_port.h>
 #include "target.h"
 #include "target_type.h"
 #include "register.h"
@@ -31,6 +30,8 @@
 #include "nds32_insn.h"
 #include "nds32_edm.h"
 
+#define NDS32_EDM_OPERATION_MAX_NUM 64
+
 #define CHECK_RETVAL(action)                   \
        do {                                    \
                int __retval = (action);        \
@@ -62,18 +63,11 @@ enum nds32_debug_reason {
        NDS32_DEBUG_LOAD_STORE_GLOBAL_STOP,
 };
 
-enum nds32_tdesc_type {
-       NDS32_CORE_TDESC = 0,
-       NDS32_SYSTEM_TDESC,
-       NDS32_AUDIO_TDESC,
-       NDS32_FPU_TDESC,
-       NDS32_NUM_TDESC,
-};
-
 #define NDS32_STRUCT_STAT_SIZE 60
 #define NDS32_STRUCT_TIMEVAL_SIZE 8
 
 enum nds32_syscall_id {
+       NDS32_SYSCALL_UNDEFINED = 0,
        NDS32_SYSCALL_EXIT = 1,
        NDS32_SYSCALL_OPEN = 2,
        NDS32_SYSCALL_CLOSE = 3,
@@ -100,7 +94,8 @@ struct nds32_edm {
        /** The number of hardware breakpoints */
        int breakpoint_num;
 
-       /** EDM_CFG.DALM, indicate if direct local memory access feature is supported or not */
+       /** EDM_CFG.DALM, indicate if direct local memory access
+        * feature is supported or not */
        bool direct_access_local_memory;
 
        /** Support ACC_CTL register */
@@ -173,10 +168,10 @@ struct nds32_memory {
        int dlm_end;
 
        /** Memory access method */
-       enum aice_memory_access access_channel;
+       enum nds_memory_access access_channel;
 
        /** Memory access mode */
-       enum aice_memory_mode mode;
+       enum nds_memory_select mode;
 
        /** Address translation */
        bool address_translation;
@@ -275,7 +270,7 @@ struct nds32 {
        /** Backup target registers may be modified in debug state */
        int (*enter_debug_state)(struct nds32 *nds32, bool enable_watchpoint);
 
-       /** Get address hitted watchpoint */
+       /** Get address hit watchpoint */
        int (*get_watched_address)(struct nds32 *nds32, uint32_t *address, uint32_t reason);
 
        /** maximum interrupt level */
@@ -289,24 +284,28 @@ struct nds32 {
        /** Flag reporting whether virtual hosting is active. */
        bool virtual_hosting;
 
-       /** Flag reporting whether continue/step hits syscall or not */
-       bool hit_syscall;
-
-       /** Value to be returned by virtual hosting SYS_ERRNO request. */
-       int virtual_hosting_errno;
-
-       /** Flag reporting whether syscall is aborted */
-       bool virtual_hosting_ctrl_c;
-
-       /** Record syscall ID for other operations to do special processing for target */
-       int active_syscall_id;
-
        /** Flag reporting whether global stop is active. */
        bool global_stop;
 
+       /** Flag reporting whether to use soft-reset-halt or not as issuing reset-halt. */
+       bool soft_reset_halt;
+
        /** reset-halt as target examine */
        bool reset_halt_as_examine;
 
+       /** backup/restore target EDM_CTL value. As debugging target debug
+        * handler, it should be true. */
+       bool keep_target_edm_ctl;
+
+       /** always use word-aligned address to access memory */
+       bool word_access_mem;
+
+       /** EDM passcode for debugging secure MCU */
+       char *edm_passcode;
+
+       /** current privilege_level if using secure MCU. value 0 is the highest level.  */
+       int privilege_level;
+
        /** Period to wait after SRST. */
        uint32_t boot_time;
 
@@ -322,12 +321,19 @@ struct nds32 {
        /** Flag to indicate fpu-extension is enabled or not */
        bool fpu_enable;
 
+       /* Andes Core has mixed endian model. Instruction is always big-endian.
+        * Data may be big or little endian. Device registers may have different
+        * endian from data and instruction. */
+       /** Endian of data memory */
+       enum target_endianness data_endian;
+
+       /** Endian of device registers */
+       enum target_endianness device_reg_endian;
+
        /** Flag to indicate if auto convert software breakpoints to
         *  hardware breakpoints or not in ROM */
        bool auto_convert_hw_bp;
 
-       int (*setup_virtual_hosting)(struct target *target, int enable);
-
        /** Backpointer to the target. */
        struct target *target;
 
@@ -343,32 +349,33 @@ struct nds32_reg {
        bool enable;
 };
 
+struct nds32_edm_operation {
+       uint32_t reg_no;
+       uint32_t value;
+};
+
 extern int nds32_config(struct nds32 *nds32);
 extern int nds32_init_arch_info(struct target *target, struct nds32 *nds32);
 extern int nds32_full_context(struct nds32 *nds32);
 extern int nds32_arch_state(struct target *target);
 extern int nds32_add_software_breakpoint(struct target *target,
-                                       struct breakpoint *breakpoint);
+               struct breakpoint *breakpoint);
 extern int nds32_remove_software_breakpoint(struct target *target,
-                                       struct breakpoint *breakpoint);
+               struct breakpoint *breakpoint);
 
-extern int nds32_get_gdb_general_reg_list(struct target *target,
-                                       struct reg **reg_list[], int *reg_list_size);
 extern int nds32_get_gdb_reg_list(struct target *target,
-                               struct reg **reg_list[], int *reg_list_size);
-extern int nds32_get_gdb_target_description(struct target *target, char **xml,
-                                       char *annex, int32_t offset, uint32_t length);
+               struct reg **reg_list[], int *reg_list_size);
 
 extern int nds32_write_buffer(struct target *target, uint32_t address,
-                               uint32_t size, const uint8_t *buffer);
+               uint32_t size, const uint8_t *buffer);
 extern int nds32_read_buffer(struct target *target, uint32_t address,
-                               uint32_t size, uint8_t *buffer);
+               uint32_t size, uint8_t *buffer);
 extern int nds32_bulk_write_memory(struct target *target,
-                                       uint32_t address, uint32_t count, const uint8_t *buffer);
+               uint32_t address, uint32_t count, const uint8_t *buffer);
 extern int nds32_read_memory(struct target *target, uint32_t address,
-                               uint32_t size, uint32_t count, uint8_t *buffer);
+               uint32_t size, uint32_t count, uint8_t *buffer);
 extern int nds32_write_memory(struct target *target, uint32_t address,
-                               uint32_t size, uint32_t count, const uint8_t *buffer);
+               uint32_t size, uint32_t count, const uint8_t *buffer);
 
 extern int nds32_init_register_table(struct nds32 *nds32);
 extern int nds32_init_memory_info(struct nds32 *nds32);
@@ -377,31 +384,27 @@ extern int nds32_get_mapped_reg(struct nds32 *nds32, unsigned regnum, uint32_t *
 extern int nds32_set_mapped_reg(struct nds32 *nds32, unsigned regnum, uint32_t value);
 
 extern int nds32_edm_config(struct nds32 *nds32);
-extern int nds32_check_extension(struct nds32 *nds32);
 extern int nds32_cache_sync(struct target *target, uint32_t address, uint32_t length);
 extern int nds32_mmu(struct target *target, int *enabled);
-extern int nds32_virtual_to_physical(struct target *target, uint32_t address, uint32_t *physical);
+extern int nds32_virtual_to_physical(struct target *target, uint32_t address,
+               uint32_t *physical);
 extern int nds32_read_phys_memory(struct target *target, uint32_t address,
-                                       uint32_t size, uint32_t count, uint8_t *buffer);
+               uint32_t size, uint32_t count, uint8_t *buffer);
 extern int nds32_write_phys_memory(struct target *target, uint32_t address,
-                                       uint32_t size, uint32_t count, const uint8_t *buffer);
-extern int nds32_soft_reset_halt(struct target *target);
+               uint32_t size, uint32_t count, const uint8_t *buffer);
 extern uint32_t nds32_nextpc(struct nds32 *nds32, int current, uint32_t address);
 extern int nds32_examine_debug_reason(struct nds32 *nds32);
 extern int nds32_step(struct target *target, int current,
-                       uint32_t address, int handle_breakpoints);
+               uint32_t address, int handle_breakpoints);
 extern int nds32_target_state(struct nds32 *nds32, enum target_state *state);
 extern int nds32_halt(struct target *target);
 extern int nds32_poll(struct target *target);
 extern int nds32_resume(struct target *target, int current,
-                       uint32_t address, int handle_breakpoints, int debug_execution);
+               uint32_t address, int handle_breakpoints, int debug_execution);
 extern int nds32_assert_reset(struct target *target);
 extern int nds32_init(struct nds32 *nds32);
-extern int nds32_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info);
-extern int nds32_gdb_fileio_write_memory(struct nds32 *nds32, uint32_t address,
-                                               uint32_t size, const uint8_t *buffer);
-extern int nds32_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c);
 extern int nds32_reset_halt(struct nds32 *nds32);
+extern int nds32_login(struct nds32 *nds32);
 
 /** Convert target handle to generic Andes target state handle. */
 static inline struct nds32 *target_to_nds32(struct target *target)
diff --git a/src/target/nds32_aice.c b/src/target/nds32_aice.c
new file mode 100644 (file)
index 0000000..78ae8c2
--- /dev/null
@@ -0,0 +1,157 @@
+/***************************************************************************
+ *   Copyright (C) 2013 Andes technology.                                  *
+ *   Hsiangkai Wang <hkwang@andestech.com>                                 *
+ *                                                                         *
+ *   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                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ ***************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <helper/log.h>
+#include "nds32_aice.h"
+
+int aice_read_reg_64(struct aice_port_s *aice, uint32_t num, uint64_t *val)
+{
+       if (aice->port->api->read_reg_64 == NULL) {
+               LOG_WARNING("Not implemented: %s", __func__);
+               return ERROR_FAIL;
+       }
+
+       return aice->port->api->read_reg_64(num, val);
+}
+
+int aice_write_reg_64(struct aice_port_s *aice, uint32_t num, uint64_t val)
+{
+       if (aice->port->api->write_reg_64 == NULL) {
+               LOG_WARNING("Not implemented: %s", __func__);
+               return ERROR_FAIL;
+       }
+
+       return aice->port->api->write_reg_64(num, val);
+}
+
+int aice_select_target(struct aice_port_s *aice, uint32_t target_id)
+{
+       if (aice->port->api->select_target == NULL) {
+               LOG_WARNING("Not implemented: %s", __func__);
+               return ERROR_FAIL;
+       }
+
+       return aice->port->api->select_target(target_id);
+}
+
+int aice_read_tlb(struct aice_port_s *aice, uint32_t virtual_address,
+               uint32_t *physical_address)
+{
+       if (aice->port->api->read_tlb == NULL) {
+               LOG_WARNING("Not implemented: %s", __func__);
+               return ERROR_FAIL;
+       }
+
+       return aice->port->api->read_tlb(virtual_address, physical_address);
+}
+
+int aice_cache_ctl(struct aice_port_s *aice, uint32_t subtype, uint32_t address)
+{
+       if (aice->port->api->cache_ctl == NULL) {
+               LOG_WARNING("Not implemented: %s", __func__);
+               return ERROR_FAIL;
+       }
+
+       return aice->port->api->cache_ctl(subtype, address);
+}
+
+int aice_set_retry_times(struct aice_port_s *aice, uint32_t a_retry_times)
+{
+       if (aice->port->api->set_retry_times == NULL) {
+               LOG_WARNING("Not implemented: %s", __func__);
+               return ERROR_FAIL;
+       }
+
+       return aice->port->api->set_retry_times(a_retry_times);
+}
+
+int aice_program_edm(struct aice_port_s *aice, char *command_sequence)
+{
+       if (aice->port->api->program_edm == NULL) {
+               LOG_WARNING("Not implemented: %s", __func__);
+               return ERROR_FAIL;
+       }
+
+       return aice->port->api->program_edm(command_sequence);
+}
+
+int aice_pack_command(struct aice_port_s *aice, bool enable_pack_command)
+{
+       if (aice->port->api->pack_command == NULL) {
+               LOG_WARNING("Not implemented: %s", __func__);
+               return ERROR_FAIL;
+       }
+
+       return aice->port->api->pack_command(enable_pack_command);
+}
+
+int aice_execute(struct aice_port_s *aice, uint32_t *instructions,
+               uint32_t instruction_num)
+{
+       if (aice->port->api->execute == NULL) {
+               LOG_WARNING("Not implemented: %s", __func__);
+               return ERROR_FAIL;
+       }
+
+       return aice->port->api->execute(instructions, instruction_num);
+}
+
+int aice_set_custom_srst_script(struct aice_port_s *aice, const char *script)
+{
+       if (aice->port->api->set_custom_srst_script == NULL) {
+               LOG_WARNING("Not implemented: %s", __func__);
+               return ERROR_FAIL;
+       }
+
+       return aice->port->api->set_custom_srst_script(script);
+}
+
+int aice_set_custom_trst_script(struct aice_port_s *aice, const char *script)
+{
+       if (aice->port->api->set_custom_trst_script == NULL) {
+               LOG_WARNING("Not implemented: %s", __func__);
+               return ERROR_FAIL;
+       }
+
+       return aice->port->api->set_custom_trst_script(script);
+}
+
+int aice_set_custom_restart_script(struct aice_port_s *aice, const char *script)
+{
+       if (aice->port->api->set_custom_restart_script == NULL) {
+               LOG_WARNING("Not implemented: %s", __func__);
+               return ERROR_FAIL;
+       }
+
+       return aice->port->api->set_custom_restart_script(script);
+}
+
+int aice_set_count_to_check_dbger(struct aice_port_s *aice, uint32_t count_to_check)
+{
+       if (aice->port->api->set_count_to_check_dbger == NULL) {
+               LOG_WARNING("Not implemented: %s", __func__);
+               return ERROR_FAIL;
+       }
+
+       return aice->port->api->set_count_to_check_dbger(count_to_check);
+}
diff --git a/src/target/nds32_aice.h b/src/target/nds32_aice.h
new file mode 100644 (file)
index 0000000..abea8df
--- /dev/null
@@ -0,0 +1,160 @@
+/***************************************************************************
+ *   Copyright (C) 2013 Andes technology.                                  *
+ *   Hsiangkai Wang <hkwang@andestech.com>                                 *
+ *                                                                         *
+ *   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                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ ***************************************************************************/
+#ifndef __NDS32_AICE_H__
+#define __NDS32_AICE_H__
+
+#include <jtag/aice/aice_port.h>
+
+int aice_read_reg_64(struct aice_port_s *aice, uint32_t num, uint64_t *val);
+int aice_write_reg_64(struct aice_port_s *aice, uint32_t num, uint64_t val);
+int aice_select_target(struct aice_port_s *aice, uint32_t target_id);
+int aice_read_tlb(struct aice_port_s *aice, uint32_t virtual_address,
+               uint32_t *physical_address);
+int aice_cache_ctl(struct aice_port_s *aice, uint32_t subtype, uint32_t address);
+int aice_set_retry_times(struct aice_port_s *aice, uint32_t a_retry_times);
+int aice_program_edm(struct aice_port_s *aice, char *command_sequence);
+int aice_pack_command(struct aice_port_s *aice, bool enable_pack_command);
+int aice_execute(struct aice_port_s *aice, uint32_t *instructions,
+               uint32_t instruction_num);
+int aice_set_custom_srst_script(struct aice_port_s *aice, const char *script);
+int aice_set_custom_trst_script(struct aice_port_s *aice, const char *script);
+int aice_set_custom_restart_script(struct aice_port_s *aice, const char *script);
+int aice_set_count_to_check_dbger(struct aice_port_s *aice, uint32_t count_to_check);
+
+static inline int aice_open(struct aice_port_s *aice, struct aice_port_param_s *param)
+{
+       return aice->port->api->open(param);
+}
+
+static inline int aice_close(struct aice_port_s *aice)
+{
+       return aice->port->api->close();
+}
+
+static inline int aice_reset(struct aice_port_s *aice)
+{
+       return aice->port->api->reset();
+}
+
+static inline int aice_assert_srst(struct aice_port_s *aice,
+               enum aice_srst_type_s srst)
+{
+       return aice->port->api->assert_srst(srst);
+}
+
+static inline int aice_run(struct aice_port_s *aice)
+{
+       return aice->port->api->run();
+}
+
+static inline int aice_halt(struct aice_port_s *aice)
+{
+       return aice->port->api->halt();
+}
+
+static inline int aice_step(struct aice_port_s *aice)
+{
+       return aice->port->api->step();
+}
+
+static inline int aice_read_register(struct aice_port_s *aice, uint32_t num,
+               uint32_t *val)
+{
+       return aice->port->api->read_reg(num, val);
+}
+
+static inline int aice_write_register(struct aice_port_s *aice, uint32_t num,
+               uint32_t val)
+{
+       return aice->port->api->write_reg(num, val);
+}
+
+static inline int aice_read_debug_reg(struct aice_port_s *aice, uint32_t addr,
+               uint32_t *val)
+{
+       return aice->port->api->read_debug_reg(addr, val);
+}
+
+static inline int aice_write_debug_reg(struct aice_port_s *aice, uint32_t addr,
+               const uint32_t val)
+{
+       return aice->port->api->write_debug_reg(addr, val);
+}
+
+static inline int aice_read_mem_unit(struct aice_port_s *aice, uint32_t addr,
+               uint32_t size, uint32_t count, uint8_t *buffer)
+{
+       return aice->port->api->read_mem_unit(addr, size, count, buffer);
+}
+
+static inline int aice_write_mem_unit(struct aice_port_s *aice, uint32_t addr,
+               uint32_t size, uint32_t count, const uint8_t *buffer)
+{
+       return aice->port->api->write_mem_unit(addr, size, count, buffer);
+}
+
+static inline int aice_read_mem_bulk(struct aice_port_s *aice, uint32_t addr,
+               uint32_t length, uint8_t *buffer)
+{
+       return aice->port->api->read_mem_bulk(addr, length, buffer);
+}
+
+static inline int aice_write_mem_bulk(struct aice_port_s *aice, uint32_t addr,
+               uint32_t length, const uint8_t *buffer)
+{
+       return aice->port->api->write_mem_bulk(addr, length, buffer);
+}
+
+static inline int aice_idcode(struct aice_port_s *aice, uint32_t *idcode,
+               uint8_t *num_of_idcode)
+{
+       return aice->port->api->idcode(idcode, num_of_idcode);
+}
+
+static inline int aice_state(struct aice_port_s *aice,
+               enum aice_target_state_s *state)
+{
+       return aice->port->api->state(state);
+}
+
+static inline int aice_set_jtag_clock(struct aice_port_s *aice, uint32_t a_clock)
+{
+       return aice->port->api->set_jtag_clock(a_clock);
+}
+
+static inline int aice_memory_access(struct aice_port_s *aice,
+               enum nds_memory_access a_access)
+{
+       return aice->port->api->memory_access(a_access);
+}
+
+static inline int aice_memory_mode(struct aice_port_s *aice,
+               enum nds_memory_select mem_select)
+{
+       return aice->port->api->memory_mode(mem_select);
+}
+
+static inline int aice_set_data_endian(struct aice_port_s *aice,
+               enum aice_target_endian target_data_endian)
+{
+       return aice->port->api->set_data_endian(target_data_endian);
+}
+
+#endif
diff --git a/src/target/nds32_cmd.c b/src/target/nds32_cmd.c
new file mode 100644 (file)
index 0000000..a16308e
--- /dev/null
@@ -0,0 +1,1106 @@
+/***************************************************************************
+ *   Copyright (C) 2013 Andes Technology                                   *
+ *   Hsiangkai Wang <hkwang@andestech.com>                                 *
+ *                                                                         *
+ *   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                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <helper/command.h>
+#include "nds32.h"
+#include "nds32_aice.h"
+#include "nds32_disassembler.h"
+
+extern struct nds32_edm_operation nds32_edm_ops[NDS32_EDM_OPERATION_MAX_NUM];
+extern uint32_t nds32_edm_ops_num;
+
+static const char *const NDS_MEMORY_ACCESS_NAME[] = {
+       "BUS",
+       "CPU",
+};
+
+static const char *const NDS_MEMORY_SELECT_NAME[] = {
+       "AUTO",
+       "MEM",
+       "ILM",
+       "DLM",
+};
+
+COMMAND_HANDLER(handle_nds32_dssim_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct nds32 *nds32 = target_to_nds32(target);
+
+       if (!is_nds32(nds32)) {
+               command_print(CMD_CTX, "current target isn't an Andes core");
+               return ERROR_FAIL;
+       }
+
+       if (CMD_ARGC > 0) {
+               if (strcmp(CMD_ARGV[0], "on") == 0)
+                       nds32->step_isr_enable = true;
+               if (strcmp(CMD_ARGV[0], "off") == 0)
+                       nds32->step_isr_enable = false;
+       }
+
+       command_print(CMD_CTX, "$INT_MASK.DSSIM: %d", nds32->step_isr_enable);
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_nds32_memory_access_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct aice_port_s *aice = target_to_aice(target);
+
+       if (!is_nds32(nds32)) {
+               command_print(CMD_CTX, "current target isn't an Andes core");
+               return ERROR_FAIL;
+       }
+
+       if (CMD_ARGC > 0) {
+
+               /* If target has no cache, always use BUS mode
+                * to access memory. */
+               struct nds32_memory *memory = &(nds32->memory);
+
+               if (memory->dcache.line_size == 0) {
+                       /* There is no Dcache. */
+                       nds32->memory.access_channel = NDS_MEMORY_ACC_BUS;
+               } else if (memory->dcache.enable == false) {
+                       /* Dcache is disabled. */
+                       nds32->memory.access_channel = NDS_MEMORY_ACC_BUS;
+               } else {
+                       /* There is Dcache and Dcache is enabled. */
+                       if (strcmp(CMD_ARGV[0], "bus") == 0)
+                               nds32->memory.access_channel = NDS_MEMORY_ACC_BUS;
+                       else if (strcmp(CMD_ARGV[0], "cpu") == 0)
+                               nds32->memory.access_channel = NDS_MEMORY_ACC_CPU;
+                       else /* default access channel is NDS_MEMORY_ACC_CPU */
+                               nds32->memory.access_channel = NDS_MEMORY_ACC_CPU;
+               }
+
+               aice_memory_access(aice, nds32->memory.access_channel);
+       }
+
+       command_print(CMD_CTX, "memory access channel: %s",
+                       NDS_MEMORY_ACCESS_NAME[nds32->memory.access_channel]);
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_nds32_memory_mode_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct aice_port_s *aice = target_to_aice(target);
+
+       if (!is_nds32(nds32)) {
+               command_print(CMD_CTX, "current target isn't an Andes core");
+               return ERROR_FAIL;
+       }
+
+       if (CMD_ARGC > 0) {
+
+               if (nds32->edm.access_control == false) {
+                       command_print(CMD_CTX, "Target does not support ACC_CTL. "
+                                       "Set memory mode to MEMORY");
+                       nds32->memory.mode = NDS_MEMORY_SELECT_MEM;
+               } else if (nds32->edm.direct_access_local_memory == false) {
+                       command_print(CMD_CTX, "Target does not support direct access "
+                                       "local memory. Set memory mode to MEMORY");
+                       nds32->memory.mode = NDS_MEMORY_SELECT_MEM;
+
+                       /* set to ACC_CTL */
+                       aice_memory_mode(aice, nds32->memory.mode);
+               } else {
+                       if (strcmp(CMD_ARGV[0], "auto") == 0) {
+                               nds32->memory.mode = NDS_MEMORY_SELECT_AUTO;
+                       } else if (strcmp(CMD_ARGV[0], "mem") == 0) {
+                               nds32->memory.mode = NDS_MEMORY_SELECT_MEM;
+                       } else if (strcmp(CMD_ARGV[0], "ilm") == 0) {
+                               if (nds32->memory.ilm_base == 0)
+                                       command_print(CMD_CTX, "Target does not support ILM");
+                               else
+                                       nds32->memory.mode = NDS_MEMORY_SELECT_ILM;
+                       } else if (strcmp(CMD_ARGV[0], "dlm") == 0) {
+                               if (nds32->memory.dlm_base == 0)
+                                       command_print(CMD_CTX, "Target does not support DLM");
+                               else
+                                       nds32->memory.mode = NDS_MEMORY_SELECT_DLM;
+                       }
+
+                       /* set to ACC_CTL */
+                       aice_memory_mode(aice, nds32->memory.mode);
+               }
+       }
+
+       command_print(CMD_CTX, "memory mode: %s",
+                       NDS_MEMORY_SELECT_NAME[nds32->memory.mode]);
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_nds32_cache_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct aice_port_s *aice = target_to_aice(target);
+       struct nds32_cache *icache = &(nds32->memory.icache);
+       struct nds32_cache *dcache = &(nds32->memory.dcache);
+       int result;
+
+       if (!is_nds32(nds32)) {
+               command_print(CMD_CTX, "current target isn't an Andes core");
+               return ERROR_FAIL;
+       }
+
+       if (CMD_ARGC > 0) {
+
+               if (strcmp(CMD_ARGV[0], "invalidate") == 0) {
+                       if ((dcache->line_size != 0) && (dcache->enable == true)) {
+                               /* D$ write back */
+                               result = aice_cache_ctl(aice, AICE_CACHE_CTL_L1D_WBALL, 0);
+                               if (result != ERROR_OK) {
+                                       command_print(CMD_CTX, "Write back data cache...failed");
+                                       return result;
+                               }
+
+                               command_print(CMD_CTX, "Write back data cache...done");
+
+                               /* D$ invalidate */
+                               result = aice_cache_ctl(aice, AICE_CACHE_CTL_L1D_INVALALL, 0);
+                               if (result != ERROR_OK) {
+                                       command_print(CMD_CTX, "Invalidate data cache...failed");
+                                       return result;
+                               }
+
+                               command_print(CMD_CTX, "Invalidate data cache...done");
+                       } else {
+                               if (dcache->line_size == 0)
+                                       command_print(CMD_CTX, "No data cache");
+                               else
+                                       command_print(CMD_CTX, "Data cache disabled");
+                       }
+
+                       if ((icache->line_size != 0) && (icache->enable == true)) {
+                               /* I$ invalidate */
+                               result = aice_cache_ctl(aice, AICE_CACHE_CTL_L1I_INVALALL, 0);
+                               if (result != ERROR_OK) {
+                                       command_print(CMD_CTX, "Invalidate instruction cache...failed");
+                                       return result;
+                               }
+
+                               command_print(CMD_CTX, "Invalidate instruction cache...done");
+                       } else {
+                               if (icache->line_size == 0)
+                                       command_print(CMD_CTX, "No instruction cache");
+                               else
+                                       command_print(CMD_CTX, "Instruction cache disabled");
+                       }
+               } else
+                       command_print(CMD_CTX, "No valid parameter");
+       }
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_nds32_icache_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct aice_port_s *aice = target_to_aice(target);
+       struct nds32_cache *icache = &(nds32->memory.icache);
+       int result;
+
+       if (!is_nds32(nds32)) {
+               command_print(CMD_CTX, "current target isn't an Andes core");
+               return ERROR_FAIL;
+       }
+
+       if (CMD_ARGC > 0) {
+
+               if (icache->line_size == 0) {
+                       command_print(CMD_CTX, "No instruction cache");
+                       return ERROR_OK;
+               }
+
+               if (strcmp(CMD_ARGV[0], "invalidate") == 0) {
+                       if (icache->enable == true) {
+                               /* I$ invalidate */
+                               result = aice_cache_ctl(aice, AICE_CACHE_CTL_L1I_INVALALL, 0);
+                               if (result != ERROR_OK) {
+                                       command_print(CMD_CTX, "Invalidate instruction cache...failed");
+                                       return result;
+                               }
+
+                               command_print(CMD_CTX, "Invalidate instruction cache...done");
+                       } else {
+                               command_print(CMD_CTX, "Instruction cache disabled");
+                       }
+               } else if (strcmp(CMD_ARGV[0], "enable") == 0) {
+                       uint32_t value;
+                       nds32_get_mapped_reg(nds32, IR8, &value);
+                       nds32_set_mapped_reg(nds32, IR8, value | 0x1);
+               } else if (strcmp(CMD_ARGV[0], "disable") == 0) {
+                       uint32_t value;
+                       nds32_get_mapped_reg(nds32, IR8, &value);
+                       nds32_set_mapped_reg(nds32, IR8, value & ~0x1);
+               } else if (strcmp(CMD_ARGV[0], "dump") == 0) {
+                       /* TODO: dump cache content */
+               } else {
+                       command_print(CMD_CTX, "No valid parameter");
+               }
+       }
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_nds32_dcache_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct aice_port_s *aice = target_to_aice(target);
+       struct nds32_cache *dcache = &(nds32->memory.dcache);
+       int result;
+
+       if (!is_nds32(nds32)) {
+               command_print(CMD_CTX, "current target isn't an Andes core");
+               return ERROR_FAIL;
+       }
+
+       if (CMD_ARGC > 0) {
+
+               if (dcache->line_size == 0) {
+                       command_print(CMD_CTX, "No data cache");
+                       return ERROR_OK;
+               }
+
+               if (strcmp(CMD_ARGV[0], "invalidate") == 0) {
+                       if (dcache->enable == true) {
+                               /* D$ write back */
+                               result = aice_cache_ctl(aice, AICE_CACHE_CTL_L1D_WBALL, 0);
+                               if (result != ERROR_OK) {
+                                       command_print(CMD_CTX, "Write back data cache...failed");
+                                       return result;
+                               }
+
+                               command_print(CMD_CTX, "Write back data cache...done");
+
+                               /* D$ invalidate */
+                               result = aice_cache_ctl(aice, AICE_CACHE_CTL_L1D_INVALALL, 0);
+                               if (result != ERROR_OK) {
+                                       command_print(CMD_CTX, "Invalidate data cache...failed");
+                                       return result;
+                               }
+
+                               command_print(CMD_CTX, "Invalidate data cache...done");
+                       } else {
+                               command_print(CMD_CTX, "Data cache disabled");
+                       }
+               } else if (strcmp(CMD_ARGV[0], "enable") == 0) {
+                       uint32_t value;
+                       nds32_get_mapped_reg(nds32, IR8, &value);
+                       nds32_set_mapped_reg(nds32, IR8, value | 0x2);
+               } else if (strcmp(CMD_ARGV[0], "disable") == 0) {
+                       uint32_t value;
+                       nds32_get_mapped_reg(nds32, IR8, &value);
+                       nds32_set_mapped_reg(nds32, IR8, value & ~0x2);
+               } else if (strcmp(CMD_ARGV[0], "dump") == 0) {
+                       /* TODO: dump cache content */
+               } else {
+                       command_print(CMD_CTX, "No valid parameter");
+               }
+       }
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_nds32_auto_break_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct nds32 *nds32 = target_to_nds32(target);
+
+       if (!is_nds32(nds32)) {
+               command_print(CMD_CTX, "current target isn't an Andes core");
+               return ERROR_FAIL;
+       }
+
+       if (CMD_ARGC > 0) {
+               if (strcmp(CMD_ARGV[0], "on") == 0)
+                       nds32->auto_convert_hw_bp = true;
+               if (strcmp(CMD_ARGV[0], "off") == 0)
+                       nds32->auto_convert_hw_bp = false;
+       }
+
+       if (nds32->auto_convert_hw_bp)
+               command_print(CMD_CTX, "convert sw break to hw break on ROM: on");
+       else
+               command_print(CMD_CTX, "convert sw break to hw break on ROM: off");
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_nds32_virtual_hosting_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct nds32 *nds32 = target_to_nds32(target);
+
+       if (!is_nds32(nds32)) {
+               command_print(CMD_CTX, "current target isn't an Andes core");
+               return ERROR_FAIL;
+       }
+
+       if (CMD_ARGC > 0) {
+               if (strcmp(CMD_ARGV[0], "on") == 0)
+                       nds32->virtual_hosting = true;
+               if (strcmp(CMD_ARGV[0], "off") == 0)
+                       nds32->virtual_hosting = false;
+       }
+
+       if (nds32->virtual_hosting)
+               LOG_INFO("virtual hosting: on");
+       else
+               LOG_INFO("virtual hosting: off");
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_nds32_global_stop_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct nds32 *nds32 = target_to_nds32(target);
+
+       if (!is_nds32(nds32)) {
+               command_print(CMD_CTX, "current target isn't an Andes core");
+               return ERROR_FAIL;
+       }
+
+       if (CMD_ARGC > 0) {
+               if (strcmp(CMD_ARGV[0], "on") == 0)
+                       nds32->global_stop = true;
+               if (strcmp(CMD_ARGV[0], "off") == 0)
+                       nds32->global_stop = false;
+       }
+
+       if (nds32->global_stop)
+               LOG_INFO("global stop: on");
+       else
+               LOG_INFO("global stop: off");
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_nds32_soft_reset_halt_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct nds32 *nds32 = target_to_nds32(target);
+
+       if (!is_nds32(nds32)) {
+               command_print(CMD_CTX, "current target isn't an Andes core");
+               return ERROR_FAIL;
+       }
+
+       if (CMD_ARGC > 0) {
+               if (strcmp(CMD_ARGV[0], "on") == 0)
+                       nds32->soft_reset_halt = true;
+               if (strcmp(CMD_ARGV[0], "off") == 0)
+                       nds32->soft_reset_halt = false;
+       }
+
+       if (nds32->soft_reset_halt)
+               LOG_INFO("soft-reset-halt: on");
+       else
+               LOG_INFO("soft-reset-halt: off");
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_nds32_boot_time_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct nds32 *nds32 = target_to_nds32(target);
+
+       if (!is_nds32(nds32)) {
+               command_print(CMD_CTX, "current target isn't an Andes core");
+               return ERROR_FAIL;
+       }
+
+       if (CMD_ARGC > 0)
+               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], nds32->boot_time);
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_nds32_login_edm_passcode_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct nds32 *nds32 = target_to_nds32(target);
+
+       if (!is_nds32(nds32)) {
+               command_print(CMD_CTX, "current target isn't an Andes core");
+               return ERROR_FAIL;
+       }
+
+       nds32->edm_passcode = strdup(CMD_ARGV[0]);
+
+       LOG_INFO("set EDM passcode: %s", nds32->edm_passcode);
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_nds32_login_edm_operation_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct nds32 *nds32 = target_to_nds32(target);
+
+       if (!is_nds32(nds32)) {
+               command_print(CMD_CTX, "current target isn't an Andes core");
+               return ERROR_FAIL;
+       }
+
+       if (CMD_ARGC > 1) {
+
+               uint32_t misc_reg_no;
+               uint32_t data;
+
+               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], misc_reg_no);
+               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], data);
+
+               if (nds32_edm_ops_num >= NDS32_EDM_OPERATION_MAX_NUM)
+                       return ERROR_FAIL;
+
+               /* Just save the operation. Execute it in nds32_login() */
+               nds32_edm_ops[nds32_edm_ops_num].reg_no = misc_reg_no;
+               nds32_edm_ops[nds32_edm_ops_num].value = data;
+               nds32_edm_ops_num++;
+       } else
+               return ERROR_FAIL;
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_nds32_reset_halt_as_init_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct nds32 *nds32 = target_to_nds32(target);
+
+       if (!is_nds32(nds32)) {
+               command_print(CMD_CTX, "current target isn't an Andes core");
+               return ERROR_FAIL;
+       }
+
+       if (CMD_ARGC > 0) {
+               if (strcmp(CMD_ARGV[0], "on") == 0)
+                       nds32->reset_halt_as_examine = true;
+               if (strcmp(CMD_ARGV[0], "off") == 0)
+                       nds32->reset_halt_as_examine = false;
+       }
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_nds32_keep_target_edm_ctl_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct nds32 *nds32 = target_to_nds32(target);
+
+       if (!is_nds32(nds32)) {
+               command_print(CMD_CTX, "current target isn't an Andes core");
+               return ERROR_FAIL;
+       }
+
+       if (CMD_ARGC > 0) {
+               if (strcmp(CMD_ARGV[0], "on") == 0)
+                       nds32->keep_target_edm_ctl = true;
+               if (strcmp(CMD_ARGV[0], "off") == 0)
+                       nds32->keep_target_edm_ctl = false;
+       }
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_nds32_decode_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct nds32 *nds32 = target_to_nds32(target);
+
+       if (!is_nds32(nds32)) {
+               command_print(CMD_CTX, "current target isn't an Andes core");
+               return ERROR_FAIL;
+       }
+
+       if (CMD_ARGC > 1) {
+
+               uint32_t addr;
+               uint32_t insn_count;
+               uint32_t opcode;
+               uint32_t read_addr;
+               uint32_t i;
+               struct nds32_instruction instruction;
+
+               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr);
+               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], insn_count);
+
+               read_addr = addr;
+               i = 0;
+               while (i < insn_count) {
+                       if (ERROR_OK != nds32_read_opcode(nds32, read_addr, &opcode))
+                               return ERROR_FAIL;
+                       if (ERROR_OK != nds32_evaluate_opcode(nds32, opcode,
+                                               read_addr, &instruction))
+                               return ERROR_FAIL;
+
+                       command_print(CMD_CTX, "%s", instruction.text);
+
+                       read_addr += instruction.instruction_size;
+                       i++;
+               }
+       } else if (CMD_ARGC == 1) {
+
+               uint32_t addr;
+               uint32_t opcode;
+               struct nds32_instruction instruction;
+
+               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr);
+
+               if (ERROR_OK != nds32_read_opcode(nds32, addr, &opcode))
+                       return ERROR_FAIL;
+               if (ERROR_OK != nds32_evaluate_opcode(nds32, opcode, addr, &instruction))
+                       return ERROR_FAIL;
+
+               command_print(CMD_CTX, "%s", instruction.text);
+       } else
+               return ERROR_FAIL;
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_nds32_word_access_mem_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct nds32 *nds32 = target_to_nds32(target);
+
+       if (!is_nds32(nds32)) {
+               command_print(CMD_CTX, "current target isn't an Andes core");
+               return ERROR_FAIL;
+       }
+
+       if (CMD_ARGC > 0) {
+               if (strcmp(CMD_ARGV[0], "on") == 0)
+                       nds32->word_access_mem = true;
+               if (strcmp(CMD_ARGV[0], "off") == 0)
+                       nds32->word_access_mem = false;
+       }
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_nds32_query_target_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct nds32 *nds32 = target_to_nds32(target);
+
+       if (!is_nds32(nds32)) {
+               command_print(CMD_CTX, "current target isn't an Andes core");
+               return ERROR_FAIL;
+       }
+
+       command_print(CMD_CTX, "OCD");
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_nds32_query_endian_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct nds32 *nds32 = target_to_nds32(target);
+
+       if (!is_nds32(nds32)) {
+               command_print(CMD_CTX, "current target isn't an Andes core");
+               return ERROR_FAIL;
+       }
+
+       uint32_t value_psw;
+       nds32_get_mapped_reg(nds32, IR0, &value_psw);
+
+       if (value_psw & 0x20)
+               command_print(CMD_CTX, "BE");
+       else
+               command_print(CMD_CTX, "LE");
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_nds32_query_cpuid_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct nds32 *nds32 = target_to_nds32(target);
+
+       if (!is_nds32(nds32)) {
+               command_print(CMD_CTX, "current target isn't an Andes core");
+               return ERROR_FAIL;
+       }
+
+       command_print(CMD_CTX, "CPUID: %s", target_name(target));
+
+       return ERROR_OK;
+}
+
+static int jim_nds32_bulk_write(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+{
+       const char *cmd_name = Jim_GetString(argv[0], NULL);
+
+       Jim_GetOptInfo goi;
+       Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
+
+       if (goi.argc < 3) {
+               Jim_SetResultFormatted(goi.interp,
+                               "usage: %s <address> <count> <data>", cmd_name);
+               return JIM_ERR;
+       }
+
+       int e;
+       jim_wide address;
+       e = Jim_GetOpt_Wide(&goi, &address);
+       if (e != JIM_OK)
+               return e;
+
+       jim_wide count;
+       e = Jim_GetOpt_Wide(&goi, &count);
+       if (e != JIM_OK)
+               return e;
+
+       uint32_t *data = malloc(count * sizeof(uint32_t));
+       jim_wide i;
+       for (i = 0; i < count; i++) {
+               jim_wide tmp;
+               e = Jim_GetOpt_Wide(&goi, &tmp);
+               if (e != JIM_OK)
+                       return e;
+               data[i] = (uint32_t)tmp;
+       }
+
+       /* all args must be consumed */
+       if (goi.argc != 0)
+               return JIM_ERR;
+
+       struct target *target = Jim_CmdPrivData(goi.interp);
+       int result;
+
+       result = target_write_buffer(target, address, count * 4, (const uint8_t *)data);
+
+       free(data);
+
+       return result;
+}
+
+static int jim_nds32_multi_write(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+{
+       const char *cmd_name = Jim_GetString(argv[0], NULL);
+
+       Jim_GetOptInfo goi;
+       Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
+
+       if (goi.argc < 3) {
+               Jim_SetResultFormatted(goi.interp,
+                               "usage: %s # of pairs [<address> <data>]+", cmd_name);
+               return JIM_ERR;
+       }
+
+       int e;
+       jim_wide num_of_pairs;
+       e = Jim_GetOpt_Wide(&goi, &num_of_pairs);
+       if (e != JIM_OK)
+               return e;
+
+       struct target *target = Jim_CmdPrivData(goi.interp);
+       struct aice_port_s *aice = target_to_aice(target);
+       int result;
+       uint32_t address;
+       uint32_t data;
+       jim_wide i;
+
+       aice_pack_command(aice, true);
+       for (i = 0; i < num_of_pairs; i++) {
+               jim_wide tmp;
+               e = Jim_GetOpt_Wide(&goi, &tmp);
+               if (e != JIM_OK)
+                       break;
+               address = (uint32_t)tmp;
+
+               e = Jim_GetOpt_Wide(&goi, &tmp);
+               if (e != JIM_OK)
+                       break;
+               data = (uint32_t)tmp;
+
+               result = target_write_buffer(target, address, 4, (const uint8_t *)&data);
+               if (result != ERROR_OK)
+                       break;
+       }
+       aice_pack_command(aice, false);
+
+       /* all args must be consumed */
+       if (goi.argc != 0)
+               return JIM_ERR;
+
+       return ERROR_OK;
+}
+
+static int jim_nds32_bulk_read(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+{
+       const char *cmd_name = Jim_GetString(argv[0], NULL);
+
+       Jim_GetOptInfo goi;
+       Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
+
+       if (goi.argc < 2) {
+               Jim_SetResultFormatted(goi.interp,
+                               "usage: %s <address> <count>", cmd_name);
+               return JIM_ERR;
+       }
+
+       int e;
+       jim_wide address;
+       e = Jim_GetOpt_Wide(&goi, &address);
+       if (e != JIM_OK)
+               return e;
+
+       jim_wide count;
+       e = Jim_GetOpt_Wide(&goi, &count);
+       if (e != JIM_OK)
+               return e;
+
+       /* all args must be consumed */
+       if (goi.argc != 0)
+               return JIM_ERR;
+
+       struct target *target = Jim_CmdPrivData(goi.interp);
+       uint32_t *data = malloc(count * sizeof(uint32_t));
+       int result;
+       result = target_read_buffer(target, address, count * 4, (uint8_t *)data);
+       char data_str[11];
+
+       jim_wide i;
+       Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+       for (i = 0; i < count; i++) {
+               sprintf(data_str, "0x%08x ", data[i]);
+               Jim_AppendStrings(interp, Jim_GetResult(interp), data_str, NULL);
+       }
+
+       free(data);
+
+       return result;
+}
+
+static int jim_nds32_read_edm_sr(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+{
+       const char *cmd_name = Jim_GetString(argv[0], NULL);
+
+       Jim_GetOptInfo goi;
+       Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
+
+       if (goi.argc < 1) {
+               Jim_SetResultFormatted(goi.interp,
+                               "usage: %s <edm_sr_name>", cmd_name);
+               return JIM_ERR;
+       }
+
+       int e;
+       char *edm_sr_name;
+       int edm_sr_name_len;
+       e = Jim_GetOpt_String(&goi, &edm_sr_name, &edm_sr_name_len);
+       if (e != JIM_OK)
+               return e;
+
+       /* all args must be consumed */
+       if (goi.argc != 0)
+               return JIM_ERR;
+
+       uint32_t edm_sr_number;
+       uint32_t edm_sr_value;
+       if (strncmp(edm_sr_name, "edm_dtr", edm_sr_name_len) == 0)
+               edm_sr_number = NDS_EDM_SR_EDM_DTR;
+       else if (strncmp(edm_sr_name, "edmsw", edm_sr_name_len) == 0)
+               edm_sr_number = NDS_EDM_SR_EDMSW;
+       else
+               return ERROR_FAIL;
+
+       struct target *target = Jim_CmdPrivData(goi.interp);
+       struct aice_port_s *aice = target_to_aice(target);
+       char data_str[11];
+
+       aice_read_debug_reg(aice, edm_sr_number, &edm_sr_value);
+
+       sprintf(data_str, "0x%08x", edm_sr_value);
+       Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+       Jim_AppendStrings(interp, Jim_GetResult(interp), data_str, NULL);
+
+       return ERROR_OK;
+}
+
+static int jim_nds32_write_edm_sr(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+{
+       const char *cmd_name = Jim_GetString(argv[0], NULL);
+
+       Jim_GetOptInfo goi;
+       Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
+
+       if (goi.argc < 2) {
+               Jim_SetResultFormatted(goi.interp,
+                               "usage: %s <edm_sr_name> <value>", cmd_name);
+               return JIM_ERR;
+       }
+
+       int e;
+       char *edm_sr_name;
+       int edm_sr_name_len;
+       e = Jim_GetOpt_String(&goi, &edm_sr_name, &edm_sr_name_len);
+       if (e != JIM_OK)
+               return e;
+
+       jim_wide value;
+       e = Jim_GetOpt_Wide(&goi, &value);
+       if (e != JIM_OK)
+               return e;
+
+       /* all args must be consumed */
+       if (goi.argc != 0)
+               return JIM_ERR;
+
+       uint32_t edm_sr_number;
+       if (strncmp(edm_sr_name, "edm_dtr", edm_sr_name_len) == 0)
+               edm_sr_number = NDS_EDM_SR_EDM_DTR;
+       else
+               return ERROR_FAIL;
+
+       struct target *target = Jim_CmdPrivData(goi.interp);
+       struct aice_port_s *aice = target_to_aice(target);
+
+       aice_write_debug_reg(aice, edm_sr_number, value);
+
+       return ERROR_OK;
+}
+
+static const struct command_registration nds32_query_command_handlers[] = {
+       {
+               .name = "target",
+               .handler = handle_nds32_query_target_command,
+               .mode = COMMAND_EXEC,
+               .usage = "",
+               .help = "reply 'OCD' for gdb to identify server-side is OpenOCD",
+       },
+       {
+               .name = "endian",
+               .handler = handle_nds32_query_endian_command,
+               .mode = COMMAND_EXEC,
+               .usage = "",
+               .help = "query target endian",
+       },
+       {
+               .name = "cpuid",
+               .handler = handle_nds32_query_cpuid_command,
+               .mode = COMMAND_EXEC,
+               .usage = "",
+               .help = "query CPU ID",
+       },
+
+       COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration nds32_exec_command_handlers[] = {
+       {
+               .name = "dssim",
+               .handler = handle_nds32_dssim_command,
+               .mode = COMMAND_EXEC,
+               .usage = "['on'|'off']",
+               .help = "display/change $INT_MASK.DSSIM status",
+       },
+       {
+               .name = "mem_access",
+               .handler = handle_nds32_memory_access_command,
+               .mode = COMMAND_EXEC,
+               .usage = "['bus'|'cpu']",
+               .help = "display/change memory access channel",
+       },
+       {
+               .name = "mem_mode",
+               .handler = handle_nds32_memory_mode_command,
+               .mode = COMMAND_EXEC,
+               .usage = "['auto'|'mem'|'ilm'|'dlm']",
+               .help = "display/change memory mode",
+       },
+       {
+               .name = "cache",
+               .handler = handle_nds32_cache_command,
+               .mode = COMMAND_EXEC,
+               .usage = "['invalidate']",
+               .help = "cache control",
+       },
+       {
+               .name = "icache",
+               .handler = handle_nds32_icache_command,
+               .mode = COMMAND_EXEC,
+               .usage = "['invalidate'|'enable'|'disable'|'dump']",
+               .help = "icache control",
+       },
+       {
+               .name = "dcache",
+               .handler = handle_nds32_dcache_command,
+               .mode = COMMAND_EXEC,
+               .usage = "['invalidate'|'enable'|'disable'|'dump']",
+               .help = "dcache control",
+       },
+       {
+               .name = "auto_break",
+               .handler = handle_nds32_auto_break_command,
+               .mode = COMMAND_EXEC,
+               .usage = "['on'|'off']",
+               .help = "convert software breakpoints to hardware breakpoints if needed",
+       },
+       {
+               .name = "virtual_hosting",
+               .handler = handle_nds32_virtual_hosting_command,
+               .mode = COMMAND_ANY,
+               .usage = "['on'|'off']",
+               .help = "turn on/off virtual hosting",
+       },
+       {
+               .name = "global_stop",
+               .handler = handle_nds32_global_stop_command,
+               .mode = COMMAND_ANY,
+               .usage = "['on'|'off']",
+               .help = "turn on/off global stop. After turning on, every load/store" \
+                        "instructions will be stopped to check memory access.",
+       },
+       {
+               .name = "soft_reset_halt",
+               .handler = handle_nds32_soft_reset_halt_command,
+               .mode = COMMAND_ANY,
+               .usage = "['on'|'off']",
+               .help = "as issuing rest-halt, to use soft-reset-halt or not." \
+                        "the feature is for backward-compatible.",
+       },
+       {
+               .name = "boot_time",
+               .handler = handle_nds32_boot_time_command,
+               .mode = COMMAND_CONFIG,
+               .usage = "milliseconds",
+               .help = "set the period to wait after srst.",
+       },
+       {
+               .name = "login_edm_passcode",
+               .handler = handle_nds32_login_edm_passcode_command,
+               .mode = COMMAND_CONFIG,
+               .usage = "passcode",
+               .help = "set EDM passcode for secure MCU debugging.",
+       },
+       {
+               .name = "login_edm_operation",
+               .handler = handle_nds32_login_edm_operation_command,
+               .mode = COMMAND_CONFIG,
+               .usage = "login_edm_operation misc_reg_no value",
+               .help = "add EDM operations for secure MCU debugging.",
+       },
+       {
+               .name = "reset_halt_as_init",
+               .handler = handle_nds32_reset_halt_as_init_command,
+               .mode = COMMAND_CONFIG,
+               .usage = "['on'|'off']",
+               .help = "reset halt as openocd init.",
+       },
+       {
+               .name = "keep_target_edm_ctl",
+               .handler = handle_nds32_keep_target_edm_ctl_command,
+               .mode = COMMAND_CONFIG,
+               .usage = "['on'|'off']",
+               .help = "Backup/Restore target EDM_CTL register.",
+       },
+       {
+               .name = "decode",
+               .handler = handle_nds32_decode_command,
+               .mode = COMMAND_EXEC,
+               .usage = "address icount",
+               .help = "decode instruction.",
+       },
+       {
+               .name = "word_access_mem",
+               .handler = handle_nds32_word_access_mem_command,
+               .mode = COMMAND_ANY,
+               .usage = "['on'|'off']",
+               .help = "Always use word-aligned address to access memory.",
+       },
+       {
+               .name = "bulk_write",
+               .jim_handler = jim_nds32_bulk_write,
+               .mode = COMMAND_EXEC,
+               .help = "Write multiple 32-bit words to target memory",
+               .usage = "address count data",
+       },
+       {
+               .name = "multi_write",
+               .jim_handler = jim_nds32_multi_write,
+               .mode = COMMAND_EXEC,
+               .help = "Write multiple addresses/words to target memory",
+               .usage = "num_of_pairs [address data]+",
+       },
+       {
+               .name = "bulk_read",
+               .jim_handler = jim_nds32_bulk_read,
+               .mode = COMMAND_EXEC,
+               .help = "Read multiple 32-bit words from target memory",
+               .usage = "address count",
+       },
+       {
+               .name = "read_edmsr",
+               .jim_handler = jim_nds32_read_edm_sr,
+               .mode = COMMAND_EXEC,
+               .help = "Read EDM system register",
+               .usage = "['edmsw'|'edm_dtr']",
+       },
+       {
+               .name = "write_edmsr",
+               .jim_handler = jim_nds32_write_edm_sr,
+               .mode = COMMAND_EXEC,
+               .help = "Write EDM system register",
+               .usage = "['edm_dtr'] value",
+       },
+       {
+               .name = "query",
+               .mode = COMMAND_EXEC,
+               .help = "Andes query command group",
+               .usage = "",
+               .chain = nds32_query_command_handlers,
+       },
+
+       COMMAND_REGISTRATION_DONE
+};
+
+const struct command_registration nds32_command_handlers[] = {
+       {
+               .name = "nds",
+               .mode = COMMAND_ANY,
+               .help = "Andes command group",
+               .usage = "",
+               .chain = nds32_exec_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
diff --git a/src/target/nds32_cmd.h b/src/target/nds32_cmd.h
new file mode 100644 (file)
index 0000000..44d361e
--- /dev/null
@@ -0,0 +1,27 @@
+/***************************************************************************
+ *   Copyright (C) 2013 Andes Technology                                   *
+ *   Hsiangkai Wang <hkwang@andestech.com>                                 *
+ *                                                                         *
+ *   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                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ ***************************************************************************/
+
+#ifndef __NDS32_CMD_H__
+#define __NDS32_CMD_H__
+#include <helper/command.h>
+
+extern const struct command_registration nds32_command_handlers[];
+
+#endif /* __NDS32_CMD_H__ */
diff --git a/src/target/nds32_disassembler.c b/src/target/nds32_disassembler.c
new file mode 100644 (file)
index 0000000..d859e0c
--- /dev/null
@@ -0,0 +1,3637 @@
+/***************************************************************************
+ *   Copyright (C) 2013 Andes Technology                                   *
+ *   Hsiangkai Wang <hkwang@andestech.com>                                 *
+ *                                                                         *
+ *   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                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <helper/log.h>
+#include <target/target.h>
+#include "nds32_disassembler.h"
+
+static const int enable4_bits[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
+
+int nds32_read_opcode(struct nds32 *nds32, uint32_t address, uint32_t *value)
+{
+       struct target *target = nds32->target;
+       uint8_t value_buf[4];
+
+       if (!target_was_examined(target)) {
+               LOG_ERROR("Target not examined yet");
+               return ERROR_FAIL;
+       }
+
+       int retval = target_read_buffer(target, address, 4, value_buf);
+
+       if (retval == ERROR_OK) {
+               /* instructions are always big-endian */
+               *value = be_to_h_u32(value_buf);
+
+               LOG_DEBUG("address: 0x%8.8" PRIx32 ", value: 0x%8.8" PRIx32 "",
+                               address,
+                               *value);
+       } else {
+               *value = 0x0;
+               LOG_DEBUG("address: 0x%8.8" PRIx32 " failed",
+                               address);
+       }
+
+       return retval;
+}
+
+static int nds32_parse_type_0(uint32_t opcode, int32_t *imm)
+{
+       *imm = opcode & 0x1FFFFFF;
+
+       return ERROR_OK;
+}
+
+static int nds32_parse_type_1(uint32_t opcode, uint8_t *rt, int32_t *imm)
+{
+       *rt = (opcode >> 20) & 0x1F;
+       *imm = opcode & 0xFFFFF;
+
+       return ERROR_OK;
+}
+
+static int nds32_parse_type_2(uint32_t opcode, uint8_t *rt, uint8_t *ra, int32_t *imm)
+{
+       *rt = (opcode >> 20) & 0x1F;
+       *ra = (opcode >> 15) & 0x1F;
+       *imm = opcode & 0x7FFF;
+
+       return ERROR_OK;
+}
+
+static int nds32_parse_type_3(uint32_t opcode, uint8_t *rt, uint8_t *ra,
+               uint8_t *rb, int32_t *imm)
+{
+       *rt = (opcode >> 20) & 0x1F;
+       *ra = (opcode >> 15) & 0x1F;
+       *rb = (opcode >> 10) & 0x1F;
+       *imm = opcode & 0x3FF;
+
+       return ERROR_OK;
+}
+
+static int nds32_parse_type_4(uint32_t opcode, uint8_t *rt, uint8_t *ra,
+               uint8_t *rb, uint8_t *rd, uint8_t *sub_opc)
+{
+       *rt = (opcode >> 20) & 0x1F;
+       *ra = (opcode >> 15) & 0x1F;
+       *rb = (opcode >> 10) & 0x1F;
+       *rd = (opcode >> 5) & 0x1F;
+       *sub_opc = opcode & 0x1F;
+
+       return ERROR_OK;
+}
+
+/* LBI, LHI, LWI, LBI.bi, LHI.bi, LWI.bi */
+static int nds32_parse_group_0_insn(struct nds32 *nds32, uint32_t opcode,
+               uint32_t address,
+               struct nds32_instruction *instruction)
+{
+       uint8_t opc_6;
+
+       opc_6 = instruction->info.opc_6;
+
+       switch (opc_6 & 0x7) {
+               case 0: /* LBI */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra), &(instruction->info.imm));
+                       instruction->info.imm = (instruction->info.imm << 17) >> 17; /* sign-extend */
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_start += instruction->info.imm;
+                       instruction->access_end = instruction->access_start + 1;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLBI\t$r%d,[$r%d+#%d]",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 1: /* LHI */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra), &(instruction->info.imm));
+                       instruction->info.imm = (instruction->info.imm << 17) >> 16; /* sign-extend */
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_start += instruction->info.imm;
+                       instruction->access_end = instruction->access_start + 2;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLHI\t$r%d,[$r%d+#%d]",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 2: /* LWI */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra), &(instruction->info.imm));
+                       instruction->info.imm = (instruction->info.imm << 17) >> 15; /* sign-extend */
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_start += instruction->info.imm;
+                       instruction->access_end = instruction->access_start + 4;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLWI\t$r%d,[$r%d+#%d]",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 4: /* LBI.bi */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra), &(instruction->info.imm));
+                       instruction->info.imm = (instruction->info.imm << 17) >> 17; /* sign-extend */
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_end = instruction->access_start + 1;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLBI.bi\t$r%d,[$r%d],#%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 5: /* LHI.bi */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra), &(instruction->info.imm));
+                       instruction->info.imm = (instruction->info.imm << 17) >> 16; /* sign-extend */
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_end = instruction->access_start + 2;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLHI.bi\t$r%d,[$r%d],#%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 6: /* LWI.bi */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra), &(instruction->info.imm));
+                       instruction->info.imm = (instruction->info.imm << 17) >> 15; /* sign-extend */
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_end = instruction->access_start + 4;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLWI.bi\t$r%d,[$r%d],#%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               default:
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION",
+                                       address,
+                                       opcode);
+                       return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_parse_group_1_insn(struct nds32 *nds32, uint32_t opcode,
+               uint32_t address, struct nds32_instruction *instruction)
+{
+       uint8_t opc_6;
+
+       opc_6 = instruction->info.opc_6;
+
+       switch (opc_6 & 0x7) {
+               case 0: /* SBI */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra), &(instruction->info.imm));
+                       instruction->info.imm = (instruction->info.imm << 17) >> 17; /* sign-extend */
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_start += instruction->info.imm;
+                       instruction->access_end = instruction->access_start + 1;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSBI\t$r%d,[$r%d+#%d]",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 1: /* SHI */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra), &(instruction->info.imm));
+                       instruction->info.imm = (instruction->info.imm << 17) >> 16; /* sign-extend */
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_start += instruction->info.imm;
+                       instruction->access_end = instruction->access_start + 2;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSHI\t$r%d,[$r%d+#%d]",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 2: /* SWI */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra), &(instruction->info.imm));
+                       instruction->info.imm = (instruction->info.imm << 17) >> 15; /* sign-extend */
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_start += instruction->info.imm;
+                       instruction->access_end = instruction->access_start + 4;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSWI\t$r%d,[$r%d+#%d]",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 4: /* SBI.bi */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra), &(instruction->info.imm));
+                       instruction->info.imm = (instruction->info.imm << 17) >> 17; /* sign-extend */
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_end = instruction->access_start + 1;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSBI.bi\t$r%d,[$r%d],#%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 5: /* SHI.bi */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra), &(instruction->info.imm));
+                       instruction->info.imm = (instruction->info.imm << 17) >> 16; /* sign-extend */
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_end = instruction->access_start + 2;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSHI.bi\t$r%d,[$r%d],#%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 6: /* SWI.bi */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra), &(instruction->info.imm));
+                       instruction->info.imm = (instruction->info.imm << 17) >> 15; /* sign-extend */
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_end = instruction->access_start + 4;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSWI.bi\t$r%d,[$r%d],#%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               default:
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION",
+                                       address,
+                                       opcode);
+                       return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_parse_group_2_insn(struct nds32 *nds32, uint32_t opcode,
+               uint32_t address, struct nds32_instruction *instruction)
+{
+       uint8_t opc_6;
+
+       opc_6 = instruction->info.opc_6;
+
+       switch (opc_6 & 0x7) {
+               case 0: /* LBSI */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra), &(instruction->info.imm));
+                       instruction->info.imm = (instruction->info.imm << 17) >> 17; /* sign-extend */
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_start += instruction->info.imm;
+                       instruction->access_end = instruction->access_start + 1;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLBSI\t$r%d,[$r%d+#%d]",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 1: /* LHSI */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra), &(instruction->info.imm));
+                       instruction->info.imm = (instruction->info.imm << 17) >> 16; /* sign-extend */
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_start += instruction->info.imm;
+                       instruction->access_end = instruction->access_start + 2;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLHSI\t$r%d,[$r%d+#%d]",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 3: { /* DPREFI */
+                               uint8_t sub_type;
+                               nds32_parse_type_2(opcode, &sub_type, &(instruction->info.ra),
+                                               &(instruction->info.imm));
+                               instruction->info.sub_opc = sub_type & 0xF;
+                               instruction->type = NDS32_INSN_MISC;
+                               if (sub_type & 0x10) { /* DPREFI.d */
+                                       /* sign-extend */
+                                       instruction->info.imm = (instruction->info.imm << 17) >> 14;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tDPREFI.d\t%d,[$r%d+#%d]",
+                                                       address,
+                                                       opcode, instruction->info.sub_opc,
+                                                       instruction->info.ra, instruction->info.imm);
+                               } else { /* DPREFI.w */
+                                       /* sign-extend */
+                                       instruction->info.imm = (instruction->info.imm << 17) >> 15;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tDPREFI.w\t%d,[$r%d+#%d]",
+                                                       address,
+                                                       opcode, instruction->info.sub_opc,
+                                                       instruction->info.ra, instruction->info.imm);
+                               }
+                       }
+                       break;
+               case 4: /* LBSI.bi */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra), &(instruction->info.imm));
+                       instruction->info.imm = (instruction->info.imm << 17) >> 17; /* sign-extend */
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_end = instruction->access_start + 1;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLBSI.bi\t$r%d,[$r%d],#%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 5: /* LHSI.bi */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra), &(instruction->info.imm));
+                       instruction->info.imm = (instruction->info.imm << 17) >> 16; /* sign-extend */
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_end = instruction->access_start + 2;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLHSI.bi\t$r%d,[$r%d],#%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 6: /* LBGP */
+                       nds32_parse_type_1(opcode, &(instruction->info.rt), &(instruction->info.imm));
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       if ((instruction->info.imm >> 19) & 0x1) { /* LBSI.gp */
+                               instruction->info.imm = (instruction->info.imm << 13) >> 13;
+                               nds32_get_mapped_reg(nds32, R29, &(instruction->access_start));
+                               instruction->access_start += instruction->info.imm;
+                               instruction->access_end = instruction->access_start + 1;
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLBSI.gp\t$r%d,[#%d]",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.imm);
+                       } else { /* LBI.gp */
+                               instruction->info.imm = (instruction->info.imm << 13) >> 13;
+                               nds32_get_mapped_reg(nds32, R29, &(instruction->access_start));
+                               instruction->access_start += instruction->info.imm;
+                               instruction->access_end = instruction->access_start + 1;
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLBI.gp\t$r%d,[#%d]",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.imm);
+                       }
+                       break;
+               default:
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION",
+                                       address,
+                                       opcode);
+                       return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_parse_mem(struct nds32 *nds32, uint32_t opcode, uint32_t address,
+               struct nds32_instruction *instruction)
+{
+       uint32_t sub_opcode = opcode & 0x3F;
+       uint32_t val_ra, val_rb;
+       switch (sub_opcode >> 3) {
+               case 0:
+                       switch (sub_opcode & 0x7) {
+                               case 0: /* LB */
+                                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                       &(instruction->info.ra), \
+                                                       &(instruction->info.rb), &(instruction->info.imm));
+                                       instruction->type = NDS32_INSN_LOAD_STORE;
+                                       nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra);
+                                       nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb);
+                                       instruction->access_start = val_ra +
+                                               (val_rb << ((instruction->info.imm >> 8) & 0x3));
+                                       instruction->access_end = instruction->access_start + 1;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLB\t$r%d,[$r%d+($r%d<<%d)]",
+                                                       address,
+                                                       opcode, instruction->info.rt, instruction->info.ra,
+                                                       instruction->info.rb,
+                                                       (instruction->info.imm >> 8) & 0x3);
+                                       break;
+                               case 1: /* LH */
+                                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                       &(instruction->info.ra),
+                                                       &(instruction->info.rb), &(instruction->info.imm));
+                                       instruction->type = NDS32_INSN_LOAD_STORE;
+                                       nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra);
+                                       nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb);
+                                       instruction->access_start = val_ra +
+                                               (val_rb << ((instruction->info.imm >> 8) & 0x3));
+                                       instruction->access_end = instruction->access_start + 2;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLH\t$r%d,[$r%d+($r%d<<%d)]",
+                                                       address,
+                                                       opcode, instruction->info.rt, instruction->info.ra,
+                                                       instruction->info.rb,
+                                                       (instruction->info.imm >> 8) & 0x3);
+                                       break;
+                               case 2: /* LW */
+                                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                       &(instruction->info.ra),
+                                                       &(instruction->info.rb), &(instruction->info.imm));
+                                       instruction->type = NDS32_INSN_LOAD_STORE;
+                                       nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra);
+                                       nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb);
+                                       instruction->access_start = val_ra +
+                                               (val_rb << ((instruction->info.imm >> 8) & 0x3));
+                                       instruction->access_end = instruction->access_start + 4;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLW\t$r%d,[$r%d+($r%d<<%d)]",
+                                                       address,
+                                                       opcode, instruction->info.rt, instruction->info.ra,
+                                                       instruction->info.rb,
+                                                       (instruction->info.imm >> 8) & 0x3);
+                                       break;
+                               case 4: /* LB.bi */
+                                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                       &(instruction->info.ra),
+                                                       &(instruction->info.rb), &(instruction->info.imm));
+                                       instruction->type = NDS32_INSN_LOAD_STORE;
+                                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                                       &(instruction->access_start));
+                                       instruction->access_end = instruction->access_start + 1;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLB.bi\t$r%d,[$r%d],($r%d<<%d)",
+                                                       address,
+                                                       opcode, instruction->info.rt,
+                                                       instruction->info.ra, instruction->info.rb,
+                                                       (instruction->info.imm >> 8) & 0x3);
+                                       break;
+                               case 5: /* LH.bi */
+                                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                       &(instruction->info.ra),
+                                                       &(instruction->info.rb), &(instruction->info.imm));
+                                       instruction->type = NDS32_INSN_LOAD_STORE;
+                                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                                       &(instruction->access_start));
+                                       instruction->access_end = instruction->access_start + 2;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLH.bi\t$r%d,[$r%d],($r%d<<%d)",
+                                                       address,
+                                                       opcode, instruction->info.rt, instruction->info.ra,
+                                                       instruction->info.rb,
+                                                       (instruction->info.imm >> 8) & 0x3);
+                                       break;
+                               case 6: /* LW.bi */
+                                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                       &(instruction->info.ra),
+                                                       &(instruction->info.rb), &(instruction->info.imm));
+                                       instruction->type = NDS32_INSN_LOAD_STORE;
+                                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                                       &(instruction->access_start));
+                                       instruction->access_end = instruction->access_start + 4;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLW.bi\t$r%d,[$r%d],($r%d<<%d)",
+                                                       address,
+                                                       opcode, instruction->info.rt, instruction->info.ra,
+                                                       instruction->info.rb,
+                                                       (instruction->info.imm >> 8) & 0x3);
+                                       break;
+                       }
+                       break;
+               case 1:
+                       switch (sub_opcode & 0x7) {
+                               case 0: /* SB */
+                                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                       &(instruction->info.ra),
+                                                       &(instruction->info.rb), &(instruction->info.imm));
+                                       instruction->type = NDS32_INSN_LOAD_STORE;
+                                       nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra);
+                                       nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb);
+                                       instruction->access_start = val_ra +
+                                               (val_rb << ((instruction->info.imm >> 8) & 0x3));
+                                       instruction->access_end = instruction->access_start + 1;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSB\t$r%d,[$r%d+($r%d<<%d)]",
+                                                       address,
+                                                       opcode, instruction->info.rt,
+                                                       instruction->info.ra, instruction->info.rb,
+                                                       (instruction->info.imm >> 8) & 0x3);
+                                       break;
+                               case 1: /* SH */
+                                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                       &(instruction->info.ra),
+                                                       &(instruction->info.rb), &(instruction->info.imm));
+                                       instruction->type = NDS32_INSN_LOAD_STORE;
+                                       nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra);
+                                       nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb);
+                                       instruction->access_start = val_ra +
+                                               (val_rb << ((instruction->info.imm >> 8) & 0x3));
+                                       instruction->access_end = instruction->access_start + 2;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSH\t$r%d,[$r%d+($r%d<<%d)]",
+                                                       address,
+                                                       opcode, instruction->info.rt, instruction->info.ra,
+                                                       instruction->info.rb,
+                                                       (instruction->info.imm >> 8) & 0x3);
+                                       break;
+                               case 2: /* SW */
+                                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                       &(instruction->info.ra),
+                                                       &(instruction->info.rb), &(instruction->info.imm));
+                                       instruction->type = NDS32_INSN_LOAD_STORE;
+                                       nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra);
+                                       nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb);
+                                       instruction->access_start = val_ra +
+                                               (val_rb << ((instruction->info.imm >> 8) & 0x3));
+                                       instruction->access_end = instruction->access_start + 4;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSW\t$r%d,[$r%d+($r%d<<%d)]",
+                                                       address,
+                                                       opcode, instruction->info.rt,
+                                                       instruction->info.ra, instruction->info.rb,
+                                                       (instruction->info.imm >> 8) & 0x3);
+                                       break;
+                               case 4: /* SB.bi */
+                                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                       &(instruction->info.ra),
+                                                       &(instruction->info.rb), &(instruction->info.imm));
+                                       instruction->type = NDS32_INSN_LOAD_STORE;
+                                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                                       &(instruction->access_start));
+                                       instruction->access_end = instruction->access_start + 1;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSB.bi\t$r%d,[$r%d],($r%d<<%d)",
+                                                       address,
+                                                       opcode, instruction->info.rt, instruction->info.ra,
+                                                       instruction->info.rb,
+                                                       (instruction->info.imm >> 8) & 0x3);
+                                       break;
+                               case 5: /* SH.bi */
+                                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                       &(instruction->info.ra),
+                                                       &(instruction->info.rb), &(instruction->info.imm));
+                                       instruction->type = NDS32_INSN_LOAD_STORE;
+                                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                                       &(instruction->access_start));
+                                       instruction->access_end = instruction->access_start + 2;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSH.bi\t$r%d,[$r%d],($r%d<<%d)",
+                                                       address,
+                                                       opcode, instruction->info.rt, instruction->info.ra,
+                                                       instruction->info.rb,
+                                                       (instruction->info.imm >> 8) & 0x3);
+                                       break;
+                               case 6: /* SW.bi */
+                                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                       &(instruction->info.ra),
+                                                       &(instruction->info.rb), &(instruction->info.imm));
+                                       instruction->type = NDS32_INSN_LOAD_STORE;
+                                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                                       &(instruction->access_start));
+                                       instruction->access_end = instruction->access_start + 4;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSW.bi\t$r%d,[$r%d],($r%d<<%d)",
+                                                       address,
+                                                       opcode, instruction->info.rt, instruction->info.ra,
+                                                       instruction->info.rb,
+                                                       (instruction->info.imm >> 8) & 0x3);
+                                       break;
+                       }
+                       break;
+               case 2:
+                       switch (sub_opcode & 0x7) {
+                               case 0: /* LBS */
+                                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                       &(instruction->info.ra),
+                                                       &(instruction->info.rb), &(instruction->info.imm));
+                                       instruction->type = NDS32_INSN_LOAD_STORE;
+                                       nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra);
+                                       nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb);
+                                       instruction->access_start = val_ra +
+                                               (val_rb << ((instruction->info.imm >> 8) & 0x3));
+                                       instruction->access_end = instruction->access_start + 1;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLBS\t$r%d,[$r%d+($r%d<<%d)]",
+                                                       address,
+                                                       opcode, instruction->info.rt,
+                                                       instruction->info.ra, instruction->info.rb,
+                                                       (instruction->info.imm >> 8) & 0x3);
+                                       break;
+                               case 1: /* LHS */
+                                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                       &(instruction->info.ra),
+                                                       &(instruction->info.rb), &(instruction->info.imm));
+                                       instruction->type = NDS32_INSN_LOAD_STORE;
+                                       nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra);
+                                       nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb);
+                                       instruction->access_start = val_ra +
+                                               (val_rb << ((instruction->info.imm >> 8) & 0x3));
+                                       instruction->access_end = instruction->access_start + 2;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLHS\t$r%d,[$r%d+($r%d<<%d)]",
+                                                       address,
+                                                       opcode, instruction->info.rt, instruction->info.ra,
+                                                       instruction->info.rb,
+                                                       (instruction->info.imm >> 8) & 0x3);
+                                       break;
+                               case 3: /* DPREF */
+                                       nds32_parse_type_3(opcode, &(instruction->info.sub_opc),
+                                                       &(instruction->info.ra),
+                                                       &(instruction->info.rb), &(instruction->info.imm));
+                                       instruction->type = NDS32_INSN_MISC;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tDPREF\t#%d,[$r%d+($r%d<<#%d)]",
+                                                       address,
+                                                       opcode, instruction->info.sub_opc,
+                                                       instruction->info.ra, instruction->info.rb,
+                                                       (instruction->info.imm >> 8) & 0x3);
+                                       break;
+                               case 4: /* LBS.bi */
+                                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                       &(instruction->info.ra),
+                                                       &(instruction->info.rb), &(instruction->info.imm));
+                                       instruction->type = NDS32_INSN_LOAD_STORE;
+                                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                                       &(instruction->access_start));
+                                       instruction->access_end = instruction->access_start + 1;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLBS.bi\t$r%d,[$r%d],($r%d<<%d)",
+                                                       address,
+                                                       opcode, instruction->info.rt, instruction->info.ra,
+                                                       instruction->info.rb,
+                                                       (instruction->info.imm >> 8) & 0x3);
+                                       break;
+                               case 5: /* LHS.bi */
+                                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                       &(instruction->info.ra),
+                                                       &(instruction->info.rb), &(instruction->info.imm));
+                                       instruction->type = NDS32_INSN_LOAD_STORE;
+                                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                                       &(instruction->access_start));
+                                       instruction->access_end = instruction->access_start + 2;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLHS.bi\t$r%d,[$r%d],($r%d<<%d)",
+                                                       address,
+                                                       opcode, instruction->info.rt, instruction->info.ra,
+                                                       instruction->info.rb,
+                                                       (instruction->info.imm >> 8) & 0x3);
+                                       break;
+                       }
+                       break;
+               case 3:
+                       switch (sub_opcode & 0x7) {
+                               case 0: /* LLW */
+                                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                       &(instruction->info.ra),
+                                                       &(instruction->info.rb), &(instruction->info.imm));
+                                       instruction->type = NDS32_INSN_LOAD_STORE;
+                                       nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra);
+                                       nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb);
+                                       instruction->access_start = val_ra +
+                                               (val_rb << ((instruction->info.imm >> 8) & 0x3));
+                                       instruction->access_end = instruction->access_start + 4;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLLW\t$r%d,[$r%d+($r%d<<%d)]",
+                                                       address,
+                                                       opcode, instruction->info.rt, instruction->info.ra,
+                                                       instruction->info.rb,
+                                                       (instruction->info.imm >> 8) & 0x3);
+                                       break;
+                               case 1: /* SCW */
+                                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                       &(instruction->info.ra),
+                                                       &(instruction->info.rb), &(instruction->info.imm));
+                                       instruction->type = NDS32_INSN_LOAD_STORE;
+                                       nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra);
+                                       nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb);
+                                       instruction->access_start = val_ra +
+                                               (val_rb << ((instruction->info.imm >> 8) & 0x3));
+                                       instruction->access_end = instruction->access_start + 4;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSCW\t$r%d,[$r%d+($r%d<<%d)]",
+                                                       address,
+                                                       opcode, instruction->info.rt, instruction->info.ra,
+                                                       instruction->info.rb,
+                                                       (instruction->info.imm >> 8) & 0x3);
+                                       break;
+                       }
+                       break;
+               case 4:
+                       switch (sub_opcode & 0x7) {
+                               case 0: /* LBUP */
+                                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                       &(instruction->info.ra),
+                                                       &(instruction->info.rb), &(instruction->info.imm));
+                                       instruction->type = NDS32_INSN_LOAD_STORE;
+                                       nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra);
+                                       nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb);
+                                       instruction->access_start = val_ra +
+                                               (val_rb << ((instruction->info.imm >> 8) & 0x3));
+                                       instruction->access_end = instruction->access_start + 1;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLBUP\t$r%d,[$r%d+($r%d<<%d)]",
+                                                       address,
+                                                       opcode, instruction->info.rt, instruction->info.ra,
+                                                       instruction->info.rb,
+                                                       (instruction->info.imm >> 8) & 0x3);
+                                       break;
+                               case 2: /* LWUP */
+                                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                       &(instruction->info.ra),
+                                                       &(instruction->info.rb), &(instruction->info.imm));
+                                       instruction->type = NDS32_INSN_LOAD_STORE;
+                                       nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra);
+                                       nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb);
+                                       instruction->access_start = val_ra +
+                                               (val_rb << ((instruction->info.imm >> 8) & 0x3));
+                                       instruction->access_end = instruction->access_start + 4;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLWUP\t$r%d,[$r%d+($r%d<<%d)]",
+                                                       address,
+                                                       opcode, instruction->info.rt, instruction->info.ra,
+                                                       instruction->info.rb,
+                                                       (instruction->info.imm >> 8) & 0x3);
+                                       break;
+                       }
+                       break;
+               case 5:
+                       switch (sub_opcode & 0x7) {
+                               case 0: /* SBUP */
+                                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                       &(instruction->info.ra),
+                                                       &(instruction->info.rb), &(instruction->info.imm));
+                                       instruction->type = NDS32_INSN_LOAD_STORE;
+                                       nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra);
+                                       nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb);
+                                       instruction->access_start = val_ra +
+                                               (val_rb << ((instruction->info.imm >> 8) & 0x3));
+                                       instruction->access_end = instruction->access_start + 1;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSBUP\t$r%d,[$r%d+($r%d<<%d)]",
+                                                       address,
+                                                       opcode, instruction->info.rt, instruction->info.ra,
+                                                       instruction->info.rb,
+                                                       (instruction->info.imm >> 8) & 0x3);
+                                       break;
+                               case 2: /* SWUP */
+                                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                       &(instruction->info.ra),
+                                                       &(instruction->info.rb), &(instruction->info.imm));
+                                       instruction->type = NDS32_INSN_LOAD_STORE;
+                                       nds32_get_mapped_reg(nds32, instruction->info.ra, &val_ra);
+                                       nds32_get_mapped_reg(nds32, instruction->info.rb, &val_rb);
+                                       instruction->access_start = val_ra +
+                                               (val_rb << ((instruction->info.imm >> 8) & 0x3));
+                                       instruction->access_end = instruction->access_start + 4;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSWUP\t$r%d,[$r%d+($r%d<<%d)]",
+                                                       address,
+                                                       opcode, instruction->info.rt, instruction->info.ra,
+                                                       instruction->info.rb,
+                                                       (instruction->info.imm >> 8) & 0x3);
+                                       break;
+                       }
+                       break;
+               default:
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION",
+                                       address,
+                                       opcode);
+                       return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_calculate_lsmw_access_range(struct nds32 *nds32,
+               struct nds32_instruction *instruction)
+{
+       uint8_t ba;
+       uint8_t id;
+       uint8_t enable4;
+
+       enable4 = (instruction->info.imm >> 6) & 0xF;
+       ba = (instruction->info.imm >> 4) & 0x1;
+       id = (instruction->info.imm >> 3) & 0x1;
+
+       if (ba) {
+               nds32_get_mapped_reg(nds32, instruction->info.ra, &(instruction->access_start));
+               if (id) { /* decrease */
+                       /* access_end is the (last_element+1), so no need to minus 4 */
+                       /* instruction->access_end -= 4; */
+                       instruction->access_end = instruction->access_start;
+               } else { /* increase */
+                       instruction->access_start += 4;
+               }
+       } else {
+               nds32_get_mapped_reg(nds32, instruction->info.ra, &(instruction->access_start));
+               instruction->access_end = instruction->access_start - 4;
+       }
+
+       if (id) { /* decrease */
+               instruction->access_start = instruction->access_end -
+                       4 * (instruction->info.rd - instruction->info.rb + 1);
+               instruction->access_start -= (4 * enable4_bits[enable4]);
+       } else { /* increase */
+               instruction->access_end = instruction->access_start +
+                       4 * (instruction->info.rd - instruction->info.rb + 1);
+               instruction->access_end += (4 * enable4_bits[enable4]);
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_parse_lsmw(struct nds32 *nds32, uint32_t opcode, uint32_t address,
+               struct nds32_instruction *instruction)
+{
+       if (opcode & 0x20) { /* SMW, SMWA, SMWZB */
+               switch (opcode & 0x3) {
+                       /* TODO */
+                       case 0: /* SMW */
+                               /* use rd as re */
+                               nds32_parse_type_3(opcode, &(instruction->info.rb),
+                                               &(instruction->info.ra),
+                                               &(instruction->info.rd), &(instruction->info.imm));
+                               instruction->type = NDS32_INSN_LOAD_STORE;
+                               nds32_calculate_lsmw_access_range(nds32, instruction);
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMW\t$r%d,[$r%d],$r%d,%d",
+                                               address,
+                                               opcode, instruction->info.rb, instruction->info.ra,
+                                               instruction->info.rd,
+                                               (instruction->info.imm >> 6) & 0xF);
+                               break;
+                       case 1: /* SMWA */
+                               nds32_parse_type_3(opcode, &(instruction->info.rb),
+                                               &(instruction->info.ra),
+                                               &(instruction->info.rd), &(instruction->info.imm));
+                               instruction->type = NDS32_INSN_LOAD_STORE;
+                               nds32_calculate_lsmw_access_range(nds32, instruction);
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMWA\t$r%d,[$r%d],$r%d,%d",
+                                               address,
+                                               opcode, instruction->info.rb, instruction->info.ra,
+                                               instruction->info.rd,
+                                               (instruction->info.imm >> 6) & 0xF);
+                               break;
+                       case 2: /* SMWZB */
+                               nds32_parse_type_3(opcode, &(instruction->info.rb),
+                                               &(instruction->info.ra),
+                                               &(instruction->info.rd), &(instruction->info.imm));
+                               instruction->type = NDS32_INSN_LOAD_STORE;
+                               /* TODO: calculate access_start/access_end */
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMWZB\t$r%d,[$r%d],$r%d,%d",
+                                               address,
+                                               opcode, instruction->info.rb, instruction->info.ra,
+                                               instruction->info.rd,
+                                               (instruction->info.imm >> 6) & 0xF);
+                               break;
+                       default:
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION",
+                                               address,
+                                               opcode);
+                               return ERROR_FAIL;
+               }
+       } else { /* LMW, LMWA, LMWZB */
+               switch (opcode & 0x3) {
+                       case 0: /* LMW */
+                               nds32_parse_type_3(opcode, &(instruction->info.rb),
+                                               &(instruction->info.ra),
+                                               &(instruction->info.rd), &(instruction->info.imm));
+                               instruction->type = NDS32_INSN_LOAD_STORE;
+                               nds32_calculate_lsmw_access_range(nds32, instruction);
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLMW\t$r%d,[$r%d],$r%d,%d",
+                                               address,
+                                               opcode, instruction->info.rb, instruction->info.ra,
+                                               instruction->info.rd,
+                                               (instruction->info.imm >> 6) & 0xF);
+                               break;
+                       case 1: /* LMWA */
+                               nds32_parse_type_3(opcode, &(instruction->info.rb),
+                                               &(instruction->info.ra),
+                                               &(instruction->info.rd), &(instruction->info.imm));
+                               instruction->type = NDS32_INSN_LOAD_STORE;
+                               nds32_calculate_lsmw_access_range(nds32, instruction);
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLMWA\t$r%d,[$r%d],$r%d,%d",
+                                               address,
+                                               opcode, instruction->info.rb, instruction->info.ra,
+                                               instruction->info.rd,
+                                               (instruction->info.imm >> 6) & 0xF);
+                               break;
+                       case 2: /* LMWZB */
+                               nds32_parse_type_3(opcode, &(instruction->info.rb),
+                                               &(instruction->info.ra),
+                                               &(instruction->info.rd), &(instruction->info.imm));
+                               instruction->type = NDS32_INSN_LOAD_STORE;
+                               /* TODO: calculate access_start/access_end */
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLMWZB\t$r%d,[$r%d],$r%d,%d",
+                                               address,
+                                               opcode, instruction->info.rb, instruction->info.ra,
+                                               instruction->info.rd,
+                                               (instruction->info.imm >> 6) & 0xF);
+                               break;
+                       default:
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION",
+                                               address,
+                                               opcode);
+                               return ERROR_FAIL;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_parse_hwgp(struct nds32 *nds32, uint32_t opcode, uint32_t address,
+               struct nds32_instruction *instruction)
+{
+       switch ((opcode >> 18) & 0x3) {
+               case 0: /* LHI.gp */
+                       nds32_parse_type_1(opcode, &(instruction->info.rt), &(instruction->info.imm));
+                       instruction->info.imm = (instruction->info.imm << 14) >> 13; /* sign-extend */
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, R29, &(instruction->access_start));
+                       instruction->access_start += instruction->info.imm;
+                       instruction->access_end = instruction->access_start + 2;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLHI.gp\t$r%d,[#%d]",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.imm);
+                       break;
+               case 1: /* LHSI.gp */
+                       nds32_parse_type_1(opcode, &(instruction->info.rt), &(instruction->info.imm));
+                       instruction->info.imm = (instruction->info.imm << 14) >> 13; /* sign-extend */
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, R29, &(instruction->access_start));
+                       instruction->access_start += instruction->info.imm;
+                       instruction->access_end = instruction->access_start + 2;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLHSI.gp\t$r%d,[#%d]",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.imm);
+                       break;
+               case 2: /* SHI.gp */
+                       nds32_parse_type_1(opcode, &(instruction->info.rt), &(instruction->info.imm));
+                       instruction->info.imm = (instruction->info.imm << 14) >> 13; /* sign-extend */
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, R29, &(instruction->access_start));
+                       instruction->access_start += instruction->info.imm;
+                       instruction->access_end = instruction->access_start + 2;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSHI.gp\t$r%d,[#%d]",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.imm);
+                       break;
+               case 3:
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       if ((opcode >> 17) & 0x1) { /* SWI.gp */
+                               nds32_parse_type_1(opcode, &(instruction->info.rt),
+                                               &(instruction->info.imm));
+                               /* sign-extend */
+                               instruction->info.imm = (instruction->info.imm << 15) >> 13;
+                               nds32_get_mapped_reg(nds32, R29, &(instruction->access_start));
+                               instruction->access_start += instruction->info.imm;
+                               instruction->access_end = instruction->access_start + 4;
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSWI.gp\t$r%d,[#%d]",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.imm);
+                       } else { /* LWI.gp */
+                               nds32_parse_type_1(opcode, &(instruction->info.rt),
+                                               &(instruction->info.imm));
+                               /* sign-extend */
+                               instruction->info.imm = (instruction->info.imm << 15) >> 13;
+                               nds32_get_mapped_reg(nds32, R29, &(instruction->access_start));
+                               instruction->access_start += instruction->info.imm;
+                               instruction->access_end = instruction->access_start + 4;
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tLWI.gp\t$r%d,[#%d]",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.imm);
+                       }
+
+                       break;
+               default:
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION",
+                                       address,
+                                       opcode);
+                       return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_parse_sbgp(struct nds32 *nds32, uint32_t opcode, uint32_t address,
+               struct nds32_instruction *instruction)
+{
+       switch ((opcode >> 19) & 0x1) {
+               case 0: /* SBI.gp */
+                       nds32_parse_type_1(opcode, &(instruction->info.rt), &(instruction->info.imm));
+                       instruction->info.imm = (instruction->info.imm << 13) >> 13; /* sign-extend */
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, R29, &(instruction->access_start));
+                       instruction->access_start += instruction->info.imm;
+                       instruction->access_end = instruction->access_start + 1;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSBI.gp\t$r%d,[#%d]",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.imm);
+                       break;
+               case 1: /* ADDI.gp */
+                       nds32_parse_type_1(opcode, &(instruction->info.rt), &(instruction->info.imm));
+                       instruction->info.imm = (instruction->info.imm << 13) >> 13; /* sign-extend */
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tADDI.gp\t$r%d,#%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.imm);
+                       break;
+               default:
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION",
+                                       address,
+                                       opcode);
+                       return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_parse_group_3_insn(struct nds32 *nds32, uint32_t opcode, uint32_t address,
+               struct nds32_instruction *instruction)
+{
+       uint8_t opc_6;
+
+       opc_6 = instruction->info.opc_6;
+
+       switch (opc_6 & 0x7) {
+               case 4: /* MEM */
+                       nds32_parse_mem(nds32, opcode, address, instruction);
+                       break;
+               case 5: /* LSMW */
+                       nds32_parse_lsmw(nds32, opcode, address, instruction);
+                       break;
+               case 6: /* HWGP */
+                       nds32_parse_hwgp(nds32, opcode, address, instruction);
+                       break;
+               case 7: /* SBGP */
+                       nds32_parse_sbgp(nds32, opcode, address, instruction);
+                       break;
+               default:
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION",
+                                       address,
+                                       opcode);
+                       return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_parse_alu_1(uint32_t opcode, uint32_t address,
+               struct nds32_instruction *instruction)
+{
+       switch (opcode & 0x1F) {
+               case 0: /* ADD */
+                       nds32_parse_type_3(opcode, &(instruction->info.rt), &(instruction->info.ra),
+                                       &(instruction->info.rb), &(instruction->info.imm));
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       instruction->info.imm = (instruction->info.imm >> 5) & 0x1F;
+                       if (instruction->info.imm)
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tADD_SLLI\t$r%d,$r%d,$r%d,%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.rb,
+                                               instruction->info.imm);
+                       else
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tADD\t$r%d,$r%d,$r%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.rb);
+                       break;
+               case 1: /* SUB */
+                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra),
+                                       &(instruction->info.rb), &(instruction->info.imm));
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       instruction->info.imm = (instruction->info.imm >> 5) & 0x1F;
+                       if (instruction->info.imm)
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSUB_SLLI\t$r%d,$r%d,$r%d,%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.rb,
+                                               instruction->info.imm);
+                       else
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSUB\t$r%d,$r%d,$r%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.rb);
+                       break;
+               case 2: /* AND */
+                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra),
+                                       &(instruction->info.rb), &(instruction->info.imm));
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       instruction->info.imm = (instruction->info.imm >> 5) & 0x1F;
+                       if (instruction->info.imm)
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tAND_SLLI\t$r%d,$r%d,$r%d,%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.rb,
+                                               instruction->info.imm);
+                       else
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tAND\t$r%d,$r%d,$r%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.rb);
+                       break;
+               case 3: /* XOR */
+                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra),
+                                       &(instruction->info.rb), &(instruction->info.imm));
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       instruction->info.imm = (instruction->info.imm >> 5) & 0x1F;
+                       if (instruction->info.imm)
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tXOR_SLLI\t$r%d,$r%d,$r%d,%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.rb,
+                                               instruction->info.imm);
+                       else
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tXOR\t$r%d,$r%d,$r%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.rb);
+                       break;
+               case 4: /* OR */
+                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra),
+                                       &(instruction->info.rb), &(instruction->info.imm));
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       instruction->info.imm = (instruction->info.imm >> 5) & 0x1F;
+                       if (instruction->info.imm)
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tOR_SLLI\t$r%d,$r%d,$r%d,%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.rb,
+                                               instruction->info.imm);
+                       else
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tOR\t$r%d,$r%d,$r%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.rb);
+                       break;
+               case 5: /* NOR */
+                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra),
+                                       &(instruction->info.rb), &(instruction->info.imm));
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tNOR\t$r%d,$r%d,$r%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.rb);
+                       break;
+               case 6: /* SLT */
+                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra),
+                                       &(instruction->info.rb), &(instruction->info.imm));
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSLT\t$r%d,$r%d,$r%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.rb);
+                       break;
+               case 7: /* SLTS */
+                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra),
+                                       &(instruction->info.rb), &(instruction->info.imm));
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSLTS\t$r%d,$r%d,$r%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.rb);
+                       break;
+               case 8: { /* SLLI */
+                               uint8_t imm;
+                               int32_t sub_op;
+                               nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                               &(instruction->info.ra),
+                                               &imm, &sub_op);
+                               instruction->info.imm = imm;
+                               instruction->type = NDS32_INSN_DATA_PROC;
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSLLI\t$r%d,$r%d,#%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.imm);
+                       }
+                       break;
+               case 9: { /* SRLI */
+                               uint8_t imm;
+                               int32_t sub_op;
+                               nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                               &(instruction->info.ra),
+                                               &imm, &sub_op);
+                               instruction->info.imm = imm;
+                               instruction->type = NDS32_INSN_DATA_PROC;
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSRLI\t$r%d,$r%d,#%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.imm);
+                       }
+                       break;
+               case 10: { /* SRAI */
+                                uint8_t imm;
+                                int32_t sub_op;
+                                nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                &(instruction->info.ra),
+                                                &imm, &sub_op);
+                                instruction->info.imm = imm;
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSRAI\t$r%d,$r%d,#%d",
+                                                address,
+                                                opcode, instruction->info.rt, instruction->info.ra,
+                                                instruction->info.imm);
+                        }
+                        break;
+               case 11: { /* ROTRI */
+                                uint8_t imm;
+                                int32_t sub_op;
+                                nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                &(instruction->info.ra),
+                                                &imm, &sub_op);
+                                instruction->info.imm = imm;
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tROTRI\t$r%d,$r%d,#%d",
+                                                address,
+                                                opcode, instruction->info.rt, instruction->info.ra,
+                                                instruction->info.imm);
+                        }
+                        break;
+               case 12: { /* SLL */
+                                nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                &(instruction->info.ra),
+                                                &(instruction->info.rb), &(instruction->info.imm));
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSLL\t$r%d,$r%d,$r%d",
+                                                address,
+                                                opcode, instruction->info.rt, instruction->info.ra,
+                                                instruction->info.rb);
+                        }
+                        break;
+               case 13: { /* SRL */
+                                nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                &(instruction->info.ra),
+                                                &(instruction->info.rb), &(instruction->info.imm));
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSRL\t$r%d,$r%d,$r%d",
+                                                address,
+                                                opcode, instruction->info.rt, instruction->info.ra,
+                                                instruction->info.rb);
+                        }
+                        break;
+               case 14: { /* SRA */
+                                nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                &(instruction->info.ra),
+                                                &(instruction->info.rb), &(instruction->info.imm));
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSRA\t$r%d,$r%d,$r%d",
+                                                address,
+                                                opcode, instruction->info.rt, instruction->info.ra,
+                                                instruction->info.rb);
+                        }
+                        break;
+               case 15: { /* ROTR */
+                                nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                &(instruction->info.ra),
+                                                &(instruction->info.rb), &(instruction->info.imm));
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tROTR\t$r%d,$r%d,$r%d",
+                                                address,
+                                                opcode, instruction->info.rt, instruction->info.ra,
+                                                instruction->info.rb);
+                        }
+                        break;
+               case 16: { /* SEB */
+                                nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                                &(instruction->info.ra),
+                                                &(instruction->info.imm));
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSEB\t$r%d,$r%d",
+                                                address,
+                                                opcode, instruction->info.rt, instruction->info.ra);
+                        }
+                        break;
+               case 17: { /* SEH */
+                                nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                                &(instruction->info.ra),
+                                                &(instruction->info.imm));
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSEH\t$r%d,$r%d",
+                                                address,
+                                                opcode, instruction->info.rt, instruction->info.ra);
+                        }
+                        break;
+               case 18: /* BITC */
+                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra),
+                                       &(instruction->info.rb), &(instruction->info.imm));
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBITC\t$r%d,$r%d,$r%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.rb);
+                        break;
+               case 19: { /* ZEH */
+                                nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                                &(instruction->info.ra),
+                                                &(instruction->info.imm));
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tZEH\t$r%d,$r%d",
+                                                address,
+                                                opcode, instruction->info.rt, instruction->info.ra);
+                        }
+                        break;
+               case 20: { /* WSBH */
+                                nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                                &(instruction->info.ra),
+                                                &(instruction->info.imm));
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tWSBH\t$r%d,$r%d",
+                                                address,
+                                                opcode, instruction->info.rt, instruction->info.ra);
+                        }
+                        break;
+               case 21: /* OR_SRLI */
+                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra),
+                                       &(instruction->info.rb), &(instruction->info.imm));
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       instruction->info.imm = (instruction->info.imm >> 5) & 0x1F;
+                       if (instruction->info.imm)
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tOR_SRLI\t$r%d,$r%d,$r%d,%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.rb,
+                                               instruction->info.imm);
+                       else
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tOR\t$r%d,$r%d,$r%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.rb);
+                        break;
+               case 22: { /* DIVSR */
+                                nds32_parse_type_4(opcode, &(instruction->info.rt),
+                                                &(instruction->info.ra),
+                                                &(instruction->info.rb), &(instruction->info.rd),
+                                                &(instruction->info.sub_opc));
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tDIVSR\t$r%d,$r%d,$r%d,$r%d",
+                                                address,
+                                                opcode, instruction->info.rt, instruction->info.ra,
+                                                instruction->info.rb,
+                                                instruction->info.rd);
+                        }
+                        break;
+               case 23: { /* DIVR */
+                                nds32_parse_type_4(opcode, &(instruction->info.rt),
+                                                &(instruction->info.ra),
+                                                &(instruction->info.rb), &(instruction->info.rd),
+                                                &(instruction->info.sub_opc));
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tDIVR\t$r%d,$r%d,$r%d,$r%d",
+                                                address,
+                                                opcode, instruction->info.rt, instruction->info.ra,
+                                                instruction->info.rb,
+                                                instruction->info.rd);
+                        }
+                        break;
+               case 24: { /* SVA */
+                                nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                &(instruction->info.ra),
+                                                &(instruction->info.rb), &(instruction->info.imm));
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSVA\t$r%d,$r%d,$r%d",
+                                                address,
+                                                opcode, instruction->info.rt, instruction->info.ra,
+                                                instruction->info.rb);
+                        }
+                        break;
+               case 25: { /* SVS */
+                                nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                &(instruction->info.ra),
+                                                &(instruction->info.rb), &(instruction->info.imm));
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSVS\t$r%d,$r%d,$r%d",
+                                                address,
+                                                opcode, instruction->info.rt, instruction->info.ra,
+                                                instruction->info.rb);
+                        }
+                        break;
+               case 26: { /* CMOVZ */
+                                nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                &(instruction->info.ra),
+                                                &(instruction->info.rb), &(instruction->info.imm));
+                                instruction->type = NDS32_INSN_MISC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tCMOVZ\t$r%d,$r%d,$r%d",
+                                                address,
+                                                opcode, instruction->info.rt, instruction->info.ra,
+                                                instruction->info.rb);
+                        }
+                        break;
+               case 27: { /* CMOVN */
+                                nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                &(instruction->info.ra),
+                                                &(instruction->info.rb), &(instruction->info.imm));
+                                instruction->type = NDS32_INSN_MISC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tCMOVN\t$r%d,$r%d,$r%d",
+                                                address,
+                                                opcode, instruction->info.rt, instruction->info.ra,
+                                                instruction->info.rb);
+                        }
+                        break;
+               case 28: /* ADD_SRLI */
+                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra),
+                                       &(instruction->info.rb), &(instruction->info.imm));
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       instruction->info.imm = (instruction->info.imm >> 5) & 0x1F;
+                       if (instruction->info.imm)
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tADD_SRLI\t$r%d,$r%d,$r%d,%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.rb,
+                                               instruction->info.imm);
+                       else
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tADD\t$r%d,$r%d,$r%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.rb);
+                        break;
+               case 29: /* SUB_SRLI */
+                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra),
+                                       &(instruction->info.rb), &(instruction->info.imm));
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       instruction->info.imm = (instruction->info.imm >> 5) & 0x1F;
+                       if (instruction->info.imm)
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSUB_SRLI\t$r%d,$r%d,$r%d,%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.rb,
+                                               instruction->info.imm);
+                       else
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSUB\t$r%d,$r%d,$r%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.rb);
+                        break;
+               case 30: /* AND_SRLI */
+                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra),
+                                       &(instruction->info.rb), &(instruction->info.imm));
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       instruction->info.imm = (instruction->info.imm >> 5) & 0x1F;
+                       if (instruction->info.imm)
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tAND_SRLI\t$r%d,$r%d,$r%d,%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.rb,
+                                               instruction->info.imm);
+                       else
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tAND\t$r%d,$r%d,$r%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.rb);
+                        break;
+               case 31: /* XOR_SRLI */
+                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra),
+                                       &(instruction->info.rb), &(instruction->info.imm));
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       instruction->info.imm = (instruction->info.imm >> 5) & 0x1F;
+                       if (instruction->info.imm)
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tXOR_SRLI\t$r%d,$r%d,$r%d,%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.rb,
+                                               instruction->info.imm);
+                       else
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tXOR\t$r%d,$r%d,$r%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.rb);
+                        break;
+               default:
+                        snprintf(instruction->text,
+                                        128,
+                                        "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION",
+                                        address,
+                                        opcode);
+                        return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_parse_alu_2(uint32_t opcode, uint32_t address,
+               struct nds32_instruction *instruction)
+{
+       switch (opcode & 0x3F) {
+               case 0: /* MAX */
+                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra),
+                                       &(instruction->info.rb), &(instruction->info.imm));
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMAX\t$r%d,$r%d,$r%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.rb);
+                       break;
+               case 1: /* MIN */
+                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra),
+                                       &(instruction->info.rb), &(instruction->info.imm));
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMIN\t$r%d,$r%d,$r%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.rb);
+                       break;
+               case 2: /* AVE */
+                       nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra),
+                                       &(instruction->info.rb), &(instruction->info.imm));
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tAVE\t$r%d,$r%d,$r%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.rb);
+                       break;
+               case 3: /* ABS */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra),
+                                       &(instruction->info.imm));
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tAVE\t$r%d,$r%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra);
+                       break;
+               case 4: { /* CLIPS */
+                               uint8_t imm;
+                               nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                               &(instruction->info.ra),
+                                               &imm, &(instruction->info.imm));
+                               instruction->info.imm = imm;
+                               instruction->type = NDS32_INSN_DATA_PROC;
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tCLIPS\t$r%d,$r%d,#%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.imm);
+                       }
+                       break;
+               case 5: { /* CLIP */
+                               uint8_t imm;
+                               nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                               &(instruction->info.ra),
+                                               &imm, &(instruction->info.imm));
+                               instruction->info.imm = imm;
+                               instruction->type = NDS32_INSN_DATA_PROC;
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tCLIP\t$r%d,$r%d,#%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.imm);
+                       }
+                       break;
+               case 6: /* CLO */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra),
+                                       &(instruction->info.imm));
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tCLO\t$r%d,$r%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra);
+                       break;
+               case 7: /* CLZ */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra),
+                                       &(instruction->info.imm));
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tCLZ\t$r%d,$r%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra);
+                       break;
+               case 8: { /* BSET */
+                               uint8_t imm;
+                               nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                               &(instruction->info.ra),
+                                               &imm, &(instruction->info.imm));
+                               instruction->info.imm = imm;
+                               instruction->type = NDS32_INSN_DATA_PROC;
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBSET\t$r%d,$r%d,#%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.imm);
+                       }
+                       break;
+               case 9: { /* BCLR */
+                               uint8_t imm;
+                               nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                               &(instruction->info.ra),
+                                               &imm, &(instruction->info.imm));
+                               instruction->info.imm = imm;
+                               instruction->type = NDS32_INSN_DATA_PROC;
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBCLR\t$r%d,$r%d,#%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.imm);
+                       }
+                       break;
+               case 10: { /* BTGL */
+                                uint8_t imm;
+                                nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                &(instruction->info.ra),
+                                                &imm, &(instruction->info.imm));
+                                instruction->info.imm = imm;
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBTGL\t$r%d,$r%d,#%d",
+                                                address,
+                                                opcode, instruction->info.rt, instruction->info.ra,
+                                                instruction->info.imm);
+                        }
+                        break;
+               case 11: { /* BTST */
+                                uint8_t imm;
+                                nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                                &(instruction->info.ra),
+                                                &imm, &(instruction->info.imm));
+                                instruction->info.imm = imm;
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBTST\t$r%d,$r%d,#%d",
+                                                address,
+                                                opcode, instruction->info.rt, instruction->info.ra,
+                                                instruction->info.imm);
+                        }
+                        break;
+               case 12: /* BSE */
+                        nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                        &(instruction->info.ra),
+                                        &(instruction->info.rb), &(instruction->info.imm));
+                        instruction->type = NDS32_INSN_DATA_PROC;
+                        snprintf(instruction->text,
+                                        128,
+                                        "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBSE\t$r%d,$r%d,$r%d",
+                                        address,
+                                        opcode, instruction->info.rt, instruction->info.ra,
+                                        instruction->info.rb);
+                        break;
+               case 13: /* BSP */
+                        nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                        &(instruction->info.ra),
+                                        &(instruction->info.rb), &(instruction->info.imm));
+                        instruction->type = NDS32_INSN_DATA_PROC;
+                        snprintf(instruction->text,
+                                        128,
+                                        "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBSP\t$r%d,$r%d,$r%d",
+                                        address,
+                                        opcode, instruction->info.rt, instruction->info.ra,
+                                        instruction->info.rb);
+                        break;
+               case 14: /* FFB */
+                        nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                        &(instruction->info.ra),
+                                        &(instruction->info.rb), &(instruction->info.imm));
+                        instruction->type = NDS32_INSN_DATA_PROC;
+                        snprintf(instruction->text,
+                                        128,
+                                        "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tFFB\t$r%d,$r%d,$r%d",
+                                        address,
+                                        opcode, instruction->info.rt, instruction->info.ra,
+                                        instruction->info.rb);
+                        break;
+               case 15: /* FFMISM */
+                        nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                        &(instruction->info.ra),
+                                        &(instruction->info.rb), &(instruction->info.imm));
+                        instruction->type = NDS32_INSN_DATA_PROC;
+                        snprintf(instruction->text,
+                                        128,
+                                        "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tFFMISM\t$r%d,$r%d,$r%d",
+                                        address,
+                                        opcode, instruction->info.rt, instruction->info.ra,
+                                        instruction->info.rb);
+                        break;
+               case 23: /* FFZMISM */
+                        nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                        &(instruction->info.ra),
+                                        &(instruction->info.rb), &(instruction->info.imm));
+                        instruction->type = NDS32_INSN_DATA_PROC;
+                        snprintf(instruction->text,
+                                        128,
+                                        "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tFFZMISM\t$r%d,$r%d,$r%d",
+                                        address,
+                                        opcode, instruction->info.rt, instruction->info.ra,
+                                        instruction->info.rb);
+                        break;
+               case 32: /* MFUSR */
+                        nds32_parse_type_1(opcode, &(instruction->info.rt),
+                                        &(instruction->info.imm));
+                        instruction->type = NDS32_INSN_RESOURCE_ACCESS;
+                        snprintf(instruction->text,
+                                        128,
+                                        "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMFUSR\t$r%d,#%d",
+                                        address,
+                                        opcode, instruction->info.rt,
+                                        (instruction->info.imm >> 10) & 0x3FF);
+                        break;
+               case 33: /* MTUSR */
+                        nds32_parse_type_1(opcode, &(instruction->info.rt),
+                                        &(instruction->info.imm));
+                        instruction->type = NDS32_INSN_RESOURCE_ACCESS;
+                        snprintf(instruction->text,
+                                        128,
+                                        "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMTUSR\t$r%d,#%d",
+                                        address,
+                                        opcode, instruction->info.rt,
+                                        (instruction->info.imm >> 10) & 0x3FF);
+                        break;
+               case 36: /* MUL */
+                        nds32_parse_type_3(opcode, &(instruction->info.rt),
+                                        &(instruction->info.ra),
+                                        &(instruction->info.rb), &(instruction->info.imm));
+                        instruction->type = NDS32_INSN_DATA_PROC;
+                        snprintf(instruction->text,
+                                        128,
+                                        "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMUL\t$r%d,$r%d,$r%d",
+                                        address,
+                                        opcode, instruction->info.rt, instruction->info.ra,
+                                        instruction->info.rb);
+                        break;
+               case 40: { /* MULTS64 */
+                                uint8_t dt_val;
+                                nds32_parse_type_3(opcode, &dt_val,
+                                                &(instruction->info.ra),
+                                                &(instruction->info.rb), &(instruction->info.imm));
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMULTS64\t$D%d,$r%d,$r%d",
+                                                address,
+                                                opcode, (dt_val >> 1) & 0x1, instruction->info.ra,
+                                                instruction->info.rb);
+                        }
+                        break;
+               case 41: { /* MULT64 */
+                                uint8_t dt_val;
+                                nds32_parse_type_3(opcode, &dt_val,
+                                                &(instruction->info.ra),
+                                                &(instruction->info.rb), &(instruction->info.imm));
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMULT64\t$D%d,$r%d,$r%d",
+                                                address,
+                                                opcode, (dt_val >> 1) & 0x1, instruction->info.ra,
+                                                instruction->info.rb);
+                        }
+                        break;
+               case 42: { /* MADDS64 */
+                                uint8_t dt_val;
+                                nds32_parse_type_3(opcode, &dt_val, &(instruction->info.ra),
+                                                &(instruction->info.rb), &(instruction->info.imm));
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMADDS64\t$D%d,$r%d,$r%d",
+                                                address,
+                                                opcode, (dt_val >> 1) & 0x1, instruction->info.ra,
+                                                instruction->info.rb);
+                        }
+                        break;
+               case 43: { /* MADD64 */
+                                uint8_t dt_val;
+                                nds32_parse_type_3(opcode, &dt_val, &(instruction->info.ra),
+                                                &(instruction->info.rb), &(instruction->info.imm));
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMADD64\t$D%d,$r%d,$r%d",
+                                                address,
+                                                opcode, (dt_val >> 1) & 0x1, instruction->info.ra,
+                                                instruction->info.rb);
+                        }
+                        break;
+               case 44: { /* MSUBS64 */
+                                uint8_t dt_val;
+                                nds32_parse_type_3(opcode, &dt_val, &(instruction->info.ra),
+                                                &(instruction->info.rb), &(instruction->info.imm));
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMSUBS64\t$D%d,$r%d,$r%d",
+                                                address,
+                                                opcode, (dt_val >> 1) & 0x1, instruction->info.ra,
+                                                instruction->info.rb);
+                        }
+                        break;
+               case 45: { /* MSUB64 */
+                                uint8_t dt_val;
+                                nds32_parse_type_3(opcode, &dt_val, &(instruction->info.ra),
+                                                &(instruction->info.rb), &(instruction->info.imm));
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMSUB64\t$D%d,$r%d,$r%d",
+                                                address,
+                                                opcode, (dt_val >> 1) & 0x1, instruction->info.ra,
+                                                instruction->info.rb);
+                        }
+                        break;
+               case 46: { /* DIVS */
+                                uint8_t dt_val;
+                                nds32_parse_type_3(opcode, &dt_val, &(instruction->info.ra),
+                                                &(instruction->info.rb), &(instruction->info.imm));
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tDIVS\t$D%d,$r%d,$r%d",
+                                                address,
+                                                opcode, (dt_val >> 1) & 0x1, instruction->info.ra,
+                                                instruction->info.rb);
+                        }
+                        break;
+               case 47: { /* DIV */
+                                uint8_t dt_val;
+                                nds32_parse_type_3(opcode, &dt_val, &(instruction->info.ra),
+                                                &(instruction->info.rb), &(instruction->info.imm));
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tDIV\t$D%d,$r%d,$r%d",
+                                                address,
+                                                opcode, (dt_val >> 1) & 0x1, instruction->info.ra,
+                                                instruction->info.rb);
+                        }
+                        break;
+               case 49: { /* MULT32 */
+                                uint8_t dt_val;
+                                nds32_parse_type_3(opcode, &dt_val, &(instruction->info.ra),
+                                                &(instruction->info.rb), &(instruction->info.imm));
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMULT32\t$D%d,$r%d,$r%d",
+                                                address,
+                                                opcode, (dt_val >> 1) & 0x1, instruction->info.ra,
+                                                instruction->info.rb);
+                        }
+                        break;
+               case 51: { /* MADD32 */
+                                uint8_t dt_val;
+                                nds32_parse_type_3(opcode, &dt_val, &(instruction->info.ra),
+                                                &(instruction->info.rb), &(instruction->info.imm));
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMADD32\t$D%d,$r%d,$r%d",
+                                                address,
+                                                opcode, (dt_val >> 1) & 0x1, instruction->info.ra,
+                                                instruction->info.rb);
+                        }
+                        break;
+               case 53: { /* MSUB32 */
+                                uint8_t dt_val;
+                                nds32_parse_type_3(opcode, &dt_val, &(instruction->info.ra),
+                                                &(instruction->info.rb), &(instruction->info.imm));
+                                instruction->type = NDS32_INSN_DATA_PROC;
+                                snprintf(instruction->text,
+                                                128,
+                                                "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMSUB32\t$D%d,$r%d,$r%d",
+                                                address,
+                                                opcode, (dt_val >> 1) & 0x1, instruction->info.ra,
+                                                instruction->info.rb);
+                        }
+                        break;
+               default:
+                        snprintf(instruction->text,
+                                        128,
+                                        "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION",
+                                        address,
+                                        opcode);
+                        return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_parse_group_4_insn(struct nds32 *nds32, uint32_t opcode,
+               uint32_t address, struct nds32_instruction *instruction)
+{
+       uint8_t opc_6;
+
+       opc_6 = instruction->info.opc_6;
+
+       switch (opc_6 & 0x7) {
+               case 0: /* ALU_1 */
+                       nds32_parse_alu_1(opcode, address, instruction);
+                       break;
+               case 1: /* ALU_2 */
+                       nds32_parse_alu_2(opcode, address, instruction);
+                       break;
+               case 2: /* MOVI */
+                       nds32_parse_type_1(opcode, &(instruction->info.rt),
+                                       &(instruction->info.imm));
+                       /* sign-extend */
+                       instruction->info.imm = (instruction->info.imm << 12) >> 12;
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMOVI\t$r%d,#%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.imm);
+                       break;
+               case 3: /* SETHI */
+                       nds32_parse_type_1(opcode, &(instruction->info.rt),
+                                       &(instruction->info.imm));
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSETHI\t$r%d,0x%8.8" PRIx32,
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.imm);
+                       break;
+               case 4: /* JI */
+                       nds32_parse_type_0(opcode, &(instruction->info.imm));
+                       /* sign-extend */
+                       instruction->info.imm = (instruction->info.imm << 8) >> 8;
+                       instruction->type = NDS32_INSN_JUMP_BRANCH;
+                       if ((instruction->info.imm >> 24) & 0x1) { /* JAL */
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tJAL\t#%d",
+                                               address,
+                                               opcode, instruction->info.imm);
+                       } else { /* J */
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tJ\t#%d",
+                                               address,
+                                               opcode, instruction->info.imm);
+                       }
+                       break;
+               case 5: { /* JREG */
+                               int32_t imm;
+                               nds32_parse_type_0(opcode, &imm);
+                               instruction->info.rb = (imm >> 10) & 0x1F;
+                               instruction->type = NDS32_INSN_JUMP_BRANCH;
+                               switch (imm & 0x1F) {
+                                       /* TODO */
+                                       case 0: /* JR */
+                                               if (imm & 0x20) { /* RET */
+                                                       snprintf(instruction->text,
+                                                                       128,
+                                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tRET\t$r%d",
+                                                                       address,
+                                                                       opcode, instruction->info.rb);
+                                               } else { /* JR */
+                                                       snprintf(instruction->text,
+                                                                       128,
+                                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tJR\t$r%d",
+                                                                       address,
+                                                                       opcode, instruction->info.rb);
+                                               }
+                                               break;
+                                       case 1: /* JRAL */
+                                               instruction->info.rt = (imm >> 20) & 0x1F;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tJRAL\t$r%d,$r%d",
+                                                               address,
+                                                               opcode, instruction->info.rt, instruction->info.rb);
+                                               break;
+                                       case 2: /* JRNEZ */
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tJRNEZ\t$r%d",
+                                                               address,
+                                                               opcode, instruction->info.rb);
+                                               break;
+                                       case 3: /* JRALNEZ */
+                                               instruction->info.rt = (imm >> 20) & 0x1F;
+                                               if (instruction->info.rt == R30)
+                                                       snprintf(instruction->text,
+                                                                       128,
+                                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tJRALNEZ\t$r%d",
+                                                                       address,
+                                                                       opcode, instruction->info.rb);
+                                               else
+                                                       snprintf(instruction->text,
+                                                                       128,
+                                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32
+                                                                       "\tJRALNEZ\t$r%d,$r%d",
+                                                                       address,
+                                                                       opcode,
+                                                                       instruction->info.rt,
+                                                                       instruction->info.rb);
+                                               break;
+                               }
+                       }
+                       break;
+               case 6: { /* BR1 */
+                               int32_t imm;
+
+                               nds32_parse_type_0(opcode, &imm);
+                               instruction->type = NDS32_INSN_JUMP_BRANCH;
+                               if ((imm >> 14) & 0x1) { /* BNE */
+                                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                                       &(instruction->info.ra), &(instruction->info.imm));
+                                       /* sign-extend */
+                                       instruction->info.imm = (instruction->info.imm << 18) >> 18;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBNE\t$r%d,$r%d,#%d",
+                                                       address,
+                                                       opcode, instruction->info.rt, instruction->info.ra,
+                                                       instruction->info.imm);
+                               } else { /* BEQ */
+                                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                                       &(instruction->info.ra), &(instruction->info.imm));
+                                       /* sign-extend */
+                                       instruction->info.imm = (instruction->info.imm << 18) >> 18;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBEQ\t$r%d,$r%d,#%d",
+                                                       address,
+                                                       opcode, instruction->info.rt,
+                                                       instruction->info.ra,
+                                                       instruction->info.imm);
+                               }
+                       }
+                       break;
+               case 7: { /* BR2 */
+                               int32_t imm;
+
+                               nds32_parse_type_0(opcode, &imm);
+                               instruction->type = NDS32_INSN_JUMP_BRANCH;
+                               switch ((imm >> 16) & 0xF) {
+                                       case 2: /* BEQZ */
+                                               nds32_parse_type_1(opcode, &(instruction->info.rt),
+                                                               &(instruction->info.imm));
+                                               instruction->info.imm = (instruction->info.imm << 16) >> 16;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBEQZ\t$r%d,#%d",
+                                                               address,
+                                                               opcode, instruction->info.rt, instruction->info.imm);
+                                               break;
+                                       case 3: /* BNEZ */
+                                               nds32_parse_type_1(opcode, &(instruction->info.rt),
+                                                               &(instruction->info.imm));
+                                               instruction->info.imm = (instruction->info.imm << 16) >> 16;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBNEZ\t$r%d,#%d",
+                                                               address,
+                                                               opcode, instruction->info.rt, instruction->info.imm);
+                                               break;
+                                       case 4: /* BGEZ */
+                                               nds32_parse_type_1(opcode, &(instruction->info.rt),
+                                                               &(instruction->info.imm));
+                                               instruction->info.imm = (instruction->info.imm << 16) >> 16;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBGEZ\t$r%d,#%d",
+                                                               address,
+                                                               opcode, instruction->info.rt, instruction->info.imm);
+                                               break;
+                                       case 5: /* BLTZ */
+                                               nds32_parse_type_1(opcode, &(instruction->info.rt),
+                                                               &(instruction->info.imm));
+                                               instruction->info.imm = (instruction->info.imm << 16) >> 16;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBLTZ\t$r%d,#%d",
+                                                               address,
+                                                               opcode, instruction->info.rt, instruction->info.imm);
+                                               break;
+                                       case 6: /* BGTZ */
+                                               nds32_parse_type_1(opcode, &(instruction->info.rt),
+                                                               &(instruction->info.imm));
+                                               instruction->info.imm = (instruction->info.imm << 16) >> 16;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBGTZ\t$r%d,#%d",
+                                                               address,
+                                                               opcode, instruction->info.rt, instruction->info.imm);
+                                               break;
+                                       case 7: /* BLEZ */
+                                               nds32_parse_type_1(opcode, &(instruction->info.rt),
+                                                               &(instruction->info.imm));
+                                               instruction->info.imm = (instruction->info.imm << 16) >> 16;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBLEZ\t$r%d,#%d",
+                                                               address,
+                                                               opcode, instruction->info.rt, instruction->info.imm);
+                                               break;
+                                       case 12: /* BGEZAL */
+                                               nds32_parse_type_1(opcode, &(instruction->info.rt),
+                                                               &(instruction->info.imm));
+                                               instruction->info.imm = (instruction->info.imm << 16) >> 16;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBGEZAL\t$r%d,#%d",
+                                                               address,
+                                                               opcode, instruction->info.rt, instruction->info.imm);
+                                               break;
+                                       case 13: /* BLTZAL */
+                                               nds32_parse_type_1(opcode, &(instruction->info.rt),
+                                                               &(instruction->info.imm));
+                                               instruction->info.imm = (instruction->info.imm << 16) >> 16;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBLTZAL\t$r%d,#%d",
+                                                               address,
+                                                               opcode, instruction->info.rt, instruction->info.imm);
+                                               break;
+                               }
+                       }
+                       break;
+               default:
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION",
+                                       address,
+                                       opcode);
+                       return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_parse_group_5_insn(struct nds32 *nds32, uint32_t opcode,
+               uint32_t address, struct nds32_instruction *instruction)
+{
+       uint8_t opc_6;
+
+       opc_6 = instruction->info.opc_6;
+
+       switch (opc_6 & 0x7) {
+               case 0: /* ADDI */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra), &(instruction->info.imm));
+                       instruction->info.imm = (instruction->info.imm << 17) >> 17; /* sign-extend */
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tADDI\t$r%d,$r%d,#%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 1: /* SUBRI */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra), &(instruction->info.imm));
+                       instruction->info.imm = (instruction->info.imm << 17) >> 17; /* sign-extend */
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSUBRI\t$r%d,$r%d,#%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 2: /* ANDI */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra), &(instruction->info.imm));
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tANDI\t$r%d,$r%d,#%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 3: /* XORI */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra), &(instruction->info.imm));
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tXORI\t$r%d,$r%d,#%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 4: /* ORI */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra), &(instruction->info.imm));
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tORI\t$r%d,$r%d,0x%8.8" PRIx32,
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 6: /* SLTI */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra), &(instruction->info.imm));
+                       instruction->info.imm = (instruction->info.imm << 17) >> 17; /* sign-extend */
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSLTI\t$r%d,$r%d,#%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 7: /* SLTSI */
+                       nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                       &(instruction->info.ra), &(instruction->info.imm));
+                       instruction->info.imm = (instruction->info.imm << 17) >> 17; /* sign-extend */
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSLTSI\t$r%d,$r%d,#%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               default:
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION",
+                                       address,
+                                       opcode);
+                       return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_parse_group_6_insn(struct nds32 *nds32, uint32_t opcode,
+               uint32_t address, struct nds32_instruction *instruction)
+{
+       uint8_t opc_6;
+
+       opc_6 = instruction->info.opc_6;
+
+       switch (opc_6 & 0x7) {
+               case 2: { /* MISC */
+                               int32_t imm;
+                               uint8_t sub_opc;
+
+                               nds32_parse_type_0(opcode, &imm);
+
+                               sub_opc = imm & 0x1F;
+                               switch (sub_opc) {
+                                       case 0: /* STANDBY */
+                                               instruction->type = NDS32_INSN_MISC;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSTANDBY\t#%d",
+                                                               address,
+                                                               opcode, (opcode >> 5) & 0x3);
+                                               break;
+                                       case 1: /* CCTL */
+                                               /* TODO */
+                                               nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                                               &(instruction->info.ra), &(instruction->info.imm));
+                                               instruction->type = NDS32_INSN_MISC;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tCCTL",
+                                                               address,
+                                                               opcode);
+                                               break;
+                                       case 2: /* MFSR */
+                                               nds32_parse_type_1(opcode, &(instruction->info.rt),
+                                                               &(instruction->info.imm));
+                                               instruction->type = NDS32_INSN_RESOURCE_ACCESS;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMFSR\t$r%d,#%d",
+                                                               address,
+                                                               opcode, instruction->info.rt,
+                                                               (instruction->info.imm >> 10) & 0x3FF);
+                                               break;
+                                       case 3: /* MTSR */
+                                               nds32_parse_type_1(opcode, &(instruction->info.ra),
+                                                               &(instruction->info.imm));
+                                               instruction->type = NDS32_INSN_RESOURCE_ACCESS;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMTSR\t$r%d,#%d",
+                                                               address,
+                                                               opcode, instruction->info.ra,
+                                                               (instruction->info.imm >> 10) & 0x3FF);
+                                               break;
+                                       case 4: /* IRET */
+                                               instruction->type = NDS32_INSN_MISC;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tIRET",
+                                                               address,
+                                                               opcode);
+                                               break;
+                                       case 5: /* TRAP */
+                                               instruction->type = NDS32_INSN_MISC;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tTRAP\t#%d",
+                                                               address,
+                                                               opcode, (imm >> 5) & 0x7FFF);
+                                               break;
+                                       case 6: /* TEQZ */
+                                               nds32_parse_type_1(opcode, &(instruction->info.ra),
+                                                               &(instruction->info.imm));
+                                               instruction->type = NDS32_INSN_MISC;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tTEQZ\t$r%d,#%d",
+                                                               address,
+                                                               opcode, instruction->info.ra,
+                                                               (instruction->info.imm >> 5) & 0x7FFF);
+                                               break;
+                                       case 7: /* TNEZ */
+                                               nds32_parse_type_1(opcode, &(instruction->info.ra),
+                                                               &(instruction->info.imm));
+                                               instruction->type = NDS32_INSN_MISC;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tTNEZ\t$r%d,#%d",
+                                                               address,
+                                                               opcode, instruction->info.ra,
+                                                               (instruction->info.imm >> 5) & 0x7FFF);
+                                               break;
+                                       case 8: /* DSB */
+                                               instruction->type = NDS32_INSN_MISC;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tDSB",
+                                                               address,
+                                                               opcode);
+                                               break;
+                                       case 9: /* ISB */
+                                               instruction->type = NDS32_INSN_MISC;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tISB",
+                                                               address,
+                                                               opcode);
+                                               break;
+                                       case 10: /* BREAK */
+                                               instruction->type = NDS32_INSN_MISC;
+                                               instruction->info.sub_opc = imm & 0x1F;
+                                               instruction->info.imm = (imm >> 5) & 0x7FFF;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBREAK\t#%d",
+                                                               address,
+                                                               opcode, instruction->info.imm);
+                                               break;
+                                       case 11: /* SYSCALL */
+                                               instruction->type = NDS32_INSN_MISC;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSYSCALL\t#%d",
+                                                               address,
+                                                               opcode, (imm >> 5) & 0x7FFF);
+                                               break;
+                                       case 12: /* MSYNC */
+                                               instruction->type = NDS32_INSN_MISC;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMSYNC\t#%d",
+                                                               address,
+                                                               opcode, (imm >> 5) & 0x7);
+                                               break;
+                                       case 13: /* ISYNC */
+                                               nds32_parse_type_1(opcode, &(instruction->info.ra),
+                                                               &(instruction->info.imm));
+                                               instruction->type = NDS32_INSN_MISC;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tISYNC\t$r%d",
+                                                               address,
+                                                               opcode, instruction->info.ra);
+                                               break;
+                                       case 14: /* TLBOP */
+                                               /* TODO */
+                                               nds32_parse_type_2(opcode, &(instruction->info.rt),
+                                                               &(instruction->info.ra), &(instruction->info.imm));
+                                               instruction->type = NDS32_INSN_RESOURCE_ACCESS;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tTLBOP",
+                                                               address,
+                                                               opcode);
+                                               break;
+                               }
+
+                               break;
+                       }
+               default:
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION",
+                                       address,
+                                       opcode);
+                       return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static uint32_t field_mask[9] = {
+       0x0,
+       0x1,
+       0x3,
+       0x7,
+       0xF,
+       0x1F,
+       0x3F,
+       0x7F,
+       0xFF,
+};
+
+static uint8_t nds32_extract_field_8u(uint16_t opcode, uint32_t start, uint32_t length)
+{
+       if (0 < length && length < 9)
+               return (opcode >> start) & field_mask[length];
+
+       return 0;
+}
+
+static int nds32_parse_group_0_insn_16(struct nds32 *nds32, uint16_t opcode,
+               uint32_t address, struct nds32_instruction *instruction)
+{
+       switch ((opcode >> 10) & 0x7) {
+               case 0: /* MOV55 */
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 5, 5);
+                       instruction->info.ra = nds32_extract_field_8u(opcode, 0, 5);
+                       instruction->type = NDS32_INSN_MISC;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tMOV55\t$r%d,$r%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra);
+                       break;
+               case 1: /* MOVI55 */
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 5, 5);
+                       instruction->info.imm = nds32_extract_field_8u(opcode, 0, 5);
+                       instruction->info.imm = (instruction->info.imm << 27) >> 27;
+                       instruction->type = NDS32_INSN_MISC;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tMOVI55\t$r%d,#%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.imm);
+                       break;
+               case 2: /* ADD45, SUB45 */
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 5, 4);
+                       instruction->info.rb = nds32_extract_field_8u(opcode, 0, 5);
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       if (nds32_extract_field_8u(opcode, 9, 1) == 0) { /* ADD45 */
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tADD45\t$r%d,$r%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.rb);
+                       } else { /* SUB45 */
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tSUB45\t$r%d,$r%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.rb);
+                       }
+
+                       break;
+               case 3: /* ADDI45, SUBI45 */
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 5, 4);
+                       instruction->info.imm = nds32_extract_field_8u(opcode, 0, 5);
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       if (nds32_extract_field_8u(opcode, 9, 1) == 0) { /* ADDI45 */
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tADDI45\t$r%d,#%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.imm);
+                       } else { /* SUBI45 */
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tSUBI45\t$r%d,#%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.imm);
+                       }
+                       break;
+               case 4: /* SRAI45, SRLI45 */
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 5, 4);
+                       instruction->info.imm = nds32_extract_field_8u(opcode, 0, 5);
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       if (nds32_extract_field_8u(opcode, 9, 1) == 0) { /* SRAI45 */
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tSRAI45\t$r%d,#%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.imm);
+                       } else { /* SRLI45 */
+                               if ((instruction->info.rt == 0) && (instruction->info.imm == 0)) {
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tNOP",
+                                                       address,
+                                                       opcode);
+                               } else {
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tSRLI45\t$r%d,#%d",
+                                                       address,
+                                                       opcode, instruction->info.rt, instruction->info.imm);
+                               }
+                       }
+                       break;
+               case 5:
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3);
+                       instruction->info.ra = nds32_extract_field_8u(opcode, 3, 3);
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       if (nds32_extract_field_8u(opcode, 9, 1) == 0) { /* SLLI333 */
+                               instruction->info.imm = nds32_extract_field_8u(opcode, 0, 3);
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tSLLI333\t$r%d,$r%d,#%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.imm);
+                       } else {
+                               instruction->info.sub_opc = nds32_extract_field_8u(opcode, 0, 3);
+                               switch (instruction->info.sub_opc) {
+                                       case 0: /* ZEB33 */
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tZEB33\t$r%d,$r%d",
+                                                               address,
+                                                               opcode, instruction->info.rt, instruction->info.ra);
+                                               break;
+                                       case 1: /* ZEH33 */
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tZEH33\t$r%d,$r%d",
+                                                               address,
+                                                               opcode, instruction->info.rt, instruction->info.ra);
+                                               break;
+                                       case 2: /* SEB33 */
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tSEB33\t$r%d,$r%d",
+                                                               address,
+                                                               opcode, instruction->info.rt, instruction->info.ra);
+                                               break;
+                                       case 3: /* SEH33 */
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tSEH33\t$r%d,$r%d",
+                                                               address,
+                                                               opcode, instruction->info.rt, instruction->info.ra);
+                                               break;
+                                       case 4: /* XLSB33 */
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tXLSB33\t$r%d,$r%d",
+                                                               address,
+                                                               opcode, instruction->info.rt, instruction->info.ra);
+                                               break;
+                                       case 5: /* XLLB33 */
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tXLLB33\t$r%d,$r%d",
+                                                               address,
+                                                               opcode, instruction->info.rt, instruction->info.ra);
+                                               break;
+                                       case 6: /* BMSKI33 */
+                                               instruction->info.ra = 0;
+                                               instruction->info.imm = nds32_extract_field_8u(opcode, 3, 3);
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tBMSKI33\t$r%d,$r%d",
+                                                               address,
+                                                               opcode, instruction->info.rt, instruction->info.imm);
+                                               break;
+                                       case 7: /* FEXTI33 */
+                                               instruction->info.ra = 0;
+                                               instruction->info.imm = nds32_extract_field_8u(opcode, 3, 3);
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tFEXTI33\t$r%d,$r%d",
+                                                               address,
+                                                               opcode, instruction->info.rt, instruction->info.imm);
+                                               break;
+                                       default:
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32
+                                                               "\tUNDEFINED INSTRUCTION",
+                                                               address,
+                                                               opcode);
+                                               return ERROR_FAIL;
+                               }
+                       }
+                       break;
+               case 6: /* ADD333, SUB333 */
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3);
+                       instruction->info.ra = nds32_extract_field_8u(opcode, 3, 3);
+                       instruction->info.rb = nds32_extract_field_8u(opcode, 0, 3);
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       if (nds32_extract_field_8u(opcode, 9, 1) == 0) { /* ADD333 */
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tADD333\t$r%d,$r%d,$r%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.rb);
+                       } else { /* SUB333 */
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tSUB333\t$r%d,$r%d,$r%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.rb);
+                       }
+                       break;
+               case 7: /* ADDI333, SUBI333 */
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3);
+                       instruction->info.ra = nds32_extract_field_8u(opcode, 3, 3);
+                       instruction->info.imm = nds32_extract_field_8u(opcode, 0, 3);
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       if (nds32_extract_field_8u(opcode, 9, 1) == 0) { /* ADDI333 */
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tADDI333\t$r%d,$r%d,#%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.imm);
+                       } else { /* SUBI333 */
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tSUBI333\t$r%d,$r%d,#%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.ra,
+                                               instruction->info.imm);
+                       }
+                       break;
+               default:
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION",
+                                       address,
+                                       opcode);
+                       return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_parse_group_1_insn_16(struct nds32 *nds32, uint16_t opcode,
+               uint32_t address, struct nds32_instruction *instruction)
+{
+       switch ((opcode >> 9) & 0xF) {
+               case 0: /* LWI333 */
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3);
+                       instruction->info.ra = nds32_extract_field_8u(opcode, 3, 3);
+                       instruction->info.imm = nds32_extract_field_8u(opcode, 0, 3) << 2;
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_start += instruction->info.imm;
+                       instruction->access_end = instruction->access_start + 4;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tLWI333\t$r%d,[$r%d+(#%d)]",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 1: /* LWI333.BI */
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3);
+                       instruction->info.ra = nds32_extract_field_8u(opcode, 3, 3);
+                       instruction->info.imm = nds32_extract_field_8u(opcode, 0, 3);
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_end = instruction->access_start + 4;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tLWI333.BI\t$r%d,[$r%d],#%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm << 2);
+                       break;
+               case 2: /* LHI333 */
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3);
+                       instruction->info.ra = nds32_extract_field_8u(opcode, 3, 3);
+                       instruction->info.imm = nds32_extract_field_8u(opcode, 0, 3) << 1;
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_start += instruction->info.imm;
+                       instruction->access_end = instruction->access_start + 2;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tLHI333\t$r%d,[$r%d+(#%d)]",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 3: /* LBI333 */
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3);
+                       instruction->info.ra = nds32_extract_field_8u(opcode, 3, 3);
+                       instruction->info.imm = nds32_extract_field_8u(opcode, 0, 3);
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_start += instruction->info.imm;
+                       instruction->access_end = instruction->access_start + 1;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tLBI333\t$r%d,[$r%d+(#%d)]",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 4: /* SWI333 */
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3);
+                       instruction->info.ra = nds32_extract_field_8u(opcode, 3, 3);
+                       instruction->info.imm = nds32_extract_field_8u(opcode, 0, 3) << 2;
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_start += instruction->info.imm;
+                       instruction->access_end = instruction->access_start + 4;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tSWI333\t$r%d,[$r%d+(#%d)]",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 5: /* SWI333.BI */
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3);
+                       instruction->info.ra = nds32_extract_field_8u(opcode, 3, 3);
+                       instruction->info.imm = nds32_extract_field_8u(opcode, 0, 3) << 2;
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_end = instruction->access_start + 4;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tSWI333.BI\t$r%d,[$r%d],#%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 6: /* SHI333 */
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3);
+                       instruction->info.ra = nds32_extract_field_8u(opcode, 3, 3);
+                       instruction->info.imm = nds32_extract_field_8u(opcode, 0, 3) << 1;
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_start += instruction->info.imm;
+                       instruction->access_end = instruction->access_start + 2;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tSHI333\t$r%d,[$r%d+(#%d)]",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 7: /* SBI333 */
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3);
+                       instruction->info.ra = nds32_extract_field_8u(opcode, 3, 3);
+                       instruction->info.imm = nds32_extract_field_8u(opcode, 0, 3);
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_start += instruction->info.imm;
+                       instruction->access_end = instruction->access_start + 1;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tSHI333\t$r%d,[$r%d+(#%d)]",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra,
+                                       instruction->info.imm);
+                       break;
+               case 8: /* ADDRI36.SP */
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3);
+                       instruction->info.imm = nds32_extract_field_8u(opcode, 0, 6) << 2;
+                       instruction->type = NDS32_INSN_DATA_PROC;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tADDRI36.SP\t$r%d,#%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.imm);
+                       break;
+               case 9: /* LWI45.FE */
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 5, 4);
+                       instruction->info.imm = nds32_extract_field_8u(opcode, 0, 5);
+                       instruction->info.imm -= 32;
+                       instruction->info.imm <<= 2;
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, R8, &(instruction->access_start));
+                       instruction->access_start += instruction->info.imm;
+                       instruction->access_end = instruction->access_start + 4;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tLWI45.FE\t$r%d,[#%d]",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.imm);
+                       break;
+               case 10: /* LWI450 */
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 5, 4);
+                       instruction->info.ra = nds32_extract_field_8u(opcode, 0, 5);
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_end = instruction->access_start + 4;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tLWI450\t$r%d,$r%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra);
+                       break;
+               case 11: /* SWI450 */
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 5, 4);
+                       instruction->info.ra = nds32_extract_field_8u(opcode, 0, 5);
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, instruction->info.ra,
+                                       &(instruction->access_start));
+                       instruction->access_end = instruction->access_start + 4;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tSWI450\t$r%d,$r%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.ra);
+                       break;
+               case 12:
+               case 13:
+               case 14:
+               case 15: /* LWI37, SWI37 */
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 8, 3);
+                       instruction->info.imm = nds32_extract_field_8u(opcode, 0, 7) << 2;
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, R28, &(instruction->access_start));
+                       instruction->access_start += instruction->info.imm;
+                       instruction->access_end = instruction->access_start + 4;
+                       if (nds32_extract_field_8u(opcode, 7, 1) == 0) { /* LWI37 */
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tLWI37\t$r%d,[fp+#%d]",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.imm);
+                       } else { /* SWI37 */
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tSWI37\t$r%d,[fp+#%d]",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.imm);
+                       }
+                       break;
+               default: /* ERROR */
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION",
+                                       address,
+                                       opcode);
+                       return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_parse_group_2_insn_16(struct nds32 *nds32, uint16_t opcode,
+               uint32_t address, struct nds32_instruction *instruction)
+{
+       switch ((opcode >> 11) & 0x3) {
+               case 0: /* BEQZ38 */
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 8, 3);
+                       instruction->info.imm = nds32_extract_field_8u(opcode, 0, 8);
+                       instruction->info.imm = (instruction->info.imm << 24) >> 24;
+                       instruction->type = NDS32_INSN_JUMP_BRANCH;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tBEQZ38\t$r%d,#%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.imm);
+                       break;
+               case 1: /* BNEZ38 */
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 8, 3);
+                       instruction->info.imm = nds32_extract_field_8u(opcode, 0, 8);
+                       instruction->info.imm = (instruction->info.imm << 24) >> 24;
+                       instruction->type = NDS32_INSN_JUMP_BRANCH;
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tBNEZ38\t$r%d,#%d",
+                                       address,
+                                       opcode, instruction->info.rt, instruction->info.imm);
+                       break;
+               case 2: /* BEQS38,J8 */
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 8, 3);
+                       instruction->info.imm = nds32_extract_field_8u(opcode, 0, 8);
+                       instruction->info.imm = (instruction->info.imm << 24) >> 24;
+                       instruction->type = NDS32_INSN_JUMP_BRANCH;
+                       if (instruction->info.rt == 5) { /* J8 */
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tJ8\t#%d",
+                                               address,
+                                               opcode, instruction->info.imm);
+                       } else { /* BEQS38 */
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tBEQS38\t$r%d,#%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.imm);
+                       }
+                       break;
+               case 3: /* BNES38, JR5, RET5, JRAL5 */
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 8, 3);
+                       instruction->info.imm = nds32_extract_field_8u(opcode, 0, 8);
+                       instruction->info.imm = (instruction->info.imm << 24) >> 24;
+                       instruction->type = NDS32_INSN_JUMP_BRANCH;
+                       if (instruction->info.rt == 5) {
+                               instruction->info.imm = 0;
+                               instruction->info.rb = nds32_extract_field_8u(opcode, 0, 5);
+                               switch (nds32_extract_field_8u(opcode, 5, 3)) {
+                                       case 0: /* JR5 */
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tJR5\t$r%d",
+                                                               address,
+                                                               opcode, instruction->info.rb);
+                                               break;
+                                       case 1: /* JRAL5 */
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tJRAL5\t$r%d",
+                                                               address,
+                                                               opcode, instruction->info.rb);
+                                               break;
+                                       case 2: /* EX9.IT */
+                                               instruction->info.rb = 0;
+                                               instruction->info.imm = nds32_extract_field_8u(opcode, 0, 5);
+                                               /* TODO: implement real instruction semantics */
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tEX9.IT\t#%d",
+                                                               address,
+                                                               opcode, instruction->info.imm);
+                                               break;
+                                       case 4: /* RET5 */
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tRET5\t$r%d",
+                                                               address,
+                                                               opcode, instruction->info.rb);
+                                               break;
+                                       case 5: /* ADD5.PC */
+                                               instruction->info.rt = 0;
+                                               instruction->info.rt = nds32_extract_field_8u(opcode, 0, 5);
+                                               instruction->type = NDS32_INSN_DATA_PROC;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tADD5.PC\t$r%d",
+                                                               address,
+                                                               opcode, instruction->info.rt);
+                                               break;
+                                       default:
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32
+                                                               "\tUNDEFINED INSTRUCTION",
+                                                               address,
+                                                               opcode);
+                                               return ERROR_FAIL;
+                               }
+                       } else { /* BNES38 */
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tBNES38\t$r%d,#%d",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.imm);
+                       }
+                       break;
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_parse_group_3_insn_16(struct nds32 *nds32, uint16_t opcode,
+               uint32_t address, struct nds32_instruction *instruction)
+{
+       switch ((opcode >> 11) & 0x3) {
+               case 0:
+                       switch ((opcode >> 9) & 0x3) {
+                               case 0: /* SLTS45 */
+                                       instruction->info.ra = nds32_extract_field_8u(opcode, 5, 4);
+                                       instruction->info.rb = nds32_extract_field_8u(opcode, 0, 5);
+                                       instruction->type = NDS32_INSN_DATA_PROC;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tSLTS45\t$r%d,$r%d",
+                                                       address,
+                                                       opcode, instruction->info.ra, instruction->info.rb);
+                                       break;
+                               case 1: /* SLT45 */
+                                       instruction->info.ra = nds32_extract_field_8u(opcode, 5, 4);
+                                       instruction->info.rb = nds32_extract_field_8u(opcode, 0, 5);
+                                       instruction->type = NDS32_INSN_DATA_PROC;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tSLT45\t$r%d,$r%d",
+                                                       address,
+                                                       opcode, instruction->info.ra, instruction->info.rb);
+                                       break;
+                               case 2: /* SLTSI45 */
+                                       instruction->info.ra = nds32_extract_field_8u(opcode, 5, 4);
+                                       instruction->info.imm = nds32_extract_field_8u(opcode, 0, 5);
+                                       instruction->type = NDS32_INSN_DATA_PROC;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tSLTSI45\t$r%d,#%d",
+                                                       address,
+                                                       opcode, instruction->info.ra, instruction->info.imm);
+                                       break;
+                               case 3: /* SLTI45 */
+                                       instruction->info.ra = nds32_extract_field_8u(opcode, 5, 4);
+                                       instruction->info.imm = nds32_extract_field_8u(opcode, 0, 5);
+                                       instruction->type = NDS32_INSN_DATA_PROC;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tSLTI45\t$r%d,#%d",
+                                                       address,
+                                                       opcode, instruction->info.ra, instruction->info.imm);
+                                       break;
+                       }
+                       break;
+               case 1:
+                       switch ((opcode >> 9) & 0x3) {
+                               case 0:
+                                       instruction->info.imm = nds32_extract_field_8u(opcode, 0, 8);
+                                       instruction->info.imm = (instruction->info.imm << 24) >> 24;
+                                       instruction->type = NDS32_INSN_JUMP_BRANCH;
+                                       if (nds32_extract_field_8u(opcode, 8, 1) == 0) { /* BEQZS8 */
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tBEQZS8\t#%d",
+                                                               address,
+                                                               opcode, instruction->info.imm);
+                                       } else { /* BNEZS8 */
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tBNEZS8\t#%d",
+                                                               address,
+                                                               opcode, instruction->info.imm);
+                                       }
+                                       break;
+                               case 1: /* BREAK16 */
+                                       if (((opcode >> 5) & 0xF) == 0) {
+                                               instruction->type = NDS32_INSN_MISC;
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tBREAK16\t#%d",
+                                                               address,
+                                                               opcode, opcode & 0x1F);
+                                       } else { /* EX9.IT */
+                                               instruction->type = NDS32_INSN_MISC;
+                                               /* TODO: implement real instruction semantics */
+                                               snprintf(instruction->text,
+                                                               128,
+                                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tEX9.IT\t#%d",
+                                                               address,
+                                                               opcode, opcode & 0x1FF);
+                                       }
+                                       break;
+                               case 2: /* ADDI10S */
+                               case 3:
+                                       instruction->info.imm = opcode & 0x3FF;
+                                       instruction->info.imm = (instruction->info.imm << 22) >> 22;
+                                       instruction->type = NDS32_INSN_DATA_PROC;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tADDI10.SP\t#%d",
+                                                       address,
+                                                       opcode, instruction->info.imm);
+                                       break;
+                       }
+                       break;
+               case 2:
+                       instruction->info.rt = nds32_extract_field_8u(opcode, 8, 3);
+                       instruction->info.imm = nds32_extract_field_8u(opcode, 0, 7) << 2;
+                       instruction->type = NDS32_INSN_LOAD_STORE;
+                       nds32_get_mapped_reg(nds32, R31, &(instruction->access_start));
+                       instruction->access_start += instruction->info.imm;
+                       instruction->access_end = instruction->access_start + 4;
+                       if (nds32_extract_field_8u(opcode, 7, 1) == 0) { /* LWI37.SP */
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tLWI37.SP\t$r%d,[+#%d]",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.imm);
+                       } else { /* SWI37.SP */
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tSWI37.SP\t$r%d,[+#%d]",
+                                               address,
+                                               opcode, instruction->info.rt, instruction->info.imm);
+                       }
+                       break;
+               case 3:
+                       switch ((opcode >> 9) & 0x3) {
+                               case 0: /* IFCALL9 */
+                                       instruction->info.imm = opcode & 0x1FF;
+                                       instruction->type = NDS32_INSN_JUMP_BRANCH;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tIFCALL9\t#%d",
+                                                       address,
+                                                       opcode, instruction->info.imm);
+                                       break;
+                               case 1: /* MOVPI45 */
+                                       instruction->info.imm = nds32_extract_field_8u(opcode, 0, 5) + 16;
+                                       instruction->info.rt = nds32_extract_field_8u(opcode, 5, 4);
+                                       instruction->type = NDS32_INSN_MISC;
+                                       snprintf(instruction->text,
+                                                       128,
+                                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32 "\t\tMOVPI45\t$r%d,#%d",
+                                                       address,
+                                                       opcode, instruction->info.rt, instruction->info.imm);
+                                       break;
+                               case 2: /* PUSH25, POP25, MOVD44 */
+                                       switch ((opcode >> 7) & 0x3) {
+                                               case 0: /* PUSH25 */
+                                                       {
+                                                               uint8_t re;
+                                                               uint8_t gpr_count;
+
+                                                               instruction->type = NDS32_INSN_LOAD_STORE;
+                                                               instruction->info.imm =
+                                                                       nds32_extract_field_8u(opcode, 0, 5) << 3;
+                                                               re = nds32_extract_field_8u(opcode, 5, 2);
+
+                                                               if (re == 0)
+                                                                       re = 6;
+                                                               else if (re == 1)
+                                                                       re = 8;
+                                                               else if (re == 2)
+                                                                       re = 10;
+                                                               else if (re == 3)
+                                                                       re = 14;
+
+                                                               instruction->info.rd = re;
+                                                               /* GPRs list: R6 ~ Re and fp, gp, lp */
+                                                               gpr_count = 3 + (re - 5);
+
+                                                               nds32_get_mapped_reg(nds32, R31,
+                                                                               &(instruction->access_end));
+                                                               instruction->access_start =
+                                                                       instruction->access_end - (gpr_count * 4);
+
+                                                               snprintf(instruction->text,
+                                                                               128,
+                                                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32
+                                                                               "\t\tPUSH25\t$r%d,#%d",
+                                                                               address,
+                                                                               opcode, instruction->info.rd,
+                                                                               instruction->info.imm);
+                                                       }
+                                                       break;
+                                               case 1: /* POP25 */
+                                                       {
+                                                               uint8_t re;
+                                                               uint8_t gpr_count;
+
+                                                               instruction->type = NDS32_INSN_LOAD_STORE;
+                                                               instruction->info.imm =
+                                                                       nds32_extract_field_8u(opcode, 0, 5) << 3;
+                                                               re = nds32_extract_field_8u(opcode, 5, 2);
+
+                                                               if (re == 0)
+                                                                       re = 6;
+                                                               else if (re == 1)
+                                                                       re = 8;
+                                                               else if (re == 2)
+                                                                       re = 10;
+                                                               else if (re == 3)
+                                                                       re = 14;
+
+                                                               instruction->info.rd = re;
+                                                               /* GPRs list: R6 ~ Re and fp, gp, lp */
+                                                               gpr_count = 3 + (re - 5);
+
+                                                               nds32_get_mapped_reg(nds32, R31,
+                                                                               &(instruction->access_start));
+                                                               instruction->access_start += instruction->info.imm;
+                                                               instruction->access_end =
+                                                                       instruction->access_start + (gpr_count * 4);
+
+                                                               snprintf(instruction->text,
+                                                                               128,
+                                                                               "0x%8.8" PRIx32 "\t0x%4.4" PRIx32
+                                                                               "\t\tPOP25\t$r%d,#%d",
+                                                                               address,
+                                                                               opcode, instruction->info.rd,
+                                                                               instruction->info.imm);
+                                                       }
+                                                       break;
+                                               case 2: /* MOVD44 */
+                                               case 3:
+                                                       instruction->info.ra =
+                                                               nds32_extract_field_8u(opcode, 0, 4) * 2;
+                                                       instruction->info.rt =
+                                                               nds32_extract_field_8u(opcode, 4, 4) * 2;
+                                                       instruction->type = NDS32_INSN_MISC;
+                                                       snprintf(instruction->text,
+                                                                       128,
+                                                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32
+                                                                       "\t\tMOVD44\t$r%d,$r%d",
+                                                                       address,
+                                                                       opcode, instruction->info.rt, instruction->info.ra);
+                                                       break;
+                                       }
+                                       break;
+                               case 3: /* NEG33, NOT33, MUL33, XOR33, AND33, OR33 */
+                                       instruction->info.ra = nds32_extract_field_8u(opcode, 3, 3);
+                                       instruction->info.rt = nds32_extract_field_8u(opcode, 6, 3);
+                                       instruction->type = NDS32_INSN_DATA_PROC;
+                                       switch (opcode & 0x7) {
+                                               case 2: /* NEG33 */
+                                                       snprintf(instruction->text,
+                                                                       128,
+                                                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32
+                                                                       "\t\tNEG33\t$r%d,$r%d",
+                                                                       address,
+                                                                       opcode, instruction->info.rt, instruction->info.ra);
+                                                       break;
+                                               case 3: /* NOT33 */
+                                                       snprintf(instruction->text,
+                                                                       128,
+                                                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32
+                                                                       "\t\tNOT33\t$r%d,$r%d",
+                                                                       address,
+                                                                       opcode, instruction->info.rt, instruction->info.ra);
+                                                       break;
+                                               case 4: /* MUL33 */
+                                                       snprintf(instruction->text,
+                                                                       128,
+                                                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32
+                                                                       "\t\tMUL33\t$r%d,$r%d",
+                                                                       address,
+                                                                       opcode, instruction->info.rt, instruction->info.ra);
+                                                       break;
+                                               case 5: /* XOR33 */
+                                                       snprintf(instruction->text,
+                                                                       128,
+                                                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32
+                                                                       "\t\tXOR33\t$r%d,$r%d",
+                                                                       address,
+                                                                       opcode, instruction->info.rt, instruction->info.ra);
+                                                       break;
+                                               case 6: /* AND33 */
+                                                       snprintf(instruction->text,
+                                                                       128,
+                                                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32
+                                                                       "\t\tAND33\t$r%d,$r%d",
+                                                                       address,
+                                                                       opcode, instruction->info.rt, instruction->info.ra);
+                                                       break;
+                                               case 7: /* OR33 */
+                                                       snprintf(instruction->text,
+                                                                       128,
+                                                                       "0x%8.8" PRIx32 "\t0x%4.4" PRIx32
+                                                                       "\t\tOR33\t$r%d,$r%d",
+                                                                       address,
+                                                                       opcode, instruction->info.rt, instruction->info.ra);
+                                                       break;
+                                       }
+                                       break;
+                       }
+                       break;
+               default:
+                       snprintf(instruction->text,
+                                       128,
+                                       "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION",
+                                       address,
+                                       opcode);
+                       return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+int nds32_evaluate_opcode(struct nds32 *nds32, uint32_t opcode, uint32_t address,
+               struct nds32_instruction *instruction)
+{
+       int retval = ERROR_OK;
+
+       /* clear fields, to avoid confusion */
+       memset(instruction, 0, sizeof(struct nds32_instruction));
+
+       if (opcode >> 31) {
+               /* 16 bits instruction */
+               instruction->instruction_size = 2;
+               opcode = (opcode >> 16) & 0xFFFF;
+               instruction->opcode = opcode;
+
+               switch ((opcode >> 13) & 0x3) {
+                       case 0:
+                               retval = nds32_parse_group_0_insn_16(nds32, opcode, address, instruction);
+                               break;
+                       case 1:
+                               retval = nds32_parse_group_1_insn_16(nds32, opcode, address, instruction);
+                               break;
+                       case 2:
+                               retval = nds32_parse_group_2_insn_16(nds32, opcode, address, instruction);
+                               break;
+                       case 3:
+                               retval = nds32_parse_group_3_insn_16(nds32, opcode, address, instruction);
+                               break;
+                       default:
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION",
+                                               address,
+                                               opcode);
+                               return ERROR_FAIL;
+               }
+       } else {
+               /* 32 bits instruction */
+               instruction->instruction_size = 4;
+               instruction->opcode = opcode;
+
+               uint8_t opc_6;
+               opc_6 = opcode >> 25;
+               instruction->info.opc_6 = opc_6;
+
+               switch ((opc_6 >> 3) & 0x7) {
+                       case 0: /* LBI, LHI, LWI, LBI.bi, LHI.bi, LWI.bi */
+                               retval = nds32_parse_group_0_insn(nds32, opcode, address, instruction);
+                               break;
+                       case 1: /* SBI, SHI, SWI, SBI.bi, SHI.bi, SWI.bi */
+                               retval = nds32_parse_group_1_insn(nds32, opcode, address, instruction);
+                               break;
+                       case 2: /* LBSI, LHSI, DPREFI, LBSI.bi, LHSI.bi, LBGP */
+                               retval = nds32_parse_group_2_insn(nds32, opcode, address, instruction);
+                               break;
+                       case 3: /* MEM, LSMW, HWGP, SBGP */
+                               retval = nds32_parse_group_3_insn(nds32, opcode, address, instruction);
+                               break;
+                       case 4: /* ALU_1, ALU_2, MOVI, SETHI, JI, JREG, BR1, BR2 */
+                               retval = nds32_parse_group_4_insn(nds32, opcode, address, instruction);
+                               break;
+                       case 5: /* ADDI, SUBRI, ANDI, XORI, ORI, SLTI, SLTSI */
+                               retval = nds32_parse_group_5_insn(nds32, opcode, address, instruction);
+                               break;
+                       case 6: /* MISC */
+                               retval = nds32_parse_group_6_insn(nds32, opcode, address, instruction);
+                               break;
+                       default: /* ERROR */
+                               snprintf(instruction->text,
+                                               128,
+                                               "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION",
+                                               address,
+                                               opcode);
+                               return ERROR_FAIL;
+               }
+       }
+
+       return retval;
+}
diff --git a/src/target/nds32_disassembler.h b/src/target/nds32_disassembler.h
new file mode 100644 (file)
index 0000000..ac0222e
--- /dev/null
@@ -0,0 +1,58 @@
+/***************************************************************************
+ *   Copyright (C) 2013 Andes Technology                                   *
+ *   Hsiangkai Wang <hkwang@andestech.com>                                 *
+ *                                                                         *
+ *   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                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ ***************************************************************************/
+
+#ifndef __NDS32_DISASSEMBLER_H__
+#define __NDS32_DISASSEMBLER_H__
+
+#include <target/nds32.h>
+
+enum nds32_instruction_type {
+       NDS32_INSN_DATA_PROC = 0,
+       NDS32_INSN_LOAD_STORE,
+       NDS32_INSN_JUMP_BRANCH,
+       NDS32_INSN_RESOURCE_ACCESS,
+       NDS32_INSN_MISC,
+};
+
+struct nds32_instruction {
+       enum nds32_instruction_type type;
+       char text[128];
+       uint32_t opcode;
+       uint8_t instruction_size;
+       uint32_t access_start;
+       uint32_t access_end;
+
+       struct {
+               uint8_t opc_6;
+               uint8_t rt;
+               uint8_t ra;
+               uint8_t rb;
+               uint8_t rd;
+               uint8_t sub_opc;
+               int32_t imm;
+       } info;
+
+};
+
+int nds32_read_opcode(struct nds32 *nds32, uint32_t address, uint32_t *value);
+int nds32_evaluate_opcode(struct nds32 *nds32, uint32_t opcode, uint32_t address,
+               struct nds32_instruction *instruction);
+
+#endif /* __NDS32_DISASSEMBLER_H__ */
index 3682b38991bb802d96c3d6750494309442d74e95..1eab7b007a22aba3f778783d191c01988c2914b4 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2013 by Andes Technology                                *
+ *   Copyright (C) 2013 Andes Technology                                   *
  *   Hsiangkai Wang <hkwang@andestech.com>                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
index ca0e4dd4f9e364c8a578496555c72237d6b90436..08d3c5ca911efcef4f1835fbdb410452a903bce6 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2013 by Andes Technology                                *
+ *   Copyright (C) 2013 Andes Technology                                   *
  *   Hsiangkai Wang <hkwang@andestech.com>                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
 #define __NDS32_INSN_H__
 
 
-#define NOP                            (0x40000009)
-#define DSB                            (0x64000008)
-#define ISB                            (0x64000009)
+#define NOP                                            (0x40000009)
+#define DSB                                            (0x64000008)
+#define ISB                                            (0x64000009)
 #define BEQ_MINUS_12                   (0x4C000000 | 0x3FFA)
-#define MTSR_DTR(a)                    (0x64000003 | (((0x03 << 7) | (0x08 << 3) | (0x00 << 0)) << 10) | (((a) & 0x1F) << 20))
-#define MFSR_DTR(a)                    (0x64000002 | (((0x03 << 7) | (0x08 << 3) | (0x00 << 0)) << 10) | (((a) & 0x1F) << 20))
-#define SETHI(a, b)                    (0x46000000 | ((a) << 20) | (b))
+#define MTSR_DTR(a)                            (0x64000003 | (((0x03 << 7) | (0x08 << 3) | (0x00 << 0)) << 10) | (((a) & 0x1F) << 20))
+#define MFSR_DTR(a)                            (0x64000002 | (((0x03 << 7) | (0x08 << 3) | (0x00 << 0)) << 10) | (((a) & 0x1F) << 20))
+#define SETHI(a, b)                            (0x46000000 | ((a) << 20) | (b))
 #define ORI(a, b, c)                   (0x58000000 | ((a) << 20) | ((b) << 15) | (c))
 #define LWI_BI(a, b)                   (0x0C000001 | (a << 20) | (b << 15))
 #define LHI_BI(a, b)                   (0x0A000001 | (a << 20) | (b << 15))
@@ -35,7 +35,7 @@
 #define SWI_BI(a, b)                   (0x1C000001 | (a << 20) | (b << 15))
 #define SHI_BI(a, b)                   (0x1A000001 | (a << 20) | (b << 15))
 #define SBI_BI(a, b)                   (0x18000001 | (a << 20) | (b << 15))
-#define IRET                           (0x64000004)
+#define IRET                                   (0x64000004)
 #define L1D_IX_WB(a)                   (0x64000021 | ((a) << 15))
 #define L1D_IX_INVAL(a)                        (0x64000001 | ((a) << 15))
 #define L1D_VA_INVAL(a)                        (0x64000101 | ((a) << 15))
 #define L1I_IX_RTAG(a)                 (0x64000261 | ((a) << 15))
 #define L1I_IX_RWD(a)                  (0x64000281 | ((a) << 15))
 #define L1I_VA_FILLCK(a)               (0x64000361 | ((a) << 15))
-#define ISYNC(a)                       (0x6400000d | ((a) << 20))
-#define MSYNC_STORE                    (0x6400002c)
-#define MSYNC_ALL                      (0x6400000c)
-#define TLBOP_TARGET_READ(a)           (0x6400000e | ((a) << 15))
-#define TLBOP_TARGET_PROBE(a, b)               (0x640000AE | ((a) << 20) | ((b) << 15))
+#define ISYNC(a)                               (0x6400000d | ((a) << 20))
+#define MSYNC_STORE                            (0x6400002c)
+#define MSYNC_ALL                              (0x6400000c)
+#define TLBOP_TARGET_READ(a)   (0x6400000e | ((a) << 15))
+#define TLBOP_TARGET_PROBE(a, b)       (0x640000AE | ((a) << 20) | ((b) << 15))
 #define MFCPD(a, b, c)                 (0x6A000041 | (a << 20) | (b << 8) | (c << 4))
 #define MFCPW(a, b, c)                 (0x6A000001 | (a << 20) | (b << 8) | (c << 4))
 #define MTCPD(a, b, c)                 (0x6A000049 | (a << 20) | (b << 8) | (c << 4))
 #define MTCPW(a, b, c)                 (0x6A000009 | (a << 20) | (b << 8) | (c << 4))
-#define MOVI_(a, b)                    (0x44000000 | (a << 20) | (b & 0xFFFFF))
+#define MOVI_(a, b)                            (0x44000000 | (a << 20) | (b & 0xFFFFF))
 #define MFUSR_G0(a, b)                 (0x42000020 | (a << 20) | (b << 15))
 #define MTUSR_G0(a, b)                 (0x42000021 | (a << 20) | (b << 15))
-#define MFSR(a, b)                     (0x64000002 | (b << 10) | (a << 20))
-#define MTSR(a, b)                     (0x64000003 | (b << 10) | (a << 20))
-#define AMFAR(a, b)                    (0x60300060 | (a << 15) | b)
-#define AMTAR(a, b)                    (0x60300040 | (a << 15) | b)
+#define MFSR(a, b)                             (0x64000002 | (b << 10) | (a << 20))
+#define MTSR(a, b)                             (0x64000003 | (b << 10) | (a << 20))
+#define AMFAR(a, b)                            (0x60300060 | (a << 15) | b)
+#define AMTAR(a, b)                            (0x60300040 | (a << 15) | b)
 #define AMFAR2(a, b)                   (0x60300260 | (a << 15) | b)
 #define AMTAR2(a, b)                   (0x60300240 | (a << 15) | b)
-#define FMFCSR                         (0x6A000701)
-#define FMTCSR                         (0x6A000709)
-#define FMFCFG                         (0x6A000301)
-#define FMFSR(a, b)                    (0x6A000001 | ((a) << 20) | ((b) << 15))
-#define FMTSR(a, b)                    (0x6A000009 | ((a) << 20) | ((b) << 15))
-#define FMFDR(a, b)                    (0x6A000041 | ((a) << 20) | ((b) << 15))
-#define FMTDR(a, b)                    (0x6A000049 | ((a) << 20) | ((b) << 15))
+#define FMFCSR                                 (0x6A000701)
+#define FMTCSR                                 (0x6A000709)
+#define FMFCFG                                 (0x6A000301)
+#define FMFSR(a, b)                            (0x6A000001 | ((a) << 20) | ((b) << 15))
+#define FMTSR(a, b)                            (0x6A000009 | ((a) << 20) | ((b) << 15))
+#define FMFDR(a, b)                            (0x6A000041 | ((a) << 20) | ((b) << 15))
+#define FMTDR(a, b)                            (0x6A000049 | ((a) << 20) | ((b) << 15))
 
 /* break instructions */
 extern const int NDS32_BREAK_16;
index a55df79fbc2ff5a19decf8949b4a02fdf40ce872..72ac4798ca2864ab25df20208bbae20134dd833e 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2013 by Andes Technology                                *
+ *   Copyright (C) 2013 Andes Technology                                   *
  *   Hsiangkai Wang <hkwang@andestech.com>                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
 #include "config.h"
 #endif
 
+#include <helper/log.h>
 #include "nds32_reg.h"
 
 static bool nds32_reg_init_done;
 static struct nds32_reg_s nds32_regs[TOTAL_REG_NUM];
+static struct nds32_reg_exception_s nds32_ex_reg_values[] = {
+       {IR0, 3, 0x3, 2},
+       {IR0, 3, 0x3, 3},
+       {IR1, 3, 0x3, 2},
+       {IR1, 3, 0x3, 3},
+       {IR2, 3, 0x3, 2},
+       {IR2, 3, 0x3, 3},
+       {MR3, 1, 0x7, 0},
+       {MR3, 1, 0x7, 4},
+       {MR3, 1, 0x7, 6},
+       {MR3, 8, 0x7, 3},
+       {0, 0, 0, 0},
+};
 
 static inline void nds32_reg_set(uint32_t number, const char *simple_mnemonic,
-                                       const char *symbolic_mnemonic, uint32_t sr_index,
-                                       enum nds32_reg_type_s type, uint8_t size)
+               const char *symbolic_mnemonic, uint32_t sr_index,
+               enum nds32_reg_type_s type, uint8_t size)
 {
        nds32_regs[number].simple_mnemonic = simple_mnemonic;
        nds32_regs[number].symbolic_mnemonic = symbolic_mnemonic;
@@ -117,6 +131,11 @@ void nds32_reg_init(void)
        nds32_reg_set(IR23, "ir23", "", SRIDX(1, 10, 5), NDS32_REG_TYPE_IR, 32);
        nds32_reg_set(IR24, "ir24", "", SRIDX(1, 10, 6), NDS32_REG_TYPE_IR, 32);
        nds32_reg_set(IR25, "ir25", "", SRIDX(1, 10, 7), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR26, "ir26", "", SRIDX(1, 8, 1), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR27, "ir27", "", SRIDX(1, 9, 1), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR28, "ir28", "", SRIDX(1, 11, 1), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR29, "ir29", "", SRIDX(1, 9, 4), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR30, "ir30", "", SRIDX(1, 1, 3), NDS32_REG_TYPE_IR, 32);
 
        nds32_reg_set(MR0, "mr0", "MMU_CTL", SRIDX(2, 0, 0), NDS32_REG_TYPE_MR, 32);
        nds32_reg_set(MR1, "mr1", "L1_PPTB", SRIDX(2, 1, 0), NDS32_REG_TYPE_MR, 32);
@@ -335,3 +354,29 @@ const char *nds32_reg_symbolic_name(uint32_t number)
 {
        return nds32_regs[number].symbolic_mnemonic;
 }
+
+bool nds32_reg_exception(uint32_t number, uint32_t value)
+{
+       int i;
+       struct nds32_reg_exception_s *ex_reg_value;
+       uint32_t field_value;
+
+       i = 0;
+       while (nds32_ex_reg_values[i].reg_num != 0) {
+               ex_reg_value = nds32_ex_reg_values + i;
+
+               if (ex_reg_value->reg_num == number) {
+                       field_value = (value >> ex_reg_value->ex_value_bit_pos) &
+                               ex_reg_value->ex_value_mask;
+                       if (field_value == ex_reg_value->ex_value) {
+                               LOG_WARNING("It will generate exceptions as setting %d to %s",
+                                               value, nds32_regs[number].simple_mnemonic);
+                               return true;
+                       }
+               }
+
+               i++;
+       }
+
+       return false;
+}
index a94194143e077594b6ac086d68db6bc45389e8d7..1c61b6164bfdcb82cc88d6c767296bb5e6747022 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2013 by Andes Technology                                *
+ *   Copyright (C) 2013 Andes Technology                                   *
  *   Hsiangkai Wang <hkwang@andestech.com>                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
@@ -24,8 +24,7 @@
 #define NDS32_REGISTER_DISABLE         (0x0)
 
 enum nds32_reg_number_s {
-       /* general registers */
-       R0 = 0,
+       R0 = 0, /* general registers */
        R1,
        R2,
        R3,
@@ -64,9 +63,7 @@ enum nds32_reg_number_s {
        D1HI,
        ITB,
        IFC_LP,
-
-       /* system registers */
-       CR0,
+       CR0, /* system registers */
        CR1,
        CR2,
        CR3,
@@ -99,6 +96,11 @@ enum nds32_reg_number_s {
        IR23,
        IR24,
        IR25,
+       IR26,
+       IR27,
+       IR28,
+       IR29,
+       IR30,
        MR0,
        MR1,
        MR2,
@@ -180,9 +182,7 @@ enum nds32_reg_number_s {
        IDR0,
        IDR1,
        SECUR0,
-
-       /* audio registers */
-       D0L24,
+       D0L24, /* audio registers */
        D1L24,
        I0,
        I1,
@@ -214,9 +214,7 @@ enum nds32_reg_number_s {
        CBE1,
        CBE2,
        CBE3,
-
-       /* fpu */
-       FPCSR,
+       FPCSR, /* fpu */
        FPCFG,
        FS0,
        FS1,
@@ -310,11 +308,19 @@ struct nds32_reg_s {
        uint8_t size;
 };
 
+struct nds32_reg_exception_s {
+       uint32_t reg_num;
+       uint32_t ex_value_bit_pos;
+       uint32_t ex_value_mask;
+       uint32_t ex_value;
+};
+
 void nds32_reg_init(void);
 uint32_t nds32_reg_sr_index(uint32_t number);
 enum nds32_reg_type_s nds32_reg_type(uint32_t number);
 uint8_t nds32_reg_size(uint32_t number);
 const char *nds32_reg_simple_name(uint32_t number);
 const char *nds32_reg_symbolic_name(uint32_t number);
+bool nds32_reg_exception(uint32_t number, uint32_t value);
 
 #endif
diff --git a/src/target/nds32_tlb.c b/src/target/nds32_tlb.c
new file mode 100644 (file)
index 0000000..58322cf
--- /dev/null
@@ -0,0 +1,80 @@
+/***************************************************************************
+ *   Copyright (C) 2013 Andes Technology                                   *
+ *   Hsiangkai Wang <hkwang@andestech.com>                                 *
+ *                                                                         *
+ *   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                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ ***************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "nds32_aice.h"
+#include "nds32_tlb.h"
+
+int nds32_probe_tlb(struct nds32 *nds32, const uint32_t virtual_address,
+               uint32_t *physical_address)
+{
+       struct target *target = nds32->target;
+       struct aice_port_s *aice = target_to_aice(target);
+
+       return aice_read_tlb(aice, virtual_address, physical_address);
+}
+
+struct page_table_walker_info_s page_table_info[PAGE_SIZE_NUM] = {
+       /* 4K page */
+       {0xFFC00000, 20, 0x003FF000, 10, 0x00000FFF, 0xFFFFF000, 0xFFFFF000, 0xFFFFF000},
+       /* 8K page */
+       {0xFF000000, 22, 0x00FFE000, 11, 0x00001FFF, 0xFFFFF000, 0xFFFFE000, 0xFFFFE000},
+};
+
+int nds32_walk_page_table(struct nds32 *nds32, const uint32_t virtual_address,
+               uint32_t *physical_address)
+{
+       struct target *target = nds32->target;
+       uint32_t value_mr1;
+       uint32_t load_address;
+       uint32_t L1_page_table_entry;
+       uint32_t L2_page_table_entry;
+       uint32_t page_size_index = nds32->mmu_config.default_min_page_size;
+       struct page_table_walker_info_s *page_table_info_p =
+               &(page_table_info[page_size_index]);
+
+       /* Read L1 Physical Page Table */
+       nds32_get_mapped_reg(nds32, MR1, &value_mr1);
+       load_address = (value_mr1 & page_table_info_p->L1_base_mask) |
+               ((virtual_address & page_table_info_p->L1_offset_mask) >>
+                page_table_info_p->L1_offset_shift);
+       /* load_address is physical address */
+       nds32_read_buffer(target, load_address, 4, (uint8_t *)&L1_page_table_entry);
+
+       /* Read L2 Physical Page Table */
+       if (L1_page_table_entry & 0x1) /* L1_PTE not present */
+               return ERROR_FAIL;
+
+       load_address = (L1_page_table_entry & page_table_info_p->L2_base_mask) |
+               ((virtual_address & page_table_info_p->L2_offset_mask) >>
+                page_table_info_p->L2_offset_shift);
+       /* load_address is physical address */
+       nds32_read_buffer(target, load_address, 4, (uint8_t *)&L2_page_table_entry);
+
+       if ((L2_page_table_entry & 0x1) != 0x1) /* L2_PTE not valid */
+               return ERROR_FAIL;
+
+       *physical_address = (L2_page_table_entry & page_table_info_p->ppn_mask) |
+               (virtual_address & page_table_info_p->va_offset_mask);
+
+       return ERROR_OK;
+}
diff --git a/src/target/nds32_tlb.h b/src/target/nds32_tlb.h
new file mode 100644 (file)
index 0000000..59e1157
--- /dev/null
@@ -0,0 +1,48 @@
+/***************************************************************************
+ *   Copyright (C) 2013 Andes Technology                                   *
+ *   Hsiangkai Wang <hkwang@andestech.com>                                 *
+ *                                                                         *
+ *   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                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ ***************************************************************************/
+#ifndef __NDS32_TLB_H__
+#define __NDS32_TLB_H__
+
+#include "nds32.h"
+
+enum {
+       PAGE_SIZE_4K = 0,
+       PAGE_SIZE_8K,
+       PAGE_SIZE_NUM,
+};
+
+struct page_table_walker_info_s {
+
+       uint32_t L1_offset_mask;
+       uint32_t L1_offset_shift;
+       uint32_t L2_offset_mask;
+       uint32_t L2_offset_shift;
+       uint32_t va_offset_mask;
+       uint32_t L1_base_mask;
+       uint32_t L2_base_mask;
+       uint32_t ppn_mask;
+};
+
+extern int nds32_probe_tlb(struct nds32 *nds32, const uint32_t virtual_address,
+               uint32_t *physical_address);
+extern int nds32_walk_page_table(struct nds32 *nds32, const uint32_t virtual_address,
+               uint32_t *physical_address);
+
+#endif
diff --git a/src/target/nds32_v2.c b/src/target/nds32_v2.c
new file mode 100644 (file)
index 0000000..90961d7
--- /dev/null
@@ -0,0 +1,763 @@
+/***************************************************************************
+ *   Copyright (C) 2013 Andes Technology                                   *
+ *   Hsiangkai Wang <hkwang@andestech.com>                                 *
+ *                                                                         *
+ *   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                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <helper/time_support.h>
+#include <helper/binarybuffer.h>
+#include "breakpoints.h"
+#include "nds32_insn.h"
+#include "nds32_reg.h"
+#include "nds32_edm.h"
+#include "nds32_cmd.h"
+#include "nds32_v2.h"
+#include "nds32_aice.h"
+#include "target_type.h"
+
+static int nds32_v2_register_mapping(struct nds32 *nds32, int reg_no)
+{
+       uint32_t max_level = nds32->max_interrupt_level;
+       uint32_t cur_level = nds32->current_interrupt_level;
+
+       if ((1 <= cur_level) && (cur_level < max_level)) {
+               if (IR0 == reg_no) {
+                       LOG_DEBUG("Map PSW to IPSW");
+                       return IR1;
+               } else if (PC == reg_no) {
+                       LOG_DEBUG("Map PC to IPC");
+                       return IR9;
+               }
+       } else if ((2 <= cur_level) && (cur_level < max_level)) {
+               if (R26 == reg_no) {
+                       LOG_DEBUG("Mapping P0 to P_P0");
+                       return IR12;
+               } else if (R27 == reg_no) {
+                       LOG_DEBUG("Mapping P1 to P_P1");
+                       return IR13;
+               } else if (IR1 == reg_no) {
+                       LOG_DEBUG("Mapping IPSW to P_IPSW");
+                       return IR2;
+               } else if (IR4 == reg_no) {
+                       LOG_DEBUG("Mapping EVA to P_EVA");
+                       return IR5;
+               } else if (IR6 == reg_no) {
+                       LOG_DEBUG("Mapping ITYPE to P_ITYPE");
+                       return IR7;
+               } else if (IR9 == reg_no) {
+                       LOG_DEBUG("Mapping IPC to P_IPC");
+                       return IR10;
+               }
+       } else if (cur_level == max_level) {
+               if (PC == reg_no) {
+                       LOG_DEBUG("Mapping PC to O_IPC");
+                       return IR11;
+               }
+       }
+
+       return reg_no;
+}
+
+static int nds32_v2_get_debug_reason(struct nds32 *nds32, uint32_t *reason)
+{
+       uint32_t val_itype;
+       struct aice_port_s *aice = target_to_aice(nds32->target);
+
+       aice_read_register(aice, IR6, &val_itype);
+
+       *reason = val_itype & 0x0F;
+
+       return ERROR_OK;
+}
+
+static int nds32_v2_activate_hardware_breakpoint(struct target *target)
+{
+       struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target);
+       struct aice_port_s *aice = target_to_aice(target);
+       struct breakpoint *bp;
+       int32_t hbr_index = 0;
+
+       for (bp = target->breakpoints; bp; bp = bp->next) {
+               if (bp->type == BKPT_SOFT) {
+                       /* already set at nds32_v2_add_breakpoint() */
+                       continue;
+               } else if (bp->type == BKPT_HARD) {
+                       /* set address */
+                       aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + hbr_index, bp->address);
+                       /* set mask */
+                       aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + hbr_index, 0);
+                       /* set value */
+                       aice_write_debug_reg(aice, NDS_EDM_SR_BPV0 + hbr_index, 0);
+
+                       if (nds32_v2->nds32.memory.address_translation)
+                               /* enable breakpoint (virtual address) */
+                               aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0x2);
+                       else
+                               /* enable breakpoint (physical address) */
+                               aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0xA);
+
+                       LOG_DEBUG("Add hardware BP %d at %08" PRIx32, hbr_index,
+                                       bp->address);
+
+                       hbr_index++;
+               } else {
+                       return ERROR_FAIL;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_v2_deactivate_hardware_breakpoint(struct target *target)
+{
+       struct aice_port_s *aice = target_to_aice(target);
+       struct breakpoint *bp;
+       int32_t hbr_index = 0;
+
+       for (bp = target->breakpoints; bp; bp = bp->next) {
+               if (bp->type == BKPT_SOFT)
+                       continue;
+               else if (bp->type == BKPT_HARD)
+                       /* disable breakpoint */
+                       aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0x0);
+               else
+                       return ERROR_FAIL;
+
+               LOG_DEBUG("Remove hardware BP %d at %08" PRIx32, hbr_index,
+                               bp->address);
+
+               hbr_index++;
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_v2_activate_hardware_watchpoint(struct target *target)
+{
+       struct aice_port_s *aice = target_to_aice(target);
+       struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target);
+       struct watchpoint *wp;
+       int32_t wp_num = nds32_v2->next_hbr_index;
+       uint32_t wp_config = 0;
+
+       for (wp = target->watchpoints; wp; wp = wp->next) {
+
+               wp_num--;
+               wp->mask = wp->length - 1;
+               if ((wp->address % wp->length) != 0)
+                       wp->mask = (wp->mask << 1) + 1;
+
+               if (wp->rw == WPT_READ)
+                       wp_config = 0x3;
+               else if (wp->rw == WPT_WRITE)
+                       wp_config = 0x5;
+               else if (wp->rw == WPT_ACCESS)
+                       wp_config = 0x7;
+
+               /* set/unset physical address bit of BPCn according to PSW.DT */
+               if (nds32_v2->nds32.memory.address_translation == false)
+                       wp_config |= 0x8;
+
+               /* set address */
+               aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + wp_num,
+                               wp->address - (wp->address % wp->length));
+               /* set mask */
+               aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + wp_num, wp->mask);
+               /* enable watchpoint */
+               aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, wp_config);
+               /* set value */
+               aice_write_debug_reg(aice, NDS_EDM_SR_BPV0 + wp_num, 0);
+
+               LOG_DEBUG("Add hardware wathcpoint %d at %08" PRIx32 " mask %08" PRIx32, wp_num,
+                               wp->address, wp->mask);
+
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_v2_deactivate_hardware_watchpoint(struct target *target)
+{
+       struct aice_port_s *aice = target_to_aice(target);
+       struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target);
+       int32_t wp_num = nds32_v2->next_hbr_index;
+       struct watchpoint *wp;
+
+       for (wp = target->watchpoints; wp; wp = wp->next) {
+               wp_num--;
+               /* disable watchpoint */
+               aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, 0x0);
+
+               LOG_DEBUG("Remove hardware wathcpoint %d at %08" PRIx32 " mask %08" PRIx32,
+                               wp_num, wp->address, wp->mask);
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_v2_check_interrupt_stack(struct nds32_v2_common *nds32_v2)
+{
+       struct nds32 *nds32 = &(nds32_v2->nds32);
+       struct aice_port_s *aice = target_to_aice(nds32->target);
+       uint32_t val_ir0;
+       uint32_t val_ir1;
+       uint32_t val_ir2;
+       uint32_t modified_psw;
+
+       /* Save interrupt level */
+       aice_read_register(aice, IR0, &val_ir0); /* get $IR0 directly */
+
+       /* backup $IR0 */
+       nds32_v2->backup_ir0 = val_ir0;
+
+       nds32->current_interrupt_level = (val_ir0 >> 1) & 0x3;
+
+       if (nds32_reach_max_interrupt_level(nds32)) {
+               LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level %d. -->",
+                               nds32->current_interrupt_level);
+
+               /* decrease interrupt level */
+               modified_psw = val_ir0 - 0x2;
+
+               /* disable GIE, IT, DT, HSS */
+               modified_psw &= (~0x8C1);
+
+               aice_write_register(aice, IR0, modified_psw);
+
+               return ERROR_OK;
+       }
+
+
+       /* There is a case that single step also trigger another interrupt,
+          then HSS bit in psw(ir0) will push to ipsw(ir1).
+          Then hit debug interrupt HSS bit in ipsw(ir1) will push to (p_ipsw)ir2
+          Therefore, HSS bit in p_ipsw(ir2) also need clear.
+
+          Only update $ir2 as current interrupt level is 2, because $ir2 will be random
+          value if the target never reaches interrupt level 2. */
+       if ((nds32->max_interrupt_level == 3) && (nds32->current_interrupt_level == 2)) {
+               aice_read_register(aice, IR2, &val_ir2); /* get $IR2 directly */
+               val_ir2 &= ~(0x01 << 11);
+               aice_write_register(aice, IR2, val_ir2);
+       }
+
+       /* get origianl DT bit and set to current state let debugger has same memory view
+          PSW.IT MUST be turned off.  Otherwise, DIM could not operate normally. */
+       aice_read_register(aice, IR1, &val_ir1);
+       modified_psw = val_ir0 | (val_ir1 & 0x80);
+       aice_write_register(aice, IR0, modified_psw);
+
+       return ERROR_OK;
+}
+
+static int nds32_v2_restore_interrupt_stack(struct nds32_v2_common *nds32_v2)
+{
+       struct nds32 *nds32 = &(nds32_v2->nds32);
+       struct aice_port_s *aice = target_to_aice(nds32->target);
+
+       /* restore origin $IR0 */
+       aice_write_register(aice, IR0, nds32_v2->backup_ir0);
+
+       return ERROR_OK;
+}
+
+/**
+ * Save processor state.  This is called after a HALT instruction
+ * succeeds, and on other occasions the processor enters debug mode
+ * (breakpoint, watchpoint, etc).
+ */
+static int nds32_v2_debug_entry(struct nds32 *nds32, bool enable_watchpoint)
+{
+       LOG_DEBUG("nds32_v2_debug_entry");
+
+       jtag_poll_set_enabled(false);
+
+       if (nds32->virtual_hosting)
+               LOG_WARNING("<-- TARGET WARNING! Virtual hosting is not supported "
+                               "under V1/V2 architecture. -->");
+
+       struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(nds32->target);
+
+       CHECK_RETVAL(nds32_v2_deactivate_hardware_breakpoint(nds32->target));
+
+       if (enable_watchpoint)
+               CHECK_RETVAL(nds32_v2_deactivate_hardware_watchpoint(nds32->target));
+
+       nds32->target->state = TARGET_HALTED;
+       nds32_examine_debug_reason(nds32);
+
+       if (nds32->init_arch_info_after_halted == false) {
+               /* init architecture info according to config registers */
+               CHECK_RETVAL(nds32_config(nds32));
+
+               nds32->init_arch_info_after_halted = true;
+       }
+
+       /* REVISIT entire cache should already be invalid !!! */
+       register_cache_invalidate(nds32->core_cache);
+
+       /* check interrupt level before .full_context(), because
+        * get_mapped_reg needs current_interrupt_level information */
+       nds32_v2_check_interrupt_stack(nds32_v2);
+
+       /* Save registers. */
+       nds32_full_context(nds32);
+
+       return ERROR_OK;
+}
+
+/* target request support */
+static int nds32_v2_target_request_data(struct target *target,
+               uint32_t size, uint8_t *buffer)
+{
+       /* AndesCore could use DTR register to communicate with OpenOCD
+        * to output messages
+        * Target data will be put in buffer
+        * The format of DTR is as follow
+        * DTR[31:16] => length, DTR[15:8] => size, DTR[7:0] => target_req_cmd
+        * target_req_cmd has three possible values:
+        *   TARGET_REQ_TRACEMSG
+        *   TARGET_REQ_DEBUGMSG
+        *   TARGET_REQ_DEBUGCHAR
+        * if size == 0, target will call target_asciimsg(),
+        * else call target_hexmsg()
+        */
+       LOG_WARNING("Not implemented: %s", __func__);
+
+       return ERROR_OK;
+}
+
+/**
+ * Restore processor state.
+ */
+static int nds32_v2_leave_debug_state(struct nds32 *nds32, bool enable_watchpoint)
+{
+       struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(nds32->target);
+
+       /* activate all hardware breakpoints */
+       CHECK_RETVAL(nds32_v2_activate_hardware_breakpoint(nds32->target));
+
+       if (enable_watchpoint) {
+               /* activate all watchpoints */
+               CHECK_RETVAL(nds32_v2_activate_hardware_watchpoint(nds32->target));
+       }
+
+       /* restore interrupt stack */
+       nds32_v2_restore_interrupt_stack(nds32_v2);
+
+       /* restore PSW, PC, and R0 ... after flushing any modified
+        * registers.
+        */
+       CHECK_RETVAL(nds32_restore_context(nds32->target));
+
+       register_cache_invalidate(nds32->core_cache);
+
+       jtag_poll_set_enabled(true);
+
+       return ERROR_OK;
+}
+
+static int nds32_v2_soft_reset_halt(struct target *target)
+{
+       /* TODO: test it */
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct aice_port_s *aice = target_to_aice(target);
+
+       aice_assert_srst(aice, AICE_SRST);
+
+       /* halt core and set pc to 0x0 */
+       int retval = target_halt(target);
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* start fetching from IVB */
+       uint32_t value_ir3;
+       nds32_get_mapped_reg(nds32, IR3, &value_ir3);
+       nds32_set_mapped_reg(nds32, PC, value_ir3 & 0xFFFF0000);
+
+       return ERROR_OK;
+}
+
+static int nds32_v2_deassert_reset(struct target *target)
+{
+       int retval;
+
+       CHECK_RETVAL(nds32_poll(target));
+
+       if (target->state != TARGET_HALTED) {
+               /* reset only */
+               LOG_WARNING("%s: ran after reset and before halt ...",
+                               target_name(target));
+               retval = target_halt(target);
+               if (retval != ERROR_OK)
+                       return retval;
+               /* call target_poll() to avoid "Halt timed out" */
+               CHECK_RETVAL(target_poll(target));
+       } else {
+               jtag_poll_set_enabled(false);
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_v2_checksum_memory(struct target *target,
+               uint32_t address, uint32_t count, uint32_t *checksum)
+{
+       LOG_WARNING("Not implemented: %s", __func__);
+
+       return ERROR_FAIL;
+}
+
+static int nds32_v2_add_breakpoint(struct target *target,
+               struct breakpoint *breakpoint)
+{
+       struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target);
+       struct nds32 *nds32 = &(nds32_v2->nds32);
+       int result;
+
+       if (breakpoint->type == BKPT_HARD) {
+               /* check hardware resource */
+               if (nds32_v2->n_hbr <= nds32_v2->next_hbr_index) {
+                       LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
+                                       "breakpoints/watchpoints!  The limit of "
+                                       "combined hardware breakpoints/watchpoints "
+                                       "is %d. -->", nds32_v2->n_hbr);
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               }
+
+               /* update next place to put hardware breakpoint */
+               nds32_v2->next_hbr_index++;
+
+               /* hardware breakpoint insertion occurs before 'continue' actually */
+               return ERROR_OK;
+       } else if (breakpoint->type == BKPT_SOFT) {
+               result = nds32_add_software_breakpoint(target, breakpoint);
+               if (ERROR_OK != result) {
+                       /* auto convert to hardware breakpoint if failed */
+                       if (nds32->auto_convert_hw_bp) {
+                               /* convert to hardware breakpoint */
+                               breakpoint->type = BKPT_HARD;
+
+                               return nds32_v2_add_breakpoint(target, breakpoint);
+                       }
+               }
+
+               return result;
+       } else /* unrecognized breakpoint type */
+               return ERROR_FAIL;
+
+       return ERROR_OK;
+}
+
+static int nds32_v2_remove_breakpoint(struct target *target,
+               struct breakpoint *breakpoint)
+{
+       struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target);
+
+       if (breakpoint->type == BKPT_HARD) {
+               if (nds32_v2->next_hbr_index <= 0)
+                       return ERROR_FAIL;
+
+               /* update next place to put hardware breakpoint */
+               nds32_v2->next_hbr_index--;
+
+               /* hardware breakpoint removal occurs after 'halted' actually */
+               return ERROR_OK;
+       } else if (breakpoint->type == BKPT_SOFT) {
+               return nds32_remove_software_breakpoint(target, breakpoint);
+       } else /* unrecognized breakpoint type */
+               return ERROR_FAIL;
+
+       return ERROR_OK;
+}
+
+static int nds32_v2_add_watchpoint(struct target *target,
+               struct watchpoint *watchpoint)
+{
+       struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target);
+
+       /* check hardware resource */
+       if (nds32_v2->n_hbr <= nds32_v2->next_hbr_index) {
+               LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
+                               "breakpoints/watchpoints!  The limit of "
+                               "combined hardware breakpoints/watchpoints is %d. -->", nds32_v2->n_hbr);
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+
+       /* update next place to put hardware watchpoint */
+       nds32_v2->next_hbr_index++;
+
+       return ERROR_OK;
+}
+
+static int nds32_v2_remove_watchpoint(struct target *target,
+               struct watchpoint *watchpoint)
+{
+       struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target);
+
+       if (nds32_v2->next_hbr_index <= 0)
+               return ERROR_FAIL;
+
+       /* update next place to put hardware breakpoint */
+       nds32_v2->next_hbr_index--;
+
+       return ERROR_OK;
+}
+
+static int nds32_v2_get_exception_address(struct nds32 *nds32,
+               uint32_t *address, uint32_t reason)
+{
+       struct aice_port_s *aice = target_to_aice(nds32->target);
+
+       aice_read_register(aice, IR4, address); /* read $EVA directly */
+
+       /* TODO: hit multiple watchpoints */
+
+       return ERROR_OK;
+}
+
+static int nds32_v2_run_algorithm(struct target *target,
+               int num_mem_params,
+               struct mem_param *mem_params,
+               int num_reg_params,
+               struct reg_param *reg_params,
+               uint32_t entry_point,
+               uint32_t exit_point,
+               int timeout_ms,
+               void *arch_info)
+{
+       LOG_WARNING("Not implemented: %s", __func__);
+
+       return ERROR_FAIL;
+}
+
+static int nds32_v2_target_create(struct target *target, Jim_Interp *interp)
+{
+       struct nds32_v2_common *nds32_v2;
+
+       nds32_v2 = calloc(1, sizeof(*nds32_v2));
+       if (!nds32_v2)
+               return ERROR_FAIL;
+
+       nds32_v2->nds32.register_map = nds32_v2_register_mapping;
+       nds32_v2->nds32.get_debug_reason = nds32_v2_get_debug_reason;
+       nds32_v2->nds32.enter_debug_state = nds32_v2_debug_entry;
+       nds32_v2->nds32.leave_debug_state = nds32_v2_leave_debug_state;
+       nds32_v2->nds32.get_watched_address = nds32_v2_get_exception_address;
+
+       nds32_init_arch_info(target, &(nds32_v2->nds32));
+
+       return ERROR_OK;
+}
+
+static int nds32_v2_init_target(struct command_context *cmd_ctx,
+               struct target *target)
+{
+       /* Initialize anything we can set up without talking to the target */
+
+       struct nds32 *nds32 = target_to_nds32(target);
+
+       nds32_init(nds32);
+
+       return ERROR_OK;
+}
+
+/* talk to the target and set things up */
+static int nds32_v2_examine(struct target *target)
+{
+       struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target);
+       struct nds32 *nds32 = &(nds32_v2->nds32);
+       struct aice_port_s *aice = target_to_aice(target);
+
+       if (!target_was_examined(target)) {
+               CHECK_RETVAL(nds32_edm_config(nds32));
+
+               if (nds32->reset_halt_as_examine)
+                       CHECK_RETVAL(nds32_reset_halt(nds32));
+       }
+
+       uint32_t edm_cfg;
+       aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg);
+
+       /* get the number of hardware breakpoints */
+       nds32_v2->n_hbr = (edm_cfg & 0x7) + 1;
+
+       nds32_v2->next_hbr_index = 0;
+
+       LOG_INFO("%s: total hardware breakpoint %d", target_name(target),
+                       nds32_v2->n_hbr);
+
+       nds32->target->state = TARGET_RUNNING;
+       nds32->target->debug_reason = DBG_REASON_NOTHALTED;
+
+       target_set_examined(target);
+
+       return ERROR_OK;
+}
+
+static int nds32_v2_translate_address(struct target *target, uint32_t *address)
+{
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct nds32_memory *memory = &(nds32->memory);
+       uint32_t physical_address;
+
+       /* Following conditions need to do address translation
+        * 1. BUS mode
+        * 2. CPU mode under maximum interrupt level */
+       if ((NDS_MEMORY_ACC_BUS == memory->access_channel) ||
+                       ((NDS_MEMORY_ACC_CPU == memory->access_channel) &&
+                        nds32_reach_max_interrupt_level(nds32))) {
+               if (ERROR_OK == target->type->virt2phys(target, *address, &physical_address))
+                       *address = physical_address;
+               else
+                       return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_v2_read_buffer(struct target *target, uint32_t address,
+               uint32_t size, uint8_t *buffer)
+{
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct nds32_memory *memory = &(nds32->memory);
+
+       if ((NDS_MEMORY_ACC_CPU == memory->access_channel) &&
+                       (target->state != TARGET_HALTED)) {
+               LOG_WARNING("target was not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* BUG: If access range crosses multiple pages, the translation will not correct
+        * for second page or so. */
+
+       nds32_v2_translate_address(target, &address);
+
+       return nds32_read_buffer(target, address, size, buffer);
+}
+
+static int nds32_v2_write_buffer(struct target *target, uint32_t address,
+               uint32_t size, const uint8_t *buffer)
+{
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct nds32_memory *memory = &(nds32->memory);
+
+       if ((NDS_MEMORY_ACC_CPU == memory->access_channel) &&
+                       (target->state != TARGET_HALTED)) {
+               LOG_WARNING("target was not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* BUG: If access range crosses multiple pages, the translation will not correct
+        * for second page or so. */
+
+       nds32_v2_translate_address(target, &address);
+
+       return nds32_write_buffer(target, address, size, buffer);
+}
+
+static int nds32_v2_read_memory(struct target *target, uint32_t address,
+               uint32_t size, uint32_t count, uint8_t *buffer)
+{
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct nds32_memory *memory = &(nds32->memory);
+
+       if ((NDS_MEMORY_ACC_CPU == memory->access_channel) &&
+                       (target->state != TARGET_HALTED)) {
+               LOG_WARNING("target was not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* BUG: If access range crosses multiple pages, the translation will not correct
+        * for second page or so. */
+
+       nds32_v2_translate_address(target, &address);
+
+       return nds32_read_memory(target, address, size, count, buffer);
+}
+
+static int nds32_v2_write_memory(struct target *target, uint32_t address,
+               uint32_t size, uint32_t count, const uint8_t *buffer)
+{
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct nds32_memory *memory = &(nds32->memory);
+
+       if ((NDS_MEMORY_ACC_CPU == memory->access_channel) &&
+                       (target->state != TARGET_HALTED)) {
+               LOG_WARNING("target was not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       /* BUG: If access range crosses multiple pages, the translation will not correct
+        * for second page or so. */
+
+       nds32_v2_translate_address(target, &address);
+
+       return nds32_write_memory(target, address, size, count, buffer);
+}
+
+/** Holds methods for V2 targets. */
+struct target_type nds32_v2_target = {
+       .name = "nds32_v2",
+
+       .poll = nds32_poll,
+       .arch_state = nds32_arch_state,
+
+       .target_request_data = nds32_v2_target_request_data,
+
+       .halt = nds32_halt,
+       .resume = nds32_resume,
+       .step = nds32_step,
+
+       .assert_reset = nds32_assert_reset,
+       .deassert_reset = nds32_v2_deassert_reset,
+       .soft_reset_halt = nds32_v2_soft_reset_halt,
+
+       /* register access */
+       .get_gdb_reg_list = nds32_get_gdb_reg_list,
+
+       /* memory access */
+       .read_buffer = nds32_v2_read_buffer,
+       .write_buffer = nds32_v2_write_buffer,
+       .read_memory = nds32_v2_read_memory,
+       .write_memory = nds32_v2_write_memory,
+
+       .checksum_memory = nds32_v2_checksum_memory,
+
+       /* breakpoint/watchpoint */
+       .add_breakpoint = nds32_v2_add_breakpoint,
+       .remove_breakpoint = nds32_v2_remove_breakpoint,
+       .add_watchpoint = nds32_v2_add_watchpoint,
+       .remove_watchpoint = nds32_v2_remove_watchpoint,
+
+       /* MMU */
+       .mmu = nds32_mmu,
+       .virt2phys = nds32_virtual_to_physical,
+       .read_phys_memory = nds32_read_phys_memory,
+       .write_phys_memory = nds32_write_phys_memory,
+
+       .run_algorithm = nds32_v2_run_algorithm,
+
+       .commands = nds32_command_handlers,
+       .target_create = nds32_v2_target_create,
+       .init_target = nds32_v2_init_target,
+       .examine = nds32_v2_examine,
+};
diff --git a/src/target/nds32_v2.h b/src/target/nds32_v2.h
new file mode 100644 (file)
index 0000000..b398055
--- /dev/null
@@ -0,0 +1,44 @@
+/***************************************************************************
+ *   Copyright (C) 2013 Andes Technology                                   *
+ *   Hsiangkai Wang <hkwang@andestech.com>                                 *
+ *                                                                         *
+ *   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                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ ***************************************************************************/
+#ifndef __NDS32_V2_H__
+#define __NDS32_V2_H__
+
+#include "nds32.h"
+
+struct nds32_v2_common {
+       struct nds32 nds32;
+
+       uint32_t backup_ir0;
+
+       /** number of hardware breakpoints */
+       int32_t n_hbr;
+
+       /** next hardware breakpoint index */
+       /** increase from low index to high index */
+       int32_t next_hbr_index;
+};
+
+static inline struct nds32_v2_common *target_to_nds32_v2(struct target *target)
+{
+       return container_of(target->arch_info, struct nds32_v2_common, nds32);
+}
+
+
+#endif /* __NDS32_V2_H__ */
diff --git a/src/target/nds32_v3.c b/src/target/nds32_v3.c
new file mode 100644 (file)
index 0000000..dc0ca5a
--- /dev/null
@@ -0,0 +1,522 @@
+/***************************************************************************
+ *   Copyright (C) 2013 Andes Technology                                   *
+ *   Hsiangkai Wang <hkwang@andestech.com>                                 *
+ *                                                                         *
+ *   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                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "breakpoints.h"
+#include "nds32_cmd.h"
+#include "nds32_aice.h"
+#include "nds32_v3.h"
+#include "nds32_v3_common.h"
+
+static int nds32_v3_activate_hardware_breakpoint(struct target *target)
+{
+       struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
+       struct aice_port_s *aice = target_to_aice(target);
+       struct breakpoint *bp;
+       int32_t hbr_index = nds32_v3->next_hbr_index;
+
+       for (bp = target->breakpoints; bp; bp = bp->next) {
+               if (bp->type == BKPT_SOFT) {
+                       /* already set at nds32_v3_add_breakpoint() */
+                       continue;
+               } else if (bp->type == BKPT_HARD) {
+                       hbr_index--;
+                       /* set address */
+                       aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + hbr_index, bp->address);
+                       /* set mask */
+                       aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + hbr_index, 0);
+                       /* set value */
+                       aice_write_debug_reg(aice, NDS_EDM_SR_BPV0 + hbr_index, 0);
+
+                       if (nds32_v3->nds32.memory.address_translation)
+                               /* enable breakpoint (virtual address) */
+                               aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0x2);
+                       else
+                               /* enable breakpoint (physical address) */
+                               aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0xA);
+
+                       LOG_DEBUG("Add hardware BP %d at %08" PRIx32, hbr_index,
+                                       bp->address);
+               } else {
+                       return ERROR_FAIL;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_v3_deactivate_hardware_breakpoint(struct target *target)
+{
+       struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
+       struct aice_port_s *aice = target_to_aice(target);
+       struct breakpoint *bp;
+       int32_t hbr_index = nds32_v3->next_hbr_index;
+
+       for (bp = target->breakpoints; bp; bp = bp->next) {
+               if (bp->type == BKPT_SOFT) {
+                       continue;
+               } else if (bp->type == BKPT_HARD) {
+                       hbr_index--;
+                       /* disable breakpoint */
+                       aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0x0);
+               } else {
+                       return ERROR_FAIL;
+               }
+
+               LOG_DEBUG("Remove hardware BP %d at %08" PRIx32, hbr_index,
+                               bp->address);
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_v3_activate_hardware_watchpoint(struct target *target)
+{
+       struct aice_port_s *aice = target_to_aice(target);
+       struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
+       struct watchpoint *wp;
+       int32_t wp_num = 0;
+       uint32_t wp_config = 0;
+       bool ld_stop, st_stop;
+
+       if (nds32_v3->nds32.global_stop)
+               ld_stop = st_stop = false;
+
+       for (wp = target->watchpoints; wp; wp = wp->next) {
+
+               if (wp_num < nds32_v3->used_n_wp) {
+                       wp->mask = wp->length - 1;
+                       if ((wp->address % wp->length) != 0)
+                               wp->mask = (wp->mask << 1) + 1;
+
+                       if (wp->rw == WPT_READ)
+                               wp_config = 0x3;
+                       else if (wp->rw == WPT_WRITE)
+                               wp_config = 0x5;
+                       else if (wp->rw == WPT_ACCESS)
+                               wp_config = 0x7;
+
+                       /* set/unset physical address bit of BPCn according to PSW.DT */
+                       if (nds32_v3->nds32.memory.address_translation == false)
+                               wp_config |= 0x8;
+
+                       /* set address */
+                       aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + wp_num,
+                                       wp->address - (wp->address % wp->length));
+                       /* set mask */
+                       aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + wp_num, wp->mask);
+                       /* enable watchpoint */
+                       aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, wp_config);
+                       /* set value */
+                       aice_write_debug_reg(aice, NDS_EDM_SR_BPV0 + wp_num, 0);
+
+                       LOG_DEBUG("Add hardware wathcpoint %d at %08" PRIx32 " mask %08" PRIx32,
+                                       wp_num, wp->address, wp->mask);
+
+                       wp_num++;
+               } else if (nds32_v3->nds32.global_stop) {
+                       if (wp->rw == WPT_READ)
+                               ld_stop = true;
+                       else if (wp->rw == WPT_WRITE)
+                               st_stop = true;
+                       else if (wp->rw == WPT_ACCESS)
+                               ld_stop = st_stop = true;
+               }
+       }
+
+       if (nds32_v3->nds32.global_stop) {
+               uint32_t edm_ctl;
+               aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
+               if (ld_stop)
+                       edm_ctl |= 0x10;
+               if (st_stop)
+                       edm_ctl |= 0x20;
+               aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_v3_deactivate_hardware_watchpoint(struct target *target)
+{
+       struct aice_port_s *aice = target_to_aice(target);
+       struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
+       int32_t wp_num = 0;
+       struct watchpoint *wp;
+       bool clean_global_stop = false;
+
+       for (wp = target->watchpoints; wp; wp = wp->next) {
+
+               if (wp_num < nds32_v3->used_n_wp) {
+                       /* disable watchpoint */
+                       aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, 0x0);
+
+                       LOG_DEBUG("Remove hardware wathcpoint %d at %08" PRIx32
+                                       " mask %08" PRIx32, wp_num,
+                                       wp->address, wp->mask);
+                       wp_num++;
+               } else if (nds32_v3->nds32.global_stop) {
+                       clean_global_stop = true;
+               }
+       }
+
+       if (clean_global_stop) {
+               uint32_t edm_ctl;
+               aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
+               edm_ctl = edm_ctl & (~0x30);
+               aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_v3_check_interrupt_stack(struct nds32 *nds32)
+{
+       uint32_t val_ir0;
+       uint32_t value;
+
+       /* Save interrupt level */
+       nds32_get_mapped_reg(nds32, IR0, &val_ir0);
+       nds32->current_interrupt_level = (val_ir0 >> 1) & 0x3;
+
+       if (nds32_reach_max_interrupt_level(nds32))
+               LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level %d. -->",
+                               nds32->current_interrupt_level);
+
+       /* backup $ir4 & $ir6 to avoid suppressed exception overwrite */
+       nds32_get_mapped_reg(nds32, IR4, &value);
+       nds32_get_mapped_reg(nds32, IR6, &value);
+
+       return ERROR_OK;
+}
+
+static int nds32_v3_restore_interrupt_stack(struct nds32 *nds32)
+{
+       uint32_t value;
+
+       /* get backup value from cache */
+       /* then set back to make the register dirty */
+       nds32_get_mapped_reg(nds32, IR0, &value);
+       nds32_set_mapped_reg(nds32, IR0, value);
+
+       nds32_get_mapped_reg(nds32, IR4, &value);
+       nds32_set_mapped_reg(nds32, IR4, value);
+
+       nds32_get_mapped_reg(nds32, IR6, &value);
+       nds32_set_mapped_reg(nds32, IR6, value);
+
+       return ERROR_OK;
+}
+
+static int nds32_v3_deassert_reset(struct target *target)
+{
+       int retval;
+       struct aice_port_s *aice = target_to_aice(target);
+       bool switch_to_v3_stack = false;
+       uint32_t value_edm_ctl;
+
+       aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &value_edm_ctl);
+       if (((value_edm_ctl >> 6) & 0x1) == 0) { /* reset to V2 EDM mode */
+               aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, value_edm_ctl | (0x1 << 6));
+               aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &value_edm_ctl);
+               if (((value_edm_ctl >> 6) & 0x1) == 1)
+                       switch_to_v3_stack = true;
+       } else
+               switch_to_v3_stack = false;
+
+       CHECK_RETVAL(nds32_poll(target));
+
+       if (target->state != TARGET_HALTED) {
+               /* reset only */
+               LOG_WARNING("%s: ran after reset and before halt ...",
+                               target_name(target));
+               retval = target_halt(target);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               /* call target_poll() to avoid "Halt timed out" */
+               CHECK_RETVAL(target_poll(target));
+       } else {
+               /* reset-halt */
+               jtag_poll_set_enabled(false);
+
+               struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
+               struct nds32 *nds32 = &(nds32_v3->nds32);
+               uint32_t value;
+               uint32_t interrupt_level;
+
+               if (switch_to_v3_stack == true) {
+                       /* PSW.INTL-- */
+                       nds32_get_mapped_reg(nds32, IR0, &value);
+                       interrupt_level = (value >> 1) & 0x3;
+                       interrupt_level--;
+                       value &= ~(0x6);
+                       value |= (interrupt_level << 1);
+                       value |= 0x400;  /* set PSW.DEX */
+                       nds32_set_mapped_reg(nds32, IR0, value);
+
+                       /* copy IPC to OIPC */
+                       if ((interrupt_level + 1) < nds32->max_interrupt_level) {
+                               nds32_get_mapped_reg(nds32, IR9, &value);
+                               nds32_set_mapped_reg(nds32, IR11, value);
+                       }
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_v3_add_breakpoint(struct target *target,
+               struct breakpoint *breakpoint)
+{
+       struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
+       struct nds32 *nds32 = &(nds32_v3->nds32);
+       int result;
+
+       if (breakpoint->type == BKPT_HARD) {
+               /* check hardware resource */
+               if (nds32_v3->n_hbr <= nds32_v3->next_hbr_index) {
+                       LOG_WARNING("<-- TARGET WARNING! Insert too many "
+                                       "hardware breakpoints/watchpoints! "
+                                       "The limit of combined hardware "
+                                       "breakpoints/watchpoints is %d. -->",
+                                       nds32_v3->n_hbr);
+                       LOG_WARNING("<-- TARGET STATUS: Inserted number of "
+                                       "hardware breakpoint: %d, hardware "
+                                       "watchpoints: %d. -->",
+                                       nds32_v3->next_hbr_index - nds32_v3->used_n_wp,
+                                       nds32_v3->used_n_wp);
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               }
+
+               /* update next place to put hardware breakpoint */
+               nds32_v3->next_hbr_index++;
+
+               /* hardware breakpoint insertion occurs before 'continue' actually */
+               return ERROR_OK;
+       } else if (breakpoint->type == BKPT_SOFT) {
+               result = nds32_add_software_breakpoint(target, breakpoint);
+               if (ERROR_OK != result) {
+                       /* auto convert to hardware breakpoint if failed */
+                       if (nds32->auto_convert_hw_bp) {
+                               /* convert to hardware breakpoint */
+                               breakpoint->type = BKPT_HARD;
+
+                               return nds32_v3_add_breakpoint(target, breakpoint);
+                       }
+               }
+
+               return result;
+       } else /* unrecognized breakpoint type */
+               return ERROR_FAIL;
+
+       return ERROR_OK;
+}
+
+static int nds32_v3_remove_breakpoint(struct target *target,
+               struct breakpoint *breakpoint)
+{
+       struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
+
+       if (breakpoint->type == BKPT_HARD) {
+               if (nds32_v3->next_hbr_index <= 0)
+                       return ERROR_FAIL;
+
+               /* update next place to put hardware breakpoint */
+               nds32_v3->next_hbr_index--;
+
+               /* hardware breakpoint removal occurs after 'halted' actually */
+               return ERROR_OK;
+       } else if (breakpoint->type == BKPT_SOFT) {
+               return nds32_remove_software_breakpoint(target, breakpoint);
+       } else /* unrecognized breakpoint type */
+               return ERROR_FAIL;
+
+       return ERROR_OK;
+}
+
+static int nds32_v3_add_watchpoint(struct target *target,
+               struct watchpoint *watchpoint)
+{
+       struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
+
+       /* check hardware resource */
+       if (nds32_v3->n_hbr <= nds32_v3->next_hbr_index) {
+               /* No hardware resource */
+               if (nds32_v3->nds32.global_stop) {
+                       LOG_WARNING("<-- TARGET WARNING! The number of "
+                                       "watchpoints exceeds the hardware "
+                                       "resources. Stop at every load/store "
+                                       "instruction to check for watchpoint matches. -->");
+                       return ERROR_OK;
+               }
+
+               LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
+                               "breakpoints/watchpoints! The limit of combined "
+                               "hardware breakpoints/watchpoints is %d. -->",
+                               nds32_v3->n_hbr);
+               LOG_WARNING("<-- TARGET STATUS: Inserted number of "
+                               "hardware breakpoint: %d, hardware "
+                               "watchpoints: %d. -->",
+                               nds32_v3->next_hbr_index - nds32_v3->used_n_wp,
+                               nds32_v3->used_n_wp);
+
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+
+       /* update next place to put hardware watchpoint */
+       nds32_v3->next_hbr_index++;
+       nds32_v3->used_n_wp++;
+
+       return ERROR_OK;
+}
+
+static int nds32_v3_remove_watchpoint(struct target *target,
+               struct watchpoint *watchpoint)
+{
+       struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
+
+       if (nds32_v3->next_hbr_index <= 0) {
+               if (nds32_v3->nds32.global_stop)
+                       return ERROR_OK;
+
+               return ERROR_FAIL;
+       }
+
+       /* update next place to put hardware breakpoint */
+       nds32_v3->next_hbr_index--;
+       nds32_v3->used_n_wp--;
+
+       return ERROR_OK;
+}
+
+struct nds32_v3_common_callback nds32_v3_common_callback = {
+       .check_interrupt_stack = nds32_v3_check_interrupt_stack,
+       .restore_interrupt_stack = nds32_v3_restore_interrupt_stack,
+       .activate_hardware_breakpoint = nds32_v3_activate_hardware_breakpoint,
+       .activate_hardware_watchpoint = nds32_v3_activate_hardware_watchpoint,
+       .deactivate_hardware_breakpoint = nds32_v3_deactivate_hardware_breakpoint,
+       .deactivate_hardware_watchpoint = nds32_v3_deactivate_hardware_watchpoint,
+};
+
+static int nds32_v3_target_create(struct target *target, Jim_Interp *interp)
+{
+       struct nds32_v3_common *nds32_v3;
+
+       nds32_v3 = calloc(1, sizeof(*nds32_v3));
+       if (!nds32_v3)
+               return ERROR_FAIL;
+
+       nds32_v3_common_register_callback(&nds32_v3_common_callback);
+       nds32_v3_target_create_common(target, &(nds32_v3->nds32));
+
+       return ERROR_OK;
+}
+
+/* talk to the target and set things up */
+static int nds32_v3_examine(struct target *target)
+{
+       struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
+       struct nds32 *nds32 = &(nds32_v3->nds32);
+       struct aice_port_s *aice = target_to_aice(target);
+
+       if (!target_was_examined(target)) {
+               CHECK_RETVAL(nds32_edm_config(nds32));
+
+               if (nds32->reset_halt_as_examine)
+                       CHECK_RETVAL(nds32_reset_halt(nds32));
+       }
+
+       uint32_t edm_cfg;
+       aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg);
+
+       /* get the number of hardware breakpoints */
+       nds32_v3->n_hbr = (edm_cfg & 0x7) + 1;
+
+       /* low interference profiling */
+       if (edm_cfg & 0x100)
+               nds32_v3->low_interference_profile = true;
+       else
+               nds32_v3->low_interference_profile = false;
+
+       nds32_v3->next_hbr_index = 0;
+       nds32_v3->used_n_wp = 0;
+
+       LOG_INFO("%s: total hardware breakpoint %d", target_name(target),
+                       nds32_v3->n_hbr);
+
+       nds32->target->state = TARGET_RUNNING;
+       nds32->target->debug_reason = DBG_REASON_NOTHALTED;
+
+       target_set_examined(target);
+
+       return ERROR_OK;
+}
+
+/** Holds methods for Andes1337 targets. */
+struct target_type nds32_v3_target = {
+       .name = "nds32_v3",
+
+       .poll = nds32_poll,
+       .arch_state = nds32_arch_state,
+
+       .target_request_data = nds32_v3_target_request_data,
+
+       .halt = nds32_halt,
+       .resume = nds32_resume,
+       .step = nds32_step,
+
+       .assert_reset = nds32_assert_reset,
+       .deassert_reset = nds32_v3_deassert_reset,
+       .soft_reset_halt = nds32_v3_soft_reset_halt,
+
+       /* register access */
+       .get_gdb_reg_list = nds32_get_gdb_reg_list,
+
+       /* memory access */
+       .read_buffer = nds32_v3_read_buffer,
+       .write_buffer = nds32_v3_write_buffer,
+       .read_memory = nds32_v3_read_memory,
+       .write_memory = nds32_v3_write_memory,
+
+       .checksum_memory = nds32_v3_checksum_memory,
+
+       /* breakpoint/watchpoint */
+       .add_breakpoint = nds32_v3_add_breakpoint,
+       .remove_breakpoint = nds32_v3_remove_breakpoint,
+       .add_watchpoint = nds32_v3_add_watchpoint,
+       .remove_watchpoint = nds32_v3_remove_watchpoint,
+
+       /* MMU */
+       .mmu = nds32_mmu,
+       .virt2phys = nds32_virtual_to_physical,
+       .read_phys_memory = nds32_read_phys_memory,
+       .write_phys_memory = nds32_write_phys_memory,
+
+       .run_algorithm = nds32_v3_run_algorithm,
+
+       .commands = nds32_command_handlers,
+       .target_create = nds32_v3_target_create,
+       .init_target = nds32_v3_init_target,
+       .examine = nds32_v3_examine,
+};
diff --git a/src/target/nds32_v3.h b/src/target/nds32_v3.h
new file mode 100644 (file)
index 0000000..7476b20
--- /dev/null
@@ -0,0 +1,46 @@
+/***************************************************************************
+ *   Copyright (C) 2013 Andes Technology                                   *
+ *   Hsiangkai Wang <hkwang@andestech.com>                                 *
+ *                                                                         *
+ *   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                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ ***************************************************************************/
+#ifndef __NDS32_V3_H__
+#define __NDS32_V3_H__
+
+#include "nds32.h"
+
+struct nds32_v3_common {
+       struct nds32 nds32;
+
+       /** number of hardware breakpoints */
+       int32_t n_hbr;
+
+       /** number of used hardware watchpoints */
+       int32_t used_n_wp;
+
+       /** next hardware breakpoint index */
+       int32_t next_hbr_index;
+
+       /** low interference profiling */
+       bool low_interference_profile;
+};
+
+static inline struct nds32_v3_common *target_to_nds32_v3(struct target *target)
+{
+       return container_of(target->arch_info, struct nds32_v3_common, nds32);
+}
+
+#endif /* __NDS32_V3_H__ */
diff --git a/src/target/nds32_v3_common.c b/src/target/nds32_v3_common.c
new file mode 100644 (file)
index 0000000..49d8413
--- /dev/null
@@ -0,0 +1,492 @@
+/***************************************************************************
+ *   Copyright (C) 2013 Andes Technology                                   *
+ *   Hsiangkai Wang <hkwang@andestech.com>                                 *
+ *                                                                         *
+ *   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                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "breakpoints.h"
+#include "nds32_reg.h"
+#include "nds32_disassembler.h"
+#include "nds32.h"
+#include "nds32_aice.h"
+#include "nds32_v3_common.h"
+
+static struct nds32_v3_common_callback *v3_common_callback;
+
+static int nds32_v3_register_mapping(struct nds32 *nds32, int reg_no)
+{
+       if (reg_no == PC)
+               return IR11;
+
+       return reg_no;
+}
+
+static int nds32_v3_get_debug_reason(struct nds32 *nds32, uint32_t *reason)
+{
+       uint32_t edmsw;
+       struct aice_port_s *aice = target_to_aice(nds32->target);
+       aice_read_debug_reg(aice, NDS_EDM_SR_EDMSW, &edmsw);
+
+       *reason = (edmsw >> 12) & 0x0F;
+
+       return ERROR_OK;
+}
+
+/**
+ * Save processor state.  This is called after a HALT instruction
+ * succeeds, and on other occasions the processor enters debug mode
+ * (breakpoint, watchpoint, etc).
+ */
+static int nds32_v3_debug_entry(struct nds32 *nds32, bool enable_watchpoint)
+{
+       LOG_DEBUG("nds32_v3_debug_entry");
+
+       jtag_poll_set_enabled(false);
+
+       enum target_state backup_state = nds32->target->state;
+       nds32->target->state = TARGET_HALTED;
+
+       if (nds32->init_arch_info_after_halted == false) {
+               /* init architecture info according to config registers */
+               CHECK_RETVAL(nds32_config(nds32));
+
+               nds32->init_arch_info_after_halted = true;
+       }
+
+       /* REVISIT entire cache should already be invalid !!! */
+       register_cache_invalidate(nds32->core_cache);
+
+       /* deactivate all hardware breakpoints */
+       CHECK_RETVAL(v3_common_callback->deactivate_hardware_breakpoint(nds32->target));
+
+       if (enable_watchpoint)
+               CHECK_RETVAL(v3_common_callback->deactivate_hardware_watchpoint(nds32->target));
+
+       if (ERROR_OK != nds32_examine_debug_reason(nds32)) {
+               nds32->target->state = backup_state;
+
+               /* re-activate all hardware breakpoints & watchpoints */
+               CHECK_RETVAL(v3_common_callback->activate_hardware_breakpoint(nds32->target));
+
+               if (enable_watchpoint)
+                       CHECK_RETVAL(v3_common_callback->activate_hardware_watchpoint(nds32->target));
+
+               jtag_poll_set_enabled(true);
+
+               return ERROR_FAIL;
+       }
+
+       /* Save registers. */
+       nds32_full_context(nds32);
+
+       /* check interrupt level */
+       v3_common_callback->check_interrupt_stack(nds32);
+
+       return ERROR_OK;
+}
+
+/**
+ * Restore processor state.
+ */
+static int nds32_v3_leave_debug_state(struct nds32 *nds32, bool enable_watchpoint)
+{
+       LOG_DEBUG("nds32_v3_leave_debug_state");
+
+       struct target *target = nds32->target;
+
+       /* activate all hardware breakpoints */
+       CHECK_RETVAL(v3_common_callback->activate_hardware_breakpoint(target));
+
+       if (enable_watchpoint) {
+               /* activate all watchpoints */
+               CHECK_RETVAL(v3_common_callback->activate_hardware_watchpoint(target));
+       }
+
+       /* restore interrupt stack */
+       v3_common_callback->restore_interrupt_stack(nds32);
+
+       /* REVISIT once we start caring about MMU and cache state,
+        * address it here ...
+        */
+
+       /* restore PSW, PC, and R0 ... after flushing any modified
+        * registers.
+        */
+       CHECK_RETVAL(nds32_restore_context(target));
+
+       /* enable polling */
+       jtag_poll_set_enabled(true);
+
+       return ERROR_OK;
+}
+
+static int nds32_v3_get_exception_address(struct nds32 *nds32,
+               uint32_t *address, uint32_t reason)
+{
+       LOG_DEBUG("nds32_v3_get_exception_address");
+
+       struct aice_port_s *aice = target_to_aice(nds32->target);
+       struct target *target = nds32->target;
+       uint32_t edmsw;
+       uint32_t edm_cfg;
+       uint32_t match_bits;
+       uint32_t match_count;
+       int32_t i;
+       static int32_t number_of_hard_break;
+
+       if (number_of_hard_break == 0) {
+               aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg);
+               number_of_hard_break = (edm_cfg & 0x7) + 1;
+       }
+
+       aice_read_debug_reg(aice, NDS_EDM_SR_EDMSW, &edmsw);
+       /* clear matching bits (write-one-clear) */
+       aice_write_debug_reg(aice, NDS_EDM_SR_EDMSW, edmsw);
+       match_bits = (edmsw >> 4) & 0xFF;
+       match_count = 0;
+       for (i = 0 ; i < number_of_hard_break ; i++) {
+               if (match_bits & (1 << i)) {
+                       aice_read_debug_reg(aice, NDS_EDM_SR_BPA0 + i, address);
+                       match_count++;
+               }
+       }
+
+       if (match_count > 1) { /* multiple hits */
+               *address = 0;
+               return ERROR_OK;
+       } else if (match_count == 1) {
+               uint32_t val_pc;
+               uint32_t opcode;
+               struct nds32_instruction instruction;
+               struct watchpoint *wp;
+               bool hit;
+
+               nds32_get_mapped_reg(nds32, PC, &val_pc);
+
+               if ((NDS32_DEBUG_DATA_ADDR_WATCHPOINT_NEXT_PRECISE == reason) ||
+                               (NDS32_DEBUG_DATA_VALUE_WATCHPOINT_NEXT_PRECISE == reason)) {
+                       if (edmsw & 0x4) /* check EDMSW.IS_16BIT */
+                               val_pc -= 2;
+                       else
+                               val_pc -= 4;
+               }
+
+               nds32_read_opcode(nds32, val_pc, &opcode);
+               nds32_evaluate_opcode(nds32, opcode, val_pc, &instruction);
+
+               LOG_DEBUG("PC: 0x%08x, access start: 0x%08x, end: 0x%08x", val_pc,
+                               instruction.access_start, instruction.access_end);
+
+               /* check if multiple hits in the access range */
+               uint32_t in_range_watch_count = 0;
+               for (wp = target->watchpoints; wp; wp = wp->next) {
+                       if ((instruction.access_start <= wp->address) &&
+                                       (wp->address < instruction.access_end))
+                               in_range_watch_count++;
+               }
+               if (in_range_watch_count > 1) {
+                       /* Hit LSMW instruction. */
+                       *address = 0;
+                       return ERROR_OK;
+               }
+
+               /* dispel false match */
+               hit = false;
+               for (wp = target->watchpoints; wp; wp = wp->next) {
+                       if (((*address ^ wp->address) & (~wp->mask)) == 0) {
+                               uint32_t watch_start;
+                               uint32_t watch_end;
+
+                               watch_start = wp->address;
+                               watch_end = wp->address + wp->length;
+
+                               if ((watch_end <= instruction.access_start) ||
+                                               (instruction.access_end <= watch_start))
+                                       continue;
+
+                               hit = true;
+                               break;
+                       }
+               }
+
+               if (hit)
+                       return ERROR_OK;
+               else
+                       return ERROR_FAIL;
+       } else if (match_count == 0) {
+               /* global stop is precise exception */
+               if ((NDS32_DEBUG_LOAD_STORE_GLOBAL_STOP == reason) && nds32->global_stop) {
+                       /* parse instruction to get correct access address */
+                       uint32_t val_pc;
+                       uint32_t opcode;
+                       struct nds32_instruction instruction;
+
+                       nds32_get_mapped_reg(nds32, PC, &val_pc);
+                       nds32_read_opcode(nds32, val_pc, &opcode);
+                       nds32_evaluate_opcode(nds32, opcode, val_pc, &instruction);
+
+                       *address = instruction.access_start;
+
+                       return ERROR_OK;
+               }
+       }
+
+       *address = 0xFFFFFFFF;
+       return ERROR_FAIL;
+}
+
+void nds32_v3_common_register_callback(struct nds32_v3_common_callback *callback)
+{
+       v3_common_callback = callback;
+}
+
+/** target_type functions: */
+/* target request support */
+int nds32_v3_target_request_data(struct target *target,
+               uint32_t size, uint8_t *buffer)
+{
+       /* AndesCore could use DTR register to communicate with OpenOCD
+        * to output messages
+        * Target data will be put in buffer
+        * The format of DTR is as follow
+        * DTR[31:16] => length, DTR[15:8] => size, DTR[7:0] => target_req_cmd
+        * target_req_cmd has three possible values:
+        *   TARGET_REQ_TRACEMSG
+        *   TARGET_REQ_DEBUGMSG
+        *   TARGET_REQ_DEBUGCHAR
+        * if size == 0, target will call target_asciimsg(),
+        * else call target_hexmsg()
+        */
+       LOG_WARNING("Not implemented: %s", __func__);
+
+       return ERROR_OK;
+}
+
+int nds32_v3_soft_reset_halt(struct target *target)
+{
+       struct aice_port_s *aice = target_to_aice(target);
+       return aice_assert_srst(aice, AICE_RESET_HOLD);
+}
+
+int nds32_v3_checksum_memory(struct target *target,
+               uint32_t address, uint32_t count, uint32_t *checksum)
+{
+       LOG_WARNING("Not implemented: %s", __func__);
+
+       return ERROR_FAIL;
+}
+
+int nds32_v3_target_create_common(struct target *target, struct nds32 *nds32)
+{
+       nds32->register_map = nds32_v3_register_mapping;
+       nds32->get_debug_reason = nds32_v3_get_debug_reason;
+       nds32->enter_debug_state = nds32_v3_debug_entry;
+       nds32->leave_debug_state = nds32_v3_leave_debug_state;
+       nds32->get_watched_address = nds32_v3_get_exception_address;
+
+       /* Init target->arch_info in nds32_init_arch_info().
+        * After this, user could use target_to_nds32() to get nds32 object */
+       nds32_init_arch_info(target, nds32);
+
+       return ERROR_OK;
+}
+
+int nds32_v3_run_algorithm(struct target *target,
+               int num_mem_params,
+               struct mem_param *mem_params,
+               int num_reg_params,
+               struct reg_param *reg_params,
+               uint32_t entry_point,
+               uint32_t exit_point,
+               int timeout_ms,
+               void *arch_info)
+{
+       LOG_WARNING("Not implemented: %s", __func__);
+
+       return ERROR_FAIL;
+}
+
+int nds32_v3_read_buffer(struct target *target, uint32_t address,
+               uint32_t size, uint8_t *buffer)
+{
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct nds32_memory *memory = &(nds32->memory);
+
+       if ((NDS_MEMORY_ACC_CPU == memory->access_channel) &&
+                       (target->state != TARGET_HALTED)) {
+               LOG_WARNING("target was not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       uint32_t physical_address;
+       /* BUG: If access range crosses multiple pages, the translation will not correct
+        * for second page or so. */
+
+       /* When DEX is set to one, hardware will enforce the following behavior without
+        * modifying the corresponding control bits in PSW.
+        *
+        * Disable all interrupts
+        * Become superuser mode
+        * Turn off IT/DT
+        * Use MMU_CFG.DE as the data access endian
+        * Use MMU_CFG.DRDE as the device register access endian if MMU_CTL.DREE is asserted
+        * Disable audio special features
+        * Disable inline function call
+        *
+        * Because hardware will turn off IT/DT by default, it MUST translate virtual address
+        * to physical address.
+        */
+       if (ERROR_OK == target->type->virt2phys(target, address, &physical_address))
+               address = physical_address;
+       else
+               return ERROR_FAIL;
+
+       return nds32_read_buffer(target, address, size, buffer);
+}
+
+int nds32_v3_write_buffer(struct target *target, uint32_t address,
+               uint32_t size, const uint8_t *buffer)
+{
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct nds32_memory *memory = &(nds32->memory);
+
+       if ((NDS_MEMORY_ACC_CPU == memory->access_channel) &&
+                       (target->state != TARGET_HALTED)) {
+               LOG_WARNING("target was not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       uint32_t physical_address;
+       /* BUG: If access range crosses multiple pages, the translation will not correct
+        * for second page or so. */
+
+       /* When DEX is set to one, hardware will enforce the following behavior without
+        * modifying the corresponding control bits in PSW.
+        *
+        * Disable all interrupts
+        * Become superuser mode
+        * Turn off IT/DT
+        * Use MMU_CFG.DE as the data access endian
+        * Use MMU_CFG.DRDE as the device register access endian if MMU_CTL.DREE is asserted
+        * Disable audio special features
+        * Disable inline function call
+        *
+        * Because hardware will turn off IT/DT by default, it MUST translate virtual address
+        * to physical address.
+        */
+       if (ERROR_OK == target->type->virt2phys(target, address, &physical_address))
+               address = physical_address;
+       else
+               return ERROR_FAIL;
+
+       return nds32_write_buffer(target, address, size, buffer);
+}
+
+int nds32_v3_read_memory(struct target *target, uint32_t address,
+               uint32_t size, uint32_t count, uint8_t *buffer)
+{
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct nds32_memory *memory = &(nds32->memory);
+
+       if ((NDS_MEMORY_ACC_CPU == memory->access_channel) &&
+                       (target->state != TARGET_HALTED)) {
+               LOG_WARNING("target was not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       uint32_t physical_address;
+       /* BUG: If access range crosses multiple pages, the translation will not correct
+        * for second page or so. */
+
+       /* When DEX is set to one, hardware will enforce the following behavior without
+        * modifying the corresponding control bits in PSW.
+        *
+        * Disable all interrupts
+        * Become superuser mode
+        * Turn off IT/DT
+        * Use MMU_CFG.DE as the data access endian
+        * Use MMU_CFG.DRDE as the device register access endian if MMU_CTL.DREE is asserted
+        * Disable audio special features
+        * Disable inline function call
+        *
+        * Because hardware will turn off IT/DT by default, it MUST translate virtual address
+        * to physical address.
+        */
+       if (ERROR_OK == target->type->virt2phys(target, address, &physical_address))
+               address = physical_address;
+       else
+               return ERROR_FAIL;
+
+       int result;
+
+       result = nds32_read_memory(target, address, size, count, buffer);
+
+       return result;
+}
+
+int nds32_v3_write_memory(struct target *target, uint32_t address,
+               uint32_t size, uint32_t count, const uint8_t *buffer)
+{
+       struct nds32 *nds32 = target_to_nds32(target);
+       struct nds32_memory *memory = &(nds32->memory);
+
+       if ((NDS_MEMORY_ACC_CPU == memory->access_channel) &&
+                       (target->state != TARGET_HALTED)) {
+               LOG_WARNING("target was not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       uint32_t physical_address;
+       /* BUG: If access range crosses multiple pages, the translation will not correct
+        * for second page or so. */
+
+       /* When DEX is set to one, hardware will enforce the following behavior without
+        * modifying the corresponding control bits in PSW.
+        *
+        * Disable all interrupts
+        * Become superuser mode
+        * Turn off IT/DT
+        * Use MMU_CFG.DE as the data access endian
+        * Use MMU_CFG.DRDE as the device register access endian if MMU_CTL.DREE is asserted
+        * Disable audio special features
+        * Disable inline function call
+        *
+        * Because hardware will turn off IT/DT by default, it MUST translate virtual address
+        * to physical address.
+        */
+       if (ERROR_OK == target->type->virt2phys(target, address, &physical_address))
+               address = physical_address;
+       else
+               return ERROR_FAIL;
+
+       return nds32_write_memory(target, address, size, count, buffer);
+}
+
+int nds32_v3_init_target(struct command_context *cmd_ctx,
+               struct target *target)
+{
+       /* Initialize anything we can set up without talking to the target */
+       struct nds32 *nds32 = target_to_nds32(target);
+
+       nds32_init(nds32);
+
+       return ERROR_OK;
+}
diff --git a/src/target/nds32_v3_common.h b/src/target/nds32_v3_common.h
new file mode 100644 (file)
index 0000000..c62da9a
--- /dev/null
@@ -0,0 +1,63 @@
+/***************************************************************************
+ *   Copyright (C) 2013 Andes Technology                                   *
+ *   Hsiangkai Wang <hkwang@andestech.com>                                 *
+ *                                                                         *
+ *   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                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ ***************************************************************************/
+#ifndef __NDS32_V3_COMMON_H__
+#define __NDS32_V3_COMMON_H__
+
+#include "target.h"
+
+struct nds32_v3_common_callback {
+       int (*check_interrupt_stack)(struct nds32 *nds32);
+       int (*restore_interrupt_stack)(struct nds32 *nds32);
+       int (*activate_hardware_breakpoint)(struct target *target);
+       int (*activate_hardware_watchpoint)(struct target *target);
+       int (*deactivate_hardware_breakpoint)(struct target *target);
+       int (*deactivate_hardware_watchpoint)(struct target *target);
+};
+
+void nds32_v3_common_register_callback(struct nds32_v3_common_callback *callback);
+int nds32_v3_target_request_data(struct target *target,
+               uint32_t size, uint8_t *buffer);
+int nds32_v3_soft_reset_halt(struct target *target);
+int nds32_v3_checksum_memory(struct target *target,
+               uint32_t address, uint32_t count, uint32_t *checksum);
+int nds32_v3_hit_watchpoint(struct target *target,
+               struct watchpoint **hit_watchpoint);
+int nds32_v3_target_create_common(struct target *target, struct nds32 *nds32);
+int nds32_v3_run_algorithm(struct target *target,
+               int num_mem_params,
+               struct mem_param *mem_params,
+               int num_reg_params,
+               struct reg_param *reg_params,
+               uint32_t entry_point,
+               uint32_t exit_point,
+               int timeout_ms,
+               void *arch_info);
+int nds32_v3_read_buffer(struct target *target, uint32_t address,
+               uint32_t size, uint8_t *buffer);
+int nds32_v3_write_buffer(struct target *target, uint32_t address,
+               uint32_t size, const uint8_t *buffer);
+int nds32_v3_read_memory(struct target *target, uint32_t address,
+               uint32_t size, uint32_t count, uint8_t *buffer);
+int nds32_v3_write_memory(struct target *target, uint32_t address,
+               uint32_t size, uint32_t count, const uint8_t *buffer);
+int nds32_v3_init_target(struct command_context *cmd_ctx,
+               struct target *target);
+
+#endif /* __NDS32_V3_COMMON_H__ */
diff --git a/src/target/nds32_v3m.c b/src/target/nds32_v3m.c
new file mode 100644 (file)
index 0000000..1898732
--- /dev/null
@@ -0,0 +1,510 @@
+/***************************************************************************
+ *   Copyright (C) 2013 Andes Technology                                   *
+ *   Hsiangkai Wang <hkwang@andestech.com>                                 *
+ *                                                                         *
+ *   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                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "breakpoints.h"
+#include "nds32_cmd.h"
+#include "nds32_aice.h"
+#include "nds32_v3m.h"
+#include "nds32_v3_common.h"
+
+static int nds32_v3m_activate_hardware_breakpoint(struct target *target)
+{
+       struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
+       struct aice_port_s *aice = target_to_aice(target);
+       struct breakpoint *bp;
+       unsigned brp_num = nds32_v3m->n_hbr - 1;
+
+       for (bp = target->breakpoints; bp; bp = bp->next) {
+               if (bp->type == BKPT_SOFT) {
+                       /* already set at nds32_v3m_add_breakpoint() */
+                       continue;
+               } else if (bp->type == BKPT_HARD) {
+                       /* set address */
+                       aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + brp_num, bp->address);
+                       /* set mask */
+                       aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + brp_num, 0);
+
+                       if (nds32_v3m->nds32.memory.address_translation)
+                               /* enable breakpoint (virtual address) */
+                               aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0x2);
+                       else
+                               /* enable breakpoint (physical address) */
+                               aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0xA);
+
+                       LOG_DEBUG("Add hardware BP %d at %08" PRIx32, brp_num,
+                                       bp->address);
+
+                       brp_num--;
+               } else {
+                       return ERROR_FAIL;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_v3m_deactivate_hardware_breakpoint(struct target *target)
+{
+       struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
+       struct aice_port_s *aice = target_to_aice(target);
+       struct breakpoint *bp;
+       unsigned brp_num = nds32_v3m->n_hbr - 1;
+
+       for (bp = target->breakpoints; bp; bp = bp->next) {
+               if (bp->type == BKPT_SOFT)
+                       continue;
+               else if (bp->type == BKPT_HARD)
+                       /* disable breakpoint */
+                       aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0x0);
+               else
+                       return ERROR_FAIL;
+
+               LOG_DEBUG("Remove hardware BP %d at %08" PRIx32, brp_num,
+                               bp->address);
+
+               brp_num--;
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_v3m_activate_hardware_watchpoint(struct target *target)
+{
+       struct aice_port_s *aice = target_to_aice(target);
+       struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
+       struct watchpoint *wp;
+       int32_t  wp_num = 0;
+       uint32_t wp_config = 0;
+       bool ld_stop, st_stop;
+
+       if (nds32_v3m->nds32.global_stop)
+               ld_stop = st_stop = false;
+
+       for (wp = target->watchpoints; wp; wp = wp->next) {
+
+               if (wp_num < nds32_v3m->used_n_wp) {
+                       wp->mask = wp->length - 1;
+                       if ((wp->address % wp->length) != 0)
+                               wp->mask = (wp->mask << 1) + 1;
+
+                       if (wp->rw == WPT_READ)
+                               wp_config = 0x3;
+                       else if (wp->rw == WPT_WRITE)
+                               wp_config = 0x5;
+                       else if (wp->rw == WPT_ACCESS)
+                               wp_config = 0x7;
+
+                       /* set/unset physical address bit of BPCn according to PSW.DT */
+                       if (nds32_v3m->nds32.memory.address_translation == false)
+                               wp_config |= 0x8;
+
+                       /* set address */
+                       aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + wp_num,
+                                       wp->address - (wp->address % wp->length));
+                       /* set mask */
+                       aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + wp_num, wp->mask);
+                       /* enable watchpoint */
+                       aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, wp_config);
+
+                       LOG_DEBUG("Add hardware wathcpoint %d at %08" PRIx32
+                                       " mask %08" PRIx32, wp_num,
+                                       wp->address, wp->mask);
+
+                       wp_num++;
+               } else if (nds32_v3m->nds32.global_stop) {
+                       if (wp->rw == WPT_READ)
+                               ld_stop = true;
+                       else if (wp->rw == WPT_WRITE)
+                               st_stop = true;
+                       else if (wp->rw == WPT_ACCESS)
+                               ld_stop = st_stop = true;
+               }
+       }
+
+       if (nds32_v3m->nds32.global_stop) {
+               uint32_t edm_ctl;
+               aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
+               if (ld_stop)
+                       edm_ctl |= 0x10;
+               if (st_stop)
+                       edm_ctl |= 0x20;
+               aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_v3m_deactivate_hardware_watchpoint(struct target *target)
+{
+       struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
+       struct aice_port_s *aice = target_to_aice(target);
+       struct watchpoint *wp;
+       int32_t wp_num = 0;
+       bool clean_global_stop = false;
+
+       for (wp = target->watchpoints; wp; wp = wp->next) {
+
+               if (wp_num < nds32_v3m->used_n_wp) {
+                       /* disable watchpoint */
+                       aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, 0x0);
+
+                       LOG_DEBUG("Remove hardware wathcpoint %d at %08" PRIx32
+                                       " mask %08" PRIx32, wp_num,
+                                       wp->address, wp->mask);
+                       wp_num++;
+               } else if (nds32_v3m->nds32.global_stop) {
+                       clean_global_stop = true;
+               }
+       }
+
+       if (clean_global_stop) {
+               uint32_t edm_ctl;
+               aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
+               edm_ctl = edm_ctl & (~0x30);
+               aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_v3m_check_interrupt_stack(struct nds32 *nds32)
+{
+       uint32_t val_ir0;
+       uint32_t value;
+
+       /* Save interrupt level */
+       nds32_get_mapped_reg(nds32, IR0, &val_ir0);
+       nds32->current_interrupt_level = (val_ir0 >> 1) & 0x3;
+
+       if (nds32_reach_max_interrupt_level(nds32))
+               LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level %d. -->",
+                               nds32->current_interrupt_level);
+
+       /* backup $ir6 to avoid suppressed exception overwrite */
+       nds32_get_mapped_reg(nds32, IR6, &value);
+
+       return ERROR_OK;
+}
+
+static int nds32_v3m_restore_interrupt_stack(struct nds32 *nds32)
+{
+       uint32_t value;
+
+       /* get backup value from cache */
+       /* then set back to make the register dirty */
+       nds32_get_mapped_reg(nds32, IR0, &value);
+       nds32_set_mapped_reg(nds32, IR0, value);
+
+       nds32_get_mapped_reg(nds32, IR6, &value);
+       nds32_set_mapped_reg(nds32, IR6, value);
+
+       return ERROR_OK;
+}
+
+static int nds32_v3m_deassert_reset(struct target *target)
+{
+       int retval;
+
+       CHECK_RETVAL(nds32_poll(target));
+
+       if (target->state != TARGET_HALTED) {
+               /* reset only */
+               LOG_WARNING("%s: ran after reset and before halt ...",
+                               target_name(target));
+               retval = target_halt(target);
+               if (retval != ERROR_OK)
+                       return retval;
+               /* call target_poll() to avoid "Halt timed out" */
+               CHECK_RETVAL(target_poll(target));
+       } else {
+               jtag_poll_set_enabled(false);
+       }
+
+       return ERROR_OK;
+}
+
+static int nds32_v3m_add_breakpoint(struct target *target,
+               struct breakpoint *breakpoint)
+{
+       struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
+       struct nds32 *nds32 = &(nds32_v3m->nds32);
+       int result;
+
+       if (breakpoint->type == BKPT_HARD) {
+               /* check hardware resource */
+               if (nds32_v3m->next_hbr_index < nds32_v3m->next_hwp_index) {
+                       LOG_WARNING("<-- TARGET WARNING! Insert too many "
+                                       "hardware breakpoints/watchpoints! "
+                                       "The limit of combined hardware "
+                                       "breakpoints/watchpoints is %d. -->",
+                                       nds32_v3m->n_hbr);
+                       LOG_WARNING("<-- TARGET STATUS: Inserted number of "
+                                       "hardware breakpoint: %d, hardware "
+                                       "watchpoints: %d. -->",
+                                       nds32_v3m->n_hbr - nds32_v3m->next_hbr_index - 1,
+                                       nds32_v3m->used_n_wp);
+                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+               }
+
+               /* update next place to put hardware breakpoint */
+               nds32_v3m->next_hbr_index--;
+
+               /* hardware breakpoint insertion occurs before 'continue' actually */
+               return ERROR_OK;
+       } else if (breakpoint->type == BKPT_SOFT) {
+               result = nds32_add_software_breakpoint(target, breakpoint);
+               if (ERROR_OK != result) {
+                       /* auto convert to hardware breakpoint if failed */
+                       if (nds32->auto_convert_hw_bp) {
+                               /* convert to hardware breakpoint */
+                               breakpoint->type = BKPT_HARD;
+
+                               return nds32_v3m_add_breakpoint(target, breakpoint);
+                       }
+               }
+
+               return result;
+       } else /* unrecognized breakpoint type */
+               return ERROR_FAIL;
+
+       return ERROR_OK;
+}
+
+static int nds32_v3m_remove_breakpoint(struct target *target,
+               struct breakpoint *breakpoint)
+{
+       struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
+
+       if (breakpoint->type == BKPT_HARD) {
+               if (nds32_v3m->next_hbr_index >= nds32_v3m->n_hbr - 1)
+                       return ERROR_FAIL;
+
+               /* update next place to put hardware breakpoint */
+               nds32_v3m->next_hbr_index++;
+
+               /* hardware breakpoint removal occurs after 'halted' actually */
+               return ERROR_OK;
+       } else if (breakpoint->type == BKPT_SOFT) {
+               return nds32_remove_software_breakpoint(target, breakpoint);
+       } else /* unrecognized breakpoint type */
+               return ERROR_FAIL;
+
+       return ERROR_OK;
+}
+
+static int nds32_v3m_add_watchpoint(struct target *target,
+               struct watchpoint *watchpoint)
+{
+       struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
+
+       /* check hardware resource */
+       if (nds32_v3m->next_hwp_index >= nds32_v3m->n_hwp) {
+               /* No hardware resource */
+               if (nds32_v3m->nds32.global_stop) {
+                       LOG_WARNING("<-- TARGET WARNING! The number of "
+                                       "watchpoints exceeds the hardware "
+                                       "resources. Stop at every load/store "
+                                       "instruction to check for watchpoint matches. -->");
+                       return ERROR_OK;
+               }
+
+               LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
+                               "watchpoints! The limit of hardware watchpoints "
+                               "is %d. -->", nds32_v3m->n_hwp);
+               LOG_WARNING("<-- TARGET STATUS: Inserted number of "
+                               "hardware watchpoint: %d. -->",
+                               nds32_v3m->used_n_wp);
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+
+       if (nds32_v3m->next_hwp_index > nds32_v3m->next_hbr_index) {
+               /* No hardware resource */
+               if (nds32_v3m->nds32.global_stop) {
+                       LOG_WARNING("<-- TARGET WARNING! The number of "
+                                       "watchpoints exceeds the hardware "
+                                       "resources. Stop at every load/store "
+                                       "instruction to check for watchpoint matches. -->");
+                       return ERROR_OK;
+               }
+
+               LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
+                               "breakpoints/watchpoints! The limit of combined "
+                               "hardware breakpoints/watchpoints is %d. -->",
+                               nds32_v3m->n_hbr);
+               LOG_WARNING("<-- TARGET STATUS: Inserted number of "
+                               "hardware breakpoint: %d, hardware "
+                               "watchpoints: %d. -->",
+                               nds32_v3m->n_hbr - nds32_v3m->next_hbr_index - 1,
+                               nds32_v3m->used_n_wp);
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+
+       /* update next place to put hardware watchpoint */
+       nds32_v3m->next_hwp_index++;
+       nds32_v3m->used_n_wp++;
+
+       return ERROR_OK;
+}
+
+static int nds32_v3m_remove_watchpoint(struct target *target,
+               struct watchpoint *watchpoint)
+{
+       struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
+
+       if (nds32_v3m->next_hwp_index <= 0) {
+               if (nds32_v3m->nds32.global_stop)
+                       return ERROR_OK;
+
+               return ERROR_FAIL;
+       }
+
+       /* update next place to put hardware watchpoint */
+       nds32_v3m->next_hwp_index--;
+       nds32_v3m->used_n_wp--;
+
+       return ERROR_OK;
+}
+
+struct nds32_v3_common_callback nds32_v3m_common_callback = {
+       .check_interrupt_stack = nds32_v3m_check_interrupt_stack,
+       .restore_interrupt_stack = nds32_v3m_restore_interrupt_stack,
+       .activate_hardware_breakpoint = nds32_v3m_activate_hardware_breakpoint,
+       .activate_hardware_watchpoint = nds32_v3m_activate_hardware_watchpoint,
+       .deactivate_hardware_breakpoint = nds32_v3m_deactivate_hardware_breakpoint,
+       .deactivate_hardware_watchpoint = nds32_v3m_deactivate_hardware_watchpoint,
+};
+
+static int nds32_v3m_target_create(struct target *target, Jim_Interp *interp)
+{
+       struct nds32_v3m_common *nds32_v3m;
+
+       nds32_v3m = calloc(1, sizeof(*nds32_v3m));
+       if (!nds32_v3m)
+               return ERROR_FAIL;
+
+       nds32_v3_common_register_callback(&nds32_v3m_common_callback);
+       nds32_v3_target_create_common(target, &(nds32_v3m->nds32));
+
+       return ERROR_OK;
+}
+
+/* talk to the target and set things up */
+static int nds32_v3m_examine(struct target *target)
+{
+       struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
+       struct nds32 *nds32 = &(nds32_v3m->nds32);
+       struct aice_port_s *aice = target_to_aice(target);
+
+       if (!target_was_examined(target)) {
+               CHECK_RETVAL(nds32_edm_config(nds32));
+
+               if (nds32->reset_halt_as_examine)
+                       CHECK_RETVAL(nds32_reset_halt(nds32));
+       }
+
+       uint32_t edm_cfg;
+       aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg);
+
+       /* get the number of hardware breakpoints */
+       nds32_v3m->n_hbr = (edm_cfg & 0x7) + 1;
+       nds32_v3m->used_n_wp = 0;
+
+       /* get the number of hardware watchpoints */
+       /* If the WP field is hardwired to zero, it means this is a
+        * simple breakpoint.  Otherwise, if the WP field is writable
+        * then it means this is a regular watchpoints. */
+       nds32_v3m->n_hwp = 0;
+       for (int32_t i = 0 ; i < nds32_v3m->n_hbr ; i++) {
+               /** check the hardware breakpoint is simple or not */
+               uint32_t tmp_value;
+               aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + i, 0x1);
+               aice_read_debug_reg(aice, NDS_EDM_SR_BPC0 + i, &tmp_value);
+
+               if (tmp_value)
+                       nds32_v3m->n_hwp++;
+       }
+       /* hardware breakpoint is inserted from high index to low index */
+       nds32_v3m->next_hbr_index = nds32_v3m->n_hbr - 1;
+       /* hardware watchpoint is inserted from low index to high index */
+       nds32_v3m->next_hwp_index = 0;
+
+       LOG_INFO("%s: total hardware breakpoint %d (simple breakpoint %d)",
+                       target_name(target), nds32_v3m->n_hbr, nds32_v3m->n_hbr - nds32_v3m->n_hwp);
+       LOG_INFO("%s: total hardware watchpoint %d", target_name(target), nds32_v3m->n_hwp);
+
+       nds32->target->state = TARGET_RUNNING;
+       nds32->target->debug_reason = DBG_REASON_NOTHALTED;
+
+       target_set_examined(target);
+
+       return ERROR_OK;
+}
+
+/** Holds methods for NDS32 V3m targets. */
+struct target_type nds32_v3m_target = {
+       .name = "nds32_v3m",
+
+       .poll = nds32_poll,
+       .arch_state = nds32_arch_state,
+
+       .target_request_data = nds32_v3_target_request_data,
+
+       .halt = nds32_halt,
+       .resume = nds32_resume,
+       .step = nds32_step,
+
+       .assert_reset = nds32_assert_reset,
+       .deassert_reset = nds32_v3m_deassert_reset,
+       .soft_reset_halt = nds32_v3_soft_reset_halt,
+
+       /* register access */
+       .get_gdb_reg_list = nds32_get_gdb_reg_list,
+
+       /* memory access */
+       .read_buffer = nds32_v3_read_buffer,
+       .write_buffer = nds32_v3_write_buffer,
+       .read_memory = nds32_v3_read_memory,
+       .write_memory = nds32_v3_write_memory,
+
+       .checksum_memory = nds32_v3_checksum_memory,
+
+       /* breakpoint/watchpoint */
+       .add_breakpoint = nds32_v3m_add_breakpoint,
+       .remove_breakpoint = nds32_v3m_remove_breakpoint,
+       .add_watchpoint = nds32_v3m_add_watchpoint,
+       .remove_watchpoint = nds32_v3m_remove_watchpoint,
+
+       /* MMU */
+       .mmu = nds32_mmu,
+       .virt2phys = nds32_virtual_to_physical,
+       .read_phys_memory = nds32_read_phys_memory,
+       .write_phys_memory = nds32_write_phys_memory,
+
+       .run_algorithm = nds32_v3_run_algorithm,
+
+       .commands = nds32_command_handlers,
+       .target_create = nds32_v3m_target_create,
+       .init_target = nds32_v3_init_target,
+       .examine = nds32_v3m_examine,
+};
diff --git a/src/target/nds32_v3m.h b/src/target/nds32_v3m.h
new file mode 100644 (file)
index 0000000..d72c2ad
--- /dev/null
@@ -0,0 +1,53 @@
+/***************************************************************************
+ *   Copyright (C) 2013 Andes Technology                                   *
+ *   Hsiangkai Wang <hkwang@andestech.com>                                 *
+ *                                                                         *
+ *   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                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
+ ***************************************************************************/
+#ifndef __NDS32_V3M_H__
+#define __NDS32_V3M_H__
+
+#include "nds32.h"
+
+struct nds32_v3m_common {
+       struct nds32 nds32;
+
+       /** number of hardware breakpoints */
+       int32_t n_hbr;
+
+       /** number of hardware watchpoints */
+       int32_t n_hwp;
+
+       /** number of used hardware watchpoints */
+       int32_t used_n_wp;
+
+       /** next hardware breakpoint index */
+       /** for simple breakpoints, hardware breakpoints are inserted
+        * from high index to low index */
+       int32_t next_hbr_index;
+
+       /** next hardware watchpoint index */
+       /** increase from low index to high index */
+       int32_t next_hwp_index;
+};
+
+static inline struct nds32_v3m_common *target_to_nds32_v3m(struct target *target)
+{
+       return container_of(target->arch_info, struct nds32_v3m_common, nds32);
+}
+
+
+#endif /* __NDS32_V3M_H__ */
index ed1a2cc4c4400c48c9607ff02f58c027bbbcf250..bfa0db79e1718e7727c868a959ea202095d04ea9 100644 (file)
@@ -89,6 +89,9 @@ extern struct target_type dsp5680xx_target;
 extern struct target_type testee_target;
 extern struct target_type avr32_ap7k_target;
 extern struct target_type hla_target;
+extern struct target_type nds32_v2_target;
+extern struct target_type nds32_v3_target;
+extern struct target_type nds32_v3m_target;
 
 static struct target_type *target_types[] = {
        &arm7tdmi_target,
@@ -113,6 +116,9 @@ static struct target_type *target_types[] = {
        &testee_target,
        &avr32_ap7k_target,
        &hla_target,
+       &nds32_v2_target,
+       &nds32_v3_target,
+       &nds32_v3m_target,
        NULL,
 };
 
diff --git a/tcl/board/nds32_xc5.cfg b/tcl/board/nds32_xc5.cfg
new file mode 100644 (file)
index 0000000..7d86996
--- /dev/null
@@ -0,0 +1,5 @@
+set _CPUTAPID 0x1000063d
+set _CHIPNAME nds32
+source [find target/nds32v3.cfg]
+
+jtag init
diff --git a/tcl/target/nds32v2.cfg b/tcl/target/nds32v2.cfg
new file mode 100644 (file)
index 0000000..bbf6b3a
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Andes Core
+#
+# http://www.andestech.com
+#
+
+jtag newtap $_CHIPNAME cpu -expected-id $_CPUTAPID
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create $_TARGETNAME nds32_v2 -endian little -chain-position $_TARGETNAME
diff --git a/tcl/target/nds32v3.cfg b/tcl/target/nds32v3.cfg
new file mode 100644 (file)
index 0000000..0c267cd
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Andes Core
+#
+# http://www.andestech.com
+#
+
+jtag newtap $_CHIPNAME cpu -expected-id $_CPUTAPID
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create $_TARGETNAME nds32_v3 -endian little -chain-position $_TARGETNAME
diff --git a/tcl/target/nds32v3m.cfg b/tcl/target/nds32v3m.cfg
new file mode 100644 (file)
index 0000000..169e3d1
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Andes Core
+#
+# http://www.andestech.com
+#
+
+jtag newtap $_CHIPNAME cpu -expected-id $_CPUTAPID
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create $_TARGETNAME nds32_v3m -endian little -chain-position $_TARGETNAME