nds32: add new target type nds32_v2, nds32_v3, nds32_v3m 59/1259/14
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 = \
        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 = \
 
 
 noinst_HEADERS = \
@@ -168,9 +177,17 @@ noinst_HEADERS = \
        avr32_mem.h \
        avr32_regs.h \
        nds32.h \
        avr32_mem.h \
        avr32_regs.h \
        nds32.h \
+       nds32_cmd.h \
+       nds32_disassembler.h \
        nds32_edm.h \
        nds32_insn.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 =
 
 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  *
  *   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>
 #define __NDS32_H__
 
 #include <jtag/jtag.h>
-#include <jtag/aice/aice_port.h>
 #include "target.h"
 #include "target_type.h"
 #include "register.h"
 #include "target.h"
 #include "target_type.h"
 #include "register.h"
@@ -31,6 +30,8 @@
 #include "nds32_insn.h"
 #include "nds32_edm.h"
 
 #include "nds32_insn.h"
 #include "nds32_edm.h"
 
+#define NDS32_EDM_OPERATION_MAX_NUM 64
+
 #define CHECK_RETVAL(action)                   \
        do {                                    \
                int __retval = (action);        \
 #define CHECK_RETVAL(action)                   \
        do {                                    \
                int __retval = (action);        \
@@ -62,18 +63,11 @@ enum nds32_debug_reason {
        NDS32_DEBUG_LOAD_STORE_GLOBAL_STOP,
 };
 
        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 {
 #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,
        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;
 
        /** 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 */
        bool direct_access_local_memory;
 
        /** Support ACC_CTL register */
@@ -173,10 +168,10 @@ struct nds32_memory {
        int dlm_end;
 
        /** Memory access method */
        int dlm_end;
 
        /** Memory access method */
-       enum aice_memory_access access_channel;
+       enum nds_memory_access access_channel;
 
        /** Memory access mode */
 
        /** Memory access mode */
-       enum aice_memory_mode mode;
+       enum nds_memory_select mode;
 
        /** Address translation */
        bool address_translation;
 
        /** 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);
 
        /** 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 */
        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 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 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;
 
        /** 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;
 
        /** 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;
 
        /** 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;
 
        /** 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;
 
        /** Backpointer to the target. */
        struct target *target;
 
@@ -343,32 +349,33 @@ struct nds32_reg {
        bool enable;
 };
 
        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,
 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,
 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,
 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,
 
 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,
 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,
 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,
 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,
 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);
 
 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_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_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,
 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,
 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,
 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,
 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_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_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)
 
 /** 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  *
  *   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  *
  *   Hsiangkai Wang <hkwang@andestech.com>                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
 #define __NDS32_INSN_H__
 
 
 #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 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))
 #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 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 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 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 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 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 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;
 
 /* 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  *
  *   Hsiangkai Wang <hkwang@andestech.com>                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
 #include "config.h"
 #endif
 
 #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];
 #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,
 
 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;
 {
        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(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);
 
        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;
 }
 {
        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  *
  *   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 {
 #define NDS32_REGISTER_DISABLE         (0x0)
 
 enum nds32_reg_number_s {
-       /* general registers */
-       R0 = 0,
+       R0 = 0, /* general registers */
        R1,
        R2,
        R3,
        R1,
        R2,
        R3,
@@ -64,9 +63,7 @@ enum nds32_reg_number_s {
        D1HI,
        ITB,
        IFC_LP,
        D1HI,
        ITB,
        IFC_LP,
-
-       /* system registers */
-       CR0,
+       CR0, /* system registers */
        CR1,
        CR2,
        CR3,
        CR1,
        CR2,
        CR3,
@@ -99,6 +96,11 @@ enum nds32_reg_number_s {
        IR23,
        IR24,
        IR25,
        IR23,
        IR24,
        IR25,
+       IR26,
+       IR27,
+       IR28,
+       IR29,
+       IR30,
        MR0,
        MR1,
        MR2,
        MR0,
        MR1,
        MR2,
@@ -180,9 +182,7 @@ enum nds32_reg_number_s {
        IDR0,
        IDR1,
        SECUR0,
        IDR0,
        IDR1,
        SECUR0,
-
-       /* audio registers */
-       D0L24,
+       D0L24, /* audio registers */
        D1L24,
        I0,
        I1,
        D1L24,
        I0,
        I1,
@@ -214,9 +214,7 @@ enum nds32_reg_number_s {
        CBE1,
        CBE2,
        CBE3,
        CBE1,
        CBE2,
        CBE3,
-
-       /* fpu */
-       FPCSR,
+       FPCSR, /* fpu */
        FPCFG,
        FS0,
        FS1,
        FPCFG,
        FS0,
        FS1,
@@ -310,11 +308,19 @@ struct nds32_reg_s {
        uint8_t size;
 };
 
        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);
 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
 
 #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 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,
 
 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,
        &testee_target,
        &avr32_ap7k_target,
        &hla_target,
+       &nds32_v2_target,
+       &nds32_v3_target,
+       &nds32_v3m_target,
        NULL,
 };
 
        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

Linking to existing account procedure

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

SSH host keys fingerprints

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