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