#endif
#include "jtag.h"
-#include "minidriver.h"
#include "interface.h"
#ifdef HAVE_STRINGS_H
/// The number of JTAG queue flushes (for profiling and debugging purposes).
static int jtag_flush_queue_count;
-static void jtag_add_scan_check(void (*jtag_add_scan)(int in_num_fields, const struct scan_field *in_fields, tap_state_t state),
+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);
/**
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 */
-typedef struct jtag_event_callback_s
-{
- jtag_event_handler_t callback;
- void* priv;
- struct jtag_event_callback_s* next;
-} jtag_event_callback_t;
+/**
+ * Contains a single callback along with a pointer that will be passed
+ * when an event occurs.
+ */
+struct jtag_event_callback {
+ /// a event callback
+ jtag_event_handler_t callback;
+ /// the private data to pass to the callback
+ void* priv;
+ /// the next callback
+ struct jtag_event_callback* next;
+};
/* callbacks to inform high-level handlers about JTAG state changes */
-static jtag_event_callback_t *jtag_event_callbacks;
+static struct jtag_event_callback *jtag_event_callbacks;
/* speed in kHz*/
static int 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;
+static struct jtag_interface *jtag = NULL;
/* configuration */
-jtag_interface_t *jtag_interface = NULL;
+struct jtag_interface *jtag_interface = NULL;
void jtag_set_error(int error)
{
return t;
}
-struct jtag_tap *jtag_tap_by_jim_obj(Jim_Interp *interp, Jim_Obj *o)
-{
- const char *cp = Jim_GetString(o, NULL);
- struct jtag_tap *t = cp ? jtag_tap_by_string(cp) : NULL;
- if (NULL == cp)
- cp = "(unknown)";
- if (NULL == t)
- Jim_SetResult_sprintf(interp, "Tap '%s' could not be found", cp);
- return t;
-}
-
struct jtag_tap* jtag_tap_next_enabled(struct jtag_tap* p)
{
p = p ? p->next_tap : jtag_all_taps();
int jtag_register_event_callback(jtag_event_handler_t callback, void *priv)
{
- jtag_event_callback_t **callbacks_p = &jtag_event_callbacks;
+ struct jtag_event_callback **callbacks_p = &jtag_event_callbacks;
if (callback == NULL)
{
callbacks_p = &((*callbacks_p)->next);
}
- (*callbacks_p) = malloc(sizeof(jtag_event_callback_t));
+ (*callbacks_p) = malloc(sizeof(struct jtag_event_callback));
(*callbacks_p)->callback = callback;
(*callbacks_p)->priv = priv;
(*callbacks_p)->next = NULL;
int jtag_unregister_event_callback(jtag_event_handler_t callback, void *priv)
{
- jtag_event_callback_t **callbacks_p;
- jtag_event_callback_t **next;
+ struct jtag_event_callback **callbacks_p;
+ struct jtag_event_callback **next;
if (callback == NULL)
{
int jtag_call_event_callbacks(enum jtag_event event)
{
- jtag_event_callback_t *callback = jtag_event_callbacks;
+ struct jtag_event_callback *callback = jtag_event_callbacks;
LOG_DEBUG("jtag event: %s", jtag_event_strings[event]);
while (callback)
{
- jtag_event_callback_t *next;
+ struct jtag_event_callback *next;
/* callback may remove itself */
next = callback->next;
interface_jtag_alloc_in_value32(field);
}
-void jtag_add_ir_scan_noverify(int in_count, const struct scan_field *in_fields,
+void jtag_add_ir_scan_noverify(struct jtag_tap *active, const struct scan_field *in_fields,
tap_state_t state)
{
jtag_prelude(state);
- int retval = interface_jtag_add_ir_scan(in_count, in_fields, state);
+ int retval = interface_jtag_add_ir_scan(active, in_fields, state);
jtag_set_error(retval);
}
+static void jtag_add_ir_scan_noverify_callback(struct jtag_tap *active, int dummy, const struct scan_field *in_fields,
+ tap_state_t state)
+{
+ jtag_add_ir_scan_noverify(active, in_fields, state);
+}
-void jtag_add_ir_scan(int in_num_fields, struct scan_field *in_fields, tap_state_t state)
+void jtag_add_ir_scan(struct jtag_tap *active, struct scan_field *in_fields, tap_state_t state)
{
assert(state != TAP_RESET);
{
/* 8 x 32 bit id's is enough for all invocations */
- for (int j = 0; j < in_num_fields; j++)
- {
- /* if we are to run a verification of the ir scan, we need to get the input back.
- * We may have to allocate space if the caller didn't ask for the input back.
- */
- in_fields[j].check_value = in_fields[j].tap->expected;
- in_fields[j].check_mask = in_fields[j].tap->expected_mask;
- }
- jtag_add_scan_check(jtag_add_ir_scan_noverify, in_num_fields, in_fields, state);
+ /* if we are to run a verification of the ir scan, we need to get the input back.
+ * We may have to allocate space if the caller didn't ask for the input back.
+ */
+ in_fields->check_value = active->expected;
+ in_fields->check_mask = active->expected_mask;
+ jtag_add_scan_check(active, jtag_add_ir_scan_noverify_callback, 1, in_fields, state);
} else
{
- jtag_add_ir_scan_noverify(in_num_fields, in_fields, state);
+ jtag_add_ir_scan_noverify(active, in_fields, state);
}
}
-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);
}
-void jtag_add_callback(jtag_callback1_t f, jtag_callback_data_t data0)
-{
- interface_jtag_add_callback(f, data0);
-}
-
-void jtag_add_callback4(jtag_callback_t f, jtag_callback_data_t data0,
- jtag_callback_data_t data1, jtag_callback_data_t data2,
- jtag_callback_data_t data3)
-{
- interface_jtag_add_callback4(f, data0, data1, data2, data3);
-}
-
static int jtag_check_value_inner(uint8_t *captured, uint8_t *in_check_value,
uint8_t *in_check_mask, int num_bits);
return jtag_check_value_inner((uint8_t *)data0, (uint8_t *)data1, (uint8_t *)data2, (int)data3);
}
-static void jtag_add_scan_check(void (*jtag_add_scan)(int in_num_fields, const struct scan_field *in_fields, tap_state_t state),
+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++)
field->modified = 1;
}
- jtag_add_scan(in_num_fields, in_fields, state);
+ jtag_add_scan(active, in_num_fields, in_fields, state);
for (int i = 0; i < in_num_fields; i++)
{
}
}
-void jtag_add_dr_scan_check(int in_num_fields, struct scan_field *in_fields, tap_state_t state)
+void jtag_add_dr_scan_check(struct jtag_tap *active, int in_num_fields, struct scan_field *in_fields, tap_state_t state)
{
if (jtag_verify)
{
- jtag_add_scan_check(jtag_add_dr_scan, in_num_fields, in_fields, state);
+ jtag_add_scan_check(active, jtag_add_dr_scan, in_num_fields, in_fields, state);
} else
{
- jtag_add_dr_scan(in_num_fields, in_fields, state);
+ jtag_add_dr_scan(active, in_num_fields, in_fields, state);
}
}
-void jtag_add_dr_scan(int in_num_fields, const struct scan_field *in_fields,
+void jtag_add_dr_scan(struct jtag_tap *active, int in_num_fields, const struct scan_field *in_fields,
tap_state_t state)
{
assert(state != TAP_RESET);
jtag_prelude(state);
int retval;
- retval = interface_jtag_add_dr_scan(in_num_fields, in_fields, state);
+ retval = interface_jtag_add_dr_scan(active, in_num_fields, in_fields, state);
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);
}
-void jtag_add_dr_out(struct jtag_tap* 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;
-
- interface_jtag_add_dr_out(tap,
- num_fields, num_bits, value,
- end_state);
-}
-
void jtag_add_tlr(void)
{
jtag_prelude(TAP_RESET);
jtag_notify_event(JTAG_TRST_ASSERTED);
}
+/**
+ * If supported by the underlying adapter, this clocks a raw bit sequence
+ * onto TMS for switching betwen JTAG and SWD modes.
+ *
+ * DO NOT use this to bypass the integrity checks and logging provided
+ * by the jtag_add_pathmove() and jtag_add_statemove() calls.
+ *
+ * @param nbits How many bits to clock out.
+ * @param seq The bit sequence. The LSB is bit 0 of seq[0].
+ * @param state The JTAG tap state to record on completion. Use
+ * TAP_INVALID to represent being in in SWD mode.
+ *
+ * @todo Update naming conventions to stop assuming everything is JTAG.
+ */
+int jtag_add_tms_seq(unsigned nbits, const uint8_t *seq, enum tap_state state)
+{
+ int retval;
+
+ if (!(jtag->supported & DEBUG_CAP_TMS_SEQ))
+ return ERROR_JTAG_NOT_IMPLEMENTED;
+
+ jtag_checks();
+ cmd_queue_cur_state = state;
+
+ retval = interface_add_tms_seq(nbits, seq, state);
+ jtag_set_error(retval);
+ return retval;
+}
+
void jtag_add_pathmove(int num_states, const tap_state_t *path)
{
tap_state_t cur_state = cmd_queue_cur_state;
{
tap_state_t cur_state = cmd_queue_cur_state;
- LOG_DEBUG("cur_state=%s goal_state=%s",
- tap_state_name(cur_state),
- tap_state_name(goal_state));
-
+ if (goal_state != cur_state)
+ {
+ LOG_DEBUG("cur_state=%s goal_state=%s",
+ tap_state_name(cur_state),
+ tap_state_name(goal_state));
+ }
/* If goal is RESET, be paranoid and force that that transition
* (e.g. five TCK cycles, TMS high). Else trust "cur_state".
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));
+ assert(tms_count < ARRAY_SIZE(moves));
for (unsigned i = 0; i < tms_count; i++, tms_bits >>= 1)
{
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);
}
}
*/
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!!!
uint8_t *in_check_mask, int num_bits)
{
int retval = ERROR_OK;
-
- int compare_failed = 0;
+ int compare_failed;
if (in_check_mask)
compare_failed = buf_cmp_mask(captured, in_check_value, in_check_mask, num_bits);
static int jtag_examine_chain_execute(uint8_t *idcode_buffer, unsigned num_idcode)
{
struct scan_field field = {
- .tap = NULL,
.num_bits = num_idcode * 32,
.out_value = idcode_buffer,
.in_value = idcode_buffer,
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();
}
static bool jtag_examine_chain_match_tap(const struct jtag_tap *tap)
{
+ uint32_t idcode = tap->idcode;
+
/* ignore expected BYPASS codes; warn otherwise */
- if (0 == tap->expected_ids_cnt && !tap->idcode)
+ if (0 == tap->expected_ids_cnt && !idcode)
return true;
+ /* optionally ignore the JTAG version field */
+ uint32_t mask = tap->ignore_version ? ~(0xff << 24) : ~0;
+
+ idcode &= mask;
+
/* Loop over the expected identification codes and test for a match */
unsigned ii, limit = tap->expected_ids_cnt;
for (ii = 0; ii < limit; ii++)
{
- if (tap->idcode == tap->expected_ids[ii])
+ uint32_t expected = tap->expected_ids[ii] & mask;
+
+ if (idcode == expected)
return true;
/* treat "-expected-id 0" as a "don't-warn" wildcard */
if ((idcode & 1) == 0)
{
/* Zero for LSB indicates a device in bypass */
- LOG_WARNING("TAP %s does not have IDCODE",
+ LOG_INFO("TAP %s does not have IDCODE",
tap->dotted_name);
idcode = 0;
tap->hasidcode = false;
/* increase length to add 2 bit sentinel after scan */
total_ir_length += 2;
- ir_test = malloc(CEIL(total_ir_length, 8));
+ ir_test = malloc(DIV_ROUND_UP(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;
field.num_bits = total_ir_length;
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();
/* If we're autoprobing, guess IR lengths. They must be at
* least two bits. Guessing will fail if (a) any TAP does
* not conform to the JTAG spec; or (b) when the upper bits
- * captured from some conforming TAP are nonzero.
+ * captured from some conforming TAP are nonzero. Or if
+ * (c) an IR length is longer than 32 bits -- which is only
+ * an implementation limit, which could someday be raised.
+ *
+ * REVISIT optimization: if there's a *single* TAP we can
+ * lift restrictions (a) and (b) by scanning a recognizable
+ * pattern before the all-ones BYPASS. Check for where the
+ * pattern starts in the result, instead of an 0...01 value.
*
* REVISIT alternative approach: escape to some tcl code
* which could provide more knowledge, based on IDCODE; and
if (tap->ir_length == 0) {
tap->ir_length = 2;
while ((val = buf_get_u32(ir_test, chain_pos,
- tap->ir_length + 1)) == 1) {
+ tap->ir_length + 1)) == 1
+ && tap->ir_length <= 32) {
tap->ir_length++;
}
LOG_WARNING("AUTO %s - use \"... -irlen %d\"",
/* if we're autoprobing, cope with potentially huge ir_length */
ir_len_bits = tap->ir_length ? : JTAG_IRLEN_MAX;
- ir_len_bytes = CEIL(ir_len_bits, 8);
+ ir_len_bytes = DIV_ROUND_UP(ir_len_bits, 8);
tap->expected = calloc(1, ir_len_bytes);
tap->expected_mask = calloc(1, ir_len_bytes);
free(tap);
}
-int jtag_interface_init(struct command_context_s *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;
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 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());
+ LOG_INFO("adapter-specific clock speed value %d", jtag_get_speed());
else if (actual_khz)
{
+ /* Adaptive clocking -- JTAG-specific */
if ((CLOCK_MODE_RCLK == clock_mode)
|| ((CLOCK_MODE_KHZ == clock_mode) && !requested_khz))
{
return ERROR_OK;
}
-int jtag_init_inner(struct command_context_s *cmd_ctx)
+int jtag_init_inner(struct command_context *cmd_ctx)
{
struct jtag_tap *tap;
int retval;
return ERROR_OK;
}
-int jtag_interface_quit(void)
+int adapter_quit(void)
{
if (!jtag || !jtag->quit)
return ERROR_OK;
}
-int jtag_init_reset(struct command_context_s *cmd_ctx)
+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");
return jtag_init_inner(cmd_ctx);
}
-int jtag_init(struct command_context_s *cmd_ctx)
+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 */
if ((retval = jtag_execute_queue()) != ERROR_OK)
return retval;
- if (Jim_Eval_Named(interp, "jtag_init", __FILE__, __LINE__) != JIM_OK)
+ if (Jim_Eval_Named(cmd_ctx->interp, "jtag_init", __FILE__, __LINE__) != JIM_OK)
return ERROR_FAIL;
return ERROR_OK;
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;
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;
}
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);
}
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);
int jtag_power_dropout(int *dropout)
{
+ if (jtag == NULL)
+ {
+ /* TODO: as the jtag interface is not valid all
+ * we can do at the moment is exit OpenOCD */
+ LOG_ERROR("No Valid JTAG Interface Configured.");
+ exit(-1);
+ }
return jtag->power_dropout(dropout);
}
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)
{
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)
{