AT91x40 series of ARM7 microcontrollers supported. still no flash capability yet...
[goodfet] / firmware / apps / jtag / jtagarm7.c
index 77e9c38..cd9bf63 100644 (file)
@@ -1,11 +1,10 @@
-/*! \file jtagarm7tdmi.c
+/*! \file jtagarm7.c
   \brief ARM7TDMI JTAG (AT91R40008, AT91SAM7xxx)
 */
 
 #include "platform.h"
 #include "command.h"
-#include "jtag.h"
-#include "jtagarm7tdmi.h"
+#include "jtagarm7.h"
 
 
 /**** 20-pin Connection Information (pin1 is on top-right for both connectors)****
@@ -34,17 +33,6 @@ GoodFET  ->  7TDMI 14-pin connector
 http://hri.sourceforge.net/tools/jtag_faq_org.html
 ********************************/
 
-
-// ! Start JTAG, setup pins, reset TAP and return IDCODE
-void jtagarm7tdmi_start() {
-  jtagsetup();
-  jtag_resettap();
-}
-
-
-//! Reset TAP State Machine       
-
-
 /*  WHAT SHOULD THIS MODULE DO?
  *     *start
  *     *shift_ir
@@ -59,10 +47,18 @@ void jtagarm7tdmi_start() {
  *     *set_register
  */
 
-u32 shift_ir(u32 ir){
-  u32 retval;
+// ! Start JTAG, setup pins, reset TAP and return IDCODE
+void jtagarm7tdmi_start() {
+  jtagsetup();
+  SETTST;
+  jtag_resettap();
+}
+
+
+u8 shift_ir(u8 ir, u8 flags){
+  u8 retval;
   jtag_goto_shift_ir();
-  retval = jtagtransn(ir, 4, LSB); 
+  retval = jtagtransn(ir, 4, LSB|flags); 
   return retval;
 }
 
@@ -75,12 +71,10 @@ commands occur. Therefore, it is recommended to pass directly from the “Update
 state” to the “Select DR” state each time the “Update” state is reached.
 */
   unsigned long retval;
-  jtag_goto_shift_ir();
-  jtagtransn(ARM7TDMI_IR_SCAN_N, 4, LSB | NORETIDLE);
+  shift_ir(ARM7TDMI_IR_SCAN_N, NORETIDLE);
   jtag_goto_shift_dr();
   retval = jtagtransn(chain, 4, LSB | NORETIDLE);
-  jtag_goto_shift_ir();
-  jtagtransn(testmode, 4, LSB); 
+  shift_ir(testmode, NORETIDLE); 
   return(retval);
 }
 
@@ -115,17 +109,16 @@ unsigned long jtagarm7tdmi_instr_primitive(unsigned long instr, char breakpt){
   unsigned long retval;
   jtagarm7tdmi_scan(1, ARM7TDMI_IR_INTEST);
 
+  //debughex32(instr);
   jtag_goto_shift_dr();
   // if the next instruction is to run using MCLK (master clock), set TDI
   if (breakpt)
     {
     SETMOSI;
-    count_sysspd_instr_since_debug++;
     } 
   else
     {
     CLRMOSI; 
-    count_dbgspd_instr_since_debug++;
     }
   jtag_tcktock();
   
@@ -135,52 +128,104 @@ unsigned long jtagarm7tdmi_instr_primitive(unsigned long instr, char breakpt){
 }
 
 u32 jtagarm7tdmi_nop(u8 brkpt){
+    //  WARNING: current_dbgstate must be up-to-date before calling this function!!!!!
+    if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT)
+        return jtagarm7tdmi_instr_primitive(THUMB_INSTR_NOP, brkpt);
     return jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, brkpt);
 }
 
 /******************** Complex Commands **************************/
 
 //! Retrieve a 32-bit Register value
-unsigned long jtagarm7tdmi_get_register(unsigned long reg) {                    //PROVEN
-  unsigned long retval=0L, instr;
-  if (eice_read(EICE_DBGSTATUS)& JTAG_ARM7TDMI_DBG_TBIT)
-    instr = THUMB_INSTR_STR_R0_r0 | reg | (reg<<16);
-  else
-    instr = (unsigned long)(reg<<12L) | (unsigned long)ARM_READ_REG;   // STR Rx, [R14] 
-
-  jtagarm7tdmi_nop( 0);
+unsigned long jtagarm7_get_reg_prim(unsigned long instr){
   jtagarm7tdmi_nop( 0);
   jtagarm7tdmi_instr_primitive(instr, 0);
   jtagarm7tdmi_nop( 0);
   jtagarm7tdmi_nop( 0);
   jtagarm7tdmi_nop( 0);
-  retval = jtagarm7tdmi_nop( 0);                        // recover 32-bit word
-  return retval;
+  return jtagarm7tdmi_nop( 0);                          // recover 32-bit word
 }
 
 //! Set a 32-bit Register value
-void jtagarm7tdmi_set_register(unsigned long reg, unsigned long val) {          // PROVEN (assuming target reg is word aligned)
-  unsigned long instr;
-  //if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT)
-    //instr = THUMB_WRITE_REG
-    instr = (unsigned long)(((unsigned long)reg<<12L) | ARM_WRITE_REG); //  LDR Rx, [R14]
-  
-  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
+void jtagarm7_set_reg_prim(unsigned long instr, unsigned long reg, unsigned long val){      // PROVEN - 100827 (non-PC)
+  jtagarm7tdmi_nop( 0);                                 // push nop into pipeline - executed 
+  jtagarm7tdmi_instr_primitive(instr, 0);               // push instr into pipeline - fetch
+    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
   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 
+    //debugstr("setting pc...");
+    jtagarm7tdmi_nop( 0);                               // push nop into pipeline - refill 
+    jtagarm7tdmi_nop( 0);                               // push nop into pipeline - refill 
+  }
+  jtagarm7tdmi_nop( 0);                               // push nop into pipeline - decode 
+  jtagarm7tdmi_nop( 0);                               // push nop into pipeline - execute 
+}
+
+void jtagarm7_thumb_swap_reg(unsigned char dir, unsigned long reg){                         // PROVEN - 100827
+  reg = reg & 7;
+  jtagarm7tdmi_nop( 0);
+  if (dir){
+    jtagarm7tdmi_instr_primitive((unsigned long)(THUMB_INSTR_MOV_LoHi | (reg) | (reg<<16)), 0);
+    //debughex32((unsigned long)(THUMB_INSTR_MOV_LoHi | (reg) | (reg<<16)));
   } 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_instr_primitive((unsigned long)(THUMB_INSTR_MOV_HiLo | (reg<<3) | (reg<<19)), 0);
+    //debughex32((unsigned long)(THUMB_INSTR_MOV_HiLo | (reg<<3) | (reg<<19)));
   }
-  jtagarm7tdmi_nop( 0);            // push nop into pipeline - executed 
-  jtagarm7tdmi_nop( 0);            // push nop into pipeline - executed 
+  jtagarm7tdmi_nop( 0);
+  jtagarm7tdmi_nop( 0);
   jtagarm7tdmi_nop( 0);
 }
+  
+unsigned long jtagarm7tdmi_get_register(unsigned long reg) {                                // PROVEN - 100827
+  unsigned long retval=0L, instr, r0;
+  current_dbgstate = eice_read(EICE_DBGSTATUS);
+  if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT){
+    if (reg > 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
+//  writing to a register is a problem child in ARM, actually.  if the register you are using as the indirect offset register is misaligned, your results are misaligned.
+//  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 - 100827
+  unsigned long instr, r0;
+  current_dbgstate = eice_read(EICE_DBGSTATUS);
+  if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT){
+    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 ---
+  jtagarm7_set_reg_prim(instr, reg, 0);
+  //  --- now we actually write to the register ---
+  jtagarm7_set_reg_prim(instr, reg, val);
+}
 
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -195,12 +240,10 @@ void jtagarm7tdmihandle(unsigned char app, unsigned char verb, unsigned long len
     txdata(app,verb,0);
     break;
   case JTAG_IR_SHIFT:
-    jtag_goto_shift_ir();
-    cmddataword[0] = jtagtransn(cmddata[0], 4, cmddata[1]);
-    txdata(app,verb,2);
+    cmddataword[0] = shift_ir(cmddata[0], cmddata[1]);
+    txdata(app,verb,1);
     break;
   case JTAG_DR_SHIFT:
-       jtag_resettap();
     jtag_goto_shift_dr();
     cmddatalong[0] = jtagtransn(cmddatalong[1],cmddata[0],cmddata[1]);
     txdata(app,verb,4);
@@ -208,10 +251,10 @@ void jtagarm7tdmihandle(unsigned char app, unsigned char verb, unsigned long len
   case JTAGARM7_CHAIN0:
     jtagarm7tdmi_scan(0, ARM7TDMI_IR_INTEST);
     jtag_goto_shift_dr();
-    debughex32(cmddatalong[0]);
-    debughex(cmddataword[4]);
-    debughex32(cmddatalong[1]);
-    debughex32(cmddatalong[3]);
+    //debughex32(cmddatalong[0]);
+    //debughex(cmddataword[4]);
+    //debughex32(cmddatalong[1]);
+    //debughex32(cmddatalong[3]);
     cmddatalong[0] = jtagtransn(cmddatalong[0], 32, LSB| NOEND| NORETIDLE);
     cmddatalong[2] = jtagtransn(cmddataword[4], 9, MSB| NOEND| NORETIDLE);
     cmddatalong[1] = jtagtransn(cmddatalong[1], 32, MSB| NOEND| NORETIDLE);
@@ -221,7 +264,7 @@ void jtagarm7tdmihandle(unsigned char app, unsigned char verb, unsigned long len
   case JTAGARM7_SCANCHAIN1:
   case JTAGARM7_DEBUG_INSTR:
     cmddatalong[0] = jtagarm7tdmi_instr_primitive(cmddatalong[0],cmddata[4]);
-    txdata(app,verb,8);
+    txdata(app,verb,4);
     break;
   case JTAGARM7_EICE_READ:
     cmddatalong[0] = eice_read(cmddata[0]);
@@ -240,6 +283,14 @@ void jtagarm7tdmihandle(unsigned char app, unsigned char verb, unsigned long len
     jtagarm7tdmi_set_register(cmddatalong[1], cmddatalong[0]);
     txdata(app,verb,4);
     break;
+  case JTAG_RESETTARGET:
+    //FIXME: BORKEN
+    debugstr("RESET TARGET");
+    CLRTST;
+    delay(cmddataword[0]);
+    SETTST;
+    txdata(app,verb,4);
+    break;
 
 
   //case JTAGARM7_STEP_INSTR: