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 dev_table = { 0x00EE : "dsPIC33FJ128GP708",
36 0x00EF : "dsPIC33FJ128GP710",
37 0x080A : "PIC24HJ12GP201",
38 0x080B : "PIC24HJ12GP202",
39 0x0444 : "PIC24FJ16GA002",
40 0x044C : "PIC24FJ16GA004",
41 0x0445 : "PIC24FJ32GA002",
42 0x044D : "PIC24FJ32GA004",
43 0x0446 : "PIC24FJ48GA002",
44 0x044E : "PIC24FJ48GA004",
45 0x0447 : "PIC24FJ64GA002",
46 0x044F : "PIC24FJ64GA004",
47 0x0405 : "PIC24FJ64GA006",
48 0x0408 : "PIC24FJ64GA008",
49 0x040B : "PIC24FJ64GA010",
50 0x0406 : "PIC24FJ96GA006",
51 0x0409 : "PIC24FJ96GA008",
52 0x040C : "PIC24FJ96GA010",
53 0x0407 : "PIC24FJ128GA006",
54 0x040A : "PIC24FJ128GA008",
55 0x040D : "PIC24FJ128GA010",
56 0x4109 : "PIC24FJ128DA106",
57 0x410D : "PIC24FJ256DA106",
58 0x410B : "PIC24FJ128DA110",
59 0x410F : "PIC24FJ256DA110",
60 0x4108 : "PIC24FJ128DA206",
61 0x410C : "PIC24FJ256DA206",
62 0x410A : "PIC24FJ128DA210",
63 0x410E : "PIC24FJ256DA210",
64 0x46C0 : "PIC24FJ64GA306",
65 0x46C4 : "PIC24FJ64GA308",
66 0x46C8 : "PIC24FJ64GA310",
67 0x46C2 : "PIC24FJ128GA306",
68 0x46C6 : "PIC24FJ128GA308",
69 0x46CA : "PIC24FJ128GA310",
70 0x4100 : "PIC24FJ128GB206",
71 0x4104 : "PIC24FJ256GB206",
72 0x4102 : "PIC24FJ128GB210",
73 0x4106 : "PIC24FJ256GB210",
75 cfg_table = { 0xF80000 : "FBS",
87 "width" : 7 } # For pretty printing.
89 #cfg_bitmask_table = {
96 def runlist( cmd_li ):
97 """Load (and execute) a given list of instructions.
98 Assumes ICSP session already started."""
99 cmd_byte_li = build_instr_stream( cmd_li )
100 data = client.writecmd( PICAPP, 0x86, len(cmd_byte_li), cmd_byte_li )
101 if client.app == PICAPP and client.verb == 0x86 and client.count != len(cmd_byte_li):
102 print "Error: incomplete execution of sixlist.\nOnly %d instructions run." % (client.count/3)
105 elif client.app == 0xff and client.verb == 0xff: # GoodFET debugstr
106 print "Error (in runlist): failed transaction; aborting."
110 class PicResponseThunk(object):
111 """A holder for a response value from the PIC, eg from a REGOUT
114 To retrieve the value, simply call the object. If the value has
115 not yet been retrieved, any pending commands in the command buffer
116 will be executed. You can determine whether the response has been
117 recieved by calling the have_response function.
119 Objects of this class should only be created by the PicCmdBuffer
122 def __init__(self, cmdbuf):
126 def _set_value(self, value):
128 def have_response(self):
129 return self.value is not None
131 if self.value is None:
133 assert self.value is not None
136 class PicCmdBuffer(object):
137 def __init__(self, client):
139 self.buffered_commands = []
140 self.response_buffer = []
141 data = client.writecmd(MONITORAPP, 0xc2)
142 assert data is not None and len(data) is 2
143 # buffer size is the size of the goodfet's recieve buffer, in
145 self.buffer_size = (ord(data[0]) + (ord(data[1]) << 8)) >> 2
147 assert len(self.buffered_commands) <= self.buffer_size
148 command = ''.join(self.buffered_commands)
149 self.buffered_commands = []
150 #print "Running: " + command.encode('hex')
151 data = self.client.writecmd(PICAPP, VERB_CMDLIST,
152 len(command), map(ord, command))
153 #print "Recieved: " + data.encode('hex')
154 assert len(data) == (len(self.response_buffer) + 1) * 2
157 for resp in self.response_buffer:
158 wd, data = data[0:2],data[2:]
159 val = ord(wd[0]) + (ord(wd[1]) << 8)
162 assert len(data) == 2
163 checksum += ord(data[0]) + (ord(data[1]) << 8)
166 self.response_buffer = []
167 def _add_command(self, command, data):
168 assert command in (0,1)
169 assert (data >> 24) == 0
170 full_cmd = [chr(command)]
172 full_cmd.append(chr((data >> (8*i)) & 0xff))
173 if len(self.buffered_commands) >= self.buffer_size:
175 self.buffered_commands.append(''.join(full_cmd))
176 def SIX(self, *insns):
177 """Run a list of instructions"""
179 self._add_command(0, insn)
182 "Read the VISI register. Returns a PicResponseThunk"
183 thunk = PicResponseThunk(self)
184 self.response_buffer.append(thunk)
185 self._add_command(1, 0)
188 def build_instr_stream( cmd_li ):
189 """Given a list of instruction words, returns a list of bytes of
190 the same, in little endian ordering."""
193 cmd_byte_li += [instr & 0xff,
195 (instr >> 16) & 0xff]
198 def readreg( reg_num ):
199 """Read contents of a working register (i.e. W0, W1, ..., W15)."""
200 instr = 0x883C20+(reg_num&0xf)
201 client.writecmd( PICAPP, 0x82, 3, [instr & 0xff,
203 (instr >> 16) & 0xff] )
204 client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] ) # NOP (pump clock)
207 def writereg( reg_num, word ):
208 """Write 16-bit word to a working register (i.e., W0, W1, ..., W15)."""
209 instr = 0x200000 + ((word&0xffff)<<4) + (reg_num&0xf)
210 client.writecmd( PICAPP, 0x82, 3, [instr & 0xff,
212 (instr >> 16) & 0xff] )
215 """Read VISI register; assumes ICSP session already started."""
216 data = client.writecmd( PICAPP, 0x83, 0 )
217 result = ord(data[0])
218 result |= ord(data[1]) << 8
222 """Read NVMCON register; assumes ICSP session already started."""
223 rd_nvmcon_li = [0x803B00, # MOV NVMCON, W0
224 0x883C20, # MOV W0, VISI
227 runlist( rd_nvmcon_li )
231 """Reset program counter during an active ISCP session."""
232 runlist( [0x040200, # GOTO 0x0200
236 #print "Starting dsPIC33F/PIC24H ICSP session..."
237 data = client.writecmd( PICAPP, 0x84, 0 )
240 #print "Stopping dsPIC33F/PIC24H ICSP session..."
241 data = client.writecmd( PICAPP, 0x85, 0 )
244 """Read and print VISI register to stdout; assumes ICSP session already started."""
245 print "Reading VISI register..."
247 print "VISI: 0x%04X" % result
249 def dump_pm( start_addr, stop_addr, pretty=False ):
250 """Dump routine, now encapsulated in a function.
251 Returns an instance of IntelHex corresponding to result.
253 Note that we start and stop an ICSP session here! This means an
254 existing session will be broken."""
255 readpm_cmd_li = [0x200000, # MOV #addr<23:16>, W0
256 0x880000 | tblpag << 3, # MOV W0, TBLPAG
257 0x200006, # MOV #addr<15:0>, W6
260 0xBA1B96, # TBLRDL [W6], [W7++]
263 0xBADBB6, # TBLRDH.B [W6++], [W7++]
266 0xBADBD6, # TBLRDH.B [++W6], [W7++]
269 0xBA1BB6, # TBLRDL [W6++], [W7++]
272 0xBA1B96, # TBLRDL [W6], [W7++]
275 0xBADBB6, # TBLRDH.B [W6++], [W7++]
278 0xBADBD6, # TBLRDH.B [++W6], [W7++]
281 0xBA0BB6, # TBLRDL [W6++], [W7]
289 print "Reading program memory 0x%06X:0x%06X ..." % ( start_addr, stop_addr )
291 client.writecmd( PICAPP, 0x82, 3, [0x00,0x02,0x04] ) #GOTO 0x200 (reset)
292 client.writecmd( PICAPP, 0x82, 3, [0x00,0x02,0x04] ) #GOTO 0x200 (reset)
293 client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] ) #NOP (pump clock)
295 last_highb = -1 # Only set TBLPAG when needed.
296 packed_instr_list = [0,0,0,0,0,0] # For packing 4 (24-bit) instructions in 6 (16-bit) words
297 for addr in range( start_addr&0xfffff8, stop_addr+8, 8 ):
298 if (addr>>16)&0xff != last_highb:
299 last_highb = (addr>>16)&0xff;
300 specify_addr_cmd = [readpm_cmd_li[0] + ((addr & 0xff0000)>>12),
302 readpm_cmd_li[2] + ((addr & 0xffff)<<4)]
304 specify_addr_cmd = [readpm_cmd_li[2] + ((addr & 0xffff)<<4)]
305 runlist( specify_addr_cmd + readpm_cmd_li[3:] )
307 for reg_num in range(6): # Read W0:5, to get packed instructions
308 packed_instr_list[reg_num] = readreg( reg_num )
309 instr_list = words2instr( packed_instr_list )
311 for offset in range(4): # Print result
312 if addr+offset*2 < start_addr:
314 if addr+offset*2 > stop_addr:
316 dumphex.puts( ((addr+offset*2)&0xffffff)*2,
317 chr(instr_list[offset]&0xff)
318 +chr((instr_list[offset]>>8)&0xff)
319 +chr((instr_list[offset]>>16)&0xff)
322 print "0x%06X 0x%06X" % (addr+offset*2,instr_list[offset])
329 def instr2words( instr_list ):
330 """Convert a list of 4 24-bit instructions to a list of 6 words
333 Returns [-1] on failure."""
334 if len(instr_list) < 4: # Catch mistakes
335 print "Error in instr2words: operand has less than 4 elements."
337 word_list = [0,0,0,0,0,0]
339 word_list[k*3] = instr_list[k*2] & 0xffff
340 word_list[k*3+1] = (instr_list[k*2]>>16)&0xff
341 word_list[k*3+1] |= (instr_list[k*2+1]>>8)&0xff00
342 word_list[k*3+2] = instr_list[k*2+1] & 0xffff
345 def words2instr( word_list ):
346 """4 24-bit instructions from a packing in 6 words (16 bit width).
347 This is the inverse of function instr2words.
349 Returns [-1] on failure."""
350 if len(word_list) < 6: # Catch mistakes
351 print "Error in words2instr: operand has less than 6 elements."
353 instr_list = [0,0,0,0]
355 instr_list[k*2] = word_list[k*3]
356 instr_list[k*2] |= (word_list[k*3+1]&0xff)<<16
357 instr_list[k*2+1] = word_list[k*3+2]
358 instr_list[k*2+1] |= (word_list[k*3+1]&0xff00)<<8
366 if len(sys.argv) == 1:
367 print "Usage: %s [-alt_tblpag] verb [objects]\n" % sys.argv[0]
368 print "%s devid" % sys.argv[0]
369 print "%s read 0x$addr" % sys.argv[0]
370 print "%s dump $foo.hex [0x$start 0x$stop] [pretty]" % sys.argv[0]
371 print "%s config" % sys.argv[0]
372 print "%s reset" % sys.argv[0]
373 print "%s program $foo.hex" % sys.argv[0]
374 print "%s verify $foo.hex" % sys.argv[0]
375 print "%s write 0x$address 0x$value" % sys.argv[0]
376 print "%s write_config 0x$reg_address (or $reg_name) [$0x0000]" % sys.argv[0]
377 print "%s erase [0x$page]" % sys.argv[0] # bulk or page erase
378 print "%s six [instruction]" % sys.argv[0]
379 print "%s sixfile [$foo.txt]" % sys.argv[0]
380 print "%s regout" % sys.argv[0]
382 Note: use - for stdout.
383 use -alt_tblpag for PIC24FJxxx{DA1,DA2,GB2,GA3}xx with tblpag at 0x54
384 Warning: only formally supports dsPIC33F/PIC24H,
385 but read/write flash memory works with PIC24F ...
389 # Initialize and open connection to GoodFET
391 client.verbose = False # Dump activity to terminal
392 client.serInit( timeout=10 ) # UART comm timeout (in seconds)
394 if sys.argv[1] == "-alt_tblpag":
398 # Handle each possible PIC verb in turn
399 if sys.argv[1] == "devid": #0x81
400 print "Requesting Application ID, DEVID and hardware revision..."
402 cmdbuf = PicCmdBuffer(client)
403 cmdbuf.SIX(0x040200, # GOTO 0x200
405 0x200FF0, # MOV #0xff, W0
406 0x880000 | tblpag << 3, # MOV W0, TBLPAG
407 0x200006, # MOV #0x0000, W6
408 0x207847, # MOV #VISI, W7
410 0xBA0B96, # TBLRDL [W6],[W7]
413 devid = cmdbuf.REGOUT()
414 cmdbuf.SIX(0x200026, # MOV #0x0002, W6
416 0xBA0B96, # TBLRDL [W6],[W7]
419 devidrev = cmdbuf.REGOUT()
420 cmdbuf.SIX(0x200800, # MOV #0x80, W0
421 0x880000 | tblpag << 3, # MOV W0, TBLPAG
422 0x207F00, # MOV #0x07F0, W6
424 0xBA0B96, # TBLRDL [W6],[W7]
427 appid = cmdbuf.REGOUT()
428 print "Application ID: 0x%02x" % appid()
429 print "DEVID: 0x%04x (%s)" % (
430 devid(), dev_table.get(devid(), "unknown"))
431 print "Revision: 0x%04x" % devidrev()
433 #print "\n(Note that -1 indicates failure to read a value.)"
435 elif sys.argv[1] == "test":
437 cmdbuf = PicCmdBuffer(client)
438 cmdbuf.SIX(0x2BEEF6, # MOV #0xBEEF, W6
440 0x780B86, # MOV W6, [W7]
443 assert cmdbuf.REGOUT()() == 0xbeef
446 elif sys.argv[1] == "reset":
447 client.writecmd( PICAPP, 0x87, 0 )
449 elif sys.argv[1] == "config": # Dump configuration registers
450 prep_cmd_li = [0x040200, # GOTO 0x0200
452 0x200F80, # MOV #0x00F8, W0
453 0x880000 | tblpag << 3, # MOV W0, TBLPAG
455 0x207847, # MOV #VISI, W7
457 rd_cmd_li = [0xBA0BB6, # TBLRDL [W6++], [W7]
461 print "Dumping configuration registers..."
462 for instr in prep_cmd_li:
463 data = client.writecmd( PICAPP, 0x82, 3, [instr & 0xff,
465 (instr >> 16) & 0xff] )
466 for k in range(12): # twelve configuration registers total
467 for instr in rd_cmd_li:
468 data = client.writecmd( PICAPP, 0x82, 3, [instr & 0xff,
470 (instr >> 16) & 0xff] )
473 if cfg_table.has_key( addr ):
474 print "0x%06X (%s): 0x%02X" % ( addr,
475 cfg_table[addr].ljust(cfg_table["width"]),
478 print "0x%06X: 0x%02X" % ( addr, result )
482 elif sys.argv[1] == "program":
483 if len(sys.argv) != 3:
484 print "Error: an Intel HEX file to load must be given."
488 proghex = IntelHex( sys.argv[2] )
490 print "Error while attempting to read from %s" % sys.argv[2]
492 ph_addrs = proghex.addresses()
494 # Load starting program memory address
495 wr_pm64_li_setaddr = [0x040200, # GOTO 0x0200
497 0x24001A, # MOV $0x4001, W10
498 0x883B0A, # MOV W10, NVMCON
499 0x200000, # + ((addr>>12)&0xff0), # MOV #addr<23:16>, W0
500 0x880000 | tblpag << 3, # MOV W0, TBLPAG
501 0x200007] # + ((addr&0xffff)<<4), # MOV #addr<15:0>, W7
503 # Load 4 instructions into write latches
504 wr_pm64_li_wrlat = [0xEB0300, # CLR W6
506 0xBB0BB6, # TBLWTL [W6++], [W7]
509 0xBBDBB6, # TBLWTH.B [W6++], [W7++]
512 0xBBEBB6, # TBLWTH.B [W6++], [++W7]
515 0xBB1BB6, # TBLWTL [W6++], [W7++]
518 0xBB0BB6, # TBLWTL [W6++], [W7]
521 0xBBDBB6, # TBLWTH.B [W6++], [W7++]
524 0xBBEBB6, # TBLWTH.B [W6++], [++W7]
527 0xBB1BB6, # TBLWTL [W6++], [W7++]
531 wr_pm64_li_wr = [0xA8E761, # BSET NVMCON, #WR
539 for last_code_addr in reversed(ph_addrs):
540 if (last_code_addr>>1) < 0xf80000:
541 last_row_addr = (last_code_addr>>1) & 0xffff80
543 for addr in range((ph_addrs[0]>>1)&0xffff80,last_code_addr+2,128):
544 # Prevent crossing addresses where upper byte
545 # (i.e., address<23:16>) changes.
546 #if addr+126 > 0xffff:
547 # stop_addr = addr | 0xffff
549 # stop_addr = addr+126
551 runlist( wr_pm64_li_setaddr[:4]
552 + [0x200000 + ((addr>>12)&0xff0),
553 wr_pm64_li_setaddr[5],
554 0x200007 + ((addr&0xffff)<<4)] )
556 instr_list = [0,0,0,0]
557 for mid_addr in range(addr,addr+126,8):
558 for offset in range(4):
559 if (mid_addr+offset*2)<<1 not in ph_addrs:
560 instr_list[offset] = 0xffffff
562 instr_list[offset] = proghex[(mid_addr+offset*2)<<1]
563 instr_list[offset] |= proghex[((mid_addr+offset*2)<<1)+1] << 8
564 instr_list[offset] |= proghex[((mid_addr+offset*2)<<1)+2] << 16
565 packed_instr_list = instr2words( instr_list )
566 runlist( [0x200000 + ((packed_instr_list[0]&0xffff)<<4),
567 0x200001 + ((packed_instr_list[1]&0xffff)<<4),
568 0x200002 + ((packed_instr_list[2]&0xffff)<<4),
569 0x200003 + ((packed_instr_list[3]&0xffff)<<4),
570 0x200004 + ((packed_instr_list[4]&0xffff)<<4),
571 0x200005 + ((packed_instr_list[5]&0xffff)<<4)]
574 runlist( wr_pm64_li_wr )
575 status = readNVMCON()
576 while status & 0x8000:
577 client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] )
578 status = readNVMCON()
580 # Configuration registers must be treated separately
581 for addr in ph_addrs[ph_addrs.index(last_code_addr):]:
584 if (addr>>1) > 0xf80017:
586 wr_cfg_li = [0x040200, # GOTO 0x0200
588 0x200007 + ((addr<<3)&0xffff0), # MOV #addr<15:0>, W7
589 0x24000A, # MOV #0x4000, W10
590 0x883B0A, # MOV W10, NVMCON
591 0x200F80, # MOV #0xF8, W0
592 0x880000 | tblpag<< 3, # MOV W0, TBLPAG
593 0x200000 + ((proghex[addr]&0x00ff)<<4), # MOV #new_val<7:0>, W0
594 0xBB0B80, # TBLWTL W0, [W7]
597 0xA8E761, # BSET NVMCON, #WR
603 status = readNVMCON()
604 while status & 0x8000:
605 client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] )
606 status = readNVMCON()
611 elif sys.argv[1] == "verify":
612 if len(sys.argv) != 3:
613 print "Error: an Intel HEX file with which to compare must be given."
617 proghex = IntelHex( sys.argv[2] )
619 print "Error while attempting to read from %s" % sys.argv[2]
622 print "WARNING: verifying config registers not yet supported."
624 for addr in proghex.addresses():
625 if addr % 4 != 0 or (addr>>1) < 0x200:
627 #elif first_addr == None:
628 # first_addr = addr>>1
629 if (addr>>1) >= 0xf80000:
632 dumphex = dump_pm( (proghex.addresses()[0]>>1),
635 # Step through addresses in HEX file and compare to those in target PIC
636 for addr in proghex.addresses():
637 if addr>>1 >= 0xF80000:
638 break # verifying config registers not yet supported
639 # Compare; fail if mismatch
640 if proghex[addr] != dumphex[addr]:
641 addr &= addr&0xfffffffc
642 found_instr = dumphex[addr]
643 found_instr |= dumphex[addr+1]<<8
644 found_instr |= dumphex[addr+2]<<16
645 exp_instr = proghex[addr]
646 exp_instr |= proghex[addr+1]<<8
647 exp_instr |= proghex[addr+2]<<16
648 print "Fail at address 0x%06X: found 0x%06X, expected 0x%06X." % ( addr>>1, found_instr, exp_instr )
651 print "PASSED" # Be verbose.
654 elif sys.argv[1] == "write":
655 if len(sys.argv) != 4:
656 print "Error: an address (in program memory) and\n value (or instruction) to write must be given."
659 addr = int(float.fromhex(sys.argv[2]))
660 new_instr = int(float.fromhex(sys.argv[3]))
663 # new_instr_li.append( int(float.fromhex(sys.argv[k+3])) )
665 #new_words = instr2words( new_instr_li )
667 wr_pm_li = [0x040200, # GOTO 0x0200
670 0x24003A, # MOV $0x4003, W10
671 0x883B0A, # MOV W10, NVMCON
672 0x200000 + ((addr>>12)&0xff0), # MOV #addr<23:16>, W0
673 0x880000 | tblpag << 3, # MOV W0, TBLPAG
674 0x200007 + ((addr&0xffff)<<4), # MOV #addr<15:0>, W7
676 # Here we load the instruction into registers W0:W1
677 0x200000 + ((new_instr&0xffff)<<4),
678 0x200001 + ((new_instr>>12)&0xff0),
679 #0x200000 + ((new_words[0]&0xffff)<<4),
680 #0x200001 + ((new_words[1]&0xffff)<<4),
681 #0x200002 + ((new_words[2]&0xffff)<<4),
682 #0x200003 + ((new_words[3]&0xffff)<<4),
683 #0x200004 + ((new_words[4]&0xffff)<<4),
684 #0x200005 + ((new_words[5]&0xffff)<<4),
688 0xBB0BB6, # TBLWTL [W6++], [W7]
691 0xBB8B96, # TBLWTH [W6], [W7]
692 #0xBBDBB6, # TBLWTH.B [W6++], [W7++]
695 #0xBBEBB6, # TBLWTH.B [W6++], [++W7]
698 #0xBB1BB6, # TBLWTL [W6++], [W7++]
701 #0xBB0BB6, # TBLWTL [W6++], [W7]
704 #0xBBDBB6, # TBLWTH.B [W6++], [W7++]
707 #0xBBEBB6, # TBLWTH.B [W6++], [++W7]
710 #0xBB1BB6, # TBLWTL [W6++], [W7++]
714 0xA8E761, # BSET NVMCON, #WR
723 status = readNVMCON()
724 while status & 0x8000:
725 client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] ) # NOP (pump clock)
726 status = readNVMCON()
730 elif sys.argv[1] == "write_config":
731 if len(sys.argv) < 3:
732 print "Error: please specify the target config register."
734 elif len(sys.argv) == 3:
735 new_val = 0xFF # Assume new value
737 new_val = int(float.fromhex(sys.argv[3]))
739 reg_addr = int(float.fromhex(sys.argv[2]))
741 if sys.argv[2] not in cfg_table.values():
742 print "Given register, %s, not recognized." % sys.argv[2]
744 reg_addr = cfg_table.keys()[cfg_table.values().index(sys.argv[2])]
746 wr_cfg_li = [0x040200, # GOTO 0x0200
748 0x200007 + ((reg_addr&0xffff)<<4), # MOV #addr<15:0>, W7
749 0x24000A, # MOV #0x4000, W10
750 0x883B0A, # MOV W10, NVMCON
751 0x200F80, # MOV #0xF8, W0
752 0x880000 | tblpag << 3, # MOV W0, TBLPAG
753 0x200000 + ((new_val&0xffff)<<4), # MOV #<new_val>, W0
754 0xBB0B80, # TBLWTL W0, [W7]
757 0xA8E761, # BSET NVMCON, #WR
766 status = readNVMCON()
767 while status & 0x8000:
768 client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] ) # NOP (pump clock)
769 status = readNVMCON()
774 elif sys.argv[1] == "read": # Read an address of program memory
777 addr = int(float.fromhex(sys.argv[2]))
779 readpm_cmd_li = [0x040200, # GOTO 0x0200
781 0x200000+((addr & 0xff0000)>>12), # MOV #addr<23:16>, W0
782 0x880000 | tblpag << 3, # MOV W0, TBLPAG
783 0x200006+((addr & 0xffff)<<4), # MOV #addr<15:0>, W6
787 0xBA1B96, # TBLRDL [W6], [W7++]
790 0xBACB96, # TBLRDH.B [W6], [W7]
794 runlist( readpm_cmd_li )
795 loww = readreg(0) # Read W0, which has lower 16 bits
796 highb = readreg(1) # Read W1, which has high 8 bits
797 result = (highb<<16) | loww
799 print "0x%06X: 0x%06X" % ( addr, result )
803 elif sys.argv[1] == "dump": # Read section of program memory
804 if len(sys.argv) < 3:
805 print "Error: please specify file in which to dump program memory."
809 if len(sys.argv) == 6:
814 if len(sys.argv) > 4:
815 start_addr = int(float.fromhex(sys.argv[3]))
816 stop_addr = int(float.fromhex(sys.argv[4]))
818 # Assume all of program memory (including unimplemented sections,
819 # which will be read as zeroes.
823 dumphex = dump_pm( start_addr, stop_addr, print_term )
827 dumphex.tofile( sys.stdout, format="hex" )
829 dumphex.tofile( fname, format="hex" )
832 elif sys.argv[1] == "erase": # Bulk (all program memory) or page erase
834 if len(sys.argv) == 3:
835 addr = int(float.fromhex(sys.argv[2]))
839 if addr is None: # Bulk erase (all of program memory)
840 erase_cmd_li = [0x040200, # GOTO 0x0200
842 0x2404FA, # MOV $0x404F, W10
843 0x883B0A, # MOV W10, NVMCON
844 0xA8E761, # BSET NVMCON, #WR
850 print "Erasing page of 0x%06X" % addr
851 erase_cmd_li = [0x040200, # GOTO 0x0200
853 0x24042A, # MOV $0x4042, W10
854 0x883B0A, # MOV W10, NVMCON
855 0x200000+((addr & 0xff0000)>>12), # MOV #addr<23:16>, W0
856 0x880000 | tblpag << 3, # MOV W0, TBLPAG
857 0x200001+((addr&0xffff)<<4), # MOV addr<15:0>, W1
859 0xBB0881, # TBLTWL W1, [W1]
862 0xA8E761, # BSET NVMCON, #WR
867 # Note that page alignment (effectively, bitmask of 0xffff80
868 # applied to given program memory address) seems to be
869 # enforced by hardware.
873 runlist( erase_cmd_li )
874 status = readNVMCON()
875 while status & 0x8000:
876 client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] ) # NOP (pump clock)
877 status = readNVMCON()
881 elif sys.argv[1] == "six": #0x82
884 if len(sys.argv) < 3:
885 instr = 0x000000 # Assume nop
887 instr = int(float.fromhex(sys.argv[2]))
888 print "Loading 0x%06X for execution..." % instr
889 data = client.writecmd( PICAPP, 0x82, 3, [instr & 0xff,
891 (instr >> 16) & 0xff] )
892 print "Executing (by loading nop; pumping clock)..."
893 data = client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] )
899 elif sys.argv[1] == "sixfile": #0x82 (repeated for each instruction in file)
902 if len(sys.argv) < 3:
903 print "Warning: no file given; trying cmd.txt..."
909 instrfile = open( fname, "r" )
911 print "Failed to open file %s for reading." % fname
915 print "Opened file %s. Consecutively reading commmands..." % fname
916 for line in instrfile:
920 instr = int(float.fromhex(words[0]))
922 print "Warning: invalid instruction found at offset %d." % instrfile.tell()
924 print "Loading 0x%06X for execution..." % instr
925 data = client.writecmd( PICAPP, 0x82, 3, [instr & 0xff,
927 (instr >> 16) & 0xff] )
929 # print "Warning: empty line found at offset %d." % instrfile.tell()
931 print "Error: exception caught while reading file %s." % fname
938 print "Loading nop, pumping clock (to finish execution)..."
939 data = client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] )
945 elif sys.argv[1] == "regout": #0x83
948 print "Reading VISI register..."
949 data = client.writecmd( PICAPP, 0x83, 0 )
950 result = ord(data[0])
951 result |= ord(data[1]) << 8
952 print "VISI: 0x%04X" % result
957 print "Unrecognized verb: %s" % sys.argv[1]