aboutsummaryrefslogtreecommitdiff
path: root/src/target
diff options
context:
space:
mode:
authorHsiangkai Wang <hsiangkai@gmail.com>2013-02-05 11:55:37 +0800
committerSpencer Oliver <spen@spen-soft.co.uk>2013-06-05 19:27:35 +0000
commitcf8a3c3d7075abad3c88cd604f8add4d06898abc (patch)
tree56f8b5794fd385ba7ba4a6617c214a9516a443b5 /src/target
parentceb402dc9e903d2f3f6bc8125dfed9d82b83d2d1 (diff)
downloadriscv-openocd-cf8a3c3d7075abad3c88cd604f8add4d06898abc.zip
riscv-openocd-cf8a3c3d7075abad3c88cd604f8add4d06898abc.tar.gz
riscv-openocd-cf8a3c3d7075abad3c88cd604f8add4d06898abc.tar.bz2
nds32: add new target type nds32_v2, nds32_v3, nds32_v3m
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>
Diffstat (limited to 'src/target')
-rw-r--r--src/target/Makefile.am21
-rw-r--r--src/target/nds32.c2156
-rw-r--r--src/target/nds32.h105
-rw-r--r--src/target/nds32_aice.c157
-rw-r--r--src/target/nds32_aice.h160
-rw-r--r--src/target/nds32_cmd.c1106
-rw-r--r--src/target/nds32_cmd.h27
-rw-r--r--src/target/nds32_disassembler.c3637
-rw-r--r--src/target/nds32_disassembler.h58
-rw-r--r--src/target/nds32_edm.h2
-rw-r--r--src/target/nds32_insn.h50
-rw-r--r--src/target/nds32_reg.c51
-rw-r--r--src/target/nds32_reg.h30
-rw-r--r--src/target/nds32_tlb.c80
-rw-r--r--src/target/nds32_tlb.h48
-rw-r--r--src/target/nds32_v2.c763
-rw-r--r--src/target/nds32_v2.h44
-rw-r--r--src/target/nds32_v3.c522
-rw-r--r--src/target/nds32_v3.h46
-rw-r--r--src/target/nds32_v3_common.c492
-rw-r--r--src/target/nds32_v3_common.h63
-rw-r--r--src/target/nds32_v3m.c510
-rw-r--r--src/target/nds32_v3m.h53
-rw-r--r--src/target/target.c6
24 files changed, 10093 insertions, 94 deletions
diff --git a/src/target/Makefile.am b/src/target/Makefile.am
index 8e9dfb6..027cc8e 100644
--- a/src/target/Makefile.am
+++ b/src/target/Makefile.am
@@ -109,7 +109,16 @@ MIPS32_SRC = \
mips_ejtag.c
NDS32_SRC = \
- nds32_reg.c
+ nds32.c \
+ nds32_reg.c \
+ nds32_cmd.c \
+ nds32_disassembler.c \
+ nds32_tlb.c \
+ nds32_v2.c \
+ nds32_v3_common.c \
+ nds32_v3.c \
+ nds32_v3m.c \
+ nds32_aice.c
noinst_HEADERS = \
@@ -168,9 +177,17 @@ noinst_HEADERS = \
avr32_mem.h \
avr32_regs.h \
nds32.h \
+ nds32_cmd.h \
+ nds32_disassembler.h \
nds32_edm.h \
nds32_insn.h \
- nds32_reg.h
+ nds32_reg.h \
+ nds32_tlb.h \
+ nds32_v2.h \
+ nds32_v3_common.h \
+ nds32_v3.h \
+ nds32_v3m.h \
+ nds32_aice.h
ocddatadir = $(pkglibdir)
nobase_dist_ocddata_DATA =
diff --git a/src/target/nds32.c b/src/target/nds32.c
new file mode 100644
index 0000000..2d47709
--- /dev/null
+++ b/src/target/nds32.c
@@ -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;
+}
diff --git a/src/target/nds32.h b/src/target/nds32.h
index cec8ae0..f585c2d 100644
--- a/src/target/nds32.h
+++ b/src/target/nds32.h
@@ -1,5 +1,5 @@
/***************************************************************************
- * Copyright (C) 2013 by Andes Technology *
+ * Copyright (C) 2013 Andes Technology *
* Hsiangkai Wang <hkwang@andestech.com> *
* *
* This program is free software; you can redistribute it and/or modify *
@@ -22,7 +22,6 @@
#define __NDS32_H__
#include <jtag/jtag.h>
-#include <jtag/aice/aice_port.h>
#include "target.h"
#include "target_type.h"
#include "register.h"
@@ -31,6 +30,8 @@
#include "nds32_insn.h"
#include "nds32_edm.h"
+#define NDS32_EDM_OPERATION_MAX_NUM 64
+
#define CHECK_RETVAL(action) \
do { \
int __retval = (action); \
@@ -62,18 +63,11 @@ enum nds32_debug_reason {
NDS32_DEBUG_LOAD_STORE_GLOBAL_STOP,
};
-enum nds32_tdesc_type {
- NDS32_CORE_TDESC = 0,
- NDS32_SYSTEM_TDESC,
- NDS32_AUDIO_TDESC,
- NDS32_FPU_TDESC,
- NDS32_NUM_TDESC,
-};
-
#define NDS32_STRUCT_STAT_SIZE 60
#define NDS32_STRUCT_TIMEVAL_SIZE 8
enum nds32_syscall_id {
+ NDS32_SYSCALL_UNDEFINED = 0,
NDS32_SYSCALL_EXIT = 1,
NDS32_SYSCALL_OPEN = 2,
NDS32_SYSCALL_CLOSE = 3,
@@ -100,7 +94,8 @@ struct nds32_edm {
/** The number of hardware breakpoints */
int breakpoint_num;
- /** EDM_CFG.DALM, indicate if direct local memory access feature is supported or not */
+ /** EDM_CFG.DALM, indicate if direct local memory access
+ * feature is supported or not */
bool direct_access_local_memory;
/** Support ACC_CTL register */
@@ -173,10 +168,10 @@ struct nds32_memory {
int dlm_end;
/** Memory access method */
- enum aice_memory_access access_channel;
+ enum nds_memory_access access_channel;
/** Memory access mode */
- enum aice_memory_mode mode;
+ enum nds_memory_select mode;
/** Address translation */
bool address_translation;
@@ -275,7 +270,7 @@ struct nds32 {
/** Backup target registers may be modified in debug state */
int (*enter_debug_state)(struct nds32 *nds32, bool enable_watchpoint);
- /** Get address hitted watchpoint */
+ /** Get address hit watchpoint */
int (*get_watched_address)(struct nds32 *nds32, uint32_t *address, uint32_t reason);
/** maximum interrupt level */
@@ -289,24 +284,28 @@ struct nds32 {
/** Flag reporting whether virtual hosting is active. */
bool virtual_hosting;
- /** Flag reporting whether continue/step hits syscall or not */
- bool hit_syscall;
-
- /** Value to be returned by virtual hosting SYS_ERRNO request. */
- int virtual_hosting_errno;
-
- /** Flag reporting whether syscall is aborted */
- bool virtual_hosting_ctrl_c;
-
- /** Record syscall ID for other operations to do special processing for target */
- int active_syscall_id;
-
/** Flag reporting whether global stop is active. */
bool global_stop;
+ /** Flag reporting whether to use soft-reset-halt or not as issuing reset-halt. */
+ bool soft_reset_halt;
+
/** reset-halt as target examine */
bool reset_halt_as_examine;
+ /** backup/restore target EDM_CTL value. As debugging target debug
+ * handler, it should be true. */
+ bool keep_target_edm_ctl;
+
+ /** always use word-aligned address to access memory */
+ bool word_access_mem;
+
+ /** EDM passcode for debugging secure MCU */
+ char *edm_passcode;
+
+ /** current privilege_level if using secure MCU. value 0 is the highest level. */
+ int privilege_level;
+
/** Period to wait after SRST. */
uint32_t boot_time;
@@ -322,12 +321,19 @@ struct nds32 {
/** Flag to indicate fpu-extension is enabled or not */
bool fpu_enable;
+ /* Andes Core has mixed endian model. Instruction is always big-endian.
+ * Data may be big or little endian. Device registers may have different
+ * endian from data and instruction. */
+ /** Endian of data memory */
+ enum target_endianness data_endian;
+
+ /** Endian of device registers */
+ enum target_endianness device_reg_endian;
+
/** Flag to indicate if auto convert software breakpoints to
* hardware breakpoints or not in ROM */
bool auto_convert_hw_bp;
- int (*setup_virtual_hosting)(struct target *target, int enable);
-
/** Backpointer to the target. */
struct target *target;
@@ -343,32 +349,33 @@ struct nds32_reg {
bool enable;
};
+struct nds32_edm_operation {
+ uint32_t reg_no;
+ uint32_t value;
+};
+
extern int nds32_config(struct nds32 *nds32);
extern int nds32_init_arch_info(struct target *target, struct nds32 *nds32);
extern int nds32_full_context(struct nds32 *nds32);
extern int nds32_arch_state(struct target *target);
extern int nds32_add_software_breakpoint(struct target *target,
- struct breakpoint *breakpoint);
+ struct breakpoint *breakpoint);
extern int nds32_remove_software_breakpoint(struct target *target,
- struct breakpoint *breakpoint);
+ struct breakpoint *breakpoint);
-extern int nds32_get_gdb_general_reg_list(struct target *target,
- struct reg **reg_list[], int *reg_list_size);
extern int nds32_get_gdb_reg_list(struct target *target,
- struct reg **reg_list[], int *reg_list_size);
-extern int nds32_get_gdb_target_description(struct target *target, char **xml,
- char *annex, int32_t offset, uint32_t length);
+ struct reg **reg_list[], int *reg_list_size);
extern int nds32_write_buffer(struct target *target, uint32_t address,
- uint32_t size, const uint8_t *buffer);
+ uint32_t size, const uint8_t *buffer);
extern int nds32_read_buffer(struct target *target, uint32_t address,
- uint32_t size, uint8_t *buffer);
+ uint32_t size, uint8_t *buffer);
extern int nds32_bulk_write_memory(struct target *target,
- uint32_t address, uint32_t count, const uint8_t *buffer);
+ uint32_t address, uint32_t count, const uint8_t *buffer);
extern int nds32_read_memory(struct target *target, uint32_t address,
- uint32_t size, uint32_t count, uint8_t *buffer);
+ uint32_t size, uint32_t count, uint8_t *buffer);
extern int nds32_write_memory(struct target *target, uint32_t address,
- uint32_t size, uint32_t count, const uint8_t *buffer);
+ uint32_t size, uint32_t count, const uint8_t *buffer);
extern int nds32_init_register_table(struct nds32 *nds32);
extern int nds32_init_memory_info(struct nds32 *nds32);
@@ -377,31 +384,27 @@ extern int nds32_get_mapped_reg(struct nds32 *nds32, unsigned regnum, uint32_t *
extern int nds32_set_mapped_reg(struct nds32 *nds32, unsigned regnum, uint32_t value);
extern int nds32_edm_config(struct nds32 *nds32);
-extern int nds32_check_extension(struct nds32 *nds32);
extern int nds32_cache_sync(struct target *target, uint32_t address, uint32_t length);
extern int nds32_mmu(struct target *target, int *enabled);
-extern int nds32_virtual_to_physical(struct target *target, uint32_t address, uint32_t *physical);
+extern int nds32_virtual_to_physical(struct target *target, uint32_t address,
+ uint32_t *physical);
extern int nds32_read_phys_memory(struct target *target, uint32_t address,
- uint32_t size, uint32_t count, uint8_t *buffer);
+ uint32_t size, uint32_t count, uint8_t *buffer);
extern int nds32_write_phys_memory(struct target *target, uint32_t address,
- uint32_t size, uint32_t count, const uint8_t *buffer);
-extern int nds32_soft_reset_halt(struct target *target);
+ uint32_t size, uint32_t count, const uint8_t *buffer);
extern uint32_t nds32_nextpc(struct nds32 *nds32, int current, uint32_t address);
extern int nds32_examine_debug_reason(struct nds32 *nds32);
extern int nds32_step(struct target *target, int current,
- uint32_t address, int handle_breakpoints);
+ uint32_t address, int handle_breakpoints);
extern int nds32_target_state(struct nds32 *nds32, enum target_state *state);
extern int nds32_halt(struct target *target);
extern int nds32_poll(struct target *target);
extern int nds32_resume(struct target *target, int current,
- uint32_t address, int handle_breakpoints, int debug_execution);
+ uint32_t address, int handle_breakpoints, int debug_execution);
extern int nds32_assert_reset(struct target *target);
extern int nds32_init(struct nds32 *nds32);
-extern int nds32_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info);
-extern int nds32_gdb_fileio_write_memory(struct nds32 *nds32, uint32_t address,
- uint32_t size, const uint8_t *buffer);
-extern int nds32_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c);
extern int nds32_reset_halt(struct nds32 *nds32);
+extern int nds32_login(struct nds32 *nds32);
/** Convert target handle to generic Andes target state handle. */
static inline struct nds32 *target_to_nds32(struct target *target)
diff --git a/src/target/nds32_aice.c b/src/target/nds32_aice.c
new file mode 100644
index 0000000..78ae8c2
--- /dev/null
+++ b/src/target/nds32_aice.c
@@ -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
index 0000000..abea8df
--- /dev/null
+++ b/src/target/nds32_aice.h
@@ -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
index 0000000..a16308e
--- /dev/null
+++ b/src/target/nds32_cmd.c
@@ -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
index 0000000..44d361e
--- /dev/null
+++ b/src/target/nds32_cmd.h
@@ -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
index 0000000..d859e0c
--- /dev/null
+++ b/src/target/nds32_disassembler.c
@@ -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
index 0000000..ac0222e
--- /dev/null
+++ b/src/target/nds32_disassembler.h
@@ -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__ */
diff --git a/src/target/nds32_edm.h b/src/target/nds32_edm.h
index 3682b38..1eab7b0 100644
--- a/src/target/nds32_edm.h
+++ b/src/target/nds32_edm.h
@@ -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 *
diff --git a/src/target/nds32_insn.h b/src/target/nds32_insn.h
index ca0e4dd..08d3c5c 100644
--- a/src/target/nds32_insn.h
+++ b/src/target/nds32_insn.h
@@ -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 *
@@ -21,13 +21,13 @@
#define __NDS32_INSN_H__
-#define NOP (0x40000009)
-#define DSB (0x64000008)
-#define ISB (0x64000009)
+#define NOP (0x40000009)
+#define DSB (0x64000008)
+#define ISB (0x64000009)
#define BEQ_MINUS_12 (0x4C000000 | 0x3FFA)
-#define MTSR_DTR(a) (0x64000003 | (((0x03 << 7) | (0x08 << 3) | (0x00 << 0)) << 10) | (((a) & 0x1F) << 20))
-#define MFSR_DTR(a) (0x64000002 | (((0x03 << 7) | (0x08 << 3) | (0x00 << 0)) << 10) | (((a) & 0x1F) << 20))
-#define SETHI(a, b) (0x46000000 | ((a) << 20) | (b))
+#define MTSR_DTR(a) (0x64000003 | (((0x03 << 7) | (0x08 << 3) | (0x00 << 0)) << 10) | (((a) & 0x1F) << 20))
+#define MFSR_DTR(a) (0x64000002 | (((0x03 << 7) | (0x08 << 3) | (0x00 << 0)) << 10) | (((a) & 0x1F) << 20))
+#define SETHI(a, b) (0x46000000 | ((a) << 20) | (b))
#define ORI(a, b, c) (0x58000000 | ((a) << 20) | ((b) << 15) | (c))
#define LWI_BI(a, b) (0x0C000001 | (a << 20) | (b << 15))
#define LHI_BI(a, b) (0x0A000001 | (a << 20) | (b << 15))
@@ -35,7 +35,7 @@
#define SWI_BI(a, b) (0x1C000001 | (a << 20) | (b << 15))
#define SHI_BI(a, b) (0x1A000001 | (a << 20) | (b << 15))
#define SBI_BI(a, b) (0x18000001 | (a << 20) | (b << 15))
-#define IRET (0x64000004)
+#define IRET (0x64000004)
#define L1D_IX_WB(a) (0x64000021 | ((a) << 15))
#define L1D_IX_INVAL(a) (0x64000001 | ((a) << 15))
#define L1D_VA_INVAL(a) (0x64000101 | ((a) << 15))
@@ -47,31 +47,31 @@
#define L1I_IX_RTAG(a) (0x64000261 | ((a) << 15))
#define L1I_IX_RWD(a) (0x64000281 | ((a) << 15))
#define L1I_VA_FILLCK(a) (0x64000361 | ((a) << 15))
-#define ISYNC(a) (0x6400000d | ((a) << 20))
-#define MSYNC_STORE (0x6400002c)
-#define MSYNC_ALL (0x6400000c)
-#define TLBOP_TARGET_READ(a) (0x6400000e | ((a) << 15))
-#define TLBOP_TARGET_PROBE(a, b) (0x640000AE | ((a) << 20) | ((b) << 15))
+#define ISYNC(a) (0x6400000d | ((a) << 20))
+#define MSYNC_STORE (0x6400002c)
+#define MSYNC_ALL (0x6400000c)
+#define TLBOP_TARGET_READ(a) (0x6400000e | ((a) << 15))
+#define TLBOP_TARGET_PROBE(a, b) (0x640000AE | ((a) << 20) | ((b) << 15))
#define MFCPD(a, b, c) (0x6A000041 | (a << 20) | (b << 8) | (c << 4))
#define MFCPW(a, b, c) (0x6A000001 | (a << 20) | (b << 8) | (c << 4))
#define MTCPD(a, b, c) (0x6A000049 | (a << 20) | (b << 8) | (c << 4))
#define MTCPW(a, b, c) (0x6A000009 | (a << 20) | (b << 8) | (c << 4))
-#define MOVI_(a, b) (0x44000000 | (a << 20) | (b & 0xFFFFF))
+#define MOVI_(a, b) (0x44000000 | (a << 20) | (b & 0xFFFFF))
#define MFUSR_G0(a, b) (0x42000020 | (a << 20) | (b << 15))
#define MTUSR_G0(a, b) (0x42000021 | (a << 20) | (b << 15))
-#define MFSR(a, b) (0x64000002 | (b << 10) | (a << 20))
-#define MTSR(a, b) (0x64000003 | (b << 10) | (a << 20))
-#define AMFAR(a, b) (0x60300060 | (a << 15) | b)
-#define AMTAR(a, b) (0x60300040 | (a << 15) | b)
+#define MFSR(a, b) (0x64000002 | (b << 10) | (a << 20))
+#define MTSR(a, b) (0x64000003 | (b << 10) | (a << 20))
+#define AMFAR(a, b) (0x60300060 | (a << 15) | b)
+#define AMTAR(a, b) (0x60300040 | (a << 15) | b)
#define AMFAR2(a, b) (0x60300260 | (a << 15) | b)
#define AMTAR2(a, b) (0x60300240 | (a << 15) | b)
-#define FMFCSR (0x6A000701)
-#define FMTCSR (0x6A000709)
-#define FMFCFG (0x6A000301)
-#define FMFSR(a, b) (0x6A000001 | ((a) << 20) | ((b) << 15))
-#define FMTSR(a, b) (0x6A000009 | ((a) << 20) | ((b) << 15))
-#define FMFDR(a, b) (0x6A000041 | ((a) << 20) | ((b) << 15))
-#define FMTDR(a, b) (0x6A000049 | ((a) << 20) | ((b) << 15))
+#define FMFCSR (0x6A000701)
+#define FMTCSR (0x6A000709)
+#define FMFCFG (0x6A000301)
+#define FMFSR(a, b) (0x6A000001 | ((a) << 20) | ((b) << 15))
+#define FMTSR(a, b) (0x6A000009 | ((a) << 20) | ((b) << 15))
+#define FMFDR(a, b) (0x6A000041 | ((a) << 20) | ((b) << 15))
+#define FMTDR(a, b) (0x6A000049 | ((a) << 20) | ((b) << 15))
/* break instructions */
extern const int NDS32_BREAK_16;
diff --git a/src/target/nds32_reg.c b/src/target/nds32_reg.c
index a55df79..72ac479 100644
--- a/src/target/nds32_reg.c
+++ b/src/target/nds32_reg.c
@@ -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 *
@@ -21,14 +21,28 @@
#include "config.h"
#endif
+#include <helper/log.h>
#include "nds32_reg.h"
static bool nds32_reg_init_done;
static struct nds32_reg_s nds32_regs[TOTAL_REG_NUM];
+static struct nds32_reg_exception_s nds32_ex_reg_values[] = {
+ {IR0, 3, 0x3, 2},
+ {IR0, 3, 0x3, 3},
+ {IR1, 3, 0x3, 2},
+ {IR1, 3, 0x3, 3},
+ {IR2, 3, 0x3, 2},
+ {IR2, 3, 0x3, 3},
+ {MR3, 1, 0x7, 0},
+ {MR3, 1, 0x7, 4},
+ {MR3, 1, 0x7, 6},
+ {MR3, 8, 0x7, 3},
+ {0, 0, 0, 0},
+};
static inline void nds32_reg_set(uint32_t number, const char *simple_mnemonic,
- const char *symbolic_mnemonic, uint32_t sr_index,
- enum nds32_reg_type_s type, uint8_t size)
+ const char *symbolic_mnemonic, uint32_t sr_index,
+ enum nds32_reg_type_s type, uint8_t size)
{
nds32_regs[number].simple_mnemonic = simple_mnemonic;
nds32_regs[number].symbolic_mnemonic = symbolic_mnemonic;
@@ -117,6 +131,11 @@ void nds32_reg_init(void)
nds32_reg_set(IR23, "ir23", "", SRIDX(1, 10, 5), NDS32_REG_TYPE_IR, 32);
nds32_reg_set(IR24, "ir24", "", SRIDX(1, 10, 6), NDS32_REG_TYPE_IR, 32);
nds32_reg_set(IR25, "ir25", "", SRIDX(1, 10, 7), NDS32_REG_TYPE_IR, 32);
+ nds32_reg_set(IR26, "ir26", "", SRIDX(1, 8, 1), NDS32_REG_TYPE_IR, 32);
+ nds32_reg_set(IR27, "ir27", "", SRIDX(1, 9, 1), NDS32_REG_TYPE_IR, 32);
+ nds32_reg_set(IR28, "ir28", "", SRIDX(1, 11, 1), NDS32_REG_TYPE_IR, 32);
+ nds32_reg_set(IR29, "ir29", "", SRIDX(1, 9, 4), NDS32_REG_TYPE_IR, 32);
+ nds32_reg_set(IR30, "ir30", "", SRIDX(1, 1, 3), NDS32_REG_TYPE_IR, 32);
nds32_reg_set(MR0, "mr0", "MMU_CTL", SRIDX(2, 0, 0), NDS32_REG_TYPE_MR, 32);
nds32_reg_set(MR1, "mr1", "L1_PPTB", SRIDX(2, 1, 0), NDS32_REG_TYPE_MR, 32);
@@ -335,3 +354,29 @@ const char *nds32_reg_symbolic_name(uint32_t number)
{
return nds32_regs[number].symbolic_mnemonic;
}
+
+bool nds32_reg_exception(uint32_t number, uint32_t value)
+{
+ int i;
+ struct nds32_reg_exception_s *ex_reg_value;
+ uint32_t field_value;
+
+ i = 0;
+ while (nds32_ex_reg_values[i].reg_num != 0) {
+ ex_reg_value = nds32_ex_reg_values + i;
+
+ if (ex_reg_value->reg_num == number) {
+ field_value = (value >> ex_reg_value->ex_value_bit_pos) &
+ ex_reg_value->ex_value_mask;
+ if (field_value == ex_reg_value->ex_value) {
+ LOG_WARNING("It will generate exceptions as setting %d to %s",
+ value, nds32_regs[number].simple_mnemonic);
+ return true;
+ }
+ }
+
+ i++;
+ }
+
+ return false;
+}
diff --git a/src/target/nds32_reg.h b/src/target/nds32_reg.h
index a941941..1c61b61 100644
--- a/src/target/nds32_reg.h
+++ b/src/target/nds32_reg.h
@@ -1,5 +1,5 @@
/***************************************************************************
- * Copyright (C) 2013 by Andes Technology *
+ * Copyright (C) 2013 Andes Technology *
* Hsiangkai Wang <hkwang@andestech.com> *
* *
* This program is free software; you can redistribute it and/or modify *
@@ -24,8 +24,7 @@
#define NDS32_REGISTER_DISABLE (0x0)
enum nds32_reg_number_s {
- /* general registers */
- R0 = 0,
+ R0 = 0, /* general registers */
R1,
R2,
R3,
@@ -64,9 +63,7 @@ enum nds32_reg_number_s {
D1HI,
ITB,
IFC_LP,
-
- /* system registers */
- CR0,
+ CR0, /* system registers */
CR1,
CR2,
CR3,
@@ -99,6 +96,11 @@ enum nds32_reg_number_s {
IR23,
IR24,
IR25,
+ IR26,
+ IR27,
+ IR28,
+ IR29,
+ IR30,
MR0,
MR1,
MR2,
@@ -180,9 +182,7 @@ enum nds32_reg_number_s {
IDR0,
IDR1,
SECUR0,
-
- /* audio registers */
- D0L24,
+ D0L24, /* audio registers */
D1L24,
I0,
I1,
@@ -214,9 +214,7 @@ enum nds32_reg_number_s {
CBE1,
CBE2,
CBE3,
-
- /* fpu */
- FPCSR,
+ FPCSR, /* fpu */
FPCFG,
FS0,
FS1,
@@ -310,11 +308,19 @@ struct nds32_reg_s {
uint8_t size;
};
+struct nds32_reg_exception_s {
+ uint32_t reg_num;
+ uint32_t ex_value_bit_pos;
+ uint32_t ex_value_mask;
+ uint32_t ex_value;
+};
+
void nds32_reg_init(void);
uint32_t nds32_reg_sr_index(uint32_t number);
enum nds32_reg_type_s nds32_reg_type(uint32_t number);
uint8_t nds32_reg_size(uint32_t number);
const char *nds32_reg_simple_name(uint32_t number);
const char *nds32_reg_symbolic_name(uint32_t number);
+bool nds32_reg_exception(uint32_t number, uint32_t value);
#endif
diff --git a/src/target/nds32_tlb.c b/src/target/nds32_tlb.c
new file mode 100644
index 0000000..58322cf
--- /dev/null
+++ b/src/target/nds32_tlb.c
@@ -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
index 0000000..59e1157
--- /dev/null
+++ b/src/target/nds32_tlb.h
@@ -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
index 0000000..90961d7
--- /dev/null
+++ b/src/target/nds32_v2.c
@@ -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
index 0000000..b398055
--- /dev/null
+++ b/src/target/nds32_v2.h
@@ -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
index 0000000..dc0ca5a
--- /dev/null
+++ b/src/target/nds32_v3.c
@@ -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
index 0000000..7476b20
--- /dev/null
+++ b/src/target/nds32_v3.h
@@ -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
index 0000000..49d8413
--- /dev/null
+++ b/src/target/nds32_v3_common.c
@@ -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
index 0000000..c62da9a
--- /dev/null
+++ b/src/target/nds32_v3_common.h
@@ -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
index 0000000..1898732
--- /dev/null
+++ b/src/target/nds32_v3m.c
@@ -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
index 0000000..d72c2ad
--- /dev/null
+++ b/src/target/nds32_v3m.h
@@ -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__ */
diff --git a/src/target/target.c b/src/target/target.c
index ed1a2cc..bfa0db7 100644
--- a/src/target/target.c
+++ b/src/target/target.c
@@ -89,6 +89,9 @@ extern struct target_type dsp5680xx_target;
extern struct target_type testee_target;
extern struct target_type avr32_ap7k_target;
extern struct target_type hla_target;
+extern struct target_type nds32_v2_target;
+extern struct target_type nds32_v3_target;
+extern struct target_type nds32_v3m_target;
static struct target_type *target_types[] = {
&arm7tdmi_target,
@@ -113,6 +116,9 @@ static struct target_type *target_types[] = {
&testee_target,
&avr32_ap7k_target,
&hla_target,
+ &nds32_v2_target,
+ &nds32_v3_target,
+ &nds32_v3m_target,
NULL,
};