5158912f6f12b833adb8ca4fdda58d5d379c4db4
[goodfet] / client / goodfet.pic
1 #!/usr/bin/env python
2 # PIC client (currently only supports dsPIC33F/PIC24H.)
3 #
4 # Note that a verify operation only considers addresses specified in
5 # the given Intel hex file ($foo.hex).
6
7 # sixfile expects a plain text file, one instruction per line.
8 #
9 #
10 # Scott Livingston  <slivingston at caltech.edu>
11 #
12 # March, April 2010.
13
14
15 import sys
16 import time
17
18 from GoodFET import GoodFET
19 from intelhex import IntelHex
20
21 #############
22 # Some constants (not really immutable...)
23 #############
24 PICAPP = 0x34
25 MONITORAPP = 0x00
26 NOK = 0x7E
27 dev_table = { 0x00EE : "dsPIC33FJ128GP708",
28               0x00EF : "dsPIC33FJ128GP710" }
29 cfg_table = { 0xF80000 : "FBS",
30               0xF80002 : "FSS",
31               0xF80004 : "FGS",
32               0xF80006 : "FOSCSEL",
33               0xF80008 : "FOSC",
34               0xF8000A : "FWDT",
35               0xF8000C : "FPOR",
36               0xF8000E : "FICD",
37               0xF80010 : "FUID0",
38               0xF80012 : "FUID1",
39               0xF80014 : "FUID2",
40               0xF80016 : "FUID3",
41               "width" : 7 } # For pretty printing.
42
43 #cfg_bitmask_table = { 
44
45
46 #############
47 # Functions:
48 #############
49
50 def runlist( cmd_li ):
51     """Load (and execute) a given list of instructions.
52 Assumes ICSP session already started."""
53     cmd_byte_li = build_instr_stream( cmd_li )
54     data = client.writecmd( PICAPP, 0x86, len(cmd_byte_li), cmd_byte_li )
55     if client.app == PICAPP and client.verb == 0x86 and client.count != len(cmd_byte_li):
56         print "Error: incomplete execution of sixlist.\nOnly %d instructions run." % (client.count/3)
57         stopICSP()
58         exit(-1)
59     elif client.app == 0xff and client.verb == 0xff: # GoodFET debugstr
60         print "Error (in runlist): failed transaction; aborting."
61         stopICSP()
62         exit(-1)
63
64 def build_instr_stream( cmd_li ):
65     """Given a list of instruction words, returns a list of bytes of
66 the same, in little endian ordering."""
67     cmd_byte_li = []
68     for instr in cmd_li:
69         cmd_byte_li += [instr & 0xff,
70                         (instr >> 8) & 0xff,
71                         (instr >> 16) & 0xff]
72     return cmd_byte_li
73
74 def readreg( reg_num ):
75     """Read contents of a working register (i.e. W0, W1, ..., W15)."""
76     instr = 0x883C20+(reg_num&0xf)
77     client.writecmd( PICAPP, 0x82, 3, [instr & 0xff,
78                                        (instr >> 8) & 0xff,
79                                        (instr >> 16) & 0xff] )
80     client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] ) # NOP (pump clock)
81     return readVISI()
82
83 def readVISI():
84     """Read VISI register; assumes ICSP session already started."""
85     data = client.writecmd( PICAPP, 0x83, 0 )
86     result = ord(data[0])
87     result |= ord(data[1]) << 8
88     return result
89
90 def readNVMCON():
91     """Read NVMCON register; assumes ICSP session already started."""
92     rd_nvmcon_li = [0x803B00, # MOV NVMCON, W0
93                     0x883C20, # MOV W0, VISI
94                     0x000000, # NOP
95                     0x000000] # NOP
96     runlist( rd_nvmcon_li )
97     return readVISI()
98
99 def startICSP():
100     #print "Starting dsPIC33F/PIC24H ICSP session..."
101     data = client.writecmd( PICAPP, 0x84, 0 )
102
103 def stopICSP():
104     #print "Stopping dsPIC33F/PIC24H ICSP session..."
105     data = client.writecmd( PICAPP, 0x85, 0 )
106
107 def dumpVISI():
108     """Read and print VISI register to stdout; assumes ICSP session already started."""
109     print "Reading VISI register..."
110     result = readVISI()
111     print "VISI: 0x%04X" % result
112
113 def instr2words( instr_list ):
114     """Convert a list of 4 24-bit instructions to a list of 6 words
115 (16-bit width).
116
117 Returns [-1] on failure."""
118     if len(instr_list) < 4: # Catch mistakes
119         print "Error in instr2words: operand has less than 4 elements."
120         return [-1]
121     word_list = [0,0,0,0,0,0]
122     for k in [0,1]:
123         word_list[k*3] = instr_list[k*2] & 0xffff
124         word_list[k*3+1] = (instr_list[k*2]>>16)&0xff
125         word_list[k*3+1] |= (instr_list[k*2+1]>>8)&0xff00
126         word_list[k*3+2] = instr_list[k*2+1] & 0xffff
127     return word_list
128
129 def words2instr( word_list ):
130     """4 24-bit instructions from a packing in 6 words (16 bit width).
131 This is the inverse of function instr2words.
132
133 Returns [-1] on failure."""
134     if len(word_list) < 6: # Catch mistakes
135         print "Error in words2instr: operand has less than 6 elements."
136         return [-1]
137     instr_list = [0,0,0,0]
138     for k in [0,1]:
139         instr_list[k*2] = word_list[k*3]
140         instr_list[k*2] |= (word_list[k*3+1]&0xff)<<16
141         instr_list[k*2+1] = word_list[k*3+2]
142         instr_list[k*2+1] |= (word_list[k*3+1]&0xff00)<<8
143     return instr_list
144
145
146 #############
147 # Main entry: 
148 #############
149
150 if len(sys.argv) == 1:
151     print "Usage: %s verb [objects]\n" % sys.argv[0]
152     print "%s devid" % sys.argv[0]
153     print "%s read 0x$addr" % sys.argv[0]
154     print "%s dump $foo.hex [0x$start 0x$stop] [pretty]" % sys.argv[0]
155     print "%s config" % sys.argv[0]
156     print "%s program $foo.hex" % sys.argv[0]
157     print "%s verify $foo.hex" % sys.argv[0]
158     print "%s write 0x$address 0x$value" % sys.argv[0]
159     print "%s write_config 0x$reg_address (or $reg_name) [$0x0000]" % sys.argv[0]
160     print "%s erase [0x$page]" % sys.argv[0] # bulk or page erase
161     print "%s six [instruction]" % sys.argv[0]
162     print "%s sixfile [$foo.txt]" % sys.argv[0]
163     print "%s regout" % sys.argv[0]
164     print """
165 Note: use - for stdout.
166 Warning: only supports dsPIC33F/PIC24H (maybe)...
167 """
168     sys.exit()
169
170 # Initialize and open connection to GoodFET
171 client = GoodFET()
172 client.verbose = False # Dump activity to terminal
173 client.serInit( timeout=10 ) # UART comm timeout (in seconds)
174
175
176 # Handle each possible PIC verb in turn
177
178 if sys.argv[1] == "devid": #0x81
179     print "Requesting Application ID, DEVID and hardware revision..."
180     data = client.writecmd( PICAPP, 0x81, 0 )
181     
182     if len(data) > 0:
183         appid = ord(data[0])
184     else:
185         appid = -1
186     if len(data) > 2:
187         devid = ord(data[1]) + (ord(data[2]) << 8)
188     else:
189         devid = -1
190     if len(data) > 4:
191         hwrev = ord(data[3]) + (ord(data[4]) << 8)
192     else:
193         hwrev = -1
194     print "Application ID:   0x%02X" % appid
195     if dev_table.has_key( devid ):
196         print "DEVID:          0x%04X  (%s)" % ( devid, dev_table[devid] )
197     else:
198         print "DEVID:          0x%04X  (unknown)" %  devid
199     print "revision:       0x%04X"% hwrev
200     #print "\n(Note that -1 indicates failure to read a value.)"
201
202 elif sys.argv[1] == "config": # Dump configuration registers
203     prep_cmd_li = [0x040200, # GOTO 0x0200
204                    0x040200, # GOTO 0x0200
205                    0x000000, # NOP
206                    0x200F80, # MOV #0x00F8, W0
207                    0x880190, # MOV W0, TBLPAG
208                    0xEB0300, # CLR W6
209                    0x207847, # MOV #VISI, W7
210                    0x000000] # NOP
211     rd_cmd_li = [0xBA0BB6, # TBLRDL [W6++], [W7]
212                  0x000000, # NOP
213                  0x000000] # NOP
214     startICSP()
215     print "Dumping configuration registers..."
216     for instr in prep_cmd_li:
217         data = client.writecmd( PICAPP, 0x82, 3, [instr & 0xff,
218                                                   (instr >> 8) & 0xff,
219                                                   (instr >> 16) & 0xff] )
220     for k in range(12): # twelve configuration registers total
221         for instr in rd_cmd_li:
222             data = client.writecmd( PICAPP, 0x82, 3, [instr & 0xff,
223                                                   (instr >> 8) & 0xff,
224                                                   (instr >> 16) & 0xff] )
225         result = readVISI()
226         addr = 0xF80000+k*2
227         if cfg_table.has_key( addr ):
228             print "0x%06X (%s): 0x%04X" % ( addr,
229                                             cfg_table[addr].ljust(cfg_table["width"]),
230                                             result )
231         else:
232             print "0x%06X: 0x%04X" % ( addr, result )
233
234     stopICSP()
235
236 elif sys.argv[1] == "program":
237     if len(sys.argv) != 3:
238         print "Error: an Intel HEX file to load must be given."
239         exit(1)
240
241     try:
242         proghex = IntelHex( sys.argv[2] )
243     except IOError:
244         print "Error while attempting to read from %s" % sys.argv[2]
245         exit(-1)
246
247     wr_pm_li = [0x040200, # GOTO 0x0200
248                 0x040200, # GOTO 0x0200
249                 0x000000, # NOP
250
251                 0x24003A, # MOV $0x4003, W10
252                 0x883B0A, # MOV W10, NVMCON
253                 
254                 0x200000,# + ((addr>>12)&0xff0),  # MOV #addr<23:16>, W0
255                 0x880190, # MOV W0, TBLPAG
256                 0x200007,# + ((addr&0xffff)<<4), # MOV #addr<15:0>, W7
257
258                 # Here we load the instruction into registers W0:W1
259                 0x200000,# + ((new_words[0]&0xffff)<<4),
260                 0x200001,# + ((new_words[1]&0xffff)<<4),
261
262                 0xEB0300, # CLR W6
263                 0x000000, # NOP
264                 0xBB0BB6, # TBLWTL [W6++], [W7]
265                 0x000000, # NOP
266                 0x000000, # NOP
267                 0xBBDBB6, # TBLWTH.B [W6++], [W7++]
268                 0x000000, # NOP
269                 0x000000, # NOP
270
271                 0xA8E761, # BSET NVMCON, #WR
272                 0x000000, # NOP
273                 0x000000, # NOP
274                 0x000000, # NOP
275                 0x000000] # NOP
276
277     startICSP()
278
279     for addr in proghex.addresses():
280         # Ignore non-aligned steps
281         if addr % 4 != 0:
282             continue
283
284         # Configuration registers must be treated separately
285         if (addr>>1) >= 0xf80000 and (addr>>1) <= 0xf80017:
286             wr_cfg_li = [0x040200, # GOTO 0x0200
287                          0x040200, # GOTO 0x0200
288                          0x000000, # NOP
289                          0x200007 + ((addr<<3)&0xffff0), # MOV #addr<15:0>, W7
290                          0x24000A, # MOV #0x4000, W10
291                          0x883B0A, # MOV W10, NVMCON
292                          0x200F80, # MOV #0xF8, W0
293                          0x880190, # MOV W0, TBLPAG
294                          0x200000 + ((proghex[addr]&0x00ff)<<4), # MOV #new_val<7:0>, W0
295                          0xBB0B80, # TBLWTL W0, [W7]
296                          0x000000, # NOP
297                          0x000000, # NOP
298                          0xA8E761, # BSET NVMCON, #WR
299                          0x000000, # NOP
300                          0x000000, # NOP
301                          0x000000, # NOP
302                          0x000000] # NOP
303             runlist( wr_cfg_li )
304             status = readNVMCON()
305             while status & 0x8000:
306                 client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] )
307                 status = readNVMCON()
308             continue
309
310         # Build instruction from 3 separate bytes
311         instr = proghex[addr]
312         instr |= proghex[addr+1] << 8
313         instr |= proghex[addr+2] << 16
314
315         # Change HEX file address to actual program memory address
316         addr_pm = addr >> 1
317
318         # Program this instruction word
319         addr_highb_cmd  = 0x200000 + ((addr_pm>>12)&0xff0)
320         addr_loww_cmd   = 0x200007 + ((addr_pm&0xffff)<<4)
321         instr_loww_cmd  = 0x200000 + ((instr&0xffff)<<4)
322         instr_highb_cmd = 0x200001 + ((instr>>12)&0xff0)
323         runlist( wr_pm_li[:5] + [addr_highb_cmd] + [wr_pm_li[6]]
324                  + [addr_loww_cmd,
325                     instr_loww_cmd, instr_highb_cmd]
326                  + wr_pm_li[10:] )
327         status = readNVMCON()
328         while status & 0x8000:
329             client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] )
330             status = readNVMCON()
331
332     stopICSP()
333
334
335 elif sys.argv[1] == "verify":
336     if len(sys.argv) != 3:
337         print "Error: an Intel HEX file with which to compare must be given."
338         exit(1)
339
340     try:
341         proghex = IntelHex( sys.argv[2] )
342     except IOError:
343         print "Error while attempting to read from %s" % sys.argv[2]
344         exit(-1)
345
346     readpm_cmd_li = [0x040200, # GOTO 0x0200
347                      0x040200, # GOTO 0x0200
348                      0x000000, # NOP
349                      0x200000, # MOV #addr_pm<23:16>, W0
350                      0x880190, # MOV W0, TBLPAG
351                      0x200006, # MOV #addr_pm<15:0>, W6
352                      0xEB0380, # CLR W7
353                      0xEB0080, # CLR W1
354                      0x000000, # NOP
355                      0xBA1B96, # TBLRDL [W6], [W7++]
356                      0x000000, # NOP
357                      0x000000, # NOP
358                      0xBACB96, # TBLRDH.B [W6], [W7]
359                      0x000000, # NOP
360                      0x000000] # NOP
361
362     print "WARNING: verifying config registers not yet supported."
363
364     startICSP()
365
366     # Step through addresses in HEX file and compare to those in target PIC
367     for addr in proghex.addresses():
368         # Ignore non-aligned steps
369         if addr % 4 != 0:
370             continue
371
372         # Configuration registers must be treated separately
373         if (addr>>1) >= 0xf80000 and (addr>>1) <= 0xf80017:
374             # Need to read datasheets to see which bits are masked.
375             # Then add dictionary to handle this.
376             # (Straightforward but tedious.)
377             continue
378         else: 
379             # Build instruction from 3 separate bytes
380             instr = proghex[addr]
381             instr |= proghex[addr+1] << 8
382             instr |= proghex[addr+2] << 16
383
384         # Change HEX file address to actual program memory address
385         addr_pm = addr >> 1
386         
387         runlist( readpm_cmd_li[:3] + [readpm_cmd_li[3]+((addr_pm&0xff0000)>>12)]
388                  + [readpm_cmd_li[4]] + [readpm_cmd_li[5]+((addr_pm&0xffff)<<4)]
389                  + readpm_cmd_li[6:] )
390         loww = readreg(0)  # Read W0, which has lower 16 bits
391         highb = readreg(1) # Read W1, which has high 8 bits
392         result = (highb<<16) | loww
393         
394         # Compare; fail if mismatch
395         if instr != result:
396             print "Fail at address 0x%06X: found 0x%06X, expected 0x%06X." % (addr_pm, result, instr )
397             stopICSP()
398             exit(-1)
399
400     stopICSP()
401
402     print "PASSED" # Be verbose.
403
404
405 elif sys.argv[1] == "write":
406     if len(sys.argv) != 4:
407         print "Error: an address (in program memory) and\n value (or instruction) to write must be given."
408         exit(1)
409     
410     addr = int(float.fromhex(sys.argv[2]))
411     new_instr = int(float.fromhex(sys.argv[3]))
412     #new_instr_li = []
413     #for k in range(4):
414     #    new_instr_li.append( int(float.fromhex(sys.argv[k+3])) )
415
416     #new_words = instr2words( new_instr_li )
417         
418     wr_pm_li = [0x040200, # GOTO 0x0200
419                 0x040200, # GOTO 0x0200
420                 0x000000, # NOP
421
422                 0x24003A, # MOV $0x4003, W10
423                 0x883B0A, # MOV W10, NVMCON
424                 0x200000 + ((addr>>12)&0xff0),  # MOV #addr<23:16>, W0
425                 0x880190, # MOV W0, TBLPAG
426                 0x200007 + ((addr&0xffff)<<4), # MOV #addr<15:0>, W7
427
428                 # Here we load the instruction into registers W0:W1
429                 0x200000 + ((new_instr&0xffff)<<4),
430                 0x200001 + ((new_instr>>12)&0xff0),
431                 #0x200000 + ((new_words[0]&0xffff)<<4),
432                 #0x200001 + ((new_words[1]&0xffff)<<4),
433                 #0x200002 + ((new_words[2]&0xffff)<<4), 
434                 #0x200003 + ((new_words[3]&0xffff)<<4),
435                 #0x200004 + ((new_words[4]&0xffff)<<4),
436                 #0x200005 + ((new_words[5]&0xffff)<<4),
437
438                 0xEB0300, # CLR W6
439                 0x000000, # NOP
440                 0xBB0BB6, # TBLWTL [W6++], [W7]
441                 0x000000, # NOP
442                 0x000000, # NOP
443                 0xBB8B96, # TBLWTH [W6], [W7]
444                 #0xBBDBB6, # TBLWTH.B [W6++], [W7++]
445                 0x000000, # NOP
446                 0x000000, # NOP
447                 #0xBBEBB6, # TBLWTH.B [W6++], [++W7]
448                 #0x000000, # NOP
449                 #0x000000, # NOP
450                 #0xBB1BB6, # TBLWTL [W6++], [W7++]
451                 #0x000000, # NOP
452                 #0x000000, # NOP
453                 #0xBB0BB6, # TBLWTL [W6++], [W7]
454                 #0x000000, # NOP
455                 #0x000000, # NOP
456                 #0xBBDBB6, # TBLWTH.B [W6++], [W7++]
457                 #0x000000, # NOP
458                 #0x000000, # NOP
459                 #0xBBEBB6, # TBLWTH.B [W6++], [++W7]
460                 #0x000000, # NOP
461                 #0x000000, # NOP
462                 #0xBB1BB6, # TBLWTL [W6++], [W7++]
463                 #0x000000, # NOP
464                 #0x000000, # NOP
465                 
466                 0xA8E761, # BSET NVMCON, #WR
467                 0x000000, # NOP
468                 0x000000, # NOP
469                 0x000000, # NOP
470                 0x000000] # NOP
471     
472     startICSP()
473
474     runlist( wr_pm_li )
475     status = readNVMCON()
476     while status & 0x8000:
477         client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] ) # NOP (pump clock)
478         status = readNVMCON()
479
480     stopICSP()
481
482 elif sys.argv[1] == "write_config":
483     if len(sys.argv) < 3:
484         print "Error: please specify the target config register."
485         exit(1)
486     elif len(sys.argv) == 3:
487         new_val = 0xFF # Assume new value
488     else:
489         new_val = int(float.fromhex(sys.argv[3]))
490     try:
491         reg_addr = int(float.fromhex(sys.argv[2]))
492     except ValueError:
493         if sys.argv[2] not in cfg_table.values():
494             print "Given register, %s, not recognized." % sys.argv[2]
495             exit(1)
496         reg_addr = cfg_table.keys()[cfg_table.values().index(sys.argv[2])]
497     
498     wr_cfg_li = [0x040200, # GOTO 0x0200
499                  0x040200, # GOTO 0x0200
500                  0x000000, # NOP
501                  0x200007 + ((reg_addr&0xffff)<<4), # MOV #addr<15:0>, W7
502                  0x24000A, # MOV #0x4000, W10
503                  0x883B0A, # MOV W10, NVMCON
504                  0x200F80, # MOV #0xF8, W0
505                  0x880190, # MOV W0, TBLPAG
506                  0x200000 + ((new_val&0xffff)<<4), # MOV #<new_val>, W0
507                  0xBB0B80, # TBLWTL W0, [W7]
508                  0x000000, # NOP
509                  0x000000, # NOP
510                  0xA8E761, # BSET NVMCON, #WR
511                  0x000000, # NOP
512                  0x000000, # NOP
513                  0x000000, # NOP
514                  0x000000] # NOP
515
516     startICSP()
517
518     runlist( wr_cfg_li )
519     status = readNVMCON()
520     while status & 0x8000:
521         client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] ) # NOP (pump clock)
522         status = readNVMCON()
523
524     stopICSP()
525         
526
527 elif sys.argv[1] == "read": # Read an address of program memory
528     startICSP()
529
530     addr = int(float.fromhex(sys.argv[2]))
531
532     readpm_cmd_li = [0x040200,                         # GOTO 0x0200
533                      0x040200,                         # GOTO 0x0200
534                      0x000000,                         # NOP
535                      0x200000+((addr & 0xff0000)>>12), # MOV #addr<23:16>, W0
536                      0x880190,                         # MOV W0, TBLPAG
537                      0x200006+((addr & 0xffff)<<4),    # MOV #addr<15:0>, W6
538                      0xEB0380,                         # CLR W7
539                      0xEB0080,                         # CLR W1
540                      0x000000,                         # NOP
541                      0xBA1B96,                         # TBLRDL [W6], [W7++]
542                      0x000000,                         # NOP
543                      0x000000,                         # NOP
544                      0xBACB96,                         # TBLRDH.B [W6], [W7]
545                      0x000000,                         # NOP
546                      0x000000]                         # NOP
547                      
548     runlist( readpm_cmd_li )
549     loww = readreg(0)  # Read W0, which has lower 16 bits
550     highb = readreg(1) # Read W1, which has high 8 bits
551     result = (highb<<16) | loww
552     
553     print "0x%06X: 0x%06X" % ( addr, result )
554
555     stopICSP()
556
557 elif sys.argv[1] == "dump": # Read section of program memory
558     if len(sys.argv) < 3:
559         print "Error: please specify file in which to dump program memory."
560         exit(1)
561     fname = sys.argv[2]
562
563     if len(sys.argv) == 6:
564         print_term = True
565     else:
566         print_term = False
567         
568     if len(sys.argv) > 4:
569         start_addr = int(float.fromhex(sys.argv[3]))
570         stop_addr  = int(float.fromhex(sys.argv[4]))
571     else:
572         # Assume all of program memory (including unimplemented sections,
573         # which will be read as zeroes.
574         start_addr = 0x0
575         stop_addr = 0xFFFFFE
576
577     readpm_cmd_li = [0x200000, # MOV #addr<23:16>, W0
578                      0x880190, # MOV W0, TBLPAG
579                      0x200006, # MOV #addr<15:0>, W6
580                      0xEB0380, # CLR W7
581                      0x000000, # NOP
582                      0xBA1B96, # TBLRDL [W6], [W7++]
583                      0x000000, # NOP
584                      0x000000, # NOP
585                      0xBADBB6, # TBLRDH.B [W6++], [W7++]
586                      0x000000, # NOP
587                      0x000000, # NOP
588                      0xBADBD6, # TBLRDH.B [++W6], [W7++]
589                      0x000000, # NOP
590                      0x000000, # NOP
591                      0xBA1BB6, # TBLRDL [W6++], [W7++]
592                      0x000000, # NOP
593                      0x000000, # NOP
594                      0xBA1B96, # TBLRDL [W6], [W7++]
595                      0x000000, # NOP
596                      0x000000, # NOP
597                      0xBADBB6, # TBLRDH.B [W6++], [W7++]
598                      0x000000, # NOP
599                      0x000000, # NOP
600                      0xBADBD6, # TBLRDH.B [++W6], [W7++]
601                      0x000000, # NOP
602                      0x000000, # NOP
603                      0xBA0BB6, # TBLRDL [W6++], [W7]
604                      0x000000, # NOP
605                      0x000000] # NOP
606
607     dumphex = IntelHex()
608
609     startICSP()
610
611     print "Reading program memory 0x%06X:0x%06X ..." % ( start_addr, stop_addr )
612     # Prep device
613     client.writecmd( PICAPP, 0x82, 3, [0x00,0x02,0x04] ) #GOTO 0x200 (reset)
614     client.writecmd( PICAPP, 0x82, 3, [0x00,0x02,0x04] ) #GOTO 0x200 (reset)
615     client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] ) #NOP (pump clock)
616
617     last_highb = -1 # Only set TBLPAG when needed.
618     packed_instr_list = [0,0,0,0,0,0] # For packing 4 (24-bit) instructions in 6 (16-bit) words
619     for addr in range( start_addr&0xfffff8, stop_addr+8, 8 ):
620         if (addr>>16)&0xff != last_highb: 
621             last_highb = (addr>>16)&0xff;
622             specify_addr_cmd = [readpm_cmd_li[0] + ((addr & 0xff0000)>>12),
623                                 readpm_cmd_li[1],
624                                 readpm_cmd_li[2] + ((addr & 0xffff)<<4)]
625         else:
626             specify_addr_cmd = [readpm_cmd_li[2] + ((addr & 0xffff)<<4)]
627         runlist( specify_addr_cmd + readpm_cmd_li[3:] )
628
629         for reg_num in range(6): # Read W0:5, to get packed instructions
630             packed_instr_list[reg_num] = readreg( reg_num )
631         instr_list = words2instr( packed_instr_list )
632
633         for offset in range(4): # Print result
634             if addr+offset*2 < start_addr:
635                 continue
636             if addr+offset*2 > stop_addr:
637                 break
638             dumphex.puts( ((addr+offset*2)&0xffffff)*2,
639                           chr(instr_list[offset]&0xff)
640                           +chr((instr_list[offset]>>8)&0xff)
641                           +chr((instr_list[offset]>>16)&0xff)
642                           +chr(0) )
643             if print_term:
644                 print "0x%06X    0x%06X" % (addr+offset*2,instr_list[offset])
645     
646     if not print_term:
647         if fname == "-":
648             dumphex.tofile( sys.stdout, format="hex" )
649         else:
650             dumphex.tofile( fname, format="hex" )
651
652     stopICSP()
653
654 elif sys.argv[1] == "erase": # Bulk (all program memory) or page erase
655
656     if len(sys.argv) == 3:
657         addr = int(float.fromhex(sys.argv[2]))
658     else:
659         addr = None
660
661     if addr is None: # Bulk erase (all of program memory)
662         erase_cmd_li = [0x040200, # GOTO 0x0200
663                         0x040200, # GOTO 0x0200
664                         0x000000, # NOP
665                         0x2404FA, # MOV $0x404F, W10
666                         0x883B0A, # MOV W10, NVMCON
667                         0xA8E761, # BSET NVMCON, #WR
668                         0x000000, # NOP
669                         0x000000, # NOP
670                         0x000000, # NOP
671                         0x000000] # NOP
672     else: # Page erase
673         print "Erasing page of 0x%06X" % addr
674         erase_cmd_li = [0x040200, # GOTO 0x0200
675                         0x040200, # GOTO 0x0200
676                         0x000000, # NOP
677                         0x24042A, # MOV $0x4042, W10
678                         0x883B0A, # MOV W10, NVMCON
679                         0x200000+((addr & 0xff0000)>>12), # MOV #addr<23:16>, W0
680                         0x880190, # MOV W0, TBLPAG
681                         0x200001+((addr&0xffff)<<4), # MOV addr<15:0>, W1
682                         0x000000, # NOP
683                         0xBB0881, # TBLTWL W1, [W1]
684                         0x000000, # NOP
685                         0x000000, # NOP
686                         0xA8E761, # BSET NVMCON, #WR
687                         0x000000, # NOP
688                         0x000000, # NOP
689                         0x000000, # NOP
690                         0x000000] # NOP
691         # Note that page alignment (effectively, bitmask of 0xffff80
692         # applied to given program memory address) seems to be
693         # enforced by hardware.
694
695     startICSP()
696
697     runlist( erase_cmd_li )
698     status = readNVMCON()
699     while status & 0x8000:
700         client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] ) # NOP (pump clock)
701         status = readNVMCON()
702
703     stopICSP()
704
705 elif sys.argv[1] == "six": #0x82
706     startICSP()
707     
708     if len(sys.argv) < 3:
709         instr = 0x000000 # Assume nop
710     else:
711         instr = int(float.fromhex(sys.argv[2]))
712     print "Loading 0x%06X for execution..." % instr
713     data = client.writecmd( PICAPP, 0x82, 3, [instr & 0xff,
714                                        (instr >> 8) & 0xff,
715                                        (instr >> 16) & 0xff] )
716     print "Executing (by loading nop; pumping clock)..."
717     data = client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] )
718
719     dumpVISI()
720
721     stopICSP()
722
723 elif sys.argv[1] == "sixfile": #0x82 (repeated for each instruction in file)
724     startICSP()
725
726     if len(sys.argv) < 3:
727         print "Warning: no file given; trying cmd.txt..."
728         fname = "cmd.txt"
729     else:
730         fname = sys.argv[2]
731
732     try:
733         instrfile = open( fname, "r" )
734     except:
735         print "Failed to open file %s for reading." % fname
736         exit(-1)
737
738     try:
739         print "Opened file %s. Consecutively reading commmands..." % fname
740         for line in instrfile:
741             words = line.split()
742             if len(words) > 0:
743                 try:
744                     instr = int(float.fromhex(words[0]))
745                 except ValueError:
746                     print "Warning: invalid instruction found at offset %d." % instrfile.tell()
747                     continue
748                 print "Loading 0x%06X for execution..." % instr
749                 data = client.writecmd( PICAPP, 0x82, 3, [instr & 0xff,
750                                                    (instr >> 8) & 0xff,
751                                                    (instr >> 16) & 0xff] )
752             #else:
753             #    print "Warning: empty line found at offset %d." % instrfile.tell()
754     except:
755         print "Error: exception caught while reading file %s." % fname
756         instrfile.close()
757         stopICSP()
758         exit(-1)
759
760     instrfile.close()
761     
762     print "Loading nop, pumping clock (to finish execution)..."
763     data = client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] )
764     
765     dumpVISI()
766
767     stopICSP()
768
769 elif sys.argv[1] == "regout": #0x83
770     startICSP()
771
772     print "Reading VISI register..."
773     data = client.writecmd( PICAPP, 0x83, 0 )
774     result = ord(data[0])
775     result |= ord(data[1]) << 8
776     print "VISI: 0x%04X" % result
777
778     stopICSP()
779
780 else:
781     print "Unrecognized verb: %s" % sys.argv[1]
782     sys.exit(-1)
783