#include "jtag.h"
#include "interface.h"
+#include <transport/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);
* 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;
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;
/* how long the OpenOCD should wait before attempting JTAG communication after reset lines deasserted (in ms) */
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 */
/**
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;
}
/* 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();
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;
cmd_queue_cur_state = state;
}
-void jtag_alloc_in_value32(struct scan_field *field)
-{
- interface_jtag_alloc_in_value32(field);
-}
-
void jtag_add_ir_scan_noverify(struct jtag_tap *active, const struct scan_field *in_fields,
tap_state_t state)
{
jtag_add_ir_scan_noverify(active, in_fields, state);
}
+/* If fields->in_value is filled out, then the captured IR value will be checked */
void jtag_add_ir_scan(struct jtag_tap *active, struct scan_field *in_fields, tap_state_t state)
{
assert(state != TAP_RESET);
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)
{
- for (int i = 0; i < in_num_fields; i++)
- {
- struct scan_field *field = &in_fields[i];
- field->allocated = 0;
- field->modified = 0;
- if (field->check_value || field->in_value)
- continue;
- interface_jtag_add_scan_check_alloc(field);
- field->modified = 1;
- }
-
jtag_add_scan(active, in_num_fields, in_fields, state);
for (int i = 0; i < in_num_fields; i++)
(jtag_callback_data_t)in_fields[i].check_mask,
(jtag_callback_data_t)in_fields[i].num_bits);
}
- if (in_fields[i].allocated)
- {
- free(in_fields[i].in_value);
- }
- if (in_fields[i].modified)
- {
- in_fields[i].in_value = NULL;
- }
}
}
retval = jtag_execute_queue();
if (retval != ERROR_OK) {
- LOG_ERROR("TRST/SRST error %d", retval);
+ LOG_ERROR("TRST/SRST error");
return;
}
}
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 (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) {
}
}
-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!!!
{
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)
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,
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 = 0;
+ 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 */
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
*/
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);
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)
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)
{
{
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;
+}