From d20a94438bdb6f1e14374b2ec3c08529316714e9 Mon Sep 17 00:00:00 2001 From: dodge-this Date: Sat, 28 Aug 2010 02:12:46 +0000 Subject: [PATCH] improvements... except now arm mode set_register for r15 doesn't work right... prolly to do with fixing dclk timing issues. never was set up the way the docs said to. that must have been why it worked. however, thumb to arm and arm to thumb work well... get/set regs in thumb mode work relatively well. need to iron out get/sets and then fix offsets for halt/resume so we hit the right instruction on exit. then work on the watch/breakpoints and continuing... also need to work on the get/set multiple regs and then read/writemem of large chunks... using multiple regs :) git-svn-id: https://svn.code.sf.net/p/goodfet/code/trunk@710 12e2690d-a6be-4b82-a7b7-67c4a43b65c8 --- client/GoodFETARM.py | 556 ---------------------------------- client/GoodFETARM7.py | 30 +- firmware/apps/jtag/jtagarm7.c | 112 ++++--- firmware/include/jtagarm7.h | 51 +--- 4 files changed, 99 insertions(+), 650 deletions(-) delete mode 100644 client/GoodFETARM.py diff --git a/client/GoodFETARM.py b/client/GoodFETARM.py deleted file mode 100644 index a2212d3..0000000 --- a/client/GoodFETARM.py +++ /dev/null @@ -1,556 +0,0 @@ -#!/usr/bin/env python -# GoodFET ARM Client Library -# -# -# Good luck with alpha / beta code. -# Contributions and bug reports welcome. -# - - - -raise Exception("DEPRECATED. USE GoodFETARM7") - -import sys, binascii, struct, time -import atlasutils.smartprint as asp -from GoodFET import GoodFET -from intelhex import IntelHex - -platforms = { - "at91sam7": {0:(0x100000, "Flash before remap, SRAM after remap"), - 0x100000: (0x100000, "Internal Flash"), - 0x200000: (0x100000, "Internal SRAM"), - }, - } - - -#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 -GET_DEBUG_CTRL = 0x80 -SET_DEBUG_CTRL = 0x81 -GET_PC = 0x82 -SET_PC = 0x83 -GET_CHIP_ID = 0x84 -GET_DEBUG_STATE = 0x85 -GET_WATCHPOINT = 0x86 -SET_WATCHPOINT = 0x87 -GET_REGISTER = 0x88 -SET_REGISTER = 0x89 -GET_REGISTERS = 0x8a -SET_REGISTERS = 0x8b -HALTCPU = 0x8c -RESUMECPU = 0x8d -DEBUG_INSTR = 0x8e # -STEP_INSTR = 0x8f # -STEP_REPLACE = 0x90 # -PROGRAM_FLASH = 0x95 -LOCKCHIP = 0x96 # ?? -CHIP_ERASE = 0x97 # can do? -# Really ARM specific stuff -GET_CPSR = 0x98 -SET_CPSR = 0x99 -GET_SPSR = 0x9a -SET_SPSR = 0x9b -SET_MODE_THUMB = 0x9c -SET_MODE_ARM = 0x9d -SET_IR = 0x9e -WAIT_DBG = 0x9f -SHIFT_DR = 0xa0 -SETWATCH0 = 0xa1 -SETWATCH1 = 0xa2 -CHAIN0 = 0xa3 - - -MSB = 0 -LSB = 1 -NOEND = 2 -NORETIDLE = 4 - -PM_usr = 0b10000 -PM_fiq = 0b10001 -PM_irq = 0b10010 -PM_svc = 0b10011 -PM_abt = 0b10111 -PM_und = 0b11011 -PM_sys = 0b11111 -proc_modes = { - 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_irq: ("Abort Processor Mode", "irq", "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_PC = 0xea000000L -ARM_INSTR_BX_PC = 0xe1200010L # need to set r0 to the desired address -THUMB_INSTR_STR_R0_r0 = 0x60006000L -THUMB_INSTR_MOV_R0_PC = 0x46b846b8L -THUMB_INSTR_BX_PC = 0x47784778L -THUMB_INSTR_NOP = 0x1c001c00L -ARM_REG_PC = 15 - -ARM7TDMI_IR_EXTEST = 0x0 -ARM7TDMI_IR_SCAN_N = 0x2 -ARM7TDMI_IR_SAMPLE = 0x3 -ARM7TDMI_IR_RESTART = 0x4 -ARM7TDMI_IR_CLAMP = 0x5 -ARM7TDMI_IR_HIGHZ = 0x7 -ARM7TDMI_IR_CLAMPZ = 0x9 -ARM7TDMI_IR_INTEST = 0xC -ARM7TDMI_IR_IDCODE = 0xE -ARM7TDMI_IR_BYPASS = 0xF - - -def PSRdecode(psrval): - output = [ "(%s mode)"%proc_modes[psrval&0x1f][1] ] - for x in xrange(5,32): - if psrval & (1<> 28 - partno = (ident >> 12) & 0x10 - mfgid = ident & 0xfff - return "mfg: %x\npartno: %x\nver: %x\n(%x)" % (ver, partno, mfgid, ident); - def ARMident(self): - """Get an ARM's ID.""" - self.writecmd(0x13,GET_CHIP_ID,0,[]) - retval = struct.unpack(">8)&0xff, (val>>16)&0xff, val>>24, reg,0,0,0]) - #self.writecmd(0x13,SET_REGISTER,8,[reg,0,0,0, (val>>16)&0xff, val>>24, val&0xff, (val>>8)&0xff]) - retval = struct.unpack(">8)&0xff, (val>>16)&0xff, val>>24]) - def ARMcmd(self,phrase): - self.writecmd(0x13,READ,len(phrase),phrase) - val=ord(self.data[0]) - print "Got %02x" % val - return val - def ARMdebuginstr(self,instr,bkpt): - if type (instr) == int or type(instr) == long: - instr = struct.pack(">8)&0xff,(data>>16)&0xff,(data>>24)&0xff]) - return self.data - def ARMwaitDBG(self, timeout=0xff): - self.writecmd(0x13,WAIT_DBG,2,[timeout&0xf,timeout>>8]) - return self.data - def ARMrestart(self): - #self.ARMset_IR(ARM7TDMI_IR_BYPASS) - self.ARMset_IR(ARM7TDMI_IR_RESTART) - def ARMset_watchpoint0(self, addr, addrmask, data, datamask, ctrl, ctrlmask): - self.data = [] - self.data.extend(chop(addr,4)) - self.data.extend(chop(addrmask,4)) - self.data.extend(chop(data,4)) - self.data.extend(chop(datamask,4)) - self.data.extend(chop(ctrl,4)) - self.data.extend(chop(ctrlmask,4)) - self.writecmd(0x13,SETWATCH0,24,self.data) - return self.data - def ARMset_watchpoint1(self, addr, addrmask, data, datamask, ctrl, ctrlmask): - self.data = [] - self.data.extend(chop(addr,4)) - self.data.extend(chop(addrmask,4)) - self.data.extend(chop(data,4)) - self.data.extend(chop(datamask,4)) - self.data.extend(chop(ctrl,4)) - self.data.extend(chop(ctrlmask,4)) - self.writecmd(0x13,SETWATCH1,24,self.data) - return self.data - def ARMreadMem(self, adr, wrdcount): - retval = [] - r0 = self.ARMget_register(0); # store R0 and R1 - r1 = self.ARMget_register(1); - #print >>sys.stderr,("CPSR:\t%x"%self.ARMget_regCPSR()) - for word in range(adr, adr+(wrdcount*4), 4): - sys.stdin.readline() - self.ARMset_register(0, word); # write address into R0 - #time.sleep(1) - self.ARMset_register(1, 0xdeadbeef) - #time.sleep(1) - self.ARM_nop(0) - #time.sleep(1) - self.ARM_nop(1) - #time.sleep(1) - self.ARMdebuginstr(ARM_READ_MEM, 0); # push LDR R1, [R0], #4 into instruction pipeline (autoincrements for consecutive reads) - #time.sleep(1) - self.ARM_nop(0) - #time.sleep(1) - self.ARMrestart() - #time.sleep(1) - self.ARMwaitDBG() - #time.sleep(1) - 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 word in xrange(adr, adr+len(string), 4): - self.ARMset_register(0, 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)) - - - # 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 ARMpeekcodewords(self,adr,words): - """Read the contents of code memory at an address.""" - self.data=[adr&0xff, (adr>>8)&0xff, (adr>>16)&0xff, (adr>>24)&0xff, words&0xff, (words>>8)&0xff, (words>>16)&0xff, (words>>24)&0xff ] - self.writecmd(0x13,READ_CODE_MEMORY,8,self.data) - retval = [] - retval.append(self.serialport.read(words*4)) - #retval = struct.unpack(">8)&0xff, (adr>>16)&0xff, (adr>>24)&0xff ] - self.writecmd(0x13, PEEK, 4, self.data) - #retval.append(self.serialport.read(words*4)) - retval = struct.unpack(">8)&0xff, (adr>>16)&0xff, (adr>>24)&0xff, val&0xff, (val>>8)&0xff, (val>>16)&0xff, (val>>24)&0xff ] - self.writecmd(0x13, POKE, 8, self.data) - retval = 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) - - def writecmd(self, app, verb, count=0, data=[]): - """Write a command and some data to the GoodFET.""" - self.serialport.write(chr(app)) - self.serialport.write(chr(verb)) - count = len(data) - #if data!=None: - # count=len(data); #Initial count ignored. - - #print "TX %02x %02x %04x" % (app,verb,count) - - #little endian 16-bit length - self.serialport.write(chr(count&0xFF)) - self.serialport.write(chr(count>>8)) - - #print "count=%02x, len(data)=%04x" % (count,len(data)) - - if count!=0: - if(isinstance(data,list)): - for i in range(0,count): - #print "Converting %02x at %i" % (data[i],i) - data[i]=chr(data[i]) - #print type(data) - outstr=''.join(data) - self.serialport.write(outstr) - if not self.besilent: - self.readcmd() - - - diff --git a/client/GoodFETARM7.py b/client/GoodFETARM7.py index be1c953..4e03e50 100644 --- a/client/GoodFETARM7.py +++ b/client/GoodFETARM7.py @@ -183,6 +183,11 @@ DBGCTRLBITS = { 1<>sys.stderr,(strng) @@ -289,7 +294,7 @@ class GoodFETARM(GoodFET): self.storedPC = val def ARMget_register(self, reg): """Get an ARM's Register""" - self.writecmd(0x13,GET_REGISTER,1,[reg&0xff]) + self.writecmd(0x13,GET_REGISTER,1,[reg&0xf]) retval = struct.unpack(" 7){ + debugstr("debug: jtagarm7tdmi_get_register: thumb reg > 15"); + reg = reg & 7; + r0 = jtagarm7_get_reg_prim( THUMB_READ_REG); // save reg0 + jtagarm7_thumb_swap_reg(THUMB_SWAP_HiLo, reg); // clobber reg0 with hi reg + retval = jtagarm7_get_reg_prim( THUMB_READ_REG); // recover 32-bit word + jtagarm7_set_reg_prim( THUMB_WRITE_REG, 0, r0); // restore r0 + return retval; + } else { + instr = (unsigned long)(THUMB_READ_REG | (unsigned long)reg | (unsigned long)(reg<<16L)); + } + } else + instr = (reg<<12L) | ARM_READ_REG; // STR Rx, [R14] + return jtagarm7_get_reg_prim(instr); } //! Set a 32-bit Register value @@ -160,43 +204,29 @@ unsigned long jtagarm7tdmi_get_register(unsigned long reg) { // this set_register implementation normalizes this process at the cost of performance. since we don't know what's in the register, we set it to 0 first // we could use r14 and hope all is well, but only for arm, not thumb mode, and not always is all well then either. this is a performance trade-off we may have to revisit later // -void jtagarm7tdmi_set_register(unsigned long reg, unsigned long val) { // PROVEN (assuming target reg is word aligned) - unsigned long instr; +void jtagarm7tdmi_set_register(unsigned long reg, unsigned long val) { // PROVEN - 100827 + unsigned long instr, r0; current_dbgstate = eice_read(EICE_DBGSTATUS); if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT){ - instr = THUMB_WRITE_REG | (reg&7) | ((reg&7)<<16) | ((reg&7)<<3) | ((reg&7)<<19); + if (reg > 7){ + + r0 = jtagarm7_get_reg_prim(THUMB_READ_REG); + jtagarm7_set_reg_prim(THUMB_WRITE_REG, 0, 0); + instr = (unsigned long)(THUMB_WRITE_REG | (unsigned long)reg | (unsigned long)(reg<<16L)); + jtagarm7_set_reg_prim(instr, reg, val); + jtagarm7_thumb_swap_reg(THUMB_SWAP_LoHi, reg); // place 32-bit word into a high register + jtagarm7_set_reg_prim( THUMB_WRITE_REG, 0, r0); // restore r0 + } else + instr = THUMB_WRITE_REG | (reg) | ((reg)<<16) | ((reg)<<3) | ((reg)<<19); } else { instr = ARM_WRITE_REG | (reg<<12L) | (reg<<16); // LDR Rx, [R14] } //debughex32(instr); // --- first time to clear the register... this ensures the write is not 8-bit offset --- - jtagarm7tdmi_nop( 0); // push nop into pipeline - clean out the pipeline... - jtagarm7tdmi_nop( 0); // push nop into pipeline - clean out the pipeline... - jtagarm7tdmi_instr_primitive(instr, 0); // push instr into pipeline - fetch - if (reg == ARM_REG_PC){ - jtagarm7tdmi_instr_primitive(0, 0); // push 32-bit word on data bus - jtagarm7tdmi_nop( 0); // push nop into pipeline - executed - jtagarm7tdmi_nop( 0); // push nop into pipeline - executed - } else { - jtagarm7tdmi_nop( 0); // push nop into pipeline - decode - jtagarm7tdmi_nop( 0); // push nop into pipeline - execute - jtagarm7tdmi_instr_primitive(0, 0); // push 32-bit word on data bus - } + jtagarm7_set_reg_prim(instr, reg, 0); // --- now we actually write to the register --- - jtagarm7tdmi_nop( 0); // push nop into pipeline - executed - jtagarm7tdmi_nop( 0); // push nop into pipeline - executed - jtagarm7tdmi_instr_primitive(instr, 0); // push instr into pipeline - fetch - if (reg == ARM_REG_PC){ - jtagarm7tdmi_instr_primitive(val, 0); // push 32-bit word on data bus - jtagarm7tdmi_nop( 0); // push nop into pipeline - executed - jtagarm7tdmi_nop( 0); // push nop into pipeline - executed - } else { - jtagarm7tdmi_nop( 0); // push nop into pipeline - decode - jtagarm7tdmi_nop( 0); // push nop into pipeline - execute - jtagarm7tdmi_instr_primitive(val, 0); // push 32-bit word on data bus - } - jtagarm7tdmi_nop( 0); // push nop into pipeline - executed + jtagarm7_set_reg_prim(instr, reg, val); jtagarm7tdmi_nop( 0); // push nop into pipeline - executed jtagarm7tdmi_nop( 0); } diff --git a/firmware/include/jtagarm7.h b/firmware/include/jtagarm7.h index a67a88c..921deea 100644 --- a/firmware/include/jtagarm7.h +++ b/firmware/include/jtagarm7.h @@ -8,60 +8,17 @@ #define JTAGSTATE_ARM 0 // bit 4 on dbg status reg is low #define JTAGSTATE_THUMB 1 -#define ARMTCKTOCK CLRTCK; PLEDOUT^=PLEDPIN; SETTCK; PLEDOUT^=PLEDPIN; -// ASSUME RUN-TEST/IDLE STATE -#define SHIFT_IR SETTMS;TCKTOCK;TCKTOCK;CLRTMS;TCKTOCK;TCKTOCK; -#define SHIFT_DR SETTMS;TCKTOCK;CLRTMS;TCKTOCK;TCKTOCK; - - - unsigned char current_chain; unsigned char current_dbgstate = -1; //unsigned char last_halt_debug_state = -1; //unsigned long last_halt_pc = -1; -//void jtag_goto_shift_ir(); -//void jtag_goto_shift_dr(); -//void jtag_reset_to_runtest_idle(); -//void jtag_arm_tcktock(); - - -// JTAGARM7TDMI Commands - -//! Write data to address. -unsigned long jtagarm7tdmi_writemem(unsigned long adr, unsigned long data); -//! Read data from address -unsigned long jtagarm7tdmi_readmem(unsigned long adr); - -//! Halt the CPU -unsigned long jtagarm7tdmi_haltcpu(); -//! Release the CPU -unsigned long jtagarm7tdmi_releasecpu(); - -//! Set the program counter. -void jtagarm7tdmi_setpc(unsigned long adr); - -//! Write data to address. -unsigned long jtagarm7tdmi_writeflash(unsigned long adr, unsigned long data); - +// JTAGARM7 Commands //! Start JTAG void jtagarm7tdmi_start(void); -//! Reset TAP State Machine -void jtagarm7tdmi_resettap(); - -//! ARM-specific JTAG bit-transfer -unsigned long jtagarmtransn(unsigned long word, unsigned char bitcount, unsigned char lsb, unsigned char end, unsigned char retidle); - -//! Grab debug register - Expect chain 2 to be selected -unsigned long jtagarm7tdmi_get_dbgstate() ; -//! Grab the core ID. -unsigned long jtagarm7tdmi_idcode(); -//! Connect Bypass Register to TDO/TDI -unsigned char jtagarm7tdmi_bypass(); -//! Connect the appropriate scan chain to TDO/TDI -unsigned long jtagarm7tdmi_scan_intest(int n); + //! Set a 32-bit ARM register void jtagarm7tdmi_set_register(unsigned long reg, unsigned long val); //! Get a 32-bit ARM register @@ -171,8 +128,12 @@ The least significant bit of the instruction register is scanned in and scanned #define THUMB_READ_REG THUMB_INSTR_STR_R0_r0 #define THUMB_INSTR_MOV_R0_PC 0x46b846b8L #define THUMB_INSTR_MOV_PC_R0 0x46474647L +#define THUMB_INSTR_MOV_HiLo 0x46404640L +#define THUMB_INSTR_MOV_LoHi 0x46804680L #define THUMB_INSTR_BX_PC 0x47784778L #define THUMB_INSTR_NOP 0x1c001c00L +#define THUMB_SWAP_HiLo 0 +#define THUMB_SWAP_LoHi 1 #define ARM_REG_PC 15 #define JTAG_ARM7TDMI_DBG_DBGACK 1 -- 2.20.1