Cleanup jtag_tap_by_abs_position:
[fw/openocd] / src / jtag / jtag.c
index 47d16fdf11afb12700e8a6d48a893baf115f73f7..05cfd94801dcf5b4406389d61c80194313124308 100644 (file)
@@ -97,8 +97,9 @@ static bool hasKHz = false;
 
 #if BUILD_ECOSBOARD == 1
        extern jtag_interface_t zy1000_interface;
-#endif
-
+#elif defined(BUILD_MINIDRIVER_DUMMY)
+       extern jtag_interface_t minidummy_interface;
+#else // standard drivers
 #if BUILD_PARPORT == 1
        extern jtag_interface_t parport_interface;
 #endif
@@ -154,11 +155,21 @@ static bool hasKHz = false;
 #if BUILD_ARMJTAGEW == 1
        extern jtag_interface_t armjtagew_interface;
 #endif
+#endif // standard drivers
 
+/**
+ * The list of built-in JTAG interfaces, containing entries for those
+ * drivers that were enabled by the @c configure script.
+ *
+ * The list should be defined to contain either one minidriver interface
+ * or some number of standard driver interfaces, never both.
+ */
 jtag_interface_t *jtag_interfaces[] = {
 #if BUILD_ECOSBOARD == 1
        &zy1000_interface,
-#endif
+#elif defined(BUILD_MINIDRIVER_DUMMY)
+       &minidummy_interface,
+#else // standard drivers
 #if BUILD_PARPORT == 1
        &parport_interface,
 #endif
@@ -201,6 +212,7 @@ jtag_interface_t *jtag_interfaces[] = {
 #if BUILD_ARMJTAGEW == 1
        &armjtagew_interface,
 #endif
+#endif // standard drivers
        NULL,
 };
 
@@ -211,6 +223,8 @@ static jtag_interface_t *jtag_interface = NULL;
 int jtag_speed = 0;
 
 /* jtag commands */
+static int handle_interface_list_command(struct command_context_s *cmd_ctx,
+               char *cmd, char **args, int argc);
 static int handle_interface_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 static int handle_jtag_speed_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 static int handle_jtag_khz_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
@@ -221,7 +235,6 @@ static int handle_jtag_ntrst_delay_command(struct command_context_s *cmd_ctx, ch
 
 static int handle_scan_chain_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 
-static int handle_endstate_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 static int handle_jtag_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 static int handle_runtest_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 static int handle_irscan_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
@@ -242,24 +255,21 @@ int jtag_tap_count(void)
        return jtag_num_taps;
 }
 
-int jtag_tap_count_enabled(void)
+unsigned jtag_tap_count_enabled(void)
 {
-       jtag_tap_t *t;
-       int n;
-
-       n = 0;
-       t = jtag_all_taps();
-       while(t){
-               if( t->enabled ){
+       jtag_tap_t *t = jtag_all_taps();
+       unsigned n = 0;
+       while(t)
+       {
+               if (t->enabled)
                        n++;
-               }
                t = t->next_tap;
        }
        return n;
 }
 
 /// Append a new TAP to the chain of all taps.
-static void jtag_tap_add(struct jtag_tap_s *t)
+void jtag_tap_add(struct jtag_tap_s *t)
 {
        t->abs_chain_position = jtag_num_taps++;
 
@@ -269,64 +279,45 @@ static void jtag_tap_add(struct jtag_tap_s *t)
        *tap = t;
 }
 
-jtag_tap_t *jtag_tap_by_string( const char *s )
+jtag_tap_t *jtag_tap_by_string(const char *s)
 {
-       jtag_tap_t *t;
+       /* try by name first */
+       jtag_tap_t *t = jtag_all_taps();
+       while (t)
+       {
+               if (0 == strcmp(t->dotted_name, s))
+                       return t;
+               t = t->next_tap;
+       }
+
+       /* no tap found by name, so try to parse the name as a number */
        char *cp;
+       unsigned n = strtoul(s, &cp, 0);
+       if ((s == cp) || (*cp != 0))
+               return NULL;
 
-       t = jtag_all_taps();
-       /* try name first */
-       while(t){
-               if( 0 == strcmp( t->dotted_name, s ) ){
-                       break;
-               } else {
-                       t = t->next_tap;
-               }
-       }
-       /* backup plan is by number */
-       if( t == NULL ){
-               /* ok - is "s" a number? */
-               int n;
-               n = strtol( s, &cp, 0 );
-               if( (s != cp) && (*cp == 0) ){
-                       /* Then it is... */
-                       t = jtag_tap_by_abs_position(n);
-               }
-       }
-       return t;
+       return jtag_tap_by_abs_position(n);
 }
 
-jtag_tap_t * jtag_tap_by_jim_obj( Jim_Interp *interp, Jim_Obj *o )
+jtag_tap_t *jtag_tap_by_jim_obj(Jim_Interp *interp, Jim_Obj *o)
 {
-       jtag_tap_t *t;
-       const char *cp;
-
-       cp = Jim_GetString( o, NULL );
-       if(cp == NULL){
+       const char *cp = Jim_GetString(o, NULL);
+       jtag_tap_t *t = cp ? jtag_tap_by_string(cp) : NULL;
+       if (NULL == cp)
                cp = "(unknown)";
-               t = NULL;
-       }  else {
-               t = jtag_tap_by_string( cp );
-       }
-       if( t == NULL ){
-               Jim_SetResult_sprintf(interp,"Tap: %s is unknown", cp );
-       }
+       if (NULL == t)
+               Jim_SetResult_sprintf(interp, "Tap '%s' could not be found", cp);
        return t;
 }
 
 /* returns a pointer to the n-th device in the scan chain */
-jtag_tap_t * jtag_tap_by_abs_position( int n )
+jtag_tap_t *jtag_tap_by_abs_position(int n)
 {
-       int orig_n;
-       jtag_tap_t *t;
+       jtag_tap_t *t = jtag_all_taps();
 
-       orig_n = n;
-       t = jtag_all_taps();
-
-       while( t && (n > 0)) {
-               n--;
+       while (t && n-- > 0)
                t = t->next_tap;
-       }
+
        return t;
 }
 
@@ -417,15 +408,13 @@ void jtag_alloc_in_value32(scan_field_t *field)
        interface_jtag_alloc_in_value32(field);
 }
 
-void jtag_add_ir_scan_noverify(int in_num_fields, const scan_field_t *in_fields, tap_state_t state)
+void jtag_add_ir_scan_noverify(int in_count, const scan_field_t *in_fields,
+               tap_state_t state)
 {
-       int retval;
        jtag_prelude(state);
 
-       retval=interface_jtag_add_ir_scan(in_num_fields, in_fields, state);
-       if (retval!=ERROR_OK)
-               jtag_error=retval;
-
+       int retval = interface_jtag_add_ir_scan(in_count, in_fields, state);
+       jtag_set_error(retval);
 }
 
 
@@ -465,15 +454,14 @@ void jtag_add_ir_scan(int in_num_fields, scan_field_t *in_fields, tap_state_t st
  * This function assumes that the caller handles extra fields for bypassed TAPs
  *
  */
-void jtag_add_plain_ir_scan(int in_num_fields, const scan_field_t *in_fields, tap_state_t state)
+void jtag_add_plain_ir_scan(int in_num_fields, const scan_field_t *in_fields,
+               tap_state_t state)
 {
-       int retval;
-
        jtag_prelude(state);
 
-       retval=interface_jtag_add_plain_ir_scan(in_num_fields, in_fields, state);
-       if (retval!=ERROR_OK)
-               jtag_error=retval;
+       int retval = interface_jtag_add_plain_ir_scan(
+                       in_num_fields, in_fields, state);
+       jtag_set_error(retval);
 }
 
 void jtag_add_callback(jtag_callback1_t f, u8 *in)
@@ -545,42 +533,34 @@ void jtag_add_dr_scan_check(int in_num_fields, scan_field_t *in_fields, tap_stat
 
 
 /**
- * Generate a DR SCAN using the fields passed to the function
- *
- * For not bypassed TAPs the function checks in_fields and uses fields specified there.
- * For bypassed TAPs the function generates a dummy 1bit field.
- *
- * The bypass status of TAPs is set by jtag_add_ir_scan().
- *
+ * Generate a DR SCAN using the fields passed to the function.
+ * For connected TAPs, the function checks in_fields and uses fields
+ * specified there.  For bypassed TAPs, the function generates a dummy
+ * 1-bit field.  The bypass status of TAPs is set by jtag_add_ir_scan().
  */
-void jtag_add_dr_scan(int in_num_fields, const scan_field_t *in_fields, tap_state_t state)
+void jtag_add_dr_scan(int in_num_fields, const scan_field_t *in_fields,
+               tap_state_t state)
 {
-       int retval;
-
        jtag_prelude(state);
 
-       retval=interface_jtag_add_dr_scan(in_num_fields, in_fields, state);
-       if (retval!=ERROR_OK)
-               jtag_error=retval;
+       int retval;
+       retval = interface_jtag_add_dr_scan(in_num_fields, in_fields, state);
+       jtag_set_error(retval);
 }
 
-
-
 /**
- * Duplicate the scan fields passed into the function into a DR SCAN command
- *
- * This function assumes that the caller handles extra fields for bypassed TAPs
- *
+ * Duplicate the scan fields passed into the function into a DR SCAN
+ * command.  Unlike jtag_add_dr_scan(), this function assumes that the
+ * caller handles extra fields for bypassed TAPs.
  */
-void jtag_add_plain_dr_scan(int in_num_fields, const scan_field_t *in_fields, tap_state_t state)
+void jtag_add_plain_dr_scan(int in_num_fields, const scan_field_t *in_fields,
+               tap_state_t state)
 {
-       int retval;
-
        jtag_prelude(state);
 
-       retval=interface_jtag_add_plain_dr_scan(in_num_fields, in_fields, state);
-       if (retval!=ERROR_OK)
-               jtag_error=retval;
+       int retval;
+       retval = interface_jtag_add_plain_dr_scan(in_num_fields, in_fields, state);
+       jtag_set_error(retval);
 }
 
 void jtag_add_dr_out(jtag_tap_t* tap,
@@ -599,92 +579,75 @@ void jtag_add_dr_out(jtag_tap_t* tap,
 void jtag_add_tlr(void)
 {
        jtag_prelude(TAP_RESET);
-
-       int retval;
-       retval=interface_jtag_add_tlr();
-       if (retval!=ERROR_OK)
-               jtag_error=retval;
-       
+       jtag_set_error(interface_jtag_add_tlr());
        jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
 }
 
 void jtag_add_pathmove(int num_states, const tap_state_t *path)
 {
        tap_state_t cur_state = cmd_queue_cur_state;
-       int i;
-       int retval;
 
        /* the last state has to be a stable state */
        if (!tap_is_state_stable(path[num_states - 1]))
        {
                LOG_ERROR("BUG: TAP path doesn't finish in a stable state");
-               exit(-1);
+               jtag_set_error(ERROR_JTAG_NOT_STABLE_STATE);
+               return;
        }
 
-       for (i=0; i<num_states; i++)
+       for (int i = 0; i < num_states; i++)
        {
                if (path[i] == TAP_RESET)
                {
                        LOG_ERROR("BUG: TAP_RESET is not a valid state for pathmove sequences");
-                       exit(-1);
+                       jtag_set_error(ERROR_JTAG_STATE_INVALID);
+                       return;
                }
 
                if ( tap_state_transition(cur_state, true)  != path[i]
                  && tap_state_transition(cur_state, false) != path[i])
                {
-                       LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(cur_state), tap_state_name(path[i]));
-                       exit(-1);
+                       LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition",
+                                       tap_state_name(cur_state), tap_state_name(path[i]));
+                       jtag_set_error(ERROR_JTAG_TRANSITION_INVALID);
+                       return;
                }
                cur_state = path[i];
        }
 
        jtag_checks();
 
-       retval = interface_jtag_add_pathmove(num_states, path);
+       jtag_set_error(interface_jtag_add_pathmove(num_states, path));
        cmd_queue_cur_state = path[num_states - 1];
-       if (retval!=ERROR_OK)
-               jtag_error=retval;
 }
 
 void jtag_add_runtest(int num_cycles, tap_state_t state)
 {
-       int retval;
-
        jtag_prelude(state);
-
-       /* executed by sw or hw fifo */
-       retval=interface_jtag_add_runtest(num_cycles, state);
-       if (retval!=ERROR_OK)
-               jtag_error=retval;
+       jtag_set_error(interface_jtag_add_runtest(num_cycles, state));
 }
 
 
-void jtag_add_clocks( int num_cycles )
+void jtag_add_clocks(int num_cycles)
 {
-       int retval;
-
-       if( !tap_is_state_stable(cmd_queue_cur_state) )
+       if (!tap_is_state_stable(cmd_queue_cur_state))
        {
-                LOG_ERROR( "jtag_add_clocks() was called with TAP in non-stable state \"%s\"",
-                                tap_state_name(cmd_queue_cur_state) );
-                jtag_error = ERROR_JTAG_NOT_STABLE_STATE;
+                LOG_ERROR("jtag_add_clocks() called with TAP in unstable state \"%s\"",
+                                tap_state_name(cmd_queue_cur_state));
+                jtag_set_error(ERROR_JTAG_NOT_STABLE_STATE);
                 return;
        }
 
-       if( num_cycles > 0 )
+       if (num_cycles > 0)
        {
                jtag_checks();
-
-               retval = interface_jtag_add_clocks(num_cycles);
-               if (retval != ERROR_OK)
-                       jtag_error=retval;
+               jtag_set_error(interface_jtag_add_clocks(num_cycles));
        }
 }
 
 void jtag_add_reset(int req_tlr_or_trst, int req_srst)
 {
        int trst_with_tlr = 0;
-       int retval;
 
        /* FIX!!! there are *many* different cases here. A better
         * approach is needed for legal combinations of transitions...
@@ -708,7 +671,7 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst)
        if (((jtag_reset_config & RESET_SRST_PULLS_TRST) && (req_srst == 1)) && (!req_tlr_or_trst))
        {
                LOG_ERROR("BUG: requested reset would assert trst");
-               jtag_error=ERROR_FAIL;
+               jtag_set_error(ERROR_FAIL);
                return;
        }
 
@@ -721,7 +684,7 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst)
        if (req_srst && !(jtag_reset_config & RESET_HAS_SRST))
        {
                LOG_ERROR("BUG: requested SRST assertion, but the current configuration doesn't support this");
-               jtag_error=ERROR_FAIL;
+               jtag_set_error(ERROR_FAIL);
                return;
        }
 
@@ -741,10 +704,10 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst)
 
        jtag_srst = req_srst;
 
-       retval = interface_jtag_add_reset(jtag_trst, jtag_srst);
-       if (retval!=ERROR_OK)
+       int retval = interface_jtag_add_reset(jtag_trst, jtag_srst);
+       if (retval != ERROR_OK)
        {
-               jtag_error=retval;
+               jtag_set_error(retval);
                return;
        }
        jtag_execute_queue();
@@ -803,11 +766,9 @@ tap_state_t jtag_get_end_state(void)
 
 void jtag_add_sleep(u32 us)
 {
-       keep_alive(); /* we might be running on a very slow JTAG clk */
-       int retval=interface_jtag_add_sleep(us);
-       if (retval!=ERROR_OK)
-               jtag_error=retval;
-       return;
+       /// @todo Here, keep_alive() appears to be a layering violation!!!
+       keep_alive();
+       jtag_set_error(interface_jtag_add_sleep(us));
 }
 
 int jtag_check_value_inner(u8 *captured, u8 *in_check_value, u8 *in_check_mask, int num_bits)
@@ -892,17 +853,8 @@ int default_interface_jtag_execute_queue(void)
 
 void jtag_execute_queue_noclear(void)
 {
-       /* each flush can take as much as 1-2ms on high bandwidth low latency interfaces.
-        * E.g. a JTAG over TCP/IP or USB....
-        */
        jtag_flush_queue_count++;
-
-       int retval=interface_jtag_execute_queue();
-       /* we keep the first error */
-       if ((jtag_error==ERROR_OK)&&(retval!=ERROR_OK))
-       {
-               jtag_error=retval;
-       }
+       jtag_set_error(interface_jtag_execute_queue());
 }
 
 int jtag_get_flush_queue_count(void)
@@ -912,11 +864,8 @@ int jtag_get_flush_queue_count(void)
 
 int jtag_execute_queue(void)
 {
-       int retval;
        jtag_execute_queue_noclear();
-       retval=jtag_error;
-       jtag_error=ERROR_OK;
-       return retval;
+       return jtag_error_clear();
 }
 
 static int jtag_reset_callback(enum jtag_event event, void *priv)
@@ -946,109 +895,168 @@ void jtag_sleep(u32 us)
 #define EXTRACT_PART(X) (((X) & 0xffff000) >> 12)
 #define EXTRACT_VER(X)  (((X) & 0xf0000000) >> 28)
 
-/* Try to examine chain layout according to IEEE 1149.1 ยง12
- */
-static int jtag_examine_chain(void)
+static int jtag_examine_chain_execute(u8 *idcode_buffer, unsigned num_idcode)
+{
+       scan_field_t field = {
+                       .tap = NULL,
+                       .num_bits = num_idcode * 32,
+                       .out_value = idcode_buffer,
+                       .in_value = idcode_buffer,
+               };
+
+       // initialize to the end of chain ID value
+       for (unsigned i = 0; i < JTAG_MAX_CHAIN_SIZE; i++)
+               buf_set_u32(idcode_buffer, i * 32, 32, 0x000000FF);
+
+       jtag_add_plain_dr_scan(1, &field, TAP_RESET);
+       return jtag_execute_queue();
+}
+
+static bool jtag_examine_chain_check(u8 *idcodes, unsigned count)
 {
-       jtag_tap_t *tap;
-       scan_field_t field;
-       u8 idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4];
-       int i;
-       int bit_count;
-       int device_count = 0;
        u8 zero_check = 0x0;
        u8 one_check = 0xff;
 
-       field.tap = NULL;
-       field.num_bits = sizeof(idcode_buffer) * 8;
-       field.out_value = idcode_buffer;
-
-       field.in_value = idcode_buffer;
+       for (unsigned i = 0; i < count * 4; i++)
+       {
+               zero_check |= idcodes[i];
+               one_check &= idcodes[i];
+       }
 
+       /* if there wasn't a single non-zero bit or if all bits were one,
+        * the scan is not valid */
+       if (zero_check == 0x00 || one_check == 0xff)
+       {
+               LOG_ERROR("JTAG communication failure: check connection, "
+                       "JTAG interface, target power etc.");
+               return false;
+       }
+       return true;
+}
 
+static void jtag_examine_chain_display(enum log_levels level, const char *msg,
+               const char *name, u32 idcode)
+{
+       log_printf_lf(level, __FILE__, __LINE__, __FUNCTION__,
+                       "JTAG tap: %s %16.16s: 0x%08x "
+                       "(mfg: 0x%3.3x, part: 0x%4.4x, ver: 0x%1.1x)",
+               name, msg, idcode,
+               EXTRACT_MFG(idcode), EXTRACT_PART(idcode), EXTRACT_VER(idcode) );
+}
 
+static bool jtag_idcode_is_final(u32 idcode)
+{
+               return idcode == 0x000000FF || idcode == 0xFFFFFFFF;
+}
 
-       for (i = 0; i < JTAG_MAX_CHAIN_SIZE; i++)
+/**
+ * This helper checks that remaining bits in the examined chain data are
+ * all as expected, but a single JTAG device requires only 64 bits to be
+ * read back correctly.  This can help identify and diagnose problems
+ * with the JTAG chain earlier, gives more helpful/explicit error messages.
+ */
+static void jtag_examine_chain_end(u8 *idcodes, unsigned count, unsigned max)
+{
+       bool triggered = false;
+       for ( ; count < max - 31; count += 32)
        {
-               buf_set_u32(idcode_buffer, i * 32, 32, 0x000000FF);
+               u32 idcode = buf_get_u32(idcodes, count, 32);
+               // do not trigger the warning if the data looks good
+               if (!triggered && jtag_idcode_is_final(idcode))
+                       continue;
+               LOG_WARNING("Unexpected idcode after end of chain: %d 0x%08x",
+                               count, idcode);
+               triggered = true;
        }
+}
 
-       jtag_add_plain_dr_scan(1, &field, TAP_RESET);
-       jtag_execute_queue();
+static bool jtag_examine_chain_match_tap(const struct jtag_tap_s *tap)
+{
+       if (0 == tap->expected_ids_cnt)
+       {
+               /// @todo Enable LOG_INFO to ask for reports about unknown TAP IDs.
+#if 0
+               LOG_INFO("Uknown JTAG TAP ID: 0x%08x", tap->idcode)
+               LOG_INFO("Please report the chip name and reported ID code to the openocd project");
+#endif
+               return true;
+       }
 
-       for (i = 0; i < JTAG_MAX_CHAIN_SIZE * 4; i++)
+       /* Loop over the expected identification codes and test for a match */
+       u8 ii;
+       for (ii = 0; ii < tap->expected_ids_cnt; ii++)
        {
-               zero_check |= idcode_buffer[i];
-               one_check &= idcode_buffer[i];
+               if (tap->idcode == tap->expected_ids[ii])
+                       break;
        }
 
-       /* if there wasn't a single non-zero bit or if all bits were one, the scan isn't valid */
-       if ((zero_check == 0x00) || (one_check == 0xff))
+       /* If none of the expected ids matched, log an error */
+       if (ii != tap->expected_ids_cnt)
        {
-               LOG_ERROR("JTAG communication failure, check connection, JTAG interface, target power etc.");
-               return ERROR_JTAG_INIT_FAILED;
+               LOG_INFO("JTAG Tap/device matched");
+               return true;
+       }
+       jtag_examine_chain_display(LOG_LVL_ERROR, "got",
+                       tap->dotted_name, tap->idcode);
+       for (ii = 0; ii < tap->expected_ids_cnt; ii++)
+       {
+               char msg[32];
+               snprintf(msg, sizeof(msg), "expected %hhu of %hhu",
+                               ii + 1, tap->expected_ids_cnt);
+               jtag_examine_chain_display(LOG_LVL_ERROR, msg,
+                               tap->dotted_name, tap->expected_ids[ii]);
        }
+       return false;
+}
+
+/* Try to examine chain layout according to IEEE 1149.1 ยง12
+ */
+static int jtag_examine_chain(void)
+{
+       u8 idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4];
+       unsigned device_count = 0;
+
+       jtag_examine_chain_execute(idcode_buffer, JTAG_MAX_CHAIN_SIZE);
+
+       if (!jtag_examine_chain_check(idcode_buffer, JTAG_MAX_CHAIN_SIZE))
+               return ERROR_JTAG_INIT_FAILED;
 
        /* point at the 1st tap */
-       tap = jtag_tap_next_enabled(NULL);
-       if( tap == NULL ){
+       jtag_tap_t *tap = jtag_tap_next_enabled(NULL);
+       if (tap == NULL)
+       {
                LOG_ERROR("JTAG: No taps enabled?");
                return ERROR_JTAG_INIT_FAILED;
        }
 
-       for (bit_count = 0; bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31;)
+       for (unsigned bit_count = 0; bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31;)
        {
                u32 idcode = buf_get_u32(idcode_buffer, bit_count, 32);
                if ((idcode & 1) == 0)
                {
                        /* LSB must not be 0, this indicates a device in bypass */
                        LOG_WARNING("Tap/Device does not have IDCODE");
-                       idcode=0;
+                       idcode = 0;
 
                        bit_count += 1;
                }
                else
                {
-                       u32 manufacturer;
-                       u32 part;
-                       u32 version;
-
-                       /* some devices, such as AVR will output all 1's instead of TDI
-                       input value at end of chain. */
-                       if ((idcode == 0x000000FF)||(idcode == 0xFFFFFFFF))
+                       /*
+                        * End of chain (invalid manufacturer ID) some devices, such
+                        * as AVR will output all 1's instead of TDI input value at
+                        * end of chain.
+                        */
+                       if (jtag_idcode_is_final(idcode))
                        {
-                               int unexpected=0;
-                               /* End of chain (invalid manufacturer ID)
-                                *
-                                * The JTAG examine is the very first thing that happens
-                                *
-                                * A single JTAG device requires only 64 bits to be read back correctly.
-                                *
-                                * The code below adds a check that the rest of the data scanned (640 bits)
-                                * are all as expected. This helps diagnose/catch problems with the JTAG chain
-                                *
-                                * earlier and gives more helpful/explicit error messages.
-                                */
-                               for (bit_count += 32; bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31;bit_count += 32)
-                               {
-                                       idcode = buf_get_u32(idcode_buffer, bit_count, 32);
-                                       if (unexpected||((idcode != 0x000000FF)&&(idcode != 0xFFFFFFFF)))
-                                       {
-                                               LOG_WARNING("Unexpected idcode after end of chain! %d 0x%08x", bit_count, idcode);
-                                               unexpected = 1;
-                                       }
-                               }
-
+                               jtag_examine_chain_end(idcode_buffer,
+                                               bit_count + 32, JTAG_MAX_CHAIN_SIZE * 32);
                                break;
                        }
 
-                       manufacturer = EXTRACT_MFG(idcode);
-                       part = EXTRACT_PART(idcode);
-                       version = EXTRACT_VER(idcode);
-
-                       LOG_INFO("JTAG tap: %s tap/device found: 0x%8.8x (Manufacturer: 0x%3.3x, Part: 0x%4.4x, Version: 0x%1.1x)",
-                                        ((tap != NULL) ? (tap->dotted_name) : "(not-named)"),
-                               idcode, manufacturer, part, version);
+                       jtag_examine_chain_display(LOG_LVL_INFO, "tap/device found",
+                                       tap ? tap->dotted_name : "(not-named)",
+                                       idcode);
 
                        bit_count += 32;
                }
@@ -1058,57 +1066,21 @@ static int jtag_examine_chain(void)
 
                tap->idcode = idcode;
 
-               if (0 == tap->expected_ids_cnt)
-               {
-                       // @todo Enable LOG_INFO to ask for reports about unknown TAP IDs.
-#if 0
-                       LOG_INFO("Uknown JTAG TAP ID: 0x%08x", tap->idcode)
-                       LOG_INFO("Please report the chip name and reported ID code to the openocd project");
-#endif
-                       tap = jtag_tap_next_enabled(tap);
-                       continue;
-               }
-                       /* Loop over the expected identification codes and test for a match */
-               u8 ii;
-               for (ii = 0; ii < tap->expected_ids_cnt; ii++) {
-                       if (tap->idcode == tap->expected_ids[ii]) {
-                               break;
-                       }
-               }
-
-               /* If none of the expected ids matched, log an error */
-               if (ii == tap->expected_ids_cnt) {
-                       LOG_ERROR("JTAG tap: %s             got: 0x%08x (mfg: 0x%3.3x, part: 0x%4.4x, ver: 0x%1.1x)",
-                                         tap->dotted_name,
-                                         idcode,
-                                         EXTRACT_MFG( tap->idcode ),
-                                         EXTRACT_PART( tap->idcode ),
-                                         EXTRACT_VER( tap->idcode ) );
-                       for (ii = 0; ii < tap->expected_ids_cnt; ii++) {
-                               LOG_ERROR("JTAG tap: %s expected %hhu of %hhu: 0x%08x (mfg: 0x%3.3x, part: 0x%4.4x, ver: 0x%1.1x)",
-                                                 tap->dotted_name,
-                                                 ii + 1,
-                                                 tap->expected_ids_cnt,
-                                                 tap->expected_ids[ii],
-                                                 EXTRACT_MFG( tap->expected_ids[ii] ),
-                                                 EXTRACT_PART( tap->expected_ids[ii] ),
-                                                 EXTRACT_VER( tap->expected_ids[ii] ) );
-                       }
-
+               // ensure the TAP ID does matches what was expected
+               if (!jtag_examine_chain_match_tap(tap))
                        return ERROR_JTAG_INIT_FAILED;
-               } else {
-                       LOG_INFO("JTAG Tap/device matched");
-               }
-               
+
                tap = jtag_tap_next_enabled(tap);
        }
 
        /* see if number of discovered devices matches configuration */
        if (device_count != jtag_tap_count_enabled())
        {
-               LOG_ERROR("number of discovered devices in JTAG chain (%i) doesn't match (enabled) configuration (%i), total taps: %d",
-                                 device_count, jtag_tap_count_enabled(), jtag_tap_count());
-               LOG_ERROR("check the config file and ensure proper JTAG communication (connections, speed, ...)");
+               LOG_ERROR("number of discovered devices in JTAG chain (%i) "
+                               "does not match (enabled) configuration (%i), total taps: %d",
+                               device_count, jtag_tap_count_enabled(), jtag_tap_count());
+               LOG_ERROR("check the config file and ensure proper JTAG communication"
+                               " (connections, speed, ...)");
                return ERROR_JTAG_INIT_FAILED;
        }
 
@@ -1612,6 +1584,9 @@ 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,
+               "interface_list", &handle_interface_list_command,
+               COMMAND_ANY, "list all built-in interfaces");
        register_command(cmd_ctx, NULL, "jtag_speed", handle_jtag_speed_command,
                COMMAND_ANY, "(DEPRECATED) set jtag speed (if supported)");
        register_command(cmd_ctx, NULL, "jtag_khz", handle_jtag_khz_command,
@@ -1630,8 +1605,6 @@ int jtag_register_commands(struct command_context_s *cmd_ctx)
        register_command(cmd_ctx, NULL, "scan_chain", handle_scan_chain_command,
                COMMAND_EXEC, "print current scan chain configuration");
 
-       register_command(cmd_ctx, NULL, "endstate", handle_endstate_command,
-               COMMAND_EXEC, "finish JTAG operations in <tap_state>");
        register_command(cmd_ctx, NULL, "jtag_reset", handle_jtag_reset_command,
                COMMAND_EXEC, "toggle reset lines <trst> <srst>");
        register_command(cmd_ctx, NULL, "runtest", handle_runtest_command,
@@ -1809,11 +1782,9 @@ static int default_srst_asserted(int *srst_asserted)
        return ERROR_OK;
 }
 
-static int handle_interface_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+static int handle_interface_command(struct command_context_s *cmd_ctx,
+               char *cmd, char **args, int argc)
 {
-       int i;
-       int retval;
-
        /* check whether the interface is already configured */
        if (jtag_interface)
        {
@@ -1822,54 +1793,54 @@ static int handle_interface_command(struct command_context_s *cmd_ctx, char *cmd
        }
 
        /* interface name is a mandatory argument */
-       if (argc < 1 || args[0][0] == '\0')
-       {
+       if (argc != 1 || args[0][0] == '\0')
                return ERROR_COMMAND_SYNTAX_ERROR;
-       }
 
-       for (i=0; jtag_interfaces[i]; i++)
+       for (unsigned i = 0; NULL != jtag_interfaces[i]; i++)
        {
-               if (strcmp(args[0], jtag_interfaces[i]->name) == 0)
-               {
-                       if ((retval = jtag_interfaces[i]->register_commands(cmd_ctx)) != ERROR_OK)
-                       {
+               if (strcmp(args[0], jtag_interfaces[i]->name) != 0)
+                       continue;
+
+               int retval = jtag_interfaces[i]->register_commands(cmd_ctx);
+               if (ERROR_OK != retval)
                                return retval;
-                       }
 
-                       jtag_interface = jtag_interfaces[i];
+               jtag_interface = jtag_interfaces[i];
 
-                       if (jtag_interface->khz == NULL)
-                       {
-                               jtag_interface->khz = default_khz;
-                       }
-                       if (jtag_interface->speed_div == NULL)
-                       {
-                               jtag_interface->speed_div = default_speed_div;
-                       }
-                       if (jtag_interface->power_dropout == NULL)
-                       {
-                               jtag_interface->power_dropout = default_power_dropout;
-                       }
-                       if (jtag_interface->srst_asserted == NULL)
-                       {
-                               jtag_interface->srst_asserted = default_srst_asserted;
-                       }
+               if (jtag_interface->khz == NULL)
+                       jtag_interface->khz = default_khz;
+               if (jtag_interface->speed_div == NULL)
+                       jtag_interface->speed_div = default_speed_div;
+               if (jtag_interface->power_dropout == NULL)
+                       jtag_interface->power_dropout = default_power_dropout;
+               if (jtag_interface->srst_asserted == NULL)
+                       jtag_interface->srst_asserted = default_srst_asserted;
 
-                       return ERROR_OK;
-               }
+               return ERROR_OK;
        }
 
        /* no valid interface was found (i.e. the configuration option,
         * didn't match one of the compiled-in interfaces
         */
-       LOG_ERROR("No valid jtag interface found (%s)", args[0]);
-       LOG_ERROR("compiled-in jtag interfaces:");
-       for (i = 0; jtag_interfaces[i]; i++)
+       LOG_ERROR("The specified JTAG interface was not found (%s)", args[0]);
+       handle_interface_list_command(cmd_ctx, cmd, args, argc);
+       return ERROR_JTAG_INVALID_INTERFACE;
+}
+
+static int handle_interface_list_command(struct command_context_s *cmd_ctx,
+               char *cmd, char **args, int argc)
+{
+       if (strcmp(cmd, "interface_list") == 0 && argc > 0)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       command_print(cmd_ctx, "The following JTAG interfaces are available:");
+       for (unsigned i = 0; NULL != jtag_interfaces[i]; i++)
        {
-               LOG_ERROR("%i: %s", i, jtag_interfaces[i]->name);
+               const char *name = jtag_interfaces[i]->name;
+               command_print(cmd_ctx, "%u: %s", i + 1, name);
        }
 
-       return ERROR_JTAG_INVALID_INTERFACE;
+       return ERROR_OK;
 }
 
 static int handle_jtag_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
@@ -2080,41 +2051,34 @@ next:
        return ERROR_OK;
 }
 
-static int handle_jtag_nsrst_delay_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+static int handle_jtag_nsrst_delay_command(struct command_context_s *cmd_ctx,
+               char *cmd, char **args, int argc)
 {
-       if (argc < 1)
-       {
-               LOG_ERROR("jtag_nsrst_delay <ms> command takes one required argument");
-               exit(-1);
-       }
-       else
-       {
+       if (argc > 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       if (argc == 1)
                jtag_set_nsrst_delay(strtoul(args[0], NULL, 0));
-       }
-
+       command_print(cmd_ctx, "jtag_nsrst_delay: %u", jtag_get_nsrst_delay());
        return ERROR_OK;
 }
 
-static int handle_jtag_ntrst_delay_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+static int handle_jtag_ntrst_delay_command(struct command_context_s *cmd_ctx,
+               char *cmd, char **args, int argc)
 {
-       if (argc < 1)
-       {
-               LOG_ERROR("jtag_ntrst_delay <ms> command takes one required argument");
-               exit(-1);
-       }
-       else
-       {
+       if (argc > 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       if (argc == 1)
                jtag_set_ntrst_delay(strtoul(args[0], NULL, 0));
-       }
-
+       command_print(cmd_ctx, "jtag_ntrst_delay: %u", jtag_get_ntrst_delay());
        return ERROR_OK;
 }
 
-
 static int handle_jtag_speed_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
 {
-       int retval=ERROR_OK;
+       int retval = ERROR_OK;
 
+       if (argc > 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
        if (argc == 1)
        {
                LOG_DEBUG("handle jtag speed");
@@ -2125,14 +2089,7 @@ static int handle_jtag_speed_command(struct command_context_s *cmd_ctx, char *cm
                /* this command can be called during CONFIG,
                 * in which case jtag isn't initialized */
                if (jtag)
-               {
-                       retval=jtag->speed(cur_speed);
-               }
-       } else if (argc == 0)
-       {
-       } else
-       {
-               return ERROR_COMMAND_SYNTAX_ERROR;
+                       retval = jtag->speed(cur_speed);
        }
        command_print(cmd_ctx, "jtag_speed: %d", jtag_speed);
 
@@ -2141,41 +2098,39 @@ static int handle_jtag_speed_command(struct command_context_s *cmd_ctx, char *cm
 
 static int handle_jtag_khz_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
 {
-       int retval=ERROR_OK;
-       LOG_DEBUG("handle jtag khz");
+       if (argc > 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
 
+       int retval = ERROR_OK;
        int cur_speed = 0;
-       if(argc == 1)
+       if (argc == 1)
        {
+               LOG_DEBUG("handle jtag khz");
+
                jtag_set_speed_khz(strtoul(args[0], NULL, 0));
                if (jtag != NULL)
                {
                        LOG_DEBUG("have interface set up");
                        int speed_div1;
-                       if ((retval=jtag->khz(jtag_get_speed_khz(), &speed_div1))!=ERROR_OK)
+                       retval = jtag->khz(jtag_get_speed_khz(), &speed_div1);
+                       if (ERROR_OK != retval)
                        {
                                jtag_set_speed_khz(0);
                                return retval;
                        }
-
                        cur_speed = jtag_speed = speed_div1;
 
-                       retval=jtag->speed(cur_speed);
-               } else
-               {
-                       hasKHz = true;
+                       retval = jtag->speed(cur_speed);
                }
-       } else if (argc==0)
-       {
-       } else
-       {
-               return ERROR_COMMAND_SYNTAX_ERROR;
+               else
+                       hasKHz = true;
        }
-       cur_speed = jtag_get_speed_khz();
 
-       if (jtag!=NULL)
+       cur_speed = jtag_get_speed_khz();
+       if (jtag != NULL)
        {
-               if ((retval=jtag->speed_div(jtag_speed, &cur_speed))!=ERROR_OK)
+               retval = jtag->speed_div(jtag_speed, &cur_speed);
+               if (ERROR_OK != retval)
                        return retval;
        }
 
@@ -2187,53 +2142,27 @@ static int handle_jtag_khz_command(struct command_context_s *cmd_ctx, char *cmd,
 
 }
 
-static int handle_endstate_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+static int handle_jtag_reset_command(struct command_context_s *cmd_ctx,
+               char *cmd, char **args, int argc)
 {
-       if (argc < 1)
+       if (argc != 2)
                return ERROR_COMMAND_SYNTAX_ERROR;
 
-       tap_state_t state = tap_state_by_name(args[0]);
-       if (state < 0)
-       {
-               command_print( cmd_ctx, "Invalid state name: %s\n", args[0] );
-               return ERROR_COMMAND_SYNTAX_ERROR;
-       }
-       jtag_set_end_state(state);
-       jtag_execute_queue();
-
-       command_print(cmd_ctx, "current endstate: %s",
-                       tap_state_name(cmd_queue_end_state));
-
-       return ERROR_OK;
-}
-
-static int handle_jtag_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
        int trst = -1;
-       int srst = -1;
-
-       if (argc < 2)
-       {
-               return ERROR_COMMAND_SYNTAX_ERROR;
-       }
-
        if (args[0][0] == '1')
                trst = 1;
        else if (args[0][0] == '0')
                trst = 0;
        else
-       {
                return ERROR_COMMAND_SYNTAX_ERROR;
-       }
 
+       int srst = -1;
        if (args[1][0] == '1')
                srst = 1;
        else if (args[1][0] == '0')
                srst = 0;
        else
-       {
                return ERROR_COMMAND_SYNTAX_ERROR;
-       }
 
        if (jtag_interface_init(cmd_ctx) != ERROR_OK)
                return ERROR_JTAG_INIT_FAILED;
@@ -2244,18 +2173,16 @@ static int handle_jtag_reset_command(struct command_context_s *cmd_ctx, char *cm
        return ERROR_OK;
 }
 
-static int handle_runtest_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+static int handle_runtest_command(struct command_context_s *cmd_ctx,
+               char *cmd, char **args, int argc)
 {
-       if (argc < 1)
-       {
+       if (argc != 1)
                return ERROR_COMMAND_SYNTAX_ERROR;
-       }
 
        jtag_add_runtest(strtol(args[0], NULL, 0), jtag_get_end_state());
        jtag_execute_queue();
 
        return ERROR_OK;
-
 }
 
 /*
@@ -2623,61 +2550,55 @@ static int handle_tms_sequence_command(struct command_context_s *cmd_ctx, char *
 }
 
 /**
- * Function jtag_add_statemove
- * moves from the current state to the goal \a state. This needs
+ * 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 @a 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.
+ *
+ * Otherwise, state must be immediately reachable in one clock cycle,
+ * and does not need to be a stable state.
  */
 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) );
+               unsigned tms_bits  = tap_get_tms_path(cur_state, goal_state);
+               unsigned tms_count = tap_get_tms_path_len(cur_state, goal_state);
+               tap_state_t moves[8];
+               assert(tms_count < DIM(moves));
 
-               for (i=0;   i<tms_count;   i++, tms_bits>>=1)
+               for (unsigned i = 0; i < tms_count; i++, tms_bits >>= 1)
                {
                        bool bit = tms_bits & 1;
 
@@ -2687,33 +2608,31 @@ int jtag_add_statemove(tap_state_t goal_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 );
+               jtag_add_pathmove(1, &goal_state);
        }
 
        else
-       {
-               retval = ERROR_FAIL;
-       }
+               return ERROR_FAIL;
 
-       return retval;
+       return ERROR_OK;
 }
 
 void jtag_set_nsrst_delay(unsigned delay)
 {
        jtag_nsrst_delay = delay;
 }
+unsigned jtag_get_nsrst_delay(void)
+{
+       return jtag_nsrst_delay;
+}
 void jtag_set_ntrst_delay(unsigned delay)
 {
        jtag_ntrst_delay = delay;
 }
-
-
+unsigned jtag_get_ntrst_delay(void)
+{
+       return jtag_ntrst_delay;
+}