JTAG: simple autoprobing
This patch adds basic autoprobing support for the JTAG scan chains which cooperate. To use, you can invoke OpenOCD with just: - interface spec: "-f interface/...cfg" - possibly with "-c 'reset_config ...'" for SRST/TRST - possibly with "-c 'jtag_khz ...'" for the JTAG clock Then set up config files matching the reported TAPs. It doesn't declare targets ... just TAPs. So facilities above the JTAG and SVF/XSVF levels won't be available without a real config; this is almost purely a way to generate diagnostics. Autoprobe was successful with most boards I tested, except ones incorporating C55x DSPs (which don't cooperate with this scheme for IR length autodetection). Here's what one multi-TAP chip reported, with the "Warn:" prefixes removed: clock speed 500 kHz There are no enabled taps. AUTO PROBING MIGHT NOT WORK!! AUTO auto0.tap - use "jtag newtap auto0 tap -expected-id 0x2b900f0f ..." AUTO auto1.tap - use "jtag newtap auto1 tap -expected-id 0x07926001 ..." AUTO auto2.tap - use "jtag newtap auto2 tap -expected-id 0x0b73b02f ..." AUTO auto0.tap - use "... -irlen 4" AUTO auto1.tap - use "... -irlen 4" AUTO auto2.tap - use "... -irlen 6" no gdb ports allocated as no target has been specified The patch tweaks IR setup a bit, so we can represent TAPs with undeclared IR length. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>__archive__
parent
0cac8b67be
commit
6cb1d10cda
9
TODO
9
TODO
|
@ -55,8 +55,10 @@ directly in minidriver API for better embedded host performance.
|
||||||
|
|
||||||
The following tasks have been suggested for adding new core JTAG support:
|
The following tasks have been suggested for adding new core JTAG support:
|
||||||
|
|
||||||
- autodetect devices present on the scan chain
|
- Improve autodetection of TAPs by supporting tcl escape procedures that
|
||||||
- implement 'discover_taps' command
|
can configure discovered TAPs based on IDCODE value ... they could:
|
||||||
|
- Remove guessing for irlen
|
||||||
|
- Allow non-default irmask/ircapture values
|
||||||
- SPI/UART emulation:
|
- SPI/UART emulation:
|
||||||
- (ab)use bit-banging JTAG interfaces to emulate SPI/UART
|
- (ab)use bit-banging JTAG interfaces to emulate SPI/UART
|
||||||
- allow SPI to program flash, MCUs, etc.
|
- allow SPI to program flash, MCUs, etc.
|
||||||
|
@ -94,6 +96,8 @@ interface support:
|
||||||
- FT2232 (libftdi):
|
- FT2232 (libftdi):
|
||||||
- make performance comparable to alternatives (on Win32, D2XX is faster)
|
- make performance comparable to alternatives (on Win32, D2XX is faster)
|
||||||
- make usability comparable to alternatives
|
- make usability comparable to alternatives
|
||||||
|
- Autodetect USB based adapters; this should be easy on Linux. If there's
|
||||||
|
more than one, list the options; otherwise, just select that one.
|
||||||
|
|
||||||
The following tasks have been suggested for adding new JTAG interfaces:
|
The following tasks have been suggested for adding new JTAG interfaces:
|
||||||
|
|
||||||
|
@ -133,6 +137,7 @@ Once the above are completed:
|
||||||
|
|
||||||
@section thelisttargets Target Support
|
@section thelisttargets Target Support
|
||||||
|
|
||||||
|
- Many common ARM cores could be autodetected using IDCODE
|
||||||
- general layer cleanup: @par
|
- general layer cleanup: @par
|
||||||
https://lists.berlios.de/pipermail/openocd-development/2009-May/006590.html
|
https://lists.berlios.de/pipermail/openocd-development/2009-May/006590.html
|
||||||
- regression: "reset halt" between 729(works) and 788(fails): @par
|
- regression: "reset halt" between 729(works) and 788(fails): @par
|
||||||
|
|
114
src/jtag/core.c
114
src/jtag/core.c
|
@ -890,6 +890,9 @@ void jtag_sleep(uint32_t us)
|
||||||
*/
|
*/
|
||||||
#define END_OF_CHAIN_FLAG 0x000000ff
|
#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)
|
static int jtag_examine_chain_execute(uint8_t *idcode_buffer, unsigned num_idcode)
|
||||||
{
|
{
|
||||||
scan_field_t field = {
|
scan_field_t field = {
|
||||||
|
@ -1027,6 +1030,8 @@ static int jtag_examine_chain(void)
|
||||||
uint8_t idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4];
|
uint8_t idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4];
|
||||||
unsigned bit_count;
|
unsigned bit_count;
|
||||||
int retval;
|
int retval;
|
||||||
|
int tapcount = 0;
|
||||||
|
bool autoprobe = false;
|
||||||
|
|
||||||
/* DR scan to collect BYPASS or IDCODE register contents.
|
/* DR scan to collect BYPASS or IDCODE register contents.
|
||||||
* Then make sure the scan data has both ones and zeroes.
|
* Then make sure the scan data has both ones and zeroes.
|
||||||
|
@ -1040,11 +1045,9 @@ static int jtag_examine_chain(void)
|
||||||
|
|
||||||
/* point at the 1st tap */
|
/* point at the 1st tap */
|
||||||
jtag_tap_t *tap = jtag_tap_next_enabled(NULL);
|
jtag_tap_t *tap = jtag_tap_next_enabled(NULL);
|
||||||
if (tap == NULL)
|
|
||||||
{
|
if (!tap)
|
||||||
LOG_ERROR("JTAG: No taps enabled?");
|
autoprobe = true;
|
||||||
return ERROR_JTAG_INIT_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (bit_count = 0;
|
for (bit_count = 0;
|
||||||
tap && bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31;
|
tap && bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31;
|
||||||
|
@ -1086,6 +1089,59 @@ static int jtag_examine_chain(void)
|
||||||
return ERROR_JTAG_INIT_FAILED;
|
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
|
/* After those IDCODE or BYPASS register values should be
|
||||||
* only the data we fed into the scan chain.
|
* only the data we fed into the scan chain.
|
||||||
*/
|
*/
|
||||||
|
@ -1120,10 +1176,13 @@ static int jtag_validate_ircapture(void)
|
||||||
int chain_pos = 0;
|
int chain_pos = 0;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
/* when autoprobing, accomodate huge IR lengths */
|
||||||
for (tap = NULL, total_ir_length = 0;
|
for (tap = NULL, total_ir_length = 0;
|
||||||
(tap = jtag_tap_next_enabled(tap)) != NULL;
|
(tap = jtag_tap_next_enabled(tap)) != NULL;
|
||||||
total_ir_length += tap->ir_length)
|
total_ir_length += tap->ir_length) {
|
||||||
continue;
|
if (tap->ir_length == 0)
|
||||||
|
total_ir_length += JTAG_IRLEN_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
/* increase length to add 2 bit sentinel after scan */
|
/* increase length to add 2 bit sentinel after scan */
|
||||||
total_ir_length += 2;
|
total_ir_length += 2;
|
||||||
|
@ -1156,6 +1215,25 @@ static int jtag_validate_ircapture(void)
|
||||||
break;
|
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.
|
/* Validate the two LSBs, which must be 01 per JTAG spec.
|
||||||
*
|
*
|
||||||
* Or ... more bits could be provided by TAP declaration.
|
* Or ... more bits could be provided by TAP declaration.
|
||||||
|
@ -1207,9 +1285,8 @@ void jtag_tap_init(jtag_tap_t *tap)
|
||||||
unsigned ir_len_bits;
|
unsigned ir_len_bits;
|
||||||
unsigned ir_len_bytes;
|
unsigned ir_len_bytes;
|
||||||
|
|
||||||
assert(0 != tap->ir_length);
|
/* if we're autoprobing, cope with potentially huge ir_length */
|
||||||
|
ir_len_bits = tap->ir_length ? : JTAG_IRLEN_MAX;
|
||||||
ir_len_bits = tap->ir_length;
|
|
||||||
ir_len_bytes = CEIL(ir_len_bits, 8);
|
ir_len_bytes = CEIL(ir_len_bits, 8);
|
||||||
|
|
||||||
tap->expected = calloc(1, ir_len_bytes);
|
tap->expected = calloc(1, ir_len_bytes);
|
||||||
|
@ -1302,8 +1379,21 @@ int jtag_init_inner(struct command_context_s *cmd_ctx)
|
||||||
|
|
||||||
tap = jtag_tap_next_enabled(NULL);
|
tap = jtag_tap_next_enabled(NULL);
|
||||||
if (tap == NULL) {
|
if (tap == NULL) {
|
||||||
LOG_ERROR("There are no enabled taps?");
|
/* Once JTAG itself is properly set up, and the scan chain
|
||||||
return ERROR_JTAG_INIT_FAILED;
|
* 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();
|
jtag_add_tlr();
|
||||||
|
|
Loading…
Reference in New Issue