How JTAG Works
Street View for Circuit Boards, Part Three
In part one, we looked at JTAG boundary scan as a way to tour the electronic networks of a circuit board, much like Street View in Google Maps lets you virtually roam road networks. In part two, we installed some software packages with open-source implementations of essential algorithms. Those software packages also include the drivers you need to communicate over the JTAG serial bus from your PC.
For those of you interested in a deeper dive, in part three, we’ll look at when to use JTAG, it’s formal syntax, and how the bits and pieces of information it returns get mapped into a full picture of the on-board landscape.
When to Use JTAG
The JTAG circuitry inside all those chips on your personal electronics is designed to be normally inert. JTAG is the doctor that your circuit board, just like any patient, never really wants a visit from. As long as your device is functioning, JTAG stays in the background and out of the way, ready to be called only if needed.
If a device has failed and is in need of repair, your best course of action is to contact the manufacturer. Always service the device in accordance with the manufacturer’s recommendations. Failure to do so will void the factory warranty. If a device requires service, its manufacturer may deliver a software upgrade electronically. Often, the upgrade uses JTAG to configure or rewrite non-volatile memory and firmware. During this process, the manufacturer will ensure the safety of the device and anything connected to it.
Outside the warranty period, a device can be taken out of operation and repurposed, for example, inside a digital twin or system mock-up. In that way, you can use JTAG boundary scan on out-of-service devices to remotely simulate faults or diagnose a failure.
The full potential of JTAG for the consumer after-market is yet to be realized. As more manufacturers come on board with the right to repair and repurpose programmable equipment, the features that JTAG makes possible may move to a more secure and open standard. While we’re not there yet, understanding JTAG as it is today can give you a glimpse into what the future may bring.
The Highs and Lows of JTAG
JTAG originates from features built into modern ICs. Physically, it’s made up of seven pins on the chip. The board manufacturer configures these pins from chip to chip and then puts them on a connector for you to access.
Two of these pins are the serial I/O lines we discussed in part two: the one named test-data in (or TDI); and the other, test-data out (TDO). Serial I/O lines shift one bit at a time in sync with the rising and falling edges of the clock line, called TCK. Also on the JTAG connector you’ll find a logic high pin (VCC, or VTref), a logic low pin (GND), and an optional hard test reset line (TRST or nRESET).
Above all others, the last pin remaining on the connector is called the test-mode selector (TMS). This pin drives JTAG’s state machine, also known as the test-access port (TAP) controller. You’ll use the TMS pin before sending and receiving on the serial I/O lines to let the bus know what to expect. The Python language offers the shortest and most definitive answer to how activity on the TMS pin sets the stage for the JTAG bus:
TMS = r"".join([
r"^(", #normallyPassive
r"(", #tmsActivity
r"0+", #!> readyToRun
r"(", #updateCycle
r"11?", #!> dr/ir selected
r"(", #sampleCycle
r"0", #!> capture/repeat
r"0*", #!> shifting TDI/TDO
r"(",
r"10+", #detourOption
r")?",
r"1",
r")+",
r"1", #!> update occurs
r"0*",
r")*",
r"11", #>end set of updateCycles
r")?",
r"1+", #return to and stay in reset
r")*$" #passively inert
])
That line of code returns the regular expression (regex) representing any number of complete passes of the JTAG TAP controller state machine. I’ve presented it above in its entirety to give you the overview. It’s ugly, right?
Regex uses math to describe machines. In each of the sections that follow, I’ll put into plain language what the regex means. First, notice how the TMS regex is arranged in pairs of opening and closing delimiters. I’ll break the expression down one delimited string at a time for a clear view of what each inner term describes.
Normally Passive
The outermost delimiters can be replaced by the following function:
normallyPassive = lambda tmsActivity : [r"^("]+tmsActivity+[r")*$"]
The term “^” means that upon power-on and also in response to a hard reset on the TRST line, JTAG will stay out of the way. The “*” symbol near the end means it will do so even in the absence of any activity clocked out on the TMS line. The “$” terminal means that the system returns to the normally passive state when TMS activity (if any) completes.
TMS Activity
The next pair of delimiters is used to make the call to put the JTAG diagnostic tool into action.
tmsActivity = lambda readyToRun : [r"("]+readyToRun+[r")?1+"]
TMS activity consists of a series of “1”s and “0”s clocked out one per cycle by the TCK line. The “+” symbol following the “1” in the code means that, from the passive state, the board can be explicitly held in reset indefinitely by keeping the TMS equal to 1. The “?” preceding it means that any changes to TMS beyond that are entirely optional. The board manufacturer takes advantage of this feature by installing a pull-up resistor that keeps TMS at “1” until you connect your JTAG cable.
Waking Up
Of course, holding the controller in reset is not what your aim is. So lets look at the other option, which is waking up and getting ready to run.
readyToRun = lambda updateCycle : [r"0+("]+updateCycle+[r")*11"]
The JTAG bus will transition to being ready for action when TMS is driven low. The bus will transition back to sleep when TMS is held high for more than two ticks after any number of update cycles.
Update Cycle
Now you’re at the meat and potatoes section of JTAG’s theory of operation. The update cycle is where the commands and data payload get transferred from your software to the onboard chips. The drivers you installed in part two do most of their work here. During the cycle, the driver checks to see if TDO and TDI respond as expected, and then completes the update to write the selected JTAG register.
updateCycle = lambda sampleCycle : [r"11?("]+sampleCycle+[r")+10*"]
As needed, any number of update cycles can be called. Each begins by setting TMS high for exactly one or two cycles. The number of cycles selects either a data register (1 cycle) or the instruction register (2 cycles).
Once one of these two registers is selected, it must be followed by at least one sample cycle; otherwise the register is de-selected and the update cycle aborts.
After the last sample cycle completes, the actual update itself occurs on the next cycle with TMS held high. Next, if you like, you can idle the JTAG controller in neutral by setting TMS low. Whether you idle or not, the board stands ready either for the next update cycle, or otherwise, the soft reset that sends it back to sleep.
Sample Cycle
The sample cycle is the meat to the update cycle’s potatoes. Upon entry to the sample cycle, the JTAG bus takes a single image of the selected register’s bit-pattern. This image is then shifted out over the TDO serial line for each tick of the TCK clock. At the same time as the current image is shifted out, incoming bits on the TDI line are queued for update. Depending on the OPCODE you last sent to the instruction register, this incoming data will be written to the selected register once the sample cycle ends and control returns to the update phase.
Activity on the TMS is described by the following regex:
sampleCycle = lambda detourOption : [r"00*("]+detourOption+[r")?1"]
That formula indicates that TMS drops low for at least one clock at the start of each sample cycle. TMS can then be held low indefinitely: during this time the TDI and TDO bits start shifting through the digital avenues negotiated by the instruction register. Normally the tour ends when TMS goes high for one cycle, but you can instead choose to detour back if you quickly signal your intention with a high to low transition on the TMS line. Otherwise, skip the detour to end this set of sample cycles.
Detour Option
The detour option is indicated when the rising TMS signal is immediately followed by dropping TMS low again:
detourOption = [r"10+"]
Detouring lets you pause the JTAG bus for however long you want. The longer you hold TMS at zero, the longer the detour lasts. Messages traveling from TDI to TDO are paused during the detour.
When you’ve lingered long enough, you raise the TMS line again like pulling the bell on the bus. Your detour grants you the privilege of commencing a new sample cycle. The set of sample cycles end if you choose not to exercise this option.
Working with RegEx
You can compose the original string presented at the start of this section from the lambda expressions in each sub-section. If you are familiar with using regular expressions, you’ll appreciate the following Python code for working with both outer and inner terms:
regexParts = [""]+normallyPassive(
tmsActivity(
readyToRun(
updateCycle(
sampleCycle(
detourOption
)
)
)
)
)+[""]
regexGroups=["".join(regexParts[p:-p]) for p in range(1,7)]
You’ll find ways to apply the 6 resulting sub-strings to a regular expression parser. That will help you identify how long the JTAG controller spends in each of the corresponding cycles, and how many bits of serial activity are shifted in and out.
A Map of Bits and Pieces
We’ve covered the seven signals that make up the JTAG bus: VCC, GND, TRST, TCK, TMS TDI, and TDO. The first two change only during power-on and shutdown. The third is a hard reset signal that turns out to be entirely optional: most of the time you will use a soft-reset on the TMS line to ensure that all chips on the bus are in a known starting state. In addition to performing a soft reset, the TMS line supports any number of high and low transitions and interprets them according to the formal grammar presented in the previous section. The purpose of the TMS line is to make sure that the JTAG bus is in the right state to direct intelligible data over the TDI and TDO lines.
The bits of data that flow out the TDO line come from snapshots of in-chip registers on the circuit board. Some of these registers are tied to the voltages on input and output pins. You can peer out onto the physical circuitry from those registers. You’ll need the software algorithms introduced in part two to do so. You’ll also need a map, which comes from the chip manufacturers in the form of a BSDL file.
Additional details about the on-chip registers and how to use them is available directly from datasheets and application notes published by the manufacturer. Those resources tell you what to send on the TDI line in order to access advanced capabilities. If the board employs highly scaled, system-on-chip solutions, then advanced capabilities may include access to embedded virtual or soft instruments that monitor internal on-chip features.
On the BDSL website, you’ll find plenty of BSDL files to get you started. Those files are intended to be parsed by machines and software. If you are a visual learner like I am, you’ll prefer software that illustrates how the data in these files relates to the real-world bill-of-materials on an actual circuit board. As a first cut, I’ve refactored some of the code from the Viveris JTAG Boundary Scan utility. My version is based on the CMake build system and relies on SWIG (the Simplified Wrapper and Interface Generator) to export portions of the Viveris library to C++ and Python. SWIG also supports exporting to other languages such as Tcl, C#, Java, and Octave.
sudo apt install -y swig
git clone https://github.com/nOw-Innovation/jtag-boundary-scanner.git
cd jtag-boundary-scanner
mkdir -p cmake
cd cmake
cmake ../lib_jtag_core .
cmake --build .
The preceding commands will build a Python 3 example in the folder cmake/test/apps/py3 called py3UI.py
. When provided with the path to a BSDL file as an input, it produces a rudimentary graphic from a BSDL file, as the following figure shows:
In the graphic, the JTAG chain is shown near the outer edge of the image. In the center, the pins of the chip are illustrated. Each pin on the chip may map to several bits from the JTAG chain. Chain-bits control the direction and state of the chip’s pin-out. Lines in the graphic connect the pin to the corresponding chain bit(s) in the JTAG boundary scan register. Lines with arrows are input/output lines. Lines without arrows are control lines that set the direction of the pin. A few bits in the JTAG chain are not directly connected to any pin. Those have internal purposes, and are sometimes included to support a common chain-length across a family of chips.
Wrapping Up
In this series, we started with an overview of JTAG and what you can do with it. Next we covered open source software packages you can use for JTAG boundary testing. To wrap up, in this article we looked more in-depth at the origins of JTAG and how it works.
As chips become more integrated and feature-rich, there is a need for software that can mine the large inventory of documentation that explains their operation. The topics covered in this series of three articles are intended to encourage software developers to create such software. Are you up for the challenge?
🔊 If you have questions or would like to me to cover other topics related to JTAG, please leave a comment.