2 # GoodFET ARM Client Library
5 # Good luck with alpha / beta code.
6 # Contributions and bug reports welcome.
9 import sys, binascii, struct, time
10 import atlasutils.smartprint as asp
11 from GoodFET import GoodFET
12 from intelhex import IntelHex
15 "at91sam7": {0:(0x100000, "Flash before remap, SRAM after remap"),
16 0x100000: (0x100000, "Internal Flash"),
17 0x200000: (0x100000, "Internal SRAM"),
35 # ARM7TDMI JTAG commands
41 GET_DEBUG_STATE = 0x85
55 CHIP_ERASE = 0x97 # can do?
56 # Really ARM specific stuff
84 PM_usr: ("User Processor Mode", "usr", "Normal program execution mode"),
85 PM_fiq: ("FIQ Processor Mode", "fiq", "Supports a high-speed data transfer or channel process"),
86 PM_irq: ("IRQ Processor Mode", "irq", "Used for general-purpose interrupt handling"),
87 PM_svc: ("Supervisor Processor Mode", "svc", "A protected mode for the operating system"),
88 PM_irq: ("Abort Processor Mode", "irq", "Implements virtual memory and/or memory protection"),
89 PM_und: ("Undefined Processor Mode", "und", "Supports software emulation of hardware coprocessor"),
90 PM_sys: ("System Processor Mode", "sys", "Runs privileged operating system tasks (ARMv4 and above)"),
102 "nImprDataAbort_int",
130 ARM_INSTR_NOP = 0xe1a00000L
131 ARM_INSTR_BX_R0 = 0xe12fff10L
132 ARM_INSTR_STR_Rx_r14 = 0xe58f0000L # from atmel docs
133 ARM_READ_REG = ARM_INSTR_STR_Rx_r14
134 ARM_INSTR_LDR_Rx_r14 = 0xe59f0000L # from atmel docs
135 ARM_WRITE_REG = ARM_INSTR_LDR_Rx_r14
136 ARM_INSTR_LDR_R1_r0_4 = 0xe4901004L
137 ARM_READ_MEM = ARM_INSTR_LDR_R1_r0_4
138 ARM_INSTR_STR_R1_r0_4 = 0xe4801004L
139 ARM_WRITE_MEM = ARM_INSTR_STR_R1_r0_4
140 ARM_INSTR_MRS_R0_CPSR = 0xe10f0000L
141 ARM_INSTR_MSR_cpsr_cxsf_R0 =0xe12ff000L
142 ARM_INSTR_STMIA_R14_r0_rx = 0xE88E0000L # add up to 65k to indicate which registers...
143 ARM_STORE_MULTIPLE = ARM_INSTR_STMIA_R14_r0_rx
144 ARM_INSTR_SKANKREGS = 0xE88F7fffL
145 ARM_INSTR_CLOBBEREGS = 0xE89F7fffL
147 ARM_INSTR_B_PC = 0xea000000L
148 ARM_INSTR_BX_PC = 0xe1200010L # need to set r0 to the desired address
149 THUMB_INSTR_STR_R0_r0 = 0x60006000L
150 THUMB_INSTR_MOV_R0_PC = 0x46b846b8L
151 THUMB_INSTR_BX_PC = 0x47784778L
152 THUMB_INSTR_NOP = 0x1c001c00L
155 ARM7TDMI_IR_EXTEST = 0x0
156 ARM7TDMI_IR_SCAN_N = 0x2
157 ARM7TDMI_IR_SAMPLE = 0x3
158 ARM7TDMI_IR_RESTART = 0x4
159 ARM7TDMI_IR_CLAMP = 0x5
160 ARM7TDMI_IR_HIGHZ = 0x7
161 ARM7TDMI_IR_CLAMPZ = 0x9
162 ARM7TDMI_IR_INTEST = 0xC
163 ARM7TDMI_IR_IDCODE = 0xE
164 ARM7TDMI_IR_BYPASS = 0xF
167 def PSRdecode(psrval):
168 output = [ "(%s mode)"%proc_modes[psrval&0x1f][1] ]
169 for x in xrange(5,32):
171 output.append(PSR_bits[x])
172 return " ".join(output)
174 fmt = [None, "B", "<H", None, "<L", None, None, None, "<Q"]
176 s = struct.pack(fmt[byts], val)
177 return [ord(b) for b in s ]
179 class GoodFETARM(GoodFET):
180 """A GoodFET variant for use with ARM7TDMI microprocessor."""
181 def ARMhaltcpu(self):
183 self.writecmd(0x13,HALTCPU,0,self.data)
184 print "CPSR: (%s) %s"%(self.ARMget_regCPSRstr())
186 def ARMreleasecpu(self):
187 """Resume the CPU."""
188 self.writecmd(0x13,RESUMECPU,0,self.data)
189 def ARMsetModeArm(self, restart=0):
190 self.writecmd(0x13,SET_MODE_ARM,0,[restart])
191 def ARMsetModeThumb(self, restart=0):
192 self.writecmd(0x13,SET_MODE_THUMB,0,[restart])
194 #self.ARMreleasecpu()
196 print "Status: %s" % self.ARMstatusstr()
198 #Grab ident three times, should be equal.
199 ident1=self.ARMident()
200 ident2=self.ARMident()
201 ident3=self.ARMident()
202 if(ident1!=ident2 or ident2!=ident3):
203 print "Error, repeated ident attempts unequal."
204 print "%04x, %04x, %04x" % (ident1, ident2, ident3)
206 #Set and Check Registers
207 regs = [1024+x for x in range(0,15)]
209 for x in range(len(regs)):
210 self.ARMset_register(x, regs[x])
212 for x in range(len(regs)):
213 regr.append(self.ARMget_register(x))
215 for x in range(len(regs)):
216 if regs[x] != regr[x]:
217 print "Error, R%d fail: %x != %x"%(x,regs[x],regr[x])
224 #Single step, printing PC.
225 print "Tracing execution at startup."
228 byte=self.ARMpeekcodebyte(i)
229 #print "PC=%04x, %02x" % (pc, byte)
232 print "Verifying that debugging a NOP doesn't affect the PC."
233 for i in range(1,15):
235 self.ARMdebuginstr([NOP])
236 if(pc!=self.ARMgetPC()):
237 print "ERROR: PC changed during ARMdebuginstr([NOP])!"
239 print "Checking pokes to XRAM."
240 for i in range(0xf000,0xf020):
241 self.ARMpokedatabyte(i,0xde)
242 if(self.ARMpeekdatabyte(i)!=0xde):
243 print "Error in DATA at 0x%04x" % i
245 #print "Status: %s." % self.ARMstatusstr()
251 """Move the FET into the JTAG ARM application."""
252 #print "Initializing ARM."
253 self.writecmd(0x13,SETUP,0,self.data)
254 def ARMget_dbgstate(self):
255 """Read the config register of an ARM."""
256 self.writecmd(0x13,GET_DEBUG_STATE,0,self.data)
257 retval = struct.unpack("<L", self.data[:4])[0]
259 def ARMget_dbgctrl(self):
260 """Read the config register of an ARM."""
261 self.writecmd(0x13,GET_DEBUG_CTRL,0,self.data)
262 retval = struct.unpack("B", self.data)[0]
264 def ARMset_dbgctrl(self,config):
265 """Write the config register of an ARM."""
266 self.writecmd(0x13,SET_DEBUG_CTRL,1,[config&7])
267 def ARMlockchip(self):
268 """Set the flash lock bit in info mem.
269 Chip-Specific. Not implemented"""
270 #self.writecmd(0x13, LOCKCHIP, 0, [])
271 raise Exception("Unimplemented: lockchip. This is chip specific and must be implemented for each chip.")
274 def ARMidentstr(self):
275 ident=self.ARMident()
277 partno = (ident >> 12) & 0x10
278 mfgid = ident & 0xfff
279 return "mfg: %x\npartno: %x\nver: %x\n(%x)" % (ver, partno, mfgid, ident);
281 """Get an ARM's ID."""
282 self.writecmd(0x13,GET_CHIP_ID,0,[])
283 retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
285 def ARMsetPC(self, val):
286 """Set an ARM's PC. Note: real PC gets all wonky in debug mode, this changes the "saved" PC which is used when exiting debug mode"""
287 self.writecmd(0x13,SET_PC,0,chop(val,4))
289 """Get an ARM's PC. Note: real PC gets all wonky in debug mode, this is the "saved" PC"""
290 self.writecmd(0x13,GET_PC,0,[])
291 retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
293 def ARMget_register(self, reg):
294 """Get an ARM's Register"""
295 self.writecmd(0x13,GET_REGISTER,1,[reg&0xff])
296 retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
298 def ARMset_register(self, reg, val):
299 """Get an ARM's Register"""
300 self.writecmd(0x13,SET_REGISTER,8,[val&0xff, (val>>8)&0xff, (val>>16)&0xff, val>>24, reg,0,0,0])
301 #self.writecmd(0x13,SET_REGISTER,8,[reg,0,0,0, (val>>16)&0xff, val>>24, val&0xff, (val>>8)&0xff])
302 retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
304 def ARMget_registers(self):
305 """Get ARM Registers"""
306 regs = [ self.ARMget_register(x) for x in range(15) ]
307 regs.append(self.ARMgetPC()) # make sure we snag the "static" version of PC
309 def ARMset_registers(self, regs, mask):
310 """Set ARM Registers"""
313 self.ARMset_register(x,regs.pop())
314 if (1<<15) & mask: # make sure we set the "static" version of PC or changes will be lost
315 self.ARMsetPC(regs.pop())
316 def ARMget_regCPSRstr(self):
317 psr = self.ARMget_regCPSR()
318 return hex(psr), PSRdecode(psr)
319 def ARMget_regCPSR(self):
320 """Get an ARM's Register"""
321 self.writecmd(0x13,GET_CPSR,0,[])
322 retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
324 def ARMset_regCPSR(self, val):
325 """Get an ARM's Register"""
326 self.writecmd(0x13,SET_CPSR,4,[val&0xff, (val>>8)&0xff, (val>>16)&0xff, val>>24])
327 def ARMcmd(self,phrase):
328 self.writecmd(0x13,READ,len(phrase),phrase)
329 val=ord(self.data[0])
330 print "Got %02x" % val
332 def ARMdebuginstr(self,instr,bkpt):
333 if type (instr) == int or type(instr) == long:
334 instr = struct.pack("<L", instr)
335 instr = [int("0x%x"%ord(x),16) for x in instr]
337 self.writecmd(0x13,DEBUG_INSTR,len(instr),instr)
339 def ARM_nop(self, bkpt):
340 return self.ARMdebuginstr(ARM_INSTR_NOP, bkpt)
341 def ARMset_IR(self, IR, noretidle=0):
342 self.writecmd(0x13,SET_IR,2, [IR, LSB|noretidle])
344 def ARMshiftDR(self, data, bits, flags):
345 self.writecmd(0x13,SHIFT_DR,8,[bits&0xff, flags&0xff, 0, 0, data&0xff,(data>>8)&0xff,(data>>16)&0xff,(data>>24)&0xff])
347 def ARMwaitDBG(self, timeout=0xff):
348 self.writecmd(0x13,WAIT_DBG,2,[timeout&0xf,timeout>>8])
350 def ARMrestart(self):
351 #self.ARMset_IR(ARM7TDMI_IR_BYPASS)
352 self.ARMset_IR(ARM7TDMI_IR_RESTART)
353 def ARMset_watchpoint0(self, addr, addrmask, data, datamask, ctrl, ctrlmask):
355 self.data.extend(chop(addr,4))
356 self.data.extend(chop(addrmask,4))
357 self.data.extend(chop(data,4))
358 self.data.extend(chop(datamask,4))
359 self.data.extend(chop(ctrl,4))
360 self.data.extend(chop(ctrlmask,4))
361 self.writecmd(0x13,SETWATCH0,24,self.data)
363 def ARMset_watchpoint1(self, addr, addrmask, data, datamask, ctrl, ctrlmask):
365 self.data.extend(chop(addr,4))
366 self.data.extend(chop(addrmask,4))
367 self.data.extend(chop(data,4))
368 self.data.extend(chop(datamask,4))
369 self.data.extend(chop(ctrl,4))
370 self.data.extend(chop(ctrlmask,4))
371 self.writecmd(0x13,SETWATCH1,24,self.data)
373 def ARMreadMem(self, adr, wrdcount):
375 r0 = self.ARMget_register(0); # store R0 and R1
376 r1 = self.ARMget_register(1);
377 #print >>sys.stderr,("CPSR:\t%x"%self.ARMget_regCPSR())
378 for word in range(adr, adr+(wrdcount*4), 4):
380 self.ARMset_register(0, word); # write address into R0
382 self.ARMset_register(1, 0xdeadbeef)
388 self.ARMdebuginstr(ARM_READ_MEM, 0); # push LDR R1, [R0], #4 into instruction pipeline (autoincrements for consecutive reads)
396 print hex(self.ARMget_register(1))
399 # FIXME: this may end up changing te current debug-state. should we compare to current_dbgstate?
400 #print repr(self.data[4])
401 if (len(self.data)>4 and self.data[4] == '\x00'):
402 print >>sys.stderr,("FAILED TO READ MEMORY/RE-ENTER DEBUG MODE")
403 raise Exception("FAILED TO READ MEMORY/RE-ENTER DEBUG MODE")
406 retval.append( self.ARMget_register(1) ) # read memory value from R1 register
407 #print >>sys.stderr,("CPSR: %x\t\tR0: %x\t\tR1: %x"%(self.ARMget_regCPSR(),self.ARMget_register(0),self.ARMget_register(1)))
408 self.ARMset_register(1, r1); # restore R0 and R1
409 self.ARMset_register(0, r0);
412 def ARMwriteMem(self, adr, wordarray):
413 r0 = self.ARMget_register(0); # store R0 and R1
414 r1 = self.ARMget_register(1);
415 #print >>sys.stderr,("CPSR:\t%x"%self.ARMget_regCPSR())
416 for word in xrange(adr, adr+len(string), 4):
417 self.ARMset_register(0, word); # write address into R0
420 self.ARMdebuginstr(ARM_WRITE_MEM, 0); # push STR R1, [R0], #4 into instruction pipeline (autoincrements for consecutive writes)
424 print hex(self.ARMget_register(1))
427 # FIXME: this may end up changing te current debug-state. should we compare to current_dbgstate?
428 #print repr(self.data[4])
429 if (len(self.data)>4 and self.data[4] == '\x00'):
430 print >>sys.stderr,("FAILED TO READ MEMORY/RE-ENTER DEBUG MODE")
431 raise Exception("FAILED TO READ MEMORY/RE-ENTER DEBUG MODE")
434 retval.append( self.ARMget_register(1) ) # read memory value from R1 register
435 #print >>sys.stderr,("CPSR: %x\t\tR0: %x\t\tR1: %x"%(self.ARMget_regCPSR(),self.ARMget_register(0),self.ARMget_register(1)))
436 self.ARMset_register(1, r1); # restore R0 and R1
437 self.ARMset_register(0, r0);
440 def ARMpeekcodewords(self,adr,words):
441 """Read the contents of code memory at an address."""
442 self.data=[adr&0xff, (adr>>8)&0xff, (adr>>16)&0xff, (adr>>24)&0xff, words&0xff, (words>>8)&0xff, (words>>16)&0xff, (words>>24)&0xff ]
443 self.writecmd(0x13,READ_CODE_MEMORY,8,self.data)
445 retval.append(self.serialport.read(words*4))
446 #retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
447 return "".join(retval)
448 def ARMpeekdatabyte(self,adr):
449 """Read the contents of data memory at an address."""
450 self.data=[ adr&0xff, (adr>>8)&0xff, (adr>>16)&0xff, (adr>>24)&0xff ]
451 self.writecmd(0x13, PEEK, 4, self.data)
452 #retval.append(self.serialport.read(words*4))
453 retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
455 def ARMpokedatabyte(self,adr,val):
456 """Write a byte to data memory."""
457 self.data=[adr&0xff, (adr>>8)&0xff, (adr>>16)&0xff, (adr>>24)&0xff, val&0xff, (val>>8)&0xff, (val>>16)&0xff, (val>>24)&0xff ]
458 self.writecmd(0x13, POKE, 8, self.data)
459 retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
461 #def ARMchiperase(self):
462 # """Erase all of the target's memory."""
463 # self.writecmd(0x13,CHIP_ERASE,0,[])
465 """Check the status."""
466 self.writecmd(0x13,GET_DEBUG_STATE,0,[])
467 return ord(self.data[0])
471 0x04 : "Interrupts Enabled (or not?)",
476 0x04 : "disable interrupts",
477 0x02 : "force dbgrq",
478 0x01 : "force dbgack"
481 def ARMstatusstr(self):
482 """Check the status as a string."""
483 status=self.ARMstatus()
488 str="%s %s" %(self.ARMstatusbits[i],str)
491 def ARMchain0(self, address, bits, data):
492 bulk = chop(address,4)
493 bulk.extend(chop(bits,8))
494 bulk.extend(chop(data,4))
496 self.writecmd(0x13,CHAIN0,16,bulk)
497 d1,b1,a1 = struct.unpack("<LQL",self.data)
500 """Start debugging."""
501 self.writecmd(0x13,START,0,self.data)
502 ident=self.ARMidentstr()
503 print "Target identifies as %s." % ident
504 print "Debug Status: %s." % self.ARMstatusstr()
505 #print "System State: %x." % self.ARMget_regCPSRstr()
506 #self.ARMreleasecpu()
510 """Stop debugging."""
511 self.writecmd(0x13,STOP,0,self.data)
512 #def ARMstep_instr(self):
513 # """Step one instruction."""
514 # self.writecmd(0x13,STEP_INSTR,0,self.data)
515 #def ARMflashpage(self,adr):
516 # """Flash 2kB a page of flash from 0xF000 in XDATA"""
521 # print "Flashing buffer to 0x%06x" % adr
522 # self.writecmd(0x13,MASS_FLASH_PAGE,4,data)
524 def writecmd(self, app, verb, count=0, data=[]):
525 """Write a command and some data to the GoodFET."""
526 self.serialport.write(chr(app))
527 self.serialport.write(chr(verb))
530 # count=len(data); #Initial count ignored.
532 #print "TX %02x %02x %04x" % (app,verb,count)
534 #little endian 16-bit length
535 self.serialport.write(chr(count&0xFF))
536 self.serialport.write(chr(count>>8))
538 #print "count=%02x, len(data)=%04x" % (count,len(data))
541 if(isinstance(data,list)):
542 for i in range(0,count):
543 #print "Converting %02x at %i" % (data[i],i)
547 self.serialport.write(outstr)
548 if not self.besilent: