Encapsulate JTAG minidriver functions, plan for new header file.
[openocd.git] / src / jtag / jtag.c
index 66a5fd850998f4730680177d9166ca41dfc3b183..303b43416629b1fdd349cac40c1d7ce73243c70c 100644 (file)
@@ -28,6 +28,7 @@
 #include "config.h"
 #endif
 
+#define INCLUDE_JTAG_MINIDRIVER_H
 #include "jtag.h"
 
 #ifdef HAVE_STRINGS_H
@@ -227,7 +228,7 @@ jtag_interface_t *jtag_interfaces[] = {
        NULL,
 };
 
-jtag_interface_t *jtag = NULL;
+static jtag_interface_t *jtag = NULL;
 
 /* configuration */
 static jtag_interface_t *jtag_interface = NULL;
@@ -641,40 +642,42 @@ int MINIDRIVER(interface_jtag_add_ir_scan)(int in_num_fields, const scan_field_t
 
        for (jtag_tap_t * tap = jtag_NextEnabledTap(NULL); tap != NULL; tap = jtag_NextEnabledTap(tap))
        {
-               int found = 0;
+               /* search the input field list for fields for the current TAP */
 
-               size_t scan_size                                = tap->ir_length;
+               bool found = false;
 
-               /* search the list */
                for (int j = 0; j < in_num_fields; j++)
                {
-                       if (tap == in_fields[j].tap)
-                       {
-                               found = 1;
+                       if (tap != in_fields[j].tap)
+                               continue;
 
-                               tap->bypass = 0;
-                               
-                               assert(in_fields[j].num_bits == tap->ir_length); /* input fields must have the same length as the TAP's IR */
+                       /* if TAP is listed in input fields, copy the value */
 
-                               cmd_queue_scan_field_clone(field, in_fields + j);
+                       found = true;
 
-                               break;
-                       }
+                       tap->bypass = 0;
+
+                       assert(in_fields[j].num_bits == tap->ir_length); /* input fields must have the same length as the TAP's IR */
+
+                       cmd_queue_scan_field_clone(field, in_fields + j);
+
+                       break;
                }
 
                if (!found)
                {
                        /* if a TAP isn't listed in input fields, set it to BYPASS */
+
                        tap->bypass = 1;
 
                        field->tap                      = tap;
-                       field->num_bits         = scan_size;
-                       field->out_value        = buf_set_ones(cmd_queue_alloc(CEIL(scan_size, 8)), scan_size);
+                       field->num_bits         = tap->ir_length;
+                       field->out_value        = buf_set_ones(cmd_queue_alloc(CEIL(tap->ir_length, 8)), tap->ir_length);
                        field->in_value         = NULL; /* do not collect input for tap's in bypass */
                }
 
                /* update device information */
-               buf_cpy(field->out_value, tap->cur_instr, scan_size);
+               buf_cpy(field->out_value, tap->cur_instr, tap->ir_length);
 
                field++;
        }
@@ -827,9 +830,6 @@ void jtag_add_dr_scan(int in_num_fields, const scan_field_t *in_fields, tap_stat
  */
 int MINIDRIVER(interface_jtag_add_dr_scan)(int in_num_fields, const scan_field_t *in_fields, tap_state_t state)
 {
-       int j;
-       int field_count = 0;
-
        /* count devices in bypass */
 
        size_t bypass_devices = 0;
@@ -854,53 +854,46 @@ int MINIDRIVER(interface_jtag_add_dr_scan)(int in_num_fields, const scan_field_t
        scan->fields                    = out_fields;
        scan->end_state                 = state;
 
+
+       scan_field_t * field = out_fields;      /* keep track where we insert data */
+
+       /* loop over all enabled TAPs */
+
        for (jtag_tap_t * tap = jtag_NextEnabledTap(NULL); tap != NULL; tap = jtag_NextEnabledTap(tap))
        {
-               int found = 0;
+               /* if TAP is not bypassed insert matching input fields */
 
-               for (j = 0; j < in_num_fields; j++)
+               if (!tap->bypass)
                {
-                       if (tap == in_fields[j].tap)
-                       {
-                               found = 1;
-                               
-                               cmd_queue_scan_field_clone(scan->fields + field_count, in_fields + j);
+                       scan_field_t * start_field = field;     /* keep initial position for assert() */
 
-                               field_count++;
-                       }
-               }
-               if (!found)
-               {
-#ifdef _DEBUG_JTAG_IO_
-                       /* if a device isn't listed, the BYPASS register should be selected */
-                       if (! tap->bypass)
+                       for (int j = 0; j < in_num_fields; j++)
                        {
-                               LOG_ERROR("BUG: no scan data for a device not in BYPASS");
-                               exit(-1);
+                               if (tap != in_fields[j].tap)
+                                       continue;
+
+                               cmd_queue_scan_field_clone(field, in_fields + j);
+
+                               field++;
                        }
-#endif
-                       /* program the scan field to 1 bit length, and ignore it's value */
-                       scan->fields[field_count].tap                   = tap;
-                       scan->fields[field_count].num_bits              = 1;
-                       scan->fields[field_count].out_value             = NULL;
-                       scan->fields[field_count].in_value              = NULL;
-                       field_count++;
+
+                       assert(field > start_field);    /* must have at least one input field per not bypassed TAP */
                }
+               
+               /* if a TAP is bypassed, generated a dummy bit*/
                else
                {
-#ifdef _DEBUG_JTAG_IO_
-                       /* if a device is listed, the BYPASS register must not be selected */
-                       if (tap->bypass)
-                       {
-                               LOG_ERROR("BUG: scan data for a device in BYPASS");
-                               exit(-1);
-                       }
-#endif
+                       field->tap                      = tap;
+                       field->num_bits         = 1;
+                       field->out_value        = NULL;
+                       field->in_value         = NULL;
+
+                       field++;
                }
        }
 
-       /* field_count represents the true number of fields setup*/
-       scan->num_fields = field_count;
+       assert(field == out_fields + scan->num_fields); /* no superfluous input fields permitted */
+
        return ERROR_OK;
 }
 
@@ -926,8 +919,6 @@ void MINIDRIVER(interface_jtag_add_dr_out)(jtag_tap_t *target_tap,
                const u32 *value,
                tap_state_t end_state)
 {
-       int field_count = 0;
-
        /* count devices in bypass */
 
        size_t bypass_devices = 0;
@@ -953,47 +944,52 @@ void MINIDRIVER(interface_jtag_add_dr_out)(jtag_tap_t *target_tap,
        scan->fields                    = out_fields;
        scan->end_state                 = end_state;
 
+
+       bool target_tap_match   = false;
+
+       scan_field_t * field = out_fields;      /* keep track where we insert data */
+
+       /* loop over all enabled TAPs */
+
        for (jtag_tap_t * tap = jtag_NextEnabledTap(NULL); tap != NULL; tap = jtag_NextEnabledTap(tap))
        {
-               scan->fields[field_count].tap = tap;
+               /* if TAP is not bypassed insert matching input fields */
 
-               if (tap == target_tap)
+               if (!tap->bypass)
                {
-#ifdef _DEBUG_JTAG_IO_
-                       /* if a device is listed, the BYPASS register must not be selected */
-                       if (tap->bypass)
-                       {
-                               LOG_ERROR("BUG: scan data for a device in BYPASS");
-                               exit(-1);
-                       }
-#endif
+                       assert(tap == target_tap); /* target_tap must match the one not bypassed TAP */
+
+                       target_tap_match = true;
+
                        for (int j = 0; j < in_num_fields; j++)
                        {
                                u8 out_value[4];
                                size_t scan_size = num_bits[j];
                                buf_set_u32(out_value, 0, scan_size, value[j]);
-                               scan->fields[field_count].num_bits              = scan_size;
-                               scan->fields[field_count].out_value             = buf_cpy(out_value, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size);
-                               scan->fields[field_count].in_value              = NULL;
-                               field_count++;
+
+                               field->tap                      = tap;
+                               field->num_bits         = scan_size;
+                               field->out_value        = buf_cpy(out_value, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size);
+                               field->in_value         = NULL;
+
+                               field++;
                        }
-               } else
+               }
+
+               /* if a TAP is bypassed, generated a dummy bit*/
+               else
                {
-#ifdef _DEBUG_JTAG_IO_
-                       /* if a device isn't listed, the BYPASS register should be selected */
-                       if (! tap->bypass)
-                       {
-                               LOG_ERROR("BUG: no scan data for a device not in BYPASS");
-                               exit(-1);
-                       }
-#endif
-                       /* program the scan field to 1 bit length, and ignore it's value */
-                       scan->fields[field_count].num_bits                      = 1;
-                       scan->fields[field_count].out_value                     = NULL;
-                       scan->fields[field_count].in_value                      = NULL;
-                       field_count++;
+
+                       field->tap                              = tap;
+                       field->num_bits                 = 1;
+                       field->out_value                = NULL;
+                       field->in_value                 = NULL;
+
+                       field++;
                }
        }
+
+       assert(target_tap_match);       /* target_tap should be enabled and not bypassed */
 }
 
 
@@ -1258,6 +1254,7 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst)
                jtag_error=retval;
                return;
        }
+       jtag_execute_queue();
 
        if (jtag_srst)
        {
@@ -1285,7 +1282,7 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst)
                 * and inform possible listeners about this
                 */
                LOG_DEBUG("TRST line asserted");
-               cmd_queue_cur_state = TAP_RESET;
+               tap_set_state(TAP_RESET);
                jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
        }
        else
@@ -2319,9 +2316,10 @@ int jtag_register_commands(struct command_context_s *cmd_ctx)
        register_command(cmd_ctx, NULL, "interface", handle_interface_command,
                COMMAND_CONFIG, "try to configure interface");
        register_command(cmd_ctx, NULL, "jtag_speed", handle_jtag_speed_command,
-               COMMAND_ANY, "set jtag speed (if supported)");
+               COMMAND_ANY, "(DEPRECATED) set jtag speed (if supported)");
        register_command(cmd_ctx, NULL, "jtag_khz", handle_jtag_khz_command,
-               COMMAND_ANY, "same as jtag_speed, except it takes maximum khz as arguments. 0 KHz = RTCK.");
+               COMMAND_ANY, "set maximum jtag speed (if supported); "
+               "parameter is maximum khz, or 0 for adaptive clocking (RTCK).");
        register_command(cmd_ctx, NULL, "jtag_device", handle_jtag_device_command,
                COMMAND_CONFIG, "jtag_device <ir_length> <ir_expected> <ir_mask>");
        register_command(cmd_ctx, NULL, "reset_config", handle_reset_config_command,
@@ -2410,6 +2408,20 @@ static int jtag_init_inner(struct command_context_s *cmd_ctx)
        return ERROR_OK;
 }
 
+int jtag_interface_quit(void)
+{
+       if (!jtag || !jtag->quit)
+               return ERROR_OK;
+
+       // close the JTAG interface
+       int result = jtag->quit();
+       if (ERROR_OK != result)
+               LOG_ERROR("failed: %d", result);
+
+       return ERROR_OK;
+}
+
+
 int jtag_init_reset(struct command_context_s *cmd_ctx)
 {
        int retval;
@@ -2654,77 +2666,111 @@ static int handle_scan_chain_command(struct command_context_s *cmd_ctx, char *cm
 
 static int handle_reset_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
 {
+       int new_cfg = 0;
+       int mask = 0;
+
        if (argc < 1)
                return ERROR_COMMAND_SYNTAX_ERROR;
 
-       if (argc >= 1)
-       {
-               if (strcmp(args[0], "none") == 0)
-                       jtag_reset_config = RESET_NONE;
-               else if (strcmp(args[0], "trst_only") == 0)
-                       jtag_reset_config = RESET_HAS_TRST;
-               else if (strcmp(args[0], "srst_only") == 0)
-                       jtag_reset_config = RESET_HAS_SRST;
-               else if (strcmp(args[0], "trst_and_srst") == 0)
-                       jtag_reset_config = RESET_TRST_AND_SRST;
+       /* Original versions cared about the order of these tokens:
+        *   reset_config signals [combination [trst_type [srst_type]]]
+        * They also clobbered the previous configuration even on error.
+        *
+        * Here we don't care about the order, and only change values
+        * which have been explicitly specified.
+        */
+       for (; argc; argc--, args++) {
+               int tmp = 0;
+               int m;
+
+               /* signals */
+               m = RESET_HAS_TRST | RESET_HAS_SRST;
+               if (strcmp(*args, "none") == 0)
+                       tmp = RESET_NONE;
+               else if (strcmp(*args, "trst_only") == 0)
+                       tmp = RESET_HAS_TRST;
+               else if (strcmp(*args, "srst_only") == 0)
+                       tmp = RESET_HAS_SRST;
+               else if (strcmp(*args, "trst_and_srst") == 0)
+                       tmp = RESET_HAS_TRST | RESET_HAS_SRST;
                else
-               {
-                       LOG_ERROR("(1) invalid reset_config argument (%s), defaulting to none", args[0]);
-                       jtag_reset_config = RESET_NONE;
+                       m = 0;
+               if (mask & m) {
+                       LOG_ERROR("extra reset_config %s spec (%s)",
+                                       "signal", *args);
                        return ERROR_INVALID_ARGUMENTS;
                }
-       }
-
-       if (argc >= 2)
-       {
-               if (strcmp(args[1], "separate") == 0)
-               {
-                       /* seperate reset lines - default */
-               } else
-               {
-                       if (strcmp(args[1], "srst_pulls_trst") == 0)
-                               jtag_reset_config |= RESET_SRST_PULLS_TRST;
-                       else if (strcmp(args[1], "trst_pulls_srst") == 0)
-                               jtag_reset_config |= RESET_TRST_PULLS_SRST;
-                       else if (strcmp(args[1], "combined") == 0)
-                               jtag_reset_config |= RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST;
-                       else
-                       {
-                               LOG_ERROR("(2) invalid reset_config argument (%s), defaulting to none", args[1]);
-                               jtag_reset_config = RESET_NONE;
-                               return ERROR_INVALID_ARGUMENTS;
-                       }
+               if (m)
+                       goto next;
+
+               /* combination (options for broken wiring) */
+               m = RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST;
+               if (strcmp(*args, "separate") == 0)
+                       /* separate reset lines - default */;
+               else if (strcmp(*args, "srst_pulls_trst") == 0)
+                       tmp |= RESET_SRST_PULLS_TRST;
+               else if (strcmp(*args, "trst_pulls_srst") == 0)
+                       tmp |= RESET_TRST_PULLS_SRST;
+               else if (strcmp(*args, "combined") == 0)
+                       tmp |= RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST;
+               else
+                       m = 0;
+               if (mask & m) {
+                       LOG_ERROR("extra reset_config %s spec (%s)",
+                                       "combination", *args);
+                       return ERROR_INVALID_ARGUMENTS;
                }
-       }
+               if (m)
+                       goto next;
 
-       if (argc >= 3)
-       {
-               if (strcmp(args[2], "trst_open_drain") == 0)
-                       jtag_reset_config |= RESET_TRST_OPEN_DRAIN;
-               else if (strcmp(args[2], "trst_push_pull") == 0)
-                       jtag_reset_config &= ~RESET_TRST_OPEN_DRAIN;
+               /* trst_type (NOP without HAS_TRST) */
+               m = RESET_TRST_OPEN_DRAIN;
+               if (strcmp(*args, "trst_open_drain") == 0)
+                       tmp |= RESET_TRST_OPEN_DRAIN;
+               else if (strcmp(*args, "trst_push_pull") == 0)
+                       /* push/pull from adapter - default */;
                else
-               {
-                       LOG_ERROR("(3) invalid reset_config argument (%s) defaulting to none", args[2] );
-                       jtag_reset_config = RESET_NONE;
+                       m = 0;
+               if (mask & m) {
+                       LOG_ERROR("extra reset_config %s spec (%s)",
+                                       "trst_type", *args);
                        return ERROR_INVALID_ARGUMENTS;
                }
-       }
+               if (m)
+                       goto next;
 
-       if (argc >= 4)
-       {
-               if (strcmp(args[3], "srst_push_pull") == 0)
-                       jtag_reset_config |= RESET_SRST_PUSH_PULL;
-               else if (strcmp(args[3], "srst_open_drain") == 0)
-                       jtag_reset_config &= ~RESET_SRST_PUSH_PULL;
+               /* srst_type (NOP without HAS_SRST) */
+               m |= RESET_SRST_PUSH_PULL;
+               if (strcmp(*args, "srst_push_pull") == 0)
+                       tmp |= RESET_SRST_PUSH_PULL;
+               else if (strcmp(*args, "srst_open_drain") == 0)
+                       /* open drain from adapter - default */;
                else
-               {
-                       LOG_ERROR("(4) invalid reset_config argument (%s), defaulting to none", args[3]);
-                       jtag_reset_config = RESET_NONE;
+                       m = 0;
+               if (mask & m) {
+                       LOG_ERROR("extra reset_config %s spec (%s)",
+                                       "srst_type", *args);
                        return ERROR_INVALID_ARGUMENTS;
                }
+               if (m)
+                       goto next;
+
+               /* caller provided nonsense; fail */
+               LOG_ERROR("unknown reset_config flag (%s)", *args);
+               return ERROR_INVALID_ARGUMENTS;
+
+next:
+               /* Remember the bits which were specified (mask)
+                * and their new values (new_cfg).
+                */
+               mask |= m;
+               new_cfg |= tmp;
        }
 
+       /* clear previous values of those bits, save new values */
+       jtag_reset_config &= ~mask;
+       jtag_reset_config |= new_cfg;
+
        return ERROR_OK;
 }
 
@@ -3674,3 +3720,90 @@ static int handle_tms_sequence_command(struct command_context_s *cmd_ctx, char *
 }
 
 /*-----</Cable Helper API>--------------------------------------*/
+
+
+/**
+ * Function jtag_add_statemove
+ * 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.
+ */
+int jtag_add_statemove(tap_state_t goal_state)
+{
+       int retval = ERROR_OK;
+
+       tap_state_t moves[8];
+       tap_state_t cur_state = cmd_queue_cur_state;
+       int i;
+       int tms_bits;
+       int     tms_count;
+
+       LOG_DEBUG( "cur_state=%s goal_state=%s",
+               tap_state_name(cur_state),
+               tap_state_name(goal_state) );
+
+
+       /*      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.
+       */
+
+       if (goal_state==cur_state )
+               ;       /* nothing to do */
+
+       else if( goal_state==TAP_RESET )
+       {
+               jtag_add_tlr();
+       }
+
+       else if( tap_is_state_stable(cur_state) && tap_is_state_stable(goal_state) )
+       {
+               /*      note: unless tms_bits holds a path that agrees with [Ref 5] in 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.
+               */
+
+               tms_bits  = tap_get_tms_path(cur_state, goal_state);
+               tms_count = tap_get_tms_path_len(cur_state, goal_state);
+
+               assert( (unsigned) tms_count < DIM(moves) );
+
+               for (i=0;   i<tms_count;   i++, tms_bits>>=1)
+               {
+                       bool bit = tms_bits & 1;
+
+                       cur_state = tap_state_transition(cur_state, bit);
+                       moves[i] = cur_state;
+               }
+
+               jtag_add_pathmove(tms_count, moves);
+       }
+
+       /*      else state must be immediately reachable in one clock cycle, and does not
+               need to be a stable state.
+       */
+       else if( tap_state_transition(cur_state, true)  == goal_state
+               ||   tap_state_transition(cur_state, false) == goal_state )
+       {
+               /* move a single state */
+               moves[0] = goal_state;
+               jtag_add_pathmove( 1, moves );
+       }
+
+       else
+       {
+               retval = ERROR_FAIL;
+       }
+
+       return retval;
+}
+

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)