aice: add Andes AICE support 56/1256/13
authorHsiangkai Wang <hsiangkai@gmail.com>
Tue, 5 Feb 2013 01:34:18 +0000 (09:34 +0800)
committerSpencer Oliver <spen@spen-soft.co.uk>
Wed, 5 Jun 2013 19:27:23 +0000 (19:27 +0000)
Andes AICE uses USB to transfer packets between OpenOCD and AICE.
It uses high-level USB commands to control targets instead of using
JTAG signals. I define an interface as aice_port_api_s. It contains
all basic operations needed by target-dependent code.

Change-Id: I117bc4f938fab2732e44c509ea68b30172d6fdb9
Signed-off-by: Hsiangkai Wang <hsiangkai@gmail.com>
Reviewed-on: http://openocd.zylin.com/1256
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
21 files changed:
configure.ac
src/jtag/Makefile.am
src/jtag/aice/Makefile.am [new file with mode: 0644]
src/jtag/aice/aice_interface.c [new file with mode: 0644]
src/jtag/aice/aice_interface.h [new file with mode: 0644]
src/jtag/aice/aice_pipe.c [new file with mode: 0644]
src/jtag/aice/aice_pipe.h [new file with mode: 0644]
src/jtag/aice/aice_port.c [new file with mode: 0644]
src/jtag/aice/aice_port.h [new file with mode: 0644]
src/jtag/aice/aice_transport.c [new file with mode: 0644]
src/jtag/aice/aice_transport.h [new file with mode: 0644]
src/jtag/aice/aice_usb.c [new file with mode: 0644]
src/jtag/aice/aice_usb.h [new file with mode: 0644]
src/jtag/interfaces.c
src/target/Makefile.am
src/target/nds32.h [new file with mode: 0644]
src/target/nds32_edm.h [new file with mode: 0644]
src/target/nds32_insn.h [new file with mode: 0644]
src/target/nds32_reg.c [new file with mode: 0644]
src/target/nds32_reg.h [new file with mode: 0644]
tcl/interface/nds32-aice.cfg [new file with mode: 0644]

index 8afe7112061179918f4c2634004baa7905e91c79..7adce9eae8f9132a378442a8a6d89fd2260639f3 100644 (file)
@@ -507,6 +507,10 @@ AC_ARG_ENABLE([libusb0],
   AS_HELP_STRING([--enable-libusb0], [Use libusb-0.1 library for USB JTAG devices]),
   [check_libusb0=$enableval], [check_libusb0=no])
 
   AS_HELP_STRING([--enable-libusb0], [Use libusb-0.1 library for USB JTAG devices]),
   [check_libusb0=$enableval], [check_libusb0=no])
 
+AC_ARG_ENABLE([aice],
+  AS_HELP_STRING([--enable-aice], [Enable building support for the Andes JTAG Programmer]),
+  [build_aice=$enableval], [build_aice=no])
+
 build_minidriver=no
 AC_MSG_CHECKING([whether to enable ZY1000 minidriver])
 if test $build_zy1000 = yes; then
 build_minidriver=no
 AC_MSG_CHECKING([whether to enable ZY1000 minidriver])
 if test $build_zy1000 = yes; then
@@ -762,6 +766,12 @@ else
   AC_DEFINE([BUILD_JLINK], [0], [0 if you don't want the J-Link JTAG driver.])
 fi
 
   AC_DEFINE([BUILD_JLINK], [0], [0 if you don't want the J-Link JTAG driver.])
 fi
 
+if test $build_aice = yes; then
+  AC_DEFINE([BUILD_AICE], [1], [1 if you want the AICE JTAG driver.])
+else
+  AC_DEFINE([BUILD_AICE], [0], [0 if you don't want the AICE JTAG driver.])
+fi
+
 if test $build_vsllink = yes; then
   AC_DEFINE([BUILD_VSLLINK], [1], [1 if you want the Versaloon-Link JTAG driver.])
 else
 if test $build_vsllink = yes; then
   AC_DEFINE([BUILD_VSLLINK], [1], [1 if you want the Versaloon-Link JTAG driver.])
 else
@@ -1137,7 +1147,8 @@ fi
 # check for usb.h when a driver will require it
 build_usb=no
 if test $build_vsllink = yes -o $build_usbprog = yes -o \
 # check for usb.h when a driver will require it
 build_usb=no
 if test $build_vsllink = yes -o $build_usbprog = yes -o \
-  $build_rlink = yes -o $build_ulink = yes -o $build_armjtagew = yes
+  $build_rlink = yes -o $build_ulink = yes -o $build_armjtagew = yes -o \
+  $build_aice = yes
 then
   build_usb=yes
 fi
 then
   build_usb=yes
 fi
@@ -1189,6 +1200,7 @@ AM_CONDITIONAL([PRESTO_DRIVER], [test $build_presto_ftd2xx = yes -o $build_prest
 AM_CONDITIONAL([USBPROG], [test $build_usbprog = yes])
 AM_CONDITIONAL([OOCD_TRACE], [test $build_oocd_trace = yes])
 AM_CONDITIONAL([JLINK], [test $build_jlink = yes])
 AM_CONDITIONAL([USBPROG], [test $build_usbprog = yes])
 AM_CONDITIONAL([OOCD_TRACE], [test $build_oocd_trace = yes])
 AM_CONDITIONAL([JLINK], [test $build_jlink = yes])
+AM_CONDITIONAL([AICE], [test $build_aice = yes])
 AM_CONDITIONAL([VSLLINK], [test $build_vsllink = yes])
 AM_CONDITIONAL([RLINK], [test $build_rlink = yes])
 AM_CONDITIONAL([ULINK], [test $build_ulink = yes])
 AM_CONDITIONAL([VSLLINK], [test $build_vsllink = yes])
 AM_CONDITIONAL([RLINK], [test $build_rlink = yes])
 AM_CONDITIONAL([ULINK], [test $build_ulink = yes])
@@ -1313,6 +1325,7 @@ AC_CONFIG_FILES([
   src/jtag/drivers/Makefile
   src/jtag/drivers/usb_blaster/Makefile
   src/jtag/hla/Makefile
   src/jtag/drivers/Makefile
   src/jtag/drivers/usb_blaster/Makefile
   src/jtag/hla/Makefile
+  src/jtag/aice/Makefile
   src/transport/Makefile
   src/xsvf/Makefile
   src/svf/Makefile
   src/transport/Makefile
   src/xsvf/Makefile
   src/svf/Makefile
index 687f11fc8fce24e6beae2454082ea2b5f3d513d9..db3e6ff2a4b193369fd7201b63c5d34e632d58a0 100644 (file)
@@ -44,6 +44,11 @@ SUBDIRS += hla
 libjtag_la_LIBADD += $(top_builddir)/src/jtag/hla/libocdhla.la
 endif
 
 libjtag_la_LIBADD += $(top_builddir)/src/jtag/hla/libocdhla.la
 endif
 
+if AICE
+SUBDIRS += aice
+libjtag_la_LIBADD += $(top_builddir)/src/jtag/aice/libocdaice.la
+endif
+
 SUBDIRS += drivers
 libjtag_la_LIBADD += $(top_builddir)/src/jtag/drivers/libocdjtagdrivers.la
 
 SUBDIRS += drivers
 libjtag_la_LIBADD += $(top_builddir)/src/jtag/drivers/libocdjtagdrivers.la
 
diff --git a/src/jtag/aice/Makefile.am b/src/jtag/aice/Makefile.am
new file mode 100644 (file)
index 0000000..38c441e
--- /dev/null
@@ -0,0 +1,27 @@
+include $(top_srcdir)/common.mk
+
+AM_CPPFLAGS += -I$(top_srcdir)/src/jtag/drivers
+
+noinst_LTLIBRARIES = libocdaice.la
+
+libocdaice_la_SOURCES = \
+       $(AICEFILES)
+
+AICEFILES =
+
+if AICE
+AICEFILES += aice_transport.c
+AICEFILES += aice_interface.c
+AICEFILES += aice_port.c
+AICEFILES += aice_usb.c
+AICEFILES += aice_pipe.c
+endif
+
+noinst_HEADERS = \
+       aice_transport.h \
+       aice_interface.h \
+       aice_port.h \
+       aice_usb.h \
+       aice_pipe.h
+
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
diff --git a/src/jtag/aice/aice_interface.c b/src/jtag/aice/aice_interface.c
new file mode 100644 (file)
index 0000000..bad3c3d
--- /dev/null
@@ -0,0 +1,500 @@
+/***************************************************************************
+ *   Copyright (C) 2013 by 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 <jtag/interface.h>
+#include <jtag/commands.h>
+#include <transport/transport.h>
+#include <target/target.h>
+#include <jtag/aice/aice_transport.h>
+#include <jtag/drivers/libusb_common.h>
+#include "aice_usb.h"
+
+#define AICE_KHZ_TO_SPEED_MAP_SIZE     16
+static int aice_khz_to_speed_map[AICE_KHZ_TO_SPEED_MAP_SIZE] = {
+       30000,
+       15000,
+       7500,
+       3750,
+       1875,
+       937,
+       468,
+       234,
+       48000,
+       24000,
+       12000,
+       6000,
+       3000,
+       1500,
+       750,
+       375,
+};
+
+static struct aice_port_s aice;
+
+/***************************************************************************/
+/* External interface implementation */
+#define AICE_MAX_TARGET_ID_CODES       0x10
+static uint32_t aice_target_id_codes[AICE_MAX_TARGET_ID_CODES];
+static uint8_t aice_num_of_target_id_codes;
+
+/***************************************************************************/
+/* AICE operations */
+int aice_init_target(struct target *t)
+{
+       int res;
+
+       LOG_DEBUG("aice_init_target");
+
+       if (aice_num_of_target_id_codes == 0) {
+               res = aice.port->api->idcode(aice_target_id_codes, &aice_num_of_target_id_codes);
+               if (res != ERROR_OK) {
+                       LOG_ERROR("<-- TARGET ERROR! Failed to identify AndesCore "
+                                       "JTAG Manufacture ID in the JTAG scan chain. "
+                                       "Failed to access EDM registers. -->");
+                       return res;
+               }
+       }
+
+       t->tap->idcode = aice_target_id_codes[t->tap->abs_chain_position];
+
+       unsigned ii, limit = t->tap->expected_ids_cnt;
+       int found = 0;
+
+       for (ii = 0; ii < limit; ii++) {
+               uint32_t expected = t->tap->expected_ids[ii];
+
+               /* treat "-expected-id 0" as a "don't-warn" wildcard */
+               if (!expected || (t->tap->idcode == expected)) {
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (found == 0) {
+               LOG_ERROR
+                       ("aice_init_target: target not found: idcode: %x ",
+                        t->tap->idcode);
+               return ERROR_FAIL;
+       }
+
+       t->tap->priv = &aice;
+       t->tap->hasidcode = 1;
+
+       return ERROR_OK;
+}
+
+/***************************************************************************/
+/* End of External interface implementation */
+
+/* initial aice
+ * 1. open usb
+ * 2. get/show version number
+ * 3. reset
+ */
+static int aice_init(void)
+{
+       if (ERROR_OK != aice.port->api->open(&(aice.param))) {
+               LOG_ERROR("Cannot find AICE Interface! Please check "
+                               "connection and permissions.");
+               return ERROR_JTAG_INIT_FAILED;
+       }
+
+       aice.port->api->set_retry_times(aice.retry_times);
+       aice.port->api->set_count_to_check_dbger(aice.count_to_check_dbger);
+
+       LOG_INFO("AICE JTAG Interface ready");
+
+       return ERROR_OK;
+}
+
+/* cleanup aice resource
+ * close usb
+ */
+static int aice_quit(void)
+{
+       aice.port->api->close();
+       return ERROR_OK;
+}
+
+static int aice_execute_reset(struct jtag_command *cmd)
+{
+       static int last_trst;
+       int retval = ERROR_OK;
+
+       DEBUG_JTAG_IO("reset trst: %i", cmd->cmd.reset->trst);
+
+       if (cmd->cmd.reset->trst != last_trst) {
+               if (cmd->cmd.reset->trst)
+                       retval = aice.port->api->reset();
+
+               last_trst = cmd->cmd.reset->trst;
+       }
+
+       return retval;
+}
+
+static int aice_execute_command(struct jtag_command *cmd)
+{
+       int retval;
+
+       switch (cmd->type) {
+               case JTAG_RESET:
+                       retval = aice_execute_reset(cmd);
+                       break;
+               default:
+                       retval = ERROR_OK;
+                       break;
+       }
+       return retval;
+}
+
+/* aice has no need to implement jtag execution model
+*/
+static int aice_execute_queue(void)
+{
+       struct jtag_command *cmd = jtag_command_queue;  /* currently processed command */
+       int retval;
+
+       retval = ERROR_OK;
+
+       while (cmd) {
+               if (aice_execute_command(cmd) != ERROR_OK)
+                       retval = ERROR_JTAG_QUEUE_FAILED;
+
+               cmd = cmd->next;
+       }
+
+       return retval;
+}
+
+/* set jtag frequency(base frequency/frequency divider) to your jtag adapter */
+static int aice_speed(int speed)
+{
+       return aice.port->api->set_jtag_clock(speed);
+}
+
+/* convert jtag adapter frequency(base frequency/frequency divider) to
+ * human readable KHz value */
+static int aice_speed_div(int speed, int *khz)
+{
+       *khz = aice_khz_to_speed_map[speed];
+
+       return ERROR_OK;
+}
+
+/* convert human readable KHz value to jtag adapter frequency
+ * (base frequency/frequency divider) */
+static int aice_khz(int khz, int *jtag_speed)
+{
+       int i;
+       for (i = 0 ; i < AICE_KHZ_TO_SPEED_MAP_SIZE ; i++) {
+               if (khz == aice_khz_to_speed_map[i]) {
+                       if (8 <= i)
+                               *jtag_speed = i | AICE_TCK_CONTROL_TCK3048;
+                       else
+                               *jtag_speed = i;
+                       break;
+               }
+       }
+
+       if (i == AICE_KHZ_TO_SPEED_MAP_SIZE) {
+               LOG_INFO("No support the jtag clock: %d", khz);
+               LOG_INFO("Supported jtag clocks are:");
+
+               for (i = 0 ; i < AICE_KHZ_TO_SPEED_MAP_SIZE ; i++)
+                       LOG_INFO("* %d", aice_khz_to_speed_map[i]);
+
+               return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+/***************************************************************************/
+/* Command handlers */
+COMMAND_HANDLER(aice_handle_aice_info_command)
+{
+       LOG_DEBUG("aice_handle_aice_info_command");
+
+       command_print(CMD_CTX, "Description: %s", aice.param.device_desc);
+       command_print(CMD_CTX, "Serial number: %s", aice.param.serial);
+       if (strncmp(aice.port->name, "aice_pipe", 9) == 0)
+               command_print(CMD_CTX, "Adapter: %s", aice.param.adapter_name);
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(aice_handle_aice_port_command)
+{
+       LOG_DEBUG("aice_handle_aice_port_command");
+
+       if (CMD_ARGC != 1) {
+               LOG_ERROR("Need exactly one argument to 'aice port'");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       for (const struct aice_port *l = aice_port_get_list(); l->name; l++) {
+               if (strcmp(l->name, CMD_ARGV[0]) == 0) {
+                       aice.port = l;
+                       return ERROR_OK;
+               }
+       }
+
+       LOG_ERROR("No AICE port '%s' found", CMD_ARGV[0]);
+       return ERROR_FAIL;
+}
+
+COMMAND_HANDLER(aice_handle_aice_desc_command)
+{
+       LOG_DEBUG("aice_handle_aice_desc_command");
+
+       if (CMD_ARGC == 1)
+               aice.param.device_desc = strdup(CMD_ARGV[0]);
+       else
+               LOG_ERROR("expected exactly one argument to aice desc <description>");
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(aice_handle_aice_serial_command)
+{
+       LOG_DEBUG("aice_handle_aice_serial_command");
+
+       if (CMD_ARGC == 1)
+               aice.param.serial = strdup(CMD_ARGV[0]);
+       else
+               LOG_ERROR("expected exactly one argument to aice serial <serial-number>");
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(aice_handle_aice_vid_pid_command)
+{
+       LOG_DEBUG("aice_handle_aice_vid_pid_command");
+
+       if (CMD_ARGC != 2) {
+               LOG_WARNING("ignoring extra IDs in aice vid_pid (maximum is 1 pair)");
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+
+       COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], aice.param.vid);
+       COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], aice.param.pid);
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(aice_handle_aice_adapter_command)
+{
+       LOG_DEBUG("aice_handle_aice_adapter_command");
+
+       if (CMD_ARGC == 1)
+               aice.param.adapter_name = strdup(CMD_ARGV[0]);
+       else
+               LOG_ERROR("expected exactly one argument to aice adapter <adapter-name>");
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(aice_handle_aice_retry_times_command)
+{
+       LOG_DEBUG("aice_handle_aice_retry_times_command");
+
+       if (CMD_ARGC == 1)
+               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], aice.retry_times);
+       else
+               LOG_ERROR("expected exactly one argument to aice retry_times <num_of_retry>");
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(aice_handle_aice_count_to_check_dbger_command)
+{
+       LOG_DEBUG("aice_handle_aice_count_to_check_dbger_command");
+
+       if (CMD_ARGC == 1)
+               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], aice.count_to_check_dbger);
+       else
+               LOG_ERROR("expected exactly one argument to aice count_to_check_dbger "
+                               "<count_of_checking>");
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(aice_handle_aice_custom_srst_script_command)
+{
+       LOG_DEBUG("aice_handle_aice_custom_srst_script_command");
+
+       if (CMD_ARGC > 0) {
+               aice.port->api->set_custom_srst_script(CMD_ARGV[0]);
+               return ERROR_OK;
+       }
+
+       return ERROR_FAIL;
+}
+
+COMMAND_HANDLER(aice_handle_aice_custom_trst_script_command)
+{
+       LOG_DEBUG("aice_handle_aice_custom_trst_script_command");
+
+       if (CMD_ARGC > 0) {
+               aice.port->api->set_custom_trst_script(CMD_ARGV[0]);
+               return ERROR_OK;
+       }
+
+       return ERROR_FAIL;
+}
+
+COMMAND_HANDLER(aice_handle_aice_custom_restart_script_command)
+{
+       LOG_DEBUG("aice_handle_aice_custom_restart_script_command");
+
+       if (CMD_ARGC > 0) {
+               aice.port->api->set_custom_restart_script(CMD_ARGV[0]);
+               return ERROR_OK;
+       }
+
+       return ERROR_FAIL;
+}
+
+COMMAND_HANDLER(aice_handle_aice_reset_command)
+{
+       LOG_DEBUG("aice_handle_aice_reset_command");
+
+       return aice.port->api->reset();
+}
+
+
+static const struct command_registration aice_subcommand_handlers[] = {
+       {
+               .name = "info",
+               .handler = &aice_handle_aice_info_command,
+               .mode = COMMAND_EXEC,
+               .help = "show aice info",
+               .usage = "aice info",
+       },
+       {
+               .name = "port",
+               .handler = &aice_handle_aice_port_command,
+               .mode = COMMAND_CONFIG,
+               .help = "set the port of the AICE",
+               .usage = "aice port ['aice_pipe'|'aice_usb']",
+       },
+       {
+               .name = "desc",
+               .handler = &aice_handle_aice_desc_command,
+               .mode = COMMAND_CONFIG,
+               .help = "set the aice device description",
+               .usage = "aice desc [desciption string]",
+       },
+       {
+               .name = "serial",
+               .handler = &aice_handle_aice_serial_command,
+               .mode = COMMAND_CONFIG,
+               .help = "set the serial number of the AICE device",
+               .usage = "aice serial [serial string]",
+       },
+       {
+               .name = "vid_pid",
+               .handler = &aice_handle_aice_vid_pid_command,
+               .mode = COMMAND_CONFIG,
+               .help = "the vendor and product ID of the AICE device",
+               .usage = "aice vid_pid (vid pid)*",
+       },
+       {
+               .name = "adapter",
+               .handler = &aice_handle_aice_adapter_command,
+               .mode = COMMAND_CONFIG,
+               .help = "set the file name of adapter",
+               .usage = "aice adapter [adapter name]",
+       },
+       {
+               .name = "retry_times",
+               .handler = &aice_handle_aice_retry_times_command,
+               .mode = COMMAND_CONFIG,
+               .help = "set retry times as AICE timeout",
+               .usage = "aice retry_times num_of_retry",
+       },
+       {
+               .name = "count_to_check_dbger",
+               .handler = &aice_handle_aice_count_to_check_dbger_command,
+               .mode = COMMAND_CONFIG,
+               .help = "set retry times as checking $DBGER status",
+               .usage = "aice count_to_check_dbger count_of_checking",
+       },
+       {
+               .name = "custom_srst_script",
+               .handler = &aice_handle_aice_custom_srst_script_command,
+               .mode = COMMAND_CONFIG,
+               .usage = "custom_srst_script script_file_name",
+               .help = "set custom srst script",
+       },
+       {
+               .name = "custom_trst_script",
+               .handler = &aice_handle_aice_custom_trst_script_command,
+               .mode = COMMAND_CONFIG,
+               .usage = "custom_trst_script script_file_name",
+               .help = "set custom trst script",
+       },
+       {
+               .name = "custom_restart_script",
+               .handler = &aice_handle_aice_custom_restart_script_command,
+               .mode = COMMAND_CONFIG,
+               .usage = "custom_restart_script script_file_name",
+               .help = "set custom restart script",
+       },
+       {
+               .name = "reset",
+               .handler = &aice_handle_aice_reset_command,
+               .mode = COMMAND_EXEC,
+               .usage = "aice reset",
+               .help = "reset AICE",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration aice_command_handlers[] = {
+       {
+               .name = "aice",
+               .mode = COMMAND_ANY,
+               .help = "perform aice management",
+               .usage = "aice [subcommand]",
+               .chain = aice_subcommand_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+/***************************************************************************/
+/* End of Command handlers */
+
+struct jtag_interface aice_interface = {
+       .name = "aice",
+       .commands = aice_command_handlers,
+       .transports = aice_transports,
+       .init = aice_init,
+       .quit = aice_quit,
+       .execute_queue = aice_execute_queue,
+       .speed = aice_speed,            /* set interface speed */
+       .speed_div = aice_speed_div,    /* return readable value */
+       .khz = aice_khz,                /* convert khz to interface speed value */
+};
+
diff --git a/src/jtag/aice/aice_interface.h b/src/jtag/aice/aice_interface.h
new file mode 100644 (file)
index 0000000..e7077a7
--- /dev/null
@@ -0,0 +1,36 @@
+/***************************************************************************
+ *   Copyright (C) 2013 by 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 __AICE_INTERFACE_H__
+#define __AICE_INTERFACE_H__
+
+struct aice_interface_param_s {
+       /** */
+       char *device_desc;
+       /** */
+       char *serial;
+       /** */
+       uint16_t vid;
+       /** */
+       uint16_t pid;
+};
+
+int aice_init_target(struct target *t);
+
+#endif
diff --git a/src/jtag/aice/aice_pipe.c b/src/jtag/aice/aice_pipe.c
new file mode 100644 (file)
index 0000000..02caa3f
--- /dev/null
@@ -0,0 +1,915 @@
+/***************************************************************************
+ *   Copyright (C) 2013 by 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
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <signal.h>
+#endif
+
+#include <helper/log.h>
+#include <helper/time_support.h>
+#include "aice_port.h"
+#include "aice_pipe.h"
+
+#define AICE_PIPE_MAXLINE 8192
+
+#ifdef _WIN32
+PROCESS_INFORMATION proc_info;
+
+HANDLE aice_pipe_output[2];
+HANDLE aice_pipe_input[2];
+
+static int aice_pipe_write(const void *buffer, int count)
+{
+       BOOL success;
+       DWORD written;
+
+       success = WriteFile(aice_pipe_output[1], buffer, count, &written, NULL);
+       if (!success) {
+               LOG_ERROR("(WIN32) write to pipe failed, error code: 0x%08lx", GetLastError());
+               return -1;
+       }
+
+       return written;
+}
+
+static int aice_pipe_read(void *buffer, int count)
+{
+       BOOL success;
+       DWORD has_read;
+
+       success = ReadFile(aice_pipe_input[0], buffer, count, &has_read, NULL);
+       if (!success || (has_read == 0)) {
+               LOG_ERROR("(WIN32) read from pipe failed, error code: 0x%08lx", GetLastError());
+               return -1;
+       }
+
+       return has_read;
+}
+
+static int aice_pipe_child_init(struct aice_port_param_s *param)
+{
+       STARTUPINFO start_info;
+       BOOL success;
+
+       ZeroMemory(&proc_info, sizeof(PROCESS_INFORMATION));
+       ZeroMemory(&start_info, sizeof(STARTUPINFO));
+       start_info.cb = sizeof(STARTUPINFO);
+       start_info.hStdError = aice_pipe_input[1];
+       start_info.hStdOutput = aice_pipe_input[1];
+       start_info.hStdInput = aice_pipe_output[0];
+       start_info.dwFlags |= STARTF_USESTDHANDLES;
+
+       success = CreateProcess(NULL,
+                       param->adapter_name,
+                       NULL,
+                       NULL,
+                       TRUE,
+                       0,
+                       NULL,
+                       NULL,
+                       &start_info,
+                       &proc_info);
+
+       if (!success) {
+               LOG_ERROR("Create new process failed");
+               return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int aice_pipe_parent_init(struct aice_port_param_s *param)
+{
+       /* send open to adapter */
+       char line[AICE_PIPE_MAXLINE];
+       char command[AICE_PIPE_MAXLINE];
+
+       command[0] = AICE_OPEN;
+       set_u16(command + 1, param->vid);
+       set_u16(command + 3, param->pid);
+
+       if (aice_pipe_write(command, 5) != 5) {
+               LOG_ERROR("write failed\n");
+               return ERROR_FAIL;
+       }
+
+       if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) {
+               LOG_ERROR("read failed\n");
+               return ERROR_FAIL;
+       }
+
+       if (line[0] == AICE_OK)
+               return ERROR_OK;
+       else
+               return ERROR_FAIL;
+}
+
+static int aice_pipe_open(struct aice_port_param_s *param)
+{
+       SECURITY_ATTRIBUTES attribute;
+
+       attribute.nLength = sizeof(SECURITY_ATTRIBUTES);
+       attribute.bInheritHandle = TRUE;
+       attribute.lpSecurityDescriptor = NULL;
+
+       if (!CreatePipe(&aice_pipe_output[0], &aice_pipe_output[1],
+                               &attribute, AICE_PIPE_MAXLINE)) {
+               LOG_ERROR("Create pipes failed");
+               return ERROR_FAIL;
+       }
+       if (!CreatePipe(&aice_pipe_input[0], &aice_pipe_input[1],
+                               &attribute, AICE_PIPE_MAXLINE)) {
+               LOG_ERROR("Create pipes failed");
+               return ERROR_FAIL;
+       }
+
+       /* do not inherit aice_pipe_output[1] & aice_pipe_input[0] to child process */
+       if (!SetHandleInformation(aice_pipe_output[1], HANDLE_FLAG_INHERIT, 0))
+               return ERROR_FAIL;
+       if (!SetHandleInformation(aice_pipe_input[0], HANDLE_FLAG_INHERIT, 0))
+               return ERROR_FAIL;
+
+       aice_pipe_child_init(param);
+
+       aice_pipe_parent_init(param);
+
+       return ERROR_OK;
+}
+
+#else
+
+int aice_pipe_output[2];
+int aice_pipe_input[2];
+
+static int aice_pipe_write(const void *buffer, int count)
+{
+       if (write(aice_pipe_output[1], buffer, count) != count) {
+               LOG_ERROR("write to pipe failed");
+               return -1;
+       }
+
+       return count;
+}
+
+static int aice_pipe_read(void *buffer, int count)
+{
+       int n;
+       long long then, cur;
+
+       then = timeval_ms();
+
+       while (1) {
+               n = read(aice_pipe_input[0], buffer, count);
+
+               if ((n == -1) && (errno == EAGAIN)) {
+                       cur = timeval_ms();
+                       if (cur - then > 500)
+                               keep_alive();
+                       continue;
+               } else if (n > 0)
+                       break;
+               else {
+                       LOG_ERROR("read from pipe failed");
+                       break;
+               }
+       }
+
+       return n;
+}
+
+static int aice_pipe_child_init(struct aice_port_param_s *param)
+{
+       close(aice_pipe_output[1]);
+       close(aice_pipe_input[0]);
+
+       if (aice_pipe_output[0] != STDIN_FILENO) {
+               if (dup2(aice_pipe_output[0], STDIN_FILENO) != STDIN_FILENO) {
+                       LOG_ERROR("Map aice_pipe to STDIN failed");
+                       return ERROR_FAIL;
+               }
+               close(aice_pipe_output[0]);
+       }
+
+       if (aice_pipe_input[1] != STDOUT_FILENO) {
+               if (dup2(aice_pipe_input[1], STDOUT_FILENO) != STDOUT_FILENO) {
+                       LOG_ERROR("Map aice_pipe to STDOUT failed");
+                       return ERROR_FAIL;
+               }
+               close(aice_pipe_input[1]);
+       }
+
+       if (execl(param->adapter_name, param->adapter_name, (char *)0) < 0) {
+               LOG_ERROR("Execute aice_pipe failed");
+               return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int aice_pipe_parent_init(struct aice_port_param_s *param)
+{
+       close(aice_pipe_output[0]);
+       close(aice_pipe_input[1]);
+
+       /* set read end of pipe as non-blocking */
+       if (fcntl(aice_pipe_input[0], F_SETFL, O_NONBLOCK))
+               return ERROR_FAIL;
+
+       /* send open to adapter */
+       char line[AICE_PIPE_MAXLINE];
+       char command[AICE_PIPE_MAXLINE];
+
+       command[0] = AICE_OPEN;
+       set_u16(command + 1, param->vid);
+       set_u16(command + 3, param->pid);
+
+       if (aice_pipe_write(command, 5) != 5) {
+               LOG_ERROR("write failed\n");
+               return ERROR_FAIL;
+       }
+
+       if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) {
+               LOG_ERROR("read failed\n");
+               return ERROR_FAIL;
+       }
+
+       if (line[0] == AICE_OK)
+               return ERROR_OK;
+       else
+               return ERROR_FAIL;
+}
+
+static void sig_pipe(int signo)
+{
+       exit(1);
+}
+
+static int aice_pipe_open(struct aice_port_param_s *param)
+{
+       pid_t pid;
+
+       if (signal(SIGPIPE, sig_pipe) == SIG_ERR) {
+               LOG_ERROR("Register SIGPIPE handler failed");
+               return ERROR_FAIL;
+       }
+
+       if (pipe(aice_pipe_output) < 0 || pipe(aice_pipe_input) < 0) {
+               LOG_ERROR("Create pipes failed");
+               return ERROR_FAIL;
+       }
+
+       pid = fork();
+       if (pid < 0) {
+               LOG_ERROR("Fork new process failed");
+               return ERROR_FAIL;
+       } else if (pid == 0) {
+               if (aice_pipe_child_init(param) != ERROR_OK) {
+                       LOG_ERROR("AICE_PIPE child process initial error");
+                       return ERROR_FAIL;
+               } else {
+                       if (aice_pipe_parent_init(param) != ERROR_OK) {
+                               LOG_ERROR("AICE_PIPE parent process initial error");
+                               return ERROR_FAIL;
+                       }
+               }
+       }
+
+       return ERROR_OK;
+}
+#endif
+
+static int aice_pipe_close(void)
+{
+       char line[AICE_PIPE_MAXLINE];
+       char command[AICE_PIPE_MAXLINE];
+
+       command[0] = AICE_CLOSE;
+
+       if (aice_pipe_write(command, 1) != 1)
+               return ERROR_FAIL;
+
+       if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
+               return ERROR_FAIL;
+
+       if (line[0] == AICE_OK) {
+#ifdef _WIN32
+               WaitForSingleObject(proc_info.hProcess, INFINITE);
+               CloseHandle(proc_info.hProcess);
+               CloseHandle(proc_info.hThread);
+#endif
+               return ERROR_OK;
+       } else
+               return ERROR_FAIL;
+}
+
+static int aice_pipe_idcode(uint32_t *idcode, uint8_t *num_of_idcode)
+{
+       char line[AICE_PIPE_MAXLINE];
+       char command[AICE_PIPE_MAXLINE];
+
+       command[0] = AICE_IDCODE;
+
+       if (aice_pipe_write(command, 1) != 1)
+               return ERROR_FAIL;
+
+       if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
+               return ERROR_FAIL;
+
+       *num_of_idcode = line[0];
+
+       if ((*num_of_idcode == 0) || (*num_of_idcode >= 16))
+               return ERROR_FAIL;
+
+       for (int i = 0 ; i < *num_of_idcode ; i++)
+               idcode[i] = get_u32(line + i * 4 + 1);
+
+       return ERROR_OK;
+}
+
+static int aice_pipe_state(enum aice_target_state_s *state)
+{
+       char line[AICE_PIPE_MAXLINE];
+       char command[AICE_PIPE_MAXLINE];
+
+       command[0] = AICE_STATE;
+
+       if (aice_pipe_write(command, 1) != 1)
+               return ERROR_FAIL;
+
+       if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
+               return ERROR_FAIL;
+
+       *state = (enum aice_target_state_s)line[0];
+
+       return ERROR_OK;
+}
+
+static int aice_pipe_reset(void)
+{
+       char line[AICE_PIPE_MAXLINE];
+       char command[AICE_PIPE_MAXLINE];
+
+       command[0] = AICE_RESET;
+
+       if (aice_pipe_write(command, 1) != 1)
+               return ERROR_FAIL;
+
+       if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
+               return ERROR_FAIL;
+
+       if (line[0] == AICE_OK)
+               return ERROR_OK;
+       else
+               return ERROR_FAIL;
+}
+
+static int aice_pipe_assert_srst(enum aice_srst_type_s srst)
+{
+       char line[AICE_PIPE_MAXLINE];
+       char command[AICE_PIPE_MAXLINE];
+
+       command[0] = AICE_ASSERT_SRST;
+       command[1] = srst;
+
+       if (aice_pipe_write(command, 2) != 2)
+               return ERROR_FAIL;
+
+       if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
+               return ERROR_FAIL;
+
+       if (line[0] == AICE_OK)
+               return ERROR_OK;
+       else
+               return ERROR_FAIL;
+}
+
+static int aice_pipe_run(void)
+{
+       char line[AICE_PIPE_MAXLINE];
+       char command[AICE_PIPE_MAXLINE];
+
+       command[0] = AICE_RUN;
+
+       if (aice_pipe_write(command, 1) != 1)
+               return ERROR_FAIL;
+
+       if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
+               return ERROR_FAIL;
+
+       if (line[0] == AICE_OK)
+               return ERROR_OK;
+       else
+               return ERROR_FAIL;
+}
+
+static int aice_pipe_halt(void)
+{
+       char line[AICE_PIPE_MAXLINE];
+       char command[AICE_PIPE_MAXLINE];
+
+       command[0] = AICE_HALT;
+
+       if (aice_pipe_write(command, 1) != 1)
+               return ERROR_FAIL;
+
+       if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
+               return ERROR_FAIL;
+
+       if (line[0] == AICE_OK)
+               return ERROR_OK;
+       else
+               return ERROR_FAIL;
+}
+
+static int aice_pipe_read_reg(uint32_t num, uint32_t *val)
+{
+       char line[AICE_PIPE_MAXLINE];
+       char command[AICE_PIPE_MAXLINE];
+
+       command[0] = AICE_READ_REG;
+       set_u32(command + 1, num);
+
+       if (aice_pipe_write(command, 5) != 5)
+               return ERROR_FAIL;
+
+       if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
+               return ERROR_FAIL;
+
+       *val = get_u32(line);
+
+       return ERROR_OK;
+}
+
+static int aice_pipe_write_reg(uint32_t num, uint32_t val)
+{
+       char line[AICE_PIPE_MAXLINE];
+       char command[AICE_PIPE_MAXLINE];
+
+       command[0] = AICE_WRITE_REG;
+       set_u32(command + 1, num);
+       set_u32(command + 5, val);
+
+       if (aice_pipe_write(command, 9) != 9)
+               return ERROR_FAIL;
+
+       if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
+               return ERROR_FAIL;
+
+       if (line[0] == AICE_OK)
+               return ERROR_OK;
+       else
+               return ERROR_FAIL;
+}
+
+static int aice_pipe_read_reg_64(uint32_t num, uint64_t *val)
+{
+       char line[AICE_PIPE_MAXLINE];
+       char command[AICE_PIPE_MAXLINE];
+
+       command[0] = AICE_READ_REG_64;
+       set_u32(command + 1, num);
+
+       if (aice_pipe_write(command, 5) != 5)
+               return ERROR_FAIL;
+
+       if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
+               return ERROR_FAIL;
+
+       *val = (((uint64_t)get_u32(line + 4)) << 32) | get_u32(line);
+
+       return ERROR_OK;
+}
+
+static int aice_pipe_write_reg_64(uint32_t num, uint64_t val)
+{
+       char line[AICE_PIPE_MAXLINE];
+       char command[AICE_PIPE_MAXLINE];
+
+       command[0] = AICE_WRITE_REG_64;
+       set_u32(command + 1, num);
+       set_u32(command + 5, val & 0xFFFFFFFF);
+       set_u32(command + 9, (val >> 32) & 0xFFFFFFFF);
+
+       if (aice_pipe_write(command, 13) != 9)
+               return ERROR_FAIL;
+
+       if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
+               return ERROR_FAIL;
+
+       if (line[0] == AICE_OK)
+               return ERROR_OK;
+       else
+               return ERROR_FAIL;
+}
+
+static int aice_pipe_step(void)
+{
+       char line[AICE_PIPE_MAXLINE];
+       char command[AICE_PIPE_MAXLINE];
+
+       command[0] = AICE_STEP;
+
+       if (aice_pipe_write(command, 1) != 1)
+               return ERROR_FAIL;
+
+       if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
+               return ERROR_FAIL;
+
+       if (line[0] == AICE_OK)
+               return ERROR_OK;
+       else
+               return ERROR_FAIL;
+}
+
+static int aice_pipe_read_mem_unit(uint32_t addr, uint32_t size,
+               uint32_t count, uint8_t *buffer)
+{
+       char command[AICE_PIPE_MAXLINE];
+
+       command[0] = AICE_READ_MEM_UNIT;
+       set_u32(command + 1, addr);
+       set_u32(command + 5, size);
+       set_u32(command + 9, count);
+
+       if (aice_pipe_write(command, 13) != 13)
+               return ERROR_FAIL;
+
+       if (aice_pipe_read(buffer, size * count) < 0)
+               return ERROR_FAIL;
+
+       return ERROR_OK;
+}
+
+static int aice_pipe_write_mem_unit(uint32_t addr, uint32_t size,
+               uint32_t count, const uint8_t *buffer)
+{
+       char line[AICE_PIPE_MAXLINE];
+       char command[AICE_PIPE_MAXLINE];
+
+       command[0] = AICE_WRITE_MEM_UNIT;
+       set_u32(command + 1, addr);
+       set_u32(command + 5, size);
+       set_u32(command + 9, count);
+
+       /* WRITE_MEM_UNIT|addr|size|count|data */
+       memcpy(command + 13, buffer, size * count);
+
+       if (aice_pipe_write(command, 13 + size * count) < 0)
+               return ERROR_FAIL;
+
+       if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
+               return ERROR_FAIL;
+
+       if (line[0] == AICE_OK)
+               return ERROR_OK;
+       else
+               return ERROR_FAIL;
+
+       return ERROR_OK;
+}
+
+static int aice_pipe_read_mem_bulk(uint32_t addr, uint32_t length, uint8_t *buffer)
+{
+       char line[AICE_PIPE_MAXLINE + 1];
+       char command[AICE_PIPE_MAXLINE];
+       uint32_t remain_len = length;
+       uint32_t prepare_len;
+       char *received_line;
+       uint32_t received_len;
+       int read_len;
+
+       command[0] = AICE_READ_MEM_BULK;
+       set_u32(command + 1, addr);
+       set_u32(command + 5, length);
+
+       if (aice_pipe_write(command, 9) < 0)
+               return ERROR_FAIL;
+
+       while (remain_len > 0) {
+               if (remain_len > AICE_PIPE_MAXLINE)
+                       prepare_len = AICE_PIPE_MAXLINE;
+               else
+                       prepare_len = remain_len;
+
+               prepare_len++;
+               received_len = 0;
+               received_line = line;
+               do {
+                       read_len = aice_pipe_read(received_line, prepare_len - received_len);
+                       if (read_len < 0)
+                               return ERROR_FAIL;
+                       received_line += read_len;
+                       received_len += read_len;
+               } while (received_len < prepare_len);
+
+               if (line[0] != AICE_OK)
+                       return ERROR_FAIL;
+
+               prepare_len--;
+               memcpy(buffer, line + 1, prepare_len);
+               remain_len -= prepare_len;
+               buffer += prepare_len;
+       }
+
+       return ERROR_OK;
+}
+
+static int aice_pipe_write_mem_bulk(uint32_t addr, uint32_t length, const uint8_t *buffer)
+{
+       char line[AICE_PIPE_MAXLINE];
+       char command[AICE_PIPE_MAXLINE + 4];
+       uint32_t remain_len = length;
+       uint32_t written_len = 0;
+       uint32_t write_len;
+
+       command[0] = AICE_WRITE_MEM_BULK;
+       set_u32(command + 1, addr);
+       set_u32(command + 5, length);
+
+       /* Send command first */
+       if (aice_pipe_write(command, 9) < 0)
+               return ERROR_FAIL;
+
+       if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
+               return ERROR_FAIL;
+
+       if (line[0] == AICE_ERROR)
+               return ERROR_FAIL;
+
+       while (remain_len > 0) {
+               if (remain_len > AICE_PIPE_MAXLINE)
+                       write_len = AICE_PIPE_MAXLINE;
+               else
+                       write_len = remain_len;
+
+               set_u32(command, write_len);
+               memcpy(command + 4, buffer + written_len, write_len); /* data only */
+
+               if (aice_pipe_write(command, write_len + 4) < 0)
+                       return ERROR_FAIL;
+
+               if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
+                       return ERROR_FAIL;
+
+               if (line[0] == AICE_ERROR)
+                       return ERROR_FAIL;
+
+               remain_len -= write_len;
+               written_len += write_len;
+       }
+
+       if (line[0] == AICE_OK)
+               return ERROR_OK;
+       else
+               return ERROR_FAIL;
+}
+
+static int aice_pipe_read_debug_reg(uint32_t addr, uint32_t *val)
+{
+       char line[AICE_PIPE_MAXLINE];
+       char command[AICE_PIPE_MAXLINE];
+
+       command[0] = AICE_READ_DEBUG_REG;
+       set_u32(command + 1, addr);
+
+       if (aice_pipe_write(command, 5) != 5)
+               return ERROR_FAIL;
+
+       if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
+               return ERROR_FAIL;
+
+       *val = get_u32(line);
+
+       return ERROR_OK;
+}
+
+static int aice_pipe_write_debug_reg(uint32_t addr, const uint32_t val)
+{
+       char line[AICE_PIPE_MAXLINE];
+       char command[AICE_PIPE_MAXLINE];
+
+       command[0] = AICE_WRITE_DEBUG_REG;
+       set_u32(command + 1, addr);
+       set_u32(command + 5, val);
+
+       if (aice_pipe_write(command, 9) != 9)
+               return ERROR_FAIL;
+
+       if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
+               return ERROR_FAIL;
+
+       if (line[0] == AICE_OK)
+               return ERROR_OK;
+       else
+               return ERROR_FAIL;
+}
+
+static int aice_pipe_set_jtag_clock(uint32_t a_clock)
+{
+       char line[AICE_PIPE_MAXLINE];
+       char command[AICE_PIPE_MAXLINE];
+
+       command[0] = AICE_SET_JTAG_CLOCK;
+       set_u32(command + 1, a_clock);
+
+       if (aice_pipe_write(command, 5) != 5)
+               return ERROR_FAIL;
+
+       if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
+               return ERROR_FAIL;
+
+       if (line[0] == AICE_OK)
+               return ERROR_OK;
+       else
+               return ERROR_FAIL;
+}
+
+static int aice_pipe_select_target(uint32_t target_id)
+{
+       char line[AICE_PIPE_MAXLINE];
+       char command[AICE_PIPE_MAXLINE];
+
+       command[0] = AICE_SELECT_TARGET;
+       set_u32(command + 1, target_id);
+
+       if (aice_pipe_write(command, 5) != 5)
+               return ERROR_FAIL;
+
+       if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
+               return ERROR_FAIL;
+
+       if (line[0] == AICE_OK)
+               return ERROR_OK;
+       else
+               return ERROR_FAIL;
+}
+
+static int aice_pipe_memory_access(enum nds_memory_access access_channel)
+{
+       char line[AICE_PIPE_MAXLINE];
+       char command[AICE_PIPE_MAXLINE];
+
+       command[0] = AICE_MEMORY_ACCESS;
+       set_u32(command + 1, access_channel);
+
+       if (aice_pipe_write(command, 5) != 5)
+               return ERROR_FAIL;
+
+       if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
+               return ERROR_FAIL;
+
+       if (line[0] == AICE_OK)
+               return ERROR_OK;
+       else
+               return ERROR_FAIL;
+}
+
+static int aice_pipe_memory_mode(enum nds_memory_select mem_select)
+{
+       char line[AICE_PIPE_MAXLINE];
+       char command[AICE_PIPE_MAXLINE];
+
+       command[0] = AICE_MEMORY_MODE;
+       set_u32(command + 1, mem_select);
+
+       if (aice_pipe_write(command, 5) != 5)
+               return ERROR_FAIL;
+
+       if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
+               return ERROR_FAIL;
+
+       if (line[0] == AICE_OK)
+               return ERROR_OK;
+       else
+               return ERROR_FAIL;
+}
+
+static int aice_pipe_read_tlb(uint32_t virtual_address, uint32_t *physical_address)
+{
+       char line[AICE_PIPE_MAXLINE];
+       char command[AICE_PIPE_MAXLINE];
+
+       command[0] = AICE_READ_TLB;
+       set_u32(command + 1, virtual_address);
+
+       if (aice_pipe_write(command, 5) != 5)
+               return ERROR_FAIL;
+
+       if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
+               return ERROR_FAIL;
+
+       if (line[0] == AICE_OK) {
+               *physical_address = get_u32(line + 1);
+               return ERROR_OK;
+       } else
+               return ERROR_FAIL;
+}
+
+static int aice_pipe_cache_ctl(uint32_t subtype, uint32_t address)
+{
+       char line[AICE_PIPE_MAXLINE];
+       char command[AICE_PIPE_MAXLINE];
+
+       command[0] = AICE_CACHE_CTL;
+       set_u32(command + 1, subtype);
+       set_u32(command + 5, address);
+
+       if (aice_pipe_write(command, 9) != 9)
+               return ERROR_FAIL;
+
+       if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
+               return ERROR_FAIL;
+
+       if (line[0] == AICE_OK)
+               return ERROR_OK;
+       else
+               return ERROR_FAIL;
+}
+
+static int aice_pipe_set_retry_times(uint32_t a_retry_times)
+{
+       return ERROR_OK;
+}
+
+/** */
+struct aice_port_api_s aice_pipe = {
+       /** */
+       .open = aice_pipe_open,
+       /** */
+       .close = aice_pipe_close,
+       /** */
+       .idcode = aice_pipe_idcode,
+       /** */
+       .state = aice_pipe_state,
+       /** */
+       .reset = aice_pipe_reset,
+       /** */
+       .assert_srst = aice_pipe_assert_srst,
+       /** */
+       .run = aice_pipe_run,
+       /** */
+       .halt = aice_pipe_halt,
+       /** */
+       .step = aice_pipe_step,
+       /** */
+       .read_reg = aice_pipe_read_reg,
+       /** */
+       .write_reg = aice_pipe_write_reg,
+       /** */
+       .read_reg_64 = aice_pipe_read_reg_64,
+       /** */
+       .write_reg_64 = aice_pipe_write_reg_64,
+       /** */
+       .read_mem_unit = aice_pipe_read_mem_unit,
+       /** */
+       .write_mem_unit = aice_pipe_write_mem_unit,
+       /** */
+       .read_mem_bulk = aice_pipe_read_mem_bulk,
+       /** */
+       .write_mem_bulk = aice_pipe_write_mem_bulk,
+       /** */
+       .read_debug_reg = aice_pipe_read_debug_reg,
+       /** */
+       .write_debug_reg = aice_pipe_write_debug_reg,
+
+       /** */
+       .set_jtag_clock = aice_pipe_set_jtag_clock,
+       /** */
+       .select_target = aice_pipe_select_target,
+
+       /** */
+       .memory_access = aice_pipe_memory_access,
+       /** */
+       .memory_mode = aice_pipe_memory_mode,
+
+       /** */
+       .read_tlb = aice_pipe_read_tlb,
+
+       /** */
+       .cache_ctl = aice_pipe_cache_ctl,
+
+       /** */
+       .set_retry_times = aice_pipe_set_retry_times,
+};
diff --git a/src/jtag/aice/aice_pipe.h b/src/jtag/aice/aice_pipe.h
new file mode 100644 (file)
index 0000000..48b0c49
--- /dev/null
@@ -0,0 +1,32 @@
+/***************************************************************************
+ *   Copyright (C) 2013 by 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 _AICE_PIPE_H_
+#define _AICE_PIPE_H_
+
+#include <helper/types.h>
+
+#define set_u32(buffer, value) h_u32_to_le((uint8_t *)buffer, value)
+#define set_u16(buffer, value) h_u16_to_le((uint8_t *)buffer, value)
+#define get_u32(buffer) le_to_h_u32((const uint8_t *)buffer)
+#define get_u16(buffer) le_to_h_u16((const uint8_t *)buffer)
+
+extern struct aice_port_api_s aice_pipe;
+
+#endif
diff --git a/src/jtag/aice/aice_port.c b/src/jtag/aice/aice_port.c
new file mode 100644 (file)
index 0000000..b61275c
--- /dev/null
@@ -0,0 +1,47 @@
+/***************************************************************************
+ *   Copyright (C) 2013 by 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 "aice_usb.h"
+#include "aice_pipe.h"
+#include "aice_port.h"
+
+static const struct aice_port aice_ports[] = {
+       {
+               .name = "aice_usb",
+               .type = AICE_PORT_AICE_USB,
+               .api = &aice_usb_api,
+       },
+       {
+               .name = "aice_pipe",
+               .type = AICE_PORT_AICE_PIPE,
+               .api = &aice_pipe,
+       },
+       {.name = NULL, /* END OF TABLE */ },
+};
+
+/** */
+const struct aice_port *aice_port_get_list(void)
+{
+       return aice_ports;
+}
diff --git a/src/jtag/aice/aice_port.h b/src/jtag/aice/aice_port.h
new file mode 100644 (file)
index 0000000..c3c7413
--- /dev/null
@@ -0,0 +1,234 @@
+/***************************************************************************
+ *   Copyright (C) 2013 by 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 _AICE_PORT_H_
+#define _AICE_PORT_H_
+
+#include <target/nds32_edm.h>
+
+#define ERROR_AICE_DISCONNECT  (-200)
+#define ERROR_AICE_TIMEOUT     (-201)
+
+enum aice_target_state_s {
+       AICE_DISCONNECT = 0,
+       AICE_TARGET_DETACH,
+       AICE_TARGET_UNKNOWN,
+       AICE_TARGET_RUNNING,
+       AICE_TARGET_HALTED,
+       AICE_TARGET_RESET,
+       AICE_TARGET_DEBUG_RUNNING,
+};
+
+enum aice_srst_type_s {
+       AICE_SRST = 0x1,
+       AICE_RESET_HOLD = 0x8,
+};
+
+enum aice_target_endian {
+       AICE_LITTLE_ENDIAN = 0,
+       AICE_BIG_ENDIAN,
+};
+
+enum aice_api_s {
+       AICE_OPEN = 0x0,
+       AICE_CLOSE,
+       AICE_RESET,
+       AICE_ASSERT_SRST,
+       AICE_RUN,
+       AICE_HALT,
+       AICE_STEP,
+       AICE_READ_REG,
+       AICE_WRITE_REG,
+       AICE_READ_REG_64,
+       AICE_WRITE_REG_64,
+       AICE_READ_MEM_UNIT,
+       AICE_WRITE_MEM_UNIT,
+       AICE_READ_MEM_BULK,
+       AICE_WRITE_MEM_BULK,
+       AICE_READ_DEBUG_REG,
+       AICE_WRITE_DEBUG_REG,
+       AICE_IDCODE,
+       AICE_STATE,
+       AICE_SET_JTAG_CLOCK,
+       AICE_SELECT_TARGET,
+       AICE_MEMORY_ACCESS,
+       AICE_MEMORY_MODE,
+       AICE_READ_TLB,
+       AICE_CACHE_CTL,
+       AICE_SET_RETRY_TIMES,
+       AICE_PROGRAM_EDM,
+       AICE_PACK_COMMAND,
+       AICE_EXECUTE,
+       AICE_SET_CUSTOM_SRST_SCRIPT,
+       AICE_SET_CUSTOM_TRST_SCRIPT,
+       AICE_SET_CUSTOM_RESTART_SCRIPT,
+       AICE_SET_COUNT_TO_CHECK_DBGER,
+       AICE_SET_DATA_ENDIAN,
+};
+
+enum aice_error_s {
+       AICE_OK,
+       AICE_ACK,
+       AICE_ERROR,
+};
+
+enum aice_cache_ctl_type {
+       AICE_CACHE_CTL_L1D_INVALALL = 0,
+       AICE_CACHE_CTL_L1D_VA_INVAL,
+       AICE_CACHE_CTL_L1D_WBALL,
+       AICE_CACHE_CTL_L1D_VA_WB,
+       AICE_CACHE_CTL_L1I_INVALALL,
+       AICE_CACHE_CTL_L1I_VA_INVAL,
+};
+
+struct aice_port_param_s {
+       /** */
+       char *device_desc;
+       /** */
+       char *serial;
+       /** */
+       uint16_t vid;
+       /** */
+       uint16_t pid;
+       /** */
+       char *adapter_name;
+};
+
+struct aice_port_s {
+       /** */
+       struct aice_port_param_s param;
+       /** */
+       const struct aice_port *port;
+       /** */
+       uint32_t retry_times;
+       /** */
+       uint32_t count_to_check_dbger;
+};
+
+/** */
+extern struct aice_port_api_s aice_usb_layout_api;
+
+/** */
+struct aice_port_api_s {
+       /** */
+       int (*open)(struct aice_port_param_s *param);
+       /** */
+       int (*close)(void);
+       /** */
+       int (*reset)(void);
+       /** */
+       int (*assert_srst)(enum aice_srst_type_s srst);
+       /** */
+       int (*run)(void);
+       /** */
+       int (*halt)(void);
+       /** */
+       int (*step)(void);
+       /** */
+       int (*read_reg)(uint32_t num, uint32_t *val);
+       /** */
+       int (*write_reg)(uint32_t num, uint32_t val);
+       /** */
+       int (*read_reg_64)(uint32_t num, uint64_t *val);
+       /** */
+       int (*write_reg_64)(uint32_t num, uint64_t val);
+       /** */
+       int (*read_mem_unit)(uint32_t addr, uint32_t size, uint32_t count,
+                       uint8_t *buffer);
+       /** */
+       int (*write_mem_unit)(uint32_t addr, uint32_t size, uint32_t count,
+                       const uint8_t *buffer);
+       /** */
+       int (*read_mem_bulk)(uint32_t addr, uint32_t length,
+                       uint8_t *buffer);
+       /** */
+       int (*write_mem_bulk)(uint32_t addr, uint32_t length,
+                       const uint8_t *buffer);
+       /** */
+       int (*read_debug_reg)(uint32_t addr, uint32_t *val);
+       /** */
+       int (*write_debug_reg)(uint32_t addr, const uint32_t val);
+
+       /** */
+       int (*idcode)(uint32_t *idcode, uint8_t *num_of_idcode);
+       /** */
+       int (*state)(enum aice_target_state_s *state);
+
+       /** */
+       int (*set_jtag_clock)(uint32_t a_clock);
+       /** */
+       int (*select_target)(uint32_t target_id);
+
+       /** */
+       int (*memory_access)(enum nds_memory_access a_access);
+       /** */
+       int (*memory_mode)(enum nds_memory_select mem_select);
+
+       /** */
+       int (*read_tlb)(uint32_t virtual_address, uint32_t *physical_address);
+
+       /** */
+       int (*cache_ctl)(uint32_t subtype, uint32_t address);
+
+       /** */
+       int (*set_retry_times)(uint32_t a_retry_times);
+
+       /** */
+       int (*program_edm)(char *command_sequence);
+
+       /** */
+       int (*pack_command)(bool enable_pack_command);
+
+       /** */
+       int (*execute)(uint32_t *instructions, uint32_t instruction_num);
+
+       /** */
+       int (*set_custom_srst_script)(const char *script);
+
+       /** */
+       int (*set_custom_trst_script)(const char *script);
+
+       /** */
+       int (*set_custom_restart_script)(const char *script);
+
+       /** */
+       int (*set_count_to_check_dbger)(uint32_t count_to_check);
+
+       /** */
+       int (*set_data_endian)(enum aice_target_endian target_data_endian);
+};
+
+#define AICE_PORT_UNKNOWN      0
+#define AICE_PORT_AICE_USB     1
+#define AICE_PORT_AICE_PIPE    2
+
+/** */
+struct aice_port {
+       /** */
+       char *name;
+       /** */
+       int type;
+       /** */
+       struct aice_port_api_s *api;
+};
+
+/** */
+const struct aice_port *aice_port_get_list(void);
+
+#endif
diff --git a/src/jtag/aice/aice_transport.c b/src/jtag/aice/aice_transport.c
new file mode 100644 (file)
index 0000000..3add3d9
--- /dev/null
@@ -0,0 +1,385 @@
+/***************************************************************************
+ *   Copyright (C) 2013 by 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
+
+/* project specific includes */
+#include <jtag/interface.h>
+#include <jtag/tcl.h>
+#include <transport/transport.h>
+#include <target/target.h>
+#include <jtag/aice/aice_interface.h>
+#include <jtag/aice/aice_transport.h>
+
+/* */
+static int jim_newtap_expected_id(Jim_Nvp *n, Jim_GetOptInfo *goi,
+               struct jtag_tap *pTap)
+{
+       jim_wide w;
+       int e = Jim_GetOpt_Wide(goi, &w);
+       if (e != JIM_OK) {
+               Jim_SetResultFormatted(goi->interp, "option: %s bad parameter",
+                               n->name);
+               return e;
+       }
+
+       unsigned expected_len = sizeof(uint32_t) * pTap->expected_ids_cnt;
+       uint32_t *new_expected_ids = malloc(expected_len + sizeof(uint32_t));
+       if (new_expected_ids == NULL) {
+               Jim_SetResultFormatted(goi->interp, "no memory");
+               return JIM_ERR;
+       }
+
+       memcpy(new_expected_ids, pTap->expected_ids, expected_len);
+
+       new_expected_ids[pTap->expected_ids_cnt] = w;
+
+       free(pTap->expected_ids);
+       pTap->expected_ids = new_expected_ids;
+       pTap->expected_ids_cnt++;
+
+       return JIM_OK;
+}
+
+#define NTAP_OPT_EXPECTED_ID 0
+
+/* */
+static int jim_aice_newtap_cmd(Jim_GetOptInfo *goi)
+{
+       struct jtag_tap *pTap;
+       int x;
+       int e;
+       Jim_Nvp *n;
+       char *cp;
+       const Jim_Nvp opts[] = {
+               {.name = "-expected-id", .value = NTAP_OPT_EXPECTED_ID},
+               {.name = NULL, .value = -1},
+       };
+
+       pTap = calloc(1, sizeof(struct jtag_tap));
+       if (!pTap) {
+               Jim_SetResultFormatted(goi->interp, "no memory");
+               return JIM_ERR;
+       }
+
+       /*
+        * we expect CHIP + TAP + OPTIONS
+        * */
+       if (goi->argc < 3) {
+               Jim_SetResultFormatted(goi->interp,
+                               "Missing CHIP TAP OPTIONS ....");
+               free(pTap);
+               return JIM_ERR;
+       }
+       Jim_GetOpt_String(goi, &cp, NULL);
+       pTap->chip = strdup(cp);
+
+       Jim_GetOpt_String(goi, &cp, NULL);
+       pTap->tapname = strdup(cp);
+
+       /* name + dot + name + null */
+       x = strlen(pTap->chip) + 1 + strlen(pTap->tapname) + 1;
+       cp = malloc(x);
+       sprintf(cp, "%s.%s", pTap->chip, pTap->tapname);
+       pTap->dotted_name = cp;
+
+       LOG_DEBUG("Creating New Tap, Chip: %s, Tap: %s, Dotted: %s, %d params",
+                       pTap->chip, pTap->tapname, pTap->dotted_name, goi->argc);
+
+       while (goi->argc) {
+               e = Jim_GetOpt_Nvp(goi, opts, &n);
+               if (e != JIM_OK) {
+                       Jim_GetOpt_NvpUnknown(goi, opts, 0);
+                       free((void *)pTap->dotted_name);
+                       free(pTap);
+                       return e;
+               }
+               LOG_DEBUG("Processing option: %s", n->name);
+               switch (n->value) {
+                       case NTAP_OPT_EXPECTED_ID:
+                               e = jim_newtap_expected_id(n, goi, pTap);
+                               if (JIM_OK != e) {
+                                       free((void *)pTap->dotted_name);
+                                       free(pTap);
+                                       return e;
+                               }
+                               break;
+               }               /* switch (n->value) */
+       }                       /* while (goi->argc) */
+
+       /* default is enabled-after-reset */
+       pTap->enabled = !pTap->disabled_after_reset;
+
+       jtag_tap_init(pTap);
+       return JIM_OK;
+}
+
+/* */
+static int jim_aice_newtap(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+{
+       Jim_GetOptInfo goi;
+       Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
+       return jim_aice_newtap_cmd(&goi);
+}
+
+/* */
+COMMAND_HANDLER(handle_aice_init_command)
+{
+       if (CMD_ARGC != 0)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       static bool jtag_initialized;
+       if (jtag_initialized) {
+               LOG_INFO("'jtag init' has already been called");
+               return ERROR_OK;
+       }
+       jtag_initialized = true;
+
+       LOG_DEBUG("Initializing jtag devices...");
+       return jtag_init(CMD_CTX);
+}
+
+static int jim_aice_arp_init(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+{
+       LOG_DEBUG("No implement: jim_aice_arp_init");
+
+       return JIM_OK;
+}
+
+/* */
+static int aice_init_reset(struct command_context *cmd_ctx)
+{
+       LOG_DEBUG("Initializing with hard TRST+SRST reset");
+
+       int retval;
+       enum reset_types jtag_reset_config = jtag_get_reset_config();
+
+       jtag_add_reset(1, 0);   /* TAP_RESET */
+       if (jtag_reset_config & RESET_HAS_SRST) {
+               jtag_add_reset(1, 1);
+               if ((jtag_reset_config & RESET_SRST_PULLS_TRST) == 0)
+                       jtag_add_reset(0, 1);
+       }
+       jtag_add_reset(0, 0);
+       retval = jtag_execute_queue();
+       if (retval != ERROR_OK)
+               return retval;
+
+       return ERROR_OK;
+}
+
+/* */
+static int jim_aice_arp_init_reset(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
+{
+       int e = ERROR_OK;
+       Jim_GetOptInfo goi;
+       Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
+       if (goi.argc != 0) {
+               Jim_WrongNumArgs(goi.interp, 1, goi.argv - 1, "(no params)");
+               return JIM_ERR;
+       }
+       struct command_context *context = current_command_context(interp);
+       e = aice_init_reset(context);
+
+       if (e != ERROR_OK) {
+               Jim_Obj *eObj = Jim_NewIntObj(goi.interp, e);
+               Jim_SetResultFormatted(goi.interp, "error: %#s", eObj);
+               Jim_FreeNewObj(goi.interp, eObj);
+               return JIM_ERR;
+       }
+       return JIM_OK;
+}
+
+static int jim_aice_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+       Jim_GetOptInfo goi;
+       Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1);
+       if (goi.argc != 0) {
+               Jim_WrongNumArgs(goi.interp, 1, goi.argv, "Too many parameters");
+               return JIM_ERR;
+       }
+       Jim_SetResult(goi.interp, Jim_NewListObj(goi.interp, NULL, 0));
+       struct jtag_tap *tap;
+
+       for (tap = jtag_all_taps(); tap; tap = tap->next_tap)
+               Jim_ListAppendElement(goi.interp,
+                               Jim_GetResult(goi.interp),
+                               Jim_NewStringObj(goi.interp,
+                                       tap->dotted_name, -1));
+
+       return JIM_OK;
+}
+
+/* */
+static const struct command_registration
+aice_transport_jtag_subcommand_handlers[] = {
+       {
+               .name = "init",
+               .mode = COMMAND_ANY,
+               .handler = handle_aice_init_command,
+               .help = "initialize jtag scan chain",
+               .usage = ""
+       },
+       {
+               .name = "arp_init",
+               .mode = COMMAND_ANY,
+               .jim_handler = jim_aice_arp_init,
+               .help = "Validates JTAG scan chain against the list of "
+                       "declared TAPs.",
+       },
+       {
+               .name = "arp_init-reset",
+               .mode = COMMAND_ANY,
+               .jim_handler = jim_aice_arp_init_reset,
+               .help = "Uses TRST and SRST to try resetting everything on "
+                       "the JTAG scan chain, then performs 'jtag arp_init'."
+       },
+       {
+               .name = "newtap",
+               .mode = COMMAND_CONFIG,
+               .jim_handler = jim_aice_newtap,
+               .help = "Create a new TAP instance named basename.tap_type, "
+                       "and appends it to the scan chain.",
+               .usage = "basename tap_type ['-expected_id' number]"
+       },
+       {
+               .name = "tapisenabled",
+               .mode = COMMAND_EXEC,
+               .jim_handler = jim_jtag_tap_enabler,
+               .help = "Returns a Tcl boolean (0/1) indicating whether "
+                       "the TAP is enabled (1) or not (0).",
+               .usage = "tap_name",
+       },
+       {
+               .name = "tapenable",
+               .mode = COMMAND_EXEC,
+               .jim_handler = jim_jtag_tap_enabler,
+               .help = "Try to enable the specified TAP using the "
+                       "'tap-enable' TAP event.",
+               .usage = "tap_name",
+       },
+       {
+               .name = "tapdisable",
+               .mode = COMMAND_EXEC,
+               .jim_handler = jim_jtag_tap_enabler,
+               .help = "Try to disable the specified TAP using the "
+                       "'tap-disable' TAP event.",
+               .usage = "tap_name",
+       },
+       {
+               .name = "configure",
+               .mode = COMMAND_EXEC,
+               .jim_handler = jim_jtag_configure,
+               .help = "Provide a Tcl handler for the specified "
+                       "TAP event.",
+               .usage = "tap_name '-event' event_name handler",
+       },
+       {
+               .name = "cget",
+               .mode = COMMAND_EXEC,
+               .jim_handler = jim_jtag_configure,
+               .help = "Return any Tcl handler for the specified "
+                       "TAP event.",
+               .usage = "tap_name '-event' event_name",
+       },
+       {
+               .name = "names",
+               .mode = COMMAND_ANY,
+               .jim_handler = jim_aice_names,
+               .help = "Returns list of all JTAG tap names.",
+       },
+
+       COMMAND_REGISTRATION_DONE
+};
+
+/* */
+static const struct command_registration aice_transport_command_handlers[] = {
+       {
+               .name = "jtag",
+               .mode = COMMAND_ANY,
+               .usage = "",
+               .chain = aice_transport_jtag_subcommand_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+
+};
+
+/* */
+static int aice_transport_register_commands(struct command_context *cmd_ctx)
+{
+       return register_commands(cmd_ctx, NULL,
+                       aice_transport_command_handlers);
+}
+
+/* */
+static int aice_transport_init(struct command_context *cmd_ctx)
+{
+       LOG_DEBUG("aice_transport_init");
+       struct target *t = get_current_target(cmd_ctx);
+       struct transport *transport;
+
+       if (!t) {
+               LOG_ERROR("no current target");
+               return ERROR_FAIL;
+       }
+
+       transport = get_current_transport();
+
+       if (!transport) {
+               LOG_ERROR("no transport selected");
+               return ERROR_FAIL;
+       }
+
+       LOG_DEBUG("current transport %s", transport->name);
+
+       return aice_init_target(t);
+}
+
+/* */
+static int aice_transport_select(struct command_context *ctx)
+{
+       LOG_DEBUG("aice_transport_select");
+
+       int retval;
+
+       retval = aice_transport_register_commands(ctx);
+
+       if (retval != ERROR_OK)
+               return retval;
+
+       return ERROR_OK;
+}
+
+static struct transport aice_jtag_transport = {
+       .name = "aice_jtag",
+       .select = aice_transport_select,
+       .init = aice_transport_init,
+};
+
+const char *aice_transports[] = { "aice_jtag", NULL };
+
+static void aice_constructor(void) __attribute__((constructor));
+static void aice_constructor(void)
+{
+       transport_register(&aice_jtag_transport);
+}
+
diff --git a/src/jtag/aice/aice_transport.h b/src/jtag/aice/aice_transport.h
new file mode 100644 (file)
index 0000000..e93d131
--- /dev/null
@@ -0,0 +1,26 @@
+/***************************************************************************
+ *   Copyright (C) 2013 by 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 _AICE_TRANSPORT_
+#define _AICE_TRANSPORT_
+
+extern const char *aice_transports[];
+
+#endif
diff --git a/src/jtag/aice/aice_usb.c b/src/jtag/aice/aice_usb.c
new file mode 100644 (file)
index 0000000..8a5b311
--- /dev/null
@@ -0,0 +1,3505 @@
+/***************************************************************************
+ *   Copyright (C) 2013 by 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 <jtag/drivers/libusb_common.h>
+#include <helper/log.h>
+#include <helper/time_support.h>
+#include <target/target.h>
+#include <jtag/jtag.h>
+#include <target/nds32_insn.h>
+#include <target/nds32_reg.h>
+#include "aice_usb.h"
+
+
+/* Global USB buffers */
+static uint8_t usb_in_buffer[AICE_IN_BUFFER_SIZE];
+static uint8_t usb_out_buffer[AICE_OUT_BUFFER_SIZE];
+static uint8_t current_target_id;
+static uint32_t jtag_clock;
+static struct aice_usb_handler_s aice_handler;
+/* AICE max retry times. If AICE command timeout, retry it. */
+static int aice_max_retry_times = 10;
+/* Default endian is little endian. */
+static enum aice_target_endian data_endian;
+
+
+/***************************************************************************/
+/* AICE commands' pack/unpack functions */
+static void aice_pack_htda(uint8_t cmd_code, uint8_t extra_word_length,
+               uint32_t address)
+{
+       usb_out_buffer[0] = cmd_code;
+       usb_out_buffer[1] = extra_word_length;
+       usb_out_buffer[2] = (uint8_t)(address & 0xFF);
+}
+
+static void aice_pack_htdc(uint8_t cmd_code, uint8_t extra_word_length,
+               uint32_t address, uint32_t word, enum aice_target_endian access_endian)
+{
+       usb_out_buffer[0] = cmd_code;
+       usb_out_buffer[1] = extra_word_length;
+       usb_out_buffer[2] = (uint8_t)(address & 0xFF);
+       if (access_endian == AICE_BIG_ENDIAN) {
+               *(uint32_t *)(usb_out_buffer + 3) = word;
+       } else {
+               usb_out_buffer[3] = (uint8_t)((word >> 24) & 0xFF);
+               usb_out_buffer[4] = (uint8_t)((word >> 16) & 0xFF);
+               usb_out_buffer[5] = (uint8_t)((word >> 8) & 0xFF);
+               usb_out_buffer[6] = (uint8_t)(word & 0xFF);
+       }
+}
+
+static void aice_pack_htdma(uint8_t cmd_code, uint8_t target_id,
+               uint8_t extra_word_length, uint32_t address)
+{
+       usb_out_buffer[0] = cmd_code;
+       usb_out_buffer[1] = target_id;
+       usb_out_buffer[2] = extra_word_length;
+       usb_out_buffer[3] = (uint8_t)(address & 0xFF);
+}
+
+static void aice_pack_htdmb(uint8_t cmd_code, uint8_t target_id,
+               uint8_t extra_word_length, uint32_t address)
+{
+       usb_out_buffer[0] = cmd_code;
+       usb_out_buffer[1] = target_id;
+       usb_out_buffer[2] = extra_word_length;
+       usb_out_buffer[3] = 0;
+       usb_out_buffer[4] = (uint8_t)((address >> 24) & 0xFF);
+       usb_out_buffer[5] = (uint8_t)((address >> 16) & 0xFF);
+       usb_out_buffer[6] = (uint8_t)((address >> 8) & 0xFF);
+       usb_out_buffer[7] = (uint8_t)(address & 0xFF);
+}
+
+static void aice_pack_htdmc(uint8_t cmd_code, uint8_t target_id,
+               uint8_t extra_word_length, uint32_t address, uint32_t word,
+               enum aice_target_endian access_endian)
+{
+       usb_out_buffer[0] = cmd_code;
+       usb_out_buffer[1] = target_id;
+       usb_out_buffer[2] = extra_word_length;
+       usb_out_buffer[3] = (uint8_t)(address & 0xFF);
+       if (access_endian == AICE_BIG_ENDIAN) {
+               *(uint32_t *)(usb_out_buffer + 4) = word;
+       } else {
+               usb_out_buffer[4] = (uint8_t)((word >> 24) & 0xFF);
+               usb_out_buffer[5] = (uint8_t)((word >> 16) & 0xFF);
+               usb_out_buffer[6] = (uint8_t)((word >> 8) & 0xFF);
+               usb_out_buffer[7] = (uint8_t)(word & 0xFF);
+       }
+}
+
+static void aice_pack_htdmc_multiple_data(uint8_t cmd_code, uint8_t target_id,
+               uint8_t extra_word_length, uint32_t address, uint32_t *word,
+               uint8_t num_of_words, enum aice_target_endian access_endian)
+{
+       usb_out_buffer[0] = cmd_code;
+       usb_out_buffer[1] = target_id;
+       usb_out_buffer[2] = extra_word_length;
+       usb_out_buffer[3] = (uint8_t)(address & 0xFF);
+
+       uint8_t i;
+       for (i = 0 ; i < num_of_words ; i++, word++) {
+               if (access_endian == AICE_BIG_ENDIAN) {
+                       *(uint32_t *)(usb_out_buffer + 4 + i * 4) = *word;
+               } else {
+                       usb_out_buffer[4 + i * 4] = (uint8_t)((*word >> 24) & 0xFF);
+                       usb_out_buffer[5 + i * 4] = (uint8_t)((*word >> 16) & 0xFF);
+                       usb_out_buffer[6 + i * 4] = (uint8_t)((*word >> 8) & 0xFF);
+                       usb_out_buffer[7 + i * 4] = (uint8_t)(*word & 0xFF);
+               }
+       }
+}
+
+static void aice_pack_htdmd(uint8_t cmd_code, uint8_t target_id,
+               uint8_t extra_word_length, uint32_t address, uint32_t word,
+               enum aice_target_endian access_endian)
+{
+       usb_out_buffer[0] = cmd_code;
+       usb_out_buffer[1] = target_id;
+       usb_out_buffer[2] = extra_word_length;
+       usb_out_buffer[3] = 0;
+       usb_out_buffer[4] = (uint8_t)((address >> 24) & 0xFF);
+       usb_out_buffer[5] = (uint8_t)((address >> 16) & 0xFF);
+       usb_out_buffer[6] = (uint8_t)((address >> 8) & 0xFF);
+       usb_out_buffer[7] = (uint8_t)(address & 0xFF);
+       if (access_endian == AICE_BIG_ENDIAN) {
+               *(uint32_t *)(usb_out_buffer + 8) = word;
+       } else {
+               usb_out_buffer[8] = (uint8_t)((word >> 24) & 0xFF);
+               usb_out_buffer[9] = (uint8_t)((word >> 16) & 0xFF);
+               usb_out_buffer[10] = (uint8_t)((word >> 8) & 0xFF);
+               usb_out_buffer[11] = (uint8_t)(word & 0xFF);
+       }
+}
+
+static void aice_pack_htdmd_multiple_data(uint8_t cmd_code, uint8_t target_id,
+               uint8_t extra_word_length, uint32_t address, const uint32_t *word,
+               enum aice_target_endian access_endian)
+{
+       usb_out_buffer[0] = cmd_code;
+       usb_out_buffer[1] = target_id;
+       usb_out_buffer[2] = extra_word_length;
+       usb_out_buffer[3] = 0;
+       usb_out_buffer[4] = (uint8_t)((address >> 24) & 0xFF);
+       usb_out_buffer[5] = (uint8_t)((address >> 16) & 0xFF);
+       usb_out_buffer[6] = (uint8_t)((address >> 8) & 0xFF);
+       usb_out_buffer[7] = (uint8_t)(address & 0xFF);
+
+       uint32_t i;
+       /* num_of_words may be over 0xFF, so use uint32_t */
+       uint32_t num_of_words = extra_word_length + 1;
+
+       for (i = 0 ; i < num_of_words ; i++, word++) {
+               if (access_endian == AICE_BIG_ENDIAN) {
+                       *(uint32_t *)(usb_out_buffer + 8 + i * 4) = *word;
+               } else {
+                       usb_out_buffer[8 + i * 4] = (uint8_t)((*word >> 24) & 0xFF);
+                       usb_out_buffer[9 + i * 4] = (uint8_t)((*word >> 16) & 0xFF);
+                       usb_out_buffer[10 + i * 4] = (uint8_t)((*word >> 8) & 0xFF);
+                       usb_out_buffer[11 + i * 4] = (uint8_t)(*word & 0xFF);
+               }
+       }
+}
+
+static void aice_unpack_dtha(uint8_t *cmd_ack_code, uint8_t *extra_word_length,
+               uint32_t *word, enum aice_target_endian access_endian)
+{
+       *cmd_ack_code = usb_in_buffer[0];
+       *extra_word_length = usb_in_buffer[1];
+
+       if (access_endian == AICE_BIG_ENDIAN) {
+               *word = *(uint32_t *)(usb_in_buffer + 2);
+       } else {
+               *word = (usb_in_buffer[2] << 24) |
+                       (usb_in_buffer[3] << 16) |
+                       (usb_in_buffer[4] << 8) |
+                       (usb_in_buffer[5]);
+       }
+}
+
+static void aice_unpack_dtha_multiple_data(uint8_t *cmd_ack_code,
+               uint8_t *extra_word_length, uint32_t *word, uint8_t num_of_words,
+               enum aice_target_endian access_endian)
+{
+       *cmd_ack_code = usb_in_buffer[0];
+       *extra_word_length = usb_in_buffer[1];
+
+       uint8_t i;
+       for (i = 0 ; i < num_of_words ; i++, word++) {
+               if (access_endian == AICE_BIG_ENDIAN) {
+                       *word = *(uint32_t *)(usb_in_buffer + 2 + i * 4);
+               } else {
+                       *word = (usb_in_buffer[2 + i * 4] << 24) |
+                               (usb_in_buffer[3 + i * 4] << 16) |
+                               (usb_in_buffer[4 + i * 4] << 8) |
+                               (usb_in_buffer[5 + i * 4]);
+               }
+       }
+}
+
+static void aice_unpack_dthb(uint8_t *cmd_ack_code, uint8_t *extra_word_length)
+{
+       *cmd_ack_code = usb_in_buffer[0];
+       *extra_word_length = usb_in_buffer[1];
+}
+
+static void aice_unpack_dthma(uint8_t *cmd_ack_code, uint8_t *target_id,
+               uint8_t *extra_word_length, uint32_t *word,
+               enum aice_target_endian access_endian)
+{
+       *cmd_ack_code = usb_in_buffer[0];
+       *target_id = usb_in_buffer[1];
+       *extra_word_length = usb_in_buffer[2];
+       if (access_endian == AICE_BIG_ENDIAN) {
+               *word = *(uint32_t *)(usb_in_buffer + 4);
+       } else {
+               *word = (usb_in_buffer[4] << 24) |
+                       (usb_in_buffer[5] << 16) |
+                       (usb_in_buffer[6] << 8) |
+                       (usb_in_buffer[7]);
+       }
+}
+
+static void aice_unpack_dthma_multiple_data(uint8_t *cmd_ack_code,
+               uint8_t *target_id, uint8_t *extra_word_length, uint32_t *word,
+               enum aice_target_endian access_endian)
+{
+       *cmd_ack_code = usb_in_buffer[0];
+       *target_id = usb_in_buffer[1];
+       *extra_word_length = usb_in_buffer[2];
+       if (access_endian == AICE_BIG_ENDIAN) {
+               *word = *(uint32_t *)(usb_in_buffer + 4);
+       } else {
+               *word = (usb_in_buffer[4] << 24) |
+                       (usb_in_buffer[5] << 16) |
+                       (usb_in_buffer[6] << 8) |
+                       (usb_in_buffer[7]);
+       }
+       word++;
+
+       uint8_t i;
+       for (i = 0; i < *extra_word_length; i++) {
+               if (access_endian == AICE_BIG_ENDIAN) {
+                       *word = *(uint32_t *)(usb_in_buffer + 8 + i * 4);
+               } else {
+                       *word = (usb_in_buffer[8 + i * 4] << 24) |
+                               (usb_in_buffer[9 + i * 4] << 16) |
+                               (usb_in_buffer[10 + i * 4] << 8) |
+                               (usb_in_buffer[11 + i * 4]);
+               }
+               word++;
+       }
+}
+
+static void aice_unpack_dthmb(uint8_t *cmd_ack_code, uint8_t *target_id,
+               uint8_t *extra_word_length)
+{
+       *cmd_ack_code = usb_in_buffer[0];
+       *target_id = usb_in_buffer[1];
+       *extra_word_length = usb_in_buffer[2];
+}
+
+/***************************************************************************/
+/* End of AICE commands' pack/unpack functions */
+
+/* calls the given usb_bulk_* function, allowing for the data to
+ * trickle in with some timeouts  */
+static int usb_bulk_with_retries(
+                       int (*f)(jtag_libusb_device_handle *, int, char *, int, int),
+                       jtag_libusb_device_handle *dev, int ep,
+                       char *bytes, int size, int timeout)
+{
+       int tries = 3, count = 0;
+
+       while (tries && (count < size)) {
+               int result = f(dev, ep, bytes + count, size - count, timeout);
+               if (result > 0)
+                       count += result;
+               else if ((-ETIMEDOUT != result) || !--tries)
+                       return result;
+       }
+       return count;
+}
+
+static int wrap_usb_bulk_write(jtag_libusb_device_handle *dev, int ep,
+               char *buff, int size, int timeout)
+{
+       /* usb_bulk_write() takes const char *buff */
+       return jtag_libusb_bulk_write(dev, ep, buff, size, timeout);
+}
+
+static inline int usb_bulk_write_ex(jtag_libusb_device_handle *dev, int ep,
+               char *bytes, int size, int timeout)
+{
+       return usb_bulk_with_retries(&wrap_usb_bulk_write,
+                       dev, ep, bytes, size, timeout);
+}
+
+static inline int usb_bulk_read_ex(jtag_libusb_device_handle *dev, int ep,
+               char *bytes, int size, int timeout)
+{
+       return usb_bulk_with_retries(&jtag_libusb_bulk_read,
+                       dev, ep, bytes, size, timeout);
+}
+
+/* Write data from out_buffer to USB. */
+static int aice_usb_write(uint8_t *out_buffer, int out_length)
+{
+       int result;
+
+       if (out_length > AICE_OUT_BUFFER_SIZE) {
+               LOG_ERROR("aice_write illegal out_length=%d (max=%d)",
+                               out_length, AICE_OUT_BUFFER_SIZE);
+               return -1;
+       }
+
+       result = usb_bulk_write_ex(aice_handler.usb_handle, aice_handler.usb_write_ep,
+                       (char *)out_buffer, out_length, AICE_USB_TIMEOUT);
+
+       DEBUG_JTAG_IO("aice_usb_write, out_length = %d, result = %d",
+                       out_length, result);
+
+       return result;
+}
+
+/* Read data from USB into in_buffer. */
+static int aice_usb_read(uint8_t *in_buffer, int expected_size)
+{
+       int result = usb_bulk_read_ex(aice_handler.usb_handle, aice_handler.usb_read_ep,
+                       (char *)in_buffer, expected_size, AICE_USB_TIMEOUT);
+
+       DEBUG_JTAG_IO("aice_usb_read, result = %d", result);
+
+       return result;
+}
+
+static uint8_t usb_out_packets_buffer[AICE_OUT_PACKETS_BUFFER_SIZE];
+static uint8_t usb_in_packets_buffer[AICE_IN_PACKETS_BUFFER_SIZE];
+static uint32_t usb_out_packets_buffer_length;
+static uint32_t usb_in_packets_buffer_length;
+static bool usb_pack_command;
+
+static int aice_usb_packet_flush(void)
+{
+       if (usb_out_packets_buffer_length == 0)
+               return 0;
+
+       LOG_DEBUG("Flush usb packets");
+
+       int result;
+
+       aice_usb_write(usb_out_packets_buffer, usb_out_packets_buffer_length);
+       result = aice_usb_read(usb_in_packets_buffer, usb_in_packets_buffer_length);
+
+       usb_out_packets_buffer_length = 0;
+       usb_in_packets_buffer_length = 0;
+
+       return result;
+}
+
+static void aice_usb_packet_append(uint8_t *out_buffer, int out_length,
+               int in_length)
+{
+       if (usb_out_packets_buffer_length + out_length > AICE_OUT_PACKETS_BUFFER_SIZE)
+               aice_usb_packet_flush();
+
+       LOG_DEBUG("Append usb packets 0x%02x", out_buffer[0]);
+
+       memcpy(usb_out_packets_buffer + usb_out_packets_buffer_length,
+                       out_buffer,
+                       out_length);
+       usb_out_packets_buffer_length += out_length;
+       usb_in_packets_buffer_length += in_length;
+}
+
+/***************************************************************************/
+/* AICE commands */
+static int aice_scan_chain(uint32_t *id_codes, uint8_t *num_of_ids)
+{
+       int result;
+       int retry_times = 0;
+
+       if (usb_pack_command)
+               aice_usb_packet_flush();
+
+       do {
+               aice_pack_htda(AICE_CMD_SCAN_CHAIN, 0x0F, 0x0);
+
+               aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDA);
+
+               LOG_DEBUG("SCAN_CHAIN, length: 0x0F");
+
+               /** TODO: modify receive length */
+               result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHA);
+               if (AICE_FORMAT_DTHA != result) {
+                       LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)",
+                                       AICE_FORMAT_DTHA, result);
+                       return ERROR_FAIL;
+               }
+
+               uint8_t cmd_ack_code;
+               aice_unpack_dtha_multiple_data(&cmd_ack_code, num_of_ids, id_codes,
+                               0x10, AICE_LITTLE_ENDIAN);
+
+               LOG_DEBUG("SCAN_CHAIN response, # of IDs: %d", *num_of_ids);
+
+               if (cmd_ack_code != AICE_CMD_SCAN_CHAIN) {
+                       LOG_ERROR("aice command timeout (command=0x%x, response=0x%x)",
+                                       AICE_CMD_SCAN_CHAIN, cmd_ack_code);
+
+                       if (retry_times > aice_max_retry_times)
+                               return ERROR_FAIL;
+
+                       /* clear timeout and retry */
+                       if (aice_write_ctrl(AICE_WRITE_CTRL_CLEAR_TIMEOUT_STATUS, 0x1) != ERROR_OK)
+                               return ERROR_FAIL;
+
+                       retry_times++;
+                       continue;
+               }
+
+               if (*num_of_ids == 0xFF) {
+                       LOG_ERROR("No target connected");
+                       return ERROR_FAIL;
+               } else if (*num_of_ids == 0x10) {
+                       LOG_INFO("The ice chain over 16 targets");
+               } else {
+                       (*num_of_ids)++;
+               }
+               break;
+       } while (1);
+
+       return ERROR_OK;
+}
+
+int aice_read_ctrl(uint32_t address, uint32_t *data)
+{
+       int result;
+
+       if (usb_pack_command)
+               aice_usb_packet_flush();
+
+       aice_pack_htda(AICE_CMD_READ_CTRL, 0, address);
+
+       aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDA);
+
+       LOG_DEBUG("READ_CTRL, address: 0x%x", address);
+
+       result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHA);
+       if (AICE_FORMAT_DTHA != result) {
+               LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)",
+                               AICE_FORMAT_DTHA, result);
+               return ERROR_FAIL;
+       }
+
+       uint8_t cmd_ack_code;
+       uint8_t extra_length;
+       aice_unpack_dtha(&cmd_ack_code, &extra_length, data, AICE_LITTLE_ENDIAN);
+
+       LOG_DEBUG("READ_CTRL response, data: 0x%x", *data);
+
+       if (cmd_ack_code != AICE_CMD_READ_CTRL) {
+               LOG_ERROR("aice command error (command=0x%x, response=0x%x)",
+                               AICE_CMD_READ_CTRL, cmd_ack_code);
+               return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+int aice_write_ctrl(uint32_t address, uint32_t data)
+{
+       int result;
+
+       if (usb_pack_command)
+               aice_usb_packet_flush();
+
+       aice_pack_htdc(AICE_CMD_WRITE_CTRL, 0, address, data, AICE_LITTLE_ENDIAN);
+
+       aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDC);
+
+       LOG_DEBUG("WRITE_CTRL, address: 0x%x, data: 0x%x", address, data);
+
+       result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHB);
+       if (AICE_FORMAT_DTHB != result) {
+               LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)",
+                               AICE_FORMAT_DTHB, result);
+               return ERROR_FAIL;
+       }
+
+       uint8_t cmd_ack_code;
+       uint8_t extra_length;
+       aice_unpack_dthb(&cmd_ack_code, &extra_length);
+
+       LOG_DEBUG("WRITE_CTRL response");
+
+       if (cmd_ack_code != AICE_CMD_WRITE_CTRL) {
+               LOG_ERROR("aice command error (command=0x%x, response=0x%x)",
+                               AICE_CMD_WRITE_CTRL, cmd_ack_code);
+               return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+int aice_read_dtr(uint8_t target_id, uint32_t *data)
+{
+       int result;
+       int retry_times = 0;
+
+       if (usb_pack_command)
+               aice_usb_packet_flush();
+
+       do {
+               aice_pack_htdma(AICE_CMD_T_READ_DTR, target_id, 0, 0);
+
+               aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMA);
+
+               LOG_DEBUG("READ_DTR");
+
+               result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMA);
+               if (AICE_FORMAT_DTHMA != result) {
+                       LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)",
+                                       AICE_FORMAT_DTHMA, result);
+                       return ERROR_FAIL;
+               }
+
+               uint8_t cmd_ack_code;
+               uint8_t extra_length;
+               uint8_t res_target_id;
+               aice_unpack_dthma(&cmd_ack_code, &res_target_id, &extra_length,
+                               data, AICE_LITTLE_ENDIAN);
+
+               LOG_DEBUG("READ_DTR response, data: 0x%x", *data);
+
+               if (cmd_ack_code == AICE_CMD_T_READ_DTR) {
+                       break;
+               } else {
+                       LOG_ERROR("aice command timeout (command=0x%x, response=0x%x)",
+                                       AICE_CMD_T_READ_DTR, cmd_ack_code);
+
+                       if (retry_times > aice_max_retry_times)
+                               return ERROR_FAIL;
+
+                       /* clear timeout and retry */
+                       if (aice_write_ctrl(AICE_WRITE_CTRL_CLEAR_TIMEOUT_STATUS, 0x1) != ERROR_OK)
+                               return ERROR_FAIL;
+
+                       retry_times++;
+               }
+       } while (1);
+
+       return ERROR_OK;
+}
+
+int aice_write_dtr(uint8_t target_id, uint32_t data)
+{
+       int result;
+       int retry_times = 0;
+
+       if (usb_pack_command)
+               aice_usb_packet_flush();
+
+       do {
+               aice_pack_htdmc(AICE_CMD_T_WRITE_DTR, target_id, 0, 0, data,
+                               AICE_LITTLE_ENDIAN);
+
+               aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMC);
+
+               LOG_DEBUG("WRITE_DTR, data: 0x%x", data);
+
+               result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMB);
+               if (AICE_FORMAT_DTHMB != result) {
+                       LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)",
+                                       AICE_FORMAT_DTHMB, result);
+                       return ERROR_FAIL;
+               }
+
+               uint8_t cmd_ack_code;
+               uint8_t extra_length;
+               uint8_t res_target_id;
+               aice_unpack_dthmb(&cmd_ack_code, &res_target_id, &extra_length);
+
+               LOG_DEBUG("WRITE_DTR response");
+
+               if (cmd_ack_code == AICE_CMD_T_WRITE_DTR) {
+                       break;
+               } else {
+                       LOG_ERROR("aice command timeout (command=0x%x, response=0x%x)",
+                                       AICE_CMD_T_WRITE_DTR, cmd_ack_code);
+
+                       if (retry_times > aice_max_retry_times)
+                               return ERROR_FAIL;
+
+                       /* clear timeout and retry */
+                       if (aice_write_ctrl(AICE_WRITE_CTRL_CLEAR_TIMEOUT_STATUS, 0x1) != ERROR_OK)
+                               return ERROR_FAIL;
+
+                       retry_times++;
+               }
+       } while (1);
+
+       return ERROR_OK;
+}
+
+int aice_read_misc(uint8_t target_id, uint32_t address, uint32_t *data)
+{
+       int result;
+       int retry_times = 0;
+
+       if (usb_pack_command)
+               aice_usb_packet_flush();
+
+       do {
+               aice_pack_htdma(AICE_CMD_T_READ_MISC, target_id, 0, address);
+
+               aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMA);
+
+               LOG_DEBUG("READ_MISC, address: 0x%x", address);
+
+               result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMA);
+               if (AICE_FORMAT_DTHMA != result) {
+                       LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)",
+                                       AICE_FORMAT_DTHMA, result);
+                       return ERROR_AICE_DISCONNECT;
+               }
+
+               uint8_t cmd_ack_code;
+               uint8_t extra_length;
+               uint8_t res_target_id;
+               aice_unpack_dthma(&cmd_ack_code, &res_target_id, &extra_length,
+                               data, AICE_LITTLE_ENDIAN);
+
+               LOG_DEBUG("READ_MISC response, data: 0x%x", *data);
+
+               if (cmd_ack_code == AICE_CMD_T_READ_MISC) {
+                       break;
+               } else {
+                       LOG_ERROR("aice command timeout (command=0x%x, response=0x%x)",
+                                       AICE_CMD_T_READ_MISC, cmd_ack_code);
+
+                       if (retry_times > aice_max_retry_times)
+                               return ERROR_FAIL;
+
+                       /* clear timeout and retry */
+                       if (aice_write_ctrl(AICE_WRITE_CTRL_CLEAR_TIMEOUT_STATUS, 0x1) != ERROR_OK)
+                               return ERROR_FAIL;
+
+                       retry_times++;
+               }
+       } while (1);
+
+       return ERROR_OK;
+}
+
+int aice_write_misc(uint8_t target_id, uint32_t address, uint32_t data)
+{
+       int result;
+       int retry_times = 0;
+
+       if (usb_pack_command)
+               aice_usb_packet_flush();
+
+       do {
+               aice_pack_htdmc(AICE_CMD_T_WRITE_MISC, target_id, 0, address,
+                               data, AICE_LITTLE_ENDIAN);
+
+               aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMC);
+
+               LOG_DEBUG("WRITE_MISC, address: 0x%x, data: 0x%x", address, data);
+
+               result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMB);
+               if (AICE_FORMAT_DTHMB != result) {
+                       LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)",
+                                       AICE_FORMAT_DTHMB, result);
+                       return ERROR_FAIL;
+               }
+
+               uint8_t cmd_ack_code;
+               uint8_t extra_length;
+               uint8_t res_target_id;
+               aice_unpack_dthmb(&cmd_ack_code, &res_target_id, &extra_length);
+
+               LOG_DEBUG("WRITE_MISC response");
+
+               if (cmd_ack_code == AICE_CMD_T_WRITE_MISC) {
+                       break;
+               } else {
+                       LOG_ERROR("aice command timeout (command=0x%x, response=0x%x)",
+                                       AICE_CMD_T_WRITE_MISC, cmd_ack_code);
+
+                       if (retry_times > aice_max_retry_times)
+                               return ERROR_FAIL;
+
+                       /* clear timeout and retry */
+                       if (aice_write_ctrl(AICE_WRITE_CTRL_CLEAR_TIMEOUT_STATUS, 0x1) != ERROR_OK)
+                               return ERROR_FAIL;
+
+                       retry_times++;
+               }
+       } while (1);
+
+       return ERROR_OK;
+}
+
+int aice_read_edmsr(uint8_t target_id, uint32_t address, uint32_t *data)
+{
+       int result;
+       int retry_times = 0;
+
+       if (usb_pack_command)
+               aice_usb_packet_flush();
+
+       do {
+               aice_pack_htdma(AICE_CMD_T_READ_EDMSR, target_id, 0, address);
+
+               aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMA);
+
+               LOG_DEBUG("READ_EDMSR, address: 0x%x", address);
+
+               result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMA);
+               if (AICE_FORMAT_DTHMA != result) {
+                       LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)",
+                                       AICE_FORMAT_DTHMA, result);
+                       return ERROR_FAIL;
+               }
+
+               uint8_t cmd_ack_code;
+               uint8_t extra_length;
+               uint8_t res_target_id;
+               aice_unpack_dthma(&cmd_ack_code, &res_target_id, &extra_length,
+                               data, AICE_LITTLE_ENDIAN);
+
+               LOG_DEBUG("READ_EDMSR response, data: 0x%x", *data);
+
+               if (cmd_ack_code == AICE_CMD_T_READ_EDMSR) {
+                       break;
+               } else {
+                       LOG_ERROR("aice command timeout (command=0x%x, response=0x%x)",
+                                       AICE_CMD_T_READ_EDMSR, cmd_ack_code);
+
+                       if (retry_times > aice_max_retry_times)
+                               return ERROR_FAIL;
+
+                       /* clear timeout and retry */
+                       if (aice_write_ctrl(AICE_WRITE_CTRL_CLEAR_TIMEOUT_STATUS, 0x1) != ERROR_OK)
+                               return ERROR_FAIL;
+
+                       retry_times++;
+               }
+       } while (1);
+
+       return ERROR_OK;
+}
+
+int aice_write_edmsr(uint8_t target_id, uint32_t address, uint32_t data)
+{
+       int result;
+       int retry_times = 0;
+
+       if (usb_pack_command)
+               aice_usb_packet_flush();
+
+       do {
+               aice_pack_htdmc(AICE_CMD_T_WRITE_EDMSR, target_id, 0, address,
+                               data, AICE_LITTLE_ENDIAN);
+
+               aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMC);
+
+               LOG_DEBUG("WRITE_EDMSR, address: 0x%x, data: 0x%x", address, data);
+
+               result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMB);
+               if (AICE_FORMAT_DTHMB != result) {
+                       LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)",
+                                       AICE_FORMAT_DTHMB, result);
+                       return ERROR_FAIL;
+               }
+
+               uint8_t cmd_ack_code;
+               uint8_t extra_length;
+               uint8_t res_target_id;
+               aice_unpack_dthmb(&cmd_ack_code, &res_target_id, &extra_length);
+
+               LOG_DEBUG("WRITE_EDMSR response");
+
+               if (cmd_ack_code == AICE_CMD_T_WRITE_EDMSR) {
+                       break;
+               } else {
+                       LOG_ERROR("aice command timeout (command=0x%x, response=0x%x)",
+                                       AICE_CMD_T_WRITE_EDMSR, cmd_ack_code);
+
+                       if (retry_times > aice_max_retry_times)
+                               return ERROR_FAIL;
+
+                       /* clear timeout and retry */
+                       if (aice_write_ctrl(AICE_WRITE_CTRL_CLEAR_TIMEOUT_STATUS, 0x1) != ERROR_OK)
+                               return ERROR_FAIL;
+
+                       retry_times++;
+               }
+       } while (1);
+
+       return ERROR_OK;
+}
+
+static int aice_switch_to_big_endian(uint32_t *word, uint8_t num_of_words)
+{
+       uint32_t tmp;
+
+       for (uint8_t i = 0 ; i < num_of_words ; i++) {
+               tmp = ((word[i] >> 24) & 0x000000FF) |
+                       ((word[i] >>  8) & 0x0000FF00) |
+                       ((word[i] <<  8) & 0x00FF0000) |
+                       ((word[i] << 24) & 0xFF000000);
+               word[i] = tmp;
+       }
+
+       return ERROR_OK;
+}
+
+static int aice_write_dim(uint8_t target_id, uint32_t *word, uint8_t num_of_words)
+{
+       int result;
+       uint32_t big_endian_word[4];
+       int retry_times = 0;
+
+       if (usb_pack_command)
+               aice_usb_packet_flush();
+
+       memcpy(big_endian_word, word, sizeof(big_endian_word));
+
+       /** instruction is big-endian */
+       aice_switch_to_big_endian(big_endian_word, num_of_words);
+
+       do {
+               aice_pack_htdmc_multiple_data(AICE_CMD_T_WRITE_DIM, target_id,
+                               num_of_words - 1, 0,
+                               big_endian_word, num_of_words, AICE_LITTLE_ENDIAN);
+
+               aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMC + (num_of_words - 1) * 4);
+
+               LOG_DEBUG("WRITE_DIM, data: 0x%08x, 0x%08x, 0x%08x, 0x%08x",
+                               big_endian_word[0],
+                               big_endian_word[1],
+                               big_endian_word[2],
+                               big_endian_word[3]);
+
+               result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMB);
+               if (AICE_FORMAT_DTHMB != result) {
+                       LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)",
+                                       AICE_FORMAT_DTHMB, result);
+                       return ERROR_FAIL;
+               }
+
+               uint8_t cmd_ack_code;
+               uint8_t extra_length;
+               uint8_t res_target_id;
+               aice_unpack_dthmb(&cmd_ack_code, &res_target_id, &extra_length);
+
+               LOG_DEBUG("WRITE_DIM response");
+
+               if (cmd_ack_code == AICE_CMD_T_WRITE_DIM) {
+                       break;
+               } else {
+                       LOG_ERROR("aice command timeout (command=0x%x, response=0x%x)",
+                                       AICE_CMD_T_WRITE_DIM, cmd_ack_code);
+
+                       if (retry_times > aice_max_retry_times)
+                               return ERROR_FAIL;
+
+                       /* clear timeout and retry */
+                       if (aice_write_ctrl(AICE_WRITE_CTRL_CLEAR_TIMEOUT_STATUS, 0x1) != ERROR_OK)
+                               return ERROR_FAIL;
+
+                       retry_times++;
+               }
+       } while (1);
+
+       return ERROR_OK;
+}
+
+static int aice_do_execute(uint8_t target_id)
+{
+       int result;
+       int retry_times = 0;
+
+       if (usb_pack_command)
+               aice_usb_packet_flush();
+
+       do {
+               aice_pack_htdmc(AICE_CMD_T_EXECUTE, target_id, 0, 0, 0, AICE_LITTLE_ENDIAN);
+
+               aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMC);
+
+               LOG_DEBUG("EXECUTE");
+
+               result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMB);
+               if (AICE_FORMAT_DTHMB != result) {
+                       LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)",
+                                       AICE_FORMAT_DTHMB, result);
+                       return ERROR_FAIL;
+               }
+
+               uint8_t cmd_ack_code;
+               uint8_t extra_length;
+               uint8_t res_target_id;
+               aice_unpack_dthmb(&cmd_ack_code, &res_target_id, &extra_length);
+
+               LOG_DEBUG("EXECUTE response");
+
+               if (cmd_ack_code == AICE_CMD_T_EXECUTE) {
+                       break;
+               } else {
+                       LOG_ERROR("aice command timeout (command=0x%x, response=0x%x)",
+                                       AICE_CMD_T_EXECUTE, cmd_ack_code);
+
+                       if (retry_times > aice_max_retry_times)
+                               return ERROR_FAIL;
+
+                       /* clear timeout and retry */
+                       if (aice_write_ctrl(AICE_WRITE_CTRL_CLEAR_TIMEOUT_STATUS, 0x1) != ERROR_OK)
+                               return ERROR_FAIL;
+
+                       retry_times++;
+               }
+       } while (1);
+
+       return ERROR_OK;
+}
+
+int aice_write_mem_b(uint8_t target_id, uint32_t address, uint32_t data)
+{
+       int result;
+       int retry_times = 0;
+
+       LOG_DEBUG("WRITE_MEM_B, ADDRESS %08" PRIx32 "  VALUE %08" PRIx32,
+                       address,
+                       data);
+
+       if (usb_pack_command) {
+               aice_pack_htdmd(AICE_CMD_T_WRITE_MEM_B, target_id, 0, address,
+                               data & 0x000000FF, data_endian);
+               aice_usb_packet_append(usb_out_buffer, AICE_FORMAT_HTDMD, AICE_FORMAT_DTHMB);
+       } else {
+               do {
+                       aice_pack_htdmd(AICE_CMD_T_WRITE_MEM_B, target_id, 0,
+                                       address, data & 0x000000FF, data_endian);
+                       aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMD);
+
+                       result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMB);
+                       if (AICE_FORMAT_DTHMB != result) {
+                               LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)",
+                                               AICE_FORMAT_DTHMB, result);
+                               return ERROR_FAIL;
+                       }
+
+                       uint8_t cmd_ack_code;
+                       uint8_t extra_length;
+                       uint8_t res_target_id;
+                       aice_unpack_dthmb(&cmd_ack_code, &res_target_id, &extra_length);
+
+                       if (cmd_ack_code == AICE_CMD_T_WRITE_MEM_B) {
+                               break;
+                       } else {
+                               LOG_ERROR("aice command timeout (command=0x%x, response=0x%x)",
+                                               AICE_CMD_T_WRITE_MEM_B, cmd_ack_code);
+
+                               if (retry_times > aice_max_retry_times)
+                                       return ERROR_FAIL;
+
+                               /* clear timeout and retry */
+                               if (aice_write_ctrl(AICE_WRITE_CTRL_CLEAR_TIMEOUT_STATUS, 0x1) != ERROR_OK)
+                                       return ERROR_FAIL;
+
+                               retry_times++;
+                       }
+               } while (1);
+       }
+
+       return ERROR_OK;
+}
+
+int aice_write_mem_h(uint8_t target_id, uint32_t address, uint32_t data)
+{
+       int result;
+       int retry_times = 0;
+
+       LOG_DEBUG("WRITE_MEM_H, ADDRESS %08" PRIx32 "  VALUE %08" PRIx32,
+                       address,
+                       data);
+
+       if (usb_pack_command) {
+               aice_pack_htdmd(AICE_CMD_T_WRITE_MEM_H, target_id, 0,
+                               (address >> 1) & 0x7FFFFFFF, data & 0x0000FFFF, data_endian);
+               aice_usb_packet_append(usb_out_buffer, AICE_FORMAT_HTDMD, AICE_FORMAT_DTHMB);
+       } else {
+               do {
+                       aice_pack_htdmd(AICE_CMD_T_WRITE_MEM_H, target_id, 0,
+                                       (address >> 1) & 0x7FFFFFFF, data & 0x0000FFFF, data_endian);
+                       aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMD);
+
+                       result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMB);
+                       if (AICE_FORMAT_DTHMB != result) {
+                               LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)",
+                                               AICE_FORMAT_DTHMB, result);
+                               return ERROR_FAIL;
+                       }
+
+                       uint8_t cmd_ack_code;
+                       uint8_t extra_length;
+                       uint8_t res_target_id;
+                       aice_unpack_dthmb(&cmd_ack_code, &res_target_id, &extra_length);
+
+                       if (cmd_ack_code == AICE_CMD_T_WRITE_MEM_H) {
+                               break;
+                       } else {
+                               LOG_ERROR("aice command timeout (command=0x%x, response=0x%x)",
+                                               AICE_CMD_T_WRITE_MEM_H, cmd_ack_code);
+
+                               if (retry_times > aice_max_retry_times)
+                                       return ERROR_FAIL;
+
+                               /* clear timeout and retry */
+                               if (aice_write_ctrl(AICE_WRITE_CTRL_CLEAR_TIMEOUT_STATUS, 0x1) != ERROR_OK)
+                                       return ERROR_FAIL;
+
+                               retry_times++;
+                       }
+               } while (1);
+       }
+
+       return ERROR_OK;
+}
+
+int aice_write_mem(uint8_t target_id, uint32_t address, uint32_t data)
+{
+       int result;
+       int retry_times = 0;
+
+       LOG_DEBUG("WRITE_MEM, ADDRESS %08" PRIx32 "  VALUE %08" PRIx32,
+                       address,
+                       data);
+
+       if (usb_pack_command) {
+               aice_pack_htdmd(AICE_CMD_T_WRITE_MEM, target_id, 0,
+                               (address >> 2) & 0x3FFFFFFF, data, data_endian);
+               aice_usb_packet_append(usb_out_buffer, AICE_FORMAT_HTDMD, AICE_FORMAT_DTHMB);
+       } else {
+               do {
+                       aice_pack_htdmd(AICE_CMD_T_WRITE_MEM, target_id, 0,
+                                       (address >> 2) & 0x3FFFFFFF, data, data_endian);
+                       aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMD);
+
+                       result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMB);
+                       if (AICE_FORMAT_DTHMB != result) {
+                               LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)",
+                                               AICE_FORMAT_DTHMB, result);
+                               return ERROR_FAIL;
+                       }
+
+                       uint8_t cmd_ack_code;
+                       uint8_t extra_length;
+                       uint8_t res_target_id;
+                       aice_unpack_dthmb(&cmd_ack_code, &res_target_id, &extra_length);
+
+                       if (cmd_ack_code == AICE_CMD_T_WRITE_MEM) {
+                               break;
+                       } else {
+                               LOG_ERROR("aice command timeout (command=0x%x, response=0x%x)",
+                                               AICE_CMD_T_WRITE_MEM, cmd_ack_code);
+
+                               if (retry_times > aice_max_retry_times)
+                                       return ERROR_FAIL;
+
+                               /* clear timeout and retry */
+                               if (aice_write_ctrl(AICE_WRITE_CTRL_CLEAR_TIMEOUT_STATUS, 0x1) != ERROR_OK)
+                                       return ERROR_FAIL;
+
+                               retry_times++;
+                       }
+               } while (1);
+       }
+
+       return ERROR_OK;
+}
+
+int aice_fastread_mem(uint8_t target_id, uint32_t *word, uint32_t num_of_words)
+{
+       int result;
+       int retry_times = 0;
+
+       if (usb_pack_command)
+               aice_usb_packet_flush();
+
+       do {
+               aice_pack_htdmb(AICE_CMD_T_FASTREAD_MEM, target_id, num_of_words - 1, 0);
+
+               aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMB);
+
+               LOG_DEBUG("FASTREAD_MEM, # of DATA %08" PRIx32, num_of_words);
+
+               result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMA + (num_of_words - 1) * 4);
+               if (result < 0) {
+                       LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)",
+                                       AICE_FORMAT_DTHMA + (num_of_words - 1) * 4, result);
+                       return ERROR_FAIL;
+               }
+
+               uint8_t cmd_ack_code;
+               uint8_t extra_length;
+               uint8_t res_target_id;
+               aice_unpack_dthma_multiple_data(&cmd_ack_code, &res_target_id,
+                               &extra_length, word, data_endian);
+
+               if (cmd_ack_code == AICE_CMD_T_FASTREAD_MEM) {
+                       break;
+               } else {
+                       LOG_ERROR("aice command timeout (command=0x%x, response=0x%x)",
+                                       AICE_CMD_T_FASTREAD_MEM, cmd_ack_code);
+
+                       if (retry_times > aice_max_retry_times)
+                               return ERROR_FAIL;
+
+                       /* clear timeout and retry */
+                       if (aice_write_ctrl(AICE_WRITE_CTRL_CLEAR_TIMEOUT_STATUS, 0x1) != ERROR_OK)
+                               return ERROR_FAIL;
+
+                       retry_times++;
+               }
+       } while (1);
+
+       return ERROR_OK;
+}
+
+int aice_fastwrite_mem(uint8_t target_id, const uint32_t *word, uint32_t num_of_words)
+{
+       int result;
+       int retry_times = 0;
+
+       if (usb_pack_command)
+               aice_usb_packet_flush();
+
+       do {
+               aice_pack_htdmd_multiple_data(AICE_CMD_T_FASTWRITE_MEM, target_id,
+                               num_of_words - 1, 0, word, data_endian);
+
+               aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMD + (num_of_words - 1) * 4);
+
+               LOG_DEBUG("FASTWRITE_MEM, # of DATA %08" PRIx32, num_of_words);
+
+               result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMB);
+               if (AICE_FORMAT_DTHMB != result) {
+                       LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)",
+                                       AICE_FORMAT_DTHMB, result);
+                       return ERROR_FAIL;
+               }
+
+               uint8_t cmd_ack_code;
+               uint8_t extra_length;
+               uint8_t res_target_id;
+               aice_unpack_dthmb(&cmd_ack_code, &res_target_id, &extra_length);
+
+               if (cmd_ack_code == AICE_CMD_T_FASTWRITE_MEM) {
+                       break;
+               } else {
+                       LOG_ERROR("aice command timeout (command=0x%x, response=0x%x)",
+                                       AICE_CMD_T_FASTWRITE_MEM, cmd_ack_code);
+
+                       if (retry_times > aice_max_retry_times)
+                               return ERROR_FAIL;
+
+                       /* clear timeout and retry */
+                       if (aice_write_ctrl(AICE_WRITE_CTRL_CLEAR_TIMEOUT_STATUS, 0x1) != ERROR_OK)
+                               return ERROR_FAIL;
+
+                       retry_times++;
+               }
+       } while (1);
+
+       return ERROR_OK;
+}
+
+int aice_read_mem_b(uint8_t target_id, uint32_t address, uint32_t *data)
+{
+       int result;
+       int retry_times = 0;
+
+       if (usb_pack_command)
+               aice_usb_packet_flush();
+
+       do {
+               aice_pack_htdmb(AICE_CMD_T_READ_MEM_B, target_id, 0, address);
+
+               aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMB);
+
+               LOG_DEBUG("READ_MEM_B");
+
+               result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMA);
+               if (AICE_FORMAT_DTHMA != result) {
+                       LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)",
+                                       AICE_FORMAT_DTHMA, result);
+                       return ERROR_FAIL;
+               }
+
+               uint8_t cmd_ack_code;
+               uint8_t extra_length;
+               uint8_t res_target_id;
+               aice_unpack_dthma(&cmd_ack_code, &res_target_id, &extra_length,
+                               data, data_endian);
+
+               LOG_DEBUG("READ_MEM_B response, data: 0x%x", *data);
+
+               if (cmd_ack_code == AICE_CMD_T_READ_MEM_B) {
+                       break;
+               } else {
+                       LOG_ERROR("aice command timeout (command=0x%x, response=0x%x)",
+                                       AICE_CMD_T_READ_MEM_B, cmd_ack_code);
+
+                       if (retry_times > aice_max_retry_times)
+                               return ERROR_FAIL;
+
+                       /* clear timeout and retry */
+                       if (aice_write_ctrl(AICE_WRITE_CTRL_CLEAR_TIMEOUT_STATUS, 0x1) != ERROR_OK)
+                               return ERROR_FAIL;
+
+                       retry_times++;
+               }
+       } while (1);
+
+       return ERROR_OK;
+}
+
+int aice_read_mem_h(uint8_t target_id, uint32_t address, uint32_t *data)
+{
+       int result;
+       int retry_times = 0;
+
+       if (usb_pack_command)
+               aice_usb_packet_flush();
+
+       do {
+               aice_pack_htdmb(AICE_CMD_T_READ_MEM_H, target_id, 0, (address >> 1) & 0x7FFFFFFF);
+
+               aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMB);
+
+               LOG_DEBUG("READ_MEM_H");
+
+               result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMA);
+               if (AICE_FORMAT_DTHMA != result) {
+                       LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)",
+                                       AICE_FORMAT_DTHMA, result);
+                       return ERROR_FAIL;
+               }
+
+               uint8_t cmd_ack_code;
+               uint8_t extra_length;
+               uint8_t res_target_id;
+               aice_unpack_dthma(&cmd_ack_code, &res_target_id, &extra_length,
+                               data, data_endian);
+
+               LOG_DEBUG("READ_MEM_H response, data: 0x%x", *data);
+
+               if (cmd_ack_code == AICE_CMD_T_READ_MEM_H) {
+                       break;
+               } else {
+                       LOG_ERROR("aice command timeout (command=0x%x, response=0x%x)",
+                                       AICE_CMD_T_READ_MEM_H, cmd_ack_code);
+
+                       if (retry_times > aice_max_retry_times)
+                               return ERROR_FAIL;
+
+                       /* clear timeout and retry */
+                       if (aice_write_ctrl(AICE_WRITE_CTRL_CLEAR_TIMEOUT_STATUS, 0x1) != ERROR_OK)
+                               return ERROR_FAIL;
+
+                       retry_times++;
+               }
+       } while (1);
+
+       return ERROR_OK;
+}
+
+int aice_read_mem(uint8_t target_id, uint32_t address, uint32_t *data)
+{
+       int result;
+       int retry_times = 0;
+
+       if (usb_pack_command)
+               aice_usb_packet_flush();
+
+       do {
+               aice_pack_htdmb(AICE_CMD_T_READ_MEM, target_id, 0,
+                               (address >> 2) & 0x3FFFFFFF);
+
+               aice_usb_write(usb_out_buffer, AICE_FORMAT_HTDMB);
+
+               LOG_DEBUG("READ_MEM");
+
+               result = aice_usb_read(usb_in_buffer, AICE_FORMAT_DTHMA);
+               if (AICE_FORMAT_DTHMA != result) {
+                       LOG_ERROR("aice_usb_read failed (requested=%d, result=%d)",
+                                       AICE_FORMAT_DTHMA, result);
+                       return ERROR_FAIL;
+               }
+
+               uint8_t cmd_ack_code;
+               uint8_t extra_length;
+               uint8_t res_target_id;
+               aice_unpack_dthma(&cmd_ack_code, &res_target_id, &extra_length,
+                               data, data_endian);
+
+               LOG_DEBUG("READ_MEM response, data: 0x%x", *data);
+
+               if (cmd_ack_code == AICE_CMD_T_READ_MEM) {
+                       break;
+               } else {
+                       LOG_ERROR("aice command timeout (command=0x%x, response=0x%x)",
+                                       AICE_CMD_T_READ_MEM, cmd_ack_code);
+
+                       if (retry_times > aice_max_retry_times)
+                               return ERROR_FAIL;
+
+                       /* clear timeout and retry */
+                       if (aice_write_ctrl(AICE_WRITE_CTRL_CLEAR_TIMEOUT_STATUS, 0x1) != ERROR_OK)
+                               return ERROR_FAIL;
+
+                       retry_times++;
+               }
+       } while (1);
+
+       return ERROR_OK;
+}
+
+/***************************************************************************/
+/* End of AICE commands */
+
+typedef int (*read_mem_func_t)(uint32_t address, uint32_t *data);
+typedef int (*write_mem_func_t)(uint32_t address, uint32_t data);
+struct cache_info {
+       uint32_t set;
+       uint32_t way;
+       uint32_t line_size;
+
+       uint32_t log2_set;
+       uint32_t log2_line_size;
+};
+
+static uint32_t r0_backup;
+static uint32_t r1_backup;
+static uint32_t host_dtr_backup;
+static uint32_t target_dtr_backup;
+static uint32_t edmsw_backup;
+static uint32_t edm_ctl_backup;
+static bool debug_under_dex_on;
+static bool dex_use_psw_on;
+static bool host_dtr_valid;
+static bool target_dtr_valid;
+static enum nds_memory_access access_channel = NDS_MEMORY_ACC_CPU;
+static enum nds_memory_select memory_select = NDS_MEMORY_SELECT_AUTO;
+static enum aice_target_state_s core_state = AICE_TARGET_UNKNOWN;
+static uint32_t edm_version;
+static struct cache_info icache = {0, 0, 0, 0, 0};
+static struct cache_info dcache = {0, 0, 0, 0, 0};
+static bool cache_init;
+static char *custom_srst_script;
+static char *custom_trst_script;
+static char *custom_restart_script;
+static uint32_t aice_count_to_check_dbger = 30;
+
+static int aice_read_reg(uint32_t num, uint32_t *val);
+static int aice_write_reg(uint32_t num, uint32_t val);
+
+static int check_suppressed_exception(uint32_t dbger_value)
+{
+       uint32_t ir4_value;
+       uint32_t ir6_value;
+       /* the default value of handling_suppressed_exception is false */
+       static bool handling_suppressed_exception;
+
+       if (handling_suppressed_exception)
+               return ERROR_OK;
+
+       if ((dbger_value & NDS_DBGER_ALL_SUPRS_EX) == NDS_DBGER_ALL_SUPRS_EX) {
+               LOG_ERROR("<-- TARGET WARNING! Exception is detected and suppressed. -->");
+               handling_suppressed_exception = true;
+
+               aice_read_reg(IR4, &ir4_value);
+               /* Clear IR6.SUPRS_EXC, IR6.IMP_EXC */
+               aice_read_reg(IR6, &ir6_value);
+               /*
+                * For MCU version(MSC_CFG.MCU == 1) like V3m
+                *  | SWID[30:16] | Reserved[15:10] | SUPRS_EXC[9]  | IMP_EXC[8]
+                *  |VECTOR[7:5] | INST[4] | Exc Type[3:0] |
+                *
+                * For non-MCU version(MSC_CFG.MCU == 0) like V3
+                *  | SWID[30:16] | Reserved[15:14] | SUPRS_EXC[13] | IMP_EXC[12]
+                *  | VECTOR[11:5] | INST[4] | Exc Type[3:0] |
+                */
+               LOG_INFO("EVA: 0x%08x", ir4_value);
+               LOG_INFO("ITYPE: 0x%08x", ir6_value);
+
+               ir6_value = ir6_value & (~0x300); /* for MCU */
+               ir6_value = ir6_value & (~0x3000); /* for non-MCU */
+               aice_write_reg(IR6, ir6_value);
+
+               handling_suppressed_exception = false;
+       }
+
+       return ERROR_OK;
+}
+
+static int check_privilege(uint32_t dbger_value)
+{
+       if ((dbger_value & NDS_DBGER_ILL_SEC_ACC) == NDS_DBGER_ILL_SEC_ACC) {
+               LOG_ERROR("<-- TARGET ERROR! Insufficient security privilege "
+                               "to execute the debug operations. -->");
+
+               /* Clear DBGER.ILL_SEC_ACC */
+               if (aice_write_misc(current_target_id, NDS_EDM_MISC_DBGER,
+                                       NDS_DBGER_ILL_SEC_ACC) != ERROR_OK)
+                       return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int aice_check_dbger(uint32_t expect_status)
+{
+       uint32_t i = 0;
+       uint32_t value_dbger;
+
+       while (1) {
+               aice_read_misc(current_target_id, NDS_EDM_MISC_DBGER, &value_dbger);
+
+               if ((value_dbger & expect_status) == expect_status) {
+                       if (ERROR_OK != check_suppressed_exception(value_dbger))
+                               return ERROR_FAIL;
+                       if (ERROR_OK != check_privilege(value_dbger))
+                               return ERROR_FAIL;
+                       return ERROR_OK;
+               }
+
+               long long then = 0;
+               if (i == aice_count_to_check_dbger)
+                       then = timeval_ms();
+               if (i >= aice_count_to_check_dbger) {
+                       if ((timeval_ms() - then) > 1000) {
+                               LOG_ERROR("Timeout (1000ms) waiting for $DBGER status "
+                                               "being 0x%08x", expect_status);
+                               return ERROR_FAIL;
+                       }
+               }
+               i++;
+       }
+
+       return ERROR_FAIL;
+}
+
+static int aice_execute_dim(uint32_t *insts, uint8_t n_inst)
+{
+       /** fill DIM */
+       if (aice_write_dim(current_target_id, insts, n_inst) != ERROR_OK)
+               return ERROR_FAIL;
+
+       /** clear DBGER.DPED */
+       if (aice_write_misc(current_target_id, NDS_EDM_MISC_DBGER, NDS_DBGER_DPED) != ERROR_OK)
+               return ERROR_FAIL;
+
+       /** execute DIM */
+       if (aice_do_execute(current_target_id) != ERROR_OK)
+               return ERROR_FAIL;
+
+       /** read DBGER.DPED */
+       if (aice_check_dbger(NDS_DBGER_DPED) != ERROR_OK) {
+               LOG_ERROR("<-- TARGET ERROR! Debug operations do not finish properly: "
+                               "0x%08x 0x%08x 0x%08x 0x%08x. -->",
+                               insts[0],
+                               insts[1],
+                               insts[2],
+                               insts[3]);
+               return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int aice_read_reg(uint32_t num, uint32_t *val)
+{
+       LOG_DEBUG("aice_read_reg, reg_no: 0x%08x", num);
+
+       uint32_t instructions[4]; /** execute instructions in DIM */
+
+       if (NDS32_REG_TYPE_GPR == nds32_reg_type(num)) { /* general registers */
+               instructions[0] = MTSR_DTR(num);
+               instructions[1] = DSB;
+               instructions[2] = NOP;
+               instructions[3] = BEQ_MINUS_12;
+       } else if (NDS32_REG_TYPE_SPR == nds32_reg_type(num)) { /* user special registers */
+               instructions[0] = MFUSR_G0(0, nds32_reg_sr_index(num));
+               instructions[1] = MTSR_DTR(0);
+               instructions[2] = DSB;
+               instructions[3] = BEQ_MINUS_12;
+       } else if (NDS32_REG_TYPE_AUMR == nds32_reg_type(num)) { /* audio registers */
+               if ((CB_CTL <= num) && (num <= CBE3)) {
+                       instructions[0] = AMFAR2(0, nds32_reg_sr_index(num));
+                       instructions[1] = MTSR_DTR(0);
+                       instructions[2] = DSB;
+                       instructions[3] = BEQ_MINUS_12;
+               } else {
+                       instructions[0] = AMFAR(0, nds32_reg_sr_index(num));
+                       instructions[1] = MTSR_DTR(0);
+                       instructions[2] = DSB;
+                       instructions[3] = BEQ_MINUS_12;
+               }
+       } else if (NDS32_REG_TYPE_FPU == nds32_reg_type(num)) { /* fpu registers */
+               if (FPCSR == num) {
+                       instructions[0] = FMFCSR;
+                       instructions[1] = MTSR_DTR(0);
+                       instructions[2] = DSB;
+                       instructions[3] = BEQ_MINUS_12;
+               } else if (FPCFG == num) {
+                       instructions[0] = FMFCFG;
+                       instructions[1] = MTSR_DTR(0);
+                       instructions[2] = DSB;
+                       instructions[3] = BEQ_MINUS_12;
+               } else {
+                       if (FS0 <= num && num <= FS31) { /* single precision */
+                               instructions[0] = FMFSR(0, nds32_reg_sr_index(num));
+                               instructions[1] = MTSR_DTR(0);
+                               instructions[2] = DSB;
+                               instructions[3] = BEQ_MINUS_12;
+                       } else if (FD0 <= num && num <= FD31) { /* double precision */
+                               instructions[0] = FMFDR(0, nds32_reg_sr_index(num));
+                               instructions[1] = MTSR_DTR(0);
+                               instructions[2] = DSB;
+                               instructions[3] = BEQ_MINUS_12;
+                       }
+               }
+       } else { /* system registers */
+               instructions[0] = MFSR(0, nds32_reg_sr_index(num));
+               instructions[1] = MTSR_DTR(0);
+               instructions[2] = DSB;
+               instructions[3] = BEQ_MINUS_12;
+       }
+
+       aice_execute_dim(instructions, 4);
+
+       uint32_t value_edmsw;
+       aice_read_edmsr(current_target_id, NDS_EDM_SR_EDMSW, &value_edmsw);
+       if (value_edmsw & NDS_EDMSW_WDV)
+               aice_read_dtr(current_target_id, val);
+       else {
+               LOG_ERROR("<-- TARGET ERROR! The debug target failed to update "
+                               "the DTR register. -->");
+               return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int aice_usb_read_reg(uint32_t num, uint32_t *val)
+{
+       LOG_DEBUG("aice_usb_read_reg");
+
+       if (num == R0) {
+               *val = r0_backup;
+       } else if (num == R1) {
+               *val = r1_backup;
+       } else if (num == DR41) {
+               /* As target is halted, OpenOCD will backup DR41/DR42/DR43.
+                * As user wants to read these registers, OpenOCD should return
+                * the backup values, instead of reading the real values.
+                * As user wants to write these registers, OpenOCD should write
+                * to the backup values, instead of writing to real registers. */
+               *val = edmsw_backup;
+       } else if (num == DR42) {
+               *val = edm_ctl_backup;
+       } else if ((target_dtr_valid == true) && (num == DR43)) {
+               *val = target_dtr_backup;
+       } else {
+               if (ERROR_OK != aice_read_reg(num, val))
+                       *val = 0xBBADBEEF;
+       }
+
+       return ERROR_OK;
+}
+
+static int aice_write_reg(uint32_t num, uint32_t val)
+{
+       LOG_DEBUG("aice_write_reg, reg_no: 0x%08x, value: 0x%08x", num, val);
+
+       uint32_t instructions[4]; /** execute instructions in DIM */
+       uint32_t value_edmsw;
+
+       aice_write_dtr(current_target_id, val);
+       aice_read_edmsr(current_target_id, NDS_EDM_SR_EDMSW, &value_edmsw);
+       if (0 == (value_edmsw & NDS_EDMSW_RDV)) {
+               LOG_ERROR("<-- TARGET ERROR! AICE failed to write to the DTR register. -->");
+               return ERROR_FAIL;
+       }
+
+       if (NDS32_REG_TYPE_GPR == nds32_reg_type(num)) { /* general registers */
+               instructions[0] = MFSR_DTR(num);
+               instructions[1] = DSB;
+               instructions[2] = NOP;
+               instructions[3] = BEQ_MINUS_12;
+       } else if (NDS32_REG_TYPE_SPR == nds32_reg_type(num)) { /* user special registers */
+               instructions[0] = MFSR_DTR(0);
+               instructions[1] = MTUSR_G0(0, nds32_reg_sr_index(num));
+               instructions[2] = DSB;
+               instructions[3] = BEQ_MINUS_12;
+       } else if (NDS32_REG_TYPE_AUMR == nds32_reg_type(num)) { /* audio registers */
+               if ((CB_CTL <= num) && (num <= CBE3)) {
+                       instructions[0] = MFSR_DTR(0);
+                       instructions[1] = AMTAR2(0, nds32_reg_sr_index(num));
+                       instructions[2] = DSB;
+                       instructions[3] = BEQ_MINUS_12;
+               } else {
+                       instructions[0] = MFSR_DTR(0);
+                       instructions[1] = AMTAR(0, nds32_reg_sr_index(num));
+                       instructions[2] = DSB;
+                       instructions[3] = BEQ_MINUS_12;
+               }
+       } else if (NDS32_REG_TYPE_FPU == nds32_reg_type(num)) { /* fpu registers */
+               if (FPCSR == num) {
+                       instructions[0] = MFSR_DTR(0);
+                       instructions[1] = FMTCSR;
+                       instructions[2] = DSB;
+                       instructions[3] = BEQ_MINUS_12;
+               } else if (FPCFG == num) {
+                       /* FPCFG is readonly */
+               } else {
+                       if (FS0 <= num && num <= FS31) { /* single precision */
+                               instructions[0] = MFSR_DTR(0);
+                               instructions[1] = FMTSR(0, nds32_reg_sr_index(num));
+                               instructions[2] = DSB;
+                               instructions[3] = BEQ_MINUS_12;
+                       } else if (FD0 <= num && num <= FD31) { /* double precision */
+                               instructions[0] = MFSR_DTR(0);
+                               instructions[1] = FMTDR(0, nds32_reg_sr_index(num));
+                               instructions[2] = DSB;
+                               instructions[3] = BEQ_MINUS_12;
+                       }
+               }
+       } else {
+               instructions[0] = MFSR_DTR(0);
+               instructions[1] = MTSR(0, nds32_reg_sr_index(num));
+               instructions[2] = DSB;
+               instructions[3] = BEQ_MINUS_12;
+       }
+
+       return aice_execute_dim(instructions, 4);
+}
+
+static int aice_usb_write_reg(uint32_t num, uint32_t val)
+{
+       LOG_DEBUG("aice_usb_write_reg");
+
+       if (num == R0)
+               r0_backup = val;
+       else if (num == R1)
+               r1_backup = val;
+       else if (num == DR42)
+               /* As target is halted, OpenOCD will backup DR41/DR42/DR43.
+                * As user wants to read these registers, OpenOCD should return
+                * the backup values, instead of reading the real values.
+                * As user wants to write these registers, OpenOCD should write
+                * to the backup values, instead of writing to real registers. */
+               edm_ctl_backup = val;
+       else if ((target_dtr_valid == true) && (num == DR43))
+               target_dtr_backup = val;
+       else
+               return aice_write_reg(num, val);
+
+       return ERROR_OK;
+}
+
+static int aice_usb_open(struct aice_port_param_s *param)
+{
+       const uint16_t vids[] = { param->vid, 0 };
+       const uint16_t pids[] = { param->pid, 0 };
+       struct jtag_libusb_device_handle *devh;
+
+       if (jtag_libusb_open(vids, pids, &devh) != ERROR_OK)
+               return ERROR_FAIL;
+
+       /* BE ***VERY CAREFUL*** ABOUT MAKING CHANGES IN THIS
+        * AREA!!!!!!!!!!!  The behavior of libusb is not completely
+        * consistent across Windows, Linux, and Mac OS X platforms.
+        * The actions taken in the following compiler conditionals may
+        * not agree with published documentation for libusb, but were
+        * found to be necessary through trials and tribulations.  Even
+        * little tweaks can break one or more platforms, so if you do
+        * make changes test them carefully on all platforms before
+        * committing them!
+        */
+
+#if IS_WIN32 == 0
+
+       jtag_libusb_reset_device(devh);
+
+#if IS_DARWIN == 0
+
+       int timeout = 5;
+       /* reopen jlink after usb_reset
+        * on win32 this may take a second or two to re-enumerate */
+       int retval;
+       while ((retval = jtag_libusb_open(vids, pids, &devh)) != ERROR_OK) {
+               usleep(1000);
+               timeout--;
+               if (!timeout)
+                       break;
+       }
+       if (ERROR_OK != retval)
+               return ERROR_FAIL;
+#endif
+
+#endif
+
+       /* usb_set_configuration required under win32 */
+       struct jtag_libusb_device *udev = jtag_libusb_get_device(devh);
+       jtag_libusb_set_configuration(devh, 0);
+       jtag_libusb_claim_interface(devh, 0);
+
+       unsigned int aice_read_ep;
+       unsigned int aice_write_ep;
+       jtag_libusb_get_endpoints(udev, &aice_read_ep, &aice_write_ep);
+
+       aice_handler.usb_read_ep = aice_read_ep;
+       aice_handler.usb_write_ep = aice_write_ep;
+       aice_handler.usb_handle = devh;
+
+       return ERROR_OK;
+}
+
+static int aice_usb_read_reg_64(uint32_t num, uint64_t *val)
+{
+       LOG_DEBUG("aice_usb_read_reg_64, %s", nds32_reg_simple_name(num));
+
+       uint32_t value;
+       uint32_t high_value;
+
+       if (ERROR_OK != aice_read_reg(num, &value))
+               value = 0xBBADBEEF;
+
+       aice_read_reg(R1, &high_value);
+
+       LOG_DEBUG("low: 0x%08x, high: 0x%08x\n", value, high_value);
+
+       if (data_endian == AICE_BIG_ENDIAN)
+               *val = (((uint64_t)high_value) << 32) | value;
+       else
+               *val = (((uint64_t)value) << 32) | high_value;
+
+       return ERROR_OK;
+}
+
+static int aice_usb_write_reg_64(uint32_t num, uint64_t val)
+{
+       uint32_t value;
+       uint32_t high_value;
+
+       if (data_endian == AICE_BIG_ENDIAN) {
+               value = val & 0xFFFFFFFF;
+               high_value = (val >> 32) & 0xFFFFFFFF;
+       } else {
+               high_value = val & 0xFFFFFFFF;
+               value = (val >> 32) & 0xFFFFFFFF;
+       }
+
+       LOG_DEBUG("aice_usb_write_reg_64, %s, low: 0x%08x, high: 0x%08x\n",
+                       nds32_reg_simple_name(num), value, high_value);
+
+       aice_write_reg(R1, high_value);
+       return aice_write_reg(num, value);
+}
+
+static int aice_get_version_info(void)
+{
+       uint32_t hardware_version;
+       uint32_t firmware_version;
+       uint32_t fpga_version;
+
+       if (aice_read_ctrl(AICE_READ_CTRL_GET_HARDWARE_VERSION, &hardware_version) != ERROR_OK)
+               return ERROR_FAIL;
+
+       if (aice_read_ctrl(AICE_READ_CTRL_GET_FIRMWARE_VERSION, &firmware_version) != ERROR_OK)
+               return ERROR_FAIL;
+
+       if (aice_read_ctrl(AICE_READ_CTRL_GET_FPGA_VERSION, &fpga_version) != ERROR_OK)
+               return ERROR_FAIL;
+
+       LOG_INFO("AICE version: hw_ver = 0x%x, fw_ver = 0x%x, fpga_ver = 0x%x",
+                       hardware_version, firmware_version, fpga_version);
+
+       return ERROR_OK;
+}
+
+#define LINE_BUFFER_SIZE 1024
+
+static int aice_execute_custom_script(const char *script)
+{
+       FILE *script_fd;
+       char line_buffer[LINE_BUFFER_SIZE];
+       char *op_str;
+       char *reset_str;
+       uint32_t delay;
+       uint32_t write_ctrl_value;
+       bool set_op;
+
+       script_fd = fopen(script, "r");
+       if (script_fd == NULL) {
+               return ERROR_FAIL;
+       } else {
+               while (fgets(line_buffer, LINE_BUFFER_SIZE, script_fd) != NULL) {
+                       /* execute operations */
+                       set_op = false;
+                       op_str = strstr(line_buffer, "set");
+                       if (op_str != NULL) {
+                               set_op = true;
+                               goto get_reset_type;
+                       }
+
+                       op_str = strstr(line_buffer, "clear");
+                       if (op_str == NULL)
+                               continue;
+get_reset_type:
+                       reset_str = strstr(op_str, "srst");
+                       if (reset_str != NULL) {
+                               if (set_op)
+                                       write_ctrl_value = AICE_CUSTOM_DELAY_SET_SRST;
+                               else
+                                       write_ctrl_value = AICE_CUSTOM_DELAY_CLEAN_SRST;
+                               goto get_delay;
+                       }
+                       reset_str = strstr(op_str, "dbgi");
+                       if (reset_str != NULL) {
+                               if (set_op)
+                                       write_ctrl_value = AICE_CUSTOM_DELAY_SET_DBGI;
+                               else
+                                       write_ctrl_value = AICE_CUSTOM_DELAY_CLEAN_DBGI;
+                               goto get_delay;
+                       }
+                       reset_str = strstr(op_str, "trst");
+                       if (reset_str != NULL) {
+                               if (set_op)
+                                       write_ctrl_value = AICE_CUSTOM_DELAY_SET_TRST;
+                               else
+                                       write_ctrl_value = AICE_CUSTOM_DELAY_CLEAN_TRST;
+                               goto get_delay;
+                       }
+                       continue;
+get_delay:
+                       /* get delay */
+                       delay = strtoul(reset_str + 4, NULL, 0);
+                       write_ctrl_value |= (delay << 16);
+
+                       if (aice_write_ctrl(AICE_WRITE_CTRL_CUSTOM_DELAY,
+                                               write_ctrl_value) != ERROR_OK) {
+                               fclose(script_fd);
+                               return ERROR_FAIL;
+                       }
+               }
+               fclose(script_fd);
+       }
+
+       return ERROR_OK;
+}
+
+static int aice_edm_reset(void)
+{
+       if (aice_write_ctrl(AICE_WRITE_CTRL_CLEAR_TIMEOUT_STATUS, 0x1) != ERROR_OK)
+               return ERROR_FAIL;
+
+       return ERROR_OK;
+}
+
+static int aice_usb_set_clock(int set_clock)
+{
+       if (aice_write_ctrl(AICE_WRITE_CTRL_TCK_CONTROL,
+                               AICE_TCK_CONTROL_TCK_SCAN) != ERROR_OK)
+               return ERROR_FAIL;
+
+       /* Read out TCK_SCAN clock value */
+       uint32_t scan_clock;
+       if (aice_read_ctrl(AICE_READ_CTRL_GET_ICE_STATE, &scan_clock) != ERROR_OK)
+               return ERROR_FAIL;
+
+       scan_clock &= 0x0F;
+
+       uint32_t scan_base_freq;
+       if (scan_clock & 0x8)
+               scan_base_freq = 48000; /* 48 MHz */
+       else
+               scan_base_freq = 30000; /* 30 MHz */
+
+       uint32_t set_base_freq;
+       if (set_clock & 0x8)
+               set_base_freq = 48000;
+       else
+               set_base_freq = 30000;
+
+       uint32_t set_freq;
+       uint32_t scan_freq;
+       set_freq = set_base_freq >> (set_clock & 0x7);
+       scan_freq = scan_base_freq >> (scan_clock & 0x7);
+
+       if (scan_freq < set_freq) {
+               LOG_ERROR("User specifies higher jtag clock than TCK_SCAN clock");
+               return ERROR_FAIL;
+       }
+
+       if (aice_write_ctrl(AICE_WRITE_CTRL_TCK_CONTROL, set_clock) != ERROR_OK)
+               return ERROR_FAIL;
+
+       uint32_t check_speed;
+       if (aice_read_ctrl(AICE_READ_CTRL_GET_ICE_STATE, &check_speed) != ERROR_OK)
+               return ERROR_FAIL;
+
+       if (((int)check_speed & 0x0F) != set_clock) {
+               LOG_ERROR("Set jtag clock failed");
+               return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int aice_edm_init(void)
+{
+       aice_write_edmsr(current_target_id, NDS_EDM_SR_DIMBR, 0xFFFF0000);
+
+       /* unconditionally try to turn on V3_EDM_MODE */
+       uint32_t edm_ctl_value;
+       aice_read_edmsr(current_target_id, NDS_EDM_SR_EDM_CTL, &edm_ctl_value);
+       aice_write_edmsr(current_target_id, NDS_EDM_SR_EDM_CTL, edm_ctl_value | 0x00000040);
+
+       aice_write_misc(current_target_id, NDS_EDM_MISC_DBGER,
+                       NDS_DBGER_DPED | NDS_DBGER_CRST | NDS_DBGER_AT_MAX);
+       aice_write_misc(current_target_id, NDS_EDM_MISC_DIMIR, 0);
+
+       /* get EDM version */
+       uint32_t value_edmcfg;
+       aice_read_edmsr(current_target_id, NDS_EDM_SR_EDM_CFG, &value_edmcfg);
+       edm_version = (value_edmcfg >> 16) & 0xFFFF;
+
+       return ERROR_OK;
+}
+
+static bool is_v2_edm(void)
+{
+       if ((edm_version & 0x1000) == 0)
+               return true;
+       else
+               return false;
+}
+
+static int aice_init_edm_registers(bool clear_dex_use_psw)
+{
+       /* enable DEH_SEL & MAX_STOP & V3_EDM_MODE & DBGI_MASK */
+       uint32_t host_edm_ctl = edm_ctl_backup | 0xA000004F;
+       if (clear_dex_use_psw)
+               /* After entering debug mode, OpenOCD may set
+                * DEX_USE_PSW accidentally through backup value
+                * of target EDM_CTL.
+                * So, clear DEX_USE_PSW by force. */
+               host_edm_ctl &= ~(0x40000000);
+
+       LOG_DEBUG("aice_init_edm_registers - EDM_CTL: 0x%08x", host_edm_ctl);
+
+       int result = aice_write_edmsr(current_target_id, NDS_EDM_SR_EDM_CTL, host_edm_ctl);
+
+       return result;
+}
+
+/**
+ * EDM_CTL will be modified by OpenOCD as debugging. OpenOCD has the
+ * responsibility to keep EDM_CTL untouched after debugging.
+ *
+ * There are two scenarios to consider:
+ * 1. single step/running as debugging (running under debug session)
+ * 2. detached from gdb (exit debug session)
+ *
+ * So, we need to bakcup EDM_CTL before halted and restore it after
+ * running. The difference of these two scenarios is EDM_CTL.DEH_SEL
+ * is on for scenario 1, and off for scenario 2.
+ */
+static int aice_backup_edm_registers(void)
+{
+       int result = aice_read_edmsr(current_target_id, NDS_EDM_SR_EDM_CTL, &edm_ctl_backup);
+
+       /* To call aice_backup_edm_registers() after DEX on, DEX_USE_PSW
+        * may be not correct.  (For example, hit breakpoint, then backup
+        * EDM_CTL. EDM_CTL.DEX_USE_PSW will be cleared.)  Because debug
+        * interrupt will clear DEX_USE_PSW, DEX_USE_PSW is always off after
+        * DEX is on.  It only backups correct value before OpenOCD issues DBGI.
+        * (Backup EDM_CTL, then issue DBGI actively (refer aice_usb_halt())) */
+       if (edm_ctl_backup & 0x40000000)
+               dex_use_psw_on = true;
+       else
+               dex_use_psw_on = false;
+
+       LOG_DEBUG("aice_backup_edm_registers - EDM_CTL: 0x%08x, DEX_USE_PSW: %s",
+                       edm_ctl_backup, dex_use_psw_on ? "on" : "off");
+
+       return result;
+}
+
+static int aice_restore_edm_registers(void)
+{
+       LOG_DEBUG("aice_restore_edm_registers -");
+
+       /* set DEH_SEL, because target still under EDM control */
+       int result = aice_write_edmsr(current_target_id, NDS_EDM_SR_EDM_CTL,
+                       edm_ctl_backup | 0x80000000);
+
+       return result;
+}
+
+static int aice_backup_tmp_registers(void)
+{
+       LOG_DEBUG("backup_tmp_registers -");
+
+       /* backup target DTR first(if the target DTR is valid) */
+       uint32_t value_edmsw;
+       aice_read_edmsr(current_target_id, NDS_EDM_SR_EDMSW, &value_edmsw);
+       edmsw_backup = value_edmsw;
+       if (value_edmsw & 0x1) { /* EDMSW.WDV == 1 */
+               aice_read_dtr(current_target_id, &target_dtr_backup);
+               target_dtr_valid = true;
+
+               LOG_DEBUG("Backup target DTR: 0x%08x", target_dtr_backup);
+       } else {
+               target_dtr_valid = false;
+       }
+
+       /* Target DTR has been backup, then backup $R0 and $R1 */
+       aice_read_reg(R0, &r0_backup);
+       aice_read_reg(R1, &r1_backup);
+
+       /* backup host DTR(if the host DTR is valid) */
+       if (value_edmsw & 0x2) { /* EDMSW.RDV == 1*/
+               /* read out host DTR and write into target DTR, then use aice_read_edmsr to
+                * read out */
+               uint32_t instructions[4] = {
+                       MFSR_DTR(R0), /* R0 has already been backup */
+                       DSB,
+                       MTSR_DTR(R0),
+                       BEQ_MINUS_12
+               };
+               aice_execute_dim(instructions, 4);
+
+               aice_read_dtr(current_target_id, &host_dtr_backup);
+               host_dtr_valid = true;
+
+               LOG_DEBUG("Backup host DTR: 0x%08x", host_dtr_backup);
+       } else {
+               host_dtr_valid = false;
+       }
+
+       LOG_DEBUG("r0: 0x%08x, r1: 0x%08x", r0_backup, r1_backup);
+
+       return ERROR_OK;
+}
+
+static int aice_restore_tmp_registers(void)
+{
+       LOG_DEBUG("restore_tmp_registers - r0: 0x%08x, r1: 0x%08x", r0_backup, r1_backup);
+
+       if (target_dtr_valid) {
+               uint32_t instructions[4] = {
+                       SETHI(R0, target_dtr_backup >> 12),
+                       ORI(R0, R0, target_dtr_backup & 0x00000FFF),
+                       NOP,
+                       BEQ_MINUS_12
+               };
+               aice_execute_dim(instructions, 4);
+
+               instructions[0] = MTSR_DTR(R0);
+               instructions[1] = DSB;
+               instructions[2] = NOP;
+               instructions[3] = BEQ_MINUS_12;
+               aice_execute_dim(instructions, 4);
+
+               LOG_DEBUG("Restore target DTR: 0x%08x", target_dtr_backup);
+       }
+
+       aice_write_reg(R0, r0_backup);
+       aice_write_reg(R1, r1_backup);
+
+       if (host_dtr_valid) {
+               aice_write_dtr(current_target_id, host_dtr_backup);
+
+               LOG_DEBUG("Restore host DTR: 0x%08x", host_dtr_backup);
+       }
+
+       return ERROR_OK;
+}
+
+static int aice_open_device(struct aice_port_param_s *param)
+{
+       if (ERROR_OK != aice_usb_open(param))
+               return ERROR_FAIL;
+
+       if (ERROR_FAIL == aice_get_version_info()) {
+               LOG_ERROR("Cannot get AICE version!");
+               return ERROR_FAIL;
+       }
+
+       LOG_INFO("AICE initialization started");
+
+       /* attempt to reset Andes EDM */
+       if (ERROR_FAIL == aice_edm_reset()) {
+               LOG_ERROR("Cannot initial AICE Interface!");
+               return ERROR_FAIL;
+       }
+
+       if (ERROR_OK != aice_edm_init()) {
+               LOG_ERROR("Cannot initial EDM!");
+               return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int aice_usb_set_jtag_clock(uint32_t a_clock)
+{
+       jtag_clock = a_clock;
+
+       if (ERROR_OK != aice_usb_set_clock(a_clock)) {
+               LOG_ERROR("Cannot set AICE JTAG clock!");
+               return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static int aice_usb_close(void)
+{
+       jtag_libusb_close(aice_handler.usb_handle);
+
+       if (custom_srst_script)
+               free(custom_srst_script);
+
+       if (custom_trst_script)
+               free(custom_trst_script);
+
+       if (custom_restart_script)
+               free(custom_restart_script);
+
+       return ERROR_OK;
+}
+
+static int aice_usb_idcode(uint32_t *idcode, uint8_t *num_of_idcode)
+{
+       return aice_scan_chain(idcode, num_of_idcode);
+}
+
+static int aice_usb_halt(void)
+{
+       if (core_state == AICE_TARGET_HALTED) {
+               LOG_DEBUG("aice_usb_halt check halted");
+               return ERROR_OK;
+       }
+
+       LOG_DEBUG("aice_usb_halt");
+
+       /** backup EDM registers */
+       aice_backup_edm_registers();
+       /** init EDM for host debugging */
+       /** no need to clear dex_use_psw, because dbgi will clear it */
+       aice_init_edm_registers(false);
+
+       /** Clear EDM_CTL.DBGIM & EDM_CTL.DBGACKM */
+       uint32_t edm_ctl_value;
+       aice_read_edmsr(current_target_id, NDS_EDM_SR_EDM_CTL, &edm_ctl_value);
+       if (edm_ctl_value & 0x3)
+               aice_write_edmsr(current_target_id, NDS_EDM_SR_EDM_CTL, edm_ctl_value & ~(0x3));
+
+       uint32_t dbger;
+       uint32_t acc_ctl_value;
+
+       debug_under_dex_on = false;
+       aice_read_misc(current_target_id, NDS_EDM_MISC_DBGER, &dbger);
+
+       if (dbger & NDS_DBGER_AT_MAX)
+               LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level. -->");
+
+       if (dbger & NDS_DBGER_DEX) {
+               if (is_v2_edm() == false) {
+                       /** debug 'debug mode'. use force_debug to issue dbgi */
+                       aice_read_misc(current_target_id, NDS_EDM_MISC_ACC_CTL, &acc_ctl_value);
+                       acc_ctl_value |= 0x8;
+                       aice_write_misc(current_target_id, NDS_EDM_MISC_ACC_CTL, acc_ctl_value);
+                       debug_under_dex_on = true;
+
+                       aice_write_misc(current_target_id, NDS_EDM_MISC_EDM_CMDR, 0);
+                       /* If CPU stalled due to AT_MAX, clear AT_MAX status. */
+                       if (dbger & NDS_DBGER_AT_MAX)
+                               aice_write_misc(current_target_id, NDS_EDM_MISC_DBGER, NDS_DBGER_AT_MAX);
+               }
+       } else {
+               /** Issue DBGI normally */
+               aice_write_misc(current_target_id, NDS_EDM_MISC_EDM_CMDR, 0);
+               /* If CPU stalled due to AT_MAX, clear AT_MAX status. */
+               if (dbger & NDS_DBGER_AT_MAX)
+                       aice_write_misc(current_target_id, NDS_EDM_MISC_DBGER, NDS_DBGER_AT_MAX);
+       }
+
+       if (aice_check_dbger(NDS_DBGER_DEX) != ERROR_OK) {
+               LOG_ERROR("<-- TARGET ERROR! Unable to stop the debug target through DBGI. -->");
+               return ERROR_FAIL;
+       }
+
+       if (debug_under_dex_on) {
+               if (dex_use_psw_on == false) {
+                       /* under debug 'debug mode', force $psw to 'debug mode' bahavior */
+                       /* !!!NOTICE!!! this is workaround for debug 'debug mode'.
+                        * it is only for debugging 'debug exception handler' purpose.
+                        * after openocd detaches from target, target behavior is
+                        * undefined. */
+                       uint32_t ir0_value;
+                       uint32_t debug_mode_ir0_value;
+                       aice_read_reg(IR0, &ir0_value);
+                       debug_mode_ir0_value = ir0_value | 0x408; /* turn on DEX, set POM = 1 */
+                       debug_mode_ir0_value &= ~(0x000000C1); /* turn off DT/IT/GIE */
+                       aice_write_reg(IR0, debug_mode_ir0_value);
+               }
+       }
+
+       /** set EDM_CTL.DBGIM & EDM_CTL.DBGACKM after halt */
+       if (edm_ctl_value & 0x3)
+               aice_write_edmsr(current_target_id, NDS_EDM_SR_EDM_CTL, edm_ctl_value);
+
+       /* backup r0 & r1 */
+       aice_backup_tmp_registers();
+       core_state = AICE_TARGET_HALTED;
+
+       return ERROR_OK;
+}
+
+static int aice_usb_state(enum aice_target_state_s *state)
+{
+       uint32_t dbger_value;
+       uint32_t ice_state;
+
+       int result = aice_read_misc(current_target_id, NDS_EDM_MISC_DBGER, &dbger_value);
+
+       if (ERROR_AICE_TIMEOUT == result) {
+               if (aice_read_ctrl(AICE_READ_CTRL_GET_ICE_STATE, &ice_state) != ERROR_OK) {
+                       LOG_ERROR("<-- AICE ERROR! AICE is unplugged. -->");
+                       return ERROR_FAIL;
+               }
+
+               if ((ice_state & 0x20) == 0) {
+                       LOG_ERROR("<-- TARGET ERROR! Target is disconnected with AICE. -->");
+                       return ERROR_FAIL;
+               } else {
+                       return ERROR_FAIL;
+               }
+       } else if (ERROR_AICE_DISCONNECT == result) {
+               LOG_ERROR("<-- AICE ERROR! AICE is unplugged. -->");
+               return ERROR_FAIL;
+       }
+
+       if ((dbger_value & NDS_DBGER_ILL_SEC_ACC) == NDS_DBGER_ILL_SEC_ACC) {
+               LOG_ERROR("<-- TARGET ERROR! Insufficient security privilege. -->");
+
+               /* Clear ILL_SEC_ACC */
+               aice_write_misc(current_target_id, NDS_EDM_MISC_DBGER, NDS_DBGER_ILL_SEC_ACC);
+
+               *state = AICE_TARGET_RUNNING;
+               core_state = AICE_TARGET_RUNNING;
+       } else if ((dbger_value & NDS_DBGER_AT_MAX) == NDS_DBGER_AT_MAX) {
+               /* Issue DBGI to exit cpu stall */
+               aice_usb_halt();
+
+               /* Read OIPC to find out the trigger point */
+               uint32_t ir11_value;
+               aice_read_reg(IR11, &ir11_value);
+
+               LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level; "
+                               "CPU is stalled at 0x%08x for debugging. -->", ir11_value);
+
+               *state = AICE_TARGET_HALTED;
+       } else if ((dbger_value & NDS_DBGER_CRST) == NDS_DBGER_CRST) {
+               LOG_DEBUG("DBGER.CRST is on.");
+
+               *state = AICE_TARGET_RESET;
+               core_state = AICE_TARGET_RUNNING;
+
+               /* Clear CRST */
+               aice_write_misc(current_target_id, NDS_EDM_MISC_DBGER, NDS_DBGER_CRST);
+       } else if ((dbger_value & NDS_DBGER_DEX) == NDS_DBGER_DEX) {
+               if (AICE_TARGET_RUNNING == core_state) {
+                       /* enter debug mode, init EDM registers */
+                       /* backup EDM registers */
+                       aice_backup_edm_registers();
+                       /* init EDM for host debugging */
+                       aice_init_edm_registers(true);
+                       aice_backup_tmp_registers();
+                       core_state = AICE_TARGET_HALTED;
+               } else if (AICE_TARGET_UNKNOWN == core_state) {
+                       /* debug 'debug mode', use force debug to halt core */
+                       aice_usb_halt();
+               }
+               *state = AICE_TARGET_HALTED;
+       } else {
+               *state = AICE_TARGET_RUNNING;
+               core_state = AICE_TARGET_RUNNING;
+       }
+
+       return ERROR_OK;
+}
+
+static int aice_usb_reset(void)
+{
+       if (aice_write_ctrl(AICE_WRITE_CTRL_CLEAR_TIMEOUT_STATUS, 0x1) != ERROR_OK)
+               return ERROR_FAIL;
+
+       if (custom_trst_script == NULL) {
+               if (aice_write_ctrl(AICE_WRITE_CTRL_JTAG_PIN_CONTROL,
+                                       AICE_JTAG_PIN_CONTROL_TRST) != ERROR_OK)
+                       return ERROR_FAIL;
+       } else {
+               /* custom trst operations */
+               if (aice_execute_custom_script(custom_trst_script) != ERROR_OK)
+                       return ERROR_FAIL;
+       }
+
+       if (aice_usb_set_clock(jtag_clock) != ERROR_OK)
+               return ERROR_FAIL;
+
+       return ERROR_OK;
+}
+
+static int aice_issue_srst(void)
+{
+       LOG_DEBUG("aice_issue_srst");
+
+       /* After issuing srst, target will be running. So we need to restore EDM_CTL. */
+       aice_restore_edm_registers();
+
+       if (custom_srst_script == NULL) {
+               if (aice_write_ctrl(AICE_WRITE_CTRL_JTAG_PIN_CONTROL,
+                                       AICE_JTAG_PIN_CONTROL_SRST) != ERROR_OK)
+                       return ERROR_FAIL;
+       } else {
+               /* custom srst operations */
+               if (aice_execute_custom_script(custom_srst_script) != ERROR_OK)
+                       return ERROR_FAIL;
+       }
+
+       /* wait CRST infinitely */
+       uint32_t dbger_value;
+       int i = 0;
+       while (1) {
+               if (aice_read_misc(current_target_id,
+                                       NDS_EDM_MISC_DBGER, &dbger_value) != ERROR_OK)
+                       return ERROR_FAIL;
+
+               if (dbger_value & NDS_DBGER_CRST)
+                       break;
+
+               if ((i % 30) == 0)
+                       keep_alive();
+               i++;
+       }
+
+       host_dtr_valid = false;
+       target_dtr_valid = false;
+
+       core_state = AICE_TARGET_RUNNING;
+       return ERROR_OK;
+}
+
+static int aice_issue_reset_hold(void)
+{
+       LOG_DEBUG("aice_issue_reset_hold");
+
+       /* set no_dbgi_pin to 0 */
+       uint32_t pin_status;
+       aice_read_ctrl(AICE_READ_CTRL_GET_JTAG_PIN_STATUS, &pin_status);
+       if (pin_status | 0x4)
+               aice_write_ctrl(AICE_WRITE_CTRL_JTAG_PIN_STATUS, pin_status & (~0x4));
+
+       /* issue restart */
+       if (custom_restart_script == NULL) {
+               if (aice_write_ctrl(AICE_WRITE_CTRL_JTAG_PIN_CONTROL,
+                                       AICE_JTAG_PIN_CONTROL_RESTART) != ERROR_OK)
+                       return ERROR_FAIL;
+       } else {
+               /* custom restart operations */
+               if (aice_execute_custom_script(custom_restart_script) != ERROR_OK)
+                       return ERROR_FAIL;
+       }
+
+       if (aice_check_dbger(NDS_DBGER_CRST | NDS_DBGER_DEX) == ERROR_OK) {
+               aice_backup_tmp_registers();
+               core_state = AICE_TARGET_HALTED;
+
+               return ERROR_OK;
+       } else {
+               /* set no_dbgi_pin to 1 */
+               aice_write_ctrl(AICE_WRITE_CTRL_JTAG_PIN_STATUS, pin_status | 0x4);
+
+               /* issue restart again */
+               if (custom_restart_script == NULL) {
+                       if (aice_write_ctrl(AICE_WRITE_CTRL_JTAG_PIN_CONTROL,
+                                               AICE_JTAG_PIN_CONTROL_RESTART) != ERROR_OK)
+                               return ERROR_FAIL;
+               } else {
+                       /* custom restart operations */
+                       if (aice_execute_custom_script(custom_restart_script) != ERROR_OK)
+                               return ERROR_FAIL;
+               }
+
+               if (aice_check_dbger(NDS_DBGER_CRST | NDS_DBGER_DEX) == ERROR_OK) {
+                       aice_backup_tmp_registers();
+                       core_state = AICE_TARGET_HALTED;
+
+                       return ERROR_OK;
+               }
+
+               /* do software reset-and-hold */
+               aice_issue_srst();
+               aice_usb_halt();
+
+               uint32_t value_ir3;
+               aice_read_reg(IR3, &value_ir3);
+               aice_write_reg(PC, value_ir3 & 0xFFFF0000);
+       }
+
+       return ERROR_FAIL;
+}
+
+static int aice_usb_assert_srst(enum aice_srst_type_s srst)
+{
+       if ((AICE_SRST != srst) && (AICE_RESET_HOLD != srst))
+               return ERROR_FAIL;
+
+       /* clear DBGER */
+       if (aice_write_misc(current_target_id, NDS_EDM_MISC_DBGER,
+                               NDS_DBGER_CLEAR_ALL) != ERROR_OK)
+               return ERROR_FAIL;
+
+       int result = ERROR_OK;
+       if (AICE_SRST == srst)
+               result = aice_issue_srst();
+       else
+               result = aice_issue_reset_hold();
+
+       /* Clear DBGER.CRST after reset to avoid 'core-reset checking' errors.
+        * assert_srst is user-intentional reset behavior, so we could
+        * clear DBGER.CRST safely.
+        */
+       if (aice_write_misc(current_target_id,
+                               NDS_EDM_MISC_DBGER, NDS_DBGER_CRST) != ERROR_OK)
+               return ERROR_FAIL;
+
+       return result;
+}
+
+static int aice_usb_run(void)
+{
+       LOG_DEBUG("aice_usb_run");
+
+       uint32_t dbger_value;
+       if (aice_read_misc(current_target_id,
+                               NDS_EDM_MISC_DBGER, &dbger_value) != ERROR_OK)
+               return ERROR_FAIL;
+
+       if ((dbger_value & NDS_DBGER_DEX) != NDS_DBGER_DEX) {
+               LOG_WARNING("<-- TARGET WARNING! The debug target exited "
+                               "the debug mode unexpectedly. -->");
+               return ERROR_FAIL;
+       }
+
+       /* restore r0 & r1 before free run */
+       aice_restore_tmp_registers();
+       core_state = AICE_TARGET_RUNNING;
+
+       /* clear DBGER */
+       aice_write_misc(current_target_id, NDS_EDM_MISC_DBGER,
+                       NDS_DBGER_CLEAR_ALL);
+
+       /** restore EDM registers */
+       /** OpenOCD should restore EDM_CTL **before** to exit debug state.
+        *  Otherwise, following instruction will read wrong EDM_CTL value.
+        *
+        *  pc -> mfsr $p0, EDM_CTL (single step)
+        *        slli $p0, $p0, 1
+        *        slri $p0, $p0, 31
+        */
+       aice_restore_edm_registers();
+
+       /** execute instructions in DIM */
+       uint32_t instructions[4] = {
+               NOP,
+               NOP,
+               NOP,
+               IRET
+       };
+       int result = aice_execute_dim(instructions, 4);
+
+       return result;
+}
+
+static int aice_usb_step(void)
+{
+       LOG_DEBUG("aice_usb_step");
+
+       uint32_t ir0_value;
+       uint32_t ir0_reg_num;
+
+       if (is_v2_edm() == true)
+               /* V2 EDM will push interrupt stack as debug exception */
+               ir0_reg_num = IR1;
+       else
+               ir0_reg_num = IR0;
+
+       /** enable HSS */
+       aice_read_reg(ir0_reg_num, &ir0_value);
+       if ((ir0_value & 0x800) == 0) {
+               /** set PSW.HSS */
+               ir0_value |= (0x01 << 11);
+               aice_write_reg(ir0_reg_num, ir0_value);
+       }
+
+       if (ERROR_FAIL == aice_usb_run())
+               return ERROR_FAIL;
+
+       int i = 0;
+       enum aice_target_state_s state;
+       while (1) {
+               /* read DBGER */
+               if (aice_usb_state(&state) != ERROR_OK)
+                       return ERROR_FAIL;
+
+               if (AICE_TARGET_HALTED == state)
+                       break;
+
+               long long then = 0;
+               if (i == 30)
+                       then = timeval_ms();
+
+               if (i >= 30) {
+                       if ((timeval_ms() - then) > 1000)
+                               LOG_WARNING("Timeout (1000ms) waiting for halt to complete");
+
+                       return ERROR_FAIL;
+               }
+               i++;
+       }
+
+       /** disable HSS */
+       aice_read_reg(ir0_reg_num, &ir0_value);
+       ir0_value &= ~(0x01 << 11);
+       aice_write_reg(ir0_reg_num, ir0_value);
+
+       return ERROR_OK;
+}
+
+static int aice_usb_read_mem_b_bus(uint32_t address, uint32_t *data)
+{
+       return aice_read_mem_b(current_target_id, address, data);
+}
+
+static int aice_usb_read_mem_h_bus(uint32_t address, uint32_t *data)
+{
+       return aice_read_mem_h(current_target_id, address, data);
+}
+
+static int aice_usb_read_mem_w_bus(uint32_t address, uint32_t *data)
+{
+       return aice_read_mem(current_target_id, address, data);
+}
+
+static int aice_usb_read_mem_b_dim(uint32_t address, uint32_t *data)
+{
+       uint32_t value;
+       uint32_t instructions[4] = {
+               LBI_BI(R1, R0),
+               MTSR_DTR(R1),
+               DSB,
+               BEQ_MINUS_12
+       };
+
+       aice_execute_dim(instructions, 4);
+
+       aice_read_dtr(current_target_id, &value);
+       *data = value & 0xFF;
+
+       return ERROR_OK;
+}
+
+static int aice_usb_read_mem_h_dim(uint32_t address, uint32_t *data)
+{
+       uint32_t value;
+       uint32_t instructions[4] = {
+               LHI_BI(R1, R0),
+               MTSR_DTR(R1),
+               DSB,
+               BEQ_MINUS_12
+       };
+
+       aice_execute_dim(instructions, 4);
+
+       aice_read_dtr(current_target_id, &value);
+       *data = value & 0xFFFF;
+
+       return ERROR_OK;
+}
+
+static int aice_usb_read_mem_w_dim(uint32_t address, uint32_t *data)
+{
+       uint32_t instructions[4] = {
+               LWI_BI(R1, R0),
+               MTSR_DTR(R1),
+               DSB,
+               BEQ_MINUS_12
+       };
+
+       aice_execute_dim(instructions, 4);
+
+       aice_read_dtr(current_target_id, data);
+
+       return ERROR_OK;
+}
+
+static int aice_usb_set_address_dim(uint32_t address)
+{
+       uint32_t instructions[4] = {
+               SETHI(R0, address >> 12),
+               ORI(R0, R0, address & 0x00000FFF),
+               NOP,
+               BEQ_MINUS_12
+       };
+
+       return aice_execute_dim(instructions, 4);
+}
+
+static int aice_usb_read_memory_unit(uint32_t addr, uint32_t size,
+               uint32_t count, uint8_t *buffer)
+{
+       LOG_DEBUG("aice_usb_read_memory_unit, addr: 0x%08x, size: %d, count: %d",
+                       addr, size, count);
+
+       if (NDS_MEMORY_ACC_CPU == access_channel)
+               aice_usb_set_address_dim(addr);
+
+       uint32_t value;
+       size_t i;
+       read_mem_func_t read_mem_func;
+
+       switch (size) {
+               case 1:
+                       if (NDS_MEMORY_ACC_BUS == access_channel)
+                               read_mem_func = aice_usb_read_mem_b_bus;
+                       else
+                               read_mem_func = aice_usb_read_mem_b_dim;
+
+                       for (i = 0; i < count; i++) {
+                               read_mem_func(addr, &value);
+                               *buffer++ = (uint8_t)value;
+                               addr++;
+                       }
+                       break;
+               case 2:
+                       if (NDS_MEMORY_ACC_BUS == access_channel)
+                               read_mem_func = aice_usb_read_mem_h_bus;
+                       else
+                               read_mem_func = aice_usb_read_mem_h_dim;
+
+                       for (i = 0; i < count; i++) {
+                               read_mem_func(addr, &value);
+                               uint16_t svalue = value;
+                               memcpy(buffer, &svalue, sizeof(uint16_t));
+                               buffer += 2;
+                               addr += 2;
+                       }
+                       break;
+               case 4:
+                       if (NDS_MEMORY_ACC_BUS == access_channel)
+                               read_mem_func = aice_usb_read_mem_w_bus;
+                       else
+                               read_mem_func = aice_usb_read_mem_w_dim;
+
+                       for (i = 0; i < count; i++) {
+                               read_mem_func(addr, &value);
+                               memcpy(buffer, &value, sizeof(uint32_t));
+                               buffer += 4;
+                               addr += 4;
+                       }
+                       break;
+       }
+
+       return ERROR_OK;
+}
+
+static int aice_usb_write_mem_b_bus(uint32_t address, uint32_t data)
+{
+       return aice_write_mem_b(current_target_id, address, data);
+}
+
+static int aice_usb_write_mem_h_bus(uint32_t address, uint32_t data)
+{
+       return aice_write_mem_h(current_target_id, address, data);
+}
+
+static int aice_usb_write_mem_w_bus(uint32_t address, uint32_t data)
+{
+       return aice_write_mem(current_target_id, address, data);
+}
+
+static int aice_usb_write_mem_b_dim(uint32_t address, uint32_t data)
+{
+       uint32_t instructions[4] = {
+               MFSR_DTR(R1),
+               SBI_BI(R1, R0),
+               DSB,
+               BEQ_MINUS_12
+       };
+
+       aice_write_dtr(current_target_id, data & 0xFF);
+       aice_execute_dim(instructions, 4);
+
+       return ERROR_OK;
+}
+
+static int aice_usb_write_mem_h_dim(uint32_t address, uint32_t data)
+{
+       uint32_t instructions[4] = {
+               MFSR_DTR(R1),
+               SHI_BI(R1, R0),
+               DSB,
+               BEQ_MINUS_12
+       };
+
+       aice_write_dtr(current_target_id, data & 0xFFFF);
+       aice_execute_dim(instructions, 4);
+
+       return ERROR_OK;
+}
+
+static int aice_usb_write_mem_w_dim(uint32_t address, uint32_t data)
+{
+       uint32_t instructions[4] = {
+               MFSR_DTR(R1),
+               SWI_BI(R1, R0),
+               DSB,
+               BEQ_MINUS_12
+       };
+
+       aice_write_dtr(current_target_id, data);
+       aice_execute_dim(instructions, 4);
+
+       return ERROR_OK;
+}
+
+static int aice_usb_write_memory_unit(uint32_t addr, uint32_t size,
+               uint32_t count, const uint8_t *buffer)
+{
+       LOG_DEBUG("aice_usb_write_memory_unit, addr: 0x%08x, size: %d, count: %d",
+                       addr, size, count);
+
+       if (NDS_MEMORY_ACC_CPU == access_channel)
+               aice_usb_set_address_dim(addr);
+
+       size_t i;
+       write_mem_func_t write_mem_func;
+
+       switch (size) {
+               case 1:
+                       if (NDS_MEMORY_ACC_BUS == access_channel)
+                               write_mem_func = aice_usb_write_mem_b_bus;
+                       else
+                               write_mem_func = aice_usb_write_mem_b_dim;
+
+                       for (i = 0; i < count; i++) {
+                               write_mem_func(addr, *buffer);
+                               buffer++;
+                               addr++;
+                       }
+                       break;
+               case 2:
+                       if (NDS_MEMORY_ACC_BUS == access_channel)
+                               write_mem_func = aice_usb_write_mem_h_bus;
+                       else
+                               write_mem_func = aice_usb_write_mem_h_dim;
+
+                       for (i = 0; i < count; i++) {
+                               uint16_t value;
+                               memcpy(&value, buffer, sizeof(uint16_t));
+
+                               write_mem_func(addr, value);
+                               buffer += 2;
+                               addr += 2;
+                       }
+                       break;
+               case 4:
+                       if (NDS_MEMORY_ACC_BUS == access_channel)
+                               write_mem_func = aice_usb_write_mem_w_bus;
+                       else
+                               write_mem_func = aice_usb_write_mem_w_dim;
+
+                       for (i = 0; i < count; i++) {
+                               uint32_t value;
+                               memcpy(&value, buffer, sizeof(uint32_t));
+
+                               write_mem_func(addr, value);
+                               buffer += 4;
+                               addr += 4;
+                       }
+                       break;
+       }
+
+       return ERROR_OK;
+}
+
+static int aice_bulk_read_mem(uint32_t addr, uint32_t count, uint8_t *buffer)
+{
+       uint32_t packet_size;
+
+       while (count > 0) {
+               packet_size = (count >= 0x100) ? 0x100 : count;
+
+               /** set address */
+               addr &= 0xFFFFFFFC;
+               if (aice_write_misc(current_target_id, NDS_EDM_MISC_SBAR, addr) != ERROR_OK)
+                       return ERROR_FAIL;
+
+               if (aice_fastread_mem(current_target_id, (uint32_t *)buffer,
+                                       packet_size) != ERROR_OK)
+                       return ERROR_FAIL;
+
+               buffer += (packet_size * 4);
+               addr += (packet_size * 4);
+               count -= packet_size;
+       }
+
+       return ERROR_OK;
+}
+
+static int aice_bulk_write_mem(uint32_t addr, uint32_t count, const uint8_t *buffer)
+{
+       uint32_t packet_size;
+
+       while (count > 0) {
+               packet_size = (count >= 0x100) ? 0x100 : count;
+
+               /** set address */
+               addr &= 0xFFFFFFFC;
+               if (aice_write_misc(current_target_id, NDS_EDM_MISC_SBAR, addr | 1) != ERROR_OK)
+                       return ERROR_FAIL;
+
+               if (aice_fastwrite_mem(current_target_id, (const uint32_t *)buffer,
+                                       packet_size) != ERROR_OK)
+                       return ERROR_FAIL;
+
+               buffer += (packet_size * 4);
+               addr += (packet_size * 4);
+               count -= packet_size;
+       }
+
+       return ERROR_OK;
+}
+
+static int aice_usb_bulk_read_mem(uint32_t addr, uint32_t length, uint8_t *buffer)
+{
+       LOG_DEBUG("aice_usb_bulk_read_mem, addr: 0x%08x, length: 0x%08x", addr, length);
+
+       int retval;
+
+       if (NDS_MEMORY_ACC_CPU == access_channel)
+               aice_usb_set_address_dim(addr);
+
+       if (NDS_MEMORY_ACC_CPU == access_channel)
+               retval = aice_usb_read_memory_unit(addr, 4, length / 4, buffer);
+       else
+               retval = aice_bulk_read_mem(addr, length / 4, buffer);
+
+       return retval;
+}
+
+static int aice_usb_bulk_write_mem(uint32_t addr, uint32_t length, const uint8_t *buffer)
+{
+       LOG_DEBUG("aice_usb_bulk_write_mem, addr: 0x%08x, length: 0x%08x", addr, length);
+
+       int retval;
+
+       if (NDS_MEMORY_ACC_CPU == access_channel)
+               aice_usb_set_address_dim(addr);
+
+       if (NDS_MEMORY_ACC_CPU == access_channel)
+               retval = aice_usb_write_memory_unit(addr, 4, length / 4, buffer);
+       else
+               retval = aice_bulk_write_mem(addr, length / 4, buffer);
+
+       return retval;
+}
+
+static int aice_usb_read_debug_reg(uint32_t addr, uint32_t *val)
+{
+       if (AICE_TARGET_HALTED == core_state) {
+               if (NDS_EDM_SR_EDMSW == addr) {
+                       *val = edmsw_backup;
+               } else if (NDS_EDM_SR_EDM_DTR == addr) {
+                       if (target_dtr_valid) {
+                               /* if EDM_DTR has read out, clear it. */
+                               *val = target_dtr_backup;
+                               edmsw_backup &= (~0x1);
+                               target_dtr_valid = false;
+                       } else {
+                               *val = 0;
+                       }
+               }
+       }
+
+       return aice_read_edmsr(current_target_id, addr, val);
+}
+
+static int aice_usb_write_debug_reg(uint32_t addr, const uint32_t val)
+{
+       if (AICE_TARGET_HALTED == core_state) {
+               if (NDS_EDM_SR_EDM_DTR == addr) {
+                       host_dtr_backup = val;
+                       edmsw_backup |= 0x2;
+                       host_dtr_valid = true;
+               }
+       }
+
+       return aice_write_edmsr(current_target_id, addr, val);
+}
+
+static int aice_usb_select_target(uint32_t target_id)
+{
+       current_target_id = target_id;
+
+       return ERROR_OK;
+}
+
+static int aice_usb_memory_access(enum nds_memory_access channel)
+{
+       LOG_DEBUG("aice_usb_memory_access, access channel: %d", channel);
+
+       access_channel = channel;
+
+       return ERROR_OK;
+}
+
+static int aice_usb_memory_mode(enum nds_memory_select mem_select)
+{
+       if (memory_select == mem_select)
+               return ERROR_OK;
+
+       LOG_DEBUG("aice_usb_memory_mode, memory select: %d", mem_select);
+
+       memory_select = mem_select;
+
+       if (NDS_MEMORY_SELECT_AUTO != memory_select)
+               aice_write_misc(current_target_id, NDS_EDM_MISC_ACC_CTL,
+                               memory_select - 1);
+       else
+               aice_write_misc(current_target_id, NDS_EDM_MISC_ACC_CTL,
+                               NDS_MEMORY_SELECT_MEM - 1);
+
+       return ERROR_OK;
+}
+
+static int aice_usb_read_tlb(uint32_t virtual_address, uint32_t *physical_address)
+{
+       LOG_DEBUG("aice_usb_read_tlb, virtual address: 0x%08x", virtual_address);
+
+       uint32_t instructions[4];
+       uint32_t probe_result;
+       uint32_t value_mr3;
+       uint32_t value_mr4;
+       uint32_t access_page_size;
+       uint32_t virtual_offset;
+       uint32_t physical_page_number;
+
+       aice_write_dtr(current_target_id, virtual_address);
+
+       /* probe TLB first */
+       instructions[0] = MFSR_DTR(R0);
+       instructions[1] = TLBOP_TARGET_PROBE(R1, R0);
+       instructions[2] = DSB;
+       instructions[3] = BEQ_MINUS_12;
+       aice_execute_dim(instructions, 4);
+
+       aice_read_reg(R1, &probe_result);
+
+       if (probe_result & 0x80000000)
+               return ERROR_FAIL;
+
+       /* read TLB entry */
+       aice_write_dtr(current_target_id, probe_result & 0x7FF);
+
+       /* probe TLB first */
+       instructions[0] = MFSR_DTR(R0);
+       instructions[1] = TLBOP_TARGET_READ(R0);
+       instructions[2] = DSB;
+       instructions[3] = BEQ_MINUS_12;
+       aice_execute_dim(instructions, 4);
+
+       /* TODO: it should backup mr3, mr4 */
+       aice_read_reg(MR3, &value_mr3);
+       aice_read_reg(MR4, &value_mr4);
+
+       access_page_size = value_mr4 & 0xF;
+       if (0 == access_page_size) { /* 4K page */
+               virtual_offset = virtual_address & 0x00000FFF;
+               physical_page_number = value_mr3 & 0xFFFFF000;
+       } else if (1 == access_page_size) { /* 8K page */
+               virtual_offset = virtual_address & 0x00001FFF;
+               physical_page_number = value_mr3 & 0xFFFFE000;
+       } else if (5 == access_page_size) { /* 1M page */
+               virtual_offset = virtual_address & 0x000FFFFF;
+               physical_page_number = value_mr3 & 0xFFF00000;
+       } else {
+               return ERROR_FAIL;
+       }
+
+       *physical_address = physical_page_number | virtual_offset;
+
+       return ERROR_OK;
+}
+
+static int aice_usb_init_cache(void)
+{
+       LOG_DEBUG("aice_usb_init_cache");
+
+       uint32_t value_cr1;
+       uint32_t value_cr2;
+
+       aice_read_reg(CR1, &value_cr1);
+       aice_read_reg(CR2, &value_cr2);
+
+       icache.set = value_cr1 & 0x7;
+       icache.log2_set = icache.set + 6;
+       icache.set = 64 << icache.set;
+       icache.way = ((value_cr1 >> 3) & 0x7) + 1;
+       icache.line_size = (value_cr1 >> 6) & 0x7;
+       if (icache.line_size != 0) {
+               icache.log2_line_size = icache.line_size + 2;
+               icache.line_size = 8 << (icache.line_size - 1);
+       } else {
+               icache.log2_line_size = 0;
+       }
+
+       LOG_DEBUG("\ticache set: %d, way: %d, line size: %d, "
+                       "log2(set): %d, log2(line_size): %d",
+                       icache.set, icache.way, icache.line_size,
+                       icache.log2_set, icache.log2_line_size);
+
+       dcache.set = value_cr2 & 0x7;
+       dcache.log2_set = dcache.set + 6;
+       dcache.set = 64 << dcache.set;
+       dcache.way = ((value_cr2 >> 3) & 0x7) + 1;
+       dcache.line_size = (value_cr2 >> 6) & 0x7;
+       if (dcache.line_size != 0) {
+               dcache.log2_line_size = dcache.line_size + 2;
+               dcache.line_size = 8 << (dcache.line_size - 1);
+       } else {
+               dcache.log2_line_size = 0;
+       }
+
+       LOG_DEBUG("\tdcache set: %d, way: %d, line size: %d, "
+                       "log2(set): %d, log2(line_size): %d",
+                       dcache.set, dcache.way, dcache.line_size,
+                       dcache.log2_set, dcache.log2_line_size);
+
+       cache_init = true;
+
+       return ERROR_OK;
+}
+
+static int aice_usb_dcache_inval_all(void)
+{
+       LOG_DEBUG("aice_usb_dcache_inval_all");
+
+       uint32_t set_index;
+       uint32_t way_index;
+       uint32_t cache_index;
+       uint32_t instructions[4];
+
+       instructions[0] = MFSR_DTR(R0);
+       instructions[1] = L1D_IX_INVAL(R0);
+       instructions[2] = DSB;
+       instructions[3] = BEQ_MINUS_12;
+
+       for (set_index = 0; set_index < dcache.set; set_index++) {
+               for (way_index = 0; way_index < dcache.way; way_index++) {
+                       cache_index = (way_index << (dcache.log2_set + dcache.log2_line_size)) |
+                               (set_index << dcache.log2_line_size);
+
+                       if (ERROR_OK != aice_write_dtr(current_target_id, cache_index))
+                               return ERROR_FAIL;
+
+                       if (ERROR_OK != aice_execute_dim(instructions, 4))
+                               return ERROR_FAIL;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int aice_usb_dcache_va_inval(uint32_t address)
+{
+       LOG_DEBUG("aice_usb_dcache_va_inval");
+
+       uint32_t instructions[4];
+
+       aice_write_dtr(current_target_id, address);
+
+       instructions[0] = MFSR_DTR(R0);
+       instructions[1] = L1D_VA_INVAL(R0);
+       instructions[2] = DSB;
+       instructions[3] = BEQ_MINUS_12;
+
+       return aice_execute_dim(instructions, 4);
+}
+
+static int aice_usb_dcache_wb_all(void)
+{
+       LOG_DEBUG("aice_usb_dcache_wb_all");
+
+       uint32_t set_index;
+       uint32_t way_index;
+       uint32_t cache_index;
+       uint32_t instructions[4];
+
+       instructions[0] = MFSR_DTR(R0);
+       instructions[1] = L1D_IX_WB(R0);
+       instructions[2] = DSB;
+       instructions[3] = BEQ_MINUS_12;
+
+       for (set_index = 0; set_index < dcache.set; set_index++) {
+               for (way_index = 0; way_index < dcache.way; way_index++) {
+                       cache_index = (way_index << (dcache.log2_set + dcache.log2_line_size)) |
+                               (set_index << dcache.log2_line_size);
+
+                       if (ERROR_OK != aice_write_dtr(current_target_id, cache_index))
+                               return ERROR_FAIL;
+
+                       if (ERROR_OK != aice_execute_dim(instructions, 4))
+                               return ERROR_FAIL;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int aice_usb_dcache_va_wb(uint32_t address)
+{
+       LOG_DEBUG("aice_usb_dcache_va_wb");
+
+       uint32_t instructions[4];
+
+       aice_write_dtr(current_target_id, address);
+
+       instructions[0] = MFSR_DTR(R0);
+       instructions[1] = L1D_VA_WB(R0);
+       instructions[2] = DSB;
+       instructions[3] = BEQ_MINUS_12;
+
+       return aice_execute_dim(instructions, 4);
+}
+
+static int aice_usb_icache_inval_all(void)
+{
+       LOG_DEBUG("aice_usb_icache_inval_all");
+
+       uint32_t set_index;
+       uint32_t way_index;
+       uint32_t cache_index;
+       uint32_t instructions[4];
+
+       instructions[0] = MFSR_DTR(R0);
+       instructions[1] = L1I_IX_INVAL(R0);
+       instructions[2] = ISB;
+       instructions[3] = BEQ_MINUS_12;
+
+       for (set_index = 0; set_index < icache.set; set_index++) {
+               for (way_index = 0; way_index < icache.way; way_index++) {
+                       cache_index = (way_index << (icache.log2_set + icache.log2_line_size)) |
+                               (set_index << icache.log2_line_size);
+
+                       if (ERROR_OK != aice_write_dtr(current_target_id, cache_index))
+                               return ERROR_FAIL;
+
+                       if (ERROR_OK != aice_execute_dim(instructions, 4))
+                               return ERROR_FAIL;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int aice_usb_icache_va_inval(uint32_t address)
+{
+       LOG_DEBUG("aice_usb_icache_va_inval");
+
+       uint32_t instructions[4];
+
+       aice_write_dtr(current_target_id, address);
+
+       instructions[0] = MFSR_DTR(R0);
+       instructions[1] = L1I_VA_INVAL(R0);
+       instructions[2] = ISB;
+       instructions[3] = BEQ_MINUS_12;
+
+       return aice_execute_dim(instructions, 4);
+}
+
+static int aice_usb_cache_ctl(uint32_t subtype, uint32_t address)
+{
+       LOG_DEBUG("aice_usb_cache_ctl");
+
+       int result;
+
+       if (cache_init == false)
+               aice_usb_init_cache();
+
+       switch (subtype) {
+               case AICE_CACHE_CTL_L1D_INVALALL:
+                       result = aice_usb_dcache_inval_all();
+                       break;
+               case AICE_CACHE_CTL_L1D_VA_INVAL:
+                       result = aice_usb_dcache_va_inval(address);
+                       break;
+               case AICE_CACHE_CTL_L1D_WBALL:
+                       result = aice_usb_dcache_wb_all();
+                       break;
+               case AICE_CACHE_CTL_L1D_VA_WB:
+                       result = aice_usb_dcache_va_wb(address);
+                       break;
+               case AICE_CACHE_CTL_L1I_INVALALL:
+                       result = aice_usb_icache_inval_all();
+                       break;
+               case AICE_CACHE_CTL_L1I_VA_INVAL:
+                       result = aice_usb_icache_va_inval(address);
+                       break;
+               default:
+                       result = ERROR_FAIL;
+                       break;
+       }
+
+       return result;
+}
+
+static int aice_usb_set_retry_times(uint32_t a_retry_times)
+{
+       aice_max_retry_times = a_retry_times;
+       return ERROR_OK;
+}
+
+static int aice_usb_program_edm(char *command_sequence)
+{
+       char *command_str;
+       char *reg_name_0;
+       char *reg_name_1;
+       uint32_t data_value;
+       int i;
+
+       /* init strtok() */
+       command_str = strtok(command_sequence, ";");
+       if (command_str == NULL)
+               return ERROR_OK;
+
+       do {
+               i = 0;
+               /* process one command */
+               while (command_str[i] == ' ' ||
+                               command_str[i] == '\n' ||
+                               command_str[i] == '\r' ||
+                               command_str[i] == '\t')
+                       i++;
+
+               /* skip ' ', '\r', '\n', '\t' */
+               command_str = command_str + i;
+
+               if (strncmp(command_str, "write_misc", 10) == 0) {
+                       reg_name_0 = strstr(command_str, "gen_port0");
+                       reg_name_1 = strstr(command_str, "gen_port1");
+
+                       if (reg_name_0 != NULL) {
+                               data_value = strtoul(reg_name_0 + 9, NULL, 0);
+
+                               if (aice_write_misc(current_target_id,
+                                                       NDS_EDM_MISC_GEN_PORT0, data_value) != ERROR_OK)
+                                       return ERROR_FAIL;
+
+                       } else if (reg_name_1 != NULL) {
+                               data_value = strtoul(reg_name_1 + 9, NULL, 0);
+
+                               if (aice_write_misc(current_target_id,
+                                                       NDS_EDM_MISC_GEN_PORT1, data_value) != ERROR_OK)
+                                       return ERROR_FAIL;
+                       } else {
+                               LOG_ERROR("program EDM, unsupported misc register: %s", command_str);
+                       }
+               } else {
+                       LOG_ERROR("program EDM, unsupported command: %s", command_str);
+               }
+
+               /* update command_str */
+               command_str = strtok(NULL, ";");
+
+       } while (command_str != NULL);
+
+       return ERROR_OK;
+}
+
+static int aice_usb_pack_command(bool enable_pack_command)
+{
+       if (enable_pack_command == false) {
+               /* turn off usb_pack_command, flush usb_packets_buffer */
+               aice_usb_packet_flush();
+       }
+
+       usb_pack_command = enable_pack_command;
+
+       return ERROR_OK;
+}
+
+static int aice_usb_execute(uint32_t *instructions, uint32_t instruction_num)
+{
+       uint32_t i, j;
+       uint8_t current_instruction_num;
+       uint32_t dim_instructions[4] = {NOP, NOP, NOP, BEQ_MINUS_12};
+
+       /* To execute 4 instructions as a special case */
+       if (instruction_num == 4)
+               return aice_execute_dim(instructions, 4);
+
+       for (i = 0 ; i < instruction_num ; i += 3) {
+               if (instruction_num - i < 3) {
+                       current_instruction_num = instruction_num - i;
+                       for (j = current_instruction_num ; j < 3 ; j++)
+                               dim_instructions[j] = NOP;
+               } else {
+                       current_instruction_num = 3;
+               }
+
+               memcpy(dim_instructions, instructions + i,
+                               current_instruction_num * sizeof(uint32_t));
+
+               /** fill DIM */
+               if (aice_write_dim(current_target_id,
+                                       dim_instructions,
+                                       4) != ERROR_OK)
+                       return ERROR_FAIL;
+
+               /** clear DBGER.DPED */
+               if (aice_write_misc(current_target_id,
+                                       NDS_EDM_MISC_DBGER, NDS_DBGER_DPED) != ERROR_OK)
+                       return ERROR_FAIL;
+
+               /** execute DIM */
+               if (aice_do_execute(current_target_id) != ERROR_OK)
+                       return ERROR_FAIL;
+
+               /** check DBGER.DPED */
+               if (aice_check_dbger(NDS_DBGER_DPED) != ERROR_OK) {
+
+                       LOG_ERROR("<-- TARGET ERROR! Debug operations do not finish properly:"
+                                       "0x%08x 0x%08x 0x%08x 0x%08x. -->",
+                                       dim_instructions[0],
+                                       dim_instructions[1],
+                                       dim_instructions[2],
+                                       dim_instructions[3]);
+                       return ERROR_FAIL;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+static int aice_usb_set_custom_srst_script(const char *script)
+{
+       custom_srst_script = strdup(script);
+
+       return ERROR_OK;
+}
+
+static int aice_usb_set_custom_trst_script(const char *script)
+{
+       custom_trst_script = strdup(script);
+
+       return ERROR_OK;
+}
+
+static int aice_usb_set_custom_restart_script(const char *script)
+{
+       custom_restart_script = strdup(script);
+
+       return ERROR_OK;
+}
+
+static int aice_usb_set_count_to_check_dbger(uint32_t count_to_check)
+{
+       aice_count_to_check_dbger = count_to_check;
+
+       return ERROR_OK;
+}
+
+static int aice_usb_set_data_endian(enum aice_target_endian target_data_endian)
+{
+       data_endian = target_data_endian;
+
+       return ERROR_OK;
+}
+
+/** */
+struct aice_port_api_s aice_usb_api = {
+       /** */
+       .open = aice_open_device,
+       /** */
+       .close = aice_usb_close,
+       /** */
+       .idcode = aice_usb_idcode,
+       /** */
+       .state = aice_usb_state,
+       /** */
+       .reset = aice_usb_reset,
+       /** */
+       .assert_srst = aice_usb_assert_srst,
+       /** */
+       .run = aice_usb_run,
+       /** */
+       .halt = aice_usb_halt,
+       /** */
+       .step = aice_usb_step,
+       /** */
+       .read_reg = aice_usb_read_reg,
+       /** */
+       .write_reg = aice_usb_write_reg,
+       /** */
+       .read_reg_64 = aice_usb_read_reg_64,
+       /** */
+       .write_reg_64 = aice_usb_write_reg_64,
+       /** */
+       .read_mem_unit = aice_usb_read_memory_unit,
+       /** */
+       .write_mem_unit = aice_usb_write_memory_unit,
+       /** */
+       .read_mem_bulk = aice_usb_bulk_read_mem,
+       /** */
+       .write_mem_bulk = aice_usb_bulk_write_mem,
+       /** */
+       .read_debug_reg = aice_usb_read_debug_reg,
+       /** */
+       .write_debug_reg = aice_usb_write_debug_reg,
+       /** */
+       .set_jtag_clock = aice_usb_set_jtag_clock,
+       /** */
+       .select_target = aice_usb_select_target,
+       /** */
+       .memory_access = aice_usb_memory_access,
+       /** */
+       .memory_mode = aice_usb_memory_mode,
+       /** */
+       .read_tlb = aice_usb_read_tlb,
+       /** */
+       .cache_ctl = aice_usb_cache_ctl,
+       /** */
+       .set_retry_times = aice_usb_set_retry_times,
+       /** */
+       .program_edm = aice_usb_program_edm,
+       /** */
+       .pack_command = aice_usb_pack_command,
+       /** */
+       .execute = aice_usb_execute,
+       /** */
+       .set_custom_srst_script = aice_usb_set_custom_srst_script,
+       /** */
+       .set_custom_trst_script = aice_usb_set_custom_trst_script,
+       /** */
+       .set_custom_restart_script = aice_usb_set_custom_restart_script,
+       /** */
+       .set_count_to_check_dbger = aice_usb_set_count_to_check_dbger,
+       /** */
+       .set_data_endian = aice_usb_set_data_endian,
+};
diff --git a/src/jtag/aice/aice_usb.h b/src/jtag/aice/aice_usb.h
new file mode 100644 (file)
index 0000000..1678c68
--- /dev/null
@@ -0,0 +1,140 @@
+/***************************************************************************
+ *   Copyright (C) 2013 by 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 __AICE_USB_H__
+#define __AICE_USB_H__
+
+#include "aice_port.h"
+
+/* AICE USB timeout value */
+#define AICE_USB_TIMEOUT                               5000
+
+/* AICE USB buffer size */
+#define AICE_IN_BUFFER_SIZE                            2048
+#define AICE_OUT_BUFFER_SIZE                   2048
+#define AICE_IN_PACKETS_BUFFER_SIZE            2048
+#define AICE_OUT_PACKETS_BUFFER_SIZE   2048
+
+/* Constants for AICE command */
+#define AICE_CMD_SCAN_CHAIN                    0x00
+#define AICE_CMD_SELECT_TARGET         0x01
+#define AICE_CMD_READ_DIM                      0x02
+#define AICE_CMD_READ_EDMSR                    0x03
+#define AICE_CMD_READ_DTR                      0x04
+#define AICE_CMD_READ_MEM                      0x05
+#define AICE_CMD_READ_MISC                     0x06
+#define AICE_CMD_FASTREAD_MEM          0x07
+#define AICE_CMD_WRITE_DIM                     0x08
+#define AICE_CMD_WRITE_EDMSR           0x09
+#define AICE_CMD_WRITE_DTR                     0x0A
+#define AICE_CMD_WRITE_MEM                     0x0B
+#define AICE_CMD_WRITE_MISC                    0x0C
+#define AICE_CMD_FASTWRITE_MEM         0x0D
+#define AICE_CMD_EXECUTE                       0x0E
+#define AICE_CMD_READ_MEM_B                    0x14
+#define AICE_CMD_READ_MEM_H                    0x15
+#define AICE_CMD_T_READ_MISC           0x20
+#define AICE_CMD_T_READ_EDMSR          0x21
+#define AICE_CMD_T_READ_DTR                    0x22
+#define AICE_CMD_T_READ_DIM                    0x23
+#define AICE_CMD_T_READ_MEM_B          0x24
+#define AICE_CMD_T_READ_MEM_H          0x25
+#define AICE_CMD_T_READ_MEM                    0x26
+#define AICE_CMD_T_FASTREAD_MEM                0x27
+#define AICE_CMD_T_WRITE_MISC          0x28
+#define AICE_CMD_T_WRITE_EDMSR         0x29
+#define AICE_CMD_T_WRITE_DTR           0x2A
+#define AICE_CMD_T_WRITE_DIM           0x2B
+#define AICE_CMD_T_WRITE_MEM_B         0x2C
+#define AICE_CMD_T_WRITE_MEM_H         0x2D
+#define AICE_CMD_T_WRITE_MEM           0x2E
+#define AICE_CMD_T_FASTWRITE_MEM       0x2F
+#define AICE_CMD_T_GET_TRACE_STATUS    0x36
+#define AICE_CMD_T_EXECUTE                     0x3E
+#define AICE_CMD_AICE_PROGRAM_READ     0x40
+#define AICE_CMD_AICE_PROGRAM_WRITE    0x41
+#define AICE_CMD_AICE_PROGRAM_CONTROL  0x42
+#define AICE_CMD_READ_CTRL                     0x50
+#define AICE_CMD_WRITE_CTRL                    0x51
+#define AICE_CMD_BATCH_BUFFER_READ     0x60
+#define AICE_CMD_READ_DTR_TO_BUFFER    0x61
+#define AICE_CMD_BATCH_BUFFER_WRITE    0x68
+#define AICE_CMD_WRITE_DTR_FROM_BUFFER 0x69
+
+/* Constants for AICE command format length */
+#define AICE_FORMAT_HTDA               3
+#define AICE_FORMAT_HTDB               6
+#define AICE_FORMAT_HTDC               7
+#define AICE_FORMAT_HTDD               10
+#define AICE_FORMAT_HTDMA              4
+#define AICE_FORMAT_HTDMB              8
+#define AICE_FORMAT_HTDMC              8
+#define AICE_FORMAT_HTDMD              12
+#define AICE_FORMAT_DTHA               6
+#define AICE_FORMAT_DTHB               2
+#define AICE_FORMAT_DTHMA              8
+#define AICE_FORMAT_DTHMB              4
+
+/* Constants for AICE command READ_CTRL */
+#define AICE_READ_CTRL_GET_ICE_STATE           0x00
+#define AICE_READ_CTRL_GET_HARDWARE_VERSION    0x01
+#define AICE_READ_CTRL_GET_FPGA_VERSION                0x02
+#define AICE_READ_CTRL_GET_FIRMWARE_VERSION    0x03
+#define AICE_READ_CTRL_GET_JTAG_PIN_STATUS     0x04
+
+/* Constants for AICE command WRITE_CTRL */
+#define AICE_WRITE_CTRL_TCK_CONTROL                            0x00
+#define AICE_WRITE_CTRL_JTAG_PIN_CONTROL               0x01
+#define AICE_WRITE_CTRL_CLEAR_TIMEOUT_STATUS   0x02
+#define AICE_WRITE_CTRL_RESERVED                               0x03
+#define AICE_WRITE_CTRL_JTAG_PIN_STATUS                        0x04
+#define AICE_WRITE_CTRL_CUSTOM_DELAY                   0x0d
+
+/* Constants for AICE command WRITE_CTRL:TCK_CONTROL */
+#define AICE_TCK_CONTROL_TCK3048               0x08
+
+/* Constants for AICE command WRITE_CTRL:JTAG_PIN_CONTROL */
+#define AICE_JTAG_PIN_CONTROL_SRST             0x01
+#define AICE_JTAG_PIN_CONTROL_TRST             0x02
+#define AICE_JTAG_PIN_CONTROL_STOP             0x04
+#define AICE_JTAG_PIN_CONTROL_RESTART  0x08
+
+/* Constants for AICE command WRITE_CTRL:TCK_CONTROL */
+#define AICE_TCK_CONTROL_TCK_SCAN              0x10
+
+/* Custom SRST/DBGI/TRST */
+#define AICE_CUSTOM_DELAY_SET_SRST             0x01
+#define AICE_CUSTOM_DELAY_CLEAN_SRST   0x02
+#define AICE_CUSTOM_DELAY_SET_DBGI             0x04
+#define AICE_CUSTOM_DELAY_CLEAN_DBGI   0x08
+#define AICE_CUSTOM_DELAY_SET_TRST             0x10
+#define AICE_CUSTOM_DELAY_CLEAN_TRST   0x20
+
+struct aice_usb_handler_s {
+       unsigned int usb_read_ep;
+       unsigned int usb_write_ep;
+       struct jtag_libusb_device_handle *usb_handle;
+};
+
+extern struct aice_port_api_s aice_usb_api;
+
+int aice_read_ctrl(uint32_t address, uint32_t *data);
+int aice_write_ctrl(uint32_t address, uint32_t data);
+
+#endif
index 2a8acdbd64e5b69c0f80c0f62ae99fb7134e0cec..8cf09a3c0ffccee12989f7ff53bea8e719db92d2 100644 (file)
@@ -116,6 +116,9 @@ extern struct jtag_interface opendous_interface;
 #if BUILD_SYSFSGPIO == 1
 extern struct jtag_interface sysfsgpio_interface;
 #endif
 #if BUILD_SYSFSGPIO == 1
 extern struct jtag_interface sysfsgpio_interface;
 #endif
+#if BUILD_AICE == 1
+extern struct jtag_interface aice_interface;
+#endif
 #endif /* standard drivers */
 
 /**
 #endif /* standard drivers */
 
 /**
@@ -200,6 +203,9 @@ struct jtag_interface *jtag_interfaces[] = {
 #if BUILD_SYSFSGPIO == 1
                &sysfsgpio_interface,
 #endif
 #if BUILD_SYSFSGPIO == 1
                &sysfsgpio_interface,
 #endif
+#if BUILD_AICE == 1
+               &aice_interface,
+#endif
 #endif /* standard drivers */
                NULL,
        };
 #endif /* standard drivers */
                NULL,
        };
index fac1e09105c69a21c701aa6e5946deb5d41470d8..8e9dfb6d21e38fadbe7760c3356a83ee3993ea54 100644 (file)
@@ -31,6 +31,7 @@ libtarget_la_SOURCES = \
        $(ARM_MISC_SRC) \
        $(AVR32_SRC) \
        $(MIPS32_SRC) \
        $(ARM_MISC_SRC) \
        $(AVR32_SRC) \
        $(MIPS32_SRC) \
+       $(NDS32_SRC) \
        avrt.c \
        dsp563xx.c \
        dsp563xx_once.c \
        avrt.c \
        dsp563xx.c \
        dsp563xx_once.c \
@@ -107,6 +108,9 @@ MIPS32_SRC = \
        mips32_dmaacc.c \
        mips_ejtag.c
 
        mips32_dmaacc.c \
        mips_ejtag.c
 
+NDS32_SRC = \
+       nds32_reg.c
+
 
 noinst_HEADERS = \
        algorithm.h \
 
 noinst_HEADERS = \
        algorithm.h \
@@ -162,7 +166,11 @@ noinst_HEADERS = \
        avr32_ap7k.h \
        avr32_jtag.h \
        avr32_mem.h \
        avr32_ap7k.h \
        avr32_jtag.h \
        avr32_mem.h \
-       avr32_regs.h
+       avr32_regs.h \
+       nds32.h \
+       nds32_edm.h \
+       nds32_insn.h \
+       nds32_reg.h
 
 ocddatadir = $(pkglibdir)
 nobase_dist_ocddata_DATA =
 
 ocddatadir = $(pkglibdir)
 nobase_dist_ocddata_DATA =
diff --git a/src/target/nds32.h b/src/target/nds32.h
new file mode 100644 (file)
index 0000000..cec8ae0
--- /dev/null
@@ -0,0 +1,432 @@
+/***************************************************************************
+ *   Copyright (C) 2013 by 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_H__
+#define __NDS32_H__
+
+#include <jtag/jtag.h>
+#include <jtag/aice/aice_port.h>
+#include "target.h"
+#include "target_type.h"
+#include "register.h"
+#include "breakpoints.h"
+#include "nds32_reg.h"
+#include "nds32_insn.h"
+#include "nds32_edm.h"
+
+#define CHECK_RETVAL(action)                   \
+       do {                                    \
+               int __retval = (action);        \
+               if (__retval != ERROR_OK) {     \
+                       LOG_DEBUG("error while calling \"%s\"", \
+                               # action);     \
+                       return __retval;        \
+               }                               \
+       } while (0)
+
+/**
+ * @file
+ * Holds the interface to Andes cores.
+ */
+
+extern const char *nds32_debug_type_name[11];
+
+enum nds32_debug_reason {
+       NDS32_DEBUG_BREAK = 0,
+       NDS32_DEBUG_BREAK_16,
+       NDS32_DEBUG_INST_BREAK,
+       NDS32_DEBUG_DATA_ADDR_WATCHPOINT_PRECISE,
+       NDS32_DEBUG_DATA_VALUE_WATCHPOINT_PRECISE,
+       NDS32_DEBUG_DATA_VALUE_WATCHPOINT_IMPRECISE,
+       NDS32_DEBUG_DEBUG_INTERRUPT,
+       NDS32_DEBUG_HARDWARE_SINGLE_STEP,
+       NDS32_DEBUG_DATA_ADDR_WATCHPOINT_NEXT_PRECISE,
+       NDS32_DEBUG_DATA_VALUE_WATCHPOINT_NEXT_PRECISE,
+       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_EXIT = 1,
+       NDS32_SYSCALL_OPEN = 2,
+       NDS32_SYSCALL_CLOSE = 3,
+       NDS32_SYSCALL_READ = 4,
+       NDS32_SYSCALL_WRITE = 5,
+       NDS32_SYSCALL_LSEEK = 6,
+       NDS32_SYSCALL_UNLINK = 7,
+       NDS32_SYSCALL_RENAME = 3001,
+       NDS32_SYSCALL_FSTAT = 10,
+       NDS32_SYSCALL_STAT = 15,
+       NDS32_SYSCALL_GETTIMEOFDAY = 19,
+       NDS32_SYSCALL_ISATTY = 3002,
+       NDS32_SYSCALL_SYSTEM = 3003,
+       NDS32_SYSCALL_ERRNO = 6001,
+};
+
+#define NDS32_COMMON_MAGIC (int)0xADE5ADE5
+
+struct nds32_edm {
+
+       /** EDM_CFG.VER, indicate the EDM version */
+       int version;
+
+       /** The number of hardware breakpoints */
+       int breakpoint_num;
+
+       /** EDM_CFG.DALM, indicate if direct local memory access feature is supported or not */
+       bool direct_access_local_memory;
+
+       /** Support ACC_CTL register */
+       bool access_control;
+
+       /** */
+       bool support_max_stop;
+};
+
+struct nds32_cache {
+
+       /** enable cache or not */
+       bool enable;
+
+       /** cache sets per way */
+       int set;
+
+       /** cache ways */
+       int way;
+
+       /** cache line size */
+       int line_size;
+
+       /** cache locking support */
+       bool lock_support;
+};
+
+struct nds32_memory {
+
+       /** ICache */
+       struct nds32_cache icache;
+
+       /** DCache */
+       struct nds32_cache dcache;
+
+       /** On-chip instruction local memory base */
+       int ilm_base;
+
+       /** On-chip instruction local memory size */
+       int ilm_size;
+
+       /** ILM base register alignment version */
+       int ilm_align_ver;
+
+       /** DLM is enabled or not */
+       bool ilm_enable;
+
+       /** DLM start address */
+       int ilm_start;
+
+       /** DLM end address */
+       int ilm_end;
+
+       /** On-chip data local memory base */
+       int dlm_base;
+
+       /** On-chip data local memory size */
+       int dlm_size;
+
+       /** DLM base register alignment version */
+       int dlm_align_ver;
+
+       /** DLM is enabled or not */
+       bool dlm_enable;
+
+       /** DLM start address */
+       int dlm_start;
+
+       /** DLM end address */
+       int dlm_end;
+
+       /** Memory access method */
+       enum aice_memory_access access_channel;
+
+       /** Memory access mode */
+       enum aice_memory_mode mode;
+
+       /** Address translation */
+       bool address_translation;
+};
+
+struct nds32_cpu_version {
+       bool performance_extension;
+       bool _16bit_extension;
+       bool performance_extension_2;
+       bool cop_fpu_extension;
+       bool string_extension;
+
+       int revision;
+       int cpu_id_family;
+       int cpu_id_version;
+};
+
+struct nds32_mmu_config {
+       int memory_protection;
+       int memory_protection_version;
+       bool fully_associative_tlb;
+       int tlb_size;
+       int tlb_ways;
+       int tlb_sets;
+       bool _8k_page_support;
+       int extra_page_size_support;
+       bool tlb_lock;
+       bool hardware_page_table_walker;
+       bool default_endian;
+       int partition_num;
+       bool invisible_tlb;
+       bool vlpt;
+       bool ntme;
+       bool drde;
+       int default_min_page_size;
+       bool multiple_page_size_in_use;
+};
+
+struct nds32_misc_config {
+       bool edm;
+       bool local_memory_dma;
+       bool performance_monitor;
+       bool high_speed_memory_port;
+       bool debug_tracer;
+       bool div_instruction;
+       bool mac_instruction;
+       int audio_isa;
+       bool L2_cache;
+       bool reduce_register;
+       bool addr_24;
+       bool interruption_level;
+       int baseline_instruction;
+       bool no_dx_register;
+       bool implement_dependant_register;
+       bool implement_dependant_sr_encoding;
+       bool ifc;
+       bool mcu;
+       bool ex9;
+       int shadow;
+};
+
+/**
+ * Represents a generic Andes core.
+ */
+struct nds32 {
+       int common_magic;
+       struct reg_cache *core_cache;
+
+       /** Handle for the debug module. */
+       struct nds32_edm edm;
+
+       /** Memory information */
+       struct nds32_memory memory;
+
+       /** cpu version */
+       struct nds32_cpu_version cpu_version;
+
+       /** MMU configuration */
+       struct nds32_mmu_config mmu_config;
+
+       /** Misc configuration */
+       struct nds32_misc_config misc_config;
+
+       /** Retrieve all core registers, for display. */
+       int (*full_context)(struct nds32 *nds32);
+
+       /** Register mappings */
+       int (*register_map)(struct nds32 *nds32, int reg_no);
+
+       /** Get debug exception virtual address */
+       int (*get_debug_reason)(struct nds32 *nds32, uint32_t *reason);
+
+       /** Restore target registers may be modified in debug state */
+       int (*leave_debug_state)(struct nds32 *nds32, bool enable_watchpoint);
+
+       /** Backup target registers may be modified in debug state */
+       int (*enter_debug_state)(struct nds32 *nds32, bool enable_watchpoint);
+
+       /** Get address hitted watchpoint */
+       int (*get_watched_address)(struct nds32 *nds32, uint32_t *address, uint32_t reason);
+
+       /** maximum interrupt level */
+       uint32_t max_interrupt_level;
+
+       /** current interrupt level */
+       uint32_t current_interrupt_level;
+
+       uint32_t watched_address;
+
+       /** 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;
+
+       /** reset-halt as target examine */
+       bool reset_halt_as_examine;
+
+       /** Period to wait after SRST. */
+       uint32_t boot_time;
+
+       /** Flag to indicate HSS steps into ISR or not */
+       bool step_isr_enable;
+
+       /** Flag to indicate register table is ready or not */
+       bool init_arch_info_after_halted;
+
+       /** Flag to indicate audio-extension is enabled or not */
+       bool audio_enable;
+
+       /** Flag to indicate fpu-extension is enabled or not */
+       bool fpu_enable;
+
+       /** 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;
+
+       void *arch_info;
+};
+
+struct nds32_reg {
+       uint32_t num;
+       uint32_t value;
+       uint64_t value_64;
+       struct target *target;
+       struct nds32 *nds32;
+       bool enable;
+};
+
+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);
+extern int nds32_remove_software_breakpoint(struct target *target,
+                                       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);
+
+extern int nds32_write_buffer(struct target *target, uint32_t address,
+                               uint32_t size, const uint8_t *buffer);
+extern int nds32_read_buffer(struct target *target, uint32_t address,
+                               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);
+extern int nds32_read_memory(struct target *target, uint32_t address,
+                               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);
+
+extern int nds32_init_register_table(struct nds32 *nds32);
+extern int nds32_init_memory_info(struct nds32 *nds32);
+extern int nds32_restore_context(struct target *target);
+extern int nds32_get_mapped_reg(struct nds32 *nds32, unsigned regnum, uint32_t *value);
+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_read_phys_memory(struct target *target, uint32_t address,
+                                       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);
+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);
+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);
+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);
+
+/** Convert target handle to generic Andes target state handle. */
+static inline struct nds32 *target_to_nds32(struct target *target)
+{
+       assert(target != NULL);
+       return target->arch_info;
+}
+
+/** */
+static inline struct aice_port_s *target_to_aice(struct target *target)
+{
+       assert(target != NULL);
+       return target->tap->priv;
+}
+
+static inline bool is_nds32(struct nds32 *nds32)
+{
+       assert(nds32 != NULL);
+       return nds32->common_magic == NDS32_COMMON_MAGIC;
+}
+
+static inline bool nds32_reach_max_interrupt_level(struct nds32 *nds32)
+{
+       assert(nds32 != NULL);
+       return nds32->max_interrupt_level == nds32->current_interrupt_level;
+}
+
+#endif /* __NDS32_H__ */
diff --git a/src/target/nds32_edm.h b/src/target/nds32_edm.h
new file mode 100644 (file)
index 0000000..3682b38
--- /dev/null
@@ -0,0 +1,116 @@
+/***************************************************************************
+ *   Copyright (C) 2013 by 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_EDM_H__
+#define __NDS32_EDM_H__
+
+/**
+ * @file
+ * This is the interface to the Embedded Debug Module for Andes cores.
+ */
+
+/* EDM misc registers */
+enum nds_edm_misc_reg {
+       NDS_EDM_MISC_DIMIR = 0x0,
+       NDS_EDM_MISC_SBAR,
+       NDS_EDM_MISC_EDM_CMDR,
+       NDS_EDM_MISC_DBGER,
+       NDS_EDM_MISC_ACC_CTL,
+       NDS_EDM_MISC_EDM_PROBE,
+       NDS_EDM_MISC_GEN_PORT0,
+       NDS_EDM_MISC_GEN_PORT1,
+};
+
+/* EDM system registers */
+enum nds_edm_system_reg {
+       NDS_EDM_SR_BPC0 = 0x00,
+       NDS_EDM_SR_BPC1,
+       NDS_EDM_SR_BPC2,
+       NDS_EDM_SR_BPC3,
+       NDS_EDM_SR_BPC4,
+       NDS_EDM_SR_BPC5,
+       NDS_EDM_SR_BPC6,
+       NDS_EDM_SR_BPC7,
+       NDS_EDM_SR_BPA0 = 0x08,
+       NDS_EDM_SR_BPA1,
+       NDS_EDM_SR_BPA2,
+       NDS_EDM_SR_BPA3,
+       NDS_EDM_SR_BPA4,
+       NDS_EDM_SR_BPA5,
+       NDS_EDM_SR_BPA6,
+       NDS_EDM_SR_BPA7,
+       NDS_EDM_SR_BPAM0 = 0x10,
+       NDS_EDM_SR_BPAM1,
+       NDS_EDM_SR_BPAM2,
+       NDS_EDM_SR_BPAM3,
+       NDS_EDM_SR_BPAM4,
+       NDS_EDM_SR_BPAM5,
+       NDS_EDM_SR_BPAM6,
+       NDS_EDM_SR_BPAM7,
+       NDS_EDM_SR_BPV0 = 0x18,
+       NDS_EDM_SR_BPV1,
+       NDS_EDM_SR_BPV2,
+       NDS_EDM_SR_BPV3,
+       NDS_EDM_SR_BPV4,
+       NDS_EDM_SR_BPV5,
+       NDS_EDM_SR_BPV6,
+       NDS_EDM_SR_BPV7,
+       NDS_EDM_SR_BPCID0 = 0x20,
+       NDS_EDM_SR_BPCID1,
+       NDS_EDM_SR_BPCID2,
+       NDS_EDM_SR_BPCID3,
+       NDS_EDM_SR_BPCID4,
+       NDS_EDM_SR_BPCID5,
+       NDS_EDM_SR_BPCID6,
+       NDS_EDM_SR_BPCID7,
+       NDS_EDM_SR_EDM_CFG = 0x28,
+       NDS_EDM_SR_EDMSW = 0x30,
+       NDS_EDM_SR_EDM_CTL = 0x38,
+       NDS_EDM_SR_EDM_DTR = 0x40,
+       NDS_EDM_SR_BPMTV = 0x48,
+       NDS_EDM_SR_DIMBR = 0x50,
+       NDS_EDM_SR_TECR0 = 0x70,
+       NDS_EDM_SR_TECR1 = 0x71,
+};
+
+enum nds_memory_access {
+       NDS_MEMORY_ACC_BUS = 0,
+       NDS_MEMORY_ACC_CPU,
+};
+
+enum nds_memory_select {
+       NDS_MEMORY_SELECT_AUTO = 0,
+       NDS_MEMORY_SELECT_MEM = 1,
+       NDS_MEMORY_SELECT_ILM = 2,
+       NDS_MEMORY_SELECT_DLM = 3,
+};
+
+#define NDS_DBGER_DEX          (0x1)
+#define NDS_DBGER_DPED         (0x2)
+#define NDS_DBGER_CRST         (0x4)
+#define NDS_DBGER_AT_MAX       (0x8)
+#define NDS_DBGER_ILL_SEC_ACC  (0x10)
+#define NDS_DBGER_ALL_SUPRS_EX (0x40000000)
+#define NDS_DBGER_RESACC       (0x80000000)
+#define NDS_DBGER_CLEAR_ALL    (0x1F)
+
+#define NDS_EDMSW_WDV          (1 << 0)
+#define NDS_EDMSW_RDV          (1 << 1)
+
+#endif /* __NDS32_EDM_H__ */
diff --git a/src/target/nds32_insn.h b/src/target/nds32_insn.h
new file mode 100644 (file)
index 0000000..ca0e4dd
--- /dev/null
@@ -0,0 +1,81 @@
+/***************************************************************************
+ *   Copyright (C) 2013 by 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_INSN_H__
+#define __NDS32_INSN_H__
+
+
+#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 ORI(a, b, c)                   (0x58000000 | ((a) << 20) | ((b) << 15) | (c))
+#define LWI_BI(a, b)                   (0x0C000001 | (a << 20) | (b << 15))
+#define LHI_BI(a, b)                   (0x0A000001 | (a << 20) | (b << 15))
+#define LBI_BI(a, b)                   (0x08000001 | (a << 20) | (b << 15))
+#define SWI_BI(a, b)                   (0x1C000001 | (a << 20) | (b << 15))
+#define SHI_BI(a, b)                   (0x1A000001 | (a << 20) | (b << 15))
+#define SBI_BI(a, b)                   (0x18000001 | (a << 20) | (b << 15))
+#define IRET                           (0x64000004)
+#define L1D_IX_WB(a)                   (0x64000021 | ((a) << 15))
+#define L1D_IX_INVAL(a)                        (0x64000001 | ((a) << 15))
+#define L1D_VA_INVAL(a)                        (0x64000101 | ((a) << 15))
+#define L1D_VA_WB(a)                   (0x64000121 | ((a) << 15))
+#define L1D_IX_RTAG(a)                 (0x64000061 | ((a) << 15))
+#define L1D_IX_RWD(a)                  (0x64000081 | ((a) << 15))
+#define L1I_IX_INVAL(a)                        (0x64000201 | ((a) << 15))
+#define L1I_VA_INVAL(a)                        (0x64000301 | ((a) << 15))
+#define L1I_IX_RTAG(a)                 (0x64000261 | ((a) << 15))
+#define L1I_IX_RWD(a)                  (0x64000281 | ((a) << 15))
+#define L1I_VA_FILLCK(a)               (0x64000361 | ((a) << 15))
+#define ISYNC(a)                       (0x6400000d | ((a) << 20))
+#define MSYNC_STORE                    (0x6400002c)
+#define MSYNC_ALL                      (0x6400000c)
+#define TLBOP_TARGET_READ(a)           (0x6400000e | ((a) << 15))
+#define TLBOP_TARGET_PROBE(a, b)               (0x640000AE | ((a) << 20) | ((b) << 15))
+#define 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 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 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))
+
+/* break instructions */
+extern const int NDS32_BREAK_16;
+extern const int NDS32_BREAK_32;
+
+
+#endif /* __NDS32_INSN_H__ */
diff --git a/src/target/nds32_reg.c b/src/target/nds32_reg.c
new file mode 100644 (file)
index 0000000..a55df79
--- /dev/null
@@ -0,0 +1,337 @@
+/***************************************************************************
+ *   Copyright (C) 2013 by 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_reg.h"
+
+static bool nds32_reg_init_done;
+static struct nds32_reg_s nds32_regs[TOTAL_REG_NUM];
+
+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)
+{
+       nds32_regs[number].simple_mnemonic = simple_mnemonic;
+       nds32_regs[number].symbolic_mnemonic = symbolic_mnemonic;
+       nds32_regs[number].sr_index = sr_index;
+       nds32_regs[number].type = type;
+       nds32_regs[number].size = size;
+}
+
+void nds32_reg_init(void)
+{
+       if (nds32_reg_init_done == true)
+               return;
+
+       nds32_reg_set(R0, "r0", "r0", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R1, "r1", "r1", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R2, "r2", "r2", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R3, "r3", "r3", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R4, "r4", "r4", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R5, "r5", "r5", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R6, "r6", "r6", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R7, "r7", "r7", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R8, "r8", "r8", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R9, "r9", "r9", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R10, "r10", "r10", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R11, "r11", "r11", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R12, "r12", "r12", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R13, "r13", "r13", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R14, "r14", "r14", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R15, "r15", "r15", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R16, "r16", "r16", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R17, "r17", "r17", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R18, "r18", "r18", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R19, "r19", "r19", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R20, "r20", "r20", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R21, "r21", "r21", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R22, "r22", "r22", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R23, "r23", "r23", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R24, "r24", "r24", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R25, "r25", "r25", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R26, "r26", "p0", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R27, "r27", "p1", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R28, "fp", "fp", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R29, "gp", "gp", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R30, "lp", "lp", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(R31, "sp", "sp", 0, NDS32_REG_TYPE_GPR, 32);
+       nds32_reg_set(PC, "pc", "pc", 31, NDS32_REG_TYPE_SPR, 32);
+
+       nds32_reg_set(D0LO, "d0lo", "d0lo", 0, NDS32_REG_TYPE_SPR, 32);
+       nds32_reg_set(D0HI, "d0hi", "d0hi", 1, NDS32_REG_TYPE_SPR, 32);
+       nds32_reg_set(D1LO, "d1lo", "d1lo", 2, NDS32_REG_TYPE_SPR, 32);
+       nds32_reg_set(D1HI, "d1hi", "d1hi", 3, NDS32_REG_TYPE_SPR, 32);
+       nds32_reg_set(ITB, "itb", "itb", 28, NDS32_REG_TYPE_SPR, 32);
+       nds32_reg_set(IFC_LP, "ifc_lp", "ifc_lp", 29, NDS32_REG_TYPE_SPR, 32);
+
+       nds32_reg_set(CR0, "cr0", "CPU_VER", SRIDX(0, 0, 0), NDS32_REG_TYPE_CR, 32);
+       nds32_reg_set(CR1, "cr1", "ICM_CFG", SRIDX(0, 1, 0), NDS32_REG_TYPE_CR, 32);
+       nds32_reg_set(CR2, "cr2", "DCM_CFG", SRIDX(0, 2, 0), NDS32_REG_TYPE_CR, 32);
+       nds32_reg_set(CR3, "cr3", "MMU_CFG", SRIDX(0, 3, 0), NDS32_REG_TYPE_CR, 32);
+       nds32_reg_set(CR4, "cr4", "MSC_CFG", SRIDX(0, 4, 0), NDS32_REG_TYPE_CR, 32);
+       nds32_reg_set(CR5, "cr5", "CORE_ID", SRIDX(0, 0, 1), NDS32_REG_TYPE_CR, 32);
+       nds32_reg_set(CR6, "cr6", "FUCOP_EXIST", SRIDX(0, 5, 0), NDS32_REG_TYPE_CR, 32);
+
+       nds32_reg_set(IR0, "ir0", "PSW", SRIDX(1, 0, 0), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR1, "ir1", "IPSW", SRIDX(1, 0, 1), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR2, "ir2", "P_IPSW", SRIDX(1, 0, 2), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR3, "ir3", "IVB", SRIDX(1, 1, 1), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR4, "ir4", "EVA", SRIDX(1, 2, 1), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR5, "ir5", "P_EVA", SRIDX(1, 2, 2), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR6, "ir6", "ITYPE", SRIDX(1, 3, 1), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR7, "ir7", "P_ITYPE", SRIDX(1, 3, 2), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR8, "ir8", "MERR", SRIDX(1, 4, 1), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR9, "ir9", "IPC", SRIDX(1, 5, 1), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR10, "ir10", "P_IPC", SRIDX(1, 5, 2), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR11, "ir11", "OIPC", SRIDX(1, 5, 3), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR12, "ir12", "P_P0", SRIDX(1, 6, 2), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR13, "ir13", "P_P1", SRIDX(1, 7, 2), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR14, "ir14", "INT_MASK", SRIDX(1, 8, 0), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR15, "ir15", "INT_PEND", SRIDX(1, 9, 0), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR16, "ir16", "", SRIDX(1, 10, 0), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR17, "ir17", "", SRIDX(1, 10, 1), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR18, "ir18", "", SRIDX(1, 11, 0), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR19, "ir19", "", SRIDX(1, 1, 2), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR20, "ir20", "", SRIDX(1, 10, 2), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR21, "ir21", "", SRIDX(1, 10, 3), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR22, "ir22", "", SRIDX(1, 10, 4), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR23, "ir23", "", SRIDX(1, 10, 5), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR24, "ir24", "", SRIDX(1, 10, 6), NDS32_REG_TYPE_IR, 32);
+       nds32_reg_set(IR25, "ir25", "", SRIDX(1, 10, 7), NDS32_REG_TYPE_IR, 32);
+
+       nds32_reg_set(MR0, "mr0", "MMU_CTL", SRIDX(2, 0, 0), NDS32_REG_TYPE_MR, 32);
+       nds32_reg_set(MR1, "mr1", "L1_PPTB", SRIDX(2, 1, 0), NDS32_REG_TYPE_MR, 32);
+       nds32_reg_set(MR2, "mr2", "TLB_VPN", SRIDX(2, 2, 0), NDS32_REG_TYPE_MR, 32);
+       nds32_reg_set(MR3, "mr3", "TLB_DATA", SRIDX(2, 3, 0), NDS32_REG_TYPE_MR, 32);
+       nds32_reg_set(MR4, "mr4", "TLB_MISC", SRIDX(2, 4, 0), NDS32_REG_TYPE_MR, 32);
+       nds32_reg_set(MR5, "mr5", "VLPT_IDX", SRIDX(2, 5, 0), NDS32_REG_TYPE_MR, 32);
+       nds32_reg_set(MR6, "mr6", "ILMB", SRIDX(2, 6, 0), NDS32_REG_TYPE_MR, 32);
+       nds32_reg_set(MR7, "mr7", "DLMB", SRIDX(2, 7, 0), NDS32_REG_TYPE_MR, 32);
+       nds32_reg_set(MR8, "mr8", "CACHE_CTL", SRIDX(2, 8, 0), NDS32_REG_TYPE_MR, 32);
+       nds32_reg_set(MR9, "mr9", "HSMP_SADDR", SRIDX(2, 9, 0), NDS32_REG_TYPE_MR, 32);
+       nds32_reg_set(MR10, "mr10", "HSMP_EADDR", SRIDX(2, 9, 1), NDS32_REG_TYPE_MR, 32);
+       nds32_reg_set(MR11, "mr11", "", SRIDX(2, 0, 1), NDS32_REG_TYPE_MR, 32);
+
+       nds32_reg_set(DR0, "dr0", "BPC0", SRIDX(3, 0, 0), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR1, "dr1", "BPA0", SRIDX(3, 1, 0), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR2, "dr2", "BPAM0", SRIDX(3, 2, 0), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR3, "dr3", "BPV0", SRIDX(3, 3, 0), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR4, "dr4", "BPCID0", SRIDX(3, 4, 0), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR5, "dr5", "BPC1", SRIDX(3, 0, 1), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR6, "dr6", "BPA1", SRIDX(3, 1, 1), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR7, "dr7", "BPAM1", SRIDX(3, 2, 1), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR8, "dr8", "BPV1", SRIDX(3, 3, 1), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR9, "dr9", "BPCID1", SRIDX(3, 4, 1), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR10, "dr10", "BPC2", SRIDX(3, 0, 2), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR11, "dr11", "BPA2", SRIDX(3, 1, 2), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR12, "dr12", "BPAM2", SRIDX(3, 2, 2), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR13, "dr13", "BPV2", SRIDX(3, 3, 2), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR14, "dr14", "BPCID2", SRIDX(3, 4, 2), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR15, "dr15", "BPC3", SRIDX(3, 0, 3), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR16, "dr16", "BPA3", SRIDX(3, 1, 3), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR17, "dr17", "BPAM3", SRIDX(3, 2, 3), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR18, "dr18", "BPV3", SRIDX(3, 3, 3), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR19, "dr19", "BPCID3", SRIDX(3, 4, 3), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR20, "dr20", "BPC4", SRIDX(3, 0, 4), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR21, "dr21", "BPA4", SRIDX(3, 1, 4), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR22, "dr22", "BPAM4", SRIDX(3, 2, 4), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR23, "dr23", "BPV4", SRIDX(3, 3, 4), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR24, "dr24", "BPCID4", SRIDX(3, 4, 4), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR25, "dr25", "BPC5", SRIDX(3, 0, 5), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR26, "dr26", "BPA5", SRIDX(3, 1, 5), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR27, "dr27", "BPAM5", SRIDX(3, 2, 5), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR28, "dr28", "BPV5", SRIDX(3, 3, 5), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR29, "dr29", "BPCID5", SRIDX(3, 4, 5), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR30, "dr30", "BPC6", SRIDX(3, 0, 6), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR31, "dr31", "BPA6", SRIDX(3, 1, 6), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR32, "dr32", "BPAM6", SRIDX(3, 2, 6), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR33, "dr33", "BPV6", SRIDX(3, 3, 6), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR34, "dr34", "BPCID6", SRIDX(3, 4, 6), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR35, "dr35", "BPC7", SRIDX(3, 0, 7), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR36, "dr36", "BPA7", SRIDX(3, 1, 7), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR37, "dr37", "BPAM7", SRIDX(3, 2, 7), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR38, "dr38", "BPV7", SRIDX(3, 3, 7), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR39, "dr39", "BPCID7", SRIDX(3, 4, 7), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR40, "dr40", "EDM_CFG", SRIDX(3, 5, 0), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR41, "dr41", "EDMSW", SRIDX(3, 6, 0), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR42, "dr42", "EDM_CTL", SRIDX(3, 7, 0), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR43, "dr43", "EDM_DTR", SRIDX(3, 8, 0), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR44, "dr44", "BPMTC", SRIDX(3, 9, 0), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR45, "dr45", "DIMBR", SRIDX(3, 10, 0), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR46, "dr46", "TECR0", SRIDX(3, 14, 0), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR47, "dr47", "TECR1", SRIDX(3, 14, 1), NDS32_REG_TYPE_DR, 32);
+       nds32_reg_set(DR48, "dr48", "", SRIDX(3, 11, 0), NDS32_REG_TYPE_DR, 32);
+
+       nds32_reg_set(PFR0, "pfr0", "PFMC0", SRIDX(4, 0, 0), NDS32_REG_TYPE_PFR, 32);
+       nds32_reg_set(PFR1, "pfr1", "PFMC1", SRIDX(4, 0, 1), NDS32_REG_TYPE_PFR, 32);
+       nds32_reg_set(PFR2, "pfr2", "PFMC2", SRIDX(4, 0, 2), NDS32_REG_TYPE_PFR, 32);
+       nds32_reg_set(PFR3, "pfr3", "PFM_CTL", SRIDX(4, 1, 0), NDS32_REG_TYPE_PFR, 32);
+
+       nds32_reg_set(DMAR0, "dmar0", "DMA_CFG", SRIDX(5, 0, 0), NDS32_REG_TYPE_DMAR, 32);
+       nds32_reg_set(DMAR1, "dmar1", "DMA_GCSW", SRIDX(5, 1, 0), NDS32_REG_TYPE_DMAR, 32);
+       nds32_reg_set(DMAR2, "dmar2", "DMA_CHNSEL", SRIDX(5, 2, 0), NDS32_REG_TYPE_DMAR, 32);
+       nds32_reg_set(DMAR3, "dmar3", "DMA_ACT", SRIDX(5, 3, 0), NDS32_REG_TYPE_DMAR, 32);
+       nds32_reg_set(DMAR4, "dmar4", "DMA_SETUP", SRIDX(5, 4, 0), NDS32_REG_TYPE_DMAR, 32);
+       nds32_reg_set(DMAR5, "dmar5", "DMA_ISADDR", SRIDX(5, 5, 0), NDS32_REG_TYPE_DMAR, 32);
+       nds32_reg_set(DMAR6, "dmar6", "DMA_ESADDR", SRIDX(5, 6, 0), NDS32_REG_TYPE_DMAR, 32);
+       nds32_reg_set(DMAR7, "dmar7", "DMA_TCNT", SRIDX(5, 7, 0), NDS32_REG_TYPE_DMAR, 32);
+       nds32_reg_set(DMAR8, "dmar8", "DMA_STATUS", SRIDX(5, 8, 0), NDS32_REG_TYPE_DMAR, 32);
+       nds32_reg_set(DMAR9, "dmar9", "DMA_2DSET", SRIDX(5, 9, 0), NDS32_REG_TYPE_DMAR, 32);
+       nds32_reg_set(DMAR10, "dmar10", "DMA_2DSCTL", SRIDX(5, 9, 1), NDS32_REG_TYPE_DMAR, 32);
+
+       nds32_reg_set(RACR, "racr", "PRUSR_ACC_CTL", SRIDX(4, 4, 0), NDS32_REG_TYPE_RACR, 32);
+       nds32_reg_set(FUCPR, "fucpr", "FUCOP_CTL", SRIDX(4, 5, 0), NDS32_REG_TYPE_RACR, 32);
+
+       nds32_reg_set(IDR0, "idr0", "SDZ_CTL", SRIDX(2, 15, 0), NDS32_REG_TYPE_IDR, 32);
+       nds32_reg_set(IDR1, "idr1", "MISC_CTL", SRIDX(2, 15, 1), NDS32_REG_TYPE_IDR, 32);
+
+       nds32_reg_set(SECUR0, "secur0", "", SRIDX(6, 0, 0), NDS32_REG_TYPE_SECURE, 32);
+
+       nds32_reg_set(D0L24, "D0L24", "D0L24", 0x10, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(D1L24, "D1L24", "D1L24", 0x11, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(I0, "I0", "I0", 0x0, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(I1, "I1", "I1", 0x1, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(I2, "I2", "I2", 0x2, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(I3, "I3", "I3", 0x3, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(I4, "I4", "I4", 0x4, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(I5, "I5", "I5", 0x5, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(I6, "I6", "I6", 0x6, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(I7, "I7", "I7", 0x7, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(M1, "M1", "M1", 0x9, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(M2, "M2", "M2", 0xA, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(M3, "M3", "M3", 0xB, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(M5, "M5", "M5", 0xD, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(M6, "M6", "M6", 0xE, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(M7, "M7", "M7", 0xF, NDS32_REG_TYPE_AUMR, 32);
+
+       nds32_reg_set(MOD, "MOD", "MOD", 0x8, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(LBE, "LBE", "LBE", 0x18, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(LE, "LE", "LE", 0x19, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(LC, "LC", "LC", 0x1A, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(ADM_VBASE, "ADM_VBASE", "ADM_VBASE", 0x1B, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(SHFT_CTL0, "SHFT_CTL0", "SHFT_CTL0", 0x12, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(SHFT_CTL1, "SHFT_CTL1", "SHFT_CTL1", 0x13, NDS32_REG_TYPE_AUMR, 32);
+
+       nds32_reg_set(CB_CTL, "CB_CTL", "CB_CTL", 0x1F, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(CBB0, "CBB0", "CBB0", 0x0, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(CBB1, "CBB1", "CBB1", 0x1, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(CBB2, "CBB2", "CBB2", 0x2, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(CBB3, "CBB3", "CBB3", 0x3, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(CBE0, "CBE0", "CBE0", 0x4, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(CBE1, "CBE1", "CBE1", 0x5, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(CBE2, "CBE2", "CBE2", 0x6, NDS32_REG_TYPE_AUMR, 32);
+       nds32_reg_set(CBE3, "CBE3", "CBE3", 0x7, NDS32_REG_TYPE_AUMR, 32);
+
+       nds32_reg_set(FPCSR, "fpcsr", "FPCSR", 0x7, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FPCFG, "fpcfg", "FPCFG", 0x7, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS0, "fs0", "FS0", 0, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS1, "fs1", "FS1", 1, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS2, "fs2", "FS2", 2, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS3, "fs3", "FS3", 3, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS4, "fs4", "FS4", 4, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS5, "fs5", "FS5", 5, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS6, "fs6", "FS6", 6, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS7, "fs7", "FS7", 7, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS8, "fs8", "FS8", 8, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS9, "fs9", "FS9", 9, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS10, "fs10", "FS10", 10, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS11, "fs11", "FS11", 11, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS12, "fs12", "FS12", 12, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS13, "fs13", "FS13", 13, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS14, "fs14", "FS14", 14, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS15, "fs15", "FS15", 15, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS16, "fs16", "FS16", 16, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS17, "fs17", "FS17", 17, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS18, "fs18", "FS18", 18, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS19, "fs19", "FS19", 19, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS20, "fs20", "FS20", 20, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS21, "fs21", "FS21", 21, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS22, "fs22", "FS22", 22, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS23, "fs23", "FS23", 23, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS24, "fs24", "FS24", 24, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS25, "fs25", "FS25", 25, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS26, "fs26", "FS26", 26, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS27, "fs27", "FS27", 27, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS28, "fs28", "FS28", 28, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS29, "fs29", "FS29", 29, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS30, "fs30", "FS30", 30, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FS31, "fs31", "FS31", 31, NDS32_REG_TYPE_FPU, 32);
+       nds32_reg_set(FD0, "fd0", "FD0", 0, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD1, "fd1", "FD1", 1, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD2, "fd2", "FD2", 2, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD3, "fd3", "FD3", 3, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD4, "fd4", "FD4", 4, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD5, "fd5", "FD5", 5, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD6, "fd6", "FD6", 6, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD7, "fd7", "FD7", 7, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD8, "fd8", "FD8", 8, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD9, "fd9", "FD9", 9, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD10, "fd10", "FD10", 10, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD11, "fd11", "FD11", 11, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD12, "fd12", "FD12", 12, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD13, "fd13", "FD13", 13, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD14, "fd14", "FD14", 14, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD15, "fd15", "FD15", 15, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD16, "fd16", "FD16", 16, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD17, "fd17", "FD17", 17, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD18, "fd18", "FD18", 18, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD19, "fd19", "FD19", 19, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD20, "fd20", "FD20", 20, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD21, "fd21", "FD21", 21, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD22, "fd22", "FD22", 22, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD23, "fd23", "FD23", 23, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD24, "fd24", "FD24", 24, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD25, "fd25", "FD25", 25, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD26, "fd26", "FD26", 26, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD27, "fd27", "FD27", 27, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD28, "fd28", "FD28", 28, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD29, "fd29", "FD29", 29, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD30, "fd30", "FD30", 30, NDS32_REG_TYPE_FPU, 64);
+       nds32_reg_set(FD31, "fd31", "FD31", 31, NDS32_REG_TYPE_FPU, 64);
+
+       nds32_reg_init_done = true;
+}
+
+uint32_t nds32_reg_sr_index(uint32_t number)
+{
+       return nds32_regs[number].sr_index;
+}
+
+enum nds32_reg_type_s nds32_reg_type(uint32_t number)
+{
+       return nds32_regs[number].type;
+}
+
+uint8_t nds32_reg_size(uint32_t number)
+{
+       return nds32_regs[number].size;
+}
+
+const char *nds32_reg_simple_name(uint32_t number)
+{
+       return nds32_regs[number].simple_mnemonic;
+}
+
+const char *nds32_reg_symbolic_name(uint32_t number)
+{
+       return nds32_regs[number].symbolic_mnemonic;
+}
diff --git a/src/target/nds32_reg.h b/src/target/nds32_reg.h
new file mode 100644 (file)
index 0000000..a941941
--- /dev/null
@@ -0,0 +1,320 @@
+/***************************************************************************
+ *   Copyright (C) 2013 by 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_REG_H__
+#define __NDS32_REG_H__
+
+#define SRIDX(a, b, c)                 ((a << 7) | (b << 3) | c)
+#define NDS32_REGISTER_DISABLE         (0x0)
+
+enum nds32_reg_number_s {
+       /* general registers */
+       R0 = 0,
+       R1,
+       R2,
+       R3,
+       R4,
+       R5,
+       R6,
+       R7,
+       R8,
+       R9,
+       R10,
+       R11,
+       R12,
+       R13,
+       R14,
+       R15,
+       R16,
+       R17,
+       R18,
+       R19,
+       R20,
+       R21,
+       R22,
+       R23,
+       R24,
+       R25,
+       R26,
+       R27,
+       R28,
+       R29,
+       R30,
+       R31,
+       PC,
+       D0LO,
+       D0HI,
+       D1LO,
+       D1HI,
+       ITB,
+       IFC_LP,
+
+       /* system registers */
+       CR0,
+       CR1,
+       CR2,
+       CR3,
+       CR4,
+       CR5,
+       CR6,
+       IR0,
+       IR1,
+       IR2,
+       IR3,
+       IR4,
+       IR5,
+       IR6,
+       IR7,
+       IR8,
+       IR9,
+       IR10,
+       IR11,
+       IR12,
+       IR13,
+       IR14,
+       IR15,
+       IR16,
+       IR17,
+       IR18,
+       IR19,
+       IR20,
+       IR21,
+       IR22,
+       IR23,
+       IR24,
+       IR25,
+       MR0,
+       MR1,
+       MR2,
+       MR3,
+       MR4,
+       MR5,
+       MR6,
+       MR7,
+       MR8,
+       MR9,
+       MR10,
+       MR11,
+       DR0,
+       DR1,
+       DR2,
+       DR3,
+       DR4,
+       DR5,
+       DR6,
+       DR7,
+       DR8,
+       DR9,
+       DR10,
+       DR11,
+       DR12,
+       DR13,
+       DR14,
+       DR15,
+       DR16,
+       DR17,
+       DR18,
+       DR19,
+       DR20,
+       DR21,
+       DR22,
+       DR23,
+       DR24,
+       DR25,
+       DR26,
+       DR27,
+       DR28,
+       DR29,
+       DR30,
+       DR31,
+       DR32,
+       DR33,
+       DR34,
+       DR35,
+       DR36,
+       DR37,
+       DR38,
+       DR39,
+       DR40,
+       DR41,
+       DR42,
+       DR43,
+       DR44,
+       DR45,
+       DR46,
+       DR47,
+       DR48,
+       PFR0,
+       PFR1,
+       PFR2,
+       PFR3,
+       DMAR0,
+       DMAR1,
+       DMAR2,
+       DMAR3,
+       DMAR4,
+       DMAR5,
+       DMAR6,
+       DMAR7,
+       DMAR8,
+       DMAR9,
+       DMAR10,
+       RACR,
+       FUCPR,
+       IDR0,
+       IDR1,
+       SECUR0,
+
+       /* audio registers */
+       D0L24,
+       D1L24,
+       I0,
+       I1,
+       I2,
+       I3,
+       I4,
+       I5,
+       I6,
+       I7,
+       M1,
+       M2,
+       M3,
+       M5,
+       M6,
+       M7,
+       MOD,
+       LBE,
+       LE,
+       LC,
+       ADM_VBASE,
+       SHFT_CTL0,
+       SHFT_CTL1,
+       CB_CTL,
+       CBB0,
+       CBB1,
+       CBB2,
+       CBB3,
+       CBE0,
+       CBE1,
+       CBE2,
+       CBE3,
+
+       /* fpu */
+       FPCSR,
+       FPCFG,
+       FS0,
+       FS1,
+       FS2,
+       FS3,
+       FS4,
+       FS5,
+       FS6,
+       FS7,
+       FS8,
+       FS9,
+       FS10,
+       FS11,
+       FS12,
+       FS13,
+       FS14,
+       FS15,
+       FS16,
+       FS17,
+       FS18,
+       FS19,
+       FS20,
+       FS21,
+       FS22,
+       FS23,
+       FS24,
+       FS25,
+       FS26,
+       FS27,
+       FS28,
+       FS29,
+       FS30,
+       FS31,
+       FD0,
+       FD1,
+       FD2,
+       FD3,
+       FD4,
+       FD5,
+       FD6,
+       FD7,
+       FD8,
+       FD9,
+       FD10,
+       FD11,
+       FD12,
+       FD13,
+       FD14,
+       FD15,
+       FD16,
+       FD17,
+       FD18,
+       FD19,
+       FD20,
+       FD21,
+       FD22,
+       FD23,
+       FD24,
+       FD25,
+       FD26,
+       FD27,
+       FD28,
+       FD29,
+       FD30,
+       FD31,
+
+       TOTAL_REG_NUM,
+};
+
+enum nds32_reg_type_s {
+       NDS32_REG_TYPE_GPR = 0,
+       NDS32_REG_TYPE_SPR,
+       NDS32_REG_TYPE_CR,
+       NDS32_REG_TYPE_IR,
+       NDS32_REG_TYPE_MR,
+       NDS32_REG_TYPE_DR,
+       NDS32_REG_TYPE_PFR,
+       NDS32_REG_TYPE_DMAR,
+       NDS32_REG_TYPE_RACR,
+       NDS32_REG_TYPE_IDR,
+       NDS32_REG_TYPE_AUMR,
+       NDS32_REG_TYPE_SECURE,
+       NDS32_REG_TYPE_FPU,
+};
+
+struct nds32_reg_s {
+       const char *simple_mnemonic;
+       const char *symbolic_mnemonic;
+       uint32_t sr_index;
+       enum nds32_reg_type_s type;
+       uint8_t size;
+};
+
+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);
+
+#endif
diff --git a/tcl/interface/nds32-aice.cfg b/tcl/interface/nds32-aice.cfg
new file mode 100644 (file)
index 0000000..5363b4c
--- /dev/null
@@ -0,0 +1,15 @@
+#
+# Andes AICE
+#
+# http://www.andestech.com
+#
+
+interface aice
+aice desc "Andes AICE adapter"
+aice serial "C001-42163"
+aice vid_pid 0x1CFC 0x0000
+aice port aice_usb
+reset_config trst_and_srst
+adapter_khz 24000
+aice retry_times 50
+aice count_to_check_dbger 30

Linking to existing account procedure

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

SSH host keys fingerprints

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