#ifndef JTAG_H
#define JTAG_H
-#include "types.h"
#include "binarybuffer.h"
#include "log.h"
-#include "command.h"
-
#ifdef _DEBUG_JTAG_IO_
#define DEBUG_JTAG_IO(expr ...) LOG_DEBUG(expr)
//extern tap_transition_t tap_transitions[16]; /* describe the TAP state diagram */
-/*-----<Cable Helper API>-------------------------------------------*/
-
-/* The "Cable Helper API" is what the cable drivers can use to help implement
- * their "Cable API". So a Cable Helper API is a set of helper functions used by
- * cable drivers, and this is different from a Cable API. A "Cable API" is what
- * higher level code used to talk to a cable.
- */
-
-
-/** implementation of wrapper function tap_set_state() */
-void tap_set_state_impl(tap_state_t new_state);
-
-/**
- * Function tap_set_state
- * sets the state of a "state follower" which tracks the state of the TAPs connected to the
- * cable. The state follower is hopefully always in the same state as the actual
- * TAPs in the jtag chain, and will be so if there are no bugs in the tracking logic within that
- * cable driver. All the cable drivers call this function to indicate the state they think
- * the TAPs attached to their cables are in. Because this function can also log transitions,
- * it will be helpful to call this function with every transition that the TAPs being manipulated
- * are expected to traverse, not just end points of a multi-step state path.
- * @param new_state is the state we think the TAPs are currently in or are about to enter.
- */
-#if defined(_DEBUG_JTAG_IO_)
-#define tap_set_state(new_state) \
- do { \
- LOG_DEBUG( "tap_set_state(%s)", tap_state_name(new_state) ); \
- tap_set_state_impl(new_state); \
- } while (0)
-#else
-static inline void tap_set_state(tap_state_t new_state)
-{
- tap_set_state_impl(new_state);
-}
-
-#endif
-
-/**
- * Function tap_get_state
- * gets the state of the "state follower" which tracks the state of the TAPs connected to
- * the cable.
- * @see tap_set_state
- * @return tap_state_t - The state the TAPs are in now.
- */
-tap_state_t tap_get_state(void);
-
-/**
- * Function tap_set_end_state
- * sets the state of an "end state follower" which tracks the state that any cable driver
- * thinks will be the end (resultant) state of the current TAP SIR or SDR operation. At completion
- * of that TAP operation this value is copied into the state follower via tap_set_state().
- * @param new_end_state is that state the TAPs should enter at completion of a pending TAP operation.
- */
-void tap_set_end_state(tap_state_t new_end_state);
-
-/**
- * Function tap_get_end_state
- * @see tap_set_end_state
- * @return tap_state_t - The state the TAPs should be in at completion of the current TAP operation.
- */
-tap_state_t tap_get_end_state(void);
-
-/**
- * Function tap_get_tms_path
- * returns a 7 bit long "bit sequence" indicating what has to be done with TMS
- * during a sequence of seven TAP clock cycles in order to get from
- * state \a "from" to state \a "to".
- * @param from is the starting state
- * @param to is the resultant or final state
- * @return int - a 7 bit sequence, with the first bit in the sequence at bit 0.
- */
-int tap_get_tms_path(tap_state_t from, tap_state_t to);
-
-/**
- * Function tap_move_ndx
- * when given a stable state, returns an index from 0-5. The index corresponds to a
- * sequence of stable states which are given in this order: <p>
- * { TAP_RESET, TAP_IDLE, TAP_DRSHIFT, TAP_DRPAUSE, TAP_IRSHIFT, TAP_IRPAUSE }
- * <p>
- * This sequence corresponds to look up tables which are used in some of the
- * cable drivers.
- * @param astate is the stable state to find in the sequence. If a non stable
- * state is passed, this may cause the program to output an error message
- * and terminate.
- * @return int - the array (or sequence) index as described above
- */
-int tap_move_ndx(tap_state_t astate);
-
-/**
- * Function tap_is_state_stable
- * returns true if the \a astate is stable.
- */
-bool tap_is_state_stable(tap_state_t astate);
-
-/**
- * Function tap_state_transition
- * takes a current TAP state and returns the next state according to the tms value.
- * @param current_state is the state of a TAP currently.
- * @param tms is either zero or non-zero, just like a real TMS line in a jtag interface.
- * @return tap_state_t - the next state a TAP would enter.
- */
-tap_state_t tap_state_transition(tap_state_t current_state, bool tms);
-
-/**
- * Function tap_state_name
- * Returns a string suitable for display representing the JTAG tap_state
- */
-const char* tap_state_name(tap_state_t state);
-
-#ifdef _DEBUG_JTAG_IO_
-/**
- * @brief Prints verbose TAP state transitions for the given TMS/TDI buffers.
- * @param tms_buf must points to a buffer containing the TMS bitstream.
- * @param tdi_buf must points to a buffer containing the TDI bitstream.
- * @param tap_len must specify the length of the TMS/TDI bitstreams.
- * @param start_tap_state must specify the current TAP state.
- * @returns the final TAP state; pass as @a start_tap_state in following call.
- */
-tap_state_t jtag_debug_state_machine(const void *tms_buf, const void *tdi_buf,
- unsigned tap_len, tap_state_t start_tap_state);
-#else
-static inline tap_state_t jtag_debug_state_machine(const void *tms_buf,
- const void *tdi_buf, unsigned tap_len, tap_state_t start_tap_state)
-{
- return start_tap_state;
-}
-#endif // _DEBUG_JTAG_IO_
-
-/*-----</Cable Helper API>------------------------------------------*/
-
extern tap_state_t cmd_queue_end_state; /* finish DR scans in dr_end_state */
extern tap_state_t cmd_queue_cur_state; /* current TAP state */
-typedef void* error_handler_t; /* Later on we can delete error_handler_t, but keep it for now to make patches more readable */
-
-struct scan_field_s;
-typedef int (*in_handler_t)(u8* in_value, void* priv, struct scan_field_s* field);
-
typedef struct scan_field_s
{
jtag_tap_t* tap; /* tap pointer this instruction refers to */
int num_bits; /* number of bits this field specifies (up to 32) */
u8* out_value; /* value to be scanned into the device */
- u8* out_mask; /* only masked bits care */
u8* in_value; /* pointer to a 32-bit memory location to take data scanned out */
- /* in_check_value/mask, in_handler_error_handler, in_handler_priv can be used by the in handler, otherwise they contain garbage */
- u8* in_check_value; /* used to validate scan results */
- u8* in_check_mask; /* check specified bits against check_value */
- in_handler_t in_handler; /* process received buffer using this handler */
- void* in_handler_priv; /* additional information for the in_handler */
+
+ u8* check_value; /* Used together with jtag_add_dr_scan_check() to check data clocked
+ in */
+ u8* check_mask; /* mask to go with check_value */
+
+ /* internal work space */
+ int allocated; /* in_value has been allocated for the queue */
+ int modified; /* did we modify the in_value? */
+ u8 intmp[4]; /* temporary storage for checking synchronously */
} scan_field_t;
+#ifdef INCLUDE_JTAG_INTERFACE_H
+
enum scan_type {
/* IN: from device to host, OUT: from host to device */
SCAN_IN = 1, SCAN_OUT = 2, SCAN_IO = 3
typedef struct scan_command_s
{
- int ir_scan; /* instruction/not data scan */
+ bool ir_scan; /* instruction/not data scan */
int num_fields; /* number of fields in *fields array */
scan_field_t* fields; /* pointer to an array of data scan fields */
tap_state_t end_state; /* TAP state in which JTAG commands should finish */
JTAG_STATEMOVE = 2,
JTAG_RUNTEST = 3,
JTAG_RESET = 4,
- JTAG_END_STATE = 5,
JTAG_PATHMOVE = 6,
JTAG_SLEEP = 7,
JTAG_STABLECLOCKS = 8
extern jtag_command_t* jtag_command_queue;
+extern void* cmd_queue_alloc(size_t size);
+extern void cmd_queue_free(void);
+
+extern void jtag_queue_command(jtag_command_t *cmd);
+extern void jtag_command_queue_reset(void);
+
+#include "interface.h"
+
+#endif // INCLUDE_JTAG_INTERFACE_H
+
/* forward declaration */
typedef struct jtag_tap_event_action_s jtag_tap_event_action_t;
};
extern jtag_tap_t* jtag_AllTaps(void);
extern jtag_tap_t* jtag_TapByPosition(int n);
-extern jtag_tap_t* jtag_TapByPosition(int n);
extern jtag_tap_t* jtag_TapByString(const char* dotted_name);
extern jtag_tap_t* jtag_TapByJimObj(Jim_Interp* interp, Jim_Obj* obj);
extern jtag_tap_t* jtag_TapByAbsPosition(int abs_position);
LINE_PUSH_PULL = 0x1,
};
-typedef struct jtag_interface_s
-{
- char* name;
-
- /* queued command execution
- */
- int (*execute_queue)(void);
-
- /* interface initalization
- */
- int (*speed)(int speed);
- int (*register_commands)(struct command_context_s* cmd_ctx);
- int (*init)(void);
- int (*quit)(void);
-
- /* returns JTAG maxium speed for KHz. 0=RTCK. The function returns
- * a failure if it can't support the KHz/RTCK.
- *
- * WARNING!!!! if RTCK is *slow* then think carefully about
- * whether you actually want to support this in the driver.
- * Many target scripts are written to handle the absence of RTCK
- * and use a fallback kHz TCK.
- */
- int (*khz)(int khz, int* jtag_speed);
-
- /* returns the KHz for the provided JTAG speed. 0=RTCK. The function returns
- * a failure if it can't support the KHz/RTCK. */
- int (*speed_div)(int speed, int* khz);
-
- /* Read and clear the power dropout flag. Note that a power dropout
- * can be transitionary, easily much less than a ms.
- *
- * So to find out if the power is *currently* on, you must invoke
- * this method twice. Once to clear the power dropout flag and a
- * second time to read the current state.
- *
- * Currently the default implementation is never to detect power dropout.
- */
- int (*power_dropout)(int* power_dropout);
-
- /* Read and clear the srst asserted detection flag.
- *
- * NB!!!! like power_dropout this does *not* read the current
- * state. srst assertion is transitionary and *can* be much
- * less than 1ms.
- */
- int (*srst_asserted)(int* srst_asserted);
-} jtag_interface_t;
-
enum jtag_event {
JTAG_TRST_ASSERTED
};
extern jtag_event_callback_t* jtag_event_callbacks;
-extern jtag_interface_t* jtag; /* global pointer to configured JTAG interface */
-
extern int jtag_speed;
extern int jtag_speed_post_reset;
*/
extern int jtag_interface_init(struct command_context_s* cmd_ctx);
+/// Shutdown the JTAG interface upon program exit.
+extern int jtag_interface_quit(void);
+
/* initialize JTAG chain using only a RESET reset. If init fails,
* try reset + init.
*/
*
*/
extern void jtag_add_ir_scan(int num_fields, scan_field_t* fields, tap_state_t endstate);
-extern int interface_jtag_add_ir_scan(int num_fields, scan_field_t* fields, tap_state_t endstate);
-extern void jtag_add_dr_scan(int num_fields, scan_field_t* fields, tap_state_t endstate);
-extern int interface_jtag_add_dr_scan(int num_fields, scan_field_t* fields, tap_state_t endstate);
-extern void jtag_add_plain_ir_scan(int num_fields, scan_field_t* fields, tap_state_t endstate);
-extern int interface_jtag_add_plain_ir_scan(int num_fields, scan_field_t* fields, tap_state_t endstate);
-extern void jtag_add_plain_dr_scan(int num_fields, scan_field_t* fields, tap_state_t endstate);
-extern int interface_jtag_add_plain_dr_scan(int num_fields, scan_field_t* fields, tap_state_t endstate);
+/* same as jtag_add_ir_scan except no verify is performed */
+extern void jtag_add_ir_scan_noverify(int num_fields, const scan_field_t *fields, tap_state_t state);
+extern void jtag_add_dr_scan(int num_fields, const scan_field_t* fields, tap_state_t endstate);
+
+/* set in_value to point to 32 bits of memory to scan into. This function
+ * is a way to handle the case of synchronous and asynchronous
+ * JTAG queues.
+ *
+ * In the event of an asynchronous queue execution the queue buffer
+ * allocation method is used, for the synchronous case the temporary 32 bits come
+ * from the input field itself.
+ */
+extern void jtag_alloc_in_value32(scan_field_t *field);
+
+/* This version of jtag_add_dr_scan() uses the check_value/mask fields */
+extern void jtag_add_dr_scan_check(int num_fields, scan_field_t* fields, tap_state_t endstate);
+extern void jtag_add_plain_ir_scan(int num_fields, const scan_field_t* fields, tap_state_t endstate);
+extern void jtag_add_plain_dr_scan(int num_fields, const scan_field_t* fields, tap_state_t endstate);
+
+
+/* Simplest/typical callback - do some conversion on the data clocked in.
+ * This callback is for such conversion that can not fail.
+ * For conversion types or checks that can
+ * fail, use the jtag_callback_t variant */
+typedef void (*jtag_callback1_t)(u8 *in);
+
+/* A simpler version of jtag_add_callback4 */
+extern void jtag_add_callback(jtag_callback1_t, u8 *in);
+
+
+/* This type can store an integer safely by a normal cast on 64 and
+ * 32 bit systems. */
+typedef intptr_t jtag_callback_data_t;
+
+/* The generic callback mechanism.
+ *
+ * The callback is invoked with three arguments. The first argument is
+ * the pointer to the data clocked in.
+ */
+typedef int (*jtag_callback_t)(u8 *in, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3);
+
+
+/* This callback can be executed immediately the queue has been flushed. Note that
+ * the JTAG queue can either be executed synchronously or asynchronously. Typically
+ * for USB the queue is executed asynchronously. For low latency interfaces, the
+ * queue may be executed synchronously.
+ *
+ * These callbacks are typically executed *after* the *entire* JTAG queue has been
+ * executed for e.g. USB interfaces.
+ *
+ * The callbacks are guaranteeed to be invoked in the order that they were queued.
+ *
+ * The strange name is due to C's lack of overloading using function arguments
+ *
+ * The callback mechansim is very general and does not really make any assumptions
+ * about what the callback does and what the arguments are.
+ *
+ * in - typically used to point to the data to operate on. More often than not
+ * this will be the data clocked in during a shift operation
+ *
+ * data1 - an integer that is big enough to be used either as an 'int' or
+ * cast to/from a pointer
+ *
+ * data2 - an integer that is big enough to be used either as an 'int' or
+ * cast to/from a pointer
+ *
+ * Why stop at 'data2' for arguments? Somewhat historical reasons. This is
+ * sufficient to implement the jtag_check_value_mask(), besides the
+ * line is best drawn somewhere...
+ *
+ * If the execution of the queue fails before the callbacks, then the
+ * callbacks may or may not be invoked depending on driver implementation.
+ */
+extern void jtag_add_callback4(jtag_callback_t, u8 *in,
+ jtag_callback_data_t data1, jtag_callback_data_t data2,
+ jtag_callback_data_t data3);
+
/* run a TAP_RESET reset. End state is TAP_RESET, regardless
* of start state.
*/
extern void jtag_add_tlr(void);
-extern int interface_jtag_add_tlr(void);
-/* Do not use jtag_add_pathmove() unless you need to, but do use it
+/* Application code *must* assume that interfaces will
+ * implement transitions between states with different
+ * paths and path lengths through the state diagram. The
+ * path will vary across interface and also across versions
+ * of the same interface over time. Even if the OpenOCD code
+ * is unchanged, the actual path taken may vary over time
+ * and versions of interface firmware or PCB revisions.
+ *
+ * Use jtag_add_pathmove() when specific transition sequences
+ * are required.
+ *
+ * Do not use jtag_add_pathmove() unless you need to, but do use it
* if you have to.
*
* DANGER! If the target is dependent upon a particular sequence
* a partial implementation of pathmove would have little practical
* application.
*/
-extern void jtag_add_pathmove(int num_states, tap_state_t* path);
-extern int interface_jtag_add_pathmove(int num_states, tap_state_t* path);
+extern void jtag_add_pathmove(int num_states, const tap_state_t* path);
/* go to TAP_IDLE, if we're not already there and cycle
* precisely num_cycles in the TAP_IDLE after which move
* to endstate via TAP_IDLE
*/
extern void jtag_add_runtest(int num_cycles, tap_state_t endstate);
-extern int interface_jtag_add_runtest(int num_cycles, tap_state_t endstate);
/* A reset of the TAP state machine can be requested.
*
*/
extern void jtag_add_reset(int req_tlr_or_trst, int srst);
-/* this drives the actual srst and trst pins. srst will always be 0
- * if jtag_reset_config & RESET_SRST_PULLS_TRST != 0 and ditto for
- * trst.
- *
- * the higher level jtag_add_reset will invoke jtag_add_tlr() if
- * approperiate
- */
-extern int interface_jtag_add_reset(int trst, int srst);
extern void jtag_add_end_state(tap_state_t endstate);
-extern int interface_jtag_add_end_state(tap_state_t endstate);
extern void jtag_add_sleep(u32 us);
-extern int interface_jtag_add_sleep(u32 us);
/**
* stable, then queues up clock_count clocks for transmission.
*/
void jtag_add_clocks(int num_cycles);
-int interface_jtag_add_clocks(int num_cycles);
/*
*/
extern int jtag_execute_queue(void);
+/* same as jtag_execute_queue() but does not clear the error flag */
+extern void jtag_execute_queue_noclear(void);
+
+/* this flag is set when an error occurs while executing the queue. cleared
+ * by jtag_execute_queue()
+ *
+ * this flag can also be set from application code if some error happens
+ * during processing that should be reported during jtag_execute_queue().
+ */
+extern int jtag_error;
+
+static __inline__ void jtag_set_error(int error)
+{
+ if ((error==ERROR_OK)||(jtag_error!=ERROR_OK))
+ {
+ /* keep first error */
+ return;
+ }
+ jtag_error=error;
+}
+
+
+
/* can be implemented by hw+sw */
-extern int interface_jtag_execute_queue(void);
extern int jtag_power_dropout(int* dropout);
extern int jtag_srst_asserted(int* srst_asserted);
/* JTAG support functions */
-extern void jtag_set_check_value(scan_field_t* field, u8* value, u8* mask, error_handler_t* in_error_handler);
-extern enum scan_type jtag_scan_type(scan_command_t* cmd);
-extern int jtag_scan_size(scan_command_t* cmd);
-extern int jtag_read_buffer(u8* buffer, scan_command_t* cmd);
-extern int jtag_build_buffer(scan_command_t* cmd, u8** buffer);
+
+/* execute jtag queue and check value and use mask if mask is != NULL. invokes
+ * jtag_set_error() with any error. */
+extern void jtag_check_value_mask(scan_field_t *field, u8 *value, u8 *mask);
+
+#ifdef INCLUDE_JTAG_INTERFACE_H
+extern enum scan_type jtag_scan_type(const scan_command_t* cmd);
+extern int jtag_scan_size(const scan_command_t* cmd);
+extern int jtag_read_buffer(u8* buffer, const scan_command_t* cmd);
+extern int jtag_build_buffer(const scan_command_t* cmd, u8** buffer);
+#endif // INCLUDE_JTAG_INTERFACE_H
extern void jtag_sleep(u32 us);
extern int jtag_call_event_callbacks(enum jtag_event event);
#define ERROR_JTAG_NOT_STABLE_STATE (-105)
#define ERROR_JTAG_DEVICE_ERROR (-107)
-
-/* this allows JTAG devices to implement the entire jtag_xxx() layer in hw/sw */
-#ifdef HAVE_JTAG_MINIDRIVER_H
-/* Here a #define MINIDRIVER() and an inline version of hw fifo interface_jtag_add_dr_out can be defined */
-#include "jtag_minidriver.h"
-#define MINIDRIVER(a) notused ## a
-#else
-#define MINIDRIVER(a) a
-
-/* jtag_add_dr_out() is a faster version of jtag_add_dr_scan()
+/* jtag_add_dr_out() is a version of jtag_add_dr_scan() which
+ * only scans data out. It operates on 32 bit integers instead
+ * of 8 bit, which makes it a better impedance match with
+ * the calling code which often operate on 32 bit integers.
*
* Current or end_state can not be TAP_RESET. end_state can be TAP_INVALID
*
* return an error. There is no way to determine if there was a failure
* during this function call.
*
- * Note that this jtag_add_dr_out can be defined as an inline function.
+ * This is an inline fn to speed up embedded hosts. Also note that
+ * interface_jtag_add_dr_out() can be a *small* inline function for
+ * embedded hosts.
+ *
+ * There is no jtag_add_dr_outin() version of this fn that also allows
+ * clocking data back in. Patches gladly accepted!
*/
-extern void interface_jtag_add_dr_out(jtag_tap_t* tap, int num_fields, const int* num_bits, const u32* value,
+extern void jtag_add_dr_out(jtag_tap_t* tap,
+ int num_fields, const int* num_bits, const u32* value,
tap_state_t end_state);
-#endif
-
-static __inline__ void jtag_add_dr_out(jtag_tap_t* tap, int num_fields, const int* num_bits, const u32* value,
- tap_state_t end_state)
-{
- if (end_state != TAP_INVALID)
- cmd_queue_end_state = end_state;
- cmd_queue_cur_state = cmd_queue_end_state;
- interface_jtag_add_dr_out(tap, num_fields, num_bits, value, cmd_queue_end_state);
-}
+/**
+ * Function jtag_add_statemove
+ * moves from the current state to the goal \a state. This needs
+ * to be handled according to the xsvf spec, see the XSTATE command
+ * description.
+ */
+extern int jtag_add_statemove(tap_state_t goal_state);
#endif /* JTAG_H */