-/***************************************************************************
- * 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 "svf.h"
#include "time_support.h"
TRST,
}svf_command_t;
-const char *svf_command_name[14] =
+static const char *svf_command_name[14] =
{
"ENDDR",
"ENDIR",
TRST_ABSENT
}trst_mode_t;
-const char *svf_trst_mode_name[4] =
+static const char *svf_trst_mode_name[4] =
{
"ON",
"OFF",
tap_state_t paths[8];
}svf_statemove_t;
-svf_statemove_t svf_statemoves[] =
+/*
+ * 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_IRPAUSE, TAP_IRPAUSE, 8, {TAP_IRPAUSE, TAP_IREXIT2, TAP_IRUPDATE, TAP_DRSELECT, TAP_IRSELECT, TAP_IRCAPTURE, TAP_IREXIT1, TAP_IRPAUSE}}
};
-char *svf_tap_state_name[TAP_NUM_STATES];
#define XXR_TDI (1 << 0)
#define XXR_TDO (1 << 1)
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,
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(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;
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)
{
}
}
-unsigned svf_get_mask_u32(int bitlen)
+static unsigned svf_get_mask_u32(int bitlen)
{
uint32_t bitmask;
return bitmask;
}
-static const char* tap_state_svf_name(tap_state_t state)
-{
- const char* ret;
-
- switch (state)
- {
- case TAP_RESET: ret = "RESET"; break;
- case TAP_IDLE: ret = "IDLE"; break;
- case TAP_DRSELECT: ret = "DRSELECT"; break;
- case TAP_DRCAPTURE: ret = "DRCAPTURE"; break;
- case TAP_DRSHIFT: ret = "DRSHIFT"; break;
- case TAP_DREXIT1: ret = "DREXIT1"; break;
- case TAP_DRPAUSE: ret = "DRPAUSE"; break;
- case TAP_DREXIT2: ret = "DREXIT2"; break;
- case TAP_DRUPDATE: ret = "DRUPDATE"; break;
- case TAP_IRSELECT: ret = "IRSELECT"; break;
- case TAP_IRCAPTURE: ret = "IRCAPTURE"; break;
- case TAP_IRSHIFT: ret = "IRSHIFT"; break;
- case TAP_IREXIT1: ret = "IREXIT1"; break;
- case TAP_IRPAUSE: ret = "IRPAUSE"; break;
- case TAP_IREXIT2: ret = "IREXIT2"; break;
- case TAP_IRUPDATE: ret = "IRUPDATE"; break;
- default: ret = "???"; break;
- }
-
- return ret;
-}
-
-static int svf_add_statemove(tap_state_t state_to)
+int svf_add_statemove(tap_state_t state_to)
{
tap_state_t state_from = cmd_queue_cur_state;
uint8_t index;
- for (index = 0; index < dimof(svf_statemoves); 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))
{
- if (TAP_RESET == state_from)
- {
- jtag_add_tlr();
- if (svf_statemoves[index].num_of_moves > 1)
- {
- jtag_add_pathmove(svf_statemoves[index].num_of_moves - 1, svf_statemoves[index].paths + 1);
- }
- }
+ /* 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
- {
- if (svf_statemoves[index].num_of_moves > 0)
- {
- jtag_add_pathmove(svf_statemoves[index].num_of_moves, svf_statemoves[index].paths);
- }
- }
+ jtag_add_pathmove(svf_statemoves[index].num_of_moves,
+ svf_statemoves[index].paths);
return ERROR_OK;
}
}
- LOG_ERROR("can not move to %s", tap_state_svf_name(state_to));
+ LOG_ERROR("SVF: can not move to %s", tap_state_name(state_to));
return ERROR_FAIL;
}
-static int handle_svf_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+COMMAND_HANDLER(handle_svf_command)
{
#define SVF_NUM_OF_OPTIONS 1
int command_num = 0, i;
svf_buffer_size = 2 * SVF_MAX_BUFFER_SIZE_TO_COMMIT;
memcpy(&svf_para, &svf_para_init, sizeof(svf_para));
- for (i = 0; i < (int)dimof(svf_tap_state_name); i++)
- {
- svf_tap_state_name[i] = (char *)tap_state_svf_name(i);
- }
// TAP_RESET
jtag_add_tlr();
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 < TAP_NUM_STATES;
+ 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)
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_hbyte_len = (bit_len + 3) >> 2;
- uint8_t ch;
+ uint8_t ch = 0;
if (ERROR_OK != svf_adjust_array_length(bin, orig_bit_len, bit_len))
{
}
}
+ // consume optional leading '0' characters
+ while (str_len > 0 && str[str_len - 1] == '0')
+ str_len--;
+
// check valid
- if (str_len > 0 || (ch & ~((1 << (4 - (bit_len % 4))) - 1)) != 0)
+ if (str_len > 0 || (ch & ~((2 << ((bit_len - 1) % 4)) - 1)) != 0)
{
- LOG_ERROR("value execede length");
+ LOG_ERROR("value execeeds length");
return ERROR_FAIL;
}
return ERROR_FAIL;
}
- command = svf_find_string_in_array(argus[0], (char **)svf_command_name, dimof(svf_command_name));
+ /* 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:
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;
field.num_bits = i;
field.out_value = &svf_tdi_buffer[svf_buffer_index];
field.in_value = &svf_tdi_buffer[svf_buffer_index];
+ /* 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;
field.num_bits = i;
field.out_value = &svf_tdi_buffer[svf_buffer_index];
field.in_value = &svf_tdi_buffer[svf_buffer_index];
+ /* 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;
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"))
{
// 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;
// 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)
{
- svf_add_statemove(svf_para.runtest_run_state);
+ retval = svf_add_statemove(svf_para.runtest_run_state);
}
// call jtag_add_clocks
// move to end_state if necessary
if (svf_para.runtest_end_state != svf_para.runtest_run_state)
{
- svf_add_statemove(svf_para.runtest_end_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;
}
return ERROR_FAIL;
}
num_of_argu--; // num of path
- i_tmp = 1; // path is from patameter 1
- for (i = 0; i < num_of_argu; i++)
+ i_tmp = 1; /* path is from parameter 1 */
+ for (i = 0; i < num_of_argu; i++, i_tmp++)
{
- path[i] = svf_find_string_in_array(argus[i_tmp++], (char **)svf_tap_state_name, dimof(svf_tap_state_name));
- if (!svf_tap_state_is_valid(path[i]))
+ 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]]);
+ LOG_ERROR("%s: %s is not a valid state",
+ argus[0], argus[i_tmp]);
+ free(path);
return ERROR_FAIL;
}
+ /* OpenOCD refuses paths containing TAP_RESET */
if (TAP_RESET == path[i])
{
+ /* FIXME last state MUST be stable! */
if (i > 0)
{
jtag_add_pathmove(i, path);
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, path);
- LOG_DEBUG("\tmove to %s by path_move", svf_tap_state_name[path[num_of_argu - 1]]);
+ LOG_DEBUG("\tmove to %s by path_move",
+ tap_state_name(path[num_of_argu - 1]));
}
else
{
- LOG_ERROR("%s is not valid state", svf_tap_state_name[path[num_of_argu - 1]]);
+ LOG_ERROR("%s: %s is not a stable state",
+ argus[0],
+ tap_state_name(path[num_of_argu - 1]));
+ free(path);
return ERROR_FAIL;
}
}
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
+ LOG_DEBUG("\tmove to %s by svf_add_statemove",
+ tap_state_name(state));
+ /* FIXME handle statemove failures */
svf_add_statemove(state);
-
- LOG_DEBUG("\tmove to %s by svf_add_statemove", svf_tap_state_name[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;
}
}
{
return ERROR_FAIL;
}
- i_tmp = svf_find_string_in_array(argus[1], (char **)svf_trst_mode_name, dimof(svf_trst_mode_name));
+ 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:
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;
+}