Lib(X)SVF - A library for implementing SVF and XSVF JTAG players ****************************************************************** Please check the subversion repository for updates: http://svn.clifford.at/libxsvf/trunk/ You also might want to have a look at the project homepage: http://www.clifford.at/libxsvf/ In papers and reports, please refer to Lib(X)SVF as follows: "Clifford Wolf, Lib(X)SVF: A library for implementing SVF and XSVF JTAG players. http://www.clifford.at/libxsvf/", e.g. using the following BibTeX code: @MISC{LibXSVF, author = {Clifford Wolf}, title = {Lib(X)SVF: A library for implementing SVF and XSVF JTAG players}, howpublished = "\url{http://www.clifford.at/libxsvf/}" } Please send bug reports and fixes to . Copyright and Disclaimer ------------------------ Copyright (C) 2009 RIEGL Research ForschungsGmbH Copyright (C) 2009 Clifford Wolf Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Introduction ------------ JTAG (IEEE 1149.1, aka "Boundary Scan", [1], [2]) is a standard IC testing, debugging and programming port. SVF (Serial Vector Format, [3], [4]) is a file format for storing the patterns that should be sent to the JTAG interface, as well as the expected response. It is used as an exchange format between programms that generate the JTAG input/output patterns and devices that can physically talk to a JTAG interface. XSVF (Xilinx Serial Vector Format, [5]) is a binary variant of the SVF file format, optimized but not limited to programming Xilinx FPGA and CPLD devices. Often one wants to use an embedded host processor or microcontroller to access the JTAG interface on an embedded device instead of using an external JTAG probe. This library can be used to implement such a solution. In addition to playing SVF and XSVF files this library is also capable of scanning the devices in the JTAG chain. Lib(X)SVF is free software licensed under the ISC license (a licence that is functionally equivalent to the 2-clause BSD license). [1] http://en.wikipedia.org/wiki/JTAG [2] http://www.fpga4fun.com/JTAG.html [3] http://en.wikipedia.org/wiki/Serial_Vector_Format [4] http://www.asset-intertech.com/support/svf.pdf [5] http://www.xilinx.com/bvdocs/appnotes/xapp503.pdf Limitations and non-standard extensions --------------------------------------- The SVF commands 'PIO' and 'PIOMAP' are unsupported. Any use of this commands in an SVF input file is reported as error. The SVF 'RUNTEST' command is implemented in a limited manner: The 'MAXIMUM' time parameter is ignored. Combining 'SCK' with a time parameter results in first executing the specified number of clock pulses followed by a delay of the specified timespan, instead of performing the clock cycles and the delay in parallel. The SVF commands 'HDR', 'HIR', 'SDR', 'SIR', 'TDR' and 'TIR' support an additional non-standard 'RMASK' parameter. This is a mask for the TDO bits, simmilar to the standard 'MASK' parameter. All TDO bits marked using a '1' in 'RMASK' are reported back to the host application using the the ret_tdo() callback function. This can be used to read data (such as device serial numbers) using JTAG by providing SVF templates. Using and Porting ----------------- The library itself is written in plain C and does not depend on any library calls or headers, not even from the standard C library. So it can be ported easily even to restricted environment, such as embedded systems. So far the libary has only been tested on 32 bit hosts. Using it on 16 bit processors might not be possible without performing some minor fixes in the code. The program 'xsvftool-gpio' (see xsvftool-gpio.c) is a good example of how to use the library. Please have a look at this program first. Note: See 'Host accessor macros' below for an alternative way of integrating libxsvf into your host environment. The host application must provide an libxsvf_host struct as defined in libxsvf.h. This struct contains some function pointers that must be set to implementations of the following functions: int setup(struct libxsvf_host *h); This function is called by libxsvf to setup/initialize the jtag interface. It is executed before any other libxsvf_host callback function is called. This function should return 0 when setting up the jtag interface went fine and -1 on an error. int shutdown(struct libxsvf_host *h); This function is called by libxsvf to shutdown the jtag interface. No other libxsvf_host callback function will be called after this function has been executed. This function should return 0 when shutting down the jtag interface went fine and -1 on an error. void udelay(struct libxsvf_host *h, long usecs, int tms, long num_tck) A function that delays execution for at least the specified number of microseconds. When the 'num_tck' argument is not 0 also the specified number tck clock cycles (i.e. 1-0-1 transitions) must be generated with TMS set to the value specified in the 'tms' argument. A simple implementation may perform the delay and the clock cycles after another instead of parallel. This only has an impact on the runtime of the player, not on its functionality. int getbyte(struct libxsvf_host *h); A function that returns the next byte from the input file or -1 on end of file. int sync(struct libxsvf_host *h); This function is only needed when writing bindings for an asynchronous hardware interface (see 'Using libxsvf with asynchronous interfaces' below). This function is optional and the function pointer may be set to a NULL pointer on implementations using the simple synchronous interface. void pulse_tck(struct libxsvf_host *h, int tms, int tdi, int tdo, int rmask, int sync) This is the main JTAG I/O callback function. It must perform the following tasks: * Set the tms line to the value specified in the 'tms' argument. * Set the tdi line to the value specified in the 'tdi' argument. This argument may be '-1' to indicate that the value of the tdi line is not important. In this case the tdi line may be set to any value or may be left unchanged. * Create a negative pulse (1-0-1) on the JTAG TCK line. * Check the tdo line against the should-be value specified in the 'tdo' argument. This argument may be '-1' to indicate that the value of the tdo line doesn't need to be checked. * Store the current tdo value if the 'rmask' value is set to '1'. This step may be ignored if the RMASK feature (see "Limitations and non-standard extensions" above) is not used. The function must return the current value of the tdo line, or -1 on a TDO-mismatch-error. A simple implementation of this function would look like this: --snip-- int my_pulse_tck(struct libxsvf_host *h, int tms, int tdi, int tdo, int rmask, int sync) { int line_tdo; setPort(TMS, tms); if (tdi >= 0) setPort(TDI, tdi); setPort(TCK, 0); setPort(TCK, 1); line_tdo = getPort(TDO); return tdo < 0 || line_tdo == tdo ? line_tdo : -1; } --snap-- The 'sync' argument can safely be ignored unless you are writing bindings for an asynchronous hardware interface (see 'Using libxsvf with asynchronous interfaces' below). void pulse_sck(struct libxsvf_host *h); A function to create a pulse on the JTAG SCK line. This function is optional and the function pointer may be set to a NULL pointer on implementations without an SCK line. In this cases an SVF 'RUNTEST n SCK' command has no effect. void set_trst(struct libxsvf_host *h, int v); A function to set the JTAG TRST line to the specified value: 1 ... drive the line high 0 ... drive the line low -1 ... do not drive the line (high impedance) -2 ... got SVF 'TRST ABSENT' command This function is optional and the function pointer may be set to a NULL pointer on implementations without an TRST line. In this cases an SVF 'TRST' command has no effect. int set_frequency(struct libxsvf_host *h, int v); A function to set the JTAG CLK frequency to the specified value in Hz. This function should return 0 when setting the frequency was successful and -1 on error. This function pointer is optional (may be set to NULL). In this case an SVF FREQUENCY command always results in an error. void report_tapstate(struct libxsvf_host *h); This function is called whenever the state of the TAP state machine has changed. The TAP state can be read using the h->tap_state enum. This function pointer is optional (may be set to NULL) and is for debugging purposes only. void report_device(struct libxsvf_host *h, unsigned long idcode); This function is called in scan mode for each device found in the JTAG chain. This function pointer is optional (may be set to NULL) and is only called in the SCAN mode. void report_status(struct libxsvf_host *h, const char *message); This function is called each time before an SVF or XSVF command is executed. This function pointer is optional (may be set to NULL) and is for debugging purposes only. void report_error(struct libxsvf_host *h, const char *file, int line, const char *message); This function is called whenever an error is detected in libxsvf. It is not optional and should provide a way to notify a user about the error. void *realloc(struct libxsvf_host *h, void *ptr, int size, enum libxsvf_mem which); This function must provide a way to allocate dynamic memory. In cases where there is a standard c library it may be a simple wrapper for the realloc() function. The xsvftool-gpio command line option '-r' can be used to auto-generate a realloc function for static buffers, based on the requirements from an example svf or xsvf file. Example given: ./xsvftool-gpio -r my_host_realloc -s demo.svf (Re-)allocation may fail. In this cases a NULL pointer must be returned. The library then generates an error, frees all resources and returns. After such a struct is prepared, the function libxsvf_play() can be called, passing the libxsvf_host struct as first and the mode (LIBXSVF_MODE_SVF, LIBXSVF_MODE_XSVF or LIBXSVF_MODE_SCAN) as second argument. Example given: if (libxsvf_play(&h, LIBXSVF_MODE_XSVF) < 0) { /* Error handling */ } The libxsvf_host struct is passed back to all callback functions and the 'user_data' member (a void pointer) can be used to pass additional data (such as a file handle) to the callbacks. Host accessor macros -------------------- Despite its great flexibility, APIs based on callback functions as the one used by libxsvf are unusual in the embedded community. Basically because they introduce a slight overhead in the memory footprint. For those who prefer a more direct integration with their host environments libxsvf also provides 'host accessor macros' in the libxsvf.h header file. Simply remove the callback functions from the libxsvf_host struct and modify the LIBXSVF_HOST_ macros to fit your needs. Using libxsvf with asynchronous interfaces ------------------------------------------ This library has been designed at first for a register mapped bit banging interface as it can be found on many microcontrollers or host CPUs. But some interfaces might require the JTAG data to be send and recivied in blocks and/or asynchronously. This is not trivial with this library because the pulse_tck() callback function is expected to transfer one single bit at a time. The solution to this is to buffer all data sent to pulse_tck() and always return a valid status (i.e. 'tdo < 0 ? 1 : tdo') and do the transfers when the buffer is full or when an interface shutdown is requested. However, some JTAG transaction must be performed synchronously (e.g. the last transaction in an XSVF XREPEAT data shift. In this cases pulse_tck() is called with the 'sync' argument set to 1. The pulse_tck() function must then perform all buffered JTAG transactions and return the actual tdo value for this last JTAG transaction or -1 if an error was detected before. An asynchronous interface binding also must implement the sync() function. It must perform all buffered JTAG transactions and return -1 if a TDO error was detected an 0 otherwise. Note: The returncode of pulse_tck is not checked in all conditions! So whenever an error is detected all further calls to pulse_tck() up to and including the next call of pulse_tck() with the 'sync' argument set or the next call to sync() or shutdown() must return -1. Have a look at the example program 'xsvftool-ft232h.c' for a reference implementation. Stripping down libxsvf ---------------------- It is possible to disable SVF, XSVF and/or SCAN support by setting the LIBXSVF_WITHOUT_SVF, LIBXSVF_WITHOUT_XSVF or LIBXSVF_WITHOUT_SCAN defines. In this cases one would not want to link against svf.o, xsvf.o or scan.o. One does not need to link agains statename.o and memname.o if the libxsvf_state2str() and libxsvf_mem2str() functions are not needed. Usually this functions are used for debugging purposes only. It is possible to modify the LIBXSVF_HOST_REPORT_STATUS() and LIBXSVF_HOST_REPORT_ERROR() macros in libxsvf.h to be empty instructions. This drastically reduces the number of string constants in the code.