+
+int jtag_power_dropout(int *dropout)
+{
+ return jtag->power_dropout(dropout);
+}
+
+int jtag_srst_asserted(int *srst_asserted)
+{
+ return jtag->srst_asserted(srst_asserted);
+}
+
+void jtag_tap_handle_event( jtag_tap_t * tap, enum jtag_tap_event e)
+{
+ jtag_tap_event_action_t * jteap;
+ int done;
+
+ jteap = tap->event_action;
+
+ done = 0;
+ while (jteap) {
+ if (jteap->event == e) {
+ done = 1;
+ LOG_DEBUG( "JTAG tap: %s event: %d (%s) action: %s\n",
+ tap->dotted_name,
+ e,
+ Jim_Nvp_value2name_simple(nvp_jtag_tap_event, e)->name,
+ Jim_GetString(jteap->body, NULL) );
+ if (Jim_EvalObj(interp, jteap->body) != JIM_OK) {
+ Jim_PrintErrorMessage(interp);
+ }
+ }
+
+ jteap = jteap->next;
+ }
+
+ if (!done) {
+ LOG_DEBUG( "event %d %s - no action",
+ e,
+ Jim_Nvp_value2name_simple( nvp_jtag_tap_event, e)->name);
+ }
+}
+
+/*-----<Cable Helper API>---------------------------------------*/
+
+/* these Cable Helper API functions are all documented in the jtag.h header file,
+ using a Doxygen format. And since Doxygen's configuration file "Doxyfile",
+ is setup to prefer its docs in the header file, no documentation is here, for
+ if it were, it would have to be doubly maintained.
+*/
+
+/**
+ * @see tap_set_state() and tap_get_state() accessors.
+ * Actual name is not important since accessors hide it.
+ */
+static tap_state_t state_follower = TAP_RESET;
+
+void tap_set_state_impl( tap_state_t new_state )
+{
+ /* this is the state we think the TAPs are in now, was cur_state */
+ state_follower = new_state;
+}
+
+tap_state_t tap_get_state()
+{
+ return state_follower;
+}
+
+/**
+ * @see tap_set_end_state() and tap_get_end_state() accessors.
+ * Actual name is not important because accessors hide it.
+ */
+static tap_state_t end_state_follower = TAP_RESET;
+
+void tap_set_end_state( tap_state_t new_end_state )
+{
+ /* this is the state we think the TAPs will be in at completion of the
+ current TAP operation, was end_state
+ */
+ end_state_follower = new_end_state;
+}
+
+tap_state_t tap_get_end_state()
+{
+ return end_state_follower;
+}
+
+
+int tap_move_ndx( tap_state_t astate )
+{
+ /* given a stable state, return the index into the tms_seqs[] array within tap_get_tms_path() */
+
+ /* old version
+ const static int move_map[16] =
+ {
+ 0, -1, -1, 2, -1, 3, -1, -1,
+ 1, -1, -1, 4, -1, 5, -1, -1
+ };
+ */
+
+ int ndx;
+
+ switch( astate )
+ {
+ case TAP_RESET: ndx = 0; break;
+ case TAP_DRSHIFT: ndx = 2; break;
+ case TAP_DRPAUSE: ndx = 3; break;
+ case TAP_IDLE: ndx = 1; break;
+ case TAP_IRSHIFT: ndx = 4; break;
+ case TAP_IRPAUSE: ndx = 5; break;
+ default:
+ LOG_ERROR( "fatal: unstable state \"%s\" used in tap_move_ndx()", tap_state_name(astate) );
+ exit(1);
+ }
+
+ return ndx;
+}
+
+int tap_get_tms_path( tap_state_t from, tap_state_t to )
+{
+ /* tap_move[i][j]: tap movement command to go from state i to state j
+ * 0: Test-Logic-Reset
+ * 1: Run-Test/Idle
+ * 2: Shift-DR
+ * 3: Pause-DR
+ * 4: Shift-IR
+ * 5: Pause-IR
+ *
+ * DRSHIFT->DRSHIFT and IRSHIFT->IRSHIFT have to be caught in interface specific code
+ */
+ static const u8 tms_seqs[6][6] =
+ {
+ /* value clocked to TMS to move from one of six stable states to another */
+
+ /* RESET IDLE DRSHIFT DRPAUSE IRSHIFT IRPAUSE */
+ { 0x7f, 0x00, 0x17, 0x0a, 0x1b, 0x16 }, /* RESET */
+ { 0x7f, 0x00, 0x25, 0x05, 0x2b, 0x0b }, /* IDLE */
+ { 0x7f, 0x31, 0x00, 0x01, 0x0f, 0x2f }, /* DRSHIFT */
+ { 0x7f, 0x30, 0x20, 0x17, 0x1e, 0x2f }, /* DRPAUSE */
+ { 0x7f, 0x31, 0x07, 0x17, 0x00, 0x01 }, /* IRSHIFT */
+ { 0x7f, 0x30, 0x1c, 0x17, 0x20, 0x2f } /* IRPAUSE */
+ };
+
+ if( !tap_is_state_stable(from) )
+ {
+ LOG_ERROR( "fatal: tap_state \"from\" (=%s) is not stable", tap_state_name(from) );
+ exit(1);
+ }
+
+ if( !tap_is_state_stable(to) )
+ {
+ LOG_ERROR( "fatal: tap_state \"to\" (=%s) is not stable", tap_state_name(to) );
+ exit(1);
+ }
+
+ /* @todo: support other than 7 clocks ? */
+ return tms_seqs[tap_move_ndx(from)][tap_move_ndx(to)];
+}
+
+
+bool tap_is_state_stable(tap_state_t astate)
+{
+ bool is_stable;
+
+ /* A switch() is used because it is symbol dependent
+ (not value dependent like an array), and can also check bounds.
+ */
+ switch( astate )
+ {
+ case TAP_RESET:
+ case TAP_IDLE:
+ case TAP_DRSHIFT:
+ case TAP_DRPAUSE:
+ case TAP_IRSHIFT:
+ case TAP_IRPAUSE:
+ is_stable = true;
+ break;
+ default:
+ is_stable = false;
+ }
+
+ return is_stable;
+}
+
+tap_state_t tap_state_transition(tap_state_t cur_state, bool tms)
+{
+ tap_state_t new_state;
+
+ /* A switch is used because it is symbol dependent and not value dependent
+ like an array. Also it can check for out of range conditions.
+ */
+
+ if (tms)
+ {
+ switch (cur_state)
+ {
+ case TAP_RESET:
+ new_state = cur_state;
+ break;
+ case TAP_IDLE:
+ case TAP_DRUPDATE:
+ case TAP_IRUPDATE:
+ new_state = TAP_DRSELECT;
+ break;
+ case TAP_DRSELECT:
+ new_state = TAP_IRSELECT;
+ break;
+ case TAP_DRCAPTURE:
+ case TAP_DRSHIFT:
+ new_state = TAP_DREXIT1;
+ break;
+ case TAP_DREXIT1:
+ case TAP_DREXIT2:
+ new_state = TAP_DRUPDATE;
+ break;
+ case TAP_DRPAUSE:
+ new_state = TAP_DREXIT2;
+ break;
+ case TAP_IRSELECT:
+ new_state = TAP_RESET;
+ break;
+ case TAP_IRCAPTURE:
+ case TAP_IRSHIFT:
+ new_state = TAP_IREXIT1;
+ break;
+ case TAP_IREXIT1:
+ case TAP_IREXIT2:
+ new_state = TAP_IRUPDATE;
+ break;
+ case TAP_IRPAUSE:
+ new_state = TAP_IREXIT2;
+ break;
+ default:
+ LOG_ERROR( "fatal: invalid argument cur_state=%d", cur_state );
+ exit(1);
+ break;
+ }
+ }
+ else
+ {
+ switch (cur_state)
+ {
+ case TAP_RESET:
+ case TAP_IDLE:
+ case TAP_DRUPDATE:
+ case TAP_IRUPDATE:
+ new_state = TAP_IDLE;
+ break;
+ case TAP_DRSELECT:
+ new_state = TAP_DRCAPTURE;
+ break;
+ case TAP_DRCAPTURE:
+ case TAP_DRSHIFT:
+ case TAP_DREXIT2:
+ new_state = TAP_DRSHIFT;
+ break;
+ case TAP_DREXIT1:
+ case TAP_DRPAUSE:
+ new_state = TAP_DRPAUSE;
+ break;
+ case TAP_IRSELECT:
+ new_state = TAP_IRCAPTURE;
+ break;
+ case TAP_IRCAPTURE:
+ case TAP_IRSHIFT:
+ case TAP_IREXIT2:
+ new_state = TAP_IRSHIFT;
+ break;
+ case TAP_IREXIT1:
+ case TAP_IRPAUSE:
+ new_state = TAP_IRPAUSE;
+ break;
+ default:
+ LOG_ERROR( "fatal: invalid argument cur_state=%d", cur_state );
+ exit(1);
+ break;
+ }
+ }
+
+ return new_state;
+}
+
+const char* tap_state_name(tap_state_t state)
+{
+ const char* ret;
+
+ switch( state )
+ {
+ case TAP_RESET: ret = "RESET"; break;
+ case TAP_IDLE: ret = "RUN/IDLE"; break;
+ case TAP_DRSELECT: ret = "DRSELECT"; break;
+ case TAP_DRCAPTURE: ret = "DRCAPTURE"; break;
+ case TAP_DRSHIFT: ret = "DRSHIFT"; break;
+ case TAP_DREXIT1: ret = "DREXIT1"; break;
+ case TAP_DRPAUSE: ret = "DRPAUSE"; break;
+ case TAP_DREXIT2: ret = "DREXIT2"; break;
+ case TAP_DRUPDATE: ret = "DRUPDATE"; break;
+ case TAP_IRSELECT: ret = "IRSELECT"; break;
+ case TAP_IRCAPTURE: ret = "IRCAPTURE"; break;
+ case TAP_IRSHIFT: ret = "IRSHIFT"; break;
+ case TAP_IREXIT1: ret = "IREXIT1"; break;
+ case TAP_IRPAUSE: ret = "IRPAUSE"; break;
+ case TAP_IREXIT2: ret = "IREXIT2"; break;
+ case TAP_IRUPDATE: ret = "IRUPDATE"; break;
+ default: ret = "???";
+ }
+
+ return ret;
+}
+
+static tap_state_t tap_state_by_name( const char *name )
+{
+ tap_state_t x;
+
+ for( x = 0 ; x < TAP_NUM_STATES ; x++ ){
+ /* be nice to the human */
+ if( 0 == strcasecmp( name, tap_state_name(x) ) ){
+ return x;
+ }
+ }
+ /* not found */
+ return TAP_INVALID;
+}
+
+#ifdef _DEBUG_JTAG_IO_
+
+#define JTAG_DEBUG_STATE_APPEND(buf, len, bit) \
+ do { buf[len] = bit ? '1' : '0'; } while(0)
+#define JTAG_DEBUG_STATE_PRINT(a, b, astr, bstr) \
+ DEBUG_JTAG_IO("TAP/SM: %9s -> %5s\tTMS: %s\tTDI: %s", \
+ tap_state_name(a), tap_state_name(b), astr, bstr)
+
+tap_state_t jtag_debug_state_machine(const void *tms_buf, const void *tdi_buf,
+ unsigned tap_bits, tap_state_t next_state)
+{
+ const u8 *tms_buffer;
+ const u8 *tdi_buffer;
+ unsigned tap_bytes;
+ unsigned cur_byte;
+ unsigned cur_bit;
+
+ unsigned tap_out_bits;
+ char tms_str[33];
+ char tdi_str[33];
+
+ tap_state_t last_state;
+
+ // set startstate (and possibly last, if tap_bits == 0)
+ last_state = next_state;
+ DEBUG_JTAG_IO("TAP/SM: START state: %s", tap_state_name(next_state));
+
+ tms_buffer = (const u8 *)tms_buf;
+ tdi_buffer = (const u8 *)tdi_buf;
+
+ tap_bytes = TAP_SCAN_BYTES(tap_bits);
+ DEBUG_JTAG_IO("TAP/SM: TMS bits: %u (bytes: %u)", tap_bits, tap_bytes);
+
+ tap_out_bits = 0;
+ for(cur_byte = 0; cur_byte < tap_bytes; cur_byte++)
+ {
+ for(cur_bit = 0; cur_bit < 8; cur_bit++)
+ {
+ // make sure we do not run off the end of the buffers
+ unsigned tap_bit = cur_byte * 8 + cur_bit;
+ if (tap_bit == tap_bits)
+ break;
+
+ // check and save TMS bit
+ tap_bit = !!(tms_buffer[cur_byte] & (1 << cur_bit));
+ JTAG_DEBUG_STATE_APPEND(tms_str, tap_out_bits, tap_bit);
+
+ // use TMS bit to find the next TAP state
+ next_state = tap_state_transition(last_state, tap_bit);
+
+ // check and store TDI bit
+ tap_bit = !!(tdi_buffer[cur_byte] & (1 << cur_bit));
+ JTAG_DEBUG_STATE_APPEND(tdi_str, tap_out_bits, tap_bit);
+
+ // increment TAP bits
+ tap_out_bits++;
+
+ // Only show TDO bits on state transitions, or
+ // after some number of bits in the same state.
+ if ((next_state == last_state) && (tap_out_bits < 32))
+ continue;
+
+ // terminate strings and display state transition
+ tms_str[tap_out_bits] = tdi_str[tap_out_bits] = 0;
+ JTAG_DEBUG_STATE_PRINT(last_state, next_state, tms_str, tdi_str);
+
+ // reset state
+ last_state = next_state;
+ tap_out_bits = 0;
+ }
+ }
+
+ if (tap_out_bits)
+ {
+ // terminate strings and display state transition
+ tms_str[tap_out_bits] = tdi_str[tap_out_bits] = 0;
+ JTAG_DEBUG_STATE_PRINT(last_state, next_state, tms_str, tdi_str);
+ }
+
+ DEBUG_JTAG_IO("TAP/SM: FINAL state: %s", tap_state_name(next_state));
+
+ return next_state;
+}
+#endif // _DEBUG_JTAG_IO_
+
+/*-----</Cable Helper API>--------------------------------------*/