X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Fjtag%2Fcore.c;h=b26701e3c01b83476b8cfb90ba9b04ff8a2afaa7;hb=353362651fc28c1f1d823659cde36dd31d1aede6;hp=bce332fc844cdb4411cd7b343081bd4acb949451;hpb=57d7743639d5092770d79f7c4b12ae694c482750;p=openocd.git diff --git a/src/jtag/core.c b/src/jtag/core.c index bce332fc84..b26701e3c0 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -33,15 +33,22 @@ #include "jtag.h" #include "interface.h" +#include #ifdef HAVE_STRINGS_H #include #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; @@ -388,15 +395,16 @@ void jtag_add_ir_scan(struct jtag_tap *active, struct scan_field *in_fields, tap } } -void jtag_add_plain_ir_scan(int in_num_fields, const struct scan_field *in_fields, +void jtag_add_plain_ir_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t state) { + assert(out_bits != NULL); assert(state != TAP_RESET); jtag_prelude(state); int retval = interface_jtag_add_plain_ir_scan( - in_num_fields, in_fields, state); + num_bits, out_bits, in_bits, state); jtag_set_error(retval); } @@ -469,15 +477,16 @@ void jtag_add_dr_scan(struct jtag_tap *active, int in_num_fields, const struct s jtag_set_error(retval); } -void jtag_add_plain_dr_scan(int in_num_fields, const struct scan_field *in_fields, +void jtag_add_plain_dr_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t state) { + assert(out_bits != NULL); assert(state != TAP_RESET); jtag_prelude(state); int retval; - retval = interface_jtag_add_plain_dr_scan(in_num_fields, in_fields, state); + retval = interface_jtag_add_plain_dr_scan(num_bits, out_bits, in_bits, state); jtag_set_error(retval); } @@ -686,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; } } @@ -697,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); } } @@ -715,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) { @@ -741,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!!! @@ -842,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) @@ -871,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, @@ -906,7 +913,7 @@ static int jtag_examine_chain_execute(uint8_t *idcode_buffer, unsigned num_idcod for (unsigned i = 0; i < JTAG_MAX_CHAIN_SIZE; i++) buf_set_u32(idcode_buffer, i * 32, 32, END_OF_CHAIN_FLAG); - jtag_add_plain_dr_scan(1, &field, TAP_DRPAUSE); + jtag_add_plain_dr_scan(field.num_bits, field.out_value, field.in_value, TAP_DRPAUSE); jtag_add_tlr(); return jtag_execute_queue(); } @@ -1207,7 +1214,7 @@ static int jtag_validate_ircapture(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(field.num_bits, field.out_value, field.in_value, TAP_IDLE); LOG_DEBUG("IR capture validation scan"); retval = jtag_execute_queue(); @@ -1344,7 +1351,11 @@ void jtag_tap_free(struct jtag_tap *tap) free(tap); } -int jtag_interface_init(struct command_context *cmd_ctx) +/** + * Do low-level setup like initializing registers, output signals, + * and clocking. + */ +int adapter_init(struct command_context *cmd_ctx) { if (jtag) return ERROR_OK; @@ -1352,24 +1363,54 @@ int jtag_interface_init(struct command_context *cmd_ctx) if (!jtag_interface) { /* nothing was previously specified by "interface" command */ - LOG_ERROR("JTAG interface has to be specified, see \"interface\" command"); + LOG_ERROR("Debug Adapter has to be specified, " + "see \"interface\" command"); 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("interface 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 */ if ((CLOCK_MODE_RCLK == clock_mode) || ((CLOCK_MODE_KHZ == clock_mode) && !requested_khz)) { @@ -1425,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 @@ -1446,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); @@ -1457,7 +1506,7 @@ int jtag_init_inner(struct command_context *cmd_ctx) return ERROR_OK; } -int jtag_interface_quit(void) +int adapter_quit(void) { if (!jtag || !jtag->quit) return ERROR_OK; @@ -1475,7 +1524,7 @@ int jtag_init_reset(struct command_context *cmd_ctx) { int retval; - if ((retval = jtag_interface_init(cmd_ctx)) != ERROR_OK) + if ((retval = adapter_init(cmd_ctx)) != ERROR_OK) return retval; LOG_DEBUG("Initializing with hard TRST+SRST reset"); @@ -1529,7 +1578,7 @@ int jtag_init(struct command_context *cmd_ctx) { int retval; - if ((retval = jtag_interface_init(cmd_ctx)) != ERROR_OK) + if ((retval = adapter_init(cmd_ctx)) != ERROR_OK) return retval; /* guard against oddball hardware: force resets to be inactive */ @@ -1548,7 +1597,7 @@ unsigned jtag_get_speed_khz(void) return speed_khz; } -static int jtag_khz_to_speed(unsigned khz, int* speed) +static int adapter_khz_to_speed(unsigned khz, int* speed) { LOG_DEBUG("convert khz to interface specific speed value"); speed_khz = khz; @@ -1568,11 +1617,11 @@ static int jtag_khz_to_speed(unsigned khz, int* speed) static int jtag_rclk_to_speed(unsigned fallback_speed_khz, int* speed) { - int retval = jtag_khz_to_speed(0, speed); + int retval = adapter_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); + retval = adapter_khz_to_speed(fallback_speed_khz, speed); } return retval; } @@ -1590,7 +1639,7 @@ 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); + int retval = adapter_khz_to_speed(khz, &speed); return (ERROR_OK != retval) ? retval : jtag_set_speed(speed); } @@ -1604,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: - jtag_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) @@ -1688,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) { @@ -1706,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) { @@ -1720,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; +}