Introduced jtag_init and "jtag arp_init" to allow target scripts more control over...
[openocd.git] / src / jtag / core.c
index 58c8e3415d347a47fc813a92490d22552ed00c47..854236f3d15346d31b5d3bba24e89c4803ff34ea 100644 (file)
@@ -1,16 +1,16 @@
 /***************************************************************************
- *   Copyright (C) 2005 by Dominic Rath                                    *
- *   Dominic.Rath@gmx.de                                                   *
+ *   Copyright (C) 2009 Zachary T Welch                                    *
+ *   zw@superlucidity.net                                                  *
  *                                                                         *
- *   Copyright (C) 2007,2008 Øyvind Harboe                                 *
+ *   Copyright (C) 2007,2008,2009 Øyvind Harboe                            *
  *   oyvind.harboe@zylin.com                                               *
  *                                                                         *
  *   Copyright (C) 2009 SoftPLC Corporation                                *
  *       http://softplc.com                                                *
  *   dick@softplc.com                                                      *
  *                                                                         *
- *   Copyright (C) 2009 Zachary T Welch                                    *
- *   zw@superlucidity.net                                                  *
+ *   Copyright (C) 2005 by Dominic Rath                                    *
+ *   Dominic.Rath@gmx.de                                                   *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   it under the terms of the GNU General Public License as published by  *
@@ -60,11 +60,16 @@ static int jtag_error = ERROR_OK;
 
 static const char *jtag_event_strings[] =
 {
-       [JTAG_TRST_ASSERTED] = "JTAG controller reset (RESET or TRST)",
+       [JTAG_TRST_ASSERTED] = "TAP reset",
+       [JTAG_TAP_EVENT_SETUP] = "TAP setup",
        [JTAG_TAP_EVENT_ENABLE] = "TAP enabled",
        [JTAG_TAP_EVENT_DISABLE] = "TAP disabled",
 };
 
+/*
+ * JTAG adapters must initialize with TRST and SRST de-asserted
+ * (they're negative logic, so that means *high*)
+ */
 static int jtag_trst = 0;
 static int jtag_srst = 0;
 
@@ -88,6 +93,8 @@ static int jtag_verify = 1;
 /* how long the OpenOCD should wait before attempting JTAG communication after reset lines deasserted (in ms) */
 static int jtag_nsrst_delay = 0; /* default to no nSRST delay */
 static int jtag_ntrst_delay = 0; /* default to no nTRST delay */
+static int jtag_nsrst_assert_width = 0; /* width of assertion */
+static int jtag_ntrst_assert_width = 0; /* width of assertion */
 
 typedef struct jtag_event_callback_s
 {
@@ -101,8 +108,9 @@ static jtag_event_callback_t *jtag_event_callbacks;
 
 /* speed in kHz*/
 static int speed_khz = 0;
-/* flag if the kHz speed was defined */
-static bool hasKHz = false;
+/* speed to fallback to when RCLK is requested but not supported */
+static int rclk_fallback_speed_khz = 0;
+static enum {CLOCK_MODE_SPEED, CLOCK_MODE_KHZ, CLOCK_MODE_RCLK} clock_mode;
 static int jtag_speed = 0;
 
 static struct jtag_interface_s *jtag = NULL;
@@ -162,10 +170,22 @@ void jtag_tap_add(struct jtag_tap_s *t)
        *tap = t;
 }
 
+/* returns a pointer to the n-th device in the scan chain */
+static inline jtag_tap_t *jtag_tap_by_position(unsigned n)
+{
+       jtag_tap_t *t = jtag_all_taps();
+
+       while (t && n-- > 0)
+               t = t->next_tap;
+
+       return t;
+}
+
 jtag_tap_t *jtag_tap_by_string(const char *s)
 {
        /* try by name first */
        jtag_tap_t *t = jtag_all_taps();
+
        while (t)
        {
                if (0 == strcmp(t->dotted_name, s))
@@ -178,7 +198,16 @@ jtag_tap_t *jtag_tap_by_string(const char *s)
        if (parse_uint(s, &n) != ERROR_OK)
                return NULL;
 
-       return jtag_tap_by_position(n);
+       /* FIXME remove this numeric fallback code late June 2010, along
+        * with all info in the User's Guide that TAPs have numeric IDs.
+        * Also update "scan_chain" output to not display the numbers.
+        */
+       t = jtag_tap_by_position(n);
+       if (t)
+               LOG_WARNING("Specify TAP '%s' by name, not number %u",
+                       t->dotted_name, n);
+
+       return t;
 }
 
 jtag_tap_t *jtag_tap_by_jim_obj(Jim_Interp *interp, Jim_Obj *o)
@@ -192,17 +221,6 @@ jtag_tap_t *jtag_tap_by_jim_obj(Jim_Interp *interp, Jim_Obj *o)
        return t;
 }
 
-/* returns a pointer to the n-th device in the scan chain */
-jtag_tap_t *jtag_tap_by_position(unsigned n)
-{
-       jtag_tap_t *t = jtag_all_taps();
-
-       while (t && n-- > 0)
-               t = t->next_tap;
-
-       return t;
-}
-
 jtag_tap_t* jtag_tap_next_enabled(jtag_tap_t* p)
 {
        p = p ? p->next_tap : jtag_all_taps();
@@ -324,6 +342,8 @@ void jtag_add_ir_scan_noverify(int in_count, const scan_field_t *in_fields,
 
 void jtag_add_ir_scan(int in_num_fields, scan_field_t *in_fields, tap_state_t state)
 {
+       assert(state != TAP_RESET);
+
        if (jtag_verify && jtag_verify_capture_ir)
        {
                /* 8 x 32 bit id's is enough for all invocations */
@@ -346,6 +366,8 @@ void jtag_add_ir_scan(int in_num_fields, scan_field_t *in_fields, tap_state_t st
 void jtag_add_plain_ir_scan(int in_num_fields, const scan_field_t *in_fields,
                tap_state_t state)
 {
+       assert(state != TAP_RESET);
+
        jtag_prelude(state);
 
        int retval = interface_jtag_add_plain_ir_scan(
@@ -365,7 +387,8 @@ void jtag_add_callback4(jtag_callback_t f, jtag_callback_data_t data0,
        interface_jtag_add_callback4(f, data0, data1, data2, data3);
 }
 
-int jtag_check_value_inner(uint8_t *captured, uint8_t *in_check_value, uint8_t *in_check_mask, int num_bits);
+static int jtag_check_value_inner(uint8_t *captured, uint8_t *in_check_value,
+               uint8_t *in_check_mask, int num_bits);
 
 static int jtag_check_value_mask_callback(jtag_callback_data_t data0, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3)
 {
@@ -424,6 +447,8 @@ void jtag_add_dr_scan_check(int in_num_fields, scan_field_t *in_fields, tap_stat
 void jtag_add_dr_scan(int in_num_fields, const scan_field_t *in_fields,
                tap_state_t state)
 {
+       assert(state != TAP_RESET);
+
        jtag_prelude(state);
 
        int retval;
@@ -434,6 +459,8 @@ void jtag_add_dr_scan(int in_num_fields, const scan_field_t *in_fields,
 void jtag_add_plain_dr_scan(int in_num_fields, const scan_field_t *in_fields,
                tap_state_t state)
 {
+       assert(state != TAP_RESET);
+
        jtag_prelude(state);
 
        int retval;
@@ -445,6 +472,7 @@ void jtag_add_dr_out(jtag_tap_t* tap,
                int num_fields, const int* num_bits, const uint32_t* value,
                tap_state_t end_state)
 {
+       assert(end_state != TAP_RESET);
        assert(end_state != TAP_INVALID);
 
        cmd_queue_cur_state = end_state;
@@ -458,7 +486,10 @@ void jtag_add_tlr(void)
 {
        jtag_prelude(TAP_RESET);
        jtag_set_error(interface_jtag_add_tlr());
+
+       /* NOTE: order here matches TRST path in jtag_add_reset() */
        jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
+       jtag_notify_event(JTAG_TRST_ASSERTED);
 }
 
 void jtag_add_pathmove(int num_states, const tap_state_t *path)
@@ -505,16 +536,16 @@ int jtag_add_statemove(tap_state_t goal_state)
 
        LOG_DEBUG("cur_state=%s goal_state=%s",
                tap_state_name(cur_state),
-               tap_state_name(goal_state) );
+               tap_state_name(goal_state));
 
 
-       if (goal_state == cur_state )
+       if (goal_state == cur_state)
                ;       /* nothing to do */
-       else if (goal_state == TAP_RESET )
+       else if (goal_state == TAP_RESET)
        {
                jtag_add_tlr();
        }
-       else if (tap_is_state_stable(cur_state) && tap_is_state_stable(goal_state) )
+       else if (tap_is_state_stable(cur_state) && tap_is_state_stable(goal_state))
        {
                unsigned tms_bits  = tap_get_tms_path(cur_state, goal_state);
                unsigned tms_count = tap_get_tms_path_len(cur_state, goal_state);
@@ -532,7 +563,7 @@ int jtag_add_statemove(tap_state_t goal_state)
                jtag_add_pathmove(tms_count, moves);
        }
        else if (tap_state_transition(cur_state, true)  == goal_state
-               ||   tap_state_transition(cur_state, false) == goal_state )
+               ||   tap_state_transition(cur_state, false) == goal_state)
        {
                jtag_add_pathmove(1, &goal_state);
        }
@@ -570,102 +601,111 @@ void jtag_add_clocks(int num_cycles)
 void jtag_add_reset(int req_tlr_or_trst, int req_srst)
 {
        int trst_with_tlr = 0;
+       int new_srst = 0;
+       int new_trst = 0;
 
-       /* FIX!!! there are *many* different cases here. A better
-        * approach is needed for legal combinations of transitions...
+       /* Without SRST, we must use target-specific JTAG operations
+        * on each target; callers should not be requesting SRST when
+        * that signal doesn't exist.
+        *
+        * RESET_SRST_PULLS_TRST is a board or chip level quirk, which
+        * can kick in even if the JTAG adapter can't drive TRST.
         */
-       if ((jtag_reset_config & RESET_HAS_SRST)&&
-                       (jtag_reset_config & RESET_HAS_TRST)&&
-                       ((jtag_reset_config & RESET_SRST_PULLS_TRST) == 0))
-       {
-               if (((req_tlr_or_trst&&!jtag_trst)||
-                               (!req_tlr_or_trst && jtag_trst))&&
-                               ((req_srst&&!jtag_srst)||
-                                               (!req_srst && jtag_srst)))
-               {
-                       /* FIX!!! srst_pulls_trst allows 1,1 => 0,0 transition.... */
-                       //LOG_ERROR("BUG: transition of req_tlr_or_trst and req_srst in the same jtag_add_reset() call is undefined");
+       if (req_srst) {
+               if (!(jtag_reset_config & RESET_HAS_SRST)) {
+                       LOG_ERROR("BUG: can't assert SRST");
+                       jtag_set_error(ERROR_FAIL);
+                       return;
+               }
+               if ((jtag_reset_config & RESET_SRST_PULLS_TRST) != 0
+                               && !req_tlr_or_trst) {
+                       LOG_ERROR("BUG: can't assert only SRST");
+                       jtag_set_error(ERROR_FAIL);
+                       return;
                }
+               new_srst = 1;
        }
 
-       /* Make sure that jtag_reset_config allows the requested reset */
-       /* if SRST pulls TRST, we can't fulfill srst == 1 with trst == 0 */
-       if (((jtag_reset_config & RESET_SRST_PULLS_TRST) && (req_srst == 1)) && (!req_tlr_or_trst))
-       {
-               LOG_ERROR("BUG: requested reset would assert trst");
-               jtag_set_error(ERROR_FAIL);
-               return;
+       /* JTAG reset (entry to TAP_RESET state) can always be achieved
+        * using TCK and TMS; that may go through a TAP_{IR,DR}UPDATE
+        * state first.  TRST accelerates it, and bypasses those states.
+        *
+        * RESET_TRST_PULLS_SRST is a board or chip level quirk, which
+        * can kick in even if the JTAG adapter can't drive SRST.
+        */
+       if (req_tlr_or_trst) {
+               if (!(jtag_reset_config & RESET_HAS_TRST))
+                       trst_with_tlr = 1;
+               else if ((jtag_reset_config & RESET_TRST_PULLS_SRST) != 0
+                               && !req_srst)
+                       trst_with_tlr = 1;
+               else
+                       new_trst = 1;
        }
 
-       /* if TRST pulls SRST, we reset with TAP T-L-R */
-       if (((jtag_reset_config & RESET_TRST_PULLS_SRST) && (req_tlr_or_trst)) && (req_srst == 0))
-       {
-               trst_with_tlr = 1;
-       }
+       /* Maybe change TRST and/or SRST signal state */
+       if (jtag_srst != new_srst || jtag_trst != new_trst) {
+               int retval;
 
-       if (req_srst && !(jtag_reset_config & RESET_HAS_SRST))
-       {
-               LOG_ERROR("BUG: requested SRST assertion, but the current configuration doesn't support this");
-               jtag_set_error(ERROR_FAIL);
-               return;
-       }
+               retval = interface_jtag_add_reset(new_trst, new_srst);
+               if (retval != ERROR_OK)
+                       jtag_set_error(retval);
+               else
+                       retval = jtag_execute_queue();
 
-       if (req_tlr_or_trst)
-       {
-               if (!trst_with_tlr && (jtag_reset_config & RESET_HAS_TRST))
-               {
-                       jtag_trst = 1;
-               } else
-               {
-                       trst_with_tlr = 1;
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("TRST/SRST error %d", retval);
+                       return;
                }
-       } else
-       {
-               jtag_trst = 0;
        }
 
-       jtag_srst = req_srst;
-
-       int retval = interface_jtag_add_reset(jtag_trst, jtag_srst);
-       if (retval != ERROR_OK)
-       {
-               jtag_set_error(retval);
-               return;
-       }
-       jtag_execute_queue();
-
-       if (jtag_srst)
-       {
-               LOG_DEBUG("SRST line asserted");
-       }
-       else
-       {
-               LOG_DEBUG("SRST line released");
-               if (jtag_nsrst_delay)
-                       jtag_add_sleep(jtag_nsrst_delay * 1000);
+       /* SRST resets everything hooked up to that signal */
+       if (jtag_srst != new_srst) {
+               jtag_srst = new_srst;
+               if (jtag_srst)
+               {
+                       LOG_DEBUG("SRST line asserted");
+                       if (jtag_nsrst_assert_width)
+                               jtag_add_sleep(jtag_nsrst_assert_width * 1000);
+               }
+               else {
+                       LOG_DEBUG("SRST line released");
+                       if (jtag_nsrst_delay)
+                               jtag_add_sleep(jtag_nsrst_delay * 1000);
+               }
        }
 
-       if (trst_with_tlr)
-       {
-               LOG_DEBUG("JTAG reset with RESET instead of TRST");
+       /* Maybe enter the JTAG TAP_RESET state ...
+        *  - using only TMS, TCK, and the JTAG state machine
+        *  - or else more directly, using TRST
+        *
+        * TAP_RESET should be invisible to non-debug parts of the system.
+        */
+       if (trst_with_tlr) {
+               LOG_DEBUG("JTAG reset with TLR instead of TRST");
                jtag_set_end_state(TAP_RESET);
                jtag_add_tlr();
-               return;
-       }
 
-       if (jtag_trst)
-       {
-               /* we just asserted nTRST, so we're now in Test-Logic-Reset,
-                * and inform possible listeners about this
-                */
-               LOG_DEBUG("TRST line asserted");
-               tap_set_state(TAP_RESET);
-               jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
-       }
-       else
-       {
-               if (jtag_ntrst_delay)
-                       jtag_add_sleep(jtag_ntrst_delay * 1000);
+       } else if (jtag_trst != new_trst) {
+               jtag_trst = new_trst;
+               if (jtag_trst) {
+                       LOG_DEBUG("TRST line asserted");
+                       tap_set_state(TAP_RESET);
+                       if (jtag_ntrst_assert_width)
+                               jtag_add_sleep(jtag_ntrst_assert_width * 1000);
+               } else {
+                       LOG_DEBUG("TRST line released");
+                       if (jtag_ntrst_delay)
+                               jtag_add_sleep(jtag_ntrst_delay * 1000);
+
+                       /* We just asserted nTRST, so we're now in TAP_RESET.
+                        * Inform possible listeners about this, now that
+                        * JTAG instructions and data can be shifted.  This
+                        * sequence must match jtag_add_tlr().
+                        */
+                       jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
+                       jtag_notify_event(JTAG_TRST_ASSERTED);
+               }
        }
 }
 
@@ -693,7 +733,8 @@ void jtag_add_sleep(uint32_t us)
        jtag_set_error(interface_jtag_add_sleep(us));
 }
 
-int jtag_check_value_inner(uint8_t *captured, uint8_t *in_check_value, uint8_t *in_check_mask, int num_bits)
+static int jtag_check_value_inner(uint8_t *captured, uint8_t *in_check_value,
+               uint8_t *in_check_mask, int num_bits)
 {
        int retval = ERROR_OK;
 
@@ -704,40 +745,33 @@ int jtag_check_value_inner(uint8_t *captured, uint8_t *in_check_value, uint8_t *
        else
                compare_failed = buf_cmp(captured, in_check_value, num_bits);
 
-       if (compare_failed){
-               /* An error handler could have caught the failing check
-                * only report a problem when there wasn't a handler, or if the handler
-                * acknowledged the error
-                */
-               /*
-               LOG_WARNING("TAP %s:",
-                                       jtag_tap_name(field->tap));
-                                       */
-               if (compare_failed)
-               {
-                       char *captured_char = buf_to_str(captured, (num_bits > DEBUG_JTAG_IOZ) ? DEBUG_JTAG_IOZ : num_bits, 16);
-                       char *in_check_value_char = buf_to_str(in_check_value, (num_bits > DEBUG_JTAG_IOZ) ? DEBUG_JTAG_IOZ : num_bits, 16);
-
-                       if (in_check_mask)
-                       {
-                               char *in_check_mask_char;
-                               in_check_mask_char = buf_to_str(in_check_mask, (num_bits > DEBUG_JTAG_IOZ) ? DEBUG_JTAG_IOZ : num_bits, 16);
-                               LOG_WARNING("value captured during scan didn't pass the requested check:");
-                               LOG_WARNING("captured: 0x%s check_value: 0x%s check_mask: 0x%s",
-                                                       captured_char, in_check_value_char, in_check_mask_char);
-                               free(in_check_mask_char);
-                       }
-                       else
-                       {
-                               LOG_WARNING("value captured during scan didn't pass the requested check: captured: 0x%s check_value: 0x%s", captured_char, in_check_value_char);
-                       }
-
-                       free(captured_char);
-                       free(in_check_value_char);
-
-                       retval = ERROR_JTAG_QUEUE_FAILED;
+       if (compare_failed) {
+               char *captured_str, *in_check_value_str;
+               int bits = (num_bits > DEBUG_JTAG_IOZ)
+                               ? DEBUG_JTAG_IOZ
+                               : num_bits;
+
+               /* NOTE:  we've lost diagnostic context here -- 'which tap' */
+
+               captured_str = buf_to_str(captured, bits, 16);
+               in_check_value_str = buf_to_str(in_check_value, bits, 16);
+
+               LOG_WARNING("Bad value '%s' captured during DR or IR scan:",
+                               captured_str);
+               LOG_WARNING(" check_value: 0x%s", in_check_value_str);
+
+               free(captured_str);
+               free(in_check_value_str);
+
+               if (in_check_mask) {
+                       char *in_check_mask_str;
+
+                       in_check_mask_str = buf_to_str(in_check_mask, bits, 16);
+                       LOG_WARNING(" check_mask: 0x%s", in_check_mask_str);
+                       free(in_check_mask_str);
                }
 
+               retval = ERROR_JTAG_QUEUE_FAILED;
        }
        return retval;
 }
@@ -794,12 +828,11 @@ static int jtag_reset_callback(enum jtag_event event, void *priv)
 {
        jtag_tap_t *tap = priv;
 
-       LOG_DEBUG("-");
-
        if (event == JTAG_TRST_ASSERTED)
        {
                tap->enabled = !tap->disabled_after_reset;
 
+               /* current instruction is either BYPASS or IDCODE */
                buf_set_ones(tap->cur_instr, tap->ir_length);
                tap->bypass = 1;
        }
@@ -812,13 +845,21 @@ void jtag_sleep(uint32_t us)
        alive_sleep(us/1000);
 }
 
-/// maximum number of JTAG devices expected in the chain
+/* Maximum number of enabled JTAG devices we expect in the scan chain,
+ * plus one (to detect garbage at the end).  Devices that don't support
+ * IDCODE take up fewer bits, possibly allowing a few more devices.
+ */
 #define JTAG_MAX_CHAIN_SIZE 20
 
 #define EXTRACT_MFG(X)  (((X) & 0xffe) >> 1)
 #define EXTRACT_PART(X) (((X) & 0xffff000) >> 12)
 #define EXTRACT_VER(X)  (((X) & 0xf0000000) >> 28)
 
+/* A reserved manufacturer ID is used in END_OF_CHAIN_FLAG, so we
+ * know that no valid TAP will have it as an IDCODE value.
+ */
+#define END_OF_CHAIN_FLAG      0x000000ff
+
 static int jtag_examine_chain_execute(uint8_t *idcode_buffer, unsigned num_idcode)
 {
        scan_field_t field = {
@@ -830,9 +871,10 @@ static int jtag_examine_chain_execute(uint8_t *idcode_buffer, unsigned num_idcod
 
        // 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);
+               buf_set_u32(idcode_buffer, i * 32, 32, END_OF_CHAIN_FLAG);
 
-       jtag_add_plain_dr_scan(1, &field, TAP_RESET);
+       jtag_add_plain_dr_scan(1, &field, TAP_DRPAUSE);
+       jtag_add_tlr();
        return jtag_execute_queue();
 }
 
@@ -851,8 +893,9 @@ static bool jtag_examine_chain_check(uint8_t *idcodes, unsigned count)
         * the scan is not valid */
        if (zero_check == 0x00 || one_check == 0xff)
        {
-               LOG_ERROR("JTAG communication failure: check connection, "
-                       "JTAG interface, target power etc.");
+               LOG_ERROR("JTAG scan chain interrogation failed: all %s",
+                               (zero_check == 0x00) ? "zeroes" : "ones");
+               LOG_ERROR("Check JTAG interface, timings, target power, etc.");
                return false;
        }
        return true;
@@ -864,16 +907,21 @@ static void jtag_examine_chain_display(enum log_levels level, const char *msg,
        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, 
+                                 name, msg,
                                  (unsigned int)idcode,
-                                 (unsigned int)EXTRACT_MFG(idcode), 
-                                 (unsigned int)EXTRACT_PART(idcode), 
-                                 (unsigned int)EXTRACT_VER(idcode) );
+                                 (unsigned int)EXTRACT_MFG(idcode),
+                                 (unsigned int)EXTRACT_PART(idcode),
+                                 (unsigned int)EXTRACT_VER(idcode));
 }
 
 static bool jtag_idcode_is_final(uint32_t idcode)
 {
-               return idcode == 0x000000FF || idcode == 0xFFFFFFFF;
+       /*
+        * Some devices, such as AVR8, will output all 1's instead
+        * of TDI input value at end of chain.  Allow those values
+        * instead of failing.
+        */
+       return idcode == END_OF_CHAIN_FLAG || idcode == 0xFFFFFFFF;
 }
 
 /**
@@ -881,8 +929,9 @@ static bool jtag_idcode_is_final(uint32_t idcode)
  * 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.
+ * Returns TRUE iff garbage was found.
  */
-static void jtag_examine_chain_end(uint8_t *idcodes, unsigned count, unsigned max)
+static bool jtag_examine_chain_end(uint8_t *idcodes, unsigned count, unsigned max)
 {
        bool triggered = false;
        for (; count < max - 31; count += 32)
@@ -895,35 +944,29 @@ static void jtag_examine_chain_end(uint8_t *idcodes, unsigned count, unsigned ma
                                        count, (unsigned int)idcode);
                triggered = true;
        }
+       return triggered;
 }
 
 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
+       /* ignore expected BYPASS codes; warn otherwise */
+       if (0 == tap->expected_ids_cnt && !tap->idcode)
                return true;
-       }
 
        /* Loop over the expected identification codes and test for a match */
        uint8_t ii;
        for (ii = 0; ii < tap->expected_ids_cnt; ii++)
        {
                if (tap->idcode == tap->expected_ids[ii])
-                       break;
-       }
+                       return true;
 
-       /* If none of the expected ids matched, log an error */
-       if (ii != tap->expected_ids_cnt)
-       {
-               LOG_INFO("JTAG Tap/device matched");
-               return true;
+               /* treat "-expected-id 0" as a "don't-warn" wildcard */
+               if (0 == tap->expected_ids[ii])
+                       return true;
        }
-       jtag_examine_chain_display(LOG_LVL_ERROR, "got",
+
+       /* If none of the expected ids matched, warn */
+       jtag_examine_chain_display(LOG_LVL_WARNING, "UNEXPECTED",
                        tap->dotted_name, tap->idcode);
        for (ii = 0; ii < tap->expected_ids_cnt; ii++)
        {
@@ -937,14 +980,17 @@ static bool jtag_examine_chain_match_tap(const struct jtag_tap_s *tap)
 }
 
 /* Try to examine chain layout according to IEEE 1149.1 §12
+ * This is called a "blind interrogation" of the scan chain.
  */
-int jtag_examine_chain(void)
+static int jtag_examine_chain(void)
 {
        uint8_t idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4];
-       unsigned device_count = 0;
+       unsigned bit_count;
 
+       /* DR scan to collect BYPASS or IDCODE register contents.
+        * Then make sure the scan data has both ones and zeroes.
+        */
        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;
 
@@ -956,84 +1002,89 @@ int jtag_examine_chain(void)
                return ERROR_JTAG_INIT_FAILED;
        }
 
-       for (unsigned bit_count = 0; bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31;)
+       for (bit_count = 0;
+                       tap && bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31;
+                       tap = jtag_tap_next_enabled(tap))
        {
                uint32_t 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");
+                       LOG_WARNING("TAP %s does not have IDCODE",
+                                       tap->dotted_name);
                        idcode = 0;
+                       tap->hasidcode = false;
 
                        bit_count += 1;
                }
                else
                {
-                       /*
-                        * 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))
-                       {
-                               jtag_examine_chain_end(idcode_buffer,
-                                               bit_count + 32, JTAG_MAX_CHAIN_SIZE * 32);
-                               break;
-                       }
-
+                       /* Friendly devices support IDCODE */
+                       tap->hasidcode = true;
                        jtag_examine_chain_display(LOG_LVL_INFO, "tap/device found",
-                                       tap ? tap->dotted_name : "(not-named)",
-                                       idcode);
+                                       tap->dotted_name, idcode);
 
                        bit_count += 32;
                }
-               device_count++;
-               if (!tap)
-                       continue;
-
                tap->idcode = idcode;
 
-               // ensure the TAP ID does matches what was expected
-               if (!jtag_examine_chain_match_tap(tap))
+               /* ensure the TAP ID matches what was expected */
+               if (!jtag_examine_chain_match_tap(tap))
                        return ERROR_JTAG_INIT_FAILED;
+       }
 
-               tap = jtag_tap_next_enabled(tap);
+       /* Fail if too many TAPs were enabled for us to verify them all. */
+       if (tap) {
+               LOG_ERROR("Too many TAPs enabled; '%s' ignored.",
+                               tap->dotted_name);
+               return ERROR_JTAG_INIT_FAILED;
        }
 
-       /* 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) "
-                               "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, ...)");
+       /* After those IDCODE or BYPASS register values should be
+        * only the data we fed into the scan chain.
+        */
+       if (jtag_examine_chain_end(idcode_buffer, bit_count,
+                       8 * sizeof(idcode_buffer))) {
+               LOG_ERROR("double-check your JTAG setup (interface, "
+                               "speed, TAPs, ...)");
                return ERROR_JTAG_INIT_FAILED;
        }
 
        return ERROR_OK;
 }
 
-int jtag_validate_chain(void)
+/*
+ * Validate the date loaded by entry to the Capture-IR state, to help
+ * find errors related to scan chain configuration (wrong IR lengths)
+ * or communication.
+ *
+ * Entry state can be anything.  On non-error exit, all TAPs are in
+ * bypass mode.  On error exits, the scan chain is reset.
+ */
+static int jtag_validate_ircapture(void)
 {
        jtag_tap_t *tap;
        int total_ir_length = 0;
        uint8_t *ir_test = NULL;
        scan_field_t field;
+       int val;
        int chain_pos = 0;
+       int retval;
 
-       tap = NULL;
-       total_ir_length = 0;
-       for (;;){
-               tap = jtag_tap_next_enabled(tap);
-               if (tap == NULL ){
-                       break;
-               }
-               total_ir_length += tap->ir_length;
-       }
+       for (tap = NULL, total_ir_length = 0;
+                       (tap = jtag_tap_next_enabled(tap)) != NULL;
+                       total_ir_length += tap->ir_length)
+               continue;
 
+       /* increase length to add 2 bit sentinel after scan */
        total_ir_length += 2;
+
        ir_test = malloc(CEIL(total_ir_length, 8));
+       if (ir_test == NULL)
+               return ERROR_FAIL;
+
+       /* after this scan, all TAPs will capture BYPASS instructions */
        buf_set_ones(ir_test, total_ir_length);
 
        field.tap = NULL;
@@ -1041,44 +1092,60 @@ int jtag_validate_chain(void)
        field.out_value = ir_test;
        field.in_value = ir_test;
 
+       jtag_add_plain_ir_scan(1, &field, TAP_IDLE);
 
-       jtag_add_plain_ir_scan(1, &field, TAP_RESET);
-       jtag_execute_queue();
+       LOG_DEBUG("IR capture validation scan");
+       retval = jtag_execute_queue();
+       if (retval != ERROR_OK)
+               goto done;
 
        tap = NULL;
        chain_pos = 0;
-       int val;
-       for (;;){
+
+       for (;;) {
                tap = jtag_tap_next_enabled(tap);
-               if (tap == NULL ){
+               if (tap == NULL{
                        break;
                }
 
-               val = buf_get_u32(ir_test, chain_pos, 2);
-               if (val != 0x1)
-               {
-                       char *cbuf = buf_to_str(ir_test, total_ir_length, 16);
-                       LOG_ERROR("Could not validate JTAG scan chain, IR mismatch, scan returned 0x%s. tap=%s pos=%d expected 0x1 got %0x", cbuf, jtag_tap_name(tap), chain_pos, val);
-                       free(cbuf);
-                       free(ir_test);
-                       return ERROR_JTAG_INIT_FAILED;
+               /* Validate the two LSBs, which must be 01 per JTAG spec.
+                * REVISIT we might be able to verify some MSBs too, using
+                * ircapture/irmask attributes.
+                */
+               val = buf_get_u32(ir_test, chain_pos, tap->ir_length);
+               if ((val & 0x3) != 1) {
+                       LOG_ERROR("%s: IR capture error; saw 0x%0*x not 0x..1",
+                                       jtag_tap_name(tap),
+                                       (tap->ir_length + 7) / tap->ir_length,
+                                       val);
+
+                       retval = ERROR_JTAG_INIT_FAILED;
+                       goto done;
                }
+               LOG_DEBUG("%s: IR capture 0x%0*x", jtag_tap_name(tap),
+                               (tap->ir_length + 7) / tap->ir_length, val);
                chain_pos += tap->ir_length;
        }
 
+       /* verify the '11' sentinel we wrote is returned at the end */
        val = buf_get_u32(ir_test, chain_pos, 2);
        if (val != 0x3)
        {
                char *cbuf = buf_to_str(ir_test, total_ir_length, 16);
-               LOG_ERROR("Could not validate end of JTAG scan chain, IR mismatch, scan returned 0x%s. pos=%d expected 0x3 got %0x", cbuf, chain_pos, val);
+
+               LOG_ERROR("IR capture error at bit %d, saw 0x%s not 0x...3",
+                               chain_pos, cbuf);
                free(cbuf);
-               free(ir_test);
-               return ERROR_JTAG_INIT_FAILED;
+               retval = ERROR_JTAG_INIT_FAILED;
        }
 
+done:
        free(ir_test);
-
-       return ERROR_OK;
+       if (retval != ERROR_OK) {
+               jtag_add_tlr();
+               jtag_execute_queue();
+       }
+       return retval;
 }
 
 
@@ -1086,6 +1153,7 @@ void jtag_tap_init(jtag_tap_t *tap)
 {
        assert(0 != tap->ir_length);
 
+       /// @todo fix, this allocates one byte per bit for all three fields!
        tap->expected = malloc(tap->ir_length);
        tap->expected_mask = malloc(tap->ir_length);
        tap->cur_instr = malloc(tap->ir_length);
@@ -1103,7 +1171,8 @@ void jtag_tap_init(jtag_tap_t *tap)
        LOG_DEBUG("Created Tap: %s @ abs position %d, "
                        "irlen %d, capture: 0x%x mask: 0x%x", tap->dotted_name,
                                tap->abs_chain_position, tap->ir_length,
-                         (unsigned int)(tap->ir_capture_value), (unsigned int)(tap->ir_capture_mask));
+                               (unsigned) tap->ir_capture_value,
+                               (unsigned) tap->ir_capture_mask);
        jtag_tap_add(tap);
 }
 
@@ -1111,7 +1180,8 @@ void jtag_tap_free(jtag_tap_t *tap)
 {
        jtag_unregister_event_callback(&jtag_reset_callback, tap);
 
-       /// @todo is anything missing? no memory leaks please 
+       /// @todo is anything missing? no memory leaks please
+       free((void *)tap->expected);
        free((void *)tap->expected_ids);
        free((void *)tap->chip);
        free((void *)tap->tapname);
@@ -1130,28 +1200,46 @@ int jtag_interface_init(struct command_context_s *cmd_ctx)
                LOG_ERROR("JTAG interface has to be specified, see \"interface\" command");
                return ERROR_JTAG_INVALID_INTERFACE;
        }
-       if (hasKHz)
-       {
-               jtag_interface->khz(jtag_get_speed_khz(), &jtag_speed);
-               hasKHz = false;
-       }
 
+       jtag = jtag_interface;
        if (jtag_interface->init() != ERROR_OK)
+       {
+               jtag = NULL;
                return ERROR_JTAG_INIT_FAILED;
+       }
+
+       int requested_khz = jtag_get_speed_khz();
+       int actual_khz = requested_khz;
+       int retval = jtag_get_speed_readable(&actual_khz);
+       if (ERROR_OK != retval)
+               LOG_INFO("interface specific clock speed value %d", jtag_get_speed());
+       else if (actual_khz)
+       {
+               if ((CLOCK_MODE_RCLK == clock_mode)
+                       || ((CLOCK_MODE_KHZ == clock_mode) && !requested_khz))
+               {
+                       LOG_INFO("RCLK (adaptive clock speed) not supported - fallback to %d kHz"
+                               , actual_khz);
+               }
+               else
+                       LOG_INFO("clock speed %d kHz", actual_khz);
+       }
+       else
+               LOG_INFO("RCLK (adaptive clock speed)");
 
-       jtag = jtag_interface;
        return ERROR_OK;
 }
 
-static int jtag_init_inner(struct command_context_s *cmd_ctx)
+int jtag_init_inner(struct command_context_s *cmd_ctx)
 {
        jtag_tap_t *tap;
        int retval;
+       bool issue_setup = true;
 
        LOG_DEBUG("Init JTAG chain");
 
        tap = jtag_tap_next_enabled(NULL);
-       if (tap == NULL ){
+       if (tap == NULL{
                LOG_ERROR("There are no enabled taps?");
                return ERROR_JTAG_INIT_FAILED;
        }
@@ -1163,14 +1251,22 @@ static int jtag_init_inner(struct command_context_s *cmd_ctx)
        /* examine chain first, as this could discover the real chain layout */
        if (jtag_examine_chain() != ERROR_OK)
        {
-               LOG_ERROR("trying to validate configured JTAG chain anyway...");
+               LOG_ERROR("Trying to use configured scan chain anyway...");
+               issue_setup = false;
        }
 
-       if (jtag_validate_chain() != ERROR_OK)
+       if (jtag_validate_ircapture() != ERROR_OK)
        {
-               LOG_WARNING("Could not validate JTAG chain, continuing anyway...");
+               LOG_WARNING("Errors during IR capture, continuing anyway...");
+               issue_setup = false;
        }
 
+       if (issue_setup)
+               jtag_notify_event(JTAG_TAP_EVENT_SETUP);
+       else
+               LOG_WARNING("Bypassing JTAG setup events due to errors");
+
+
        return ERROR_OK;
 }
 
@@ -1195,11 +1291,11 @@ int jtag_init_reset(struct command_context_s *cmd_ctx)
        if ((retval = jtag_interface_init(cmd_ctx)) != ERROR_OK)
                return retval;
 
-       LOG_DEBUG("Trying to bring the JTAG controller to life by asserting TRST / RESET");
+       LOG_DEBUG("Trying to bring the JTAG controller to life by asserting TRST / TLR");
 
        /* Reset can happen after a power cycle.
         *
-        * Ideally we would only assert TRST or run RESET before the target reset.
+        * Ideally we would only assert TRST or run TLR before the target reset.
         *
         * However w/srst_pulls_trst, trst is asserted together with the target
         * reset whether we want it or not.
@@ -1212,7 +1308,7 @@ int jtag_init_reset(struct command_context_s *cmd_ctx)
         * NB! order matters!!!! srst *can* disconnect JTAG circuitry
         *
         */
-       jtag_add_reset(1, 0); /* RESET or TRST */
+       jtag_add_reset(1, 0); /* TAP_RESET, using TMS+TCK or TRST */
        if (jtag_reset_config & RESET_HAS_SRST)
        {
                jtag_add_reset(1, 1);
@@ -1238,27 +1334,22 @@ int jtag_init(struct command_context_s *cmd_ctx)
        int retval;
        if ((retval = jtag_interface_init(cmd_ctx)) != ERROR_OK)
                return retval;
-       if (jtag_init_inner(cmd_ctx) == ERROR_OK)
-       {
-               return ERROR_OK;
-       }
-       return jtag_init_reset(cmd_ctx);
-}
 
-void jtag_set_speed_khz(unsigned khz)
-{
-       speed_khz = khz;
+       if (Jim_Eval_Named(interp, "jtag_init", __FILE__, __LINE__) != JIM_OK)
+               return ERROR_FAIL;
+
+       return ERROR_OK;
 }
+
 unsigned jtag_get_speed_khz(void)
 {
        return speed_khz;
 }
-int jtag_config_khz(unsigned khz)
-{
-       LOG_DEBUG("handle jtag khz");
-       jtag_set_speed_khz(khz);
 
-       int cur_speed = 0;
+static int jtag_khz_to_speed(unsigned khz, int* speed)
+{
+       LOG_DEBUG("convert khz to interface specific speed value");
+       speed_khz = khz;
        if (jtag != NULL)
        {
                LOG_DEBUG("have interface set up");
@@ -1266,33 +1357,84 @@ int jtag_config_khz(unsigned khz)
                int retval = jtag->khz(jtag_get_speed_khz(), &speed_div1);
                if (ERROR_OK != retval)
                {
-                       jtag_set_speed_khz(0);
                        return retval;
                }
-               cur_speed = speed_div1;
+               *speed = speed_div1;
        }
-       return jtag_set_speed(cur_speed);
+       return ERROR_OK;
 }
 
-int jtag_get_speed(void)
+static int jtag_rclk_to_speed(unsigned fallback_speed_khz, int* speed)
 {
-       return jtag_speed;
+       int retval = jtag_khz_to_speed(0, speed);
+       if ((ERROR_OK != retval) && fallback_speed_khz)
+       {
+               LOG_DEBUG("trying fallback speed...");
+               retval = jtag_khz_to_speed(fallback_speed_khz, speed);
+       }
+       return retval;
 }
 
-int jtag_set_speed(int speed)
+static int jtag_set_speed(int speed)
 {
        jtag_speed = speed;
        /* this command can be called during CONFIG,
         * in which case jtag isn't initialized */
-       hasKHz = !jtag;
        return jtag ? jtag->speed(speed) : ERROR_OK;
 }
 
-int jtag_get_speed_readable(int *speed)
+int jtag_config_speed(int speed)
 {
-       return jtag ? jtag->speed_div(jtag_get_speed(), speed) : ERROR_OK;
+       LOG_DEBUG("handle jtag speed");
+       clock_mode = CLOCK_MODE_SPEED;
+       return jtag_set_speed(speed);
 }
 
+int jtag_config_khz(unsigned khz)
+{
+       LOG_DEBUG("handle jtag khz");
+       clock_mode = CLOCK_MODE_KHZ;
+       int speed = 0;
+       int retval = jtag_khz_to_speed(khz, &speed);
+       return (ERROR_OK != retval) ? retval : jtag_set_speed(speed);
+}
+
+int jtag_config_rclk(unsigned fallback_speed_khz)
+{
+       LOG_DEBUG("handle jtag rclk");
+       clock_mode = CLOCK_MODE_RCLK;
+       rclk_fallback_speed_khz = fallback_speed_khz;
+       int speed = 0;
+       int retval = jtag_rclk_to_speed(fallback_speed_khz, &speed);
+       return (ERROR_OK != retval) ? retval : jtag_set_speed(speed);
+}
+
+int jtag_get_speed(void)
+{
+       int speed;
+       switch(clock_mode)
+       {
+               case CLOCK_MODE_SPEED:
+                       speed = jtag_speed;
+                       break;
+               case CLOCK_MODE_KHZ:
+                       jtag_khz_to_speed(jtag_get_speed_khz(), &speed);
+                       break;
+               case CLOCK_MODE_RCLK:
+                       jtag_rclk_to_speed(rclk_fallback_speed_khz, &speed);
+                       break;
+               default:
+                       LOG_ERROR("BUG: unknown jtag clock mode");
+                       speed = 0;
+                       break;
+       }
+       return speed;
+}
+
+int jtag_get_speed_readable(int *khz)
+{
+       return jtag ? jtag->speed_div(jtag_get_speed(), khz) : ERROR_OK;
+}
 
 void jtag_set_verify(bool enable)
 {
@@ -1358,3 +1500,21 @@ unsigned jtag_get_ntrst_delay(void)
 {
        return jtag_ntrst_delay;
 }
+
+
+void jtag_set_nsrst_assert_width(unsigned delay)
+{
+       jtag_nsrst_assert_width = delay;
+}
+unsigned jtag_get_nsrst_assert_width(void)
+{
+       return jtag_nsrst_assert_width;
+}
+void jtag_set_ntrst_assert_width(unsigned delay)
+{
+       jtag_ntrst_assert_width = delay;
+}
+unsigned jtag_get_ntrst_assert_width(void)
+{
+       return jtag_ntrst_assert_width;
+}

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)