-/***************************************************************************
- * 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"
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_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}},
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;
+ /* when resetting, be paranoid and ignore current state */
+ if (state_to == TAP_RESET) {
+ jtag_add_tlr();
+ return ERROR_OK;
+ }
+
for (index = 0; index < dimof(svf_statemoves); index++)
{
- if ((svf_statemoves[index].from == state_from)
+ 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_svf_name(state_to));
return ERROR_FAIL;
}
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));
+ return (TAP_RESET == state) || (TAP_IDLE == state)
+ || (TAP_DRPAUSE == state) || (TAP_IRPAUSE == state);
}
static int svf_tap_state_is_valid(tap_state_t state)
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;
- uint8_t 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))
{
return ERROR_FAIL;
}
- if (str_byte_len > str_len)
- {
- loop_cnt = str_byte_len;
- }
- else
+ for (i = 0; i < str_hbyte_len; i++)
{
- loop_cnt = str_len;
- }
-
- for (i = 0; i < loop_cnt; 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;
- }
- }
+ // check valid
+ if (str_len > 0 || (ch & ~((1 << (4 - (bit_len % 4))) - 1)) != 0)
+ {
+ LOG_ERROR("value execede length");
+ return ERROR_FAIL;
}
return ERROR_OK;
{
index = svf_check_tdo_para[i].buffer_offset;
len = svf_check_tdo_para[i].bit_len;
- if ((svf_check_tdo_para[i].enabled)
+ if ((svf_check_tdo_para[i].enabled)
&& buf_cmp_mask(&svf_tdi_buffer[index], &svf_tdo_buffer[index], &svf_mask_buffer[index], len))
{
unsigned bitmask;
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",
+ 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,
+ LOG_ERROR("read = 0x%X, want = 0x%X, mask = 0x%X",
+ received & bitmask,
+ expected & bitmask,
tapmask & bitmask);
return ERROR_FAIL;
}
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;
// 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)
if (!svf_tap_state_is_valid(path[i]))
{
LOG_ERROR("%s is not valid state", svf_tap_state_name[path[i]]);
+ 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);
else
{
LOG_ERROR("%s is not valid state", svf_tap_state_name[path[num_of_argu - 1]]);
+ free(path);
return ERROR_FAIL;
}
}
state = svf_find_string_in_array(argus[1], (char **)svf_tap_state_name, dimof(svf_tap_state_name));
if (svf_tap_state_is_stable(state))
{
- // TODO: move to state
+ LOG_DEBUG("\tmove to %s by svf_add_statemove",
+ svf_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
{