JTAG Debugging
Update 2008/01/14: Some progress in supporting multiple devicesUpdate 2008/01/12: First succes with openocd added
Posted on 2008/01/12 - 19:46
Well, it sure has been one hell of an exciting week. Soldering the first prototype together, getting rid of all solder shortcuts, making absolutely sure that it wouldn't go up in smoke, and then apply some power. It started up without a hitch and I got so excited that I tossed a single image on the frontpage, and continued working on the card instead of the website. Hope you'll pardon me, but four months 'in' the project and after countless hours seeing it come to life is amazing.
So the next step was obviously to get software figured out, installed, and running so I can actually start working on the HDL which needs to be flashed into the card. That turned out to be a bigger fight than I thought. First of all, I started up FTDIs tool called MPROG to flash some data into the eeprom of the ftdi chip to let it act as an Amontec JTAGkey. Turned out that figuring out what settings that where exactly took a while, but the end result was that the Amontec Demo tool could toggle JTAG commands on the bus. That implicitly also meant that the JTAG bus was actually working, so this was the first 'unofficial' confirmation that at least the PROM, the FPGA and the CPLD were working. After reading into how JTAG really worked on bitlevel (I somewhat hoped to avoid that, but found some good instructions in this document) I got the following data:
DR TDO: 0x5f046093 0141c093 49608093
That's three IDCODEs from the chips, albeit in a slightly mangled form (the first byte really reads 0xf5). The next step obviously was to try and do some more advanced stuff, so I prepared an SVF file with Xilinx iMPACT which would then be parsed by the Amontec svfplayer. However, it unfortunately turns out that my programmer differs too much from their original and the application crashed when trying to initialise. Too bad, we did some debugging but it seemed that we had to go for plan B after all, which is using openocd.
The problem with openocd is that it doesn't want to compile natively on windows. So after a lot of searching, asking for help on forums, and figuring out annoying error messages I got it to compile in cygwin. But oddly enough it still didn't want to connect with the ftdi drivers, so I ended up using the precompiled version from yagarto. For documentation purposes, here are some of the important bits of the configuration file;
interface ft2232 reset_config none #jtag scan chain #format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE) jtag_device 8 0x01 0x007 0xfe # xcf04s jtag_device 6 0x01 0x003 0x09 # xc3s400 jtag_device 8 0x01 0x0e3 0xfe # xc95144xl
The interface is by use of an ft2232 (other details are filled in as well, but not interesting at the moment - see any other configuration file for those) but one without dedicated reset lines. I couldn't find confirmation that this is the proper way to indicate that, but it seems to work ok. Then, there are three jtag devices with their details which I grabbed from the BSDL files describing them. If I run openocd with this config it seems to be able to get all IDCODEs out of the devices correctly, but I'm not certain if it's using the configuration for that. It could be that it's using a 'trick' I used as well when doing it manually.
So anyway, openocd seems to be unable to parse standard svf files, but only accepts xsvf. xilinx has a little tool to translate from svf to xsvf (when exporting directly from iMPACT to xsvf it's using this as well) but it gives some very odd results. I'm not sure if it's the fault of openocd or xilinx, but when executed it gives errors like;
Warning: jtag.c:647 jtag_add_dr_scan(): scan data for a device in BYPASS Warning: jtag.c:1132 jtag_read_buffer(): value captured during scan didn't pass the requested check: captured: 0x0349608093 check_value: 0x03d411824c check_mask: 0x003ffffffc
I have absolutely no idea where that 0x03d411824c is coming from, but it doesn't make much sense. The captured value seems to be 0x03 with the first IDCODE (or last, depending on how you look at it - the one from the CPLD) attached to it. The other warning about reading from a device in BYPASS have I only seen once but doesn't sound too healthy either. So that's where we stand at the moment. If anybody has an idea as to how to get generated svf files into the xcf04s prom and the cpld or why this xsvf isn't working, please let me know. An other option would be to try and get xc3sprog working on a linux machine but that would require me setting up a completely new linux machine just for testing this tool, so I'm considering it a last resort.
Update 12 Jan:
I couldn't resist and continued fighting a bit while I should've gone to bed (I've got to work tomorrow morning)
but sometimes you just have an idea, and you have to try it out now. And it turns out I'm partially right.
Reinder decrypted the xsvf file and noticed that the numbers contained in it where shifted by a few bits, depending
on how far the device was in the chain. That made me thinking along the lines of; iMPACT knows what devices are in
the chain so it can compensate for it in the TDO checks, without wasting extra clock cycles, and openocd knows
how many devices are in the chain so will execute the commands in the xsvf file, making sure that everything
aligns. Which causes the TDO checks to be compensated twice. Which screws up things.
So what I did was make a chain in iMPACT with only the device I want to check (the CPLD, being the last in the chain, the device in question) and executing a command on it. Then, exporting it to xsvf and finally executing it in openocd. Et voila! The command was executed correctly, although some warnings still showed up.
Client: > xsvf 0 xsvftest2.xsvf XSVF file programmed successfully Server: (a few times) Warning: jtag.c:647 jtag_add_dr_scan(): scan data for a device in BYPASS
So that works. Brilliant. I can start hacking for the CPLD and if it turns out that all xsvf commands used by iMPACT are supported by openocd (which they are as far as I know) and can get the firmware flashed into the actual CPLD. If, however, I try to do it for the other devices (that being the fpga and prom) I'm still getting some weird data. I think it has something to do with the BYPASS warning, but I'll look at it tomorrow evening or something. I've been told that xcf proms are proprietary death traps, so we'll see how much hacking it'll require.
Update 14 Jan:
We're getting somewhere. After an upgrade to the latest version of Xilinx Webpack the "scan data for a device in
BYPASS" disappeared so that's one down, couple to go. When doing some more advanced things, I kept getting this
little bugger;
Error: ft2232.c:477 ft2232_add_pathmove(): BUG: rti -> tlr isn't a valid TAP transition
After some fighting, I got openocd compiling correctly. The trick is to use the 'make' command that actually comes with cygwin, not the one from whatever tool that's installed on my computer as well, causing me to think I'm using the correct make when in fact I'm not. D'oh. Right now I'm compiling it with;
./configure --enable-parport --enable-ft2232-ftd2xx --enable-amtjtagaccel -with-ftd2xx=/cygdrive/c/CDM/
Be careful with that last directory listing. The latest drivers from ftdi come with an amd64 and i386 folder, so make sure you copy the library from the correct folder into the folder below it, and give that folder to configure since that folder also holds some other files that you'll need later when compiling (an header file in particular).
But anyway, back to that transition error. xapp503 reads at the bottom of page 21 that "If the state is 0x00 (Test-Logic-Reset), then force the TAP to the Test-Logic-Reset state via the guaranteed TAP reset sequence: hold TMS High and apply a minimum of five TCK cycles. For non-zero state values, if the TAP is already in the specified state, then do nothing. Otherwise, transition the TAP to the next specified state." In other words, it warns us that it'll give odd XSTATE commands, and openocd starts throwing up when it sees them. I took the liberty of trying to fix it since I'm considering it a bug, and changed line 473 of ft2232.c to;
else if (tap_transitions[cur_state].high == cmd->path[state_count] || !cmd->path[state_count]) buf_set_u32(&tms_byte, bit_count++, 1, 0x1);
I added the second condition, since cmd->path[state_count] is 0 when we're supposed to go to TLR. When that happens, output a at least a clock with tms high, until we've resetted stuff. I'm not sure if this is completely correct but at the moment things seem to work;
> xsvf plain test3.xsvf XSVF file programmed successfully
That leaves a couple of other issues, like the fact that I still can't get any valid data in or out of the xcf except when it's not supposed to give any data. Reinder suspects that the other devices aren't being properly put in BYPASS, we'll have to look at it. Also some more complex statements seem to screw up openocd so we've still got some work to do before we can start flashing HDL stuff into it.
[: wacco :]