When I first got into FPGA development I used the Xilinx Platform Cable USB II, which sells for $258.75 on Digikey as of this writing. It integrated nicely with the Xilinx IDE but I quickly grew frustrated. I wanted to use the BSCAN_SPARTAN6 primitive in the FPGA to move debug data on and off the FPGA using JTAG, but Xilinx does not provide any sort of API for scripting the platform cable. Although iMPACT allows manual bit twiddling in the chain as well as executing pre-made SVF files, there is no way to do interactive testing with it
My first step in deciding how to proceed was to see what made their adapter tick. I would have opened up the adapter to see what was inside, but Bunnie saved me the trouble by posting pictures a while ago as the Name That Ware for March 2011.
Xilinx Platform Cable USB II (image courtesy of Bunnie) |
After browsing for something cheaper and based on a well-known chipset, I found the Digilent HS1, a $54.99 FT2232-based adapter which is supported by Digilent's documented JTAG API and integrated nicely with the Xilinx IDE. In addition, since it's a standard FTDI chipset it would be possible to interact with it at a lower level using libftd2xx. (I also built a custom FT232H-based programmer that I have half a dozen of around my lab, but I wanted a known-good design to verify my software on first.)
The HS1 worked quite well using the Xilinx tools, but I still needed JTAG code to talk to it and interact with the FPGAs for scripted tests. I looked at a couple of popular options and rejected each of them:
- OpenOCD (GNU GPL, incompatible with the BSD license used by my work)
- xc3sprog (GPL, standalone tool with no API, includes programming algorithms that can run directly off a .bit file)
- urjtag (GPL, has a socket-based JTAG server under development but not released yet)
The basic structure of libjtaghal is built around two core object types: interfaces and devices. A JtagInterface represents a connection to a single JTAG adapter. As of now I support:
- FT*232H MPSSE (assumes ADBUS7 is the output enable, an option to configure this is planned for the future)
- Digilent API (for HS1 and integrated programmers on the Atlys etc)
- Generic socket-based protocol for talking to remote libjtaghal servers
A JtagDevice represents a single chip in a scan chain. Support for multi-device scan chains needs a bit more work; this is one of the reasons I haven't released it yet.
A given JtagDevice may implement one or more additional interfaces. Some of these are:
- CPLD (generic complex programmable logic device)
- FPGA (generic FPGA device)
- ProgrammableDevice (any device which accepts firmware of some sort, including CPLDs, FPGAs, MCUs, and JTAG-capable ROMs)
- RPCNetworkInterface (a device which supports sending RPC messages over JTAG)
- DMANetworkInterface (a device which supports sending DMA messages over JTAG)
- RPCAndDMANetworkInterface (implements RPCNetworkInterface, DMANetworkInterface, and some logic to connect the two protocols)
JtagDevice* device = iface.GetDevice(devnum); if(device == NULL) { throw JtagExceptionWrapper( "Device is null, cannot continue", "", JtagException::EXCEPTION_TYPE_BOARD_FAULT); } //Make sure it's a programmable device ProgrammableDevice* pdev = dynamic_cast(device); if(pdev == NULL) { throw JtagExceptionWrapper( "Device is not a programmable device, cannot continue", "", JtagException::EXCEPTION_TYPE_BOARD_FAULT); } //Load the firmware image and program the device printf("Loading firmware image...\n"); FirmwareImage* img = pdev->LoadFirmwareImage(bitfile); printf("Programming device...\n"); pdev->Program(img); printf("Configuration successful\n"); delete img;
This is part of the test case for my gigabit Ethernet MAC, allocating a page of memory on the device under test by talking to the RAM controller at NoC address "raddr" via the RPCNetworkInterface "iface". (Details on how this is implemented will be coming in a few posts.)
printf("Allocating memory...\n"); iface.RPCFunctionCall(raddr, RAM_ALLOCATE, 0, 0, 0, rxm); uint32_t txptr = rxm.data[1]; printf(" Transmit buffer is at 0x%08x\n", txptr);
There's a lot more to the system than this but I'll save the rest for my next post :)
The BSD license is compatible with the GNU GPL.
ReplyDeleteIt's compatible, but once you link a BSD'd project with a GPL'd project the result is covered by GPL, which is not acceptable to me. I need the final binaries to be BSD so that it will be possible for third parties to use them in both open and closed source projects.
ReplyDeleteThank you for your post. This is excellent information.
ReplyDeleteJTAG