Introduction of buggy arm jtag code. Still working out instruction pipeline bugs...
authordodge-this <dodge-this@12e2690d-a6be-4b82-a7b7-67c4a43b65c8>
Fri, 12 Mar 2010 05:27:31 +0000 (05:27 +0000)
committerdodge-this <dodge-this@12e2690d-a6be-4b82-a7b7-67c4a43b65c8>
Fri, 12 Mar 2010 05:27:31 +0000 (05:27 +0000)
I'm sure there are many other bugs, and the code may be ugly and suboptimial, but it's a base to work from.  hack fun!

git-svn-id: https://svn.code.sf.net/p/goodfet/code/trunk@402 12e2690d-a6be-4b82-a7b7-67c4a43b65c8

firmware/apps/jtag/jtagarm7tdmi.c [new file with mode: 0644]
firmware/include/jtagarm7tdmi.h [new file with mode: 0644]

diff --git a/firmware/apps/jtag/jtagarm7tdmi.c b/firmware/apps/jtag/jtagarm7tdmi.c
new file mode 100644 (file)
index 0000000..25138f7
--- /dev/null
@@ -0,0 +1,1058 @@
+/*! \file jtagarm7tdmi.c
+  \author Matthew Carpenter <matt@inguardians.com>
+  \brief ARM7TDMI JTAG (AT91R40008)
+*/
+
+#include "platform.h"
+#include "command.h"
+#include "jtag.h"
+#include "jtagarm7tdmi.h"
+
+
+/**** 20-pin Connection Information (pin1 is on top-right for both connectors)****
+GoodFET  ->  7TDMI 20-pin connector (HE-10 connector)
+  1               13 (TDO)
+  2               1  (Vdd)
+  3               5  (TDI)
+  5               7  (TMS)
+  7               9  (TCK)
+  8               15 (nRST)
+  9               4,6,8,10,12,14,16,18,20 (GND)
+  11              17/3 (nTRST)  (different sources suggest 17 or 3 alternately)
+********************************/
+
+/**** 14-pin Connection Information (pin1 is on top-right for both connectors)****
+GoodFET  ->  7TDMI 14-pin connector
+  1               11 (TDO)
+  2               1  (Vdd)
+  3               5  (TDI)
+  5               7  (TMS)
+  7               9  (TCK)
+  8               12 (nRST)
+  9               2,4,6,8,10,14 (GND)
+  11              3 (nTRST)
+
+http://hri.sourceforge.net/tools/jtag_faq_org.html
+********************************/
+
+/****************************************************************
+Enabling jtag likely differs with most platforms.  We will attempt to enable most from here.  Override jtagarm7tdmi_start() to extend for other implementations
+ARM7TDMI enables three different scan chains:
+    * Chain0 - "entire periphery" including data bus
+    * Chain1 - core data bus (subset of Chain0)  - Instruction Pipeline
+    * Chain2 - EmbeddedICE Logic Registers - This is our way into the fun stuff.
+    
+
+---
+You can disable EmbeddedICE-RT by setting the DBGEN input LOW.
+Caution
+Hard wiring the DBGEN input LOW permanently disables all debug functionality.
+When DBGEN is LOW, it inhibits DBGDEWPT, DBGIEBKPT, and EDBGRQ to
+the core, and DBGACK from the ARM9E-S core is always LOW.
+---
+
+
+---
+When the ARM9E-S core is in debug state, you can examine the core and system state
+by forcing the load and store multiples into the instruction pipeline.
+Before you can examine the core and system state, the debugger must determine
+whether the processor entered debug from Thumb state or ARM state, by examining
+bit 4 of the EmbeddedICE-RT debug status register. If bit 4 is HIGH, the core has
+entered debug from Thumb state.
+For more details about determining the core state, see Determining the core and system
+state on page B-18.
+---
+
+
+--- olimex - http://www.olimex.com/dev/pdf/arm-jtag.pdf
+JTAG signals description:
+PIN.1 (VTREF) Target voltage sense. Used to indicate the target’s operating voltage to thedebug tool.
+PIN.2 (VTARGET) Target voltage. May be used to supply power to the debug tool.
+PIN.3 (nTRST) JTAG TAP reset, this signal should be pulled up to Vcc in target board.
+PIN4,6, 8, 10,12,14,16,18,20 Ground. The Gnd-Signal-Gnd-Signal strategy implemented on the 20-way connection scheme improves noiseimmunity on the target connect cable.
+*PIN.5 (TDI) JTAG serial data in, should be pulled up to Vcc on target board.
+*PIN.7 (TMS) JTAG TAP Mode Select, should be pulled up to Vcc on target board.
+*PIN.9 (TCK) JTAG clock.
+PIN.11 (RTCK) JTAG retimed clock.Implemented on certain ASIC ARM implementations the host ASIC may need to synchronize external inputs (such as JTAG inputs) with its own internal clock.
+*PIN.13 (TDO) JTAG serial data out.
+*PIN.15 (nSRST) Target system reset.
+*PIN.17 (DBGRQ) Asynchronous debug request.  DBGRQ allows an external signal to force the ARM core into debug mode, should be pull down to GND.
+PIN.19 (DBGACK) Debug acknowledge. The ARM core acknowledges debug-mode inresponse to a DBGRQ input.
+
+****************************************************************/
+
+
+/************************** JTAGARM7TDMI Primitives ****************************/
+void jtag_goto_shift_ir() {
+  SETTMS;
+  jtag_arm_tcktock();
+  jtag_arm_tcktock();
+  CLRTMS;
+  jtag_arm_tcktock();
+  jtag_arm_tcktock();
+
+}
+
+void jtag_goto_shift_dr() {
+  SETTMS;
+  jtag_arm_tcktock();
+  CLRTMS;
+  jtag_arm_tcktock();
+  jtag_arm_tcktock();
+}
+
+void jtag_reset_to_runtest_idle() {
+  SETTMS;
+  jtag_arm_tcktock();
+  jtag_arm_tcktock();
+  jtag_arm_tcktock();
+  jtag_arm_tcktock();
+  jtag_arm_tcktock();  // now in Reset state
+  CLRTMS;
+  jtag_arm_tcktock();  // now in Run-Test/Idle state
+}
+
+void jtag_arm_tcktock() {
+  CLRTCK; 
+  PLEDOUT^=PLEDPIN; 
+  delay(5);
+  SETTCK; 
+  PLEDOUT^=PLEDPIN;
+}
+
+// ! Start JTAG, setup pins, reset TAP and return IDCODE
+unsigned long jtagarm7tdmi_start() {
+  jtagsetup();
+  //Known-good starting position.
+  //Might be unnecessary.
+  SETTST;
+  SETRST;
+  
+  delay(0xFF);
+  
+  //Entry sequence from Page 67 of SLAU265A for 4-wire JTAG
+  CLRRST;
+  delay(20);
+  CLRTST;
+
+  msdelay(10);
+  SETRST;
+  /*
+  P5DIR &=~RST;
+  */
+  delay(0xFF);
+  jtagarm7tdmi_resettap();
+  current_chain = 3;
+  return jtagarm7tdmi_idcode();
+}
+
+
+//! Reset TAP State Machine       
+void jtagarm7tdmi_resettap(){               // PROVEN
+  jtag_reset_to_runtest_idle();
+}
+
+//! Shift N bits over TDI/TDO.  May choose LSB or MSB, and select whether to terminate (TMS-high on last bit) and whether to return to RUNTEST/IDLE
+unsigned long jtagarmtransn(unsigned long word, unsigned char bitcount, unsigned char lsb, unsigned char end, unsigned char retidle){               // PROVEN
+  unsigned int bit;
+  unsigned long high = 1;
+  unsigned long mask;
+
+  for (bit=(bitcount-1)/8; bit>0; bit--)
+    high <<= 8;
+  high <<= ((bitcount-1)%8);
+
+  mask = high-1;
+
+  if (lsb) {
+    for (bit = bitcount; bit > 0; bit--) {
+      /* write MOSI on trailing edge of previous clock */
+      if (word & 1)
+        {SETMOSI;}
+      else
+        {CLRMOSI;}
+      word >>= 1;
+
+      if (bit==1 && end)
+        SETTMS;//TMS high on last bit to exit.
+       
+      jtag_arm_tcktock();
+
+      /* read MISO on trailing edge */
+      if (READMISO){
+        word += (high);
+      }
+    }
+  } else {
+    for (bit=bitcount; bit>0; bit++) {
+      /* write MOSI on trailing edge of previous clock */
+      if (word & high)
+        {SETMOSI;}
+      else
+        {CLRMOSI;}
+      word = (word & mask) << 1;
+
+      if (bit==1 && end)
+        SETTMS;//TMS high on last bit to exit.
+
+      jtag_arm_tcktock();
+
+      /* read MISO on trailing edge */
+      word |= READMISO;
+    }
+  }
+
+  if (end){
+    // exit state
+    jtag_arm_tcktock();
+    // update state
+    if (retidle){
+      CLRTMS;
+      jtag_arm_tcktock();
+    }
+  }
+  return word;
+}
+
+
+
+//! push an instruction into the pipeline  - Assumes scan-chain 1 is already INTEST
+unsigned long jtagarm7tdmi_instr_primitive(unsigned long instr, char breakpt){               // PROVEN
+  unsigned long retval;
+  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_arm_tcktock();
+  
+  // Now shift in the 32 bits
+  retval = jtagarmtransn(instr, 32, MSB, END, RETIDLE);    // Must return to RUN-TEST/IDLE state for instruction to enter pipeline, and causes debug clock.
+  jtag_arm_tcktock();
+  return(retval);
+  
+}
+
+/*    stolen from ARM DDI0029G documentation, translated using ARM Architecture Reference Manual (14128.pdf)
+STR R0, [R0]; Save R0 before use
+MOV R0, PC ; Copy PC into R0
+STR R0, [R0]; Now save the PC in R0
+BX PC ; Jump into ARM state
+MOV R8, R8 ;
+MOV R8, R8 ;
+NOP
+NOP
+
+*/
+//! set the current mode to ARM, returns PC (FIXME).  Should be used by haltcpu(), which should also store PC and the THUMB state, for use by releasecpu();
+unsigned long jtagarm7tdmi_setMode_ARM(){               // PROVEN
+  unsigned long retval = 0xff;
+  while ((jtagarm7tdmi_get_dbgstate() & JTAG_ARM7TDMI_DBG_TBIT)&& retval-- > 0){
+    jtagarm7tdmi_scan_intest(1);
+    cmddataword[1] = jtagarm7tdmi_instr_primitive(THUMB_INSTR_STR_R0_r0,0);
+    cmddataword[2] = jtagarm7tdmi_instr_primitive(THUMB_INSTR_MOV_R0_PC,0);
+    cmddataword[3] = jtagarm7tdmi_instr_primitive(THUMB_INSTR_STR_R0_r0,0);
+    cmddataword[4] = jtagarm7tdmi_instr_primitive(THUMB_INSTR_BX_PC,0);
+    cmddataword[5] = jtagarm7tdmi_instr_primitive(THUMB_INSTR_NOP,0);
+    cmddataword[6] = jtagarm7tdmi_instr_primitive(THUMB_INSTR_NOP,0);
+    delay(10);
+  }
+  return(retval);
+}
+
+
+
+
+/************************* EmbeddedICE Primitives ****************************/
+//! shifter for writing to chain2 (EmbeddedICE). 
+unsigned long eice_write(unsigned char reg, unsigned long data){
+  unsigned long retval, temp;
+  jtagarm7tdmi_scan_intest(2);
+  // Now shift in the 32 bits
+  SHIFT_DR;
+  retval = jtagarmtransn(data, 32, LSB, NOEND, NORETIDLE);          // send in the data - 32-bits lsb
+  temp = jtagarmtransn(reg, 5, LSB, NOEND, NORETIDLE);              // send in the register address - 5 bits lsb
+  jtagarmtransn(1, 1, LSB, END, RETIDLE);              // send in the register address - 5 bits lsb
+  
+  //SETTMS;   // Last Bit - Exit UPDATE_DR
+  //// is this update a read/write or just read?
+  //SETMOSI;
+  //jtag_arm_tcktock();
+  
+  return(retval); 
+}
+
+//! shifter for reading from chain2 (EmbeddedICE).
+unsigned long eice_read(unsigned char reg){               // PROVEN
+  unsigned long temp;
+  jtagarm7tdmi_scan_intest(2);
+
+  // send in the register address - 5 bits LSB
+  SHIFT_DR;
+  temp = jtagarmtransn(reg, 5, LSB, NOEND, NORETIDLE);
+  
+  // clear TDI to select "read only"
+  jtagarmtransn(0, 1, LSB, END, RETIDLE);
+  
+  SHIFT_DR;
+  // Now shift out the 32 bits
+  return(jtagarmtransn(0, 32, LSB, END, RETIDLE));   // atmel arm jtag docs pp.10-11: LSB first
+  
+}
+
+
+
+
+/************************************************************************
+* ARM7TDMI core has 6 primary registers to be connected between TDI/TDO
+*   * Bypass Register
+*   * ID Code Register
+*   * Scan Chain Select Register    (4 bits_lsb)
+*   * Scan Chain 0                  (64+* bits: 32_databits_lsb + ctrlbits + 32_addrbits_msb)
+*   * Scan Chain 1                  (33 bits: 32_bits + BREAKPT)
+*   * Scan Chain 2                  (38 bits: rw + 5_regbits_msb + 32_databits_msb)
+************************************************************************/
+
+
+
+/************************** Basic JTAG Verb Commands *******************************/
+//! Grab the core ID.
+unsigned long jtagarm7tdmi_idcode(){               // PROVEN
+  SHIFT_IR;
+  jtagarmtransn(ARM7TDMI_IR_IDCODE, 4, LSB, END, RETIDLE);
+  SHIFT_DR;
+  return jtagarmtransn(0,32, LSB, END, RETIDLE);
+}
+
+//!  Connect Bypass Register to TDO/TDI
+unsigned char jtagarm7tdmi_bypass(){               // PROVEN
+  SHIFT_IR;
+  return jtagarmtransn(ARM7TDMI_IR_BYPASS, 4, LSB, END, NORETIDLE);
+}
+//!  INTEST verb - do internal test
+unsigned char jtagarm7tdmi_intest() { 
+  SHIFT_IR;
+  return jtagarmtransn(ARM7TDMI_IR_INTEST, 4, LSB, END, NORETIDLE); 
+}
+
+//!  EXTEST verb
+unsigned char jtagarm7tdmi_extest() { 
+  SHIFT_IR;
+  return jtagarmtransn(ARM7TDMI_IR_EXTEST, 4, LSB, END, NORETIDLE);
+}
+
+//!  SAMPLE verb
+//unsigned long jtagarm7tdmi_sample() { 
+//  jtagarm7tdmi_ir_shift4(ARM7TDMI_IR_SAMPLE);        // ???? same here.
+//  return jtagtransn(0,32);
+//}
+
+//!  RESTART verb
+unsigned char jtagarm7tdmi_restart() { 
+  SHIFT_IR;
+  return jtagarmtransn(ARM7TDMI_IR_RESTART, 4, LSB, END, RETIDLE); 
+}
+
+//!  ARM7TDMI_IR_CLAMP               0x5
+unsigned long jtagarm7tdmi_clamp() { 
+  SHIFT_IR;
+  jtagarmtransn(ARM7TDMI_IR_CLAMP, 4, LSB, END, NORETIDLE);
+  SHIFT_DR;
+  return jtagarmtransn(0, 32, LSB, END, RETIDLE);
+}
+
+//!  ARM7TDMI_IR_HIGHZ               0x7
+unsigned char jtagarm7tdmi_highz() { 
+  SHIFT_IR;
+  return jtagarmtransn(ARM7TDMI_IR_HIGHZ, 4, LSB, END, NORETIDLE);
+}
+
+//! define ARM7TDMI_IR_CLAMPZ              0x9
+unsigned char jtagarm7tdmi_clampz() { 
+  SHIFT_IR;
+  return jtagarmtransn(ARM7TDMI_IR_CLAMPZ, 4, LSB, END, NORETIDLE);
+}
+
+
+//!  Connect the appropriate scan chain to TDO/TDI.  SCAN_N, INTEST, ENDS IN SHIFT_DR!!!!!
+unsigned long jtagarm7tdmi_scan_intest(int chain) {               // PROVEN
+  unsigned long retval;
+  if (current_chain == chain)
+    return current_chain;
+  jtagarm7tdmi_resettap();  // assumed already sane?
+  SHIFT_IR;
+  jtagarmtransn(ARM7TDMI_IR_SCAN_N, 4, LSB, END, NORETIDLE);
+  SHIFT_DR;
+  retval = jtagarmtransn(chain, 4, LSB, END, NORETIDLE);
+  current_chain = chain;
+  jtagarm7tdmi_intest();
+  //SHIFT_DR;
+  return(retval);
+}
+
+
+
+
+/************************* ICEBreaker/EmbeddedICE Stuff ******************************/
+//! Grab debug register
+unsigned long jtagarm7tdmi_get_dbgstate() {       // ICE Debug register, *NOT* ARM register DSCR    //    PROVEN
+  jtagarm7tdmi_resettap();
+  jtagarm7tdmi_scan_intest(2);                         // select ICEBreaker
+  return eice_read(EICE_DBGSTATUS);
+}
+
+//! Grab debug register
+unsigned long jtagarm7tdmi_get_dbgctrl() {
+  jtagarm7tdmi_resettap();
+  jtagarm7tdmi_scan_intest(2);                        // select ICEBreaker
+  return eice_read(EICE_DBGCTRL);
+}
+
+//! Update debug register
+unsigned long jtagarm7tdmi_set_dbgctrl(unsigned long bits) {
+  jtagarm7tdmi_resettap();
+  jtagarm7tdmi_scan_intest(2);                        // select ICEBreaker
+  return eice_write(EICE_DBGCTRL, bits);
+}
+
+
+
+//!  Set and Enable Watchpoint 0
+void jtagarm7tdmi_set_watchpoint0(unsigned long addr, unsigned long addrmask, unsigned long data, unsigned long datamask, unsigned long ctrl, unsigned long ctrlmask){
+  // select ICEBreaker
+  jtagarm7tdmi_scan_intest(2);
+  // store watchpoint info?  - not right now
+  // write 0 in watchpoint 0 address
+  eice_write(EICE_WP0ADDR, addr);
+  // write 0xffffffff in watchpoint 0 address mask
+  eice_write(EICE_WP0ADDRMASK, addrmask);
+  // write 0 in watchpoint 0 data
+  eice_write(EICE_WP0DATA, data);
+  // write 0xffffffff in watchpoint 0 data mask
+  eice_write(EICE_WP0DATAMASK, datamask);
+  // write 0x00000100 in watchpoint 0 control value register (enables watchpoint)
+  eice_write(EICE_WP0CTRL, ctrlmask);
+  // write 0xfffffff7 in watchpoint 0 control mask - only detect the fetch instruction
+  eice_write(EICE_WP0CTRLMASK, ctrlmask);
+}
+
+//!  Set and Enable Watchpoint 1
+void jtagarm7tdmi_set_watchpoint1(unsigned long addr, unsigned long addrmask, unsigned long data, unsigned long datamask, unsigned long ctrl, unsigned long ctrlmask){
+  // select ICEBreaker
+  jtagarm7tdmi_scan_intest(2);
+  // store watchpoint info?  - not right now
+  // write 0 in watchpoint 1 address
+  eice_write(EICE_WP1ADDR, addr);
+  // write 0xffffffff in watchpoint 1 address mask
+  eice_write(EICE_WP1ADDRMASK, addrmask);
+  // write 0 in watchpoint 1 data
+  eice_write(EICE_WP1DATA, data);
+  // write 0xffffffff in watchpoint 1 data mask
+  eice_write(EICE_WP1DATAMASK, datamask);
+  // write 0x00000100 in watchpoint 1 control value register (enables watchpoint)
+  eice_write(EICE_WP1CTRL, ctrl);
+  // write 0xfffffff7 in watchpoint 1 control mask - only detect the fetch instruction
+  eice_write(EICE_WP1CTRLMASK, ctrlmask);
+}
+
+//!  Disable Watchpoint 0
+void jtagarm7tdmi_disable_watchpoint0(){
+  // select ICEBreaker
+  jtagarm7tdmi_scan_intest(2);
+  // write 0 in watchpoint 0 control value - disables watchpoint 0
+  eice_write(EICE_WP0CTRL, 0x0);
+}
+  
+//!  Disable Watchpoint 1
+void jtagarm7tdmi_disable_watchpoint1(){
+  // select ICEBreaker
+  jtagarm7tdmi_scan_intest(2);
+  // write 0 in watchpoint 0 control value - disables watchpoint 0
+  eice_write(EICE_WP1CTRL, 0x0);
+}
+
+
+
+/******************** Complex Commands **************************/
+//! Push an instruction into the CPU pipeline
+//  NOTE!  Must provide EXECNOPARM for parameter if no parm is required.
+unsigned long test_exec(unsigned long instr, unsigned long parameter, unsigned char systemspeed) {
+  unsigned long retval;
+  // select chain 1
+  jtagarm7tdmi_scan_intest(1);
+
+  cmddatalong[1] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[2] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP,systemspeed);
+  // write 32-bit instruction code into DR
+  cmddatalong[3] = jtagarm7tdmi_instr_primitive(instr, 0);
+  cmddatalong[4] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[5] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  // inject long
+  cmddatalong[6] = jtagarm7tdmi_instr_primitive(parameter, 0);
+  cmddatalong[7] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[8] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[9] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  retval = cmddatalong[9];
+
+  return(retval);
+}
+
+
+//! Push an instruction into the CPU pipeline
+//  NOTE!  Must provide EXECNOPARM for parameter if no parm is required.
+unsigned long jtagarm7tdmi_exec(unsigned long instr, unsigned long parameter, unsigned char systemspeed) {
+  unsigned long retval;
+  // select chain 1
+  jtagarm7tdmi_scan_intest(1);
+
+  cmddatalong[1] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[2] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP,systemspeed);
+  // write 32-bit instruction code into DR
+  cmddatalong[3] = jtagarm7tdmi_instr_primitive(instr, 0);
+  cmddatalong[4] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[5] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  // inject long
+  cmddatalong[6] = jtagarm7tdmi_instr_primitive(parameter, 0);
+  cmddatalong[7] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  retval = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[9] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[8] = retval;
+
+  return(retval);
+}
+
+//! Retrieve a 32-bit Register value
+unsigned long jtagarm7tdmi_get_register(unsigned char reg) {
+  unsigned long retval = 0, instr;
+  //JTAGARM7TDMI_RESETTAP();
+  // select chain 1, automatically put in INTEST
+  jtagarm7tdmi_scan_intest(1);
+  instr = ARM_INSTR_STR_Rx_r14 + ((reg<<12)&0xf00);
+  //retval = jtagarm7tdmi_exec(instr, 0);
+  // push STR_Rx, [R14] into pipeline
+  cmddatalong[1] = jtagarm7tdmi_instr_primitive(ARM_INSTR_LDR_R1_r0_4, 0);
+  // push nop into pipeline - fetched
+  cmddatalong[2] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  // push nop into pipeline - decoded
+  cmddatalong[3] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  // push nop into pipeline - executed 
+  cmddatalong[4] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  // recover 32-bit word
+  //retval = jtagarmtransn(0, 32, LSB, END, RETIDLE);
+  retval = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[5] = retval;
+  cmddatalong[6] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[7] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[8] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  return retval;
+}
+
+//! Set a 32-bit Register value
+unsigned long jtagarm7tdmi_set_register(unsigned char reg, unsigned long val) {
+  unsigned long retval = 0, instr;
+  //jtagarm7tdmi_resettap();
+  // select chain 1
+  jtagarm7tdmi_scan_intest(1);
+  instr = ARM_INSTR_LDR_Rx_r14 + ((reg<<12)&0xf00);
+  //retval = jtagarm7tdmi_exec(instr, 0);
+  // push STR_Rx, [R14] into pipeline
+  cmddatalong[1] = jtagarm7tdmi_instr_primitive(instr, 0);
+  // push nop into pipeline - fetched
+  cmddatalong[2] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  // push nop into pipeline - decoded
+  cmddatalong[2] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  
+  // push 32-bit word on data bus - execute state
+  //retval = jtagarmtransn(val, 32, LSB, END, RETIDLE);
+  cmddatalong[3] = jtagarm7tdmi_instr_primitive(val, 0);
+  // push nop into pipeline - executed 
+  cmddatalong[4] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  if (reg == ARM_REG_PC){
+    cmddatalong[5] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+    cmddatalong[6] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  }
+  retval = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[7] = retval;
+  return(retval);
+}
+
+
+
+//! Get all registers.  Return an array
+unsigned long* jtagarm7tdmi_get_registers() {
+  jtagarm7tdmi_scan_intest(1);
+  cmddatalong[1] = jtagarm7tdmi_instr_primitive(ARM_INSTR_SKANKREGS,0);
+  cmddatalong[2] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[3] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[4] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[5] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[6] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[7] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[8] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[9] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[10] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[11] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[12] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[13] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[14] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[15] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[16] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[17] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[18] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[19] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[20] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  return registers;
+}
+
+//! Retrieve the CPSR Register value
+unsigned long jtagarm7tdmi_get_regCPSR() {
+  unsigned long retval = 0;
+  // select chain 1
+  cmddatalong[1] = jtagarm7tdmi_scan_intest(1);
+
+  // push STR_Rx, [R14] into pipeline
+  cmddatalong[2] = jtagarm7tdmi_instr_primitive(ARM_INSTR_MRS_R0_CPSR, 0);
+  // push nop into pipeline - fetched
+  cmddatalong[3] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  // push nop into pipeline - decoded
+  cmddatalong[4] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  // push nop into pipeline - executed 
+  cmddatalong[5] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  // recover 32-bit word
+  retval = jtagarmtransn(0, 32, LSB, END, RETIDLE);
+  cmddatalong[6] = retval;
+  return retval;
+}
+
+//! Retrieve the CPSR Register value
+unsigned long jtagarm7tdmi_set_regCPSR(unsigned long val) {
+  unsigned long retval = 0;
+  // select chain 1
+  jtagarm7tdmi_scan_intest(1);
+
+  // push MSR cpsr_cxsf, R0 into pipeline
+  cmddatalong[1] = jtagarm7tdmi_instr_primitive(ARM_INSTR_MSR_cpsr_cxsf_R0, 0);
+  // push nop into pipeline - fetched
+  cmddatalong[2] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  // push nop into pipeline - decoded
+  cmddatalong[3] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  
+  // push 32-bit word on data bus
+  retval = jtagarmtransn(val, 32, LSB, END, RETIDLE);
+  // push nop into pipeline - executed 
+  cmddatalong[5] = jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  cmddatalong[4] = retval;
+  return(retval);
+}
+
+//! Write data to address - Assume TAP in run-test/idle state
+unsigned long jtagarm7tdmi_writemem(unsigned long adr, unsigned long data){
+  unsigned long r0=0, r1=-1;
+  // select chain 1
+  jtagarm7tdmi_scan_intest(1);
+
+  // store R0 and R1
+  r0 = jtagarm7tdmi_get_register(0);
+  r1 = jtagarm7tdmi_get_register(1);
+  // write address into R0
+  jtagarm7tdmi_set_register(0, adr);
+  // write data in R1
+  jtagarm7tdmi_set_register(1, data);
+  //retval = jtagarm7tdmi_exec(ARM_INSTR_LDR_R1_r0_4,1);
+  // push nop into pipeline to "clean" it ???
+  jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  // push nop into pipeline with BREAKPT set
+  jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 1);
+  // push LDR R1, R0, #4 into instruction pipeline
+  jtagarm7tdmi_instr_primitive(ARM_INSTR_LDR_R1_r0_4, 0);
+  // push nop into pipeline
+  jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  // restore R0 and R1 
+  jtagarm7tdmi_set_register(1, r1);
+  jtagarm7tdmi_set_register(0, r0);
+  return(-1);
+}
+
+//! Read data from address
+unsigned long jtagarm7tdmi_readmem(unsigned long adr){
+  unsigned long retval = 0;
+  unsigned long r0=0, r1=-1;
+  int waitcount = 0xfff;
+  // select chain 1
+  jtagarm7tdmi_scan_intest(1);
+
+  // select chain 2
+  // store R0 and R1  - not yet...
+  r0 = jtagarm7tdmi_get_register(0);
+  r1 = jtagarm7tdmi_get_register(1);
+  // write address into R0
+  jtagarm7tdmi_set_register(0, adr);
+  // push nop into pipeline to "clean" it ???
+  jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  // push nop into pipeline with BREAKPT set
+  jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 1);
+  // push LDR R1, R0, #4 into instruction pipeline
+  jtagarm7tdmi_instr_primitive(ARM_INSTR_LDR_R1_r0_4, 0);
+  // push nop into pipeline
+  jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, 0);
+  // SHIFT_IR with RESTART instruction
+  jtagarm7tdmi_restart();
+  // Poll the Debug Status Register for DBGACK and nMREQ to be HIGH
+  while ((jtagarm7tdmi_get_dbgstate() & 1) == 0  && waitcount > 0){
+    delay(1);
+    waitcount --;
+  }
+  if (waitcount == 0xffff){
+    return (-1);
+  } else {
+    retval = jtagarm7tdmi_get_register(1);
+  // read memory value from R1 register
+  // restore R0 and R1 
+  jtagarm7tdmi_set_register(1, r1);
+  jtagarm7tdmi_set_register(0, r0);
+  }
+  return retval;
+}
+
+
+//! Read Program Counter
+unsigned long jtagarm7tdmi_getpc(){
+  return jtagarm7tdmi_get_register(ARM_REG_PC);
+}
+
+//! Set Program Counter
+unsigned long jtagarm7tdmi_setpc(unsigned long adr){
+  return jtagarm7tdmi_set_register(ARM_REG_PC, adr);
+}
+
+//! Halt CPU - returns 0xffff if the operation fails to complete within 
+unsigned long jtagarm7tdmi_haltcpu(){                   //  PROVEN
+  int waitcount = 0xfff;
+  // select ICEBreaker
+  jtagarm7tdmi_scan_intest(2);
+  // store watchpoint info?  - not right now
+  // write 0 in watchpoint 1 address
+  eice_write(EICE_WP1ADDR, 0);
+  // write 0xffffffff in watchpoint 1 address mask
+  eice_write(EICE_WP1ADDRMASK, 0xffffffff);
+  // write 0 in watchpoint 1 data
+  eice_write(EICE_WP1DATA, 0);
+  // write 0xffffffff in watchpoint 1 data mask
+  eice_write(EICE_WP1DATAMASK, 0xffffffff);
+  // write 0x00000100 in watchpoint 1 control value register (enables watchpoint)
+  eice_write(EICE_WP1CTRL, 0x100);                              //!!!!! WTF!  THIS IS SUPPOSED TO BE 9 bits wide?!?
+  // write 0xfffffff7 in watchpoint 1 control mask - only detect the fetch instruction
+  eice_write(EICE_WP1CTRLMASK, 0xfffffff7);                     //!!!!! WTF!  THIS IS SUPPOSED TO BE 8 bits wide?!?
+  // poll until debug status says the cpu is in debug mode
+  while (!(jtagarm7tdmi_get_dbgstate() & 0x1)   && waitcount > 0){
+    delay(5);
+    waitcount --;
+  }
+  // write 0 in watchpoint 0 control value - disables watchpoint 0
+  eice_write(EICE_WP1CTRL, 0x0);
+
+  // store the debug state
+  last_halt_debug_state = jtagarm7tdmi_get_dbgstate();
+  last_halt_pc = jtagarm7tdmi_getpc() - 4;   // assume -4 for entering debug mode via watchpoint.
+  count_dbgspd_instr_since_debug = 0;
+  count_sysspd_instr_since_debug = 0;
+  if (last_halt_debug_state & JTAG_ARM7TDMI_DBG_TBIT){
+    jtagarm7tdmi_setMode_ARM();
+  }
+  return waitcount;
+}
+
+unsigned long jtagarm7tdmi_releasecpu(){
+  int waitcount = 0xfff;
+  unsigned long instr;
+  // somehow determine what PC should be (a couple ways possible, calculations required)
+  jtagarm7tdmi_scan_intest(1);
+  // NOP
+  jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP,0);
+  // NOP/BREAKPT
+  jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP,1);
+
+  if (last_halt_debug_state & JTAG_ARM7TDMI_DBG_TBIT){      // FIXME:  FORKED.
+    instr = ARM_INSTR_BX_PC + 0x1000000 - (count_dbgspd_instr_since_debug) - (count_sysspd_instr_since_debug*3);  //FIXME: make this right  - can't we just do an a7solute b/bx?
+    jtagarm7tdmi_instr_primitive(instr,0);
+  } else {
+    instr = ARM_INSTR_B_PC + 0x1000000 - (count_dbgspd_instr_since_debug) - (count_sysspd_instr_since_debug*3);  //FIXME: make this right  - can't we just do an absolute b/bx?
+    jtagarm7tdmi_instr_primitive(instr,0);
+  }
+  // VERB_RESTART
+  SHIFT_IR;
+  jtagarmtransn(ARM7TDMI_IR_RESTART,4,LSB,END,RETIDLE);
+
+  // wait until restart-bit set in debug state register
+  while ((jtagarm7tdmi_get_dbgstate() & JTAG_ARM7TDMI_DBG_DBGACK) && waitcount > 0){
+    //delay(1);
+    waitcount --;
+  }
+  last_halt_debug_state = -1;
+  last_halt_pc = -1;
+  return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//! Handles ARM7TDMI JTAG commands.  Forwards others to JTAG.
+void jtagarm7tdmihandle(unsigned char app, unsigned char verb, unsigned long len){
+  register char blocks;
+  
+  unsigned int i,val;
+  unsigned long at;
+  
+  //jtagarm7tdmi_resettap();
+  switch(verb){
+  case START:
+    //Enter JTAG mode.
+    cmddatalong[0] = jtagarm7tdmi_start();
+    cmddatalong[1] = jtagarm7tdmi_haltcpu();
+    //jtagarm7tdmi_resettap();
+    txdata(app,verb,0x8);
+    break;
+  case JTAGARM7TDMI_READMEM:
+  case PEEK:
+    blocks=(len>4?cmddata[4]:1);
+    at=cmddatalong[0];
+    
+    len=0x80;
+    txhead(app,verb,len);
+    
+    while(blocks--){
+      for(i=0;i<len;i+=2){
+       jtagarm7tdmi_resettap();
+       delay(10);
+       
+       val=jtagarm7tdmi_readmem(at);
+               
+       at+=2;
+       serial_tx(val&0xFF);
+       serial_tx((val&0xFF00)>>8);
+      }
+    }
+    
+    break;
+  case JTAGARM7TDMI_GET_CHIP_ID:
+       jtagarm7tdmi_resettap();
+    cmddatalong[0] = jtagarm7tdmi_idcode();
+    txdata(app,verb,4);
+    break;
+
+
+  case JTAGARM7TDMI_WRITEMEM:
+  case POKE:
+       jtagarm7tdmi_resettap();
+    jtagarm7tdmi_writemem(cmddatalong[0],
+                      cmddataword[2]);
+    cmddataword[0]=jtagarm7tdmi_readmem(cmddatalong[0]);
+    txdata(app,verb,2);
+    break;
+
+  case JTAGARM7TDMI_HALTCPU:  
+    cmddatalong[0] = jtagarm7tdmi_haltcpu();
+    txdata(app,verb,4);
+    break;
+  case JTAGARM7TDMI_RELEASECPU:
+       jtagarm7tdmi_resettap();
+    cmddatalong[0] = jtagarm7tdmi_releasecpu();
+    txdata(app,verb,4);
+    break;
+  //unimplemented functions
+  //case JTAGARM7TDMI_SETINSTRFETCH:
+  //case JTAGARM7TDMI_WRITEFLASH:
+  //case JTAGARM7TDMI_ERASEFLASH:
+  case JTAGARM7TDMI_SET_PC:
+       jtagarm7tdmi_resettap();
+    cmddatalong[0] = jtagarm7tdmi_setpc(cmddatalong[0]);
+    txdata(app,verb,4);
+    break;
+  case JTAGARM7TDMI_GET_DEBUG_CTRL:
+       jtagarm7tdmi_resettap();
+    cmddatalong[0] = jtagarm7tdmi_get_dbgctrl();
+    txdata(app,verb,1);
+    break;
+  case JTAGARM7TDMI_SET_DEBUG_CTRL:
+       jtagarm7tdmi_resettap();
+    cmddatalong[0] = jtagarm7tdmi_set_dbgctrl(cmddata[0]);
+    txdata(app,verb,4);
+    break;
+  case JTAGARM7TDMI_GET_PC:
+       jtagarm7tdmi_resettap();
+    cmddatalong[0] = jtagarm7tdmi_getpc();
+    txdata(app,verb,4);
+    break;
+  case JTAGARM7TDMI_GET_DEBUG_STATE:
+    jtagarm7tdmi_resettap();            // Shouldn't need this, but currently do.  FIXME!
+    cmddatalong[0] = jtagarm7tdmi_get_dbgstate();
+    txdata(app,verb,4);
+    break;
+  //case JTAGARM7TDMI_GET_WATCHPOINT:
+  //case JTAGARM7TDMI_SET_WATCHPOINT:
+  case JTAGARM7TDMI_GET_REGISTER:
+       jtagarm7tdmi_resettap();
+    cmddatalong[0] = jtagarm7tdmi_get_register(cmddata[0]);
+    txdata(app,verb,96);
+    break;
+  case JTAGARM7TDMI_SET_REGISTER:
+       jtagarm7tdmi_resettap();
+    cmddatalong[0] = cmddatalong[1];
+    jtagarm7tdmi_set_register(cmddata[0], cmddatalong[1]);
+    txdata(app,verb,96);
+    break;
+  case JTAGARM7TDMI_GET_REGISTERS:
+       jtagarm7tdmi_resettap();
+    jtagarm7tdmi_get_registers();
+    txdata(app,verb,80);
+    break;
+  //case JTAGARM7TDMI_SET_REGISTERS:
+  case JTAGARM7TDMI_DEBUG_INSTR:
+       jtagarm7tdmi_resettap();
+    cmddataword[0] = jtagarm7tdmi_exec(cmddataword[0], cmddataword[1], cmddata[9]);
+    txdata(app,verb,80);
+    break;
+  case JTAGARM7TDMI_STEP_INSTR:
+/*  case JTAGARM7TDMI_READ_CODE_MEMORY:
+  case JTAGARM7TDMI_WRITE_FLASH_PAGE:
+  case JTAGARM7TDMI_READ_FLASH_PAGE:
+  case JTAGARM7TDMI_MASS_ERASE_FLASH:
+  case JTAGARM7TDMI_PROGRAM_FLASH:
+  case JTAGARM7TDMI_LOCKCHIP:
+  case JTAGARM7TDMI_CHIP_ERASE:
+  */
+// Really ARM specific stuff
+  case JTAGARM7TDMI_GET_CPSR:
+       jtagarm7tdmi_resettap();
+    cmddatalong[0] = jtagarm7tdmi_get_regCPSR();
+    txdata(app,verb,4);
+    break;
+  case JTAGARM7TDMI_SET_CPSR:
+       jtagarm7tdmi_resettap();
+    cmddatalong[0] = jtagarm7tdmi_set_regCPSR(cmddatalong[0]);
+    txdata(app,verb,4);
+    break;
+  case JTAGARM7TDMI_GET_SPSR:           // FIXME: NOT CORRECT
+       jtagarm7tdmi_resettap();
+    cmddatalong[0] = jtagarm7tdmi_get_regCPSR();
+    txdata(app,verb,4);
+    break;
+  case JTAGARM7TDMI_SET_SPSR:           // FIXME: NOT CORRECT
+       jtagarm7tdmi_resettap();
+    cmddatalong[0] = jtagarm7tdmi_set_regCPSR(cmddatalong[0]);
+    txdata(app,verb,4);
+    break;
+  case JTAGARM7TDMI_SET_MODE_THUMB:
+  case JTAGARM7TDMI_SET_MODE_ARM:
+       jtagarm7tdmi_resettap();
+    cmddataword[0] = jtagarm7tdmi_setMode_ARM();
+    txdata(app,verb,4);
+    break;
+    
+  case 0xD0:          // loopback test
+    jtagarm7tdmi_resettap();
+    cmddatalong[0] = jtagarm7tdmi_bypass(cmddatalong[0]);
+    txdata(app,verb,4);
+    break;
+  case 0xD1:          // Set Scan Chain
+    jtagarm7tdmi_resettap();
+    cmddatalong[1] = jtagarm7tdmi_scan_intest(cmddataword[0]);
+    SHIFT_DR;
+    cmddatalong[0] = jtagarmtransn(cmddataword[2], 32, LSB, END, RETIDLE);
+    
+    txdata(app,verb,8);
+    break;
+  case 0xD2:          // DBGSTATE
+    cmddatalong[0] = jtagarm7tdmi_get_dbgstate();
+    txdata(app,verb,4);
+    break;
+  case 0xD3:          // EXECUTE
+    jtagarm7tdmi_resettap();
+    //cmddatalong[0] = jtagarm7tdmi_exec(cmddatalong[0], EXECNOPARM, 0);
+    cmddatalong[0] = test_exec(cmddatalong[0], EXECNOPARM, 0);
+    txdata(app,verb,52);
+    break;
+  case 0xD4:          // GET REGISTER
+    jtagarm7tdmi_resettap();
+    cmddatalong[0] = jtagarm7tdmi_get_register(cmddata[0]);
+    txdata(app,verb,40);
+    break;
+  case 0xD5:          // SET REGISTER
+    jtagarm7tdmi_resettap();
+    cmddatalong[0] = jtagarm7tdmi_set_register(cmddata[0], cmddatalong[1]);
+    txdata(app,verb,40);
+    break;
+  case 0xD6:          // SHIFT_DR
+    SHIFT_DR;
+    cmddatalong[0] = jtagarmtransn(cmddatalong[0], 32, LSB, END, RETIDLE);
+    txdata(app,verb,4);
+    break;
+  case 0xD7:          // INSTR_PRIMITIVE
+    jtagarm7tdmi_resettap();
+    // select chain 1
+    jtagarm7tdmi_scan_intest(1);
+    cmddatalong[0] = jtagarm7tdmi_instr_primitive(cmddatalong[0], 0);
+    txdata(app,verb,4);
+    break;
+  case 0xD8:          // EICE_READ
+    jtagarm7tdmi_resettap();
+    cmddatalong[0] = eice_read(cmddatalong[0]);
+    txdata(app,verb,4);
+    break;
+  case 0xD9:          // EICE_WRITE
+    jtagarm7tdmi_resettap();
+    cmddatalong[0] = eice_write(cmddatalong[0], cmddatalong[1]);
+    txdata(app,verb,4);
+    break;
+  case 0xDA:          // TEST MSB THROUGH CHAIN0 and CHAIN1
+    jtagarm7tdmi_resettap();
+    jtagarm7tdmi_scan_intest(0);
+    cmddatalong[0] = jtagarmtransn(0x41414141, 32, MSB, NOEND, NORETIDLE);
+    cmddatalong[1] = jtagarmtransn(0x42424242, 32, MSB, NOEND, NORETIDLE);
+    cmddatalong[2] = jtagarmtransn(0x43434343,  9, MSB, NOEND, NORETIDLE);
+    cmddatalong[3] = jtagarmtransn(0x44444444, 32, MSB, NOEND, NORETIDLE);
+    cmddatalong[4] = jtagarmtransn(cmddatalong[0], 32, MSB, NOEND, NORETIDLE);
+    cmddatalong[5] = jtagarmtransn(cmddatalong[1], 32, MSB, NOEND, NORETIDLE);
+    cmddatalong[6] = jtagarmtransn(cmddatalong[2],  9, MSB, NOEND, NORETIDLE);
+    cmddatalong[7] = jtagarmtransn(cmddatalong[3], 32, MSB, END, RETIDLE);
+    jtagarm7tdmi_resettap();
+    jtagarm7tdmi_scan_intest(1);
+    cmddatalong[8] = jtagarmtransn(0x41414141, 32, MSB, NOEND, NORETIDLE);
+    cmddatalong[9] = jtagarmtransn(0x44444444,  1, MSB, NOEND, NORETIDLE);
+    cmddatalong[10] = jtagarmtransn(cmddatalong[8], 32, MSB, NOEND, NORETIDLE);
+    cmddatalong[11] = jtagarmtransn(cmddatalong[9],  1, MSB, END, RETIDLE);
+    txdata(app,verb,48);
+    break;
+  case 0xDB:          // WHATEVER IR, READ 32
+    jtagarm7tdmi_resettap();
+    SHIFT_IR;
+    jtagarmtransn(cmddata[0], 4, LSB, END, NORETIDLE);
+    SHIFT_DR;
+    cmddatalong[0] = jtagarmtransn(cmddatalong[1], 32, LSB, END, RETIDLE);
+    txdata(app,verb,8);
+    break;
+    
+  default:
+    jtaghandle(app,verb,len);
+  }
+}
diff --git a/firmware/include/jtagarm7tdmi.h b/firmware/include/jtagarm7tdmi.h
new file mode 100644 (file)
index 0000000..7475117
--- /dev/null
@@ -0,0 +1,202 @@
+/*! \file jtagarm7tdmi.h
+  \author Matthew Carpenter <matt@inguardians.com>
+  \brief JTAG handler functions for the ARM7TDMI family of processors
+*/
+
+#include "jtag.h"
+
+
+#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 long registers[16];   // constant array 
+unsigned char current_chain;
+unsigned char last_halt_debug_state = -1;
+unsigned long last_halt_pc = -1;
+unsigned long count_dbgspd_instr_since_debug = 0;
+unsigned long count_sysspd_instr_since_debug = 0;
+
+
+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.
+unsigned long jtagarm7tdmi_setpc(unsigned long adr);
+
+//! Write data to address.
+unsigned long jtagarm7tdmi_writeflash(unsigned long adr, unsigned long data);
+
+
+//! Start JTAG
+unsigned long 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);
+
+// ARM7TDMI-specific pins
+// DBGRQ - GoodFET Pin 8
+#define DBGRQ   TST
+
+/*      ARM7TDMI data
+The instruction register is 4 bits in length.
+There is no parity bit.
+The fixed value 0001 is loaded into the instruction register during the CAPTURE-IR
+controller state.
+The least significant bit of the instruction register is scanned in and scanned out first.
+*/
+
+//4-bit ARM7TDMI JTAG commands, bit-swapped
+#define ARM7TDMI_IR_EXTEST              0x0
+#define ARM7TDMI_IR_SCAN_N              0x2
+#define ARM7TDMI_IR_SAMPLE              0x3
+#define ARM7TDMI_IR_RESTART             0x4
+#define ARM7TDMI_IR_CLAMP               0x5
+#define ARM7TDMI_IR_HIGHZ               0x7
+#define ARM7TDMI_IR_CLAMPZ              0x9
+#define ARM7TDMI_IR_INTEST              0xC
+#define ARM7TDMI_IR_IDCODE              0xE
+#define ARM7TDMI_IR_BYPASS              0xF
+
+// read 3 bit - Debug Control
+#define EICE_DBGCTRL                    0       
+#define EICE_DBGCTRL_BITLEN             3
+// read 5 bit - Debug Status
+#define EICE_DBGSTATUS                  1
+#define EICE_DBGSTATUS_BITLEN           5
+// read 6 bit - Debug Comms Control Register
+#define EICE_DBGCCR                     4
+#define EICE_DBGCCR_BITLEN              6
+// r/w 32 bit - Debug Comms Data Register
+#define EICE_DBGCDR                     5
+// r/w 32 bit - Watchpoint 0 Address
+#define EICE_WP0ADDR                    8
+// r/w 32 bit - Watchpoint 0 Addres Mask
+#define EICE_WP0ADDRMASK                9
+// r/w 32 bit - Watchpoint 0 Data
+#define EICE_WP0DATA                    10
+// r/w 32 bit - Watchpoint 0 Data Masl
+#define EICE_WP0DATAMASK                11
+// r/w 9 bit - Watchpoint 0 Control Value
+#define EICE_WP0CTRL                    12
+// r/w 8 bit - Watchpoint 0 Control Mask
+#define EICE_WP0CTRLMASK                13
+// r/w 32 bit - Watchpoint 0 Address
+#define EICE_WP1ADDR                    16
+// r/w 32 bit - Watchpoint 0 Addres Mask
+#define EICE_WP1ADDRMASK                17
+// r/w 32 bit - Watchpoint 0 Data
+#define EICE_WP1DATA                    18
+// r/w 32 bit - Watchpoint 0 Data Masl
+#define EICE_WP1DATAMASK                19
+// r/w 9 bit - Watchpoint 0 Control Value
+#define EICE_WP1CTRL                    20
+// r/w 8 bit - Watchpoint 0 Control Mask
+#define EICE_WP1CTRLMASK                21
+
+
+#define NOEND 0
+#define END 1
+#define MSB 0
+#define LSB 1
+#define NORETIDLE 0
+#define RETIDLE 1
+
+
+//JTAGARM7TDMI commands
+#define JTAGARM7TDMI_GET_DEBUG_CTRL       0x80
+#define JTAGARM7TDMI_SET_DEBUG_CTRL       0x81
+#define JTAGARM7TDMI_GET_PC               0x82
+#define JTAGARM7TDMI_SET_PC               0x83
+#define JTAGARM7TDMI_GET_CHIP_ID          0x84
+#define JTAGARM7TDMI_GET_DEBUG_STATE      0x85
+#define JTAGARM7TDMI_GET_WATCHPOINT       0x86
+#define JTAGARM7TDMI_SET_WATCHPOINT       0x87
+#define JTAGARM7TDMI_GET_REGISTER         0x88
+#define JTAGARM7TDMI_SET_REGISTER         0x89
+#define JTAGARM7TDMI_GET_REGISTERS        0x8a
+#define JTAGARM7TDMI_SET_REGISTERS        0x8b
+#define JTAGARM7TDMI_HALTCPU              0x8c
+#define JTAGARM7TDMI_RELEASECPU           0x8d
+#define JTAGARM7TDMI_DEBUG_INSTR          0x8e
+#define JTAGARM7TDMI_STEP_INSTR           0x8f
+#define JTAGARM7TDMI_WRITEMEM             0x90
+#define JTAGARM7TDMI_READMEM              0x91
+#define JTAGARM7TDMI_WRITE_FLASH_PAGE     0x92
+#define JTAGARM7TDMI_READ_FLASH_PAGE      0x93
+#define JTAGARM7TDMI_MASS_ERASE_FLASH     0x94
+#define JTAGARM7TDMI_PROGRAM_FLASH        0x95
+#define JTAGARM7TDMI_LOCKCHIP             0x96
+#define JTAGARM7TDMI_CHIP_ERASE           0x97
+// Really ARM specific stuff
+#define JTAGARM7TDMI_GET_CPSR             0x98
+#define JTAGARM7TDMI_SET_CPSR             0x99
+#define JTAGARM7TDMI_GET_SPSR             0x9a
+#define JTAGARM7TDMI_SET_SPSR             0x9b
+#define JTAGARM7TDMI_SET_MODE_THUMB       0x9c
+#define JTAGARM7TDMI_SET_MODE_ARM         0x9d
+
+
+// for deeper understanding, read the instruction cycle timing section of: 
+//      http://www.atmel.com/dyn/resources/prod_documents/DDI0029G_7TDMI_R3_trm.pdf
+#define EXECNOPARM                  0xe1a00000
+#define ARM_INSTR_NOP               0xe1a00000
+#define ARM_INSTR_STR_Rx_r14        0xe58e0000
+#define ARM_READ_REG                ARM_INSTR_STR_Rx_r14
+#define ARM_INSTR_LDR_Rx_r14        0xe59e0000
+#define ARM_WRITE_REG               ARM_INSTR_LDR_Rx_r14
+#define ARM_INSTR_LDR_R1_r0_4       0xe4901004
+#define ARM_READ_MEM                ARM_INSTR_LDR_R1_r0_4
+#define ARM_INSTR_MRS_R0_CPSR       0xf10f0000
+#define ARM_INSTR_MSR_cpsr_cxsf_R0  0xe12ff000
+#define ARM_INSTR_STM_R0_r0_r15     0x 
+#define ARM_INSTR_STMIA_R14_r0_rx   0xE88E0000      // add up to 65k to indicate which registers...
+#define ARM_INSTR_SKANKREGS         0xE88Effff      // add up to 65k to indicate which registers...
+#define ARM_STORE_MULTIPLE          ARM_INSTR_STMIA_R14_r0-rx
+
+#define ARM_INSTR_B_PC              0xea000000
+#define ARM_INSTR_BX_PC             0xe1200010      // need to set r0 to the desired address
+#define THUMB_INSTR_STR_R0_r0       0x60006000
+#define THUMB_INSTR_MOV_R0_PC       0x46b846b8
+#define THUMB_INSTR_BX_PC           0x47784778
+#define THUMB_INSTR_NOP             0x1c001c00
+#define ARM_REG_PC                  15
+
+#define JTAG_ARM7TDMI_DBG_DBGACK    1
+#define JTAG_ARM7TDMI_DBG_DBGRQ     2
+#define JTAG_ARM7TDMI_DBG_IFEN      4
+#define JTAG_ARM7TDMI_DBG_cgenL     8
+#define JTAG_ARM7TDMI_DBG_TBIT      16
+