XSVF: use svf_add_statemove()
authorDavid Brownell <dbrownell@users.sourceforge.net>
Wed, 21 Oct 2009 03:04:36 +0000 (20:04 -0700)
committerDavid Brownell <dbrownell@users.sourceforge.net>
Wed, 21 Oct 2009 03:04:36 +0000 (20:04 -0700)
XSVF improvements:

 - Layer parts of XSVF directly over SVF, calling svf_add_statemove()
   instead of expecting jtag_add_statemove() to conform to the SVF/XSVF
   requirements (which it doesn't).

   This should improve XSTATE handling a lot; it removes most users of
   jtag_add_statemove(), and the comments about how it should really do
   what svf_add_statemove() does.

 - Update XSTATE logic to be a closer match to the XSVF spec.  The main
   open issue here is (still) that this implementation doesn't know how
   to build and submit paths from single-state transitions ... but now
   it will report that error case.

 - Update the User's Guide to mention the two utility scripts for
   working with XSVF, and to mention the five extension opcodes.

Handling of state transition paths is, overall, still a mess.  I think
they should all be specified as paths not unlike SVF uses, and compiled
to the bitstrings later ... so that we can actually make sense of the
paths.  (And see the extra clocks, detours through RUN, etc.)

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
doc/openocd.texi
src/jtag/jtag.h
src/svf/svf.c
src/svf/svf.h
src/xsvf/Makefile.am
src/xsvf/xsvf.c

index 107441d..500faf9 100644 (file)
@@ -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
index 5085445..7253c3e 100644 (file)
@@ -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);
 
index ecb0ffa..dfbbde4 100644 (file)
@@ -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
                        {
index 822cad2..83123fc 100644 (file)
 
 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 */
index 847fb80..fd9f8c3 100644 (file)
@@ -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
index 083e6e3..d00c47c 100644 (file)
@@ -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;
                }
        }