pyregs target to goodfet.nrf, for dumping radio configurations.
[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 from GoodFET import GoodFET
59 from intelhex import IntelHex
60
61
62
63
64 class GoodFETARM(GoodFET):
65     """A GoodFET variant for use with ARM7TDMI microprocessor."""
66     def ARMhaltcpu(self):
67         """Halt the CPU."""
68         self.writecmd(0x33,HALTCPU,0,self.data)
69     def ARMreleasecpu(self):
70         """Resume the CPU."""
71         self.writecmd(0x33,RESUMECPU,0,self.data)
72     def ARMsetModeArm(self):
73         self.writecmd(0x33,SET_MODE_ARM,0,self.data)
74     def ARMtest(self):
75         self.ARMreleasecpu()
76         self.ARMhaltcpu()
77         print "Status: %s" % self.ARMstatusstr()
78         
79         #Grab ident three times, should be equal.
80         ident1=self.ARMident()
81         ident2=self.ARMident()
82         ident3=self.ARMident()
83         if(ident1!=ident2 or ident2!=ident3):
84             print "Error, repeated ident attempts unequal."
85             print "%04x, %04x, %04x" % (ident1, ident2, ident3)
86         
87         #Set and Check Registers
88         regs = [1024+x for x in range(1,15)]
89         regr = []
90         for x in range(len(regs)):
91             self.ARMset_register(x, regs[x])
92
93         for x in range(len(regs)):
94             regr.append(self.ARMget_register(x))
95         
96         for x in range(len(regs)):
97             if regs[x] != regr[x]:
98                 print "Error, R%d fail: %x != %x"%(x,regs[x],regr[x])
99
100         return
101
102
103
104
105         #Single step, printing PC.
106         print "Tracing execution at startup."
107         for i in range(15):
108             pc=self.ARMgetPC()
109             byte=self.ARMpeekcodebyte(i)
110             #print "PC=%04x, %02x" % (pc, byte)
111             self.ARMstep_instr()
112         
113         print "Verifying that debugging a NOP doesn't affect the PC."
114         for i in range(1,15):
115             pc=self.ARMgetPC()
116             self.ARMdebuginstr([NOP])
117             if(pc!=self.ARMgetPC()):
118                 print "ERROR: PC changed during ARMdebuginstr([NOP])!"
119         
120         print "Checking pokes to XRAM."
121         for i in range(0xf000,0xf020):
122             self.ARMpokedatabyte(i,0xde)
123             if(self.ARMpeekdatabyte(i)!=0xde):
124                 print "Error in DATA at 0x%04x" % i
125         
126         #print "Status: %s." % self.ARMstatusstr()
127         #Exit debugger
128         self.stop()
129         print "Done."
130
131     def setup(self):
132         """Move the FET into the JTAG ARM application."""
133         #print "Initializing ARM."
134         self.writecmd(0x33,SETUP,0,self.data)
135     def ARMget_dbgstate(self):
136         """Read the config register of an ARM."""
137         retval = struct.unpack("<L", self.data[:4])[0]
138         return retval
139     def ARMget_dbgctrl(self):
140         """Read the config register of an ARM."""
141         self.writecmd(0x33,GET_DEBUG_CTRL,0,self.data)
142         retval = struct.unpack("B", self.data)[0]
143         return retval
144     def ARMset_dbgctrl(self,config):
145         """Write the config register of an ARM."""
146         self.writecmd(0x33,SET_DEBUG_CTRL,1,[config&7])
147     def ARMlockchip(self):
148         """Set the flash lock bit in info mem."""
149         self.writecmd(0x33, LOCKCHIP, 0, [])
150     
151
152     def ARMidentstr(self):
153         ident=self.ARMident()
154         ver     = ident >> 28
155         partno  = (ident >> 12) & 0x10
156         mfgid   = ident & 0xfff
157         return "mfg: %x\npartno: %x\nver: %x\n(%x)" % (ver, partno, mfgid, ident); 
158     def ARMident(self):
159         """Get an ARM's ID."""
160         self.writecmd(0x33,GET_CHIP_ID,0,[])
161         retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
162         return retval
163     def ARMgetPC(self):
164         """Get an ARM's PC."""
165         self.writecmd(0x33,GET_PC,0,[])
166         retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
167         return retval
168     def ARMget_register(self, reg):
169         """Get an ARM's Register"""
170         self.writecmd(0x33,GET_REGISTER,1,[reg&0xff])
171         retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
172         return retval
173     def ARMset_register(self, reg, val):
174         """Get an ARM's Register"""
175         self.writecmd(0x33,SET_REGISTER,8,[reg,0,0,0,val&0xff, (val>>8)&0xff, (val>>16)&0xff, val>>24])
176         #self.writecmd(0x33,SET_REGISTER,8,[reg,0,0,0, (val>>16)&0xff, val>>24, val&0xff, (val>>8)&0xff])
177         retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
178         return retval
179     def ARMget_registers(self):
180         """Get ARM Registers"""
181         self.writecmd(0x33,GET_REGISTERS,0, [])
182         retval = []
183         for x in range(0,len(self.data), 4):
184           retval.append(struct.unpack("<L", self.data[x:x+4])[0])
185         return retval
186     def ARMset_registers(self, regs):
187         """Set ARM Registers"""
188         regarry = []
189         for reg in regs:
190           regarry.extend([reg&0xff, (reg>>8)&0xff, (reg>>16)&0xff, reg>>24])
191         self.writecmd(0x33,SET_REGISTERS,16*4,regarry)
192         retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
193         return retval
194     def ARMcmd(self,phrase):
195         self.writecmd(0x33,READ,len(phrase),phrase)
196         val=ord(self.data[0])
197         print "Got %02x" % val
198         return val
199     def ARMdebuginstr(self,instr):
200         if type (instr) == int:
201             instr = struct.pack("<L", instr)
202         self.writecmd(0x33,DEBUG_INSTR,len(instr),instr)
203         return (self.data[0])
204     def ARMpeekcodebyte(self,adr):
205         """Read the contents of code memory at an address."""
206         self.data=[adr&0xff, (adr&0xff00)>>8]
207         self.writecmd(0x33,PEEK,2,self.data)
208         retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
209         return retval
210     def ARMpeekdatabyte(self,adr):
211         """Read the contents of data memory at an address."""
212         self.data=[adr&0xff, (adr&0xff00)>>8]
213         self.writecmd(0x33, PEEK, 2, self.data)
214         retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
215         return retval
216     def ARMpokedatabyte(self,adr,val):
217         """Write a byte to data memory."""
218         self.data=[adr&0xff, (adr&0xff00)>>8, val]
219         self.writecmd(0x33, POKE, 3, self.data)
220         retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
221         return retval
222     def ARMchiperase(self):
223         """Erase all of the target's memory."""
224         self.writecmd(0x33,CHIP_ERASE,0,[])
225     def ARMstatus(self):
226         """Check the status."""
227         self.writecmd(0x33,GET_DEBUG_STATE,0,[])
228         return ord(self.data[0])
229     ARMstatusbits={
230                   0x10 : "TBIT",
231                   0x08 : "cgenL",
232                   0x04 : "Interrupts Enabled (or not?)",
233                   0x02 : "DBGRQ",
234                   0x01 : "DGBACK"
235                   }
236     ARMctrlbits={
237                   0x04 : "disable interrupts",
238                   0x02 : "force dbgrq",
239                   0x01 : "force dbgack"
240                   }
241                   
242     def ARMstatusstr(self):
243         """Check the status as a string."""
244         status=self.ARMstatus()
245         str=""
246         i=1
247         while i<0x100:
248             if(status&i):
249                 str="%s %s" %(self.ARMstatusbits[i],str)
250             i*=2
251         return str
252     def start(self):
253         """Start debugging."""
254         self.writecmd(0x33,START,0,self.data)
255         #ident=self.ARMidentstr()
256         #print "Target identifies as %s." % ident
257         #print "Status: %s." % self.ARMstatusstr()
258         #self.ARMreleasecpu()
259         #self.ARMhaltcpu()
260         #print "Status: %s." % self.ARMstatusstr()
261         
262     def stop(self):
263         """Stop debugging."""
264         self.writecmd(0x33,STOP,0,self.data)
265     def ARMstep_instr(self):
266         """Step one instruction."""
267         self.writecmd(0x33,STEP_INSTR,0,self.data)
268     def ARMflashpage(self,adr):
269         """Flash 2kB a page of flash from 0xF000 in XDATA"""
270         data=[adr&0xFF,
271               (adr>>8)&0xFF,
272               (adr>>16)&0xFF,
273               (adr>>24)&0xFF]
274         print "Flashing buffer to 0x%06x" % adr
275         self.writecmd(0x33,MASS_FLASH_PAGE,4,data)
276
277     def writecmd(self, app, verb, count=0, data=[]):
278         """Write a command and some data to the GoodFET."""
279         self.serialport.write(chr(app))
280         self.serialport.write(chr(verb))
281         count = len(data)
282         #if data!=None:
283         #    count=len(data); #Initial count ignored.
284
285         #print "TX %02x %02x %04x" % (app,verb,count)
286
287         #little endian 16-bit length
288         self.serialport.write(chr(count&0xFF))
289         self.serialport.write(chr(count>>8))
290
291         #print "count=%02x, len(data)=%04x" % (count,len(data))
292
293         if count!=0:
294             if(isinstance(data,list)):
295                 for i in range(0,count):
296                     #print "Converting %02x at %i" % (data[i],i)
297                     data[i]=chr(data[i])
298             #print type(data)
299             outstr=''.join(data)
300             self.serialport.write(outstr)
301         if not self.besilent:
302             self.readcmd()
303
304