From 9ca6ae61c04ecf5efc4a4b5e2598400d4d0ef977 Mon Sep 17 00:00:00 2001 From: sys64738 Date: Mon, 27 Sep 2021 17:58:53 +0200 Subject: [PATCH] JTAG ID scanning works! --- CMakeLists.txt | 1 + src/main.c | 13 ++++++-- src/pio_sbw.c | 36 ++++++++++++++++++--- src/tap.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/tap.h | 22 +++++++++++++ 5 files changed, 150 insertions(+), 7 deletions(-) create mode 100644 src/tap.c create mode 100644 src/tap.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e0ff4cc..27efd79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,7 @@ if(FAMILY STREQUAL "rp2040") target_sources(${PROJECT} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c ${CMAKE_CURRENT_SOURCE_DIR}/src/pio_sbw.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/tap.c ) # Example include diff --git a/src/main.c b/src/main.c index c57622e..1ba5eb7 100644 --- a/src/main.c +++ b/src/main.c @@ -9,7 +9,9 @@ #include #include #include + #include "pio_sbw.h" +#include "tap.h" void printbuf(const uint8_t* buf, size_t size) { for (size_t i = 0; i < size; ++i) @@ -30,7 +32,7 @@ int main() { bool s = sbw_init(); printf("%s\n", s ? "inited" : "failure"); - uint8_t tdi = 0x0f, tdo = 0; + /*uint8_t tdi = 0x0f, tdo = 0; sbw_sequence(8, true, &tdi, &tdo); printf("seq done, tdo=%02x\n", tdo); @@ -49,7 +51,14 @@ int main() { printf("doing a tclk burst now!\n"); sbw_tclk_burst(16); - printf("done.\n"); + printf("done.\n");*/ + + sbw_tap_reset(); + sbw_check_fuse(); + + uint8_t id = sbw_tap_shift_ir(0xff/*IR_BYPASS*/); + + printf("JTAG ID=%02x\n", id); return 0; } diff --git a/src/pio_sbw.c b/src/pio_sbw.c index 608e855..365f6f4 100644 --- a/src/pio_sbw.c +++ b/src/pio_sbw.c @@ -24,24 +24,50 @@ void sbw_preinit(void) { // TEST low for >0.025us <7us: latch on "we want SBW" signal // TEST high again for >1 us: ready to SBW - gpio_put(PINOUT_SBW_TCK , false); + //gpio_put(PINOUT_SBW_TCK , false); + gpio_put(PINOUT_SBW_TDIO, true ); gpio_put(PINOUT_SBW_TDIO, false); gpio_set_dir(PINOUT_SBW_TCK , true); gpio_set_dir(PINOUT_SBW_TDIO, true); gpio_set_function(PINOUT_SBW_TCK , GPIO_FUNC_SIO); gpio_set_function(PINOUT_SBW_TDIO, GPIO_FUNC_SIO); - // TCK, TDIO now low - busy_wait_us_32(150); // reset debug state while keeping CPU in reset + /*// TCK, TDIO now low + busy_wait_ms(4);//busy_wait_us_32(150); // reset debug state while keeping CPU in reset gpio_put(PINOUT_SBW_TCK , true ); // we want a debugger busy_wait_us_32(1); gpio_put(PINOUT_SBW_TDIO, true ); // we want SBW - busy_wait_us_32(1); + busy_wait_ms(20);//busy_wait_us_32(1); gpio_put(PINOUT_SBW_TCK , false); // latch "we want SBW" busy_wait_us_32(3); gpio_put(PINOUT_SBW_TCK , true ); // start SBW stuff - busy_wait_us_32(100); // wait a bit more + busy_wait_ms(5);//busy_wait_us_32(100); // wait a bit more*/ + + gpio_put(PINOUT_SBW_TCK , false); + gpio_put(PINOUT_SBW_TDIO, true); + busy_wait_ms(4); // reset TEST logic + gpio_put(PINOUT_SBW_TDIO, true); + busy_wait_us_32(1); + gpio_put(PINOUT_SBW_TCK , true); + busy_wait_ms(20); // activate TEST logic + + // "phase 1" + gpio_put(PINOUT_SBW_TDIO, true); + busy_wait_us_32(60); + + // "phase 2" + gpio_put(PINOUT_SBW_TCK , false); + + // "phase 3" + busy_wait_us_32(1); + + // "phase 4" + gpio_put(PINOUT_SBW_TCK , true); + busy_wait_us_32(60); + + // "phase 5" + busy_wait_ms(5); } int sbw_piosm = -1, sbw_offset = -1; diff --git a/src/tap.c b/src/tap.c new file mode 100644 index 0000000..6dd6139 --- /dev/null +++ b/src/tap.c @@ -0,0 +1,85 @@ + +#include "pio_sbw.h" + +#include "tap.h" + +// FIXME: TDI in run-test/idle ALWAYS TCLK value?? + +void sbw_tap_reset(void) { + // TDI always 1 + // TMS=1,1,1,1,1,1 -- reset TAP state to initial + // TMS=0 -- test-logic-reset to run-test/idle + // TMS=1,0,1,0,1 -- perform fuse check + // TMS=1,0 -- back to run-test/idle + + //const uint16_t tms_seq = 0x1abf;//0x3f | (0<<6) | (0x15 << 7) | (0x1 << 12); + const uint8_t tms_seq[2] = {0xbf,0x1a}; + sbw_tms_sequence(14, true, tms_seq); +} + +void sbw_check_fuse(void) { + // TDI always 1 + // TMS=01010110 + const uint8_t tms_seq = 0x6a; + sbw_tms_sequence(8, true, &tms_seq); +} + +static uint8_t bitswap(uint8_t in) { + static const uint8_t lut[16] = { + 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, + 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf + }; + + return (lut[in&0xf] << 4) | lut[in>>4]; +} +static inline uint16_t bitswap16(uint16_t in) { + return ((uint16_t)bitswap(in & 0xff) << 8) | bitswap(in >> 8); +} + +uint16_t sbw_tap_shift_dr(uint16_t newdr) { + // DR content is MSB-first instead of LSB-first (IR is the latter) + // except the PIO already does bitswaps, so we need to do it for the IR instead + newdr = /*bitswap16(*/newdr/*)*/; + + // 100: run-test/idle -> select-dr-scan -> capture-dr -> shift-dr + const uint8_t tms_seq = 0x01; + sbw_tms_sequence(3, true, &tms_seq); + + // 15 data bits with TMS=0 + // 1 data bit with TMS=1 (to exit1-dr) + uint16_t res = 0; + uint8_t newdr2 = newdr >> 15, resb = 0; + sbw_sequence(15, false, (const uint8_t*)&newdr, (uint8_t*)&res); // FIXME: little-endian-only + sbw_sequence( 1, true , &newdr2, &resb); + res |= (uint16_t)resb << 15; + + // TMS=1 (to update-dr) + // TMS=0 (to run-test/idle) + const uint8_t tms_seq_2 = 0x01; + sbw_tms_sequence(2, true, &tms_seq_2); + + return /*bitswap16(*/res/*)*/; +} + +uint8_t sbw_tap_shift_ir(uint8_t newir) { + newir = bitswap(newir); + + // 1100: run-test/idle -> select-dr-scan -> select-ir-scan -> capture-ir -> shift-ir + const uint8_t tms_seq = 0x03; + sbw_tms_sequence(4, true, &tms_seq); + + // 7 data bits with TMS=0 + // 1 data bit with TMS=1 (to exit1-ir) + uint8_t res = 0, resb = 0, newir2 = newir >> 7; + sbw_sequence(7, false, &newir , &res ); + sbw_sequence(1, true , &newir2, &resb); + res |= resb << 7; + + // TMS=1 (to update-ir) + // TMS=0 (to run-test/idle) + const uint8_t tms_seq_2 = 0x01; + sbw_tms_sequence(2, true, &tms_seq_2); + + return bitswap(res); +} + diff --git a/src/tap.h b/src/tap.h new file mode 100644 index 0000000..4682b68 --- /dev/null +++ b/src/tap.h @@ -0,0 +1,22 @@ + +#ifndef SBW_TAP_H_ +#define SBW_TAP_H_ + +// move to run-test/idle. typically this is done by sending a single TMS=0 +// cycle, but the MSP430 has an extra JTAG fuse check that needs to be done +void sbw_tap_reset(void); +// more fuse checking stuff +void sbw_check_fuse(void); + +// write IR contents. starts and ends in run-test/idle +uint8_t sbw_tap_shift_ir(uint8_t newir); +// read current IR contents. starts and ends in run-test/idle +//uint8_t sbw_tap_read_ir(void); + +// write DR contents. starts and ends in run-test/idle +uint16_t sbw_tap_shift_dr(uint16_t newdr); +// read current DR contents. starts and ends in run-test/idle +static inline uint16_t sbw_tap_read_dr(void) { return sbw_tap_shift_dr(0x0000); } + +#endif +