updates.
[goodfet] / client / GoodFETARM.py
1 #!/usr/bin/env python
2 # GoodFET ARM Client Library
3
4 #
5 # Good luck with alpha / beta code.
6 # Contributions and bug reports welcome.
7 #
8
9 import sys, binascii, struct
10 import atlasutils.smartprint as asp
11 from GoodFET import GoodFET
12 from intelhex import IntelHex
13
14 platforms = {
15     "at91sam7": {0:(0x100000, "Flash before remap, SRAM after remap"),
16                  0x100000: (0x100000, "Internal Flash"),
17                  0x200000: (0x100000, "Internal SRAM"),
18                  },
19     }
20                 
21
22 #Global Commands
23 READ  = 0x00
24 WRITE = 0x01
25 PEEK  = 0x02
26 POKE  = 0x03
27 SETUP = 0x10
28 START = 0x20
29 STOP  = 0x21
30 CALL  = 0x30
31 EXEC  = 0x31
32 NOK   = 0x7E
33 OK    = 0x7F
34
35 # ARM7TDMI JTAG commands
36 GET_DEBUG_CTRL      = 0x80
37 SET_DEBUG_CTRL      = 0x81
38 GET_PC              = 0x82
39 SET_PC              = 0x83
40 GET_CHIP_ID         = 0x84
41 GET_DEBUG_STATE     = 0x85
42 GET_WATCHPOINT      = 0x86
43 SET_WATCHPOINT      = 0x87
44 GET_REGISTER        = 0x88
45 SET_REGISTER        = 0x89
46 GET_REGISTERS       = 0x8a
47 SET_REGISTERS       = 0x8b
48 HALTCPU             = 0x8c
49 RESUMECPU           = 0x8d
50 DEBUG_INSTR         = 0x8e      #
51 STEP_INSTR          = 0x8f      #
52 STEP_REPLACE        = 0x90      #
53 PROGRAM_FLASH       = 0x95
54 LOCKCHIP            = 0x96      # ??
55 CHIP_ERASE          = 0x97      # can do?
56 # Really ARM specific stuff
57 GET_CPSR            = 0x98
58 SET_CPSR            = 0x99
59 GET_SPSR            = 0x9a
60 SET_SPSR            = 0x9b
61 SET_MODE_THUMB      = 0x9c
62 SET_MODE_ARM        = 0x9d
63 SET_IR              = 0x9e
64 WAIT_DBG            = 0x9f
65 SHIFT_DR            = 0xa0
66 SETWATCH0           = 0xa1
67 SETWATCH1           = 0xa2
68
69 PM_usr = 0b10000
70 PM_fiq = 0b10001
71 PM_irq = 0b10010
72 PM_svc = 0b10011
73 PM_abt = 0b10111
74 PM_und = 0b11011
75 PM_sys = 0b11111
76 proc_modes = {
77     PM_usr: ("User Processor Mode", "usr", "Normal program execution mode"),
78     PM_fiq: ("FIQ Processor Mode", "fiq", "Supports a high-speed data transfer or channel process"),
79     PM_irq: ("IRQ Processor Mode", "irq", "Used for general-purpose interrupt handling"),
80     PM_svc: ("Supervisor Processor Mode", "svc", "A protected mode for the operating system"),
81     PM_irq: ("Abort Processor Mode", "irq", "Implements virtual memory and/or memory protection"),
82     PM_und: ("Undefined Processor Mode", "und", "Supports software emulation of hardware coprocessor"),
83     PM_sys: ("System Processor Mode", "sys", "Runs privileged operating system tasks (ARMv4 and above)"),
84 }
85
86 PSR_bits = [ 
87     None,
88     None,
89     None,
90     None,
91     None,
92     "Thumb",
93     "nFIQ_int",
94     "nIRQ_int",
95     "nImprDataAbort_int",
96     "BIGendian",
97     None,
98     None,
99     None,
100     None,
101     None,
102     None,
103     "GE_0",
104     "GE_1",
105     "GE_2",
106     "GE_3",
107     None,
108     None,
109     None,
110     None,
111     "Jazelle",
112     None,
113     None,
114     "Q (DSP-overflow)",
115     "oVerflow",
116     "Carry",
117     "Zero",
118     "Neg",
119     ]
120
121
122
123 ARM_INSTR_NOP =             0xe1a00000L
124 ARM_INSTR_BX_R0 =           0xe12fff10L
125 ARM_INSTR_STR_Rx_r14 =      0xe58f0000L # from atmel docs
126 ARM_READ_REG =              ARM_INSTR_STR_Rx_r14
127 ARM_INSTR_LDR_Rx_r14 =      0xe59f0000L # from atmel docs
128 ARM_WRITE_REG =             ARM_INSTR_LDR_Rx_r14
129 ARM_INSTR_LDR_R1_r0_4 =     0xe4901004L
130 ARM_READ_MEM =              ARM_INSTR_LDR_R1_r0_4
131 ARM_INSTR_STR_R1_r0_4 =     0xe4801004L
132 ARM_WRITE_MEM =             ARM_INSTR_STR_R1_r0_4
133 ARM_INSTR_MRS_R0_CPSR =     0xe10f0000L
134 ARM_INSTR_MSR_cpsr_cxsf_R0 =0xe12ff000L
135 ARM_INSTR_STMIA_R14_r0_rx = 0xE88E0000L      # add up to 65k to indicate which registers...
136 ARM_STORE_MULTIPLE =        ARM_INSTR_STMIA_R14_r0_rx
137 ARM_INSTR_SKANKREGS =       0xE88F7fffL
138 ARM_INSTR_CLOBBEREGS =      0xE89F7fffL
139
140 ARM_INSTR_B_PC =            0xea000000L
141 ARM_INSTR_BX_PC =           0xe1200010L      # need to set r0 to the desired address
142 THUMB_INSTR_STR_R0_r0 =     0x60006000L
143 THUMB_INSTR_MOV_R0_PC =     0x46b846b8L
144 THUMB_INSTR_BX_PC =         0x47784778L
145 THUMB_INSTR_NOP =           0x1c001c00L
146 ARM_REG_PC =                15
147
148 ARM7TDMI_IR_EXTEST =            0x0
149 ARM7TDMI_IR_SCAN_N =            0x2
150 ARM7TDMI_IR_SAMPLE =            0x3
151 ARM7TDMI_IR_RESTART =           0x4
152 ARM7TDMI_IR_CLAMP =             0x5
153 ARM7TDMI_IR_HIGHZ =             0x7
154 ARM7TDMI_IR_CLAMPZ =            0x9
155 ARM7TDMI_IR_INTEST =            0xC
156 ARM7TDMI_IR_IDCODE =            0xE
157 ARM7TDMI_IR_BYPASS =            0xF
158
159
160 def PSRdecode(psrval):
161     output = [ "(%s mode)"%proc_modes[psrval&0x1f][1] ]
162     for x in xrange(5,32):
163         if psrval & (1<<x):
164             output.append(PSR_bits[x])
165     return " ".join(output)
166    
167 fmt = [None, "B", "<H", None, "<L", None, None, None, "<Q"]
168 def chop(val,byts):
169     s = struct.pack(fmt[byts], val)
170     return [ord(b) for b in s ]
171         
172 class GoodFETARM(GoodFET):
173     """A GoodFET variant for use with ARM7TDMI microprocessor."""
174     def ARMhaltcpu(self):
175         """Halt the CPU."""
176         self.writecmd(0x13,HALTCPU,0,self.data)
177         print "CPSR: (%s) %s"%(self.ARMget_regCPSRstr())
178     def ARMreleasecpu(self):
179         """Resume the CPU."""
180         self.writecmd(0x13,RESUMECPU,0,self.data)
181     def ARMsetModeArm(self, restart=0):
182         self.writecmd(0x13,SET_MODE_ARM,0,[restart])
183     def ARMsetModeThumb(self, restart=0):
184         self.writecmd(0x13,SET_MODE_THUMB,0,[restart])
185     def ARMtest(self):
186         #self.ARMreleasecpu()
187         #self.ARMhaltcpu()
188         print "Status: %s" % self.ARMstatusstr()
189         
190         #Grab ident three times, should be equal.
191         ident1=self.ARMident()
192         ident2=self.ARMident()
193         ident3=self.ARMident()
194         if(ident1!=ident2 or ident2!=ident3):
195             print "Error, repeated ident attempts unequal."
196             print "%04x, %04x, %04x" % (ident1, ident2, ident3)
197         
198         #Set and Check Registers
199         regs = [1024+x for x in range(0,15)]
200         regr = []
201         for x in range(len(regs)):
202             self.ARMset_register(x, regs[x])
203
204         for x in range(len(regs)):
205             regr.append(self.ARMget_register(x))
206         
207         for x in range(len(regs)):
208             if regs[x] != regr[x]:
209                 print "Error, R%d fail: %x != %x"%(x,regs[x],regr[x])
210
211         return
212
213
214
215
216         #Single step, printing PC.
217         print "Tracing execution at startup."
218         for i in range(15):
219             pc=self.ARMgetPC()
220             byte=self.ARMpeekcodebyte(i)
221             #print "PC=%04x, %02x" % (pc, byte)
222             self.ARMstep_instr()
223         
224         print "Verifying that debugging a NOP doesn't affect the PC."
225         for i in range(1,15):
226             pc=self.ARMgetPC()
227             self.ARMdebuginstr([NOP])
228             if(pc!=self.ARMgetPC()):
229                 print "ERROR: PC changed during ARMdebuginstr([NOP])!"
230         
231         print "Checking pokes to XRAM."
232         for i in range(0xf000,0xf020):
233             self.ARMpokedatabyte(i,0xde)
234             if(self.ARMpeekdatabyte(i)!=0xde):
235                 print "Error in DATA at 0x%04x" % i
236         
237         #print "Status: %s." % self.ARMstatusstr()
238         #Exit debugger
239         self.stop()
240         print "Done."
241
242     def setup(self):
243         """Move the FET into the JTAG ARM application."""
244         #print "Initializing ARM."
245         self.writecmd(0x13,SETUP,0,self.data)
246     def ARMget_dbgstate(self):
247         """Read the config register of an ARM."""
248         self.writecmd(0x13,GET_DEBUG_STATE,0,self.data)
249         retval = struct.unpack("<L", self.data[:4])[0]
250         return retval
251     def ARMget_dbgctrl(self):
252         """Read the config register of an ARM."""
253         self.writecmd(0x13,GET_DEBUG_CTRL,0,self.data)
254         retval = struct.unpack("B", self.data)[0]
255         return retval
256     def ARMset_dbgctrl(self,config):
257         """Write the config register of an ARM."""
258         self.writecmd(0x13,SET_DEBUG_CTRL,1,[config&7])
259     #def ARMlockchip(self):
260     #    """Set the flash lock bit in info mem."""
261     #    self.writecmd(0x13, LOCKCHIP, 0, [])
262     
263
264     def ARMidentstr(self):
265         ident=self.ARMident()
266         ver     = ident >> 28
267         partno  = (ident >> 12) & 0x10
268         mfgid   = ident & 0xfff
269         return "mfg: %x\npartno: %x\nver: %x\n(%x)" % (ver, partno, mfgid, ident); 
270     def ARMident(self):
271         """Get an ARM's ID."""
272         self.writecmd(0x13,GET_CHIP_ID,0,[])
273         retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
274         return retval
275     def ARMsetPC(self, val):
276         """Set an ARM's PC."""
277         self.writecmd(0x13,SET_PC,0,chop(val,4))
278     def ARMgetPC(self):
279         """Get an ARM's PC."""
280         self.writecmd(0x13,GET_PC,0,[])
281         retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
282         return retval
283     def ARMget_register(self, reg):
284         """Get an ARM's Register"""
285         self.writecmd(0x13,GET_REGISTER,1,[reg&0xff])
286         retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
287         return retval
288     def ARMset_register(self, reg, val):
289         """Get an ARM's Register"""
290         self.writecmd(0x13,SET_REGISTER,8,[val&0xff, (val>>8)&0xff, (val>>16)&0xff, val>>24, reg,0,0,0])
291         #self.writecmd(0x13,SET_REGISTER,8,[reg,0,0,0, (val>>16)&0xff, val>>24, val&0xff, (val>>8)&0xff])
292         retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
293         return retval
294     def ARMget_registers(self):
295         """Get ARM Registers"""
296         regs = [ self.ARMget_register(x) for x in range(15) ]
297         regs.append(self.ARMgetPC())            # make sure we snag the "static" version of PC
298         return regs
299     def ARMset_registers(self, regs, mask):
300         """Set ARM Registers"""
301         for x in xrange(15):
302           if (1<<x) & mask:
303             self.ARMset_register(x,regs.pop())
304         if (1<<15) & mask:                      # make sure we set the "static" version of PC or changes will be lost
305           self.ARMsetPC(regs.pop())
306     def ARMget_regCPSRstr(self):
307         psr = self.ARMget_regCPSR()
308         return hex(psr), PSRdecode(psr)
309     def ARMget_regCPSR(self):
310         """Get an ARM's Register"""
311         self.writecmd(0x13,GET_CPSR,0,[])
312         retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
313         return retval
314     def ARMset_regCPSR(self, val):
315         """Get an ARM's Register"""
316         self.writecmd(0x13,SET_CPSR,4,[val&0xff, (val>>8)&0xff, (val>>16)&0xff, val>>24])
317     def ARMcmd(self,phrase):
318         self.writecmd(0x13,READ,len(phrase),phrase)
319         val=ord(self.data[0])
320         print "Got %02x" % val
321         return val
322     def ARMdebuginstr(self,instr,bkpt):
323         if type (instr) == int or type(instr) == long:
324             instr = struct.pack("<L", instr)
325         instr = [int("0x%x"%ord(x),16) for x in instr]
326         instr.extend([bkpt])
327         self.writecmd(0x13,DEBUG_INSTR,len(instr),instr)
328         return (self.data)
329     def ARM_nop(self, bkpt):
330         return self.ARMdebuginstr(ARM_INSTR_NOP, bkpt)
331     def ARMset_IR(self, IR):
332         self.writecmd(0x13,SET_IR,1, [IR])
333         return self.data
334     def ARMshiftDR(self, data, bits, LSB, END, RETIDLE):
335         self.writecmd(0x13,SHIFT_DR,8,[bits&0xff, LSB&0xff, END&0xff, RETIDLE&0xff, data&0xff,(data>>8)&0xff,(data>>16)&0xff,(data>>24)&0xff])
336         return self.data
337     def ARMwaitDBG(self, timeout=0xff):
338         self.writecmd(0x13,WAIT_DBG,2,[timeout&0xf,timeout>>8])
339         return self.data
340     def ARMrestart(self):
341         self.ARMset_IR(ARM7TDMI_IR_RESTART)
342     def ARMset_watchpoint0(self, addr, addrmask, data, datamask, ctrl, ctrlmask):
343         self.data = []
344         self.data.extend(chop(addr,4))
345         self.data.extend(chop(addrmask,4))
346         self.data.extend(chop(data,4))
347         self.data.extend(chop(datamask,4))
348         self.data.extend(chop(ctrl,4))
349         self.data.extend(chop(ctrlmask,4))
350         self.writecmd(0x13,SETWATCH0,24,self.data)
351         return self.data
352     def ARMset_watchpoint1(self, addr, addrmask, data, datamask, ctrl, ctrlmask):
353         self.data = []
354         self.data.extend(chop(addr,4))
355         self.data.extend(chop(addrmask,4))
356         self.data.extend(chop(data,4))
357         self.data.extend(chop(datamask,4))
358         self.data.extend(chop(ctrl,4))
359         self.data.extend(chop(ctrlmask,4))
360         self.writecmd(0x13,SETWATCH1,24,self.data)
361         return self.data
362     def ARMreadMem(self, adr, wrdcount):
363         retval = [] 
364         r0 = self.ARMget_register(0);        # store R0 and R1
365         r1 = self.ARMget_register(1);
366         print >>sys.stderr,("CPSR:\t%x"%self.ARMget_regCPSR())
367         for word in range(adr, adr+(wrdcount*4), 4):
368             self.ARMset_register(0, word);        # write address into R0
369             self.ARM_nop(0)
370             self.ARM_nop(1)
371             self.ARMdebuginstr(ARM_READ_MEM, 0); # push LDR R1, [R0], #4 into instruction pipeline  (autoincrements for consecutive reads)
372             self.ARM_nop(0)
373             self.ARMrestart()
374             self.ARMwaitDBG()
375             print self.ARMget_register(1)
376
377
378             # FIXME: this may end up changing te current debug-state.  should we compare to current_dbgstate?
379             #print repr(self.data[4])
380             if (len(self.data)>4 and self.data[4] == '\x00'):
381               print >>sys.stderr,("FAILED TO READ MEMORY/RE-ENTER DEBUG MODE")
382               raise Exception("FAILED TO READ MEMORY/RE-ENTER DEBUG MODE")
383               return (-1);
384             else:
385               retval.append( self.ARMget_register(1) )  # read memory value from R1 register
386               print >>sys.stderr,("CPSR: %x\t\tR0: %x\t\tR1: %x"%(self.ARMget_regCPSR(),self.ARMget_register(0),self.ARMget_register(1)))
387         self.ARMset_register(1, r1);       # restore R0 and R1 
388         self.ARMset_register(0, r0);
389         return retval
390
391     def ARMpeekcodewords(self,adr,words):
392         """Read the contents of code memory at an address."""
393         self.data=[adr&0xff, (adr>>8)&0xff, (adr>>16)&0xff, (adr>>24)&0xff, words&0xff, (words>>8)&0xff, (words>>16)&0xff, (words>>24)&0xff ]
394         self.writecmd(0x13,READ_CODE_MEMORY,8,self.data)
395         retval = []
396         retval.append(self.serialport.read(words*4))
397         #retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
398         return "".join(retval)
399     def ARMpeekdatabyte(self,adr):
400         """Read the contents of data memory at an address."""
401         self.data=[ adr&0xff, (adr>>8)&0xff, (adr>>16)&0xff, (adr>>24)&0xff ]
402         self.writecmd(0x13, PEEK, 4, self.data)
403         #retval.append(self.serialport.read(words*4))
404         retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
405         return retval
406     def ARMpokedatabyte(self,adr,val):
407         """Write a byte to data memory."""
408         self.data=[adr&0xff, (adr>>8)&0xff, (adr>>16)&0xff, (adr>>24)&0xff, val&0xff, (val>>8)&0xff, (val>>16)&0xff, (val>>24)&0xff ]
409         self.writecmd(0x13, POKE, 8, self.data)
410         retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
411         return retval
412     #def ARMchiperase(self):
413     #    """Erase all of the target's memory."""
414     #    self.writecmd(0x13,CHIP_ERASE,0,[])
415     def ARMstatus(self):
416         """Check the status."""
417         self.writecmd(0x13,GET_DEBUG_STATE,0,[])
418         return ord(self.data[0])
419     ARMstatusbits={
420                   0x10 : "TBIT",
421                   0x08 : "cgenL",
422                   0x04 : "Interrupts Enabled (or not?)",
423                   0x02 : "DBGRQ",
424                   0x01 : "DGBACK"
425                   }
426     ARMctrlbits={
427                   0x04 : "disable interrupts",
428                   0x02 : "force dbgrq",
429                   0x01 : "force dbgack"
430                   }
431                   
432     def ARMstatusstr(self):
433         """Check the status as a string."""
434         status=self.ARMstatus()
435         str=""
436         i=1
437         while i<0x100:
438             if(status&i):
439                 str="%s %s" %(self.ARMstatusbits[i],str)
440             i*=2
441         return str
442     def start(self):
443         """Start debugging."""
444         self.writecmd(0x13,START,0,self.data)
445         ident=self.ARMidentstr()
446         print "Target identifies as %s." % ident
447         print "Debug Status: %s." % self.ARMstatusstr()
448         #print "System State: %x." % self.ARMget_regCPSRstr()
449         #self.ARMreleasecpu()
450         #self.ARMhaltcpu()
451         
452     def stop(self):
453         """Stop debugging."""
454         self.writecmd(0x13,STOP,0,self.data)
455     #def ARMstep_instr(self):
456     #    """Step one instruction."""
457     #    self.writecmd(0x13,STEP_INSTR,0,self.data)
458     #def ARMflashpage(self,adr):
459     #    """Flash 2kB a page of flash from 0xF000 in XDATA"""
460     #    data=[adr&0xFF,
461     #          (adr>>8)&0xFF,
462     #          (adr>>16)&0xFF,
463     #          (adr>>24)&0xFF]
464     #    print "Flashing buffer to 0x%06x" % adr
465     #    self.writecmd(0x13,MASS_FLASH_PAGE,4,data)
466
467     def writecmd(self, app, verb, count=0, data=[]):
468         """Write a command and some data to the GoodFET."""
469         self.serialport.write(chr(app))
470         self.serialport.write(chr(verb))
471         count = len(data)
472         #if data!=None:
473         #    count=len(data); #Initial count ignored.
474
475         #print "TX %02x %02x %04x" % (app,verb,count)
476
477         #little endian 16-bit length
478         self.serialport.write(chr(count&0xFF))
479         self.serialport.write(chr(count>>8))
480
481         #print "count=%02x, len(data)=%04x" % (count,len(data))
482
483         if count!=0:
484             if(isinstance(data,list)):
485                 for i in range(0,count):
486                     #print "Converting %02x at %i" % (data[i],i)
487                     data[i]=chr(data[i])
488             #print type(data)
489             outstr=''.join(data)
490             self.serialport.write(outstr)
491         if not self.besilent:
492             self.readcmd()
493
494
495