Tuesday, March 19, 2013

JTAG Communication by Java

The new target board DE0-Nano enables JTAG communication using download cable to communicate with host PC only by its embedded functions.
Currently, however, somehow it’s hard to get well-organized information on JTAG communication.  No technical document seems available even about DE0-Nano’s attached demo application surely able to communicate with host PC.
Based on this reality, I am disclosing the result of my study:

DE0-Nano has a USB Blaster-compatible circuit in its body, and so allows host PC to access the board itself simply using the driver of USB Blaster.

As this compatible circuit uses FT245BL produced by Future Technology Devices International Ltd. (FTDI), the driver of USB Blaster must be FTDI’s D2XX driver actually.  As proof of this, it is possible to access the board just using a DLL file (ftd2xx.dll) attached to D2XX driver.
Therefore, information on accessing hardware is available in an indirect form as a document of D2XX driver.

The next point to be discussed is what type of data should be exchanged.  Regarding this, details are available in a document relating to UrJTAG.  In short, data are clammed in USB packets no longer than 64 bytes and sent out in two kinds of formats, either bit banging mode, which enables controlling all JTAG signals, or byte shift mode capable of high-speed data communication.

Then, the next question is how to establish communication with host PC by JTAG.  The simplest way is probably to use Virtual JTAG Megafunction for on-chip debugging
Now let’s design a circuit.

jtag_led_bdf.png

This figure shows connecting input and output pins to sld_virtual_jtag megafunction by schematic editor of Quartus II software.  For here, we input and output 8-bit data, and so set the parameter sld_ir_width to 8 and sld_auto_instance_index to “YES” just in case.

Connect the input pins key[7..0] to ir_out, and the output pins led[7..0] to ir_in.
Allocate LED pins (A15, A13, B13, A11, D1, F3, B1, L3) on the board to the led[7..0], while for the key[7..0], we only use 2-bit push-buttons (E1, J15), and so assign other pins freely to DIP switches (M15, B9, T8, M1) and GPIO input pins (B8, A8).

If you don’t want such a hassle to input codes, here you can have the block design file (jtag_led.bdf) and the sof file (jtag_led.sof) finished with logic synthesis.  However, you need to specify the pin numbers and the device (EP4CE22F17C6) in case of the block design file.

Write the above-shown circuit into the DE0-Nano beforehand, and execute the below-mentioned Java program on the JNA pre-installed environment.
If you don’t want to install JNA or compile Java scripts, just run the Jar file (jtag_led.jar) which bundles JNA.

I confirmed the working only in the Windows XP environment, but probably it will work in any Win32 environment.  Though it isn’t tested yet in a 64-bit environment, I expect it to work just by changing the DLL file name: “usbblstr32” –> “usbblstr64”.

import com.sun.jna.*;
import com.sun.jna.ptr.*;
public class JTAG_LED {
    static native int FT_OpenEx(String pArg1, int flags,
        PointerByReference pHandle);
    static native int FT_Close(Pointer ftHandle);
    static native int FT_Write(Pointer ftHandle, Pointer lpBuffer,
        int dwBytesToWrite, IntByReference lpdwBytesWritten);
    static native int FT_Read(Pointer ftHandle, Pointer lpBuffer,
        int dwBytesToRead, IntByReference lpdwBytesReturned);
    static {
        Native.register("usbblstr32");
    }
    Pointer ftHandle = null;
    public JTAG_LED(String description) {
        PointerByReference pHandle = new PointerByReference();
        if (FT_OpenEx(description, 2, pHandle) != 0) {
            throw new RuntimeException("FT_OpenEx failed.");
        }
        ftHandle = pHandle.getValue();
    }
    public void close() {
        FT_Close(ftHandle);
    }
    Memory memory = new Memory(64);
    IntByReference ref = new IntByReference();
    public static final short L = 0x2D2C;
    public static final short H = L | 0x1010;
    public static final short TMS = L | 0x0202;
    public static final short TMS_H = TMS | H;
    public static final short OFF = 0x0D0C;
    public void write(short... data) {
        memory.write(0, data, 0, data.length);
        FT_Write(ftHandle, memory, data.length << 1, ref);
    }
    public static final int WR = 0x81;
    public static final int RD = 0xC1;
    public static short byteshift(int data, int mode) {
        return (short) ((data << 8) | mode);
    }
    public byte read() {
        FT_Read(ftHandle, memory, 1, ref);
        return memory.getByte(0);
    }
    public static void main(String[] args) throws InterruptedException {
        JTAG_LED jtag = new JTAG_LED("USB-Blaster");
        jtag.write(TMS, TMS, TMS, TMS, TMS); // TEST_LOGIC/RESET
        jtag.write(L, TMS, TMS, L, L); // SHIFT_IR
        jtag.write(byteshift(0x0e, WR), L, TMS); // USER1 instruction
        jtag.write(TMS, TMS, L, L); // SHIFT_DR
        jtag.write(byteshift(0, WR), TMS_H, TMS, TMS, L, L); // Dummy write
        int lfsr = 1;
        for (int b = 1; (b & 1) != 0;) {
            jtag.write(byteshift(lfsr, RD), TMS_H, TMS, TMS, L, L);
            if (((lfsr <<= 1) & 256) != 0) lfsr ^= 0x171;
            b = jtag.read() & 255;
            System.out.println(Integer.toBinaryString(b));
            Thread.sleep(((b & 2) != 0) ? 10 : 100);
        }
        jtag.write(byteshift(0, WR), TMS_H, TMS, OFF);
        jtag.close();
    }
}

Once the circuit works successfully, though this picture may not show it well, LED will start flickering rapidly.  The flickering is patterned by LFSR, and so not totally randomized.  It sometimes looks as if flowing to the left.  The flickering gets slower by pushing the left push-button.  The program stops and LED goes off by pushing the right push-button.  When Java program is executed on the console, it displays the condition of input pins in binary to let us check the conditions of push-buttons and DIP switches.

All these operations are regulated by host PC.  As a proof, you will see LOAD LED (D4) on during operation, while the light is off at other times.

de0nano_jtag.jpg

This sample program is to apply the virtual instruction register (VIR) of sld_virtual_jtag megafunction for data communication, which is, indeed, a very extraordinary use.
As VIR allows data length up to 32 bit, this technique would have no problem in exchanging data within the length.  A more conventional way is to specify a channel by VIR and then to communicate data by virtual data register (VDR), which sets no limit on data length but requires the implementation of shift register otherwise.

The actual processes of writing VIR are setting USER1 (0000001110) to instruction register (IR) of JTAG and then setting data for transmission and instance ID to data register (DR).  As instance ID surely becomes one-bit-long “1” upon generating only one instance of megafunction, data plus “1” needs to be sent.
While receiving data coincides sending data, the channel choice is reflected only in the next data reception and on.  Therefore, it is necessary to settle the channel by sending dummy data once at first transmission.
While this sample is so simple that leaves almost all tasks to megafunction, actual communication would require protocol-level implementation such as FIFO and flow control.

Though JTAG-related circuit have individual clock domain and therefore require care to metastability, DCFIFO is just a “twofer” to clear the requirement and to mount FIFO.