diff --git a/afterburner.ino b/afterburner.ino index 262eed4..5f682ab 100644 --- a/afterburner.ino +++ b/afterburner.ino @@ -114,6 +114,7 @@ #define COMMAND_MEASURE_VPP 'm' #define COMMAND_CALIBRATE_VPP 'b' #define COMMAND_CALIBRATION_OFFSET 'B' +#define COMMAND_JTAG_PLAYER 'j' #define READGAL 0 #define VERIFYGAL 1 @@ -445,6 +446,10 @@ static void printFormatedNumberHex2(unsigned char num) ; #include "aftb_vpp.h" #include "aftb_sparse.h" +// share fusemap buffer with jtag +#define XSVF_HEAP fusemap +#include "jtag_xsvf_player.h" + // print some help on the serial console void printHelp(char full) { Serial.println(F("AFTerburner v." VERSION)); @@ -727,7 +732,7 @@ char handleTerminalCommands() { c = line[0]; if (!isUploading || c != '#') { // prevent 2 character commands from being flagged as invalid - if (!(c == COMMAND_SET_GAL_TYPE || c == COMMAND_CALIBRATION_OFFSET)) { + if (!(c == COMMAND_SET_GAL_TYPE || c == COMMAND_CALIBRATION_OFFSET || c == COMMAND_JTAG_PLAYER)) { c = COMMAND_UNKNOWN; } } @@ -2838,6 +2843,33 @@ static void calibrateVpp(void) { } } +static void startJtagPlayer(uint8_t vpp) { + jtag_port_t jport; + //assign jtag pins + jport.tms = 12; + jport.tdi = 2; + jport.tdo = 4; + jport.tck = 3; + jport.vref = 10; + + //Serial.println(vpp ? F("JTAG VPP 1"): F("JTAG VPP 0")); + + // ensure PC app is ready + delay(200); + // set VPP if required + if (varVppExists) { + varVppSet(vpp ? VPP_11V0 : VPP_5V0); + } + + // start XSVF player / processor + jtag_play_xsvf(&jport); + + // unset VPP + if (varVppExists) { + varVppSet(VPP_5V0); + } +} + // Arduino main loop void loop() { @@ -3014,6 +3046,12 @@ void loop() { calibrateVpp(); } break; + case COMMAND_JTAG_PLAYER: { + startJtagPlayer(line[1] == '1'); + //flush the serial line in case the player ended abruptly + readGarbage(); + } break; + default: { if (command != COMMAND_NONE) { Serial.print(F("ER Unknown command: ")); diff --git a/jtag_xsvf_player.h b/jtag_xsvf_player.h new file mode 100644 index 0000000..a96946e --- /dev/null +++ b/jtag_xsvf_player.h @@ -0,0 +1,950 @@ +#ifndef _JTAG_XSVF_PLAYER_H_ +#define _JTAG_XSVF_PLAYER_H_ + + +/* +Arduino JTAG Player for Afterburner GAL project +--------------------------------------- +Adapted from JTAG library 1.0.15 by Marcelo Jimenez +https://github.com/mrjimenez/JTAG + +This port: +* improves flash size on AVR MCU (about 6.5kb vs 11kb) + +* allows to allocate JTAG internal buffers temporarily within a shared + global buffer (heap). Define XSVF_HEAP to enable such feature: + uint8_t heap[900]; + #define XSVF_HEAP heap + #include "jtag_xsvf_player.h" + +* reduces the code to a single .h file + +Use the original JTAG libray python scripts to upload XSVF files +from your PC: +./xsvf -p /dev/ttyACM0 my_file.xsvf + +Arduino usage: + jtag_port_t jport; + + Serial.begin(115200); + + //assign jtag pins (vref pin checks the cable is plugged in) + jport.tms = 12; + jport.tdi = 2; + jport.tdo = 4; + jport.tck = 3; + jport.vref = 10; + + //process XSVF data received from serial port + jtag_play_xsvf(&jport); + +*/ + + +//XSVF_BUF_SIZE must be power of 2 ( 4,8 16,32,64 etc) +#define XSVF_BUF_SIZE 64 + +#define XSVF_DEBUG 0 +#define XSVF_CALC_CSUM 1 + +#define XCOMPLETE 0 +#define XTDOMASK 1 +#define XSIR 2 +#define XSDR 3 +#define XRUNTEST 4 +#define XRESERVED_5 5 +#define XRESERVED_6 6 +#define XREPEAT 7 +#define XSDRSIZE 8 +#define XSDRTDO 9 +#define XSETSDRMASKS 10 +#define XSDRINC 11 +#define XSDRB 12 +#define XSDRC 13 +#define XSDRE 14 +#define XSDRTDOB 15 +#define XSDRTDOC 16 +#define XSDRTDOE 17 +#define XSTATE 18 +#define XENDIR 19 +#define XENDDR 20 +#define XSIR2 21 +#define XCOMMENT 22 +#define XWAIT 23 + +#define S_MAX_CHAIN_SIZE_BYTES 129 +#define S_MAX_CHAIN_SIZE_BITS (S_MAX_CHAIN_SIZE_BYTES * 8) + +#define STATE_RUN_TEST_IDLE 1 +#define STATE_PAUSE_DR 6 +#define STATE_PAUSE_IR 13 + +#define ERR_IO 1 +#define ERR_XSIR_SIZE 2 +#define ERR_XSDRSIZE 3 +#define ERR_XENDIR 4 +#define ERR_XENDDR 5 +#define ERR_XSDR 6 +#define ERR_INSTR_NOT_IMPLEMENTED 99 +#define ERR_DR_CHECK_FAILED 101 + + +/* + * Low nibble : TMS == 0 + * High nibble: TMS == 1 + */ + +#define TMS_T(TMS_HIGH_STATE, TMS_LOW_STATE) (((TMS_HIGH_STATE) << 4) | (TMS_LOW_STATE)) + +#define XSTATE_TEST_LOGIC_RESET 0 +#define XSTATE_RUN_TEST_IDLE 1 +#define XSTATE_SELECT_DR_SCAN 2 +#define XSTATE_CAPTURE_DR 3 +#define XSTATE_SHIFT_DR 4 +#define XSTATE_EXIT1_DR 5 +#define XSTATE_PAUSE_DR 6 +#define XSTATE_EXIT2_DR 7 +#define XSTATE_UPDATE_DR 8 +#define XSTATE_SELECT_IR_SCAN 9 +#define XSTATE_CAPTURE_IR 10 +#define XSTATE_SHIFT_IR 11 +#define XSTATE_EXIT1_IR 12 +#define XSTATE_PAUSE_IR 13 +#define XSTATE_EXIT2_IR 14 +#define XSTATE_UPDATE_IR 15 + +#define TMS_T00 /* STATE_TEST_LOGIC_RESET */ TMS_T(XSTATE_TEST_LOGIC_RESET, XSTATE_RUN_TEST_IDLE) +#define TMS_T01 /* STATE_RUN_TEST_IDLE */ TMS_T(XSTATE_SELECT_DR_SCAN, XSTATE_RUN_TEST_IDLE) +#define TMS_T02 /* STATE_SELECT_DR_SCAN */ TMS_T(XSTATE_SELECT_IR_SCAN, XSTATE_CAPTURE_DR) +#define TMS_T03 /* STATE_CAPTURE_DR */ TMS_T(XSTATE_EXIT1_DR, XSTATE_SHIFT_DR) +#define TMS_T04 /* STATE_SHIFT_DR */ TMS_T(XSTATE_EXIT1_DR, XSTATE_SHIFT_DR) +#define TMS_T05 /* STATE_EXIT1_DR */ TMS_T(XSTATE_UPDATE_DR, XSTATE_PAUSE_DR) +#define TMS_T06 /* STATE_PAUSE_DR */ TMS_T(XSTATE_EXIT2_DR, XSTATE_PAUSE_DR) +#define TMS_T07 /* STATE_EXIT2_DR */ TMS_T(XSTATE_UPDATE_DR, XSTATE_SHIFT_DR) +#define TMS_T08 /* STATE_UPDATE_DR */ TMS_T(XSTATE_SELECT_DR_SCAN, XSTATE_RUN_TEST_IDLE) +#define TMS_T09 /* STATE_SELECT_IR_SCAN */ TMS_T(XSTATE_TEST_LOGIC_RESET, XSTATE_CAPTURE_IR) +#define TMS_T10 /* STATE_CAPTURE_IR */ TMS_T(XSTATE_EXIT1_IR, XSTATE_SHIFT_IR) +#define TMS_T11 /* STATE_SHIFT_IR */ TMS_T(XSTATE_EXIT1_IR, XSTATE_SHIFT_IR) +#define TMS_T12 /* STATE_EXIT1_IR */ TMS_T(XSTATE_UPDATE_IR, XSTATE_PAUSE_IR) +#define TMS_T13 /* STATE_PAUSE_IR */ TMS_T(XSTATE_EXIT2_IR, XSTATE_PAUSE_IR) +#define TMS_T14 /* STATE_EXIT2_IR */ TMS_T(XSTATE_UPDATE_IR, XSTATE_SHIFT_IR) +#define TMS_T15 /* STATE_UPDATE_IR */ TMS_T(XSTATE_SELECT_DR_SCAN, XSTATE_RUN_TEST_IDLE) + + +#define BITSTR(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) ( \ + ((uint16_t)(A) << 15) | \ + ((uint16_t)(B) << 14) | \ + ((uint16_t)(C) << 13) | \ + ((uint16_t)(D) << 12) | \ + ((uint16_t)(E) << 11) | \ + ((uint16_t)(F) << 10) | \ + ((uint16_t)(G) << 9) | \ + ((uint16_t)(H) << 8) | \ + ((uint16_t)(I) << 7) | \ + ((uint16_t)(J) << 6) | \ + ((uint16_t)(K) << 5) | \ + ((uint16_t)(L) << 4) | \ + ((uint16_t)(M) << 3) | \ + ((uint16_t)(N) << 2) | \ + ((uint16_t)(O) << 1) | \ + ((uint16_t)(P) << 0) ) + +/* + * The index of this vector is the current state. The i-th bit tells you the + * value TMS must assume in order to go to state "i". + +------------------------------------------------------------------------------------------------------------ +| | || F | E | D | C || B | A | 9 | 8 || 7 | 6 | 5 | 4 || 3 | 2 | 1 | 0 || HEX | +------------------------------------------------------------------------------------------------------------ +| STATE_TEST_LOGIC_RESET | 0 || 0 | 0 | 0 | 0 || 0 | 0 | 0 | 0 || 0 | 0 | 0 | 0 || 0 | 0 | 0 | 1 || 0x0001 | +| STATE_RUN_TEST_IDLE | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 0 | 1 || 0xFFFD | +| STATE_SELECT_DR_SCAN | 2 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 0 || 0 | 0 | 0 | 0 || 0 | x | 1 | 1 || 0xFE03 | +| STATE_CAPTURE_DR | 3 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 0 || x | 1 | 1 | 1 || 0xFFE7 | +| STATE_SHIFT_DR | 4 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 0 || 1 | 1 | 1 | 1 || 0xFFEF | +| STATE_EXIT1_DR | 5 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0 | 0 | x | 0 || 1 | 1 | 1 | 1 || 0xFF0F | +| STATE_PAUSE_DR | 6 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 0 | 1 | 1 || 1 | 1 | 1 | 1 || 0xFFBF | +| STATE_EXIT2_DR | 7 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || x | 0 | 0 | 0 || 1 | 1 | 1 | 1 || 0xFF0F | +| STATE_UPDATE_DR | 8 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | x || 1 | 1 | 1 | 1 || 1 | 1 | 0 | 1 || 0xFEFD | +| STATE_SELECT_IR_SCAN | 9 || 0 | 0 | 0 | 0 || 0 | 0 | x | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0x01FF | +| STATE_CAPTURE_IR | A || 1 | 1 | 1 | 1 || 0 | x | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0xF3FF | +| STATE_SHIFT_IR | B || 1 | 1 | 1 | 1 || 0 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0xF7FF | +| STATE_EXIT1_IR | C || 1 | 0 | 0 | x || 0 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0x87FF | +| STATE_PAUSE_IR | D || 1 | 1 | 0 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0xDFFF | +| STATE_EXIT2_IR | E || 1 | x | 0 | 0 || 0 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 0x87FF | +| STATE_UPDATE_IR | F || x | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 1 | 1 || 1 | 1 | 0 | 1 || 0x7FFD | +------------------------------------------------------------------------------------------------------------ + +*/ + +#define BS00 /* STATE_TEST_LOGIC_RESET */ BITSTR( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 ) +#define BS01 /* STATE_RUN_TEST_IDLE */ BITSTR( 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1 ) +#define BS02 /* STATE_SELECT_DR_SCAN */ BITSTR( 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1 ) +#define BS03 /* STATE_CAPTURE_DR */ BITSTR( 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1 ) +#define BS04 /* STATE_SHIFT_DR */ BITSTR( 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1 ) +#define BS05 /* STATE_EXIT1_DR */ BITSTR( 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1 ) +#define BS06 /* STATE_PAUSE_DR */ BITSTR( 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1 ) +#define BS07 /* STATE_EXIT2_DR */ BITSTR( 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1 ) +#define BS08 /* STATE_UPDATE_DR */ BITSTR( 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1 ) +#define BS09 /* STATE_SELECT_IR_SCAN */ BITSTR( 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 ) +#define BS10 /* STATE_CAPTURE_IR */ BITSTR( 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ) +#define BS11 /* STATE_SHIFT_IR */ BITSTR( 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ) +#define BS12 /* STATE_EXIT1_IR */ BITSTR( 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ) +#define BS13 /* STATE_PAUSE_IR */ BITSTR( 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ) +#define BS14 /* STATE_EXIT2_IR */ BITSTR( 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ) +#define BS15 /* STATE_UPDATE_IR */ BITSTR( 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1 ) + + +typedef struct xsvf_t { + uint8_t* xsvf_tdo_mask; + uint8_t* xsvf_tdi; + uint8_t* xsvf_tdo; + uint8_t* xsvf_tdo_expected; + uint8_t* xsvf_address_mask; + uint8_t* xsvf_data_mask; + + uint32_t rdpos; + uint32_t wrpos; + + #if XSVF_CALC_CSUM + uint32_t csum; + #endif + + uint16_t instruction_counter = 0; + uint8_t error = 0; + uint8_t xcomplete; + + uint16_t sirsize_bits; + uint16_t sirsize_bytes; + + uint32_t sdrsize_bits; + uint32_t sdrsize_bytes; + uint32_t runtest; + + uint8_t repeat; + uint8_t next_state; + uint8_t endir_state; + uint8_t enddr_state; + + uint32_t wait_time_usecs; + uint8_t wait_start_state; + uint8_t wait_end_state; + uint8_t jtag_current_state; + +} xsvf_t; + +#ifdef XSVF_HEAP +// variables will be allocated on heap +uint8_t* xsvf_buf; +xsvf_t* xsvf; +uint8_t* xsvf_tms_transitions; +uint16_t* xsvf_tms_map; +#else /* XSVF_HEAP */ +// variables allocated globally +uint8_t xsvf_buf[XSVF_BUF_SIZE]; +uint8_t xsvf_tdo_mask[S_MAX_CHAIN_SIZE_BYTES]; +uint8_t xsvf_tdi[S_MAX_CHAIN_SIZE_BYTES]; +uint8_t xsvf_tdo[S_MAX_CHAIN_SIZE_BYTES]; +uint8_t xsvf_tdo_expected[S_MAX_CHAIN_SIZE_BYTES]; +uint8_t xsvf_address_mask[S_MAX_CHAIN_SIZE_BYTES]; +uint8_t xsvf_data_mask[S_MAX_CHAIN_SIZE_BYTES]; +xsvf_t xsvf_context; +xsvf_t* xsvf = &xsvf_context; + +static const uint8_t xsvf_tms_transitions[] = { + TMS_T00, TMS_T01, TMS_T02, TMS_T03, TMS_T04, TMS_T05, TMS_T06, TMS_T07, + TMS_T08, TMS_T09, TMS_T10, TMS_T11, TMS_T12, TMS_T13, TMS_T14, TMS_T15, +}; +static const uint16_t xsvf_tms_map[] = { + BS00, BS01, BS02, BS03, BS04, BS05, BS06, BS07, + BS08, BS09, BS10, BS11, BS12, BS13, BS14, BS15 +}; +#endif + + + +typedef struct jtag_port_t { + uint8_t tms; + uint8_t tdi; + uint8_t tdo; + uint8_t tck; + uint8_t vref; +} jtag_port_t; + +static void jtag_port_init(jtag_port_t* port) { + pinMode(port->tms, OUTPUT); + pinMode(port->tdi, OUTPUT); + pinMode(port->tck, OUTPUT); + pinMode(port->tdo, INPUT); + pinMode(port->vref, INPUT); +} + +static void jtag_port_pulse_clock(jtag_port_t* port) { + digitalWrite(port->tck, 0); + delayMicroseconds(1); + digitalWrite(port->tck, 1); +} + +static uint8_t jtag_port_pulse_clock_read_tdo(jtag_port_t* port) { + uint8_t val; + digitalWrite(port->tck, 0); + delayMicroseconds(1); + val = digitalRead(port->tdo); + digitalWrite(port->tck, 1); + return val; +} + +static inline void jtag_port_set_tms(jtag_port_t* port, uint8_t val) { + digitalWrite(port->tms, val); +} +static inline void jtag_port_set_tdi(jtag_port_t* port, uint8_t val) { + digitalWrite(port->tdi, val); +} + +static inline uint8_t jtag_port_get_veref(jtag_port_t* port) { + return digitalRead(port->vref); +} + + +static uint8_t xsvf_player_next_byte(void) { + uint8_t retry = 16; + uint8_t pos = xsvf->rdpos & (XSVF_BUF_SIZE - 1); + + if (xsvf->wrpos == xsvf->rdpos) { + size_t r = 0; + while (r == 0) { + Serial.println("$064"); // request to receive BUF size bytes + r = Serial.readBytes(xsvf_buf + pos, XSVF_BUF_SIZE - pos); + if (r == 0) { + retry --; + if (retry == 0) { + xsvf->error = 1; + return 0; + } + delay(1); + } else { + xsvf->wrpos += r; + } + } + } + + xsvf->rdpos++; +#if XSVF_DEBUG + Serial.print(F("D BYTE ")); + Serial.print(xsvf_buf[pos], DEC); + Serial.print(F(" 0x")); + Serial.println(xsvf_buf[pos], HEX); +#endif +#if XSVF_CALC_CSUM + xsvf->csum += xsvf_buf[pos]; +#endif + + return xsvf_buf[pos]; +} + +static uint8_t xsvf_player_get_next_byte(void) { + return xsvf_player_next_byte(); +} +/* +static uint16_t xsvf_player_get_next_word(void) { + uint16_t i = xsvf_player_next_byte(); + i <<= 8; + i |= xsvf_player_next_byte(); + return i; +} +*/ + +static uint32_t xsvf_player_get_next_long(void) { + uint32_t i = xsvf_player_next_byte(); + i <<= 8; + i |= xsvf_player_next_byte(); + i <<= 8; + i |= xsvf_player_next_byte(); + i <<= 8; + i |= xsvf_player_next_byte(); + return i; +} + +static uint32_t xsvf_player_get_next_bytes(uint8_t* data, uint32_t count) { + while(count--) { + *data++ = xsvf_player_next_byte(); + } +} + +#ifdef XSVF_HEAP +static uint32_t xsvf_heap_pos(uint32_t* pos, uint16_t size) { + uint32_t heap_pos = *pos; + //allocate on 4 byte boundaries + heap_pos = (heap_pos + 3) & 0xFFFFFFFC; + *pos = heap_pos + size; + return heap_pos; +} +#endif + +static void xsvf_clear() { + uint16_t i; + uint8_t* d = (uint8_t*) xsvf; + //clear the xsvf data in RAM + i = sizeof(xsvf_t); + while(i) { + i--; + d[i] = 0; + } +} + +static void xsvf_player_init(jtag_port_t* port) { + jtag_port_init(port); + +#ifdef XSVF_HEAP + { + // variables allocated on the heap + uint32_t heap_pos = (uint32_t) XSVF_HEAP; + + xsvf = (xsvf_t*) xsvf_heap_pos(&heap_pos, sizeof(xsvf_t)); + xsvf_buf = (uint8_t*) xsvf_heap_pos(&heap_pos, XSVF_BUF_SIZE); + + xsvf_clear(); + + xsvf->xsvf_tdo_mask = (uint8_t*) xsvf_heap_pos(&heap_pos, S_MAX_CHAIN_SIZE_BYTES); + xsvf->xsvf_tdi = (uint8_t*) xsvf_heap_pos(&heap_pos, S_MAX_CHAIN_SIZE_BYTES); + xsvf->xsvf_tdo = (uint8_t*) xsvf_heap_pos(&heap_pos, S_MAX_CHAIN_SIZE_BYTES); + xsvf->xsvf_tdo_expected = (uint8_t*) xsvf_heap_pos(&heap_pos, S_MAX_CHAIN_SIZE_BYTES); + xsvf->xsvf_address_mask = (uint8_t*) xsvf_heap_pos(&heap_pos, S_MAX_CHAIN_SIZE_BYTES); + xsvf->xsvf_data_mask = (uint8_t*) xsvf_heap_pos(&heap_pos, S_MAX_CHAIN_SIZE_BYTES); + xsvf_tms_transitions = (uint8_t*) xsvf_heap_pos(&heap_pos, 16); + xsvf_tms_map = (uint16_t*) xsvf_heap_pos(&heap_pos, 32); + + if (heap_pos - ((uint32_t)XSVF_HEAP) > sizeof(XSVF_HEAP)) { + Serial.print(F("Q-1,ERROR: Heap is small:")); + Serial.println(heap_pos - ((uint32_t)XSVF_HEAP), DEC); + return; + } + + //set up TM transitions + xsvf_tms_transitions[0] = TMS_T00; + xsvf_tms_transitions[1] = TMS_T01; + xsvf_tms_transitions[2] = TMS_T02; + xsvf_tms_transitions[3] = TMS_T03; + xsvf_tms_transitions[4] = TMS_T04; + xsvf_tms_transitions[5] = TMS_T05; + xsvf_tms_transitions[6] = TMS_T06; + xsvf_tms_transitions[7] = TMS_T07; + xsvf_tms_transitions[8] = TMS_T08; + xsvf_tms_transitions[9] = TMS_T09; + xsvf_tms_transitions[10] = TMS_T10; + xsvf_tms_transitions[11] = TMS_T11; + xsvf_tms_transitions[12] = TMS_T12; + xsvf_tms_transitions[13] = TMS_T13; + xsvf_tms_transitions[14] = TMS_T14; + xsvf_tms_transitions[15] = TMS_T15; + + //set up bitstream map + xsvf_tms_map[0] = BS00; + xsvf_tms_map[1] = BS01; + xsvf_tms_map[2] = BS02; + xsvf_tms_map[3] = BS03; + xsvf_tms_map[4] = BS04; + xsvf_tms_map[5] = BS05; + xsvf_tms_map[6] = BS06; + xsvf_tms_map[7] = BS07; + xsvf_tms_map[8] = BS08; + xsvf_tms_map[9] = BS09; + xsvf_tms_map[10] = BS10; + xsvf_tms_map[11] = BS11; + xsvf_tms_map[12] = BS12; + xsvf_tms_map[13] = BS13; + xsvf_tms_map[14] = BS14; + xsvf_tms_map[15] = BS15; + + } +#else + { + xsvf_clear(); + + xsvf->xsvf_tdo_mask = xsvf_tdo_mask; + xsvf->xsvf_tdi = xsvf_tdi; + xsvf->xsvf_tdo = xsvf_tdo; + xsvf->xsvf_tdo_expected = xsvf_tdo_expected; + xsvf->xsvf_address_mask = xsvf_address_mask; + xsvf->xsvf_data_mask = xsvf_data_mask; + } +#endif + + xsvf->repeat = 32; + xsvf->endir_state = XSTATE_RUN_TEST_IDLE; + xsvf->enddr_state = STATE_RUN_TEST_IDLE; +} + + +static void xsvf_jtagtap_state_ack(uint8_t tms) { + tms <<= 2; // either 0 or 4 + xsvf->jtag_current_state = (xsvf_tms_transitions[xsvf->jtag_current_state] >> tms) & 0xf; +} + +static void xsvf_jtagtap_shift_td( + jtag_port_t* port, + uint8_t *input_data, + uint8_t *output_data, + uint32_t data_bits, + uint8_t must_end) +{ + uint32_t i, j; + uint32_t bit_count = data_bits; + uint32_t byte_count = (data_bits+ 7) >> 3; + + for (i = 0; i < byte_count; ++i) { + uint8_t byte_out = input_data[byte_count - 1 - i]; + uint8_t tdo_byte = 0; + for (j = 0; j < 8 && bit_count-- > 0; ++j) { + uint8_t tdo; + if (bit_count == 0 && must_end) { + jtag_port_set_tms(port, 1); + xsvf_jtagtap_state_ack(1); + } + jtag_port_set_tdi(port, byte_out & 1); + byte_out >>= 1; + tdo = jtag_port_pulse_clock_read_tdo(port); + tdo_byte |= tdo << j; + } + output_data[byte_count - 1 - i] = tdo_byte; + } +} + +static void xsvf_jtagtap_state_step(jtag_port_t* port, uint8_t tms) { + jtag_port_set_tms(port, tms); + jtag_port_pulse_clock(port); + xsvf_jtagtap_state_ack(tms); +} + +static void xsvf_jtagtap_state_goto(jtag_port_t* port, uint8_t state) { + if (xsvf->error) { + return; + } + if (state == XSTATE_TEST_LOGIC_RESET) { + uint8_t i; + for (i = 0; i < 5; ++i) { + xsvf_jtagtap_state_step(port, 1); + } + } else { + while (xsvf->jtag_current_state != state) { + xsvf_jtagtap_state_step(port, (xsvf_tms_map[xsvf->jtag_current_state] >> state) & 1); + } + } +} + +static void xsvf_jtagtap_wait_time(jtag_port_t* port, uint32_t microseconds) { + uint32_t until; + + if (xsvf->error) { + return; + } + + until = micros() + microseconds; + while (microseconds--) { + jtag_port_pulse_clock(port); + } + while (micros() < until) { + jtag_port_pulse_clock(port); + } +} + +static void xsvf_jtag_sir(jtag_port_t* port) { + if (xsvf->error) { + return; + } + xsvf_jtagtap_state_goto(port, XSTATE_SHIFT_IR); + xsvf_jtagtap_shift_td(port, xsvf->xsvf_tdi, xsvf->xsvf_tdo, xsvf->sirsize_bits, 1); + if (xsvf->runtest) { + xsvf_jtagtap_state_goto(port, xsvf->endir_state); + } else { + xsvf_jtagtap_state_goto(port, XSTATE_RUN_TEST_IDLE); + xsvf_jtagtap_wait_time(port, xsvf->runtest); + } +} + + +static uint8_t xsvf_jtag_is_tdo_as_expected(uint8_t use_mask) +{ + uint32_t i; + for (i = 0; i < xsvf->sdrsize_bytes; ++i) { + uint8_t expected = xsvf->xsvf_tdo_expected[i]; + uint8_t actual = xsvf->xsvf_tdo[i]; + if (use_mask) { + uint8_t mask = xsvf->xsvf_tdo_mask[i]; + expected &= mask; + actual &= mask; + } + if (expected != actual) { +#if XSVF_DEBUG + Serial.println(F("D...NO MATCH!")); +#endif + return 0; + } + } + +#if XSVF_DEBUG + Serial.println(F("D...match!")); +#endif + return 1; +} + + +#define SDR_MUST_BEGIN (flags & 0b1000) +#define SDR_MUST_CHECK (flags & 0b0100) +#define SDR_USE_MASK (flags & 0b0010) +#define SDR_MUST_END (flags & 0b0001) + +static uint8_t xsvf_jtag_sdr(jtag_port_t* port, uint8_t flags) +{ + int16_t attempts_left = xsvf->repeat; + uint8_t matched = 0; + uint8_t must_end = SDR_MUST_END; + uint8_t must_check = SDR_MUST_CHECK; + uint8_t use_mask = SDR_USE_MASK; + + if (xsvf->error) { + return 0; + } + + if (SDR_MUST_BEGIN) { + xsvf_jtagtap_state_goto(port, XSTATE_SHIFT_DR); + } + while (!matched && attempts_left-- >= 0) { + xsvf_jtagtap_shift_td(port, xsvf->xsvf_tdi, xsvf->xsvf_tdo, xsvf->sdrsize_bits, must_end); + if (!must_check) { + break; + } + matched = xsvf_jtag_is_tdo_as_expected(use_mask); + if (!matched) { + // XAP058, page 14 + xsvf_jtagtap_state_goto(port, XSTATE_PAUSE_DR); + xsvf_jtagtap_state_goto(port, XSTATE_SHIFT_DR); + xsvf_jtagtap_state_goto(port, XSTATE_RUN_TEST_IDLE); + xsvf_jtagtap_wait_time(port, xsvf->runtest); + // + xsvf_jtagtap_state_goto(port, XSTATE_SHIFT_DR); +#if XSVF_DEBUG + if (attempts_left >= 0) { + Serial.print(F("D...repeating: ")); + Serial.println(xsvf->repeat - attempts_left, DEC); + } +#endif + } + } + if (must_check && !matched) { + xsvf->error = ERR_DR_CHECK_FAILED; + Serial.println(F("D!DR check failed!")); + } + if (must_end && matched) { + if (!xsvf->runtest) { + xsvf_jtagtap_state_goto(port, xsvf->enddr_state); + } else { + xsvf_jtagtap_state_goto(port, XSTATE_RUN_TEST_IDLE); + xsvf_jtagtap_wait_time(port, xsvf->runtest); + } + } + + return !must_check || (must_check && matched); +} + + + +/* + * Reads the next instruction from the serial port. Also reads any + * remaining instruction parameters into the instruction buffer. + */ +static uint8_t xsvf_player_handle_next_instruction(jtag_port_t* port) { + uint8_t instruction = xsvf_player_next_byte(); + if (xsvf->error) { + return ERR_IO; // failure + } + xsvf->instruction_counter++; + +#if XSVF_DEBUG + Serial.print(F("D INSTR ")); + Serial.print(xsvf->instruction_counter, DEC); + Serial.print(F(" (0x")); + Serial.print(instruction, HEX); + Serial.print(F("): ")); +#endif + + //do not use switch as it uses RAM + // ---[COMPLETE ] -------------------------------------------- + if (instruction == XCOMPLETE) { +#if XSVF_DEBUG + Serial.println(F("XCOMPLETE")); +#endif + xsvf->xcomplete = 1; + } else + + // ---[TDO MASK] -------------------------------------------- + if (instruction == XTDOMASK) { +#if XSVF_DEBUG + Serial.println(F("XTDOMASK")); +#endif + xsvf_player_get_next_bytes(xsvf->xsvf_tdo_mask, xsvf->sdrsize_bytes); + } else + + // ---[SIR SIR2] -------------------------------------------- + if (instruction == XSIR || instruction == XSIR2) { +#if XSVF_DEBUG + Serial.println(instruction == XSIR ? F("XSIR") : F("XSIR2")); +#endif + xsvf->sirsize_bits = xsvf_player_get_next_byte(); + if (instruction == XSIR2) { + xsvf->sirsize_bits <= 8; + xsvf->sirsize_bits |= xsvf_player_get_next_byte(); + } + xsvf->sirsize_bytes = (xsvf->sirsize_bits + 7) >> 3; + if (xsvf->sirsize_bytes > S_MAX_CHAIN_SIZE_BYTES) { + return ERR_XSIR_SIZE; + } + xsvf_player_get_next_bytes(xsvf->xsvf_tdi, xsvf->sirsize_bytes); + xsvf_jtag_sir(port); + } else + + // ---[SDR ] -------------------------------------------- + if (instruction == XSDR || (instruction >= XSDRB && instruction <= XSDRE)) { + uint8_t flags = 0b1111; +#if XSVF_DEBUG + Serial.println(F("XSDRx")); +#endif + xsvf_player_get_next_bytes(xsvf->xsvf_tdi, xsvf->sdrsize_bytes); + if (instruction != XSDR) { + flags = (instruction == XSDRB) ? 0b1000 : (instruction == XSDRC) ? 0b0000 : 0b0001; + } + if (!xsvf_jtag_sdr(port, flags)) { + xsvf->error = ERR_XSDR; + } + } else + + // ---[RUN TEST ] -------------------------------------------- + if (instruction == XRUNTEST) { +#if XSVF_DEBUG + Serial.println(F("XRUNTEST")); +#endif + xsvf->runtest = xsvf_player_get_next_long(); + } else + // ---[REPEAT ] -------------------------------------------- + if (instruction == XREPEAT) { +#if XSVF_DEBUG + Serial.println(F("XREPEAT")); +#endif + xsvf->repeat = xsvf_player_get_next_byte(); + } else + + // ---[SDRSIZE ] -------------------------------------------- + if (instruction == XSDRSIZE) { +#if XSVF_DEBUG + Serial.println(F("XSDRSIZE")); +#endif + xsvf->sdrsize_bits = xsvf_player_get_next_long(); + xsvf->sdrsize_bytes = (xsvf->sdrsize_bits + 7) >> 3; + if (xsvf->sdrsize_bytes > S_MAX_CHAIN_SIZE_BYTES) { + return ERR_XSDRSIZE; + } + } else + + // ---[SDRTDO ] -------------------------------------------- + if (instruction == XSDRTDO || (instruction >= XSDRTDOB && instruction <= XSDRTDOE)) { + uint8_t flags = 0b1111; +#if XSVF_DEBUG + Serial.println(F("XSDRTDOx")); +#endif + xsvf_player_get_next_bytes(xsvf->xsvf_tdi, xsvf->sdrsize_bytes); + xsvf_player_get_next_bytes(xsvf->xsvf_tdo_expected, xsvf->sdrsize_bytes); + if (instruction != XSDRTDO) { + flags = (instruction == XSDRTDOB) ? 0b1100 : (instruction == XSDRTDOC) ? 0b0100 : 0b0101; + } + if (!xsvf_jtag_sdr(port, flags)) { + xsvf->error = ERR_XSDR; + } + } else + + // ---[SET SDR MASKS ] -------------------------------------------- + if (instruction == XSETSDRMASKS) { +#if XSVF_DEBUG + Serial.println(F("XSETSDRMASKS")); +#endif + xsvf_player_get_next_bytes(xsvf->xsvf_address_mask, xsvf->sdrsize_bytes); + xsvf_player_get_next_bytes(xsvf->xsvf_data_mask, xsvf->sdrsize_bytes); + } else + + // ---[SDR INC ] -------------------------------------------- + if (instruction == XSDRINC) { +#if XSVF_DEBUG + Serial.println(F("XSDRINC")); +#endif + xsvf_player_get_next_bytes(xsvf->xsvf_tdi, xsvf->sdrsize_bytes); + // TODO - check: return false? + } else + + // ---[STATE ] -------------------------------------------- + if (instruction == XSTATE) { +#if XSVF_DEBUG + Serial.println(F("XSTATE")); +#endif + xsvf->next_state = xsvf_player_get_next_byte(); + xsvf_jtagtap_state_goto(port, xsvf->next_state); + } else + + // ---[END IR ] -------------------------------------------- + if (instruction == XENDIR) { + uint8_t s; +#if XSVF_DEBUG + Serial.println(F("XENDIR")); +#endif + s = xsvf_player_get_next_byte(); + if (s == 0) { + xsvf->endir_state = STATE_RUN_TEST_IDLE; + } else + if (s == 1) { + xsvf->endir_state = STATE_PAUSE_IR; + } else { + return ERR_XENDIR; + } + } else + + // ---[END DR ] -------------------------------------------- + if (instruction == XENDDR) { + uint8_t s; +#if XSVF_DEBUG + Serial.println(F("XENDDR")); +#endif + + s = xsvf_player_get_next_byte(); + if (s == 0) { + xsvf->enddr_state = STATE_RUN_TEST_IDLE; + } else + if (s == 1) { + xsvf->enddr_state = STATE_PAUSE_DR; + } else { + return ERR_XENDDR; + } + } else + + // ---[COMMENT ] -------------------------------------------- + if (instruction == XCOMMENT) { + uint8_t c; +#if XSVF_DEBUG + Serial.println(F("XCOMMENT")); +#endif + Serial.print(F("D"));//debug message preamble + //read the comment bytes + do { + c = xsvf_player_get_next_byte(); + // special feature: dump the TDO data + if (c == '#') { + uint8_t cnt = 0; + uint8_t size = xsvf_player_get_next_byte() - '0'; + //dump the tdo buffer bytes + while(cnt < size) { + char t[4]; + uint8_t v = xsvf->xsvf_tdo[cnt]; + uint8_t x1 = v >> 4; + v &= 0xF; + // DEC to HEX conversion with leading zero + t[0] = (char) (x1 < 10 ? '0' + x1 : 55 + x1 ); + t[1] = (char) (v < 10 ? '0' + v : 55 + v ); + t[2] = 0; + Serial.print(t); + cnt++; + } + } else if (c) { + Serial.print((char)c); + } + } while(c); + Serial.println(); + } else + + // ---[WAIT ] -------------------------------------------- + if (instruction == XWAIT) { +#if XSVF_DEBUG + Serial.println(F("XWAIT")); +#endif + //TOOD - do we need these states to be global? + xsvf->wait_start_state = xsvf_player_get_next_byte(); + xsvf->wait_end_state = xsvf_player_get_next_byte(); + xsvf->wait_time_usecs = xsvf_player_get_next_long(); + xsvf_jtagtap_state_goto(port, xsvf->wait_start_state); + xsvf_jtagtap_wait_time(port, xsvf->wait_time_usecs); + xsvf_jtagtap_state_goto(port, xsvf->wait_end_state); + + } else + + // ---[UNKNOWN ] -------------------------------------------- + { +#if XSVF_DEBUG + Serial.print(F("XUNKNOWN:")); + Serial.println(instruction, DEC); +#endif + //unimplemented instruction + return ERR_INSTR_NOT_IMPLEMENTED; + } + + if (xsvf->error) { + return xsvf->error; // failure + } + return 0; +} + + +static void jtag_play_xsvf(jtag_port_t* port) +{ + uint32_t n = 0; + uint8_t ret; + + xsvf_player_init(port); + + //check xref is high + if (!jtag_port_get_veref(port)) { + Serial.println(F("Q-255,JTAG not connected")); + return; + } + + Serial.println(F("RXSVF")); //announce ready to receive XSVF stream + + while(1) { + n++; + ret = xsvf_player_handle_next_instruction(port); + if (ret) { + Serial.print(F("Q-")); + Serial.print(ret, DEC ); + Serial.println(F(",Fail")); + break; + } else { + if (xsvf->xcomplete) { + Serial.println(F("!Success")); + break; + } + } + } + Serial.print(F("!Processed instr:")); + Serial.println(xsvf->instruction_counter, DEC); + +#if XSVF_CALC_CSUM + Serial.print(F("!sum: 0x")); + // print leading zeros in the check sum hex value + { + uint32_t i = 0xF0000000; + while((!(xsvf->csum & i)) && i) { + Serial.print(F("0")); + i >>= 4; + } + } + Serial.print(xsvf->csum, HEX); + Serial.print(F("/")); + Serial.println(xsvf->rdpos, DEC); +#endif /* XSVF_CALC_CSUM */ + + if (xsvf->xcomplete) { + Serial.println(F("Q-0,OK")); + } + // put the jtag port pins into High-Z (vref already is input) + pinMode(port->tms, INPUT); + pinMode(port->tdi, INPUT); + pinMode(port->tck, INPUT); + pinMode(port->tdo, INPUT); +} + + +#endif /*_JTAG_XSVF_PLAYER_H_*/ \ No newline at end of file