/// 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 scan_field_t *in_fields, tap_state_t state),
- int in_num_fields, scan_field_t *in_fields, tap_state_t state);
+static void jtag_add_scan_check(void (*jtag_add_scan)(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);
/**
* The jtag_error variable is set when an error occurs while executing
/**
* List all TAPs that have been created.
*/
-static jtag_tap_t *__jtag_all_taps = NULL;
+static struct jtag_tap *__jtag_all_taps = NULL;
/**
* The number of TAPs in the __jtag_all_taps list, used to track the
* assigned chain position to new TAPs
/************/
-jtag_tap_t *jtag_all_taps(void)
+struct jtag_tap *jtag_all_taps(void)
{
return __jtag_all_taps;
};
unsigned jtag_tap_count_enabled(void)
{
- jtag_tap_t *t = jtag_all_taps();
+ struct jtag_tap *t = jtag_all_taps();
unsigned n = 0;
while (t)
{
}
/// Append a new TAP to the chain of all taps.
-void jtag_tap_add(struct jtag_tap_s *t)
+void jtag_tap_add(struct jtag_tap *t)
{
t->abs_chain_position = jtag_num_taps++;
- jtag_tap_t **tap = &__jtag_all_taps;
+ struct jtag_tap **tap = &__jtag_all_taps;
while (*tap != NULL)
tap = &(*tap)->next_tap;
*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)
+static inline struct jtag_tap *jtag_tap_by_position(unsigned n)
{
- jtag_tap_t *t = jtag_all_taps();
+ struct jtag_tap *t = jtag_all_taps();
while (t && n-- > 0)
t = t->next_tap;
return t;
}
-jtag_tap_t *jtag_tap_by_string(const char *s)
+struct jtag_tap *jtag_tap_by_string(const char *s)
{
/* try by name first */
- jtag_tap_t *t = jtag_all_taps();
+ struct jtag_tap *t = jtag_all_taps();
while (t)
{
return t;
}
-jtag_tap_t *jtag_tap_by_jim_obj(Jim_Interp *interp, Jim_Obj *o)
+struct jtag_tap *jtag_tap_by_jim_obj(Jim_Interp *interp, Jim_Obj *o)
{
const char *cp = Jim_GetString(o, NULL);
- jtag_tap_t *t = cp ? jtag_tap_by_string(cp) : NULL;
+ struct jtag_tap *t = cp ? jtag_tap_by_string(cp) : NULL;
if (NULL == cp)
cp = "(unknown)";
if (NULL == t)
return t;
}
-jtag_tap_t* jtag_tap_next_enabled(jtag_tap_t* p)
+struct jtag_tap* jtag_tap_next_enabled(struct jtag_tap* p)
{
p = p ? p->next_tap : jtag_all_taps();
while (p)
return NULL;
}
-const char *jtag_tap_name(const jtag_tap_t *tap)
+const char *jtag_tap_name(const struct jtag_tap *tap)
{
return (tap == NULL) ? "(unknown)" : tap->dotted_name;
}
cmd_queue_cur_state = state;
}
-void jtag_alloc_in_value32(scan_field_t *field)
+void jtag_alloc_in_value32(struct scan_field *field)
{
interface_jtag_alloc_in_value32(field);
}
-void jtag_add_ir_scan_noverify(int in_count, const scan_field_t *in_fields,
+void jtag_add_ir_scan_noverify(int in_count, const struct scan_field *in_fields,
tap_state_t state)
{
jtag_prelude(state);
}
-void jtag_add_ir_scan(int in_num_fields, scan_field_t *in_fields, tap_state_t state)
+void jtag_add_ir_scan(int in_num_fields, struct scan_field *in_fields, tap_state_t state)
{
assert(state != TAP_RESET);
}
}
-void jtag_add_plain_ir_scan(int in_num_fields, const scan_field_t *in_fields,
+void jtag_add_plain_ir_scan(int in_num_fields, const struct scan_field *in_fields,
tap_state_t state)
{
assert(state != TAP_RESET);
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 scan_field_t *in_fields, tap_state_t state),
- int in_num_fields, scan_field_t *in_fields, tap_state_t state)
+static void jtag_add_scan_check(void (*jtag_add_scan)(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_s *field = &in_fields[i];
+ struct scan_field *field = &in_fields[i];
field->allocated = 0;
field->modified = 0;
if (field->check_value || field->in_value)
}
}
-void jtag_add_dr_scan_check(int in_num_fields, scan_field_t *in_fields, tap_state_t state)
+void jtag_add_dr_scan_check(int in_num_fields, struct scan_field *in_fields, tap_state_t state)
{
if (jtag_verify)
{
}
-void jtag_add_dr_scan(int in_num_fields, const scan_field_t *in_fields,
+void jtag_add_dr_scan(int in_num_fields, const struct scan_field *in_fields,
tap_state_t state)
{
assert(state != TAP_RESET);
jtag_set_error(retval);
}
-void jtag_add_plain_dr_scan(int in_num_fields, const scan_field_t *in_fields,
+void jtag_add_plain_dr_scan(int in_num_fields, const struct scan_field *in_fields,
tap_state_t state)
{
assert(state != TAP_RESET);
jtag_set_error(retval);
}
-void jtag_add_dr_out(jtag_tap_t* tap,
+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)
{
tap_state_name(goal_state));
- if (goal_state == cur_state)
- ; /* nothing to do */
- else if (goal_state == TAP_RESET)
- {
+ /* If goal is RESET, be paranoid and force that that transition
+ * (e.g. five TCK cycles, TMS high). Else trust "cur_state".
+ */
+ if (goal_state == TAP_RESET)
jtag_add_tlr();
- }
+ else if (goal_state == cur_state)
+ /* nothing to do */ ;
+
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);
return retval;
}
-void jtag_check_value_mask(scan_field_t *field, uint8_t *value, uint8_t *mask)
+void jtag_check_value_mask(struct scan_field *field, uint8_t *value, uint8_t *mask)
{
assert(field->in_value != NULL);
static int jtag_reset_callback(enum jtag_event event, void *priv)
{
- jtag_tap_t *tap = priv;
+ struct jtag_tap *tap = priv;
if (event == JTAG_TRST_ASSERTED)
{
*/
#define END_OF_CHAIN_FLAG 0x000000ff
+/* a larger IR length than we ever expect to autoprobe */
+#define JTAG_IRLEN_MAX 60
+
static int jtag_examine_chain_execute(uint8_t *idcode_buffer, unsigned num_idcode)
{
- scan_field_t field = {
+ struct scan_field field = {
.tap = NULL,
.num_bits = num_idcode * 32,
.out_value = idcode_buffer,
return triggered;
}
-static bool jtag_examine_chain_match_tap(const struct jtag_tap_s *tap)
+static bool jtag_examine_chain_match_tap(const struct jtag_tap *tap)
{
/* 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++)
+ unsigned ii, limit = tap->expected_ids_cnt;
+
+ for (ii = 0; ii < limit; ii++)
{
if (tap->idcode == tap->expected_ids[ii])
return true;
/* 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++)
+ for (ii = 0; ii < limit; ii++)
{
char msg[32];
- snprintf(msg, sizeof(msg), "expected %hhu of %hhu",
- ii + 1, tap->expected_ids_cnt);
+
+ snprintf(msg, sizeof(msg), "expected %u of %u", ii + 1, limit);
jtag_examine_chain_display(LOG_LVL_ERROR, msg,
tap->dotted_name, tap->expected_ids[ii]);
}
uint8_t idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4];
unsigned bit_count;
int retval;
+ int tapcount = 0;
+ bool autoprobe = false;
/* DR scan to collect BYPASS or IDCODE register contents.
* Then make sure the scan data has both ones and zeroes.
return ERROR_JTAG_INIT_FAILED;
/* point at the 1st tap */
- jtag_tap_t *tap = jtag_tap_next_enabled(NULL);
- if (tap == NULL)
- {
- LOG_ERROR("JTAG: No taps enabled?");
- return ERROR_JTAG_INIT_FAILED;
- }
+ struct jtag_tap *tap = jtag_tap_next_enabled(NULL);
+
+ if (!tap)
+ autoprobe = true;
for (bit_count = 0;
tap && bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31;
return ERROR_JTAG_INIT_FAILED;
}
+ /* if autoprobing, the tap list is still empty ... populate it! */
+ while (autoprobe && bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31) {
+ uint32_t idcode;
+ char buf[12];
+
+ /* Is there another TAP? */
+ idcode = buf_get_u32(idcode_buffer, bit_count, 32);
+ if (jtag_idcode_is_final(idcode))
+ break;
+
+ /* Default everything in this TAP except IR length.
+ *
+ * REVISIT create a jtag_alloc(chip, tap) routine, and
+ * share it with jim_newtap_cmd().
+ */
+ tap = calloc(1, sizeof *tap);
+ if (!tap)
+ return ERROR_FAIL;
+
+ sprintf(buf, "auto%d", tapcount++);
+ tap->chip = strdup(buf);
+ tap->tapname = strdup("tap");
+
+ sprintf(buf, "%s.%s", tap->chip, tap->tapname);
+ tap->dotted_name = strdup(buf);
+
+ /* tap->ir_length == 0 ... signifying irlen autoprobe */
+ tap->ir_capture_mask = 0x03;
+ tap->ir_capture_value = 0x01;
+
+ tap->enabled = true;
+
+ if ((idcode & 1) == 0) {
+ bit_count += 1;
+ tap->hasidcode = false;
+ } else {
+ bit_count += 32;
+ tap->hasidcode = true;
+ tap->idcode = idcode;
+
+ tap->expected_ids_cnt = 1;
+ tap->expected_ids = malloc(sizeof(uint32_t));
+ tap->expected_ids[0] = idcode;
+ }
+
+ LOG_WARNING("AUTO %s - use \"jtag newtap "
+ "%s %s -expected-id 0x%8.8" PRIx32 " ...\"",
+ tap->dotted_name, tap->chip, tap->tapname,
+ tap->idcode);
+
+ jtag_tap_init(tap);
+ }
+
/* After those IDCODE or BYPASS register values should be
* only the data we fed into the scan chain.
*/
*/
static int jtag_validate_ircapture(void)
{
- jtag_tap_t *tap;
+ struct jtag_tap *tap;
int total_ir_length = 0;
uint8_t *ir_test = NULL;
- scan_field_t field;
+ struct scan_field field;
int val;
int chain_pos = 0;
int retval;
+ /* when autoprobing, accomodate huge IR lengths */
for (tap = NULL, total_ir_length = 0;
(tap = jtag_tap_next_enabled(tap)) != NULL;
- total_ir_length += tap->ir_length)
- continue;
+ total_ir_length += tap->ir_length) {
+ if (tap->ir_length == 0)
+ total_ir_length += JTAG_IRLEN_MAX;
+ }
/* increase length to add 2 bit sentinel after scan */
total_ir_length += 2;
break;
}
+ /* 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.
+ *
+ * REVISIT alternative approach: escape to some tcl code
+ * which could provide more knowledge, based on IDCODE; and
+ * only guess when that has no success.
+ */
+ 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++;
+ }
+ LOG_WARNING("AUTO %s - use \"... -irlen %d\"",
+ jtag_tap_name(tap), tap->ir_length);
+ }
+
/* Validate the two LSBs, which must be 01 per JTAG spec.
*
* Or ... more bits could be provided by TAP declaration.
}
-void jtag_tap_init(jtag_tap_t *tap)
+void jtag_tap_init(struct jtag_tap *tap)
{
- assert(0 != tap->ir_length);
+ unsigned ir_len_bits;
+ unsigned ir_len_bytes;
- /// @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);
+ /* 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);
- /// @todo cope sanely with ir_length bigger than 32 bits
- buf_set_u32(tap->expected, 0, tap->ir_length, tap->ir_capture_value);
- buf_set_u32(tap->expected_mask, 0, tap->ir_length, tap->ir_capture_mask);
- buf_set_ones(tap->cur_instr, tap->ir_length);
+ tap->expected = calloc(1, ir_len_bytes);
+ tap->expected_mask = calloc(1, ir_len_bytes);
+ tap->cur_instr = malloc(ir_len_bytes);
- // place TAP in bypass mode
+ /// @todo cope better with ir_length bigger than 32 bits
+ if (ir_len_bits > 32)
+ ir_len_bits = 32;
+
+ buf_set_u32(tap->expected, 0, ir_len_bits, tap->ir_capture_value);
+ buf_set_u32(tap->expected_mask, 0, ir_len_bits, tap->ir_capture_mask);
+
+ // TAP will be in bypass mode after jtag_validate_ircapture()
tap->bypass = 1;
+ buf_set_ones(tap->cur_instr, tap->ir_length);
+
// register the reset callback for the TAP
jtag_register_event_callback(&jtag_reset_callback, tap);
jtag_tap_add(tap);
}
-void jtag_tap_free(jtag_tap_t *tap)
+void jtag_tap_free(struct jtag_tap *tap)
{
jtag_unregister_event_callback(&jtag_reset_callback, tap);
int jtag_init_inner(struct command_context_s *cmd_ctx)
{
- jtag_tap_t *tap;
+ struct jtag_tap *tap;
int retval;
bool issue_setup = true;
tap = jtag_tap_next_enabled(NULL);
if (tap == NULL) {
- LOG_ERROR("There are no enabled taps?");
- return ERROR_JTAG_INIT_FAILED;
+ /* Once JTAG itself is properly set up, and the scan chain
+ * isn't absurdly large, IDCODE autoprobe should work fine.
+ *
+ * But ... IRLEN autoprobe can fail even on systems which
+ * are fully conformant to JTAG. Also, JTAG setup can be
+ * quite finicky on some systems.
+ *
+ * REVISIT: if TAP autoprobe works OK, then in many cases
+ * we could escape to tcl code and set up targets based on
+ * the TAP's IDCODE values.
+ */
+ LOG_WARNING("There are no enabled taps. "
+ "AUTO PROBING MIGHT NOT WORK!!");
+
+ /* REVISIT default clock will often be too fast ... */
}
jtag_add_tlr();
return jtag ? jtag->speed(speed) : ERROR_OK;
}
-int jtag_config_speed(int speed)
-{
- 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");