From 6ec4512553ac11e9893437fd80ab21992f0ab4f5 Mon Sep 17 00:00:00 2001 From: dodge-this Date: Sun, 22 Aug 2010 06:55:01 +0000 Subject: [PATCH] omj, i can't believe i left this one out. sheesh. i'm stupid. git-svn-id: https://svn.code.sf.net/p/goodfet/code/trunk@706 12e2690d-a6be-4b82-a7b7-67c4a43b65c8 --- client/GoodFETARM7.py | 549 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 549 insertions(+) create mode 100644 client/GoodFETARM7.py diff --git a/client/GoodFETARM7.py b/client/GoodFETARM7.py new file mode 100644 index 0000000..be1c953 --- /dev/null +++ b/client/GoodFETARM7.py @@ -0,0 +1,549 @@ +#!/usr/bin/env python +# GoodFET ARM Client Library +# +# +# Good luck with alpha / beta code. +# Contributions and bug reports welcome. +# +# todo: +# * full cycle debugging.. halt to resume +# * ensure correct PC handling +# * flash manipulation (probably need to get the specific chip for this one) +# * set security (chip-specific) +# * -ancilary/faster- ldm/stm versions of memory access (had trouble in past, possibly also due to haphazard abuse of DCLK) +# +# fixme now stuff: +# * thumb mode get/set_register +# * thumb to arm mode +# * rethink the whole python/c trade-off for cross-python session debugging + +import sys, binascii, struct, time +import atlasutils.smartprint as asp +from GoodFET import GoodFET +from intelhex import IntelHex + + +#Global Commands +READ = 0x00 +WRITE = 0x01 +PEEK = 0x02 +POKE = 0x03 +SETUP = 0x10 +START = 0x20 +STOP = 0x21 +CALL = 0x30 +EXEC = 0x31 +NOK = 0x7E +OK = 0x7F + +# ARM7TDMI JTAG commands +IR_SHIFT = 0x80 +DR_SHIFT = 0x81 +RESETTAP = 0x82 +RESETTARGET = 0x86 +GET_REGISTER = 0x87 +SET_REGISTER = 0x88 +DEBUG_INSTR = 0x89 +# Really ARM specific stuff +WAIT_DBG = 0x91 +CHAIN0 = 0x93 +SCANCHAIN1 = 0x94 +EICE_READ = 0x95 +EICE_WRITE = 0x96 + +IR_EXTEST = 0x0 +IR_SCAN_N = 0x2 +IR_SAMPLE = 0x3 +IR_RESTART = 0x4 +IR_CLAMP = 0x5 +IR_HIGHZ = 0x7 +IR_CLAMPZ = 0x9 +IR_INTEST = 0xC +IR_IDCODE = 0xE +IR_BYPASS = 0xF + +DBG_DBGACK = 1 +DBG_DBGRQ = 2 +DBG_IFEN = 4 +DBG_cgenL = 8 +DBG_TBIT = 16 + + +EICE_DBGCTRL = 0 # read 3 bit - Debug Control +EICE_DBGCTRL_BITLEN = 3 +EICE_DBGSTATUS = 1 # read 5 bit - Debug Status +EICE_DBGSTATUS_BITLEN = 5 +EICE_DBGCCR = 4 # read 6 bit - Debug Comms Control Register +EICE_DBGCCR_BITLEN = 6 +EICE_DBGCDR = 5 # r/w 32 bit - Debug Comms Data Register +EICE_WP0ADDR = 8 # r/w 32 bit - Watchpoint 0 Address +EICE_WP0ADDRMASK = 9 # r/w 32 bit - Watchpoint 0 Addres Mask +EICE_WP0DATA = 10 # r/w 32 bit - Watchpoint 0 Data +EICE_WP0DATAMASK = 11 # r/w 32 bit - Watchpoint 0 Data Masl +EICE_WP0CTRL = 12 # r/w 9 bit - Watchpoint 0 Control Value +EICE_WP0CTRLMASK = 13 # r/w 8 bit - Watchpoint 0 Control Mask +EICE_WP1ADDR = 16 # r/w 32 bit - Watchpoint 0 Address +EICE_WP1ADDRMASK = 17 # r/w 32 bit - Watchpoint 0 Addres Mask +EICE_WP1DATA = 18 # r/w 32 bit - Watchpoint 0 Data +EICE_WP1DATAMASK = 19 # r/w 32 bit - Watchpoint 0 Data Masl +EICE_WP1CTRL = 20 # r/w 9 bit - Watchpoint 0 Control Value +EICE_WP1CTRLMASK = 21 # r/w 8 bit - Watchpoint 0 Control Mask + +MSB = 0 +LSB = 1 +NOEND = 2 +NORETIDLE = 4 + +F_TBIT = 1<<40 + +PM_usr = 0b10000 +PM_fiq = 0b10001 +PM_irq = 0b10010 +PM_svc = 0b10011 +PM_abt = 0b10111 +PM_und = 0b11011 +PM_sys = 0b11111 +proc_modes = { + 0: ("UNKNOWN, MESSED UP PROCESSOR MODE","fsck", "This should Never happen. MCU is in funky state!"), + PM_usr: ("User Processor Mode", "usr", "Normal program execution mode"), + PM_fiq: ("FIQ Processor Mode", "fiq", "Supports a high-speed data transfer or channel process"), + PM_irq: ("IRQ Processor Mode", "irq", "Used for general-purpose interrupt handling"), + PM_svc: ("Supervisor Processor Mode", "svc", "A protected mode for the operating system"), + PM_abt: ("Abort Processor Mode", "abt", "Implements virtual memory and/or memory protection"), + PM_und: ("Undefined Processor Mode", "und", "Supports software emulation of hardware coprocessor"), + PM_sys: ("System Processor Mode", "sys", "Runs privileged operating system tasks (ARMv4 and above)"), +} + +PSR_bits = [ + None, None, None, None, None, "Thumb", "nFIQ_int", "nIRQ_int", + "nImprDataAbort_int", "BIGendian", None, None, None, None, None, None, + "GE_0", "GE_1", "GE_2", "GE_3", None, None, None, None, + "Jazelle", None, None, "Q (DSP-overflow)", "oVerflow", "Carry", "Zero", "Neg", + ] + +ARM_INSTR_NOP = 0xe1a00000L +ARM_INSTR_BX_R0 = 0xe12fff10L +ARM_INSTR_STR_Rx_r14 = 0xe58f0000L # from atmel docs +ARM_READ_REG = ARM_INSTR_STR_Rx_r14 +ARM_INSTR_LDR_Rx_r14 = 0xe59f0000L # from atmel docs +ARM_WRITE_REG = ARM_INSTR_LDR_Rx_r14 +ARM_INSTR_LDR_R1_r0_4 = 0xe4901004L +ARM_READ_MEM = ARM_INSTR_LDR_R1_r0_4 +ARM_INSTR_STR_R1_r0_4 = 0xe4801004L +ARM_WRITE_MEM = ARM_INSTR_STR_R1_r0_4 +ARM_INSTR_MRS_R0_CPSR = 0xe10f0000L +ARM_INSTR_MSR_cpsr_cxsf_R0 =0xe12ff000L +ARM_INSTR_STMIA_R14_r0_rx = 0xE88E0000L # add up to 65k to indicate which registers... +ARM_STORE_MULTIPLE = ARM_INSTR_STMIA_R14_r0_rx +ARM_INSTR_SKANKREGS = 0xE88F7fffL +ARM_INSTR_CLOBBEREGS = 0xE89F7fffL + +ARM_INSTR_B_IMM = 0xea000000L +ARM_INSTR_B_PC = 0xea000000L +ARM_INSTR_BX_PC = 0xe1200010L # need to set r0 to the desired address +THUMB_INSTR_LDR_R0_r0 = 0x68006800L +THUMB_WRITE_REG = THUMB_INSTR_LDR_R0_r0 +THUMB_INSTR_STR_R0_r0 = 0x60006000L +THUMB_READ_REG = THUMB_INSTR_STR_R0_r0 +THUMB_INSTR_MOV_R0_PC = 0x46b846b8L +THUMB_INSTR_MOV_PC_R0 = 0x46474647L +THUMB_INSTR_BX_PC = 0x47784778L +THUMB_INSTR_NOP = 0x1c001c00L +THUMB_INSTR_B_IMM = 0xe000e000L +ARM_REG_PC = 15 + +nRW = 0 +MAS0 = 1 +MAS1 = 2 +nOPC = 3 +nTRANS = 4 +EXTERN = 5 +CHAIN = 6 +RANGE = 7 +ENABLE = 8 + +DBGCTRLBITS = { + 'nRW':nRW, + 'MAS0':MAS0, + 'MAS1':MAS1, + 'nOPC':nOPC, + 'nTRANS':nTRANS, + 'EXTERN':EXTERN, + 'CHAIN':CHAIN, + 'RANGE':RANGE, + 'ENABLE':ENABLE, + 1<>sys.stderr,(strng) +def PSRdecode(psrval): + output = [ "(%s mode)"%proc_modes[psrval&0x1f][1] ] + for x in xrange(5,32): + if psrval & (1<>8)&0xff,(data>>16)&0xff,(data>>24)&0xff]) + return self.data + def ARMwaitDBG(self, timeout=0xff): + self.current_dbgstate = self.ARMget_dbgstate() + while ( not ((self.current_dbgstate & 9L) == 9)): + timeout -=1 + self.current_dbgstate = self.ARMget_dbgstate() + return timeout + def ARMident(self): + """Get an ARM's ID.""" + self.ARMshift_IR(IR_IDCODE,0) + self.ARMshift_DR(0,32,LSB) + retval = struct.unpack("> 28 + partno = (ident >> 12) & 0x10 + mfgid = ident & 0xfff + return "mfg: %x\npartno: %x\nver: %x\n(%x)" % (ver, partno, mfgid, ident); + def ARMeice_write(self, reg, val): + data = chop(val,4) + data.extend([reg]) + retval = self.writecmd(0x13, EICE_WRITE, 5, data) + return retval + def ARMeice_read(self, reg): + self.writecmd(0x13, EICE_READ, 1, [reg]) + retval, = struct.unpack(">8)&0xff, (val>>16)&0xff, val>>24, reg,0,0,0]) + retval = struct.unpack(">sys.stderr,("CPSR:\t%x"%self.ARMget_regCPSR()) + self.ARMset_register(0, adr); # write address into R0 + self.ARMset_register(1, 0xdeadbeef) + for word in range(adr, adr+(wrdcount*4), 4): + #sys.stdin.readline() + self.ARM_nop(0) + self.ARM_nop(1) + self.ARMdebuginstr(ARM_READ_MEM, 0); # push LDR R1, [R0], #4 into instruction pipeline (autoincrements for consecutive reads) + self.ARM_nop(0) + self.ARMrestart() + self.ARMwaitDBG() + print hex(self.ARMget_register(1)) + + # FIXME: this may end up changing te current debug-state. should we compare to current_dbgstate? + #print repr(self.data[4]) + if (len(self.data)>4 and self.data[4] == '\x00'): + print >>sys.stderr,("FAILED TO READ MEMORY/RE-ENTER DEBUG MODE") + raise Exception("FAILED TO READ MEMORY/RE-ENTER DEBUG MODE") + return (-1); + else: + retval.append( self.ARMget_register(1) ) # read memory value from R1 register + #print >>sys.stderr,("CPSR: %x\t\tR0: %x\t\tR1: %x"%(self.ARMget_regCPSR(),self.ARMget_register(0),self.ARMget_register(1))) + self.ARMset_register(1, r1); # restore R0 and R1 + self.ARMset_register(0, r0); + return retval + + def ARMwriteMem(self, adr, wordarray): + r0 = self.ARMget_register(0); # store R0 and R1 + r1 = self.ARMget_register(1); + #print >>sys.stderr,("CPSR:\t%x"%self.ARMget_regCPSR()) + for widx in xrange(len(wordarray)): + address = adr + (widx*4) + word = wordarray[widx] + self.ARMset_register(0, address); # write address into R0 + self.ARMset_register(1, word); # write address into R0 + self.ARM_nop(0) + self.ARM_nop(1) + self.ARMdebuginstr(ARM_WRITE_MEM, 0); # push STR R1, [R0], #4 into instruction pipeline (autoincrements for consecutive writes) + self.ARM_nop(0) + self.ARMrestart() + self.ARMwaitDBG() + print hex(self.ARMget_register(1)) + self.ARMset_register(1, r1); # restore R0 and R1 + self.ARMset_register(0, r0); + + ARMstatusbits={ + 0x10 : "TBIT", + 0x08 : "cgenL", + 0x04 : "Interrupts Enabled (or not?)", + 0x02 : "DBGRQ", + 0x01 : "DGBACK" + } + ARMctrlbits={ + 0x04 : "disable interrupts", + 0x02 : "force dbgrq", + 0x01 : "force dbgack" + } + + def ARMchain0(self, address, bits=0x819684c054, data=0): + bulk = chop(address,4) + bulk.extend(chop(bits,8)) + bulk.extend(chop(data,4)) + print (repr(bulk)) + self.writecmd(0x13,CHAIN0,16,bulk) + d1,b1,a1 = struct.unpack(">8)&0xFF, + # (adr>>16)&0xFF, + # (adr>>24)&0xFF] + # print "Flashing buffer to 0x%06x" % adr + # self.writecmd(0x13,MASS_FLASH_PAGE,4,data) + + -- 2.20.1