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...)
30 # 0x32 is the normal address of the TBLPAG register. On some PICs,
31 # though, it appears at 0x54 (see DS39970B). Affected PIC families
32 # include: PIC24FJxxx{DA1,DA2,GB2,GA3}xx
35 WRITE_MAX_POLL_ATTEMPTS = 100
37 dev_table = { 0x00EE : "dsPIC33FJ128GP708",
38 0x00EF : "dsPIC33FJ128GP710",
39 0x080A : "PIC24HJ12GP201",
40 0x080B : "PIC24HJ12GP202",
41 0x0444 : "PIC24FJ16GA002",
42 0x044C : "PIC24FJ16GA004",
43 0x0445 : "PIC24FJ32GA002",
44 0x044D : "PIC24FJ32GA004",
45 0x0446 : "PIC24FJ48GA002",
46 0x044E : "PIC24FJ48GA004",
47 0x0447 : "PIC24FJ64GA002",
48 0x044F : "PIC24FJ64GA004",
49 0x0405 : "PIC24FJ64GA006",
50 0x0408 : "PIC24FJ64GA008",
51 0x040B : "PIC24FJ64GA010",
52 0x0406 : "PIC24FJ96GA006",
53 0x0409 : "PIC24FJ96GA008",
54 0x040C : "PIC24FJ96GA010",
55 0x0407 : "PIC24FJ128GA006",
56 0x040A : "PIC24FJ128GA008",
57 0x040D : "PIC24FJ128GA010",
58 0x1000 : "PIC24FJ64GA106",
59 0x1008 : "PIC24FJ128GA106",
60 0x1010 : "PIC24FJ192GA106",
61 0x1018 : "PIC24FJ256GA106",
62 0x1002 : "PIC24FJ64GA108",
63 0x100A : "PIC24FJ128GA108",
64 0x1012 : "PIC24FJ192GA108",
65 0x101A : "PIC24FJ256GA108",
66 0x1006 : "PIC24FJ64GA110",
67 0x100E : "PIC24FJ128GA110",
68 0x1016 : "PIC24FJ192GA110",
69 0x101E : "PIC24FJ256GA110",
70 0x1001 : "PIC24FJ64GB106",
71 0x1009 : "PIC24FJ128GB106",
72 0x1011 : "PIC24FJ192GB106",
73 0x1019 : "PIC24FJ256GB106",
74 0x1003 : "PIC24FJ64GB108",
75 0x100B : "PIC24FJ128GB108",
76 0x1013 : "PIC24FJ192GB108",
77 0x101B : "PIC24FJ256GB108",
78 0x1007 : "PIC24FJ64GB110",
79 0x100F : "PIC24FJ128GB110",
80 0x1017 : "PIC24FJ192GB110",
81 0x101F : "PIC24FJ256GB110",
82 0x4109 : "PIC24FJ128DA106",
83 0x410D : "PIC24FJ256DA106",
84 0x410B : "PIC24FJ128DA110",
85 0x410F : "PIC24FJ256DA110",
86 0x4108 : "PIC24FJ128DA206",
87 0x410C : "PIC24FJ256DA206",
88 0x410A : "PIC24FJ128DA210",
89 0x410E : "PIC24FJ256DA210",
90 0x46C0 : "PIC24FJ64GA306",
91 0x46C4 : "PIC24FJ64GA308",
92 0x46C8 : "PIC24FJ64GA310",
93 0x46C2 : "PIC24FJ128GA306",
94 0x46C6 : "PIC24FJ128GA308",
95 0x46CA : "PIC24FJ128GA310",
96 0x4100 : "PIC24FJ128GB206",
97 0x4104 : "PIC24FJ256GB206",
98 0x4102 : "PIC24FJ128GB210",
99 0x4106 : "PIC24FJ256GB210",
101 cfg_table = { 0xF80000 : "FBS",
104 0xF80006 : "FOSCSEL",
113 "width" : 7 } # For pretty printing.
115 #cfg_bitmask_table = {
122 def runlist( cmd_li ):
123 """Load (and execute) a given list of instructions.
124 Assumes ICSP session already started."""
125 cmd_byte_li = build_instr_stream( cmd_li )
126 data = client.writecmd( PICAPP, 0x86, len(cmd_byte_li), cmd_byte_li )
127 if client.app == PICAPP and client.verb == 0x86 and client.count != len(cmd_byte_li):
128 print "Error: incomplete execution of sixlist.\nOnly %d instructions run." % (client.count/3)
131 elif client.app == 0xff and client.verb == 0xff: # GoodFET debugstr
132 print "Error (in runlist): failed transaction; aborting."
136 class PicResponseThunk(object):
137 """A holder for a response value from the PIC, eg from a REGOUT
140 To retrieve the value, simply call the object. If the value has
141 not yet been retrieved, any pending commands in the command buffer
142 will be executed. You can determine whether the response has been
143 recieved by calling the have_response function.
145 Objects of this class should only be created by the PicCmdBuffer
148 def __init__(self, cmdbuf):
152 def _set_value(self, value):
154 def have_response(self):
155 return self.value is not None
157 if self.value is None:
159 assert self.value is not None
162 class PicCmdBuffer(object):
163 def __init__(self, client):
165 self.buffered_commands = []
166 self.response_buffer = []
167 data = client.writecmd(MONITORAPP, 0xc2)
168 assert data is not None and len(data) is 2
169 # buffer size is the size of the goodfet's recieve buffer, in
171 self.buffer_size = (ord(data[0]) + (ord(data[1]) << 8)) >> 2
173 assert len(self.buffered_commands) <= self.buffer_size
174 command = ''.join(self.buffered_commands)
175 self.buffered_commands = []
176 #print "Running: " + command.encode('hex')
177 data = self.client.writecmd(PICAPP, VERB_CMDLIST,
178 len(command), map(ord, command))
179 #print "Recieved: " + data.encode('hex')
180 assert len(data) == (len(self.response_buffer) + 1) * 2
183 for resp in self.response_buffer:
184 wd, data = data[0:2],data[2:]
185 val = ord(wd[0]) + (ord(wd[1]) << 8)
188 assert len(data) == 2
189 checksum += ord(data[0]) + (ord(data[1]) << 8)
192 self.response_buffer = []
193 def _add_command(self, command, data):
194 assert command in (0,1)
195 assert (data >> 24) == 0
196 full_cmd = [chr(command)]
198 full_cmd.append(chr((data >> (8*i)) & 0xff))
199 if len(self.buffered_commands) >= self.buffer_size:
201 self.buffered_commands.append(''.join(full_cmd))
202 def SIX(self, *insns):
203 """Run a list of instructions"""
205 self._add_command(0, insn)
208 "Read the VISI register. Returns a PicResponseThunk"
209 thunk = PicResponseThunk(self)
210 self.response_buffer.append(thunk)
211 self._add_command(1, 0)
214 def build_instr_stream( cmd_li ):
215 """Given a list of instruction words, returns a list of bytes of
216 the same, in little endian ordering."""
219 cmd_byte_li += [instr & 0xff,
221 (instr >> 16) & 0xff]
224 def readreg( reg_num ):
225 """Read contents of a working register (i.e. W0, W1, ..., W15)."""
226 instr = 0x883C20+(reg_num&0xf)
227 client.writecmd( PICAPP, 0x82, 3, [instr & 0xff,
229 (instr >> 16) & 0xff] )
230 client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] ) # NOP (pump clock)
233 def writereg( reg_num, word ):
234 """Write 16-bit word to a working register (i.e., W0, W1, ..., W15)."""
235 instr = 0x200000 + ((word&0xffff)<<4) + (reg_num&0xf)
236 client.writecmd( PICAPP, 0x82, 3, [instr & 0xff,
238 (instr >> 16) & 0xff] )
241 """Read VISI register; assumes ICSP session already started."""
242 data = client.writecmd( PICAPP, 0x83, 0 )
243 result = ord(data[0])
244 result |= ord(data[1]) << 8
248 """Read NVMCON register; assumes ICSP session already started."""
249 rd_nvmcon_li = [0x803B00, # MOV NVMCON, W0
250 0x883C20, # MOV W0, VISI
253 runlist( rd_nvmcon_li )
257 """Reset program counter during an active ISCP session."""
258 runlist( [0x040200, # GOTO 0x0200
262 #print "Starting dsPIC33F/PIC24H ICSP session..."
263 data = client.writecmd( PICAPP, 0x84, 0 )
266 #print "Stopping dsPIC33F/PIC24H ICSP session..."
267 data = client.writecmd( PICAPP, 0x85, 0 )
270 """Read and print VISI register to stdout; assumes ICSP session already started."""
271 print "Reading VISI register..."
273 print "VISI: 0x%04X" % result
275 def dump_pm( start_addr, stop_addr, pretty=False ):
276 """Dump routine, now encapsulated in a function.
277 Returns an instance of IntelHex corresponding to result.
279 Note that we start and stop an ICSP session here! This means an
280 existing session will be broken."""
281 readpm_cmd_li = [0x200000, # MOV #addr<23:16>, W0
282 0x880000 | tblpag << 3, # MOV W0, TBLPAG
283 0x200006, # MOV #addr<15:0>, W6
286 0xBA1B96, # TBLRDL [W6], [W7++]
289 0xBADBB6, # TBLRDH.B [W6++], [W7++]
292 0xBADBD6, # TBLRDH.B [++W6], [W7++]
295 0xBA1BB6, # TBLRDL [W6++], [W7++]
298 0xBA1B96, # TBLRDL [W6], [W7++]
301 0xBADBB6, # TBLRDH.B [W6++], [W7++]
304 0xBADBD6, # TBLRDH.B [++W6], [W7++]
307 0xBA0BB6, # TBLRDL [W6++], [W7]
315 print "Reading program memory 0x%06X:0x%06X ..." % ( start_addr, stop_addr )
317 client.writecmd( PICAPP, 0x82, 3, [0x00,0x02,0x04] ) #GOTO 0x200 (reset)
318 client.writecmd( PICAPP, 0x82, 3, [0x00,0x02,0x04] ) #GOTO 0x200 (reset)
319 client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] ) #NOP (pump clock)
321 last_highb = -1 # Only set TBLPAG when needed.
322 packed_instr_list = [0,0,0,0,0,0] # For packing 4 (24-bit) instructions in 6 (16-bit) words
323 for addr in range( start_addr&0xfffff8, stop_addr+8, 8 ):
324 if (addr>>16)&0xff != last_highb:
325 last_highb = (addr>>16)&0xff;
326 specify_addr_cmd = [readpm_cmd_li[0] + ((addr & 0xff0000)>>12),
328 readpm_cmd_li[2] + ((addr & 0xffff)<<4)]
330 specify_addr_cmd = [readpm_cmd_li[2] + ((addr & 0xffff)<<4)]
331 runlist( specify_addr_cmd + readpm_cmd_li[3:] )
333 for reg_num in range(6): # Read W0:5, to get packed instructions
334 packed_instr_list[reg_num] = readreg( reg_num )
335 instr_list = words2instr( packed_instr_list )
337 for offset in range(4): # Print result
338 if addr+offset*2 < start_addr:
340 if addr+offset*2 > stop_addr:
342 dumphex.puts( ((addr+offset*2)&0xffffff)*2,
343 chr(instr_list[offset]&0xff)
344 +chr((instr_list[offset]>>8)&0xff)
345 +chr((instr_list[offset]>>16)&0xff)
348 print "0x%06X 0x%06X" % (addr+offset*2,instr_list[offset])
355 def instr2words( instr_list ):
356 """Convert a list of 4 24-bit instructions to a list of 6 words
359 Returns [-1] on failure."""
360 if len(instr_list) < 4: # Catch mistakes
361 print "Error in instr2words: operand has less than 4 elements."
363 word_list = [0,0,0,0,0,0]
365 word_list[k*3] = instr_list[k*2] & 0xffff
366 word_list[k*3+1] = (instr_list[k*2]>>16)&0xff
367 word_list[k*3+1] |= (instr_list[k*2+1]>>8)&0xff00
368 word_list[k*3+2] = instr_list[k*2+1] & 0xffff
371 def words2instr( word_list ):
372 """4 24-bit instructions from a packing in 6 words (16 bit width).
373 This is the inverse of function instr2words.
375 Returns [-1] on failure."""
376 if len(word_list) < 6: # Catch mistakes
377 print "Error in words2instr: operand has less than 6 elements."
379 instr_list = [0,0,0,0]
381 instr_list[k*2] = word_list[k*3]
382 instr_list[k*2] |= (word_list[k*3+1]&0xff)<<16
383 instr_list[k*2+1] = word_list[k*3+2]
384 instr_list[k*2+1] |= (word_list[k*3+1]&0xff00)<<8
392 if len(sys.argv) == 1:
393 print "Usage: %s [-alt_tblpag] verb [objects]\n" % sys.argv[0]
394 print "%s devid" % sys.argv[0]
395 print "%s read 0x$addr" % sys.argv[0]
396 print "%s dump $foo.hex [0x$start 0x$stop] [pretty]" % sys.argv[0]
397 print "%s config" % sys.argv[0]
398 print "%s reset" % sys.argv[0]
399 print "%s program $foo.hex" % sys.argv[0]
400 print "%s verify $foo.hex" % sys.argv[0]
401 print "%s write 0x$address 0x$value" % sys.argv[0]
402 print "%s write_config 0x$reg_address (or $reg_name) [$0x0000]" % sys.argv[0]
403 print "%s erase [0x$page]" % sys.argv[0] # bulk or page erase
404 print "%s six [instruction]" % sys.argv[0]
405 print "%s sixfile [$foo.txt]" % sys.argv[0]
406 print "%s regout" % sys.argv[0]
408 Note: use - for stdout.
409 use -alt_tblpag for PIC24FJxxx{DA1,DA2,GB2,GA3}xx with tblpag at 0x54
410 Warning: only formally supports dsPIC33F/PIC24H,
411 but read/write flash memory works with PIC24F ...
415 # Initialize and open connection to GoodFET
417 client.verbose = False # Dump activity to terminal
418 client.serInit( timeout=10 ) # UART comm timeout (in seconds)
420 if sys.argv[1] == "-alt_tblpag":
424 # Handle each possible PIC verb in turn
425 if sys.argv[1] == "devid": #0x81
426 print "Requesting Application ID, DEVID and hardware revision..."
428 cmdbuf = PicCmdBuffer(client)
429 cmdbuf.SIX(0x040200, # GOTO 0x200
431 0x200FF0, # MOV #0xff, W0
432 0x880000 | tblpag << 3, # MOV W0, TBLPAG
433 0x200006, # MOV #0x0000, W6
434 0x207847, # MOV #VISI, W7
436 0xBA0B96, # TBLRDL [W6],[W7]
439 devid = cmdbuf.REGOUT()
440 cmdbuf.SIX(0x200026, # MOV #0x0002, W6
442 0xBA0B96, # TBLRDL [W6],[W7]
445 devidrev = cmdbuf.REGOUT()
446 cmdbuf.SIX(0x200800, # MOV #0x80, W0
447 0x880000 | tblpag << 3, # MOV W0, TBLPAG
448 0x207F00, # MOV #0x07F0, W6
450 0xBA0B96, # TBLRDL [W6],[W7]
453 appid = cmdbuf.REGOUT()
454 print "Application ID: 0x%02x" % appid()
455 print "DEVID: 0x%04x (%s)" % (
456 devid(), dev_table.get(devid(), "unknown"))
457 print "Revision: 0x%04x" % devidrev()
459 #print "\n(Note that -1 indicates failure to read a value.)"
461 elif sys.argv[1] == "test":
463 cmdbuf = PicCmdBuffer(client)
464 cmdbuf.SIX(0x2BEEF6, # MOV #0xBEEF, W6
466 0x780B86, # MOV W6, [W7]
469 assert cmdbuf.REGOUT()() == 0xbeef
472 elif sys.argv[1] == "reset":
473 client.writecmd( PICAPP, 0x87, 0 )
475 elif sys.argv[1] == "config": # Dump configuration registers
476 prep_cmd_li = [0x040200, # GOTO 0x0200
478 0x200F80, # MOV #0x00F8, W0
479 0x880000 | tblpag << 3, # MOV W0, TBLPAG
481 0x207847, # MOV #VISI, W7
483 rd_cmd_li = [0xBA0BB6, # TBLRDL [W6++], [W7]
487 print "Dumping configuration registers..."
488 for instr in prep_cmd_li:
489 data = client.writecmd( PICAPP, 0x82, 3, [instr & 0xff,
491 (instr >> 16) & 0xff] )
492 for k in range(12): # twelve configuration registers total
493 for instr in rd_cmd_li:
494 data = client.writecmd( PICAPP, 0x82, 3, [instr & 0xff,
496 (instr >> 16) & 0xff] )
499 if cfg_table.has_key( addr ):
500 print "0x%06X (%s): 0x%02X" % ( addr,
501 cfg_table[addr].ljust(cfg_table["width"]),
504 print "0x%06X: 0x%02X" % ( addr, result )
508 elif sys.argv[1] == "program":
509 if len(sys.argv) != 3:
510 print "Error: an Intel HEX file to load must be given."
514 proghex = IntelHex( sys.argv[2] )
516 print "Error while attempting to read from %s" % sys.argv[2]
518 ph_addrs = proghex.addresses()
520 # Load starting program memory address
521 wr_pm64_li_setaddr = [0x040200, # GOTO 0x0200
523 0x24001A, # MOV $0x4001, W10
524 0x883B0A, # MOV W10, NVMCON
525 0x200000, # + ((addr>>12)&0xff0), # MOV #addr<23:16>, W0
526 0x880000 | tblpag << 3, # MOV W0, TBLPAG
527 0x200007] # + ((addr&0xffff)<<4), # MOV #addr<15:0>, W7
529 # Load 4 instructions into write latches
530 wr_pm64_li_wrlat = [0xEB0300, # CLR W6
532 0xBB0BB6, # TBLWTL [W6++], [W7]
535 0xBBDBB6, # TBLWTH.B [W6++], [W7++]
538 0xBBEBB6, # TBLWTH.B [W6++], [++W7]
541 0xBB1BB6, # TBLWTL [W6++], [W7++]
544 0xBB0BB6, # TBLWTL [W6++], [W7]
547 0xBBDBB6, # TBLWTH.B [W6++], [W7++]
550 0xBBEBB6, # TBLWTH.B [W6++], [++W7]
553 0xBB1BB6, # TBLWTL [W6++], [W7++]
557 wr_pm64_li_wr = [0xA8E761, # BSET NVMCON, #WR
565 for last_code_addr in reversed(ph_addrs):
566 if (last_code_addr>>1) < 0xf80000:
567 last_row_addr = (last_code_addr>>1) & 0xffff80
569 for addr in range((ph_addrs[0]>>1)&0xffff80,last_code_addr+2,128):
570 # Prevent crossing addresses where upper byte
571 # (i.e., address<23:16>) changes.
572 #if addr+126 > 0xffff:
573 # stop_addr = addr | 0xffff
575 # stop_addr = addr+126
577 print "Writing address 0x%06X" % (addr)
579 runlist( wr_pm64_li_setaddr[:4]
580 + [0x200000 + ((addr>>12)&0xff0),
581 wr_pm64_li_setaddr[5],
582 0x200007 + ((addr&0xffff)<<4)] )
584 instr_list = [0,0,0,0]
585 for mid_addr in range(addr,addr+126,8):
586 for offset in range(4):
587 if (mid_addr+offset*2)<<1 not in ph_addrs:
588 instr_list[offset] = 0xffffff
590 instr_list[offset] = proghex[(mid_addr+offset*2)<<1]
591 instr_list[offset] |= proghex[((mid_addr+offset*2)<<1)+1] << 8
592 instr_list[offset] |= proghex[((mid_addr+offset*2)<<1)+2] << 16
593 packed_instr_list = instr2words( instr_list )
594 runlist( [0x200000 + ((packed_instr_list[0]&0xffff)<<4),
595 0x200001 + ((packed_instr_list[1]&0xffff)<<4),
596 0x200002 + ((packed_instr_list[2]&0xffff)<<4),
597 0x200003 + ((packed_instr_list[3]&0xffff)<<4),
598 0x200004 + ((packed_instr_list[4]&0xffff)<<4),
599 0x200005 + ((packed_instr_list[5]&0xffff)<<4)]
602 runlist( wr_pm64_li_wr )
604 status = readNVMCON()
605 while status & 0x8000:
607 #print " Status was 0x%04X for address 0x%06X" % (status, addr)
608 if attempts >= WRITE_MAX_POLL_ATTEMPTS:
609 print "Error writing to address 0x%06X (Status: 0x%04X)\nTry erase and program again." % (addr, status)
612 client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] )
613 status = readNVMCON()
615 # Configuration registers must be treated separately
616 for addr in ph_addrs[ph_addrs.index(last_code_addr):]:
618 print "Configuration register 0x%06X" % ( addr )
622 if (addr>>1) > 0xf80017:
624 wr_cfg_li = [0x040200, # GOTO 0x0200
626 0x200007 + ((addr<<3)&0xffff0), # MOV #addr<15:0>, W7
627 0x24000A, # MOV #0x4000, W10
628 0x883B0A, # MOV W10, NVMCON
629 0x200F80, # MOV #0xF8, W0
630 0x880000 | tblpag<< 3, # MOV W0, TBLPAG
631 0x200000 + ((proghex[addr]&0x00ff)<<4), # MOV #new_val<7:0>, W0
632 0xBB0B80, # TBLWTL W0, [W7]
635 0xA8E761, # BSET NVMCON, #WR
642 status = readNVMCON()
643 while status & 0x8000:
645 #print " Status was 0x%04X for address 0x%06X" % (status, addr)
646 if attempts >= WRITE_MAX_POLL_ATTEMPTS:
647 print "Error writing to address 0x%06X (Status: 0x%04X)\nTry erase and program again." % (addr, status)
650 client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] )
651 status = readNVMCON()
656 elif sys.argv[1] == "verify":
657 if len(sys.argv) != 3:
658 print "Error: an Intel HEX file with which to compare must be given."
662 proghex = IntelHex( sys.argv[2] )
664 print "Error while attempting to read from %s" % sys.argv[2]
667 print "WARNING: verifying config registers not yet supported."
669 for addr in proghex.addresses():
670 if addr % 4 != 0 or (addr>>1) < 0x200:
672 #elif first_addr == None:
673 # first_addr = addr>>1
674 if (addr>>1) >= 0xf80000:
677 dumphex = dump_pm( (proghex.addresses()[0]>>1),
680 # Step through addresses in HEX file and compare to those in target PIC
681 for addr in proghex.addresses():
682 if addr>>1 >= 0xF80000:
683 break # verifying config registers not yet supported
684 # Compare; fail if mismatch
685 if proghex[addr] != dumphex[addr]:
686 addr &= addr&0xfffffffc
687 found_instr = dumphex[addr]
688 found_instr |= dumphex[addr+1]<<8
689 found_instr |= dumphex[addr+2]<<16
690 exp_instr = proghex[addr]
691 exp_instr |= proghex[addr+1]<<8
692 exp_instr |= proghex[addr+2]<<16
693 print "Fail at address 0x%06X: found 0x%06X, expected 0x%06X." % ( addr>>1, found_instr, exp_instr )
696 print "PASSED" # Be verbose.
699 elif sys.argv[1] == "write":
700 if len(sys.argv) != 4:
701 print "Error: an address (in program memory) and\n value (or instruction) to write must be given."
704 addr = int(float.fromhex(sys.argv[2]))
705 new_instr = int(float.fromhex(sys.argv[3]))
708 # new_instr_li.append( int(float.fromhex(sys.argv[k+3])) )
710 #new_words = instr2words( new_instr_li )
712 wr_pm_li = [0x040200, # GOTO 0x0200
715 0x24003A, # MOV $0x4003, W10
716 0x883B0A, # MOV W10, NVMCON
717 0x200000 + ((addr>>12)&0xff0), # MOV #addr<23:16>, W0
718 0x880000 | tblpag << 3, # MOV W0, TBLPAG
719 0x200007 + ((addr&0xffff)<<4), # MOV #addr<15:0>, W7
721 # Here we load the instruction into registers W0:W1
722 0x200000 + ((new_instr&0xffff)<<4),
723 0x200001 + ((new_instr>>12)&0xff0),
724 #0x200000 + ((new_words[0]&0xffff)<<4),
725 #0x200001 + ((new_words[1]&0xffff)<<4),
726 #0x200002 + ((new_words[2]&0xffff)<<4),
727 #0x200003 + ((new_words[3]&0xffff)<<4),
728 #0x200004 + ((new_words[4]&0xffff)<<4),
729 #0x200005 + ((new_words[5]&0xffff)<<4),
733 0xBB0BB6, # TBLWTL [W6++], [W7]
736 0xBB8B96, # TBLWTH [W6], [W7]
737 #0xBBDBB6, # TBLWTH.B [W6++], [W7++]
740 #0xBBEBB6, # TBLWTH.B [W6++], [++W7]
743 #0xBB1BB6, # TBLWTL [W6++], [W7++]
746 #0xBB0BB6, # TBLWTL [W6++], [W7]
749 #0xBBDBB6, # TBLWTH.B [W6++], [W7++]
752 #0xBBEBB6, # TBLWTH.B [W6++], [++W7]
755 #0xBB1BB6, # TBLWTL [W6++], [W7++]
759 0xA8E761, # BSET NVMCON, #WR
768 status = readNVMCON()
769 while status & 0x8000:
770 client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] ) # NOP (pump clock)
771 status = readNVMCON()
775 elif sys.argv[1] == "write_config":
776 if len(sys.argv) < 3:
777 print "Error: please specify the target config register."
779 elif len(sys.argv) == 3:
780 new_val = 0xFF # Assume new value
782 new_val = int(float.fromhex(sys.argv[3]))
784 reg_addr = int(float.fromhex(sys.argv[2]))
786 if sys.argv[2] not in cfg_table.values():
787 print "Given register, %s, not recognized." % sys.argv[2]
789 reg_addr = cfg_table.keys()[cfg_table.values().index(sys.argv[2])]
791 wr_cfg_li = [0x040200, # GOTO 0x0200
793 0x200007 + ((reg_addr&0xffff)<<4), # MOV #addr<15:0>, W7
794 0x24000A, # MOV #0x4000, W10
795 0x883B0A, # MOV W10, NVMCON
796 0x200F80, # MOV #0xF8, W0
797 0x880000 | tblpag << 3, # MOV W0, TBLPAG
798 0x200000 + ((new_val&0xffff)<<4), # MOV #<new_val>, W0
799 0xBB0B80, # TBLWTL W0, [W7]
802 0xA8E761, # BSET NVMCON, #WR
811 status = readNVMCON()
812 while status & 0x8000:
813 client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] ) # NOP (pump clock)
814 status = readNVMCON()
819 elif sys.argv[1] == "read": # Read an address of program memory
822 addr = int(float.fromhex(sys.argv[2]))
824 readpm_cmd_li = [0x040200, # GOTO 0x0200
826 0x200000+((addr & 0xff0000)>>12), # MOV #addr<23:16>, W0
827 0x880000 | tblpag << 3, # MOV W0, TBLPAG
828 0x200006+((addr & 0xffff)<<4), # MOV #addr<15:0>, W6
832 0xBA1B96, # TBLRDL [W6], [W7++]
835 0xBACB96, # TBLRDH.B [W6], [W7]
839 runlist( readpm_cmd_li )
840 loww = readreg(0) # Read W0, which has lower 16 bits
841 highb = readreg(1) # Read W1, which has high 8 bits
842 result = (highb<<16) | loww
844 print "0x%06X: 0x%06X" % ( addr, result )
848 elif sys.argv[1] == "dump": # Read section of program memory
849 if len(sys.argv) < 3:
850 print "Error: please specify file in which to dump program memory."
854 if len(sys.argv) == 6:
859 if len(sys.argv) > 4:
860 start_addr = int(float.fromhex(sys.argv[3]))
861 stop_addr = int(float.fromhex(sys.argv[4]))
863 # Assume all of program memory (including unimplemented sections,
864 # which will be read as zeroes.
868 dumphex = dump_pm( start_addr, stop_addr, print_term )
872 dumphex.tofile( sys.stdout, format="hex" )
874 dumphex.tofile( fname, format="hex" )
877 elif sys.argv[1] == "erase": # Bulk (all program memory) or page erase
879 if len(sys.argv) == 3:
880 addr = int(float.fromhex(sys.argv[2]))
884 if addr is None: # Bulk erase (all of program memory)
885 erase_cmd_li = [0x040200, # GOTO 0x0200
887 0x2404FA, # MOV $0x404F, W10
888 0x883B0A, # MOV W10, NVMCON
889 0xA8E761, # BSET NVMCON, #WR
895 print "Erasing page of 0x%06X" % addr
896 erase_cmd_li = [0x040200, # GOTO 0x0200
898 0x24042A, # MOV $0x4042, W10
899 0x883B0A, # MOV W10, NVMCON
900 0x200000+((addr & 0xff0000)>>12), # MOV #addr<23:16>, W0
901 0x880000 | tblpag << 3, # MOV W0, TBLPAG
902 0x200001+((addr&0xffff)<<4), # MOV addr<15:0>, W1
904 0xBB0881, # TBLTWL W1, [W1]
907 0xA8E761, # BSET NVMCON, #WR
912 # Note that page alignment (effectively, bitmask of 0xffff80
913 # applied to given program memory address) seems to be
914 # enforced by hardware.
918 runlist( erase_cmd_li )
919 status = readNVMCON()
920 while status & 0x8000:
921 client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] ) # NOP (pump clock)
922 status = readNVMCON()
926 elif sys.argv[1] == "six": #0x82
929 if len(sys.argv) < 3:
930 instr = 0x000000 # Assume nop
932 instr = int(float.fromhex(sys.argv[2]))
933 print "Loading 0x%06X for execution..." % instr
934 data = client.writecmd( PICAPP, 0x82, 3, [instr & 0xff,
936 (instr >> 16) & 0xff] )
937 print "Executing (by loading nop; pumping clock)..."
938 data = client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] )
944 elif sys.argv[1] == "sixfile": #0x82 (repeated for each instruction in file)
947 if len(sys.argv) < 3:
948 print "Warning: no file given; trying cmd.txt..."
954 instrfile = open( fname, "r" )
956 print "Failed to open file %s for reading." % fname
960 print "Opened file %s. Consecutively reading commmands..." % fname
961 for line in instrfile:
965 instr = int(float.fromhex(words[0]))
967 print "Warning: invalid instruction found at offset %d." % instrfile.tell()
969 print "Loading 0x%06X for execution..." % instr
970 data = client.writecmd( PICAPP, 0x82, 3, [instr & 0xff,
972 (instr >> 16) & 0xff] )
974 # print "Warning: empty line found at offset %d." % instrfile.tell()
976 print "Error: exception caught while reading file %s." % fname
983 print "Loading nop, pumping clock (to finish execution)..."
984 data = client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] )
990 elif sys.argv[1] == "regout": #0x83
993 print "Reading VISI register..."
994 data = client.writecmd( PICAPP, 0x83, 0 )
995 result = ord(data[0])
996 result |= ord(data[1]) << 8
997 print "VISI: 0x%04X" % result
1002 print "Unrecognized verb: %s" % sys.argv[1]