diff --git a/doc/openocd.texi b/doc/openocd.texi index 107441d2d..500faf9a5 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -6096,6 +6096,8 @@ with handlers for that event. @deffn Command {pathmove} start_state [next_state ...] Start by moving to @var{start_state}, which must be one of the @emph{stable} states. +Unless it is the only state given, this will often be the +current state, so that no TCK transitions are needed. Then, in a series of single state transitions (conforming to the JTAG state machine) shift to each @var{next_state} in sequence, one per TCK cycle. @@ -6130,8 +6132,8 @@ Default is enabled. The @var{tap_state} names used by OpenOCD in the @command{drscan}, @command{irscan}, and @command{pathmove} commands are the same -as those used in SVF boundary scan documents, except that some -versions of SVF use @sc{idle} instead of @sc{run/idle}. +as those used in SVF boundary scan documents, except that +SVF uses @sc{idle} instead of @sc{run/idle}. @itemize @bullet @item @b{RESET} ... @emph{stable} (with TMS high); @@ -6222,6 +6224,27 @@ Unless the @option{quiet} option is specified, messages are logged for comments and some retries. @end deffn +The OpenOCD sources also include two utility scripts +for working with XSVF; they are not currently installed +after building the software. +You may find them useful: + +@itemize +@item @emph{svf2xsvf} ... converts SVF files into the extended XSVF +syntax understood by the @command{xsvf} command; see notes below. +@item @emph{xsvfdump} ... converts XSVF files into a text output format; +understands the OpenOCD extensions. +@end itemize + +The input format accepts a handful of non-standard extensions. +These include three opcodes corresponding to SVF extensions +from Lattice Semiconductor (LCOUNT, LDELAY, LDSR), and +two opcodes supporting a more accurate translation of SVF +(XTRST, XWAITSTATE). +If @emph{xsvfdump} shows a file is using those opcodes, it +probably will not be usable with other XSVF tools. + + @node TFTP @chapter TFTP @cindex TFTP diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h index 5085445f3..7253c3eaa 100644 --- a/src/jtag/jtag.h +++ b/src/jtag/jtag.h @@ -536,29 +536,7 @@ extern void jtag_add_pathmove(int num_states, const tap_state_t* path); * @return ERROR_OK on success, or an error code on failure. * * Moves from the current state to the goal \a state. - * - * This needs to be handled according to the xsvf spec, see the XSTATE - * command description. From the XSVF spec, pertaining to XSTATE: - * - * For special states known as stable states (Test-Logic-Reset, - * Run-Test/Idle, Pause-DR, Pause- IR), an XSVF interpreter follows - * predefined TAP state paths when the starting state is a stable state - * and when the XSTATE specifies a new stable state. See the STATE - * command in the [Ref 5] for the TAP state paths between stable - * states. - * - * For non-stable states, XSTATE should specify a state that is only one - * TAP state transition distance from the current TAP state to avoid - * undefined TAP state paths. A sequence of multiple XSTATE commands can - * be issued to transition the TAP through a specific state path. - * - * @note Unless @c tms_bits holds a path that agrees with [Ref 5] in the - * above spec, then this code is not fully conformant to the xsvf spec. - * This puts a burden on tap_get_tms_path() function from the xsvf spec. - * If in doubt, you should confirm that that burden is being met. - * - * Otherwise, @a goal_state must be immediately reachable in one clock - * cycle, and does not need to be a stable state. + * Both states must be stable. */ extern int jtag_add_statemove(tap_state_t goal_state); diff --git a/src/svf/svf.c b/src/svf/svf.c index ecb0ffa4b..dfbbde4be 100644 --- a/src/svf/svf.c +++ b/src/svf/svf.c @@ -31,8 +31,8 @@ #include "config.h" #endif -#include "svf.h" #include "jtag.h" +#include "svf.h" #include "time_support.h" @@ -311,7 +311,7 @@ static const char* tap_state_svf_name(tap_state_t state) 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; @@ -619,9 +619,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)); + return (TAP_RESET == state) || (TAP_IDLE == state) + || (TAP_DRPAUSE == state) || (TAP_IRPAUSE == state); } static int svf_tap_state_is_valid(tap_state_t state) @@ -1082,6 +1083,7 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str) 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; @@ -1177,6 +1179,7 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str) 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; @@ -1278,10 +1281,13 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str) // 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 @@ -1290,7 +1296,7 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str) // 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) @@ -1337,8 +1343,10 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str) 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); @@ -1378,10 +1386,10 @@ static int svf_run_command(struct command_context_s *cmd_ctx, char *cmd_str) 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 { diff --git a/src/svf/svf.h b/src/svf/svf.h index 822cad22e..83123fc3b 100644 --- a/src/svf/svf.h +++ b/src/svf/svf.h @@ -24,4 +24,25 @@ extern int svf_register_commands(struct command_context_s *cmd_ctx); +/** + * svf_add_statemove() moves from the current state to @a goal_state. + * + * @param goal_state The final TAP state. + * @return ERROR_OK on success, or an error code on failure. + * + * The current and goal states must satisfy svf_tap_state_is_stable(). + * State transition paths used by this routine are those given in the + * SVF specification for single-argument STATE commands (and also used + * for various other state transitions). + */ +extern int svf_add_statemove(tap_state_t goal_state); + +/** + * svf_tap_state_is_stable() returns true for stable non-SHIFT states + * + * @param state The TAP state in question + * @return true iff the state is stable and not a SHIFT state. + */ +extern bool svf_tap_state_is_stable(tap_state_t state); + #endif /* SVF_H */ diff --git a/src/xsvf/Makefile.am b/src/xsvf/Makefile.am index 847fb8070..fd9f8c3f7 100644 --- a/src/xsvf/Makefile.am +++ b/src/xsvf/Makefile.am @@ -1,6 +1,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/server \ -I$(top_srcdir)/src/helper \ + -I$(top_srcdir)/src/svf \ -I$(top_srcdir)/src/jtag METASOURCES = AUTO diff --git a/src/xsvf/xsvf.c b/src/xsvf/xsvf.c index 083e6e325..d00c47c6d 100644 --- a/src/xsvf/xsvf.c +++ b/src/xsvf/xsvf.c @@ -42,6 +42,7 @@ #include "xsvf.h" #include "jtag.h" +#include "svf.h" /* XSVF commands, from appendix B of xapp503.pdf */ @@ -432,7 +433,7 @@ static int handle_xsvf_command(struct command_context_s *cmd_ctx, char *cmd, cha /* See page 19 of XSVF spec regarding opcode "XSDR" */ if (xruntest) { - jtag_add_statemove(TAP_IDLE); + result = svf_add_statemove(TAP_IDLE); if (runtest_requires_tck) jtag_add_clocks(xruntest); @@ -440,7 +441,7 @@ static int handle_xsvf_command(struct command_context_s *cmd_ctx, char *cmd, cha jtag_add_sleep(xruntest); } else if (xendir != TAP_DRPAUSE) /* we are already in TAP_DRPAUSE */ - jtag_add_statemove(xenddr); + result = svf_add_statemove(xenddr); } break; @@ -499,32 +500,37 @@ static int handle_xsvf_command(struct command_context_s *cmd_ctx, char *cmd, cha LOG_DEBUG("XSTATE 0x%02X %s", uc, tap_state_name(mystate)); - /* there is no need for the lookahead code that was here since we - queue up the jtag commands anyway. This is a simple way to handle - the XSTATE. - */ + /* NOTE: the current state is SVF-stable! */ + + /* no change == NOP */ + if (mystate == cmd_queue_cur_state + && mystate != TAP_RESET) + break; - if (jtag_add_statemove(mystate) != ERROR_OK) + /* Hand off to SVF? */ + if (svf_tap_state_is_stable(mystate)) { - /* For special states known as stable states - (Test-Logic-Reset, Run-Test/Idle, Pause-DR, Pause- IR), - an XSVF interpreter follows predefined TAP state paths - when the starting state is a stable state and when the - XSTATE specifies a new stable state (see the STATE - command in the [Ref 5] for the TAP state paths between - stable states). For non-stable states, XSTATE should - specify a state that is only one TAP state transition - distance from the current TAP state to avoid undefined - TAP state paths. A sequence of multiple XSTATE commands - can be issued to transition the TAP through a specific - state path. - */ - - LOG_ERROR("XSTATE %s is not reachable from current state %s in one clock cycle", - tap_state_name(mystate), - tap_state_name(cmd_queue_cur_state) -); + result = svf_add_statemove(mystate); + if (result != ERROR_OK) + unsupported = 1; + break; } + + /* + * A sequence of XSTATE transitions, each TAP + * state adjacent to the previous one. + * + * NOTE: OpenOCD requires something that XSVF + * doesn't: the last TAP state in the path + * must be stable. + * + * FIXME Implement path collection; submit via + * jtag_add_pathmove() after teaching it to + * report errors. + */ + LOG_ERROR("XSVF: 'XSTATE %s' ... NYET", + tap_state_name(mystate)); + unsupported = 1; } break; @@ -708,9 +714,10 @@ static int handle_xsvf_command(struct command_context_s *cmd_ctx, char *cmd, cha } else { - jtag_add_statemove(wait_state); + /* FIXME handle statemove errors ... */ + result = svf_add_statemove(wait_state); jtag_add_sleep(delay); - jtag_add_statemove(end_state); + result = svf_add_statemove(end_state); } } break; @@ -755,19 +762,22 @@ static int handle_xsvf_command(struct command_context_s *cmd_ctx, char *cmd, cha * be issuing a number of clocks in this state. This set of allowed states is also * determined by the SVF RUNTEST command's allowed states. */ - if (wait_state != TAP_IRPAUSE && wait_state != TAP_DRPAUSE && wait_state != TAP_RESET && wait_state != TAP_IDLE) + if (!svf_tap_state_is_stable(wait_state)) { - LOG_ERROR("illegal XWAITSTATE wait_state: \"%s\"", tap_state_name(wait_state)); + LOG_ERROR("illegal XWAITSTATE wait_state: \"%s\"", + tap_state_name(wait_state)); unsupported = 1; + /* REVISIT "break" so we won't run? */ } - jtag_add_statemove(wait_state); + /* FIXME handle statemove errors ... */ + result = svf_add_statemove(wait_state); jtag_add_clocks(clock_count); jtag_add_sleep(usecs); - jtag_add_statemove(end_state); + result = svf_add_statemove(end_state); } break; @@ -806,6 +816,7 @@ static int handle_xsvf_command(struct command_context_s *cmd_ctx, char *cmd, cha break; } + /* NOTE: loop_state must be stable! */ loop_state = xsvf_to_tap(state); loop_clocks = be_to_h_u32(clock_buf); loop_usecs = be_to_h_u32(usecs_buf); @@ -839,7 +850,7 @@ static int handle_xsvf_command(struct command_context_s *cmd_ctx, char *cmd, cha { scan_field_t field; - jtag_add_statemove(loop_state); + result = svf_add_statemove(loop_state); jtag_add_clocks(loop_clocks); jtag_add_sleep(loop_usecs); @@ -917,8 +928,8 @@ static int handle_xsvf_command(struct command_context_s *cmd_ctx, char *cmd, cha LOG_DEBUG("xsvf failed, setting taps to reasonable state"); /* upon error, return the TAPs to a reasonable state */ - jtag_add_statemove(TAP_IDLE); - jtag_execute_queue(); + result = svf_add_statemove(TAP_IDLE); + result = jtag_execute_queue(); break; } }