use COMMAND_HANDLER macro to define all commands
[fw/openocd] / src / svf / svf.c
index baa00885e72e37a2fc22e7a8752335efb2406f5b..76b067047e7fb2afbfc88ac5e45dee6372f16c8b 100644 (file)
@@ -1,22 +1,21 @@
-/***************************************************************************
- *      Copyright (C) 2009 by Simon Qian                                                                          *
- *      SimonQian@SimonQian.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.,                                                                           *
- *      59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.                         *
- ***************************************************************************/
+/*
+ * Copyright (C) 2009 by Simon Qian
+ * SimonQian@SimonQian.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.,
+ * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
 
 
 /* The specification for SVF is available here:
 #include "config.h"
 #endif
 
-#include "svf.h"
-
 #include "jtag.h"
-#include "command.h"
-#include "log.h"
-
-#include <ctype.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <string.h>
+#include "svf.h"
+#include "time_support.h"
 
-#include <sys/time.h>
-#include <time.h>
 
 // SVF command
 typedef enum
@@ -68,7 +55,7 @@ typedef enum
        TRST,
 }svf_command_t;
 
-const char *svf_command_name[14] = 
+static const char *svf_command_name[14] =
 {
        "ENDDR",
        "ENDIR",
@@ -94,7 +81,7 @@ typedef enum
        TRST_ABSENT
 }trst_mode_t;
 
-const char *svf_trst_mode_name[4] =
+static const char *svf_trst_mode_name[4] =
 {
        "ON",
        "OFF",
@@ -102,7 +89,53 @@ const char *svf_trst_mode_name[4] =
        "ABSENT"
 };
 
-char *svf_tap_state_name[16];
+typedef struct
+{
+       tap_state_t from;
+       tap_state_t to;
+       uint32_t num_of_moves;
+       tap_state_t paths[8];
+}svf_statemove_t;
+
+/*
+ * These paths are from the SVF specification for the STATE command, to be
+ * used when the STATE command only includes the final state.  The first
+ * element of the path is the "from" (current) state, and the last one is
+ * the "to" (target) state.
+ *
+ * All specified paths are the shortest ones in the JTAG spec, and are thus
+ * not (!!) exact matches for the paths used elsewhere in OpenOCD.  Note
+ * that PAUSE-to-PAUSE transitions all go through UPDATE and then CAPTURE,
+ * which has specific effects on the various registers; they are not NOPs.
+ *
+ * Paths to RESET are disabled here.  As elsewhere in OpenOCD, and in XSVF
+ * and many SVF implementations, we don't want to risk missing that state.
+ * To get to RESET, always we ignore the current state.
+ */
+static const svf_statemove_t svf_statemoves[] =
+{
+       // from                 to                              num_of_moves,   paths[8]
+//     {TAP_RESET,             TAP_RESET,              1,                              {TAP_RESET}},
+       {TAP_RESET,             TAP_IDLE,               2,                              {TAP_RESET, TAP_IDLE}},
+       {TAP_RESET,             TAP_DRPAUSE,    6,                              {TAP_RESET, TAP_IDLE, TAP_DRSELECT, TAP_DRCAPTURE, TAP_DREXIT1, TAP_DRPAUSE}},
+       {TAP_RESET,             TAP_IRPAUSE,    7,                              {TAP_RESET, TAP_IDLE, TAP_DRSELECT, TAP_IRSELECT, TAP_IRCAPTURE, TAP_IREXIT1, TAP_IRPAUSE}},
+
+//     {TAP_IDLE,              TAP_RESET,              4,                              {TAP_IDLE, TAP_DRSELECT, TAP_IRSELECT, TAP_RESET}},
+       {TAP_IDLE,              TAP_IDLE,               1,                              {TAP_IDLE}},
+       {TAP_IDLE,              TAP_DRPAUSE,    5,                              {TAP_IDLE, TAP_DRSELECT, TAP_DRCAPTURE, TAP_DREXIT1, TAP_DRPAUSE}},
+       {TAP_IDLE,              TAP_IRPAUSE,    6,                              {TAP_IDLE, TAP_DRSELECT, TAP_IRSELECT, TAP_IRCAPTURE, TAP_IREXIT1, TAP_IRPAUSE}},
+
+//     {TAP_DRPAUSE,   TAP_RESET,              6,                              {TAP_DRPAUSE, TAP_DREXIT2, TAP_DRUPDATE, TAP_DRSELECT, TAP_IRSELECT, TAP_RESET}},
+       {TAP_DRPAUSE,   TAP_IDLE,               4,                              {TAP_DRPAUSE, TAP_DREXIT2, TAP_DRUPDATE, TAP_IDLE}},
+       {TAP_DRPAUSE,   TAP_DRPAUSE,    7,                              {TAP_DRPAUSE, TAP_DREXIT2, TAP_DRUPDATE, TAP_DRSELECT, TAP_DRCAPTURE, TAP_DREXIT1, TAP_DRPAUSE}},
+       {TAP_DRPAUSE,   TAP_IRPAUSE,    8,                              {TAP_DRPAUSE, TAP_DREXIT2, TAP_DRUPDATE, TAP_DRSELECT, TAP_IRSELECT, TAP_IRCAPTURE, TAP_IREXIT1, TAP_IRPAUSE}},
+
+//     {TAP_IRPAUSE,   TAP_RESET,              6,                              {TAP_IRPAUSE, TAP_IREXIT2, TAP_IRUPDATE, TAP_DRSELECT, TAP_IRSELECT, TAP_RESET}},
+       {TAP_IRPAUSE,   TAP_IDLE,               4,                              {TAP_IRPAUSE, TAP_IREXIT2, TAP_IRUPDATE, TAP_IDLE}},
+       {TAP_IRPAUSE,   TAP_DRPAUSE,    7,                              {TAP_IRPAUSE, TAP_IREXIT2, TAP_IRUPDATE, TAP_DRSELECT, TAP_DRCAPTURE, TAP_DREXIT1, TAP_DRPAUSE}},
+       {TAP_IRPAUSE,   TAP_IRPAUSE,    8,                              {TAP_IRPAUSE, TAP_IREXIT2, TAP_IRUPDATE, TAP_DRSELECT, TAP_IRSELECT, TAP_IRCAPTURE, TAP_IREXIT1, TAP_IRPAUSE}}
+};
+
 
 #define XXR_TDI                                                (1 << 0)
 #define XXR_TDO                                                (1 << 1)
@@ -112,10 +145,10 @@ typedef struct
 {
        int len;
        int data_mask;
-       u8 *tdi;
-       u8 *tdo;
-       u8 *mask;
-       u8 *smask;
+       uint8_t *tdi;
+       uint8_t *tdo;
+       uint8_t *mask;
+       uint8_t *smask;
 }svf_xxr_para_t;
 
 typedef struct
@@ -135,8 +168,8 @@ typedef struct
        svf_xxr_para_t sdr_para;
 }svf_para_t;
 
-svf_para_t svf_para;
-const svf_para_t svf_para_init = 
+static svf_para_t svf_para;
+static const svf_para_t svf_para_init =
 {
 //     frequency,      ir_end_state,   dr_end_state,   runtest_run_state,      runtest_end_state,      trst_mode
        0,                      TAP_IDLE,               TAP_IDLE,               TAP_IDLE,                       TAP_IDLE,                       TRST_Z,
@@ -173,13 +206,10 @@ typedef struct
 static svf_check_tdo_para_t *svf_check_tdo_para = NULL;
 static int svf_check_tdo_para_index = 0;
 
-#define dimof(a)                                       (sizeof(a) / sizeof((a)[0]))
-
 static int svf_read_command_from_file(int fd);
 static int svf_check_tdo(void);
-static int svf_add_check_para(u8 enabled, int buffer_offset, int bit_len);
+static int svf_add_check_para(uint8_t enabled, int buffer_offset, int bit_len);
 static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str);
-static int handle_svf_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 
 static int svf_fd = 0;
 static char *svf_command_buffer = NULL;
@@ -189,19 +219,12 @@ static int svf_line_number = 1;
 static jtag_tap_t *tap = NULL;
 
 #define SVF_MAX_BUFFER_SIZE_TO_COMMIT  (4 * 1024)
-static u8 *svf_tdi_buffer = NULL, *svf_tdo_buffer = NULL, *svf_mask_buffer = NULL;
+static uint8_t *svf_tdi_buffer = NULL, *svf_tdo_buffer = NULL, *svf_mask_buffer = NULL;
 static int svf_buffer_index = 0, svf_buffer_size = 0;
+static int svf_quiet = 0;
 
 
-int svf_register_commands(struct command_context_s *cmd_ctx)
-{
-       register_command(cmd_ctx, NULL, "svf", handle_svf_command,
-               COMMAND_EXEC, "run svf <file>");
-
-       return ERROR_OK;
-}
-
-void svf_free_xxd_para(svf_xxr_para_t *para)
+static void svf_free_xxd_para(svf_xxr_para_t *para)
 {
        if (NULL != para)
        {
@@ -228,25 +251,99 @@ void svf_free_xxd_para(svf_xxr_para_t *para)
        }
 }
 
-static int handle_svf_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+static unsigned svf_get_mask_u32(int bitlen)
+{
+       uint32_t bitmask;
+
+       if (bitlen < 0)
+       {
+               bitmask = 0;
+       }
+       else if (bitlen >= 32)
+       {
+               bitmask = 0xFFFFFFFF;
+       }
+       else
+       {
+               bitmask = (1 << bitlen) - 1;
+       }
+
+       return bitmask;
+}
+
+int svf_add_statemove(tap_state_t state_to)
+{
+       tap_state_t state_from = cmd_queue_cur_state;
+       uint8_t index;
+
+       /* when resetting, be paranoid and ignore current state */
+       if (state_to == TAP_RESET) {
+               jtag_add_tlr();
+               return ERROR_OK;
+       }
+
+       for (index = 0; index < DIM(svf_statemoves); index++)
+       {
+               if ((svf_statemoves[index].from == state_from)
+                       && (svf_statemoves[index].to == state_to))
+               {
+                       /* recorded path includes current state ... avoid extra TCKs! */
+                       if (svf_statemoves[index].num_of_moves > 1)
+                               jtag_add_pathmove(svf_statemoves[index].num_of_moves - 1,
+                                               svf_statemoves[index].paths + 1);
+                       else
+                               jtag_add_pathmove(svf_statemoves[index].num_of_moves,
+                                               svf_statemoves[index].paths);
+                       return ERROR_OK;
+               }
+       }
+       LOG_ERROR("SVF: can not move to %s", tap_state_name(state_to));
+       return ERROR_FAIL;
+}
+
+COMMAND_HANDLER(handle_svf_command)
 {
+#define SVF_NUM_OF_OPTIONS                     1
        int command_num = 0, i;
        int ret = ERROR_OK;
+       long long time_ago;
 
-       if (argc < 1)
+       if ((argc < 1) || (argc > (1 + SVF_NUM_OF_OPTIONS)))
        {
-               command_print(cmd_ctx, "usage: svf <file>");
+               command_print(cmd_ctx, "usage: svf <file> [quiet]");
                return ERROR_FAIL;
        }
 
+       // parse variant
+       svf_quiet = 0;
+       for (i = 1; i < argc; i++)
+       {
+               if (!strcmp(args[i], "quiet"))
+               {
+                       svf_quiet = 1;
+               }
+               else
+               {
+                       LOG_ERROR("unknown variant for svf: %s", args[i]);
+
+                       // no need to free anything now
+                       return ERROR_FAIL;
+               }
+       }
+
        if ((svf_fd = open(args[0], O_RDONLY)) < 0)
        {
                command_print(cmd_ctx, "file \"%s\" not found", args[0]);
+
+               // no need to free anything now
                return ERROR_FAIL;
        }
 
        LOG_USER("svf processing file: \"%s\"", args[0]);
 
+       // get time
+       time_ago = timeval_ms();
+
        // init
        svf_line_number = 1;
        svf_command_buffer_size = 0;
@@ -265,21 +362,21 @@ static int handle_svf_command(struct command_context_s *cmd_ctx, char *cmd, char
        // in case current command cannot be commited, and next command is a bit scan command
        // here is 32K bits for this big scan command, it should be enough
        // buffer will be reallocated if buffer size is not enough
-       svf_tdi_buffer = (u8 *)malloc(2 * SVF_MAX_BUFFER_SIZE_TO_COMMIT);
+       svf_tdi_buffer = (uint8_t *)malloc(2 * SVF_MAX_BUFFER_SIZE_TO_COMMIT);
        if (NULL == svf_tdi_buffer)
        {
                LOG_ERROR("not enough memory");
                ret = ERROR_FAIL;
                goto free_all;
        }
-       svf_tdo_buffer = (u8 *)malloc(2 * SVF_MAX_BUFFER_SIZE_TO_COMMIT);
+       svf_tdo_buffer = (uint8_t *)malloc(2 * SVF_MAX_BUFFER_SIZE_TO_COMMIT);
        if (NULL == svf_tdo_buffer)
        {
                LOG_ERROR("not enough memory");
                ret = ERROR_FAIL;
                goto free_all;
        }
-       svf_mask_buffer = (u8 *)malloc(2 * SVF_MAX_BUFFER_SIZE_TO_COMMIT);
+       svf_mask_buffer = (uint8_t *)malloc(2 * SVF_MAX_BUFFER_SIZE_TO_COMMIT);
        if (NULL == svf_mask_buffer)
        {
                LOG_ERROR("not enough memory");
@@ -289,14 +386,11 @@ static int handle_svf_command(struct command_context_s *cmd_ctx, char *cmd, char
        svf_buffer_size = 2 * SVF_MAX_BUFFER_SIZE_TO_COMMIT;
 
        memcpy(&svf_para, &svf_para_init, sizeof(svf_para));
-       for (i = 0; i < dimof(svf_tap_state_name); i++)
-       {
-               svf_tap_state_name[i] = (char *)jtag_state_name(i);
-       }
+
        // TAP_RESET
        jtag_add_tlr();
 
-       while ( ERROR_OK == svf_read_command_from_file(svf_fd) )
+       while (ERROR_OK == svf_read_command_from_file(svf_fd))
        {
                if (ERROR_OK != svf_run_command(cmd_ctx, svf_command_buffer))
                {
@@ -315,6 +409,9 @@ static int handle_svf_command(struct command_context_s *cmd_ctx, char *cmd, char
                ret = ERROR_FAIL;
        }
 
+       // print time
+       command_print(cmd_ctx, "%lld ms used", timeval_ms() - time_ago);
+
 free_all:
 
        close(svf_fd);
@@ -376,9 +473,9 @@ static int svf_read_command_from_file(int fd)
        char ch, *tmp_buffer = NULL;
        int cmd_pos = 0, cmd_ok = 0, slash = 0, comment = 0;
 
-       while (!cmd_ok && (read(fd, &ch, 1) > 0) )
+       while (!cmd_ok && (read(fd, &ch, 1) > 0))
        {
-               switch(ch)
+               switch (ch)
                {
                case '!':
                        slash = 0;
@@ -449,7 +546,7 @@ static int svf_parse_cmd_string(char *str, int len, char **argus, int *num_of_ar
 
        while (pos < len)
        {
-               switch(str[pos])
+               switch (str[pos])
                {
                case '\n':
                case '\r':
@@ -478,14 +575,10 @@ static int svf_parse_cmd_string(char *str, int len, char **argus, int *num_of_ar
        return ERROR_OK;
 }
 
-static int svf_tap_state_is_stable(tap_state_t state)
+bool svf_tap_state_is_stable(tap_state_t state)
 {
-       return ((TAP_RESET == state) || (TAP_IDLE == state) || (TAP_DRPAUSE == state) || (TAP_IRPAUSE == state));
-}
-
-static int svf_tap_state_is_valid(tap_state_t state)
-{
-       return ((state >= 0) && (state < sizeof(svf_tap_state_name)));
+       return (TAP_RESET == state) || (TAP_IDLE == state)
+                       || (TAP_DRPAUSE == state) || (TAP_IRPAUSE == state);
 }
 
 static int svf_find_string_in_array(char *str, char **strs, int num_of_element)
@@ -502,7 +595,7 @@ static int svf_find_string_in_array(char *str, char **strs, int num_of_element)
        return 0xFF;
 }
 
-static int svf_adjust_array_length(u8 **arr, int orig_bit_len, int new_bit_len)
+static int svf_adjust_array_length(uint8_t **arr, int orig_bit_len, int new_bit_len)
 {
        int new_byte_len = (new_bit_len + 7) >> 3;
 
@@ -513,7 +606,7 @@ static int svf_adjust_array_length(u8 **arr, int orig_bit_len, int new_bit_len)
                        free(*arr);
                        *arr = NULL;
                }
-               *arr = (u8*)malloc(new_byte_len);
+               *arr = (uint8_t*)malloc(new_byte_len);
                if (NULL == *arr)
                {
                        LOG_ERROR("not enough memory");
@@ -524,10 +617,10 @@ static int svf_adjust_array_length(u8 **arr, int orig_bit_len, int new_bit_len)
        return ERROR_OK;
 }
 
-static int svf_copy_hexstring_to_binary(char *str, u8 **bin, int orig_bit_len, int bit_len)
+static int svf_copy_hexstring_to_binary(char *str, uint8_t **bin, int orig_bit_len, int bit_len)
 {
-       int i, str_len = strlen(str), str_byte_len = (bit_len + 3) >> 2, loop_cnt;
-       u8 ch, need_write = 1;
+       int i, str_len = strlen(str), str_hbyte_len = (bit_len + 3) >> 2;
+       uint8_t ch = 0;
 
        if (ERROR_OK != svf_adjust_array_length(bin, orig_bit_len, bit_len))
        {
@@ -535,75 +628,58 @@ static int svf_copy_hexstring_to_binary(char *str, u8 **bin, int orig_bit_len, i
                return ERROR_FAIL;
        }
 
-       if (str_byte_len > str_len)
-       {
-               loop_cnt = str_byte_len;
-       }
-       else
-       {
-               loop_cnt = str_len;
-       }
-
-       for (i = 0; i < loop_cnt; i++)
+       for (i = 0; i < str_hbyte_len; i++)
        {
-               if (i < str_len)
+               ch = 0;
+               while (str_len > 0)
                {
-                       ch = str[str_len - i - 1];
-                       if ((ch >= '0') && (ch <= '9'))
-                       {
-                               ch = ch - '0';
-                       }
-                       else if ((ch >= 'A') && (ch <= 'F'))
-                       {
-                               ch = ch - 'A' + 10;
-                       }
-                       else
+                       ch = str[--str_len];
+
+                       if (!isblank(ch))
                        {
-                               LOG_ERROR("invalid hex string");
-                               return ERROR_FAIL;
+                               if ((ch >= '0') && (ch <= '9'))
+                               {
+                                       ch = ch - '0';
+                                       break;
+                               }
+                               else if ((ch >= 'A') && (ch <= 'F'))
+                               {
+                                       ch = ch - 'A' + 10;
+                                       break;
+                               }
+                               else
+                               {
+                                       LOG_ERROR("invalid hex string");
+                                       return ERROR_FAIL;
+                               }
                        }
-               }
-               else
-               {
+
                        ch = 0;
                }
 
-               // check valid
-               if (i >= str_byte_len)
+               // write bin
+               if (i % 2)
                {
-                       // all data written, other data should be all '0's and needn't to be written
-                       need_write = 0;
-                       if (ch != 0)
-                       {
-                               LOG_ERROR("value execede length");
-                               return ERROR_FAIL;
-                       }
+                       // MSB
+                       (*bin)[i / 2] |= ch << 4;
                }
-               else if (i == (str_byte_len - 1))
+               else
                {
-                       // last data byte, written if valid
-                       if ((ch & ~((1 << (bit_len - 4 * i)) - 1)) != 0)
-                       {
-                               LOG_ERROR("value execede length");
-                               return ERROR_FAIL;
-                       }
+                       // LSB
+                       (*bin)[i / 2] = 0;
+                       (*bin)[i / 2] |= ch;
                }
+       }
 
-               if (need_write)
-               {
-                       // write bin
-                       if (i % 2)
-                       {
-                               // MSB
-                               (*bin)[i / 2] |= ch << 4;
-                       }
-                       else
-                       {
-                               // LSB
-                               (*bin)[i / 2] = 0;
-                               (*bin)[i / 2] |= ch;
-                       }
-               }
+       // consume optional leading '0' characters
+       while (str_len > 0 && str[str_len - 1] == '0')
+               str_len--;
+
+       // check valid
+       if (str_len > 0 || (ch & ~((2 << ((bit_len - 1) % 4)) - 1)) != 0)
+       {
+               LOG_ERROR("value execeeds length");
+               return ERROR_FAIL;
        }
 
        return ERROR_OK;
@@ -611,26 +687,29 @@ static int svf_copy_hexstring_to_binary(char *str, u8 **bin, int orig_bit_len, i
 
 static int svf_check_tdo(void)
 {
-       int i, j, byte_len, index;
+       int i, len, index;
 
        for (i = 0; i < svf_check_tdo_para_index; i++)
        {
-               if (svf_check_tdo_para[i].enabled)
+               index = svf_check_tdo_para[i].buffer_offset;
+               len = svf_check_tdo_para[i].bit_len;
+               if ((svf_check_tdo_para[i].enabled)
+                       && buf_cmp_mask(&svf_tdi_buffer[index], &svf_tdo_buffer[index], &svf_mask_buffer[index], len))
                {
-                       byte_len = (svf_check_tdo_para[i].bit_len + 7) >> 3;
-                       index = svf_check_tdo_para[i].buffer_offset;
-                       for (j = 0; j < byte_len; j++)
-                       {
-                               if ((svf_tdi_buffer[index + j] & svf_mask_buffer[index + j]) != svf_tdo_buffer[index + j])
-                               {
-                                       LOG_ERROR("tdo check error at line %d, read = 0x%X, want = 0x%X, mask = 0x%X", 
-                                                               svf_check_tdo_para[i].line_num, 
-                                                               (*(int*)(svf_tdi_buffer + index)) & ((1 << svf_check_tdo_para[i].bit_len) - 1), 
-                                                               (*(int*)(svf_tdo_buffer + index)) & ((1 << svf_check_tdo_para[i].bit_len) - 1), 
-                                                               (*(int*)(svf_mask_buffer + index)) & ((1 << svf_check_tdo_para[i].bit_len) - 1));
-                                       return ERROR_FAIL;
-                               }
-                       }
+                       unsigned bitmask;
+                       unsigned received, expected, tapmask;
+                       bitmask = svf_get_mask_u32(svf_check_tdo_para[i].bit_len);
+
+                       memcpy(&received, svf_tdi_buffer + index, sizeof(unsigned));
+                       memcpy(&expected, svf_tdo_buffer + index, sizeof(unsigned));
+                       memcpy(&tapmask, svf_mask_buffer + index, sizeof(unsigned));
+                       LOG_ERROR("tdo check error at line %d",
+                                         svf_check_tdo_para[i].line_num);
+                       LOG_ERROR("read = 0x%X, want = 0x%X, mask = 0x%X",
+                                         received & bitmask,
+                                         expected & bitmask,
+                                         tapmask & bitmask);
+                       return ERROR_FAIL;
                }
        }
        svf_check_tdo_para_index = 0;
@@ -638,7 +717,7 @@ static int svf_check_tdo(void)
        return ERROR_OK;
 }
 
-static int svf_add_check_para(u8 enabled, int buffer_offset, int bit_len)
+static int svf_add_check_para(uint8_t enabled, int buffer_offset, int bit_len)
 {
        if (svf_check_tdo_para_index >= SVF_CHECK_TDO_PARA_SIZE)
        {
@@ -655,10 +734,21 @@ static int svf_add_check_para(u8 enabled, int buffer_offset, int bit_len)
        return ERROR_OK;
 }
 
-// not good to use this
-extern jtag_command_t** jtag_get_last_command_p(void);
-extern void* cmd_queue_alloc(size_t size);
-extern jtag_command_t **last_comand_pointer;
+static int svf_execute_tap(void)
+{
+       if (ERROR_OK != jtag_execute_queue())
+       {
+               return ERROR_FAIL;
+       }
+       else if (ERROR_OK != svf_check_tdo())
+       {
+               return ERROR_FAIL;
+       }
+
+       svf_buffer_index = 0;
+
+       return ERROR_OK;
+}
 
 static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str)
 {
@@ -668,28 +758,33 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str)
        // tmp variable
        int i_tmp;
 
-       // not good to use this
-       jtag_command_t **last_cmd;
-
        // for RUNTEST
        int run_count;
        float min_time, max_time;
        // for XXR
        svf_xxr_para_t *xxr_para_tmp;
-       u8 **pbuffer_tmp;
+       uint8_t **pbuffer_tmp;
        scan_field_t field;
        // for STATE
        tap_state_t *path = NULL, state;
 
-       LOG_DEBUG("%s", cmd_str);
+       if (!svf_quiet)
+       {
+               LOG_USER("%s", svf_command_buffer);
+       }
 
        if (ERROR_OK != svf_parse_cmd_string(cmd_str, strlen(cmd_str), argus, &num_of_argu))
        {
                return ERROR_FAIL;
        }
 
-       command = svf_find_string_in_array(argus[0], (char **)svf_command_name, dimof(svf_command_name));
-       switch(command)
+       /* NOTE: we're a bit loose here, because we ignore case in
+        * TAP state names (instead of insisting on uppercase).
+        */
+
+       command = svf_find_string_in_array(argus[0],
+                       (char **)svf_command_name, DIM(svf_command_name));
+       switch (command)
        {
        case ENDDR:
        case ENDIR:
@@ -698,23 +793,28 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str)
                        LOG_ERROR("invalid parameter of %s", argus[0]);
                        return ERROR_FAIL;
                }
-               i_tmp = svf_find_string_in_array(argus[1], (char **)svf_tap_state_name, dimof(svf_tap_state_name));
+
+               i_tmp = tap_state_by_name(argus[1]);
+
                if (svf_tap_state_is_stable(i_tmp))
                {
                        if (command == ENDIR)
                        {
                                svf_para.ir_end_state = i_tmp;
-                               LOG_DEBUG("\tir_end_state = %s", svf_tap_state_name[svf_para.ir_end_state]);
+                               LOG_DEBUG("\tIR end_state = %s",
+                                               tap_state_name(i_tmp));
                        }
                        else
                        {
                                svf_para.dr_end_state = i_tmp;
-                               LOG_DEBUG("\tdr_end_state = %s", svf_tap_state_name[svf_para.dr_end_state]);
+                               LOG_DEBUG("\tDR end_state = %s",
+                                               tap_state_name(i_tmp));
                        }
                }
                else
                {
-                       LOG_ERROR("%s is not valid state", argus[1]);
+                       LOG_ERROR("%s: %s is not a stable state",
+                                       argus[0], argus[1]);
                        return ERROR_FAIL;
                }
                break;
@@ -736,6 +836,10 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str)
                                LOG_ERROR("HZ not found in FREQUENCY command");
                                return ERROR_FAIL;
                        }
+                       if (ERROR_OK != svf_execute_tap())
+                       {
+                               return ERROR_FAIL;
+                       }
                        svf_para.frequency = atof(argus[1]);
                        // TODO: set jtag speed to
                        if (svf_para.frequency > 0)
@@ -776,7 +880,7 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str)
                xxr_para_tmp->data_mask = 0;
                for (i = 2; i < num_of_argu; i += 2)
                {
-                       if ((argus[i + 1][0] != '(') || (argus[i + 1][strlen(argus[i + 1]) - 1] != ')'))
+                       if ((strlen(argus[i + 1]) < 3) || (argus[i + 1][0] != '(') || (argus[i + 1][strlen(argus[i + 1]) - 1] != ')'))
                        {
                                LOG_ERROR("data section error");
                                return ERROR_FAIL;
@@ -817,9 +921,9 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str)
                                LOG_ERROR("fail to parse hex value");
                                return ERROR_FAIL;
                        }
-                       LOG_DEBUG("\t%s = 0x%X", argus[i], (**(int**)pbuffer_tmp) & ((1 << (xxr_para_tmp->len)) - 1));
+                       LOG_DEBUG("\t%s = 0x%X", argus[i], (**(int**)pbuffer_tmp) & svf_get_mask_u32(xxr_para_tmp->len));
                }
-               // If a command changes the length of the last scan of the same type and the MASK parameter is absent, 
+               // If a command changes the length of the last scan of the same type and the MASK parameter is absent,
                // the mask pattern used is all cares
                if (!(xxr_para_tmp->data_mask & XXR_MASK) && (i_tmp != xxr_para_tmp->len))
                {
@@ -831,6 +935,27 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str)
                        }
                        buf_set_ones(xxr_para_tmp->mask, xxr_para_tmp->len);
                }
+               // If TDO is absent, no comparison is needed, set the mask to 0
+               if (!(xxr_para_tmp->data_mask & XXR_TDO))
+               {
+                       if (NULL == xxr_para_tmp->tdo)
+                       {
+                               if (ERROR_OK != svf_adjust_array_length(&xxr_para_tmp->tdo, i_tmp, xxr_para_tmp->len))
+                               {
+                                       LOG_ERROR("fail to adjust length of array");
+                                       return ERROR_FAIL;
+                               }
+                       }
+                       if (NULL == xxr_para_tmp->mask)
+                       {
+                               if (ERROR_OK != svf_adjust_array_length(&xxr_para_tmp->mask, i_tmp, xxr_para_tmp->len))
+                               {
+                                       LOG_ERROR("fail to adjust length of array");
+                                       return ERROR_FAIL;
+                               }
+                       }
+                       memset(xxr_para_tmp->mask, 0, (xxr_para_tmp->len + 7) >> 3);
+               }
                // do scan if necessary
                if (SDR == command)
                {
@@ -843,10 +968,10 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str)
                                LOG_ERROR("buffer is not enough, report to author");
                                return ERROR_FAIL;
 #else
-                               u8 *buffer_tmp;
+                               uint8_t *buffer_tmp;
 
                                // reallocate buffer
-                               buffer_tmp = (u8 *)malloc(svf_buffer_index + ((i + 7) >> 3));
+                               buffer_tmp = (uint8_t *)malloc(svf_buffer_index + ((i + 7) >> 3));
                                if (NULL == buffer_tmp)
                                {
                                        LOG_ERROR("not enough memory");
@@ -857,7 +982,7 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str)
                                free(svf_tdi_buffer);
                                svf_tdi_buffer = buffer_tmp;
 
-                               buffer_tmp = (u8 *)malloc(svf_buffer_index + ((i + 7) >> 3));
+                               buffer_tmp = (uint8_t *)malloc(svf_buffer_index + ((i + 7) >> 3));
                                if (NULL == buffer_tmp)
                                {
                                        LOG_ERROR("not enough memory");
@@ -868,7 +993,7 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str)
                                free(svf_tdo_buffer);
                                svf_tdo_buffer = buffer_tmp;
 
-                               buffer_tmp = (u8 *)malloc(svf_buffer_index + ((i + 7) >> 3));
+                               buffer_tmp = (uint8_t *)malloc(svf_buffer_index + ((i + 7) >> 3));
                                if (NULL == buffer_tmp)
                                {
                                        LOG_ERROR("not enough memory");
@@ -922,12 +1047,8 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str)
                        field.tap = tap;
                        field.num_bits = i;
                        field.out_value = &svf_tdi_buffer[svf_buffer_index];
-                       field.out_mask = NULL;
                        field.in_value = &svf_tdi_buffer[svf_buffer_index];
-                       field.in_check_value = NULL;
-                       field.in_check_mask = NULL;
-                       field.in_handler = NULL;
-                       field.in_handler_priv = NULL;
+                       /* NOTE:  doesn't use SVF-specified state paths */
                        jtag_add_plain_dr_scan(1, &field, svf_para.dr_end_state);
 
                        svf_buffer_index += (i + 7) >> 3;
@@ -943,10 +1064,10 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str)
                                LOG_ERROR("buffer is not enough, report to author");
                                return ERROR_FAIL;
 #else
-                               u8 *buffer_tmp;
+                               uint8_t *buffer_tmp;
 
                                // reallocate buffer
-                               buffer_tmp = (u8 *)malloc(svf_buffer_index + ((i + 7) >> 3));
+                               buffer_tmp = (uint8_t *)malloc(svf_buffer_index + ((i + 7) >> 3));
                                if (NULL == buffer_tmp)
                                {
                                        LOG_ERROR("not enough memory");
@@ -957,7 +1078,7 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str)
                                free(svf_tdi_buffer);
                                svf_tdi_buffer = buffer_tmp;
 
-                               buffer_tmp = (u8 *)malloc(svf_buffer_index + ((i + 7) >> 3));
+                               buffer_tmp = (uint8_t *)malloc(svf_buffer_index + ((i + 7) >> 3));
                                if (NULL == buffer_tmp)
                                {
                                        LOG_ERROR("not enough memory");
@@ -968,7 +1089,7 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str)
                                free(svf_tdo_buffer);
                                svf_tdo_buffer = buffer_tmp;
 
-                               buffer_tmp = (u8 *)malloc(svf_buffer_index + ((i + 7) >> 3));
+                               buffer_tmp = (uint8_t *)malloc(svf_buffer_index + ((i + 7) >> 3));
                                if (NULL == buffer_tmp)
                                {
                                        LOG_ERROR("not enough memory");
@@ -1022,12 +1143,8 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str)
                        field.tap = tap;
                        field.num_bits = i;
                        field.out_value = &svf_tdi_buffer[svf_buffer_index];
-                       field.out_mask = NULL;
                        field.in_value = &svf_tdi_buffer[svf_buffer_index];
-                       field.in_check_value = NULL;
-                       field.in_check_mask = NULL;
-                       field.in_handler = NULL;
-                       field.in_handler_priv = NULL;
+                       /* NOTE:  doesn't use SVF-specified state paths */
                        jtag_add_plain_ir_scan(1, &field, svf_para.ir_end_state);
 
                        svf_buffer_index += (i + 7) >> 3;
@@ -1051,25 +1168,31 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str)
                min_time = 0;
                max_time = 0;
                i = 1;
+
                // run_state
-               i_tmp = svf_find_string_in_array(argus[i], (char **)svf_tap_state_name, dimof(svf_tap_state_name));
-               if (svf_tap_state_is_valid(i_tmp))
+               i_tmp = tap_state_by_name(argus[i]);
+               if (i_tmp != TAP_INVALID)
                {
                        if (svf_tap_state_is_stable(i_tmp))
                        {
                                svf_para.runtest_run_state = i_tmp;
 
-                               // When a run_state is specified, the new  run_state becomes the default end_state
+                               /* When a run_state is specified, the new
+                                * run_state becomes the default end_state.
+                                */
                                svf_para.runtest_end_state = i_tmp;
-                               LOG_DEBUG("\trun_state = %s", svf_tap_state_name[svf_para.runtest_run_state]);
+                               LOG_DEBUG("\trun_state = %s",
+                                               tap_state_name(i_tmp));
                                i++;
                        }
                        else
                        {
-                               LOG_ERROR("%s is not valid state", svf_tap_state_name[i_tmp]);
+                               LOG_ERROR("%s: %s is not a stable state",
+                                       argus[0], tap_state_name(i_tmp));
                                return ERROR_FAIL;
                        }
                }
+
                // run_count run_clk
                if (((i + 2) <= num_of_argu) && strcmp(argus[i + 1], "SEC"))
                {
@@ -1103,15 +1226,18 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str)
                // ENDSTATE end_state
                if (((i + 2) <= num_of_argu) && !strcmp(argus[i], "ENDSTATE"))
                {
-                       i_tmp = svf_find_string_in_array(argus[i + 1], (char **)svf_tap_state_name, dimof(svf_tap_state_name));
+                       i_tmp = tap_state_by_name(argus[i + 1]);
+
                        if (svf_tap_state_is_stable(i_tmp))
                        {
                                svf_para.runtest_end_state = i_tmp;
-                               LOG_DEBUG("\tend_state = %s", svf_tap_state_name[svf_para.runtest_end_state]);
+                               LOG_DEBUG("\tend_state = %s",
+                                       tap_state_name(i_tmp));
                        }
                        else
                        {
-                               LOG_ERROR("%s is not valid state", svf_tap_state_name[i_tmp]);
+                               LOG_ERROR("%s: %s is not a stable state",
+                                       argus[0], tap_state_name(i_tmp));
                                return ERROR_FAIL;
                        }
                        i += 2;
@@ -1126,14 +1252,36 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str)
                {
                        if (run_count > 0)
                        {
+                               // run_state and end_state is checked to be stable state
                                // TODO: do runtest
+#if 1
+                               /* FIXME handle statemove failures */
+                               int retval;
+
+                               // enter into run_state if necessary
+                               if (cmd_queue_cur_state != svf_para.runtest_run_state)
+                               {
+                                       retval = svf_add_statemove(svf_para.runtest_run_state);
+                               }
+
+                               // call jtag_add_clocks
+                               jtag_add_clocks(run_count);
+
+                               // move to end_state if necessary
+                               if (svf_para.runtest_end_state != svf_para.runtest_run_state)
+                               {
+                                       retval = svf_add_statemove(svf_para.runtest_end_state);
+                               }
+#else
                                if (svf_para.runtest_run_state != TAP_IDLE)
                                {
-                                       // RUNTEST can only executed in TAP_IDLE
-                                       LOG_ERROR("cannot runtest in %s state", svf_tap_state_name[svf_para.runtest_run_state]);
+                                       LOG_ERROR("cannot runtest in %s state",
+                                               tap_state_name(svf_para.runtest_run_state));
                                        return ERROR_FAIL;
                                }
+
                                jtag_add_runtest(run_count, svf_para.runtest_end_state);
+#endif
                        }
                }
                else
@@ -1158,32 +1306,51 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str)
                                LOG_ERROR("not enough memory");
                                return ERROR_FAIL;
                        }
-                       for (i = 1; i < num_of_argu; i++)
+                       num_of_argu--;          // num of path
+                       i_tmp = 1;              /* path is from parameter 1 */
+                       for (i = 0; i < num_of_argu; i++, i_tmp++)
                        {
-                               path[i - 1] = svf_find_string_in_array(argus[i], (char **)svf_tap_state_name, dimof(svf_tap_state_name));
-                               if (!svf_tap_state_is_valid(path[i - 1]))
+                               path[i] = tap_state_by_name(argus[i_tmp]);
+                               if (path[i] == TAP_INVALID)
                                {
-                                       LOG_ERROR("%s is not valid state", svf_tap_state_name[path[i - 1]]);
+                                       LOG_ERROR("%s: %s is not a valid state",
+                                               argus[0], argus[i_tmp]);
+                                       free(path);
                                        return ERROR_FAIL;
                                }
-                               if (TAP_RESET == path[i - 1])
+                               /* OpenOCD refuses paths containing TAP_RESET */
+                               if (TAP_RESET == path[i])
                                {
-                                       LOG_ERROR("TAP_RESET is not allowed in pathmove");
-                                       return ERROR_FAIL;
+                                       /* FIXME last state MUST be stable! */
+                                       if (i > 0)
+                                       {
+                                               jtag_add_pathmove(i, path);
+                                       }
+                                       jtag_add_tlr();
+                                       num_of_argu -= i + 1;
+                                       i = -1;
                                }
                        }
-                       if (svf_tap_state_is_stable(path[num_of_argu - 1]))
-                       {
-                               // last state MUST be stable state
-                               // TODO: call path_move
-                               jtag_add_pathmove(num_of_argu - 1, path);
-                               LOG_DEBUG("\tmove to %s by path_move", svf_tap_state_name[path[num_of_argu - 1]]);
-                       }
-                       else
+                       if (num_of_argu > 0)
                        {
-                               LOG_ERROR("%s is not valid state", svf_tap_state_name[path[num_of_argu - 1]]);
-                               return ERROR_FAIL;
+                               // execute last path if necessary
+                               if (svf_tap_state_is_stable(path[num_of_argu - 1]))
+                               {
+                                       // last state MUST be stable state
+                                       jtag_add_pathmove(num_of_argu, path);
+                                       LOG_DEBUG("\tmove to %s by path_move",
+                                               tap_state_name(path[num_of_argu - 1]));
+                               }
+                               else
+                               {
+                                       LOG_ERROR("%s: %s is not a stable state",
+                                               argus[0],
+                                               tap_state_name(path[num_of_argu - 1]));
+                                       free(path);
+                                       return ERROR_FAIL;
+                               }
                        }
+                       // no need to keep this memory, in jtag_add_pathmove, path will be duplicated
                        if (NULL != path)
                        {
                                free(path);
@@ -1193,23 +1360,18 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str)
                else
                {
                        // STATE stable_state
-                       state = svf_find_string_in_array(argus[1], (char **)svf_tap_state_name, dimof(svf_tap_state_name));
+                       state = tap_state_by_name(argus[1]);
                        if (svf_tap_state_is_stable(state))
                        {
-                               // TODO: move to state
-                               last_cmd = jtag_get_last_command_p();
-                               *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t));
-                               last_comand_pointer = &((*last_cmd)->next);
-                               (*last_cmd)->next = NULL;
-                               (*last_cmd)->type = JTAG_STATEMOVE;
-                               (*last_cmd)->cmd.statemove = cmd_queue_alloc(sizeof(statemove_command_t));
-                               (*last_cmd)->cmd.statemove->end_state = state;
-
-                               LOG_DEBUG("\tmove to %s by state_move", svf_tap_state_name[state]);
+                               LOG_DEBUG("\tmove to %s by svf_add_statemove",
+                                               tap_state_name(state));
+                               /* FIXME handle statemove failures */
+                               svf_add_statemove(state);
                        }
                        else
                        {
-                               LOG_ERROR("%s is not valid state", svf_tap_state_name[state]);
+                               LOG_ERROR("%s: %s is not a stable state",
+                                       argus[0], tap_state_name(state));
                                return ERROR_FAIL;
                        }
                }
@@ -1223,16 +1385,21 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str)
                }
                if (svf_para.trst_mode != TRST_ABSENT)
                {
-                       i_tmp = svf_find_string_in_array(argus[1], (char **)svf_trst_mode_name, dimof(svf_trst_mode_name));
+                       if (ERROR_OK != svf_execute_tap())
+                       {
+                               return ERROR_FAIL;
+                       }
+                       i_tmp = svf_find_string_in_array(argus[1],
+                                       (char **)svf_trst_mode_name,
+                                       DIM(svf_trst_mode_name));
                        switch (i_tmp)
                        {
                        case TRST_ON:
                                jtag_add_reset(1, 0);
                                break;
-                       case TRST_OFF:
-                               jtag_add_reset(1, 1);
-                               break;
                        case TRST_Z:
+                       case TRST_OFF:
+                               jtag_add_reset(0, 0);
                                break;
                        case TRST_ABSENT:
                                break;
@@ -1262,22 +1429,20 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str)
                        (((command != STATE) && (command != RUNTEST)) || \
                        ((command == STATE) && (num_of_argu == 2))))
                {
-                       // there is data to be executed
-                       if (ERROR_OK != jtag_execute_queue())
+                       if (ERROR_OK != svf_execute_tap())
                        {
                                return ERROR_FAIL;
                        }
+
                        // output debug info
                        if ((SIR == command) || (SDR == command))
                        {
-                               LOG_DEBUG("\tTDO read = 0x%X", (*(int*)svf_tdi_buffer) & ((1 << (svf_check_tdo_para[0].bit_len)) - 1));
-                       }
-                       if (ERROR_OK != svf_check_tdo())
-                       {
-                               return ERROR_FAIL;
+                               int read_value;
+                               memcpy(&read_value, svf_tdi_buffer, sizeof(int));
+                               // in debug mode, data is from index 0
+                               int read_mask = svf_get_mask_u32(svf_check_tdo_para[0].bit_len);
+                               LOG_DEBUG("\tTDO read = 0x%X", read_value & read_mask);
                        }
-
-                       svf_buffer_index = 0;
                }
        }
        else
@@ -1288,18 +1453,18 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str)
                        (((command != STATE) && (command != RUNTEST)) || \
                        ((command == STATE) && (num_of_argu == 2))))
                {
-                       if (ERROR_OK != jtag_execute_queue())
-                       {
-                               return ERROR_FAIL;
-                       }
-                       else if (ERROR_OK != svf_check_tdo())
-                       {
-                               return ERROR_FAIL;
-                       }
-
-                       svf_buffer_index = 0;
+                       return svf_execute_tap();
                }
        }
 
        return ERROR_OK;
 }
+
+int svf_register_commands(struct command_context_s *cmd_ctx)
+{
+       register_command(cmd_ctx, NULL, "svf",
+                       &handle_svf_command, COMMAND_EXEC,
+                       "run svf <file>");
+
+       return ERROR_OK;
+}