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