w00t! jtag arm is a reality on goodfet.
[goodfet] / client / GoodFETARM.py
1 #!/usr/bin/env python
2 # GoodFET 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
12 #Global Commands
13 READ  = 0x00
14 WRITE = 0x01
15 PEEK  = 0x02
16 POKE  = 0x03
17 SETUP = 0x10
18 START = 0x20
19 STOP  = 0x21
20 CALL  = 0x30
21 EXEC  = 0x31
22 NOK   = 0x7E
23 OK    = 0x7F
24
25 # ARM7TDMI JTAG commands
26 GET_DEBUG_CTRL      = 0x80
27 SET_DEBUG_CTRL      = 0x81
28 GET_PC              = 0x82
29 SET_PC              = 0x83
30 GET_CHIP_ID         = 0x84
31 GET_DEBUG_STATE     = 0x85
32 GET_WATCHPOINT      = 0x86
33 SET_WATCHPOINT      = 0x87
34 GET_REGISTER        = 0x88
35 SET_REGISTER        = 0x89
36 GET_REGISTERS       = 0x8a
37 SET_REGISTERS       = 0x8b
38 HALTCPU             = 0x8c
39 RESUMECPU           = 0x8d
40 DEBUG_INSTR         = 0x8e      #
41 STEP_INSTR          = 0x8f      #
42 STEP_REPLACE        = 0x90      #
43 READ_CODE_MEMORY    = 0x91      # ??
44 WRITE_FLASH_PAGE    = 0x92      # ??
45 READ_FLASH_PAGE     = 0x93      # ??
46 MASS_ERASE_FLASH    = 0x94      # ??
47 PROGRAM_FLASH       = 0x95
48 LOCKCHIP            = 0x96      # ??
49 CHIP_ERASE          = 0x97      # can do?
50 # Really ARM specific stuff
51 GET_CPSR            = 0x98
52 SET_CPSR            = 0x99
53 GET_SPSR            = 0x9a
54 SET_SPSR            = 0x9b
55 SET_MODE_THUMB      = 0x9c
56 SET_MODE_ARM        = 0x9d
57
58
59 platforms = {
60     "at91sam7": {0:(0x100000, "Flash before remap, SRAM after remap"),
61                  0x100000: (0x100000, "Internal Flash"),
62                  0x200000: (0x100000, "Internal SRAM"),
63                  },
64     }
65                 
66 from GoodFET import GoodFET
67 from intelhex import IntelHex
68
69
70
71
72 class GoodFETARM(GoodFET):
73     """A GoodFET variant for use with ARM7TDMI microprocessor."""
74     def ARMhaltcpu(self):
75         """Halt the CPU."""
76         self.writecmd(0x13,HALTCPU,0,self.data)
77     def ARMreleasecpu(self):
78         """Resume the CPU."""
79         self.writecmd(0x13,RESUMECPU,0,self.data)
80     def ARMsetModeArm(self):
81         self.writecmd(0x13,SET_MODE_ARM,0,self.data)
82     def ARMsetModeThumb(self):
83         self.writecmd(0x13,SET_MODE_THUMB,0,self.data)
84     def ARMtest(self):
85         #self.ARMreleasecpu()
86         #self.ARMhaltcpu()
87         print "Status: %s" % self.ARMstatusstr()
88         
89         #Grab ident three times, should be equal.
90         ident1=self.ARMident()
91         ident2=self.ARMident()
92         ident3=self.ARMident()
93         if(ident1!=ident2 or ident2!=ident3):
94             print "Error, repeated ident attempts unequal."
95             print "%04x, %04x, %04x" % (ident1, ident2, ident3)
96         
97         #Set and Check Registers
98         regs = [1024+x for x in range(0,15)]
99         regr = []
100         for x in range(len(regs)):
101             self.ARMset_register(x, regs[x])
102
103         for x in range(len(regs)):
104             regr.append(self.ARMget_register(x))
105         
106         for x in range(len(regs)):
107             if regs[x] != regr[x]:
108                 print "Error, R%d fail: %x != %x"%(x,regs[x],regr[x])
109
110         return
111
112
113
114
115         #Single step, printing PC.
116         print "Tracing execution at startup."
117         for i in range(15):
118             pc=self.ARMgetPC()
119             byte=self.ARMpeekcodebyte(i)
120             #print "PC=%04x, %02x" % (pc, byte)
121             self.ARMstep_instr()
122         
123         print "Verifying that debugging a NOP doesn't affect the PC."
124         for i in range(1,15):
125             pc=self.ARMgetPC()
126             self.ARMdebuginstr([NOP])
127             if(pc!=self.ARMgetPC()):
128                 print "ERROR: PC changed during ARMdebuginstr([NOP])!"
129         
130         print "Checking pokes to XRAM."
131         for i in range(0xf000,0xf020):
132             self.ARMpokedatabyte(i,0xde)
133             if(self.ARMpeekdatabyte(i)!=0xde):
134                 print "Error in DATA at 0x%04x" % i
135         
136         #print "Status: %s." % self.ARMstatusstr()
137         #Exit debugger
138         self.stop()
139         print "Done."
140
141     def setup(self):
142         """Move the FET into the JTAG ARM application."""
143         #print "Initializing ARM."
144         self.writecmd(0x13,SETUP,0,self.data)
145     def ARMget_dbgstate(self):
146         """Read the config register of an ARM."""
147         self.writecmd(0x13,GET_DEBUG_STATE,0,self.data)
148         retval = struct.unpack("<L", self.data[:4])[0]
149         return retval
150     def ARMget_dbgctrl(self):
151         """Read the config register of an ARM."""
152         self.writecmd(0x13,GET_DEBUG_CTRL,0,self.data)
153         retval = struct.unpack("B", self.data)[0]
154         return retval
155     def ARMset_dbgctrl(self,config):
156         """Write the config register of an ARM."""
157         self.writecmd(0x13,SET_DEBUG_CTRL,1,[config&7])
158     #def ARMlockchip(self):
159     #    """Set the flash lock bit in info mem."""
160     #    self.writecmd(0x13, LOCKCHIP, 0, [])
161     
162
163     def ARMidentstr(self):
164         ident=self.ARMident()
165         ver     = ident >> 28
166         partno  = (ident >> 12) & 0x10
167         mfgid   = ident & 0xfff
168         return "mfg: %x\npartno: %x\nver: %x\n(%x)" % (ver, partno, mfgid, ident); 
169     def ARMident(self):
170         """Get an ARM's ID."""
171         self.writecmd(0x13,GET_CHIP_ID,0,[])
172         retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
173         return retval
174     def ARMgetPC(self):
175         """Get an ARM's PC."""
176         self.writecmd(0x13,GET_PC,0,[])
177         retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
178         return retval
179     def ARMget_register(self, reg):
180         """Get an ARM's Register"""
181         self.writecmd(0x13,GET_REGISTER,1,[reg&0xff])
182         retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
183         return retval
184     def ARMset_register(self, reg, val):
185         """Get an ARM's Register"""
186         self.writecmd(0x13,SET_REGISTER,8,[val&0xff, (val>>8)&0xff, (val>>16)&0xff, val>>24, reg,0,0,0])
187         #self.writecmd(0x13,SET_REGISTER,8,[reg,0,0,0, (val>>16)&0xff, val>>24, val&0xff, (val>>8)&0xff])
188         retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
189         return retval
190     def ARMget_registers(self):
191         """Get ARM Registers"""
192         self.writecmd(0x13,GET_REGISTERS,0, [])
193         retval = []
194         for x in range(0,len(self.data), 4):
195           retval.append(struct.unpack("<L", self.data[x:x+4])[0])
196         return retval
197     def ARMset_registers(self, regs):
198         """Set ARM Registers"""
199         regarry = []
200         for reg in regs:
201           regarry.extend([reg&0xff, (reg>>8)&0xff, (reg>>16)&0xff, reg>>24])
202         self.writecmd(0x13,SET_REGISTERS,16*4,regarry)
203         retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
204         return retval
205     def ARMget_regCPSR(self):
206         """Get an ARM's Register"""
207         self.writecmd(0x13,GET_CPSR,0,[])
208         retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
209         return retval
210     def ARMset_regCPSR(self, val):
211         """Get an ARM's Register"""
212         self.writecmd(0x13,SET_CPSR,4,[val&0xff, (val>>8)&0xff, (val>>16)&0xff, val>>24])
213     def ARMcmd(self,phrase):
214         self.writecmd(0x13,READ,len(phrase),phrase)
215         val=ord(self.data[0])
216         print "Got %02x" % val
217         return val
218     def ARMdebuginstr(self,instr):
219         if type (instr) == int:
220             instr = struct.pack("<L", instr)
221         self.writecmd(0x13,DEBUG_INSTR,len(instr),instr)
222         return (self.data[0])
223     def ARMpeekcodewords(self,adr,words):
224         """Read the contents of code memory at an address."""
225         self.data=[adr&0xff, (adr>>8)&0xff, (adr>>16)&0xff, (adr>>24)&0xff, words&0xff, (words>>8)&0xff, (words>>16)&0xff, (words>>24)&0xff ]
226         self.writecmd(0x13,READ_CODE_MEMORY,8,self.data)
227         retval = []
228         retval.append(self.serialport.read(words*4))
229         #retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
230         return "".join(retval)
231     def ARMpeekdatabyte(self,adr):
232         """Read the contents of data memory at an address."""
233         self.data=[ adr&0xff, (adr>>8)&0xff, (adr>>16)&0xff, (adr>>24)&0xff ]
234         self.writecmd(0x13, PEEK, 4, self.data)
235         #retval.append(self.serialport.read(words*4))
236         retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
237         return retval
238     def ARMpokedatabyte(self,adr,val):
239         """Write a byte to data memory."""
240         self.data=[adr&0xff, (adr>>8)&0xff, (adr>>16)&0xff, (adr>>24)&0xff, val&0xff, (val>>8)&0xff, (val>>16)&0xff, (val>>24)&0xff ]
241         self.writecmd(0x13, POKE, 8, self.data)
242         retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
243         return retval
244     #def ARMchiperase(self):
245     #    """Erase all of the target's memory."""
246     #    self.writecmd(0x13,CHIP_ERASE,0,[])
247     def ARMstatus(self):
248         """Check the status."""
249         self.writecmd(0x13,GET_DEBUG_STATE,0,[])
250         return ord(self.data[0])
251     ARMstatusbits={
252                   0x10 : "TBIT",
253                   0x08 : "cgenL",
254                   0x04 : "Interrupts Enabled (or not?)",
255                   0x02 : "DBGRQ",
256                   0x01 : "DGBACK"
257                   }
258     ARMctrlbits={
259                   0x04 : "disable interrupts",
260                   0x02 : "force dbgrq",
261                   0x01 : "force dbgack"
262                   }
263                   
264     def ARMstatusstr(self):
265         """Check the status as a string."""
266         status=self.ARMstatus()
267         str=""
268         i=1
269         while i<0x100:
270             if(status&i):
271                 str="%s %s" %(self.ARMstatusbits[i],str)
272             i*=2
273         return str
274     def start(self):
275         """Start debugging."""
276         self.writecmd(0x13,START,0,self.data)
277         ident=self.ARMidentstr()
278         print "Target identifies as %s." % ident
279         print "Status: %s." % self.ARMstatusstr()
280         #self.ARMreleasecpu()
281         #self.ARMhaltcpu()
282         #print "Status: %s." % self.ARMstatusstr()
283         
284     def stop(self):
285         """Stop debugging."""
286         self.writecmd(0x13,STOP,0,self.data)
287     #def ARMstep_instr(self):
288     #    """Step one instruction."""
289     #    self.writecmd(0x13,STEP_INSTR,0,self.data)
290     #def ARMflashpage(self,adr):
291     #    """Flash 2kB a page of flash from 0xF000 in XDATA"""
292     #    data=[adr&0xFF,
293     #          (adr>>8)&0xFF,
294     #          (adr>>16)&0xFF,
295     #          (adr>>24)&0xFF]
296     #    print "Flashing buffer to 0x%06x" % adr
297     #    self.writecmd(0x13,MASS_FLASH_PAGE,4,data)
298
299     def writecmd(self, app, verb, count=0, data=[]):
300         """Write a command and some data to the GoodFET."""
301         self.serialport.write(chr(app))
302         self.serialport.write(chr(verb))
303         count = len(data)
304         #if data!=None:
305         #    count=len(data); #Initial count ignored.
306
307         #print "TX %02x %02x %04x" % (app,verb,count)
308
309         #little endian 16-bit length
310         self.serialport.write(chr(count&0xFF))
311         self.serialport.write(chr(count>>8))
312
313         #print "count=%02x, len(data)=%04x" % (count,len(data))
314
315         if count!=0:
316             if(isinstance(data,list)):
317                 for i in range(0,count):
318                     #print "Converting %02x at %i" % (data[i],i)
319                     data[i]=chr(data[i])
320             #print type(data)
321             outstr=''.join(data)
322             self.serialport.write(outstr)
323         if not self.besilent:
324             self.readcmd()
325
326