JTAG XSVF ParserUpdate 2008/01/31: Successfully flashed CPLD with test code
Update 2008/01/30: Couple of bug fixes
Posted on 2008/01/26 - 23:53
Let me start of by apologizing for the nearly two weeks of no updates. The kerneltrap interview generated a lot of new traffic (Hi!) but the timing wasn't so great, it's the end of the school semester meaning I've been studying like crazy for the last two weeks. A few exams, finishing up a bunch of applications and writing up a paper on network management in Ad-hoc environment. Fun subject if you have the time for it (if you're interested btw, grab it here) which unfortunately was absolutely not the case. But anyway I believe I've survived most of it and managed to hack together some stuff for project vga in the progress.
I've talked about the problems with open OCD getting to recognize my programmer correctly before and noted that it had some issues regarding parsing and playing XSVF files correctly. I was about to get into some serious retooling of open OCD when one of the developers said to another on the mailing list;
Also, taking into account the main purpose of OpenOCD (ARM debugging), if statemove works with ARM cores, then everything is just fine.
I might be taking things a little out of context here but it's what motivated me to develop a custom XSVF parser for project vga. Since I'm using a standard FT2232D chip it should also work without too much effort on other programmers using this chip, which means Amontec JTAGkey programmers and the like. Right now though it's identifying the programmer by its location id, a specific string which is written in the EEPROM of the FTDI. This can be easily changed however. Because I had to understand what was going on in the first place I read up about JTAG and the FTDI commands to control the MPSSE controller. Note that I'm not using the JTAG libraries provided by FTDI but sending raw commands directly.
You can grab an early copy of the XSVF Parser here which should compile under cygwin on little endian machines. I haven't done any testing on anything else but windows yet, however I've been told that with the proper drivers and commenting the inclusion of the windows.h header it compiles on linux and after some slight changes it talks to an Amontec programmer as predicted. If you want to compile it get the latest FTDI drivers and libraries here (it's the closed source once, basically because they're quite a bit faster than the open source one I've been told - it shouldn't be too hard to support the open source one as well) and extract those files in the folder with the xsvfparser. Actual command line details are explained in the source file.
It isn't quite done yet since my main problem at the moment is getting the runtest to work properly. The documentation has a few things to say about runtest;
Defines the amount of time (in microseconds) the device should sit in the Run-Test/Idle state after each visit to the SDR state when the current XENDDR state is IDLE (see the XENDDR command below). The initial XRUNTEST time is zero microseconds. Note: For XSVF containing XRUNTEST commands applied to Xilinx FPGAs, the time parameter must be interpreted as the minimum number of TCK pulses issued within the Run-Test/Idle state after each visit to the SDR state.
Ok, fair enough, but the idea was that the parser didn't have to know about whatever was going on in the file or JTAG chain and that the XSVF contained all details. There's no way of knowing if we're supposed to clock or not. And if we assume all commands require clocking, will it cause problems on the CPLD? Both an FPGA and a CPLD are in the chain, so we have to find some middle ground. Obviously, since we're actually flashing data into the CPLD I favor not clocking since all commands I care about (that is, flashing data) are supposed to be for the CPLD. However, what am I supposed to do with the XCF? But wait, it gets even better, what does it say in the details regarding SDR commands?
If the TDO value does not match TDOExpected, perform the exception-handling sequence described in the XC9500 programming algorithm section. [...] If the last XRUNTEST time is zero, then go to XENDDR state. Otherwise, go to the Run_Test/Idle state and wait for the XRUNTEST time.
What exactly is this exception-handling sequence? I haven't found a clear description of it anywhere. Great. Also, the CPLD will obviously perform some kind of action during the period we're waiting, but we've already clocked out the data at this point. So in this scenario the TDO value will pretty much always not match what we're looking for the first time, which makes the exception-handling sequence even more important. Oh, and bonus points for the people who spot the contradiction. Is there a situation where we have to wait for the runtest time according to one description and not go to it according to the other? (hint: YES. And in that case, which state should we go to or stay in? I haven't got a clue)
So that's about it for where we are at this point. It can already execute correctly some easy files like fetching all device IDs which is more than openOCD could accomplish and gets pretty far with the somewhat more complex ones, but fails at properly implementing the runtest. In less than 3 weeks I'm having an audit about the project at my university so far, and the idea is to get at least something flashed into the devices by then. The week after that I'll be most likely presenting the prototype with some background info at FOSDEM in Brussels in the X.org devRoom. If you feel like dropping by, see you then!
Update 30 Jan:
I found out about xapp058 for which is also some example code available but alas, it only confuses more on certain points. I still haven't figured out what the exact byte (and bit) order is in the XSVF files and everybody seems to just do something. The example code helps though. I do think I'm getting close;
tdoMask: 0x000003 tdoCache: 0x000008 tdoMatch: 0x000001
It looks like I'm just a few bits off, however, figuring out where the problem exists in the code is proving to be quite a challenge. Xapp058 has a few nice diagrams explaining the earlier runtest problem, but also introduces a new one; the first thing it does in Step 3 of Figure 9 (page 13) is shift out a single bit of data, without sampling TDO. I'm almost certain that this must be wrong; if I'd do that, the code would already fail when checking the device ID earlier. Also, the examples in xapp503 contradict this too. It's still suspicious though.
I uploaded the latest version of the parser (saved it over the old one, you can get it here) and it's a bit of a mess at this point due to all the debugging statements, so sorry about that. You can find the output here, when executing this xsvf which is supposed to do a blank check of the CPLD. A final note; I limited the number of xrepeats because it got annoying to see the same error 32 times. I periodically check if it might help to do it 32 times but so far it didn't matter at all.
Oh, and before I forget; xapp058 defines the XC9500 exception procedure so I implemented that as well. So far though it didn't really help mostly because maybe I'm still shifting in incorrect data somewhere somehow. I suspect this problem only showed up by now because this is the first statement where the data shifted in has different remaining bits from the first (or last) bytes that have to be shifted in. Or something like that. I'll keep on trying stuff out. I'm suspecting that the '8' I'm seeing is in fact my own bit I shifted in - meaning the CPLD is in bypass and not doing what it's supposed to do. Then again, maybe it's meant to be in bypass but should give a bit back as well, making the output '9'. That would fit the mask and explain some of the behaviour I saw when I was definitely shifting out incorrect bits. But it wouldn't explain why I'm shifting out that 1 bit in the first place. Argh.
Second update today
Found the culprit, I flushed the buffer when it was full, intended for when data was going to the Instructions Register and the buffer size wasn't set yet (thus the default) it would flush and continue. There was an off-by-one in there however causing it to flush the data early sometimes which under certain circumstances caused errors. Really odd, but should do the trick now. This also means the code is probably bug-free enough to start programming the CPLD with actual code! I'll continue tonight however with further testing and trying to get it to work for the XCF as well, which needs some other things (like tck clocking in runtest) and seems to fail after the first bank is tested. No idea yet why. See the error report here.
Update 31 Jan:
With some little effort getting familiar with ISE Webpack I wrote a little timer which counts up to some insanely large number on every clock, which should result in a nice blinking LED roughly once a second. Turned out the connection for the second LED connected to the CPLD is broken, something easily fixed if you have a soldering station handy. Which I don't have right now. So two-led-magic will have to wait. The code used is here, the mapping of the pins is here, and the reasons all PCI pins are already defined is because I've also been playing with Ben Jackson's code but that part isn't working yet. Now, without further ado;
A little test app flashed in the CPLD
Exciting, isn't it? Unfortunately the system is unwilling to boot up with the card plugged in, I suspect it's because I'm not giving it some proper data when it's trying to initialise the card. The reason is that I've done some lengthy checking for shortcuts which might've been caused due to soldering the components on the board but couldn't find any. Haven't verified yet if all CPLD pins are actually connected to the wires, that might cause some corrupt data or something. But at least it should start the system up without using and registering my card, but it refuses. So sorting that out, as well as trying to get the XCF PROM programmed properly (still failing for reasons unknown - probably still a few bugs in the code) will keep me busy for the next days or so. On a final note, this is how the chain looks like in iMPACT, just to show you that I don't have to worry anywhere which device is being programmed or how my chain looks like (contrary to openOCD) because iMPACT takes care of those details;
The device chain in iMPACT
[: wacco :]