cd9bf631d37a077363d9c7f9b3f10cad037a2bb5
[goodfet] / firmware / apps / jtag / jtagarm7.c
1 /*! \file jtagarm7.c
2   \brief ARM7TDMI JTAG (AT91R40008, AT91SAM7xxx)
3 */
4
5 #include "platform.h"
6 #include "command.h"
7 #include "jtagarm7.h"
8
9
10 /**** 20-pin Connection Information (pin1 is on top-right for both connectors)****
11 GoodFET  ->  7TDMI 20-pin connector (HE-10 connector)
12   1               13 (TDO)
13   2               1  (Vdd)
14   3               5  (TDI)
15   5               7  (TMS)
16   7               9  (TCK)
17   8               15 (nRST)
18   9               4,6,8,10,12,14,16,18,20 (GND)
19   11              17/3 (nTRST)  (different sources suggest 17 or 3 alternately)
20 ********************************/
21
22 /**** 14-pin Connection Information (pin1 is on top-right for both connectors)****
23 GoodFET  ->  7TDMI 14-pin connector
24   1               11 (TDO)
25   2               1  (Vdd)
26   3               5  (TDI)
27   5               7  (TMS)
28   7               9  (TCK)
29   8               12 (nRST)
30   9               2,4,6,8,10,14 (GND)
31   11              3 (nTRST)
32
33 http://hri.sourceforge.net/tools/jtag_faq_org.html
34 ********************************/
35
36 /*  WHAT SHOULD THIS MODULE DO?
37  *     *start
38  *     *shift_ir
39  *     *shift_dr
40  *      reset_tap
41  *     *scanchain0
42  *     *scanchain1 (instr_primitive)
43  *     *scanchain2 (hmmmm... perhaps we'll need to keep the debug calls)
44  *     *    eice_read
45  *     *    eice_write
46  *     *get_register
47  *     *set_register
48  */
49
50 // ! Start JTAG, setup pins, reset TAP and return IDCODE
51 void jtagarm7tdmi_start() {
52   jtagsetup();
53   SETTST;
54   jtag_resettap();
55 }
56
57
58 u8 shift_ir(u8 ir, u8 flags){
59   u8 retval;
60   jtag_goto_shift_ir();
61   retval = jtagtransn(ir, 4, LSB|flags); 
62   return retval;
63 }
64
65 //!  Connect the appropriate scan chain to TDO/TDI.  SCAN_N, INTEST
66 unsigned long jtagarm7tdmi_scan(u8 chain, u8 testmode) {               // PROVEN
67 /*
68 When selecting a scan chain the “Run Test/Idle” state should never be reached, other-
69 wise, when in debug state, the core will not be correctly isolated and intrusive
70 commands occur. Therefore, it is recommended to pass directly from the “Update”
71 state” to the “Select DR” state each time the “Update” state is reached.
72 */
73   unsigned long retval;
74   shift_ir(ARM7TDMI_IR_SCAN_N, NORETIDLE);
75   jtag_goto_shift_dr();
76   retval = jtagtransn(chain, 4, LSB | NORETIDLE);
77   shift_ir(testmode, NORETIDLE); 
78   return(retval);
79 }
80
81
82 /************************* EmbeddedICE Primitives ****************************/
83 //! shifter for writing to chain2 (EmbeddedICE). 
84 unsigned long eice_write(unsigned char reg, unsigned long data){
85   unsigned long retval, temp;
86   jtagarm7tdmi_scan(2, ARM7TDMI_IR_INTEST);
87   jtag_goto_shift_dr();
88   retval = jtagtransn(data, 32, LSB| NOEND| NORETIDLE);         // send in the data - 32-bits lsb
89   temp = jtagtransn(reg, 5, LSB| NOEND| NORETIDLE);             // send in the register address - 5 bits lsb
90   jtagtransn(1, 1, LSB);                                        // send in the WRITE bit
91   return(retval); 
92 }
93
94 //! shifter for reading from chain2 (EmbeddedICE).
95 unsigned long eice_read(unsigned char reg){               // PROVEN
96   unsigned long temp, retval;
97   jtagarm7tdmi_scan(2, ARM7TDMI_IR_INTEST);
98   jtag_goto_shift_dr();                                         // send in the register address - 5 bits LSB
99   temp = jtagtransn(reg, 5, LSB| NOEND| NORETIDLE);
100   jtagtransn(0L, 1, LSB);                                       // clear TDI to select "read only"
101   jtag_goto_shift_dr();                                         // Now shift out the 32 bits
102   retval = jtagtransn(0L, 32, LSB);                             // atmel arm jtag docs pp.10-11: LSB first
103   return(retval);
104   
105 }
106
107 //! push an instruction into the pipeline
108 unsigned long jtagarm7tdmi_instr_primitive(unsigned long instr, char breakpt){  // PROVEN
109   unsigned long retval;
110   jtagarm7tdmi_scan(1, ARM7TDMI_IR_INTEST);
111
112   //debughex32(instr);
113   jtag_goto_shift_dr();
114   // if the next instruction is to run using MCLK (master clock), set TDI
115   if (breakpt)
116     {
117     SETMOSI;
118     } 
119   else
120     {
121     CLRMOSI; 
122     }
123   jtag_tcktock();
124   
125   // Now shift in the 32 bits
126   retval = jtagtransn(instr, 32, 0);    // Must return to RUN-TEST/IDLE state for instruction to enter pipeline, and causes debug clock.
127   return(retval);
128 }
129
130 u32 jtagarm7tdmi_nop(u8 brkpt){
131     //  WARNING: current_dbgstate must be up-to-date before calling this function!!!!!
132     if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT)
133         return jtagarm7tdmi_instr_primitive(THUMB_INSTR_NOP, brkpt);
134     return jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, brkpt);
135 }
136
137 /******************** Complex Commands **************************/
138
139 //! Retrieve a 32-bit Register value
140 unsigned long jtagarm7_get_reg_prim(unsigned long instr){
141   jtagarm7tdmi_nop( 0);
142   jtagarm7tdmi_instr_primitive(instr, 0);
143   jtagarm7tdmi_nop( 0);
144   jtagarm7tdmi_nop( 0);
145   jtagarm7tdmi_nop( 0);
146   return jtagarm7tdmi_nop( 0);                          // recover 32-bit word
147 }
148
149 //! Set a 32-bit Register value
150 void jtagarm7_set_reg_prim(unsigned long instr, unsigned long reg, unsigned long val){      // PROVEN - 100827 (non-PC)
151   jtagarm7tdmi_nop( 0);                                 // push nop into pipeline - executed 
152   jtagarm7tdmi_instr_primitive(instr, 0);               // push instr into pipeline - fetch
153     jtagarm7tdmi_nop( 0);                               // push nop into pipeline - decode 
154     jtagarm7tdmi_nop( 0);                               // push nop into pipeline - execute 
155     jtagarm7tdmi_instr_primitive(val, 0);               // push 32-bit word on data bus
156   if (reg == ARM_REG_PC){
157     //debugstr("setting pc...");
158     jtagarm7tdmi_nop( 0);                               // push nop into pipeline - refill 
159     jtagarm7tdmi_nop( 0);                               // push nop into pipeline - refill 
160   }
161   jtagarm7tdmi_nop( 0);                               // push nop into pipeline - decode 
162   jtagarm7tdmi_nop( 0);                               // push nop into pipeline - execute 
163 }
164
165 void jtagarm7_thumb_swap_reg(unsigned char dir, unsigned long reg){                         // PROVEN - 100827
166   reg = reg & 7;
167   jtagarm7tdmi_nop( 0);
168   if (dir){
169     jtagarm7tdmi_instr_primitive((unsigned long)(THUMB_INSTR_MOV_LoHi | (reg) | (reg<<16)), 0);
170     //debughex32((unsigned long)(THUMB_INSTR_MOV_LoHi | (reg) | (reg<<16)));
171   } else {
172     jtagarm7tdmi_instr_primitive((unsigned long)(THUMB_INSTR_MOV_HiLo | (reg<<3) | (reg<<19)), 0);
173     //debughex32((unsigned long)(THUMB_INSTR_MOV_HiLo | (reg<<3) | (reg<<19)));
174   }
175   jtagarm7tdmi_nop( 0);
176   jtagarm7tdmi_nop( 0);
177   jtagarm7tdmi_nop( 0);
178 }
179   
180 unsigned long jtagarm7tdmi_get_register(unsigned long reg) {                                // PROVEN - 100827
181   unsigned long retval=0L, instr, r0;
182   current_dbgstate = eice_read(EICE_DBGSTATUS);
183   if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT){
184     if (reg > 7){
185       //debugstr("debug: jtagarm7tdmi_get_register: thumb reg > 15");
186       reg = reg & 7;
187       r0 = jtagarm7_get_reg_prim( THUMB_READ_REG);          // save reg0
188       jtagarm7_thumb_swap_reg(THUMB_SWAP_HiLo, reg);        // clobber reg0 with hi reg
189       retval = jtagarm7_get_reg_prim( THUMB_READ_REG);      // recover 32-bit word
190       jtagarm7_set_reg_prim( THUMB_WRITE_REG, 0, r0);       // restore r0
191       return retval;
192     } else {
193       instr = (unsigned long)(THUMB_READ_REG | (unsigned long)reg | (unsigned long)(reg<<16L));
194     }
195   } else
196     instr = (reg<<12L) | ARM_READ_REG;    // STR Rx, [R14] 
197   return jtagarm7_get_reg_prim(instr);
198 }
199
200 //! Set a 32-bit Register value
201 //  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.
202 //  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
203 //  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
204 //
205 void jtagarm7tdmi_set_register(unsigned long reg, unsigned long val) {                      // PROVEN - 100827
206   unsigned long instr, r0;
207   current_dbgstate = eice_read(EICE_DBGSTATUS);
208   if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT){
209     if (reg > 7){
210       
211       r0 = jtagarm7_get_reg_prim(THUMB_READ_REG);
212       jtagarm7_set_reg_prim(THUMB_WRITE_REG, 0, 0);
213       instr = (unsigned long)(THUMB_WRITE_REG | (unsigned long)reg | (unsigned long)(reg<<16L));
214       jtagarm7_set_reg_prim(instr, reg, val);
215       jtagarm7_thumb_swap_reg(THUMB_SWAP_LoHi, reg);                // place 32-bit word into a high register
216       jtagarm7_set_reg_prim( THUMB_WRITE_REG, 0, r0);               // restore r0
217     } else
218       instr = THUMB_WRITE_REG | (reg) | ((reg)<<16) | ((reg)<<3) | ((reg)<<19);
219   } else {
220     instr = ARM_WRITE_REG | (reg<<12L) | (reg<<16); //  LDR Rx, [R14]
221   }
222   
223   //debughex32(instr);
224   //  --- first time to clear the register... this ensures the write is not 8-bit offset ---
225   jtagarm7_set_reg_prim(instr, reg, 0);
226   //  --- now we actually write to the register ---
227   jtagarm7_set_reg_prim(instr, reg, val);
228 }
229
230
231 ///////////////////////////////////////////////////////////////////////////////////////////////////
232 //! Handles ARM7TDMI JTAG commands.  Forwards others to JTAG.
233 void jtagarm7tdmihandle(unsigned char app, unsigned char verb, unsigned long len){
234   unsigned int val;
235  
236   switch(verb){
237   case START:
238     //Enter JTAG mode.
239     jtagarm7tdmi_start();
240     txdata(app,verb,0);
241     break;
242   case JTAG_IR_SHIFT:
243     cmddataword[0] = shift_ir(cmddata[0], cmddata[1]);
244     txdata(app,verb,1);
245     break;
246   case JTAG_DR_SHIFT:
247     jtag_goto_shift_dr();
248     cmddatalong[0] = jtagtransn(cmddatalong[1],cmddata[0],cmddata[1]);
249     txdata(app,verb,4);
250     break;
251   case JTAGARM7_CHAIN0:
252     jtagarm7tdmi_scan(0, ARM7TDMI_IR_INTEST);
253     jtag_goto_shift_dr();
254     //debughex32(cmddatalong[0]);
255     //debughex(cmddataword[4]);
256     //debughex32(cmddatalong[1]);
257     //debughex32(cmddatalong[3]);
258     cmddatalong[0] = jtagtransn(cmddatalong[0], 32, LSB| NOEND| NORETIDLE);
259     cmddatalong[2] = jtagtransn(cmddataword[4], 9, MSB| NOEND| NORETIDLE);
260     cmddatalong[1] = jtagtransn(cmddatalong[1], 32, MSB| NOEND| NORETIDLE);
261     cmddatalong[3] = jtagtransn(cmddatalong[3], 32, MSB);
262     txdata(app,verb,16);
263     break;
264   case JTAGARM7_SCANCHAIN1:
265   case JTAGARM7_DEBUG_INSTR:
266     cmddatalong[0] = jtagarm7tdmi_instr_primitive(cmddatalong[0],cmddata[4]);
267     txdata(app,verb,4);
268     break;
269   case JTAGARM7_EICE_READ:
270     cmddatalong[0] = eice_read(cmddata[0]);
271     txdata(app,verb,0x4);
272     break;
273   case JTAGARM7_EICE_WRITE:
274     eice_write(cmddata[4], cmddatalong[0]);
275     txdata(app,verb,0);
276     break;
277   case JTAGARM7_GET_REGISTER:
278     val = cmddata[0];
279     cmddatalong[0] = jtagarm7tdmi_get_register(val);
280     txdata(app,verb,4);
281     break;
282   case JTAGARM7_SET_REGISTER:
283     jtagarm7tdmi_set_register(cmddatalong[1], cmddatalong[0]);
284     txdata(app,verb,4);
285     break;
286   case JTAG_RESETTARGET:
287     //FIXME: BORKEN
288     debugstr("RESET TARGET");
289     CLRTST;
290     delay(cmddataword[0]);
291     SETTST;
292     txdata(app,verb,4);
293     break;
294
295
296   //case JTAGARM7_STEP_INSTR:
297 /*  case JTAGARM7_READ_CODE_MEMORY:
298   case JTAGARM7_WRITE_FLASH_PAGE:
299   case JTAGARM7_READ_FLASH_PAGE:
300   case JTAGARM7_MASS_ERASE_FLASH:
301   case JTAGARM7_PROGRAM_FLASH:
302   case JTAGARM7_LOCKCHIP:
303   case JTAGARM7_CHIP_ERASE:
304   */
305   default:
306     jtaghandle(app,verb,len);
307   }
308 }
309
310