readChunk (may replace readMem) is implemented, moving memory into regs then reading...
[goodfet] / client / GoodFETARM7.py
index be1c953..21f4fe7 100644 (file)
@@ -13,8 +13,8 @@
 #  * -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
+#  * thumb mode get/set_register    - DONE!
+#  * thumb to arm mode              - DONE!
 #  * rethink the whole python/c trade-off for cross-python session debugging
 
 import sys, binascii, struct, time
@@ -133,7 +133,8 @@ 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_INSTR_STMIA_R14_r0_rx = 0xE88e0000L      # add up to 65k to indicate which registers...
+ARM_INSTR_LDMIA_R14_r0_rx = 0xE89e0000L      # 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
@@ -183,6 +184,12 @@ DBGCTRLBITS = {
         1<<ENABLE:'ENABLE',
         }
 
+LDM_BITMASKS = [(1<<x)-1 for x in xrange(16)]
+#### TOTALLY BROKEN, NEED VALIDATION AND TESTING
+PCOFF_DBGRQ = 4 * 4
+PCOFF_WATCH = 4 * 4
+PCOFF_BREAK = 4 * 4
+
 
 def debugstr(strng):
     print >>sys.stderr,(strng)
@@ -289,7 +296,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("<L", "".join(self.data[0:4]))[0]
         return retval
     def ARMset_register(self, reg, val):
@@ -339,11 +346,23 @@ class GoodFETARM(GoodFET):
         self.ARMeice_write(EICE_WP1CTRLMASK, ctrlmask);   # write 0xfffffff7 in watchpoint 1 control mask - only detect the fetch instruction
         return self.data
     def THUMBgetPC(self):
+        THUMB_INSTR_STR_R0_r0 =     0x60006000L
+        THUMB_INSTR_MOV_R0_PC =     0x46b846b8L
+        THUMB_INSTR_BX_PC =         0x47784778L
+        THUMB_INSTR_NOP =           0x1c001c00L
+
         r0 = self.ARMget_register(0)
         self.ARMdebuginstr(THUMB_INSTR_MOV_R0_PC, 0)
         retval = self.ARMget_register(0)
         self.ARMset_register(0,r0)
         return retval
+    def ARMcapture_system_state(self, pcoffset):
+        if self.ARMget_dbgstate() & DBG_TBIT:
+            pcoffset += 8
+        else:
+            pcoffset += 4
+        self.storedPC = self.ARMget_register(15) + pcoffset
+        self.last_dbg_state = self.ARMget_dbgstate()
     def ARMhaltcpu(self):
         """Halt the CPU."""
         if not(self.ARMget_dbgstate()&1):
@@ -351,7 +370,7 @@ class GoodFETARM(GoodFET):
             if (self.ARMwaitDBG() == 0):
                 raise Exception("Timeout waiting to enter DEBUG mode on HALT")
             self.ARMset_dbgctrl(0)
-            self.last_dbg_state = self.ARMget_dbgstate()
+            self.ARMcapture_system_state(PCOFF_DBGRQ)
             if self.last_dbg_state&0x10:
                 self.storedPC = self.THUMBgetPC()
             else:
@@ -394,7 +413,7 @@ class GoodFETARM(GoodFET):
             print hex(self.storedPC)
             print hex(self.ARMget_register(15))
             print hex(self.ARMchain0(self.storedPC,self.flags)[0])
-            self.ARMdebuginstr(THUMB_INSTR_B_IMM | (0x7fc07fc))
+            self.ARMdebuginstr(THUMB_INSTR_B_IMM | (0x7fc07fc),0)
             self.ARM_nop()
             self.ARMrestart()
 
@@ -406,12 +425,7 @@ class GoodFETARM(GoodFET):
         r0 = None
         if ((self.current_dbgstate & DBG_TBIT)):
             debugstr("=== Switching to ARM mode ===")
-            #r0 = self.ARMget_register(0)
             self.ARM_nop(0)
-            #self.ARMdebuginstr(THUMB_INSTR_NOP,0)
-            #self.ARMdebuginstr(THUMB_INSTR_STR_R0_r0,0)
-            #self.ARMdebuginstr(THUMB_INSTR_MOV_R0_PC,0)
-            #self.ARMdebuginstr(THUMB_INSTR_STR_R0_r0,0)
             self.ARMdebuginstr(THUMB_INSTR_BX_PC,0)
             self.ARM_nop(0)
             self.ARM_nop(0)
@@ -423,12 +437,14 @@ class GoodFETARM(GoodFET):
         debugstr("=== Switching to THUMB mode ===")
         if ( not (self.current_dbgstate & DBG_TBIT)):
             self.storedPC |= 1
+            r0 = self.ARMget_register(0)
             self.ARMset_register(0, self.storedPC)
             self.ARM_nop(0)
             self.ARMdebuginstr(ARM_INSTR_BX_R0,0)
             self.ARM_nop(0)
             self.ARM_nop(0)
             self.resettap()
+            self.ARMset_register(0,r0)
         self.current_dbgstate = self.ARMget_dbgstate();
         return self.current_dbgstate
     def ARMget_regCPSRstr(self):
@@ -483,7 +499,28 @@ class GoodFETARM(GoodFET):
         self.ARMset_register(1, r1);       # restore R0 and R1 
         self.ARMset_register(0, r0);
         return retval
-
+    def ARMreadChunk(self, adr, wordcount):         
+        """ Only works in ARM mode currently
+        WARNING: Addresses must be word-aligned!
+        """
+        regs = self.ARMget_registers()
+        output = []
+        count = wordcount
+        while (wordcount > 0):
+            count = (wordcount, 0xe)[wordcount>0xd]
+            bitmask = LDM_BITMASKS[count]
+            self.ARMset_register(14,adr)
+            self.ARM_nop(1)
+            self.ARMdebuginstr(ARM_INSTR_LDMIA_R14_r0_rx | bitmask ,0)
+            #FIXME: do we need the extra nop here?
+            self.ARMrestart()
+            self.ARMwaitDBG()
+            output.extend([self.ARMget_register(x) for x in xrange(count)])
+            wordcount -= count
+            adr += count*4
+            print hex(adr)
+        # FIXME: handle the rest of the wordcount here.
+        return output
     def ARMwriteMem(self, adr, wordarray):
         r0 = self.ARMget_register(0);        # store R0 and R1
         r1 = self.ARMget_register(1);