2 # PIC client (currently only supports dsPIC33F/PIC24H.)
4 # Note that a verify operation only considers addresses specified in
5 # the given Intel hex file ($foo.hex).
7 # sixfile expects a plain text file, one instruction per line.
10 # Scott Livingston <slivingston at caltech.edu>
18 from GoodFET import GoodFET
19 from intelhex import IntelHex
22 # Some constants (not really immutable...)
27 dev_table = { 0x00EE : "dsPIC33FJ128GP708",
28 0x00EF : "dsPIC33FJ128GP710",
29 0x080A : "PIC24HJ12GP201",
30 0x080B : "PIC24HJ12GP202",
31 0x0444 : "PIC24FJ16GA002",
32 0x044C : "PIC24FJ16GA004",
33 0x0445 : "PIC24FJ32GA002",
34 0x044D : "PIC24FJ32GA004",
35 0x0446 : "PIC24FJ48GA002",
36 0x044E : "PIC24FJ48GA004",
37 0x0447 : "PIC24FJ64GA002",
38 0x044F : "PIC24FJ64GA004",
39 0x0405 : "PIC24FJ64GA006",
40 0x0408 : "PIC24FJ64GA008",
41 0x040B : "PIC24FJ64GA010",
42 0x0406 : "PIC24FJ96GA006",
43 0x0409 : "PIC24FJ96GA008",
44 0x040C : "PIC24FJ96GA010",
45 0x0407 : "PIC24FJ128GA006",
46 0x040A : "PIC24FJ128GA008",
47 0x040D : "PIC24FJ128GA010" }
48 cfg_table = { 0xF80000 : "FBS",
60 "width" : 7 } # For pretty printing.
62 #cfg_bitmask_table = {
69 def runlist( cmd_li ):
70 """Load (and execute) a given list of instructions.
71 Assumes ICSP session already started."""
72 cmd_byte_li = build_instr_stream( cmd_li )
73 data = client.writecmd( PICAPP, 0x86, len(cmd_byte_li), cmd_byte_li )
74 if client.app == PICAPP and client.verb == 0x86 and client.count != len(cmd_byte_li):
75 print "Error: incomplete execution of sixlist.\nOnly %d instructions run." % (client.count/3)
78 elif client.app == 0xff and client.verb == 0xff: # GoodFET debugstr
79 print "Error (in runlist): failed transaction; aborting."
83 def build_instr_stream( cmd_li ):
84 """Given a list of instruction words, returns a list of bytes of
85 the same, in little endian ordering."""
88 cmd_byte_li += [instr & 0xff,
93 def readreg( reg_num ):
94 """Read contents of a working register (i.e. W0, W1, ..., W15)."""
95 instr = 0x883C20+(reg_num&0xf)
96 client.writecmd( PICAPP, 0x82, 3, [instr & 0xff,
98 (instr >> 16) & 0xff] )
99 client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] ) # NOP (pump clock)
102 def writereg( reg_num, word ):
103 """Write 16-bit word to a working register (i.e., W0, W1, ..., W15)."""
104 instr = 0x200000 + ((word&0xffff)<<4) + (reg_num&0xf)
105 client.writecmd( PICAPP, 0x82, 3, [instr & 0xff,
107 (instr >> 16) & 0xff] )
110 """Read VISI register; assumes ICSP session already started."""
111 data = client.writecmd( PICAPP, 0x83, 0 )
112 result = ord(data[0])
113 result |= ord(data[1]) << 8
117 """Read NVMCON register; assumes ICSP session already started."""
118 rd_nvmcon_li = [0x803B00, # MOV NVMCON, W0
119 0x883C20, # MOV W0, VISI
122 runlist( rd_nvmcon_li )
126 """Reset program counter during an active ISCP session."""
127 runlist( [0x040200, # GOTO 0x0200
131 #print "Starting dsPIC33F/PIC24H ICSP session..."
132 data = client.writecmd( PICAPP, 0x84, 0 )
135 #print "Stopping dsPIC33F/PIC24H ICSP session..."
136 data = client.writecmd( PICAPP, 0x85, 0 )
139 """Read and print VISI register to stdout; assumes ICSP session already started."""
140 print "Reading VISI register..."
142 print "VISI: 0x%04X" % result
144 def dump_pm( start_addr, stop_addr, pretty=False ):
145 """Dump routine, now encapsulated in a function.
146 Returns an instance of IntelHex corresponding to result.
148 Note that we start and stop an ICSP session here! This means an
149 existing session will be broken."""
150 readpm_cmd_li = [0x200000, # MOV #addr<23:16>, W0
151 0x880190, # MOV W0, TBLPAG
152 0x200006, # MOV #addr<15:0>, W6
155 0xBA1B96, # TBLRDL [W6], [W7++]
158 0xBADBB6, # TBLRDH.B [W6++], [W7++]
161 0xBADBD6, # TBLRDH.B [++W6], [W7++]
164 0xBA1BB6, # TBLRDL [W6++], [W7++]
167 0xBA1B96, # TBLRDL [W6], [W7++]
170 0xBADBB6, # TBLRDH.B [W6++], [W7++]
173 0xBADBD6, # TBLRDH.B [++W6], [W7++]
176 0xBA0BB6, # TBLRDL [W6++], [W7]
184 print "Reading program memory 0x%06X:0x%06X ..." % ( start_addr, stop_addr )
186 client.writecmd( PICAPP, 0x82, 3, [0x00,0x02,0x04] ) #GOTO 0x200 (reset)
187 client.writecmd( PICAPP, 0x82, 3, [0x00,0x02,0x04] ) #GOTO 0x200 (reset)
188 client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] ) #NOP (pump clock)
190 last_highb = -1 # Only set TBLPAG when needed.
191 packed_instr_list = [0,0,0,0,0,0] # For packing 4 (24-bit) instructions in 6 (16-bit) words
192 for addr in range( start_addr&0xfffff8, stop_addr+8, 8 ):
193 if (addr>>16)&0xff != last_highb:
194 last_highb = (addr>>16)&0xff;
195 specify_addr_cmd = [readpm_cmd_li[0] + ((addr & 0xff0000)>>12),
197 readpm_cmd_li[2] + ((addr & 0xffff)<<4)]
199 specify_addr_cmd = [readpm_cmd_li[2] + ((addr & 0xffff)<<4)]
200 runlist( specify_addr_cmd + readpm_cmd_li[3:] )
202 for reg_num in range(6): # Read W0:5, to get packed instructions
203 packed_instr_list[reg_num] = readreg( reg_num )
204 instr_list = words2instr( packed_instr_list )
206 for offset in range(4): # Print result
207 if addr+offset*2 < start_addr:
209 if addr+offset*2 > stop_addr:
211 dumphex.puts( ((addr+offset*2)&0xffffff)*2,
212 chr(instr_list[offset]&0xff)
213 +chr((instr_list[offset]>>8)&0xff)
214 +chr((instr_list[offset]>>16)&0xff)
217 print "0x%06X 0x%06X" % (addr+offset*2,instr_list[offset])
224 def instr2words( instr_list ):
225 """Convert a list of 4 24-bit instructions to a list of 6 words
228 Returns [-1] on failure."""
229 if len(instr_list) < 4: # Catch mistakes
230 print "Error in instr2words: operand has less than 4 elements."
232 word_list = [0,0,0,0,0,0]
234 word_list[k*3] = instr_list[k*2] & 0xffff
235 word_list[k*3+1] = (instr_list[k*2]>>16)&0xff
236 word_list[k*3+1] |= (instr_list[k*2+1]>>8)&0xff00
237 word_list[k*3+2] = instr_list[k*2+1] & 0xffff
240 def words2instr( word_list ):
241 """4 24-bit instructions from a packing in 6 words (16 bit width).
242 This is the inverse of function instr2words.
244 Returns [-1] on failure."""
245 if len(word_list) < 6: # Catch mistakes
246 print "Error in words2instr: operand has less than 6 elements."
248 instr_list = [0,0,0,0]
250 instr_list[k*2] = word_list[k*3]
251 instr_list[k*2] |= (word_list[k*3+1]&0xff)<<16
252 instr_list[k*2+1] = word_list[k*3+2]
253 instr_list[k*2+1] |= (word_list[k*3+1]&0xff00)<<8
261 if len(sys.argv) == 1:
262 print "Usage: %s verb [objects]\n" % sys.argv[0]
263 print "%s devid" % sys.argv[0]
264 print "%s read 0x$addr" % sys.argv[0]
265 print "%s dump $foo.hex [0x$start 0x$stop] [pretty]" % sys.argv[0]
266 print "%s config" % sys.argv[0]
267 print "%s reset" % sys.argv[0]
268 print "%s program $foo.hex" % sys.argv[0]
269 print "%s verify $foo.hex" % sys.argv[0]
270 print "%s write 0x$address 0x$value" % sys.argv[0]
271 print "%s write_config 0x$reg_address (or $reg_name) [$0x0000]" % sys.argv[0]
272 print "%s erase [0x$page]" % sys.argv[0] # bulk or page erase
273 print "%s six [instruction]" % sys.argv[0]
274 print "%s sixfile [$foo.txt]" % sys.argv[0]
275 print "%s regout" % sys.argv[0]
277 Note: use - for stdout.
278 Warning: only formally supports dsPIC33F/PIC24H,
279 but read/write flash memory works with PIC24F ...
283 # Initialize and open connection to GoodFET
285 client.verbose = False # Dump activity to terminal
286 client.serInit( timeout=10 ) # UART comm timeout (in seconds)
289 # Handle each possible PIC verb in turn
291 if sys.argv[1] == "devid": #0x81
292 print "Requesting Application ID, DEVID and hardware revision..."
293 data = client.writecmd( PICAPP, 0x81, 0 )
300 devid = ord(data[1]) + (ord(data[2]) << 8)
304 hwrev = ord(data[3]) + (ord(data[4]) << 8)
307 print "Application ID: 0x%02X" % appid
308 if dev_table.has_key( devid ):
309 print "DEVID: 0x%04X (%s)" % ( devid, dev_table[devid] )
311 print "DEVID: 0x%04X (unknown)" % devid
312 print "revision: 0x%04X"% hwrev
313 #print "\n(Note that -1 indicates failure to read a value.)"
315 elif sys.argv[1] == "reset":
316 client.writecmd( PICAPP, 0x87, 0 )
318 elif sys.argv[1] == "config": # Dump configuration registers
319 prep_cmd_li = [0x040200, # GOTO 0x0200
321 0x200F80, # MOV #0x00F8, W0
322 0x880190, # MOV W0, TBLPAG
324 0x207847, # MOV #VISI, W7
326 rd_cmd_li = [0xBA0BB6, # TBLRDL [W6++], [W7]
330 print "Dumping configuration registers..."
331 for instr in prep_cmd_li:
332 data = client.writecmd( PICAPP, 0x82, 3, [instr & 0xff,
334 (instr >> 16) & 0xff] )
335 for k in range(12): # twelve configuration registers total
336 for instr in rd_cmd_li:
337 data = client.writecmd( PICAPP, 0x82, 3, [instr & 0xff,
339 (instr >> 16) & 0xff] )
342 if cfg_table.has_key( addr ):
343 print "0x%06X (%s): 0x%02X" % ( addr,
344 cfg_table[addr].ljust(cfg_table["width"]),
347 print "0x%06X: 0x%02X" % ( addr, result )
351 elif sys.argv[1] == "program":
352 if len(sys.argv) != 3:
353 print "Error: an Intel HEX file to load must be given."
357 proghex = IntelHex( sys.argv[2] )
359 print "Error while attempting to read from %s" % sys.argv[2]
361 ph_addrs = proghex.addresses()
363 # Load starting program memory address
364 wr_pm64_li_setaddr = [0x040200, # GOTO 0x0200
366 0x24001A, # MOV $0x4001, W10
367 0x883B0A, # MOV W10, NVMCON
368 0x200000, # + ((addr>>12)&0xff0), # MOV #addr<23:16>, W0
369 0x880190, # MOV W0, TBLPAG
370 0x200007] # + ((addr&0xffff)<<4), # MOV #addr<15:0>, W7
372 # Load 4 instructions into write latches
373 wr_pm64_li_wrlat = [0xEB0300, # CLR W6
375 0xBB0BB6, # TBLWTL [W6++], [W7]
378 0xBBDBB6, # TBLWTH.B [W6++], [W7++]
381 0xBBEBB6, # TBLWTH.B [W6++], [++W7]
384 0xBB1BB6, # TBLWTL [W6++], [W7++]
387 0xBB0BB6, # TBLWTL [W6++], [W7]
390 0xBBDBB6, # TBLWTH.B [W6++], [W7++]
393 0xBBEBB6, # TBLWTH.B [W6++], [++W7]
396 0xBB1BB6, # TBLWTL [W6++], [W7++]
400 wr_pm64_li_wr = [0xA8E761, # BSET NVMCON, #WR
408 for last_code_addr in reversed(ph_addrs):
409 if (last_code_addr>>1) < 0xf80000:
410 last_row_addr = (last_code_addr>>1) & 0xffff80
412 for addr in range((ph_addrs[0]>>1)&0xffff80,last_code_addr+2,128):
413 # Prevent crossing addresses where upper byte
414 # (i.e., address<23:16>) changes.
415 #if addr+126 > 0xffff:
416 # stop_addr = addr | 0xffff
418 # stop_addr = addr+126
420 runlist( wr_pm64_li_setaddr[:4]
421 + [0x200000 + ((addr>>12)&0xff0),
422 wr_pm64_li_setaddr[5],
423 0x200007 + ((addr&0xffff)<<4)] )
425 instr_list = [0,0,0,0]
426 for mid_addr in range(addr,addr+126,8):
427 for offset in range(4):
428 if (mid_addr+offset*2)<<1 not in ph_addrs:
429 instr_list[offset] = 0xffffff
431 instr_list[offset] = proghex[(mid_addr+offset*2)<<1]
432 instr_list[offset] |= proghex[((mid_addr+offset*2)<<1)+1] << 8
433 instr_list[offset] |= proghex[((mid_addr+offset*2)<<1)+2] << 16
434 packed_instr_list = instr2words( instr_list )
435 runlist( [0x200000 + ((packed_instr_list[0]&0xffff)<<4),
436 0x200001 + ((packed_instr_list[1]&0xffff)<<4),
437 0x200002 + ((packed_instr_list[2]&0xffff)<<4),
438 0x200003 + ((packed_instr_list[3]&0xffff)<<4),
439 0x200004 + ((packed_instr_list[4]&0xffff)<<4),
440 0x200005 + ((packed_instr_list[5]&0xffff)<<4)]
443 runlist( wr_pm64_li_wr )
444 status = readNVMCON()
445 while status & 0x8000:
446 client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] )
447 status = readNVMCON()
449 # Configuration registers must be treated separately
450 for addr in ph_addrs[ph_addrs.index(last_code_addr):]:
453 if (addr>>1) > 0xf80017:
455 wr_cfg_li = [0x040200, # GOTO 0x0200
457 0x200007 + ((addr<<3)&0xffff0), # MOV #addr<15:0>, W7
458 0x24000A, # MOV #0x4000, W10
459 0x883B0A, # MOV W10, NVMCON
460 0x200F80, # MOV #0xF8, W0
461 0x880190, # MOV W0, TBLPAG
462 0x200000 + ((proghex[addr]&0x00ff)<<4), # MOV #new_val<7:0>, W0
463 0xBB0B80, # TBLWTL W0, [W7]
466 0xA8E761, # BSET NVMCON, #WR
472 status = readNVMCON()
473 while status & 0x8000:
474 client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] )
475 status = readNVMCON()
480 elif sys.argv[1] == "verify":
481 if len(sys.argv) != 3:
482 print "Error: an Intel HEX file with which to compare must be given."
486 proghex = IntelHex( sys.argv[2] )
488 print "Error while attempting to read from %s" % sys.argv[2]
491 print "WARNING: verifying config registers not yet supported."
493 for addr in proghex.addresses():
494 if addr % 4 != 0 or (addr>>1) < 0x200:
496 #elif first_addr == None:
497 # first_addr = addr>>1
498 if (addr>>1) >= 0xf80000:
501 dumphex = dump_pm( (proghex.addresses()[0]>>1),
504 # Step through addresses in HEX file and compare to those in target PIC
505 for addr in proghex.addresses():
506 if addr>>1 >= 0xF80000:
507 break # verifying config registers not yet supported
508 # Compare; fail if mismatch
509 if proghex[addr] != dumphex[addr]:
510 addr &= addr&0xfffffffc
511 found_instr = dumphex[addr]
512 found_instr |= dumphex[addr+1]<<8
513 found_instr |= dumphex[addr+2]<<16
514 exp_instr = proghex[addr]
515 exp_instr |= proghex[addr+1]<<8
516 exp_instr |= proghex[addr+2]<<16
517 print "Fail at address 0x%06X: found 0x%06X, expected 0x%06X." % ( addr>>1, found_instr, exp_instr )
520 print "PASSED" # Be verbose.
523 elif sys.argv[1] == "write":
524 if len(sys.argv) != 4:
525 print "Error: an address (in program memory) and\n value (or instruction) to write must be given."
528 addr = int(float.fromhex(sys.argv[2]))
529 new_instr = int(float.fromhex(sys.argv[3]))
532 # new_instr_li.append( int(float.fromhex(sys.argv[k+3])) )
534 #new_words = instr2words( new_instr_li )
536 wr_pm_li = [0x040200, # GOTO 0x0200
539 0x24003A, # MOV $0x4003, W10
540 0x883B0A, # MOV W10, NVMCON
541 0x200000 + ((addr>>12)&0xff0), # MOV #addr<23:16>, W0
542 0x880190, # MOV W0, TBLPAG
543 0x200007 + ((addr&0xffff)<<4), # MOV #addr<15:0>, W7
545 # Here we load the instruction into registers W0:W1
546 0x200000 + ((new_instr&0xffff)<<4),
547 0x200001 + ((new_instr>>12)&0xff0),
548 #0x200000 + ((new_words[0]&0xffff)<<4),
549 #0x200001 + ((new_words[1]&0xffff)<<4),
550 #0x200002 + ((new_words[2]&0xffff)<<4),
551 #0x200003 + ((new_words[3]&0xffff)<<4),
552 #0x200004 + ((new_words[4]&0xffff)<<4),
553 #0x200005 + ((new_words[5]&0xffff)<<4),
557 0xBB0BB6, # TBLWTL [W6++], [W7]
560 0xBB8B96, # TBLWTH [W6], [W7]
561 #0xBBDBB6, # TBLWTH.B [W6++], [W7++]
564 #0xBBEBB6, # TBLWTH.B [W6++], [++W7]
567 #0xBB1BB6, # TBLWTL [W6++], [W7++]
570 #0xBB0BB6, # TBLWTL [W6++], [W7]
573 #0xBBDBB6, # TBLWTH.B [W6++], [W7++]
576 #0xBBEBB6, # TBLWTH.B [W6++], [++W7]
579 #0xBB1BB6, # TBLWTL [W6++], [W7++]
583 0xA8E761, # BSET NVMCON, #WR
592 status = readNVMCON()
593 while status & 0x8000:
594 client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] ) # NOP (pump clock)
595 status = readNVMCON()
599 elif sys.argv[1] == "write_config":
600 if len(sys.argv) < 3:
601 print "Error: please specify the target config register."
603 elif len(sys.argv) == 3:
604 new_val = 0xFF # Assume new value
606 new_val = int(float.fromhex(sys.argv[3]))
608 reg_addr = int(float.fromhex(sys.argv[2]))
610 if sys.argv[2] not in cfg_table.values():
611 print "Given register, %s, not recognized." % sys.argv[2]
613 reg_addr = cfg_table.keys()[cfg_table.values().index(sys.argv[2])]
615 wr_cfg_li = [0x040200, # GOTO 0x0200
617 0x200007 + ((reg_addr&0xffff)<<4), # MOV #addr<15:0>, W7
618 0x24000A, # MOV #0x4000, W10
619 0x883B0A, # MOV W10, NVMCON
620 0x200F80, # MOV #0xF8, W0
621 0x880190, # MOV W0, TBLPAG
622 0x200000 + ((new_val&0xffff)<<4), # MOV #<new_val>, W0
623 0xBB0B80, # TBLWTL W0, [W7]
626 0xA8E761, # BSET NVMCON, #WR
635 status = readNVMCON()
636 while status & 0x8000:
637 client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] ) # NOP (pump clock)
638 status = readNVMCON()
643 elif sys.argv[1] == "read": # Read an address of program memory
646 addr = int(float.fromhex(sys.argv[2]))
648 readpm_cmd_li = [0x040200, # GOTO 0x0200
650 0x200000+((addr & 0xff0000)>>12), # MOV #addr<23:16>, W0
651 0x880190, # MOV W0, TBLPAG
652 0x200006+((addr & 0xffff)<<4), # MOV #addr<15:0>, W6
656 0xBA1B96, # TBLRDL [W6], [W7++]
659 0xBACB96, # TBLRDH.B [W6], [W7]
663 runlist( readpm_cmd_li )
664 loww = readreg(0) # Read W0, which has lower 16 bits
665 highb = readreg(1) # Read W1, which has high 8 bits
666 result = (highb<<16) | loww
668 print "0x%06X: 0x%06X" % ( addr, result )
672 elif sys.argv[1] == "dump": # Read section of program memory
673 if len(sys.argv) < 3:
674 print "Error: please specify file in which to dump program memory."
678 if len(sys.argv) == 6:
683 if len(sys.argv) > 4:
684 start_addr = int(float.fromhex(sys.argv[3]))
685 stop_addr = int(float.fromhex(sys.argv[4]))
687 # Assume all of program memory (including unimplemented sections,
688 # which will be read as zeroes.
692 dumphex = dump_pm( start_addr, stop_addr, print_term )
696 dumphex.tofile( sys.stdout, format="hex" )
698 dumphex.tofile( fname, format="hex" )
701 elif sys.argv[1] == "erase": # Bulk (all program memory) or page erase
703 if len(sys.argv) == 3:
704 addr = int(float.fromhex(sys.argv[2]))
708 if addr is None: # Bulk erase (all of program memory)
709 erase_cmd_li = [0x040200, # GOTO 0x0200
711 0x2404FA, # MOV $0x404F, W10
712 0x883B0A, # MOV W10, NVMCON
713 0xA8E761, # BSET NVMCON, #WR
719 print "Erasing page of 0x%06X" % addr
720 erase_cmd_li = [0x040200, # GOTO 0x0200
722 0x24042A, # MOV $0x4042, W10
723 0x883B0A, # MOV W10, NVMCON
724 0x200000+((addr & 0xff0000)>>12), # MOV #addr<23:16>, W0
725 0x880190, # MOV W0, TBLPAG
726 0x200001+((addr&0xffff)<<4), # MOV addr<15:0>, W1
728 0xBB0881, # TBLTWL W1, [W1]
731 0xA8E761, # BSET NVMCON, #WR
736 # Note that page alignment (effectively, bitmask of 0xffff80
737 # applied to given program memory address) seems to be
738 # enforced by hardware.
742 runlist( erase_cmd_li )
743 status = readNVMCON()
744 while status & 0x8000:
745 client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] ) # NOP (pump clock)
746 status = readNVMCON()
750 elif sys.argv[1] == "six": #0x82
753 if len(sys.argv) < 3:
754 instr = 0x000000 # Assume nop
756 instr = int(float.fromhex(sys.argv[2]))
757 print "Loading 0x%06X for execution..." % instr
758 data = client.writecmd( PICAPP, 0x82, 3, [instr & 0xff,
760 (instr >> 16) & 0xff] )
761 print "Executing (by loading nop; pumping clock)..."
762 data = client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] )
768 elif sys.argv[1] == "sixfile": #0x82 (repeated for each instruction in file)
771 if len(sys.argv) < 3:
772 print "Warning: no file given; trying cmd.txt..."
778 instrfile = open( fname, "r" )
780 print "Failed to open file %s for reading." % fname
784 print "Opened file %s. Consecutively reading commmands..." % fname
785 for line in instrfile:
789 instr = int(float.fromhex(words[0]))
791 print "Warning: invalid instruction found at offset %d." % instrfile.tell()
793 print "Loading 0x%06X for execution..." % instr
794 data = client.writecmd( PICAPP, 0x82, 3, [instr & 0xff,
796 (instr >> 16) & 0xff] )
798 # print "Warning: empty line found at offset %d." % instrfile.tell()
800 print "Error: exception caught while reading file %s." % fname
807 print "Loading nop, pumping clock (to finish execution)..."
808 data = client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] )
814 elif sys.argv[1] == "regout": #0x83
817 print "Reading VISI register..."
818 data = client.writecmd( PICAPP, 0x83, 0 )
819 result = ord(data[0])
820 result |= ord(data[1]) << 8
821 print "VISI: 0x%04X" % result
826 print "Unrecognized verb: %s" % sys.argv[1]