]> git.sur5r.net Git - openocd/blobdiff - src/jtag/core.c
Silence -O3 warning
[openocd] / src / jtag / core.c
index bdf968e95417d68a1e0390ef3e4d8671b135a390..22d0b8c302e8a09c6b09c127840fffbf1019e47e 100644 (file)
 
 #include "jtag.h"
 #include "interface.h"
+#include "transport.h"
 
 #ifdef HAVE_STRINGS_H
 #include <strings.h>
 #endif
 
+/* SVF and XSVF are higher level JTAG command sets (for boundary scan) */
+#include "svf/svf.h"
+#include "xsvf/xsvf.h"
 
 /// The number of JTAG queue flushes (for profiling and debugging purposes).
 static int jtag_flush_queue_count;
 
+// Sleep this # of ms after flushing the queue
+static int jtag_flush_queue_sleep = 0;
+
 static void jtag_add_scan_check(struct jtag_tap *active,
                void (*jtag_add_scan)(struct jtag_tap *active, int in_num_fields, const struct scan_field *in_fields, tap_state_t state),
                int in_num_fields, struct scan_field *in_fields, tap_state_t state);
@@ -52,9 +59,9 @@ static void jtag_add_scan_check(struct jtag_tap *active,
  * when an error occurs during processing that should be reported during
  * jtag_execute_queue().
  *
- * Tts value may be checked with jtag_get_error() and cleared with
- * jtag_error_clear().  This value is returned (and cleared) by
- * jtag_execute_queue().
+ * The value is set and cleared, but never read by normal application code.
+ *
+ * This value is returned (and cleared) by jtag_execute_queue().
  */
 static int jtag_error = ERROR_OK;
 
@@ -86,16 +93,15 @@ static struct jtag_tap *__jtag_all_taps = NULL;
 static unsigned jtag_num_taps = 0;
 
 static enum reset_types jtag_reset_config = RESET_NONE;
-static tap_state_t cmd_queue_end_state = TAP_RESET;
 tap_state_t cmd_queue_cur_state = TAP_RESET;
 
 static bool jtag_verify_capture_ir = true;
 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 adapter_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 adapter_nsrst_assert_width = 0; /* width of assertion */
 static int jtag_ntrst_assert_width = 0; /* width of assertion */
 
 /**
@@ -118,24 +124,29 @@ static struct jtag_event_callback *jtag_event_callbacks;
 static int speed_khz = 0;
 /* 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 enum {CLOCK_MODE_UNSELECTED, CLOCK_MODE_KHZ, CLOCK_MODE_RCLK} clock_mode;
 static int jtag_speed = 0;
 
 static struct jtag_interface *jtag = NULL;
 
+
+const struct swd_driver *swd = NULL;
+
 /* configuration */
 struct jtag_interface *jtag_interface = NULL;
 
+void jtag_set_flush_queue_sleep(int ms)
+{
+       jtag_flush_queue_sleep = ms;
+}
+
 void jtag_set_error(int error)
 {
        if ((error == ERROR_OK) || (jtag_error != ERROR_OK))
                return;
        jtag_error = error;
 }
-int jtag_get_error(void)
-{
-       return jtag_error;
-}
+
 int jtag_error_clear(void)
 {
        int temp = jtag_error;
@@ -205,7 +216,7 @@ void jtag_tap_add(struct jtag_tap *t)
 }
 
 /* returns a pointer to the n-th device in the scan chain */
-static inline struct jtag_tap *jtag_tap_by_position(unsigned n)
+struct jtag_tap *jtag_tap_by_position(unsigned n)
 {
        struct jtag_tap *t = jtag_all_taps();
 
@@ -288,28 +299,24 @@ int jtag_register_event_callback(jtag_event_handler_t callback, void *priv)
 
 int jtag_unregister_event_callback(jtag_event_handler_t callback, void *priv)
 {
-       struct jtag_event_callback **callbacks_p;
-       struct jtag_event_callback **next;
+       struct jtag_event_callback **p = &jtag_event_callbacks, *temp;
 
        if (callback == NULL)
        {
                return ERROR_INVALID_ARGUMENTS;
        }
 
-       for (callbacks_p = &jtag_event_callbacks;
-                       *callbacks_p != NULL;
-                       callbacks_p = next)
+       while (*p)
        {
-               next = &((*callbacks_p)->next);
-
-               if ((*callbacks_p)->priv != priv)
-                       continue;
-
-               if ((*callbacks_p)->callback == callback)
+               if (((*p)->priv != priv) || ((*p)->callback != callback))
                {
-                       free(*callbacks_p);
-                       *callbacks_p = *next;
+                       p = &(*p)->next;
+                       continue;
                }
+
+               temp = *p;
+               *p = (*p)->next;
+               free(temp);
        }
 
        return ERROR_OK;
@@ -688,7 +695,7 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst)
                        retval = jtag_execute_queue();
 
                if (retval != ERROR_OK) {
-                       LOG_ERROR("TRST/SRST error %d", retval);
+                       LOG_ERROR("TRST/SRST error");
                        return;
                }
        }
@@ -699,13 +706,13 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst)
                if (jtag_srst)
                {
                        LOG_DEBUG("SRST line asserted");
-                       if (jtag_nsrst_assert_width)
-                               jtag_add_sleep(jtag_nsrst_assert_width * 1000);
+                       if (adapter_nsrst_assert_width)
+                               jtag_add_sleep(adapter_nsrst_assert_width * 1000);
                }
                else {
                        LOG_DEBUG("SRST line released");
-                       if (jtag_nsrst_delay)
-                               jtag_add_sleep(jtag_nsrst_delay * 1000);
+                       if (adapter_nsrst_delay)
+                               jtag_add_sleep(adapter_nsrst_delay * 1000);
                }
        }
 
@@ -717,7 +724,6 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst)
         */
        if (trst_with_tlr) {
                LOG_DEBUG("JTAG reset with TLR instead of TRST");
-               jtag_set_end_state(TAP_RESET);
                jtag_add_tlr();
 
        } else if (jtag_trst != new_trst) {
@@ -743,23 +749,6 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst)
        }
 }
 
-tap_state_t jtag_set_end_state(tap_state_t state)
-{
-       if ((state == TAP_DRSHIFT)||(state == TAP_IRSHIFT))
-       {
-               LOG_ERROR("BUG: TAP_DRSHIFT/IRSHIFT can't be end state. Calling code should use a larger scan field");
-       }
-
-       if (state != TAP_INVALID)
-               cmd_queue_end_state = state;
-       return cmd_queue_end_state;
-}
-
-tap_state_t jtag_get_end_state(void)
-{
-       return cmd_queue_end_state;
-}
-
 void jtag_add_sleep(uint32_t us)
 {
        /// @todo Here, keep_alive() appears to be a layering violation!!!
@@ -844,6 +833,15 @@ void jtag_execute_queue_noclear(void)
 {
        jtag_flush_queue_count++;
        jtag_set_error(interface_jtag_execute_queue());
+
+       if (jtag_flush_queue_sleep > 0)
+       {
+               /* For debug purposes it can be useful to test performance
+                * or behavior when delaying after flushing the queue,
+                * e.g. to simulate long roundtrip times.
+                */
+               usleep(jtag_flush_queue_sleep * 1000);
+       }
 }
 
 int jtag_get_flush_queue_count(void)
@@ -873,9 +871,16 @@ static int jtag_reset_callback(enum jtag_event event, void *priv)
        return ERROR_OK;
 }
 
+/* sleep at least us microseconds. When we sleep more than 1000ms we
+ * do an alive sleep, i.e. keep GDB alive. Note that we could starve
+ * GDB if we slept for <1000ms many times.
+ */
 void jtag_sleep(uint32_t us)
 {
-       alive_sleep(us/1000);
+       if (us < 1000)
+               usleep(us);
+       else
+               alive_sleep((us+999)/1000);
 }
 
 /* Maximum number of enabled JTAG devices we expect in the scan chain,
@@ -1363,18 +1368,46 @@ int adapter_init(struct command_context *cmd_ctx)
                return ERROR_JTAG_INVALID_INTERFACE;
        }
 
+       int retval;
+       retval = jtag_interface->init();
+       if (retval != ERROR_OK)
+       {
+               return retval;
+       }
        jtag = jtag_interface;
-       if (jtag_interface->init() != ERROR_OK)
+
+       /* LEGACY SUPPORT ... adapter drivers  must declare what
+        * transports they allow.  Until they all do so, assume
+        * the legacy drivers are JTAG-only
+        */
+       if (!transports_are_declared()) {
+               LOG_ERROR("Adapter driver '%s' did not declare "
+                       "which transports it allows; assuming "
+                       "JTAG-only", jtag->name);
+               retval = allow_transports(cmd_ctx, jtag_only);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       if (CLOCK_MODE_UNSELECTED == clock_mode)
        {
-               jtag = NULL;
+               LOG_ERROR("An adapter speed is not selected in the init script."
+                       " Insert a call to adapter_khz or jtag_rclk to proceed.");
                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);
+       int jtag_speed_var;
+       retval = jtag_get_speed(&jtag_speed_var);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = jtag->speed(jtag_speed_var);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = jtag_get_speed_readable(&actual_khz);
        if (ERROR_OK != retval)
-               LOG_INFO("adapter-specific clock speed value %d", jtag_get_speed());
+               LOG_INFO("adapter-specific clock speed value %d", jtag_speed_var);
        else if (actual_khz)
        {
                /* Adaptive clocking -- JTAG-specific */
@@ -1433,17 +1466,19 @@ int jtag_init_inner(struct command_context *cmd_ctx)
        case ERROR_OK:
                /* complete success */
                break;
-       case ERROR_JTAG_INIT_SOFT_FAIL:
+       default:
                /* For backward compatibility reasons, try coping with
                 * configuration errors involving only ID mismatches.
                 * We might be able to talk to the devices.
+                *
+                * Also the device might be powered down during startup.
+                *
+                * After OpenOCD starts, we can try to power on the device
+                * and run a reset.
                 */
                LOG_ERROR("Trying to use configured scan chain anyway...");
                issue_setup = false;
                break;
-       default:
-               /* some hard error; already issued diagnostics */
-               return retval;
        }
 
        /* Now look at IR values.  Problems here will prevent real
@@ -1454,7 +1489,13 @@ int jtag_init_inner(struct command_context *cmd_ctx)
         */
        retval = jtag_validate_ircapture();
        if (retval != ERROR_OK)
-               return retval;
+       {
+               /* The target might be powered down. The user
+                * can power it up and reset it after firing
+                * up OpenOCD.
+                */
+               issue_setup = false;
+       }
 
        if (issue_setup)
                jtag_notify_event(JTAG_TAP_EVENT_SETUP);
@@ -1612,31 +1653,30 @@ int jtag_config_rclk(unsigned fallback_speed_khz)
        return (ERROR_OK != retval) ? retval : jtag_set_speed(speed);
 }
 
-int jtag_get_speed(void)
+int jtag_get_speed(int *speed)
 {
-       int speed;
        switch(clock_mode)
        {
-               case CLOCK_MODE_SPEED:
-                       speed = jtag_speed;
-                       break;
                case CLOCK_MODE_KHZ:
-                       adapter_khz_to_speed(jtag_get_speed_khz(), &speed);
+                       adapter_khz_to_speed(jtag_get_speed_khz(), speed);
                        break;
                case CLOCK_MODE_RCLK:
-                       jtag_rclk_to_speed(rclk_fallback_speed_khz, &speed);
+                       jtag_rclk_to_speed(rclk_fallback_speed_khz, speed);
                        break;
                default:
                        LOG_ERROR("BUG: unknown jtag clock mode");
-                       speed = 0;
-                       break;
+                       return ERROR_FAIL;
        }
-       return speed;
+       return ERROR_OK;
 }
 
 int jtag_get_speed_readable(int *khz)
 {
-       return jtag ? jtag->speed_div(jtag_get_speed(), khz) : ERROR_OK;
+       int jtag_speed_var = 0;
+       int retval = jtag_get_speed(&jtag_speed_var);
+       if (retval != ERROR_OK)
+               return retval;
+       return jtag ? jtag->speed_div(jtag_speed_var, khz) : ERROR_OK;
 }
 
 void jtag_set_verify(bool enable)
@@ -1696,11 +1736,11 @@ int jtag_get_srst(void)
 
 void jtag_set_nsrst_delay(unsigned delay)
 {
-       jtag_nsrst_delay = delay;
+       adapter_nsrst_delay = delay;
 }
 unsigned jtag_get_nsrst_delay(void)
 {
-       return jtag_nsrst_delay;
+       return adapter_nsrst_delay;
 }
 void jtag_set_ntrst_delay(unsigned delay)
 {
@@ -1714,11 +1754,11 @@ unsigned jtag_get_ntrst_delay(void)
 
 void jtag_set_nsrst_assert_width(unsigned delay)
 {
-       jtag_nsrst_assert_width = delay;
+       adapter_nsrst_assert_width = delay;
 }
 unsigned jtag_get_nsrst_assert_width(void)
 {
-       return jtag_nsrst_assert_width;
+       return adapter_nsrst_assert_width;
 }
 void jtag_set_ntrst_assert_width(unsigned delay)
 {
@@ -1728,3 +1768,44 @@ unsigned jtag_get_ntrst_assert_width(void)
 {
        return jtag_ntrst_assert_width;
 }
+
+static int jtag_select(struct command_context *ctx)
+{
+       int retval;
+
+       /* NOTE:  interface init must already have been done.
+        * That works with only C code ... no Tcl glue required.
+        */
+
+       retval = jtag_register_commands(ctx);
+
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = svf_register_commands(ctx);
+
+       if (retval != ERROR_OK)
+               return retval;
+
+       return xsvf_register_commands(ctx);
+}
+
+static struct transport jtag_transport = {
+       .name = "jtag",
+       .select = jtag_select,
+       .init = jtag_init,
+};
+
+static void jtag_constructor(void) __attribute__((constructor));
+static void jtag_constructor(void)
+{
+       transport_register(&jtag_transport);
+}
+
+/** Returns true if the current debug session
+ * is using JTAG as its transport.
+ */
+bool transport_is_jtag(void)
+{
+       return get_current_transport() == &jtag_transport;
+}