jtag: Rewrite TAP verification/auto-probe logic
Enable auto-creating additional discovered TAPs even if some TAPs are predefined, avoiding initialization failure when it's not necessary. Also, drop the arbitrary limit on the number of predefined TAPs. Still, don't auto-create any if there are more than 20 TAPs already, to stop a noisy connection from creating unlimited TAPs. Create auto-probed TAPs with less noise. Reduce code duplication between verification and auto-probing. Change-Id: I82a504d92dbcc0060206e71f10c5158256b5f561 Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com> Reviewed-on: http://openocd.zylin.com/2236 Tested-by: jenkins Reviewed-by: Paul Fertser <fercerpav@gmail.com>__archive__
parent
24fb042a73
commit
1fa4c728aa
172
src/jtag/core.c
172
src/jtag/core.c
|
@ -886,11 +886,7 @@ void jtag_sleep(uint32_t us)
|
|||
alive_sleep((us+999)/1000);
|
||||
}
|
||||
|
||||
/* Maximum number of enabled JTAG devices we expect in the scan chain,
|
||||
* plus one (to detect garbage at the end). Devices that don't support
|
||||
* IDCODE take up fewer bits, possibly allowing a few more devices.
|
||||
*/
|
||||
#define JTAG_MAX_CHAIN_SIZE 20
|
||||
#define JTAG_MAX_AUTO_TAPS 20
|
||||
|
||||
#define EXTRACT_MFG(X) (((X) & 0xffe) >> 1)
|
||||
#define EXTRACT_PART(X) (((X) & 0xffff000) >> 12)
|
||||
|
@ -913,7 +909,7 @@ static int jtag_examine_chain_execute(uint8_t *idcode_buffer, unsigned num_idcod
|
|||
};
|
||||
|
||||
/* initialize to the end of chain ID value */
|
||||
for (unsigned i = 0; i < JTAG_MAX_CHAIN_SIZE; i++)
|
||||
for (unsigned i = 0; i < num_idcode; i++)
|
||||
buf_set_u32(idcode_buffer, i * 32, 32, END_OF_CHAIN_FLAG);
|
||||
|
||||
jtag_add_plain_dr_scan(field.num_bits, field.out_value, field.in_value, TAP_DRPAUSE);
|
||||
|
@ -998,21 +994,16 @@ static bool jtag_examine_chain_end(uint8_t *idcodes, unsigned count, unsigned ma
|
|||
|
||||
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 && !idcode)
|
||||
if (tap->expected_ids_cnt == 0 || !tap->hasidcode)
|
||||
return true;
|
||||
|
||||
/* optionally ignore the JTAG version field - bits 28-31 of IDCODE */
|
||||
uint32_t mask = tap->ignore_version ? ~(0xf << 28) : ~0;
|
||||
|
||||
idcode &= mask;
|
||||
uint32_t idcode = tap->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++) {
|
||||
for (unsigned ii = 0; ii < tap->expected_ids_cnt; ii++) {
|
||||
uint32_t expected = tap->expected_ids[ii] & mask;
|
||||
|
||||
if (idcode == expected)
|
||||
|
@ -1026,10 +1017,10 @@ static bool jtag_examine_chain_match_tap(const struct jtag_tap *tap)
|
|||
/* 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 < limit; ii++) {
|
||||
for (unsigned ii = 0; ii < tap->expected_ids_cnt; ii++) {
|
||||
char msg[32];
|
||||
|
||||
snprintf(msg, sizeof(msg), "expected %u of %u", ii + 1, limit);
|
||||
snprintf(msg, sizeof(msg), "expected %u of %u", ii + 1, tap->expected_ids_cnt);
|
||||
jtag_examine_chain_display(LOG_LVL_ERROR, msg,
|
||||
tap->dotted_name, tap->expected_ids[ii]);
|
||||
}
|
||||
|
@ -1041,71 +1032,44 @@ static bool jtag_examine_chain_match_tap(const struct jtag_tap *tap)
|
|||
*/
|
||||
static int jtag_examine_chain(void)
|
||||
{
|
||||
uint8_t idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4];
|
||||
unsigned bit_count;
|
||||
int retval;
|
||||
int tapcount = 0;
|
||||
bool autoprobe = false;
|
||||
unsigned max_taps = jtag_tap_count();
|
||||
|
||||
/* Autoprobe up to this many. */
|
||||
if (max_taps < JTAG_MAX_AUTO_TAPS)
|
||||
max_taps = JTAG_MAX_AUTO_TAPS;
|
||||
|
||||
/* Add room for end-of-chain marker. */
|
||||
max_taps++;
|
||||
|
||||
uint8_t *idcode_buffer = malloc(max_taps * 4);
|
||||
if (idcode_buffer == NULL)
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
|
||||
/* DR scan to collect BYPASS or IDCODE register contents.
|
||||
* Then make sure the scan data has both ones and zeroes.
|
||||
*/
|
||||
LOG_DEBUG("DR scan interrogation for IDCODE/BYPASS");
|
||||
retval = jtag_examine_chain_execute(idcode_buffer, JTAG_MAX_CHAIN_SIZE);
|
||||
retval = jtag_examine_chain_execute(idcode_buffer, max_taps);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
if (!jtag_examine_chain_check(idcode_buffer, JTAG_MAX_CHAIN_SIZE))
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
goto out;
|
||||
if (!jtag_examine_chain_check(idcode_buffer, max_taps)) {
|
||||
retval = ERROR_JTAG_INIT_FAILED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* point at the 1st tap */
|
||||
/* Point at the 1st predefined tap, if any */
|
||||
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;
|
||||
tap = jtag_tap_next_enabled(tap)) {
|
||||
unsigned bit_count = 0;
|
||||
unsigned autocount = 0;
|
||||
for (unsigned i = 0; i < max_taps; i++) {
|
||||
assert(bit_count < max_taps * 32);
|
||||
uint32_t idcode = buf_get_u32(idcode_buffer, bit_count, 32);
|
||||
|
||||
if ((idcode & 1) == 0) {
|
||||
/* Zero for LSB indicates a device in bypass */
|
||||
LOG_INFO("TAP %s does not have IDCODE",
|
||||
tap->dotted_name);
|
||||
idcode = 0;
|
||||
tap->hasidcode = false;
|
||||
|
||||
bit_count += 1;
|
||||
} else {
|
||||
/* Friendly devices support IDCODE */
|
||||
tap->hasidcode = true;
|
||||
jtag_examine_chain_display(LOG_LVL_INFO,
|
||||
"tap/device found",
|
||||
tap->dotted_name, idcode);
|
||||
|
||||
bit_count += 32;
|
||||
}
|
||||
tap->idcode = idcode;
|
||||
|
||||
/* ensure the TAP ID matches what was expected */
|
||||
if (!jtag_examine_chain_match_tap(tap))
|
||||
retval = ERROR_JTAG_INIT_SOFT_FAIL;
|
||||
}
|
||||
|
||||
/* Fail if too many TAPs were enabled for us to verify them all. */
|
||||
if (tap) {
|
||||
LOG_ERROR("Too many TAPs enabled; '%s' ignored.",
|
||||
tap->dotted_name);
|
||||
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];
|
||||
|
||||
/* No predefined TAP? Auto-probe. */
|
||||
if (tap == NULL) {
|
||||
/* Is there another TAP? */
|
||||
idcode = buf_get_u32(idcode_buffer, bit_count, 32);
|
||||
if (jtag_idcode_is_final(idcode))
|
||||
break;
|
||||
|
||||
|
@ -1115,56 +1079,61 @@ static int jtag_examine_chain(void)
|
|||
* share it with jim_newtap_cmd().
|
||||
*/
|
||||
tap = calloc(1, sizeof *tap);
|
||||
if (!tap)
|
||||
return ERROR_FAIL;
|
||||
if (!tap) {
|
||||
retval = ERROR_FAIL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
sprintf(buf, "auto%d", tapcount++);
|
||||
tap->chip = strdup(buf);
|
||||
tap->chip = alloc_printf("auto%u", autocount++);
|
||||
tap->tapname = strdup("tap");
|
||||
tap->dotted_name = alloc_printf("%s.%s", tap->chip, tap->tapname);
|
||||
|
||||
sprintf(buf, "%s.%s", tap->chip, tap->tapname);
|
||||
tap->dotted_name = strdup(buf);
|
||||
|
||||
/* tap->ir_length == 0 ... signifying irlen autoprobe */
|
||||
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;
|
||||
jtag_tap_init(tap);
|
||||
}
|
||||
|
||||
LOG_WARNING("AUTO %s - use \"jtag newtap "
|
||||
"%s %s -expected-id 0x%8.8" PRIx32 " ...\"",
|
||||
tap->dotted_name, tap->chip, tap->tapname,
|
||||
tap->idcode);
|
||||
if ((idcode & 1) == 0) {
|
||||
/* Zero for LSB indicates a device in bypass */
|
||||
LOG_INFO("TAP %s does not have IDCODE", tap->dotted_name);
|
||||
tap->hasidcode = false;
|
||||
tap->idcode = 0;
|
||||
|
||||
jtag_tap_init(tap);
|
||||
bit_count += 1;
|
||||
} else {
|
||||
/* Friendly devices support IDCODE */
|
||||
tap->hasidcode = true;
|
||||
tap->idcode = idcode;
|
||||
jtag_examine_chain_display(LOG_LVL_INFO, "tap/device found", tap->dotted_name, idcode);
|
||||
|
||||
bit_count += 32;
|
||||
}
|
||||
|
||||
/* ensure the TAP ID matches what was expected */
|
||||
if (!jtag_examine_chain_match_tap(tap))
|
||||
retval = ERROR_JTAG_INIT_SOFT_FAIL;
|
||||
|
||||
tap = jtag_tap_next_enabled(tap);
|
||||
}
|
||||
|
||||
/* After those IDCODE or BYPASS register values should be
|
||||
* only the data we fed into the scan chain.
|
||||
*/
|
||||
if (jtag_examine_chain_end(idcode_buffer, bit_count,
|
||||
8 * sizeof(idcode_buffer))) {
|
||||
LOG_ERROR("double-check your JTAG setup (interface, "
|
||||
"speed, missing TAPs, ...)");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
if (jtag_examine_chain_end(idcode_buffer, bit_count, max_taps * 32)) {
|
||||
LOG_ERROR("double-check your JTAG setup (interface, speed, ...)");
|
||||
retval = ERROR_JTAG_INIT_FAILED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Return success or, for backwards compatibility if only
|
||||
* some IDCODE values mismatched, a soft/continuable fault.
|
||||
*/
|
||||
out:
|
||||
free(idcode_buffer);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -1227,7 +1196,7 @@ static int jtag_validate_ircapture(void)
|
|||
* 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. Or if
|
||||
* (c) an IR length is longer than 32 bits -- which is only
|
||||
* (c) an IR length is longer than JTAG_IRLEN_MAX bits,
|
||||
* an implementation limit, which could someday be raised.
|
||||
*
|
||||
* REVISIT optimization: if there's a *single* TAP we can
|
||||
|
@ -1242,11 +1211,12 @@ static int jtag_validate_ircapture(void)
|
|||
if (tap->ir_length == 0) {
|
||||
tap->ir_length = 2;
|
||||
while ((val = buf_get_u64(ir_test, chain_pos, tap->ir_length + 1)) == 1
|
||||
&& tap->ir_length <= 64) {
|
||||
&& tap->ir_length < JTAG_IRLEN_MAX) {
|
||||
tap->ir_length++;
|
||||
}
|
||||
LOG_WARNING("AUTO %s - use \"... -irlen %d\"",
|
||||
jtag_tap_name(tap), tap->ir_length);
|
||||
LOG_WARNING("AUTO %s - use \"jtag newtap " "%s %s -irlen %d "
|
||||
"-expected-id 0x%08" PRIx32 "\"",
|
||||
tap->dotted_name, tap->chip, tap->tapname, tap->ir_length, tap->idcode);
|
||||
}
|
||||
|
||||
/* Validate the two LSBs, which must be 01 per JTAG spec.
|
||||
|
|
Loading…
Reference in New Issue