Extending Jtagulator Code with SVF Player? - in progress
cheezus
Posts: 298
in Propeller 1
I finally had a chance to play with the codebase and it's very nice! I plugged in a board and it identified it and spit out a bunch of useful info. Now what I'd LIKE to do is load a SVF or xsvf from SD card and program to the target device. Seems pretty simple, but then again so am I most of the time.
The output from Jtagulator looks like this
Other programmers seem to prefer the xsvf files but I can generate either for my target very easily. Since I can open SVF files in notepad ++ I'm thinking this will be the easier way to go. Looking further into a file we get an initialization, followed by checking for read / write protect.
The next part is where I get lost, I think it's bypassing any other devices in the chain?
Now the next part is pretty obvious, the bitstream itself. I won't post the long, repeating garbage just a sampling.
And then this init / bypass sequence again.
Then it verifies the image, I guess
Again, just a small sample of the actual bitstream. Which ends with some housekeeping.
PropJTAG has these methods, should cover it. It's just a matter of learning how to parse the svf file.
I know any assumptions i make are going to come back to bite me in the end. If I really get lucky, it might support something other than the target chip. At some point, at some time. This seems like a fun project but with how cheap jtag programmers can be had I'm not going to stress on it. :cool:
The output from Jtagulator looks like this
▒ UU LLL JJJ TTTTTTT AAAAA GGGGGGGGGGG UUUU LLL AAAAA TTTTTTTT OOOOOOO RRRRRRRRR JJJJ TTTTTTT AAAAAA GGGGGGG UUUU LLL AAAAAA TTTTTTTT OOOOOOO RRRRRRRR JJJJ TTTT AAAAAAA GGG UUU UUUU LLL AAA AAA TTT OOOO OOO RRR RRR JJJJ TTTT AAA AAA GGG GGG UUUU UUUU LLL AAA AAA TTT OOO OOO RRRRRRR JJJJ TTTT AAA AA GGGGGGGGG UUUUUUUU LLLLLLLL AAAA TTT OOOOOOOOO RRR RRR JJJ TTTT AAA AA GGGGGGGGG UUUUUUUU LLLLLLLLL AAA TTT OOOOOOOOO RRR RRR JJJ TT GGG AAA RR RRR JJJ GG AA RRR JJJ G A RR Welcome to JTAGulator. Press 'H' for available commands. Warning: Use of this tool may affect target system behavior! JTAG> v Current target I/O voltage: Undefined Enter new target I/O voltage (1.2 - 3.3, 0 for off): 3.3 New target I/O voltage set: 3.3 Ensure VADJ is NOT connected to target! JTAG> i Enter starting channel [0]: 0 Enter ending channel [8]: 8 Possible permutations: 504 Bring channels LOW between each permutation? [Y/n]: y Enter length of time for channels to remain LOW (in ms, 1 - 1000) [100]: Enter length of time after channels return HIGH before proceeding (in ms, 1 - 1000) [100]: Press spacebar to begin (any other key to abort)... JTAGulating! Press any key to abort... -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- TDI: N/A TDO: 6 TCK: 4 TMS: 5 Device ID #1: 0000 0110111001011100 00001001001 1 (0x06E5C093) ---------------------------------------------------------------------------------------------------------------------------------------- IDCODE scan complete. JTAG> d TDI not needed to retrieve Device ID. Enter TDO pin [6]: Enter TCK pin [4]: Enter TMS pin [5]: Device ID #1: 0000 0110111001011100 00001001001 1 (0x06E5C093) -> Manufacturer ID: 0x049 -> Part Number: 0x6E5C -> Version: 0x0 IDCODE listing complete. JTAG> y Enter TDI pin [0]: 7 Enter TDO pin [6]: Enter TCK pin [4]: Enter TMS pin [5]: Ignore single-bit Data Registers? [Y/n]: y Instruction Register (IR) length: 8 Possible instructions: 256 Press spacebar to begin (any other key to abort)... JTAGulating! Press any key to abort... IR: 00000000 (0x00) -> DR: 192 IR: 00000001 (0x01) -> DR: 32 IR: 00000010 (0x02) -> DR: 192 IR: 00000011 (0x03) -> DR: 192 - IR: 00010001 (0x11) -> DR: 281 IR: 00010010 (0x12) -> DR: 281 IR: 00010011 (0x13) -> DR: 281 IR: 00010100 (0x14) -> DR: 281 IR: 00010101 (0x15) -> DR: 281 IR: 00010110 (0x16) -> DR: 192 ------ IR: 11000000 (0xC0) -> DR: 281 -- IR: 11100100 (0xE4) -> DR: 281 - IR: 11100110 (0xE6) -> DR: 281 IR: 11100111 (0xE7) -> DR: 281 IR: 11101000 (0xE8) -> DR: 281 IR: 11101001 (0xE9) -> DR: 281 IR: 11101010 (0xEA) -> DR: 281 - IR: 11101101 (0xED) -> DR: 281 IR: 11101110 (0xEE) -> DR: 281 - IR: 11110000 (0xF0) -> DR: 281 - IR: 11111101 (0xFD) -> DR: 32 IR/DR discovery complete.
Other programmers seem to prefer the xsvf files but I can generate either for my target very easily. Since I can open SVF files in notepad ++ I'm thinking this will be the easier way to go. Looking further into a file we get an initialization, followed by checking for read / write protect.
TRST OFF; ENDIR IDLE; ENDDR IDLE; STATE RESET; STATE IDLE; FREQUENCY 1E6 HZ; //Operation: Program -p 0 -e -v TIR 0 ; HIR 0 ; TDR 0 ; HDR 0 ; TIR 0 ; HIR 0 ; HDR 0 ; TDR 0 ; //Loading device with 'idcode' instruction. SIR 8 TDI (01) SMASK (ff) ; SDR 32 TDI (00000000) SMASK (ffffffff) TDO (f6e5f093) MASK (0fff8fff) ; //Check for Read/Write Protect. SIR 8 TDI (ff) TDO (01) MASK (03) ; //Boundary Scan Chain Contents //Position 1: xc2c64a TIR 0 ; HIR 0 ; TDR 0 ; HDR 0 ; TIR 0 ; HIR 0 ; TDR 0 ; HDR 0 ; TIR 0 ; HIR 0 ; HDR 0 ; TDR 0 ; //Loading device with 'idcode' instruction. SIR 8 TDI (01) ; SDR 32 TDI (00000000) TDO (f6e5f093) ; //Check for Read/Write Protect. SIR 8 TDI (ff) TDO (01) MASK (03) ; TIR 0 ; HIR 0 ; HDR 0 ; TDR 0 ;
The next part is where I get lost, I think it's bypassing any other devices in the chain?
// Loading devices with 'enable' or 'bypass' instruction. SIR 8 TDI (e8) ; // Loading devices with 'erase' or 'bypass' instruction. ENDIR IRPAUSE; SIR 8 TDI (ed) SMASK (ff) ; ENDIR IDLE; STATE IREXIT2 IRUPDATE DRSELECT DRCAPTURE DREXIT1 DRPAUSE; RUNTEST DRPAUSE 20 TCK; STATE IDLE; RUNTEST IDLE 100000 TCK; STATE DRPAUSE; RUNTEST DRPAUSE 5000 TCK; RUNTEST IDLE 1 TCK; // Loading devices with 'init' or 'bypass' instruction. ENDIR IRPAUSE; SIR 8 TDI (f0) SMASK (ff) ; STATE IDLE; RUNTEST IDLE 20 TCK; // Loading devices with 'init' or 'bypass' instruction. ENDIR IRPAUSE; SIR 8 TDI (f0) SMASK (ff) ; STATE IREXIT2 IRUPDATE DRSELECT DRCAPTURE DREXIT1 DRUPDATE IDLE; RUNTEST 800 TCK; ENDIR IDLE; // Loading devices with 'conld' or 'bypass' instruction. SIR 8 TDI (c0) ; RUNTEST 100 TCK; // Loading devices with 'conld' or 'bypass' instruction. SIR 8 TDI (c0) ; RUNTEST 100 TCK; // Loading devices with 'enable' or 'bypass' instruction. SIR 8 TDI (e8) ;
Now the next part is pretty obvious, the bitstream itself. I won't post the long, repeating garbage just a sampling.
// Programming. // Loading devices with 'program' instruction. ENDIR IRPAUSE; SIR 8 TDI (ea) ; SDR 281 TDI (0003deab2aaaabffffffffefbeffffffffebfe7d7ffffffffffffffffffffffb7efefa0f) SMASK (01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; ENDIR IDLE; RUNTEST 10000 TCK; SDR 281 TDI (0102417dfdf7dffffffffffffffffffffffffe7e1fffffffffffffffffffffefbefefa7d) ; RUNTEST 10000 TCK; SDR 281 TDI (0182f97dfdf7dffffffffffffffffffffffffe7e1fffffffffffffffffffffefbefefb81) ; RUNTEST 10000 TCK; SDR 281 TDI (0083df7dfdf7dffffffffffffffffffffffffe7e1fffffffffffffffffffffefbefefa0f) ; RUNTEST 10000 TCK; SDR 281 TDI (00c241fffffffffffffffff7bffffffffffffe3e5fffffffffffffffffffffffffffce7d) ; RUNTEST 10000 TCK; SDR 281 TDI (01c2f97dfdf7dffffffffffffffffffffffdf67ebffffffffffffffffffffffffffbff81) ; RUNTEST 10000 TCK; SDR 281 TDI (0143df7dfedffffffffffffffffffffffffffe6e5fffffffffffffffffffffefbefefa0f) ; RUNTEST 10000 TCK; SDR 281 TDI (004241ffffffffffffffffffffffffffffffff7f5fffffffffffffffffffffefbefefa7d) ; RUNTEST 10000 TCK; SDR 281 TDI (0062f97dfdf7dffffffffffffffffffffffffe7e79ffffffffffffffffffffefbefefb01) ; RUNTEST 10000 TCK; SDR 281 TDI (0163df7dfdf7dffffffffffffffffffffffffe7e79ffffffffffffffffffffefbefefa0f) ; RUNTEST 10000 TCK; SDR 281 TDI (01e2417dfdf7dffffffffffffffffffffffffe7e1fffffffffffffffffffffefbefefa7d) ; RUNTEST 10000 TCK; SDR 281 TDI (00e2f97dfdf7edfffffffffffffffffffffffe667fffffffffffffffffffffefbefefb01) ; RUNTEST 10000 TCK; SDR 281 TDI (00a3df2dacb2cbfffffffff7defffffffffffe1e7ffffffffbefbfffefedb34d34d6d20f) ;
And then this init / bypass sequence again.
// Programming. // Loading devices with 'program' instruction. ENDIR IRPAUSE; SIR 8 TDI (ea) ; SDR 281 TDI (0003deab2aaaabffffffffefbeffffffffebfe7d7ffffffffffffffffffffffb7efefa0f) SMASK (01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; ENDIR IDLE; RUNTEST 10000 TCK; SDR 281 TDI (0102417dfdf7dffffffffffffffffffffffffe7e1fffffffffffffffffffffefbefefa7d) ; RUNTEST 10000 TCK; SDR 281 TDI (0182f97dfdf7dffffffffffffffffffffffffe7e1fffffffffffffffffffffefbefefb81) ; RUNTEST 10000 TCK; SDR 281 TDI (0083df7dfdf7dffffffffffffffffffffffffe7e1fffffffffffffffffffffefbefefa0f) ; RUNTEST 10000 TCK; SDR 281 TDI (00c241fffffffffffffffff7bffffffffffffe3e5fffffffffffffffffffffffffffce7d) ; RUNTEST 10000 TCK; SDR 281 TDI (01c2f97dfdf7dffffffffffffffffffffffdf67ebffffffffffffffffffffffffffbff81) ; RUNTEST 10000 TCK; SDR 281 TDI (0143df7dfedffffffffffffffffffffffffffe6e5fffffffffffffffffffffefbefefa0f) ; RUNTEST 10000 TCK; SDR 281 TDI (004241ffffffffffffffffffffffffffffffff7f5fffffffffffffffffffffefbefefa7d) ; RUNTEST 10000 TCK; SDR 281 TDI (0062f97dfdf7dffffffffffffffffffffffffe7e79ffffffffffffffffffffefbefefb01) ; RUNTEST 10000 TCK; SDR 281 TDI (0163df7dfdf7dffffffffffffffffffffffffe7e79ffffffffffffffffffffefbefefa0f) ; RUNTEST 10000 TCK; SDR 281 TDI (01e2417dfdf7dffffffffffffffffffffffffe7e1fffffffffffffffffffffefbefefa7d) ; RUNTEST 10000 TCK; SDR 281 TDI (00e2f97dfdf7edfffffffffffffffffffffffe667fffffffffffffffffffffefbefefb01) ; RUNTEST 10000 TCK; SDR 281 TDI (00a3df2dacb2cbfffffffff7defffffffffffe1e7ffffffffbefbfffefedb34d34d6d20f) ;
Then it verifies the image, I guess
// Verification. // Loading device with a 'verify' instruction. ENDIR IRPAUSE; SIR 8 TDI (ee) ; ENDDR DRPAUSE; SDR 7 TDI (00) SMASK (7f) ; ENDIR IDLE; RUNTEST DRPAUSE 20 TCK; ENDDR IDLE; RUNTEST IDLE 100 TCK; SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03deab2aaaabffffffffefbeffffffffebfe7d7ffffffffffffffffffffffb7efefa0f) MASK ( 03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; RUNTEST 100 TCK; ENDDR DRPAUSE; SDR 7 TDI (40) SMASK (7f) ; RUNTEST DRPAUSE 20 TCK; ENDDR IDLE; RUNTEST IDLE 100 TCK; SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (02417dfdf7dffffffffffffffffffffffffe7e1fffffffffffffffffffffefbefefa7d) MASK ( 03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; RUNTEST 100 TCK; ENDDR DRPAUSE; SDR 7 TDI (60) SMASK (7f) ; RUNTEST DRPAUSE 20 TCK; ENDDR IDLE; RUNTEST IDLE 100 TCK; SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (02f97dfdf7dffffffffffffffffffffffffe7e1fffffffffffffffffffffefbefefb81) MASK ( 03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; RUNTEST 100 TCK; ENDDR DRPAUSE; SDR 7 TDI (20) SMASK (7f) ; RUNTEST DRPAUSE 20 TCK; ENDDR IDLE; RUNTEST IDLE 100 TCK; SDR 274 TDI (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) TDO (03df7dfdf7dffffffffffffffffffffffffe7e1fffffffffffffffffffffefbefefa0f) MASK ( 03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; RUNTEST 100 TCK;
Again, just a small sample of the actual bitstream. Which ends with some housekeeping.
//Loading device with 'conld' instruction. SIR 8 TDI (c0) ; RUNTEST IDLE 100 TCK; //Loading device with 'enable' instruction. SIR 8 TDI (e8) ; // Setting Done bit ... // Loading device with a 'program' instruction. ENDIR IRPAUSE; SIR 8 TDI (ea) ; SDR 281 TDI (0017fdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) SMASK (01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) ; ENDIR IDLE; RUNTEST 10000 TCK; SIR 8 TDI (f0) SMASK (ff) ; STATE IDLE; RUNTEST IDLE 20 TCK; ENDIR IRPAUSE; SIR 8 TDI (f0) SMASK (ff) ; STATE IREXIT2 IRUPDATE DRSELECT DRCAPTURE DREXIT1 DRUPDATE IDLE; RUNTEST 800 TCK; ENDIR IDLE; //Loading device with 'conld' instruction. SIR 8 TDI (c0) ; RUNTEST IDLE 100 TCK; //Loading device with 'idcode' instruction. SIR 8 TDI (01) ; SDR 32 TDI (00000000) SMASK (ffffffff) TDO (f6e5f093) MASK (0fff8fff) ; //Check for Done bit. SIR 8 TDI (ff) TDO (05) MASK (07) ; TIR 0 ; HIR 0 ; HDR 0 ; TDR 0 ; TIR 0 ; HIR 0 ; HDR 0 ; TDR 0 ; TIR 0 ; HIR 0 ; TDR 0 ; HDR 0 ; SIR 8 TDI (ff) ; SDR 1 TDI (00) SMASK (01) ;
PropJTAG has these methods, should cover it. It's just a matter of learning how to parse the svf file.
PUB Config(tdi_pin, tdo_pin, tck_pin, tms_pin, tck_speed) PUB Detect_Devices : num PUB Detect_IR_Length : num PUB Detect_DR_Length(value) : num PUB Bypass_Test(num, bPattern) : value PUB Get_Device_IDs(num, idptr) PUB Send_Instruction(instruction, num_bits) : ret_value PUB Send_Data(data, num_bits) : ret_value PUB Restore_Idle
I know any assumptions i make are going to come back to bite me in the end. If I really get lucky, it might support something other than the target chip. At some point, at some time. This seems like a fun project but with how cheap jtag programmers can be had I'm not going to stress on it. :cool:
Comments
The code is pretty ugly right now and it's not flexible at all. But it's a start!
*edit -
I spent some time getting the multi-line source working as well as better handling of comments. I'm updating the code below to reflect the improvements. I think reading from card and filling a command buffer with a valid command is working right so now it's just figuring out how to parse the command!
And I'm pretty much stuck here trying to figure out how to move through the TAP states properly. I guess it's a bit more complicated than I thought it was and all the code I've found handling this is C++ which I don't understand at all
I think that using a case statement to load a bit pattern for TMS and number of clocks would be much better but I tried to do this first and only succeeded at confusing myself.
This is what's added to the Jtagulator Main object.
The section that parses the command buffer works okay I guess.
This mess of code handles the STATE command, and while it seems to work... it's UGLY.
I think I have the right idea creating a table, there's just gotta be a better way to use them. Right now it's brute force using compare current and new state, ugly like I said. I think it should work though, or at least I hope.
I do have a bug I can't find with debugging the state change but it only seems to show up on unsupported modes. I can cause it by removing the Send_Instruction or Send_Data call which changes from the current state to the IR or DR PAUSE state. IR PAUSE to DR PAUSE or the other way around. I'm not going to spend too much time chasing this one, just make a note for now in case I stumble across it later. Sometimes the hardest part of programming is deciding how to handle bad input
I'm implementing just enough to program the coolrunner ii devices I use right now and they seem pretty simple. It's been a real interesting exercise trying to implement and hopefully someone else will find it useful when I'm done. Things are shaping up pretty nicely and while they could be improved (a lot)… lipstick on a pig at this point.
I am kinda stuck on the last problem to solve, or at least I hope it's the last major problem. The built in send/receive can handle up to 32 bit transmissions, but I need to send almost 300 bits!! I've worked it out to fit in 9 longs, data in, data out and mask (I'm ignoring SMASK, I figure I'm ignoring enough other stuff right now couldn't hurt to ignore one more thing). This is a total of 27 longs! Okay, shouldn't be TOO scary right? I guess where I'm getting confused is they're kinda oddball numbers, 274 bits and 281. I'll probably just end up brute forcing this like the rest.
I'm going to put this here in case I break things again
That's common, you just define a bit-counter and decide some convention of which end you unpack from.
Attached is a simple test SVF file for an Atmel CPLD, which has a length of 326, if you are interested in other vendor test cases.
The problem is I'm over/under thinking the ASCII characters vs pure bits and shifting data out LSB and in MSB. I guess knowing a max number of bits to support would be a good idea. I know what my test case is but I'll have to do some research as what's a the best place to start.
Here's the existing code for handling the actual shift:
The one place where this code will break is with a buffer over-run with greater lengths. It generates an error message to the terminal but keeps going. Right now from thinking about it 326 bits would break the 9 long bitfield code I was working on. Making it variable bitlength would be nice but I'm at a loss right now.
Another thing that would be nice to have are some switches to "turn off" output functions, and turn on debugging code, just to test parsing the file. Maybe I can add that if I get everything else working.
This is going to be painfully slow, once it does work. I've got some ideas to improve performance but I think one big performance hit comes from parsing an ascii file. XSVF would be way more efficient. The other one is a result of doing all the pin control in spin. I think there's a few ways to go about generating an asm engine without handwriting code. It would be a really neat display of the multi-core capability to assign a cog one portion of the task of programming and handle it all inline, in parallel.
I've saved that AMTEL bitstream, i'll see if it parses and what it generates. Thanks for that. Will be nice to see if it can handle other vendors once working. I thought I was going to give up working on the state control code but I made it through. The amtel file will probably break that too by manually cycling through the ir register state.
The 4 supported commands are decoded in this block. I keep telling myself there's a way to handle the string compare with a list. These work great with the parsing code above.
The next part is for SIR (Instruction register, always 8 bits) and although not tested it should work. But this ugliness just gets uglier when trying to handle the large data. I'm going to try to get through this but the $15 board from china is looking more attractive by the minute. The whole idea of waiting till April is the only thing stopping me at this point.
I tried getting some captures of the wire last time I hooked up my PC-III programmer. Something wasn't right and although I was able to identify the CPLD, it didn't pass the programming stage. I didn't realize I was going to have this hard of a time. Should probably have looked at XSVF instead!
Any sage advice greatly appreciated!