c4c12f6ba378af46f3bbad3dc38edf9c18c63bf6
[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 "jtag.h"
8 #include "jtagarm7.h"
9
10 //! Handles ARM7TDMI JTAG commands.  Forwards others to JTAG.
11 void jtagarm7_handle_fn( uint8_t const app,
12                                                  uint8_t const verb,
13                                                  uint32_t const len);
14
15 // define the jtagarm7 app's app_t
16 app_t const jtagarm7_app = {
17
18         /* app number */
19         JTAGARM7,
20
21         /* handle fn */
22         jtagarm7_handle_fn,
23
24         /* name */
25         "JTAGARM7",
26
27         /* desc */
28         "\tThe JTAGARM7 app extends the basic JTAG app with support\n"
29         "\tfor JTAG'ing ARM7TDMI based devices.\n"
30 };
31
32 unsigned long last_instr = -1;
33 unsigned char last_sysstate = 0;
34 unsigned char last_ir = -1;
35 unsigned char last_scanchain = -1;
36 unsigned char current_dbgstate = -1;
37 //unsigned char last_halt_debug_state = -1;
38 //unsigned long last_halt_pc = -1;
39
40 /**** 20-pin Connection Information (pin1 is on top-right for both connectors)****
41 GoodFET  ->  7TDMI 20-pin connector (HE-10 connector)
42   1               13 (TDO)
43   2               1  (Vdd)
44   3               5  (TDI)
45   5               7  (TMS)
46   7               9  (TCK)
47   9               4,6,8,10,12,14,16,18,20 (GND)
48   11              15 (nRST)
49   //  no longer...  (11              17/3 (nTRST)  (different sources suggest 17 or 3 alternately))
50 ********************************/
51
52 /**** 14-pin Connection Information (pin1 is on top-right for both connectors)****
53 GoodFET  ->  7TDMI 14-pin connector
54   1               11 (TDO)
55   2               1  (Vdd)
56   3               5  (TDI)
57   5               7  (TMS)
58   7               9  (TCK)
59   9               2,4,6,8,10,14 (GND)
60   11              12 (nRST)
61   //  no longer... (11              3 (nTRST))
62
63 http://hri.sourceforge.net/tools/jtag_faq_org.html
64 ********************************/
65
66 /*  WHAT SHOULD THIS MODULE DO?
67  *     *start
68  *     *jtagarm_shift_ir
69  *     *shift_dr
70  *      reset_tap
71  *     *scanchain0
72  *     *scanchain1 (instr_primitive)
73  *     *scanchain2 (hmmmm... perhaps we'll need to keep the debug calls)
74  *     *    eice_read
75  *     *    eice_write
76  *     *get_register
77  *     *set_register
78  */
79
80 // ! Start JTAG, setup pins, reset TAP and return IDCODE
81 void jtagarm7tdmi_start() {
82   jtag_setup();
83   SETTST;
84   jtag_reset_tap();
85 }
86
87
88 u8 jtagarm_shift_ir(u8 ir, u8 flags){
89   u8 retval = 0;
90   if (last_ir != ir){
91         jtag_capture_ir();
92         jtag_shift_register();
93     retval = jtag_trans_n(ir, 4, LSB|flags); 
94     last_ir = ir;
95   }
96   return retval;
97 }
98
99 //!  Connect the appropriate scan chain to TDO/TDI.  SCAN_N, INTEST
100 unsigned long jtagarm7tdmi_scan(u8 chain, u8 testmode) {               // PROVEN
101 /*
102 When selecting a scan chain the “Run Test/Idle” state should never be reached, other-
103 wise, when in debug state, the core will not be correctly isolated and intrusive
104 commands occur. Therefore, it is recommended to pass directly from the “Update”
105 state” to the “Select DR” state each time the “Update” state is reached.
106 */
107   unsigned long retval = 0;
108   if (last_scanchain != chain){
109     jtagarm_shift_ir(ARM7TDMI_IR_SCAN_N, NORETIDLE);
110     last_scanchain = chain;
111         jtag_capture_dr();
112         jtag_shift_register();
113     retval = jtag_trans_n(chain, 4, LSB | NORETIDLE);
114   }
115   jtagarm_shift_ir(testmode, NORETIDLE); 
116   return(retval);
117 }
118
119
120 /************************* EmbeddedICE Primitives ****************************/
121 //! shifter for writing to chain2 (EmbeddedICE). 
122 unsigned long eice_write(unsigned char reg, unsigned long data){
123   unsigned long retval, temp;
124   jtagarm7tdmi_scan(2, ARM7TDMI_IR_INTEST);
125   jtag_capture_dr();
126   jtag_shift_register();
127   retval = jtag_trans_n(data, 32, LSB| NOEND| NORETIDLE);         // send in the data - 32-bits lsb
128   temp = jtag_trans_n(reg, 5, LSB| NOEND| NORETIDLE);             // send in the register address - 5 bits lsb
129   jtag_trans_n(1, 1, LSB);                                        // send in the WRITE bit
130   return(retval); 
131 }
132
133 //! shifter for reading from chain2 (EmbeddedICE).
134 unsigned long eice_read(unsigned char reg){               // PROVEN
135   unsigned long temp, retval;
136   jtagarm7tdmi_scan(2, ARM7TDMI_IR_INTEST);
137   jtag_capture_dr();
138   jtag_shift_register(); // send in the register address - 5 bits LSB
139   temp = jtag_trans_n(reg, 5, LSB| NOEND| NORETIDLE);
140   jtag_trans_n(0L, 1, LSB);                                       // clear TDI to select "read only"
141   jtag_capture_dr();
142   jtag_shift_register(); // Now shift out the 32 bits
143   retval = jtag_trans_n(0L, 32, LSB);                             // atmel arm jtag docs pp.10-11: LSB first
144   return(retval);
145   
146 }
147
148 //! push an instruction into the pipeline
149 unsigned long jtagarm7tdmi_instr_primitive(unsigned long instr, char breakpt){  // PROVEN
150   unsigned long retval = 0;
151   //debugstr("jtagarm7tdmi_instr_primitive");
152   jtagarm7tdmi_scan(1, ARM7TDMI_IR_INTEST);
153
154   //debugstr("instruction:");
155   //debughex32(instr);
156   //if (!(last_instr == instr && last_sysstate == breakpt))
157   {
158           jtag_capture_dr();
159           jtag_shift_register();
160     // if the next instruction is to run using MCLK (master clock), set TDI
161     if (breakpt)
162       {
163       //debugstr("--breakpt flag set");
164       SETMOSI;
165       } 
166     else
167       {
168       CLRMOSI; 
169       }
170     jtag_tcktock();
171     
172     // Now shift in the 32 bits
173     retval = jtag_trans_n(instr, 32, 0);    // Must return to RUN-TEST/IDLE state for instruction to enter pipeline, and causes debug clock.
174     //debugstr("hot off the pipeline!");
175     //debughex32(retval);
176     last_instr = instr;
177     last_sysstate = breakpt;
178   }// else
179   //{ // this assumes we don't want retval!  wtfo!?
180   //  jtag_tcktock();
181   //}
182   return(retval);
183 }
184
185 u32 jtagarm7tdmi_nop(u8 brkpt){
186     //  WARNING: current_dbgstate must be up-to-date before calling this function!!!!!
187     //debugstr("jtagarm7tdmi_nop");
188     if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT)
189         return jtagarm7tdmi_instr_primitive(THUMB_INSTR_NOP, brkpt);
190     return jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, brkpt);
191 }
192
193 /******************** Complex Commands **************************/
194
195 //! Retrieve a 32-bit Register value
196 unsigned long jtagarm7_get_reg_prim(unsigned long instr){
197   //debugstr("jtagarm7_get_reg_prim");
198   jtagarm7tdmi_nop( 0);
199   jtagarm7tdmi_instr_primitive(instr, 0);
200   jtagarm7tdmi_nop( 0);
201   jtagarm7tdmi_nop( 0);
202   jtagarm7tdmi_nop( 0);
203   return jtagarm7tdmi_nop( 0);                          // recover 32-bit word
204 }
205
206 //! Set a 32-bit Register value
207 void jtagarm7_set_reg_prim(unsigned long instr, unsigned long reg, unsigned long val){      // PROVEN - 100827 (non-PC)
208   jtagarm7tdmi_nop( 0);                                 // push nop into pipeline - executed 
209   jtagarm7tdmi_instr_primitive(instr, 0);               // push instr into pipeline - fetch
210     jtagarm7tdmi_nop( 0);                               // push nop into pipeline - decode 
211     jtagarm7tdmi_nop( 0);                               // push nop into pipeline - execute 
212     jtagarm7tdmi_instr_primitive(val, 0);               // push 32-bit word on data bus
213   if (reg == ARM_REG_PC){
214     //debugstr("setting pc...");
215     jtagarm7tdmi_nop( 0);                               // push nop into pipeline - refill 
216     jtagarm7tdmi_nop( 0);                               // push nop into pipeline - refill 
217   }
218   jtagarm7tdmi_nop( 0);                               // push nop into pipeline - decode 
219   jtagarm7tdmi_nop( 0);                               // push nop into pipeline - execute 
220 }
221
222 void jtagarm7_thumb_swap_reg(unsigned char dir, unsigned long reg){                         // PROVEN - 100827
223   reg = reg & 7;
224   jtagarm7tdmi_nop( 0);
225   if (dir){
226     jtagarm7tdmi_instr_primitive((unsigned long)(THUMB_INSTR_MOV_LoHi | (reg) | (reg<<16)), 0);
227   } else {
228     jtagarm7tdmi_instr_primitive((unsigned long)(THUMB_INSTR_MOV_HiLo | (reg<<3) | (reg<<19)), 0);
229   }
230   jtagarm7tdmi_nop( 0);
231   jtagarm7tdmi_nop( 0);
232   jtagarm7tdmi_nop( 0);
233 }
234   
235 unsigned long jtagarm7tdmi_get_register(unsigned long reg) {                                // PROVEN - 100827
236   unsigned long retval=0L, instr, r0;
237   current_dbgstate = eice_read(EICE_DBGSTATUS);
238   //debugstr("current_dbgstate:");
239   //debughex32(current_dbgstate);
240
241   if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT){
242     if (reg > 7){
243       //debugstr("debug: jtagarm7tdmi_get_register: thumb reg > 15");
244       reg = reg & 7;
245       r0 = jtagarm7_get_reg_prim( THUMB_READ_REG);          // save reg0
246       jtagarm7_thumb_swap_reg(THUMB_SWAP_HiLo, reg);        // clobber reg0 with hi reg
247       retval = jtagarm7_get_reg_prim( THUMB_READ_REG);      // recover 32-bit word
248       jtagarm7_set_reg_prim( THUMB_WRITE_REG, 0, r0);       // restore r0
249       return retval;
250     } else {
251       //debugstr("debug: jtagarm7tdmi_get_register: thumb reg < 15");
252       instr = (unsigned long)(THUMB_READ_REG | (unsigned long)reg | (unsigned long)(reg<<16L));
253     }
254   } else
255   {
256     //debugstr("debug: jtagarm7tdmi_get_register: arm");
257     instr = (reg<<12L) | ARM_READ_REG;    // STR Rx, [R14] 
258   }
259   return jtagarm7_get_reg_prim(instr);
260 }
261
262 //! Set a 32-bit Register value
263 //  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.
264 //  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
265 //  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
266 //
267 void jtagarm7tdmi_set_register(unsigned long reg, unsigned long val) {                      // PROVEN - 100827
268   unsigned long instr, r0;
269   current_dbgstate = eice_read(EICE_DBGSTATUS);
270   if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT){
271     if (reg > 7){
272       
273       r0 = jtagarm7_get_reg_prim(THUMB_READ_REG);
274       jtagarm7_set_reg_prim(THUMB_WRITE_REG, 0, 0);
275       instr = (unsigned long)(THUMB_WRITE_REG | (unsigned long)reg | (unsigned long)(reg<<16L));
276       jtagarm7_set_reg_prim(instr, reg, val);
277       jtagarm7_thumb_swap_reg(THUMB_SWAP_LoHi, reg);                // place 32-bit word into a high register
278       jtagarm7_set_reg_prim( THUMB_WRITE_REG, 0, r0);               // restore r0
279     } else
280       instr = THUMB_WRITE_REG | (reg) | ((reg)<<16) | ((reg)<<3) | ((reg)<<19);
281   } else {
282     instr = ARM_WRITE_REG | (reg<<12L) | (reg<<16); //  LDR Rx, [R14]
283   }
284   
285   //debughex32(instr);
286   //  --- first time to clear the register... this ensures the write is not 8-bit offset ---
287   jtagarm7_set_reg_prim(instr, reg, 0);
288   //  --- now we actually write to the register ---
289   jtagarm7_set_reg_prim(instr, reg, val);
290 }
291
292
293 ///////////////////////////////////////////////////////////////////////////////////////////////////
294 //! Handles ARM7TDMI JTAG commands.  Forwards others to JTAG.
295 void jtagarm7_handle_fn( uint8_t const app,
296                                                  uint8_t const verb,
297                                                  uint32_t const len)
298 {
299   unsigned int val;
300  
301   switch(verb){
302   case START:
303     //Enter JTAG mode.
304     jtagarm7tdmi_start();
305     txdata(app,verb,0);
306     break;
307   case JTAG_IR_SHIFT:
308     cmddataword[0] = jtagarm_shift_ir(cmddata[0], cmddata[1]);
309     txdata(app,verb,1);
310     break;
311   case JTAG_DR_SHIFT:
312         jtag_capture_dr();
313         jtag_shift_register();
314     val = cmddata[0];
315     if (cmddata[0] > 32)
316     {
317         debughex32(cmddatalong[0]);
318         debughex32(cmddatalong[1]);
319         cmddatalong[1] = jtag_trans_n(cmddatalong[2], val - 32 ,cmddata[1] | NOEND |NORETIDLE);
320         cmddatalong[0] = jtag_trans_n(cmddatalong[2], 32, cmddata[1]);
321     }
322     else
323     {
324         debughex32(cmddatalong[0]);
325         cmddatalong[0] = jtag_trans_n(cmddatalong[1], val, cmddata[1]);
326     }
327     txdata(app,verb,val/8);
328     break;
329   case JTAG_DR_SHIFT_MORE:
330     // assumes you just executed JTAG_DR_SHIFT with NOEND flag set
331     val = cmddata[0];
332     if (cmddata[0] > 32)
333     {
334         debughex32(cmddatalong[0]);
335         debughex32(cmddatalong[1]);
336         cmddatalong[1] = jtag_trans_n(cmddatalong[2], val - 32 ,cmddata[1] | NOEND |NORETIDLE);
337         cmddatalong[0] = jtag_trans_n(cmddatalong[2], 32, cmddata[1]);
338     }
339     else
340     {
341         debughex32(cmddatalong[0]);
342         cmddatalong[0] = jtag_trans_n(cmddatalong[1], val, cmddata[1]);
343     }
344     txdata(app,verb,val/8);
345     break;
346   case JTAGARM7_CHAIN0:
347     jtagarm7tdmi_scan(0, ARM7TDMI_IR_INTEST);
348         jtag_capture_dr();
349         jtag_shift_register();
350     //debughex32(cmddatalong[0]);
351     //debughex(cmddataword[4]);
352     //debughex32(cmddatalong[1]);
353     //debughex32(cmddatalong[3]);
354     cmddatalong[0] = jtag_trans_n(cmddatalong[0], 32, LSB| NOEND| NORETIDLE);
355     cmddatalong[2] = jtag_trans_n(cmddataword[4], 9, MSB| NOEND| NORETIDLE);
356     cmddatalong[1] = jtag_trans_n(cmddatalong[1], 32, MSB| NOEND| NORETIDLE);
357     cmddatalong[3] = jtag_trans_n(cmddatalong[3], 32, MSB);
358     txdata(app,verb,16);
359     break;
360   case JTAGARM7_SCANCHAIN1:
361   case JTAGARM7_DEBUG_INSTR:
362     cmddatalong[0] = jtagarm7tdmi_instr_primitive(cmddatalong[0],cmddata[4]);
363     txdata(app,verb,4);
364     break;
365   case JTAGARM7_EICE_READ:
366     cmddatalong[0] = eice_read(cmddata[0]);
367     txdata(app,verb,0x4);
368     break;
369   case JTAGARM7_EICE_WRITE:
370     eice_write(cmddata[4], cmddatalong[0]);
371     txdata(app,verb,0);
372     break;
373   case JTAGARM7_GET_REGISTER:
374     val = cmddata[0];
375     cmddatalong[0] = jtagarm7tdmi_get_register(val);
376     txdata(app,verb,4);
377     break;
378   case JTAGARM7_SET_REGISTER:
379     jtagarm7tdmi_set_register(cmddatalong[1], cmddatalong[0]);
380     txdata(app,verb,4);
381     break;
382   case JTAG_RESET_TARGET:
383     //FIXME: BORKEN
384     debugstr("RESET TARGET");
385     debughex((P3OUT&RST));
386     CLRRST;
387     debughex((P3OUT&RST));
388     delay(cmddataword[0]);
389     SETRST;
390     debughex((P3OUT&RST));
391     txdata(app,verb,4);
392     break;
393
394
395   //case JTAGARM7_STEP_INSTR:
396 /*  case JTAGARM7_READ_CODE_MEMORY:
397   case JTAGARM7_WRITE_FLASH_PAGE:
398   case JTAGARM7_READ_FLASH_PAGE:
399   case JTAGARM7_MASS_ERASE_FLASH:
400   case JTAGARM7_PROGRAM_FLASH:
401   case JTAGARM7_LOCKCHIP:
402   case JTAGARM7_CHIP_ERASE:
403   */
404   default:
405     (*(jtag_app.handle))(app,verb,len);
406   }
407 }
408
409