5310d62b4f11c1787df060696c0bf549f7a75524
[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 g_jtag_ir_size = 4;
38 unsigned char g_jtagarm_scan_n_bitsize = 4;
39 //unsigned char last_halt_debug_state = -1;
40 //unsigned long last_halt_pc = -1;
41
42 /**** 20-pin Connection Information (pin1 is on top-right for both connectors)****
43 GoodFET  ->  7TDMI 20-pin connector (HE-10 connector)
44   1               13 (TDO)
45   2               1  (Vdd)
46   3               5  (TDI)
47   5               7  (TMS)
48   7               9  (TCK)
49   9               4,6,8,10,12,14,16,18,20 (GND)
50   11              15 (nRST)
51   //  no longer...  (11              17/3 (nTRST)  (different sources suggest 17 or 3 alternately))
52 ********************************/
53
54 /**** 14-pin Connection Information (pin1 is on top-right for both connectors)****
55 GoodFET  ->  7TDMI 14-pin connector
56   1               11 (TDO)
57   2               1  (Vdd)
58   3               5  (TDI)
59   5               7  (TMS)
60   7               9  (TCK)
61   9               2,4,6,8,10,14 (GND)
62   11              12 (nRST)
63   //  no longer... (11              3 (nTRST))
64
65 http://hri.sourceforge.net/tools/jtag_faq_org.html
66 ********************************/
67
68 /*  WHAT SHOULD THIS MODULE DO?
69  *     *start
70  *     *jtagarm_shift_ir
71  *     *shift_dr
72  *      reset_tap
73  *     *scanchain0
74  *     *scanchain1 (instr_primitive)
75  *     *scanchain2 (hmmmm... perhaps we'll need to keep the debug calls)
76  *     *    eice_read
77  *     *    eice_write
78  *     *get_register
79  *     *set_register
80  */
81
82 // ! Start JTAG, setup pins, reset TAP and return IDCODE
83 void jtagarm7tdmi_start() {
84   jtag_setup();
85   SETTST;
86   jtag_reset_tap();
87 }
88
89
90 u8 jtagarm_shift_ir(u8 ir, u8 flags){
91   u8 retval = 0;
92   if (last_ir != ir){
93         jtag_capture_ir();
94         jtag_shift_register();
95     retval = jtag_trans_n(ir, g_jtag_ir_size, LSB|flags); 
96     last_ir = ir;
97   }
98   return retval;
99 }
100
101 //!  Connect the appropriate scan chain to TDO/TDI.  SCAN_N, INTEST
102 unsigned long jtagarm7tdmi_scan(u8 chain, u8 testmode) {               // PROVEN
103 /*
104 When selecting a scan chain the “Run Test/Idle” state should never be reached, other-
105 wise, when in debug state, the core will not be correctly isolated and intrusive
106 commands occur. Therefore, it is recommended to pass directly from the “Update”
107 state” to the “Select DR” state each time the “Update” state is reached.
108 */
109   unsigned long retval = 0;
110   if (last_scanchain != chain){
111     jtagarm_shift_ir(ARM7TDMI_IR_SCAN_N, NORETIDLE);
112     last_scanchain = chain;
113         jtag_capture_dr();
114         jtag_shift_register();
115     retval = jtag_trans_n(chain, g_jtagarm_scan_n_bitsize, LSB | NORETIDLE);
116   }
117   jtagarm_shift_ir(testmode, NORETIDLE); 
118   return(retval);
119 }
120
121
122 /************************* EmbeddedICE Primitives ****************************/
123 //! shifter for writing to chain2 (EmbeddedICE). 
124 unsigned long eice_write(unsigned char reg, unsigned long data){
125   unsigned long retval;
126   jtagarm7tdmi_scan(2, ARM7TDMI_IR_INTEST);
127   jtag_capture_dr();
128   jtag_shift_register();
129   retval = jtag_trans_n(data, 32, LSB| NOEND| NORETIDLE);         // send in the data - 32-bits lsb
130   jtag_trans_n(reg, 5, LSB| NOEND| NORETIDLE);             // send in the register address - 5 bits lsb
131   jtag_trans_n(1, 1, LSB);                                        // send in the WRITE bit
132   return(retval); 
133 }
134
135 //! shifter for reading from chain2 (EmbeddedICE).
136 unsigned long eice_read(unsigned char reg){               // PROVEN
137   unsigned long retval;
138   jtagarm7tdmi_scan(2, ARM7TDMI_IR_INTEST);
139   jtag_capture_dr();
140   jtag_shift_register(); // send in the register address - 5 bits LSB
141   jtag_trans_n(reg, 5, LSB| NOEND| NORETIDLE);
142   jtag_trans_n(0L, 1, LSB);                                       // clear TDI to select "read only"
143   jtag_capture_dr();
144   jtag_shift_register(); // Now shift out the 32 bits
145   retval = jtag_trans_n(0L, 32, LSB);                             // atmel arm jtag docs pp.10-11: LSB first
146   return(retval);
147   
148 }
149
150 //! push an instruction into the pipeline
151 unsigned long jtagarm7tdmi_instr_primitive(unsigned long instr, char breakpt){  // PROVEN
152   unsigned long retval = 0;
153   jtagarm7tdmi_scan(1, ARM7TDMI_IR_INTEST);
154
155   //if (!(last_instr == instr && last_sysstate == breakpt))
156   {
157           jtag_capture_dr();
158           jtag_shift_register();
159     // if the next instruction is to run using MCLK (master clock), set TDI
160     if (breakpt)
161       {
162       //debugstr("--breakpt flag set");
163       SETMOSI;
164       } 
165     else
166       {
167       CLRMOSI; 
168       }
169     jtag_tcktock();
170     
171     // Now shift in the 32 bits
172     retval = jtag_trans_n(instr, 32, 0);    // Must return to RUN-TEST/IDLE state for instruction to enter pipeline, and causes debug clock.
173     last_instr = instr;
174     last_sysstate = breakpt;
175   }
176   return(retval);
177 }
178
179 //! push an instruction into the pipeline
180 unsigned long jtagarm_instr_primitive(unsigned char *instr, char breakpt){ 
181   unsigned long retval = 0;
182   jtagarm7tdmi_scan(1, ARM7TDMI_IR_INTEST);
183
184   //if (!(last_instr == instr && last_sysstate == breakpt))
185   {
186           jtag_capture_dr();
187           jtag_shift_register();
188
189     // if the next instruction is to run using MCLK (master clock), set TDI
190     if (breakpt)
191       { SETMOSI; } 
192     else
193       { CLRMOSI; }
194     jtag_tcktock();
195     
196     // Now shift in the 32 bits
197     retval = jtag_trans_many(instr, 32, 0);    // Must return to RUN-TEST/IDLE state for instruction to enter pipeline, and causes debug clock.
198     last_instr = *instr;
199     last_sysstate = breakpt;
200   }
201   return(retval);
202 }
203
204 u32 jtagarm7tdmi_nop(u8 brkpt){
205     //  WARNING: current_dbgstate must be up-to-date before calling this function!!!!!
206     //debugstr("jtagarm7tdmi_nop");
207     if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT)
208         return jtagarm7tdmi_instr_primitive(THUMB_INSTR_NOP, brkpt);
209     return jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, brkpt);
210 }
211
212 /******************** Complex Commands **************************/
213
214 //! Retrieve a 32-bit Register value
215 unsigned long jtagarm7_get_reg_prim(unsigned long instr){
216   //debugstr("jtagarm7_get_reg_prim");
217   jtagarm7tdmi_nop( 0);
218   jtagarm7tdmi_instr_primitive(instr, 0);
219   jtagarm7tdmi_nop( 0);
220   jtagarm7tdmi_nop( 0);
221   jtagarm7tdmi_nop( 0);
222   return jtagarm7tdmi_nop( 0);                          // recover 32-bit word
223 }
224
225 //! Set a 32-bit Register value
226 void jtagarm7_set_reg_prim(unsigned long instr, unsigned long reg, unsigned long val){      // PROVEN - 100827 (non-PC)
227   jtagarm7tdmi_nop( 0);                                 // push nop into pipeline - executed 
228   jtagarm7tdmi_instr_primitive(instr, 0);               // push instr into pipeline - fetch
229     jtagarm7tdmi_nop( 0);                               // push nop into pipeline - decode 
230     jtagarm7tdmi_nop( 0);                               // push nop into pipeline - execute 
231     jtagarm7tdmi_instr_primitive(val, 0);               // push 32-bit word on data bus
232   if (reg == ARM_REG_PC){
233     //debugstr("setting pc...");
234     jtagarm7tdmi_nop( 0);                               // push nop into pipeline - refill 
235     jtagarm7tdmi_nop( 0);                               // push nop into pipeline - refill 
236   }
237   jtagarm7tdmi_nop( 0);                               // push nop into pipeline - decode 
238   jtagarm7tdmi_nop( 0);                               // push nop into pipeline - execute 
239 }
240
241 void jtagarm7_thumb_swap_reg(unsigned char dir, unsigned long reg){                         // PROVEN - 100827
242   reg = reg & 7;
243   jtagarm7tdmi_nop( 0);
244   if (dir){
245     jtagarm7tdmi_instr_primitive((unsigned long)(THUMB_INSTR_MOV_LoHi | (reg) | (reg<<16)), 0);
246   } else {
247     jtagarm7tdmi_instr_primitive((unsigned long)(THUMB_INSTR_MOV_HiLo | (reg<<3) | (reg<<19)), 0);
248   }
249   jtagarm7tdmi_nop( 0);
250   jtagarm7tdmi_nop( 0);
251   jtagarm7tdmi_nop( 0);
252 }
253   
254 unsigned long jtagarm7tdmi_get_register(unsigned long reg) {                                // PROVEN - 100827
255   unsigned long retval=0L, instr, r0;
256   current_dbgstate = eice_read(EICE_DBGSTATUS);
257   //debugstr("current_dbgstate:");
258   //debughex32(current_dbgstate);
259
260   if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT){
261     if (reg > 7){
262       //debugstr("debug: jtagarm7tdmi_get_register: thumb reg > 15");
263       reg = reg & 7;
264       r0 = jtagarm7_get_reg_prim( THUMB_READ_REG);          // save reg0
265       jtagarm7_thumb_swap_reg(THUMB_SWAP_HiLo, reg);        // clobber reg0 with hi reg
266       retval = jtagarm7_get_reg_prim( THUMB_READ_REG);      // recover 32-bit word
267       jtagarm7_set_reg_prim( THUMB_WRITE_REG, 0, r0);       // restore r0
268       return retval;
269     } else {
270       //debugstr("debug: jtagarm7tdmi_get_register: thumb reg < 15");
271       instr = (unsigned long)(THUMB_READ_REG | (unsigned long)reg | (unsigned long)(reg<<16L));
272     }
273   } else
274   {
275     //debugstr("debug: jtagarm7tdmi_get_register: arm");
276     instr = (reg<<12L) | ARM_READ_REG;    // STR Rx, [R14] 
277   }
278   return jtagarm7_get_reg_prim(instr);
279 }
280
281 //! Set a 32-bit Register value
282 //  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.
283 //  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
284 //  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
285 //
286 void jtagarm7tdmi_set_register(unsigned long reg, unsigned long val) {                      // PROVEN - 100827
287   unsigned long instr, r0;
288   current_dbgstate = eice_read(EICE_DBGSTATUS);
289   if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT){
290     if (reg > 7){
291       
292       r0 = jtagarm7_get_reg_prim(THUMB_READ_REG);
293       jtagarm7_set_reg_prim(THUMB_WRITE_REG, 0, 0);
294       instr = (unsigned long)(THUMB_WRITE_REG | (unsigned long)reg | (unsigned long)(reg<<16L));
295       jtagarm7_set_reg_prim(instr, reg, val);
296       jtagarm7_thumb_swap_reg(THUMB_SWAP_LoHi, reg);                // place 32-bit word into a high register
297       jtagarm7_set_reg_prim( THUMB_WRITE_REG, 0, r0);               // restore r0
298     } else
299       instr = THUMB_WRITE_REG | (reg) | ((reg)<<16) | ((reg)<<3) | ((reg)<<19);
300   } else {
301     instr = ARM_WRITE_REG | (reg<<12L) | (reg<<16); //  LDR Rx, [R14]
302   }
303   
304   //debughex32(instr);
305   //  --- first time to clear the register... this ensures the write is not 8-bit offset ---
306   jtagarm7_set_reg_prim(instr, reg, 0);
307   //  --- now we actually write to the register ---
308   jtagarm7_set_reg_prim(instr, reg, val);
309 }
310
311
312 ///////////////////////////////////////////////////////////////////////////////////////////////////
313 //! Handles ARM7TDMI JTAG commands.  Forwards others to JTAG.
314 void jtagarm7_handle_fn( uint8_t const app,
315                                                  uint8_t const verb,
316                                                  uint32_t const len)
317 {
318   unsigned int val;
319  
320   switch(verb){
321   case START:
322     //Enter JTAG mode.
323     jtagarm7tdmi_start();
324     txdata(app,verb,0);
325     break;
326   case JTAGARM7_SCAN_N_SIZE:
327     g_jtagarm_scan_n_bitsize = cmddata[0];
328     txdata(app,verb,1);
329     break;
330   case JTAGARM7_IR_SIZE:
331     g_jtag_ir_size = cmddata[0];
332     txdata(app,verb,1);
333     break;
334   case JTAG_IR_SHIFT:
335     cmddataword[0] = jtagarm_shift_ir(cmddata[0], cmddata[1]);
336     txdata(app,verb,1);
337     break;
338   case JTAG_DR_SHIFT:
339         jtag_capture_dr();
340         jtag_shift_register();
341     val = cmddata[0];
342     if (cmddata[0] > 32)
343     {
344         //debughex32(cmddatalong[0]);
345         //debughex32(cmddatalong[1]);
346         cmddatalong[1] = jtag_trans_n(cmddatalong[2], val - 32 ,cmddata[1] | NOEND |NORETIDLE);
347         cmddatalong[0] = jtag_trans_n(cmddatalong[2], 32, cmddata[1]);
348     }
349     else
350     {
351         //debughex32(cmddatalong[0]);
352         cmddatalong[0] = jtag_trans_n(cmddatalong[1], val, cmddata[1]);
353     }
354     txdata(app,verb,val/8);
355     break;
356   case JTAG_DR_SHIFT_MORE:
357     // assumes you just executed JTAG_DR_SHIFT with NOEND flag set
358     debugstr("JTAG_DR_SHIFT_MORE");
359     val = cmddata[0];
360     if (cmddata[0] > 32)
361     {
362         //debughex32(cmddatalong[0]);
363         //debughex32(cmddatalong[1]);
364         cmddatalong[1] = jtag_trans_n(cmddatalong[2], val - 32 ,cmddata[1] | NOEND |NORETIDLE);
365         cmddatalong[0] = jtag_trans_n(cmddatalong[2], 32, cmddata[1]);
366     }
367     else
368     {
369         debughex32(cmddatalong[0]);
370         cmddatalong[0] = jtag_trans_n(cmddatalong[1], val, cmddata[1]);
371     }
372     txdata(app,verb,val/8);
373     break;
374   case JTAG_DR_SHIFT_MANY:
375         jtag_capture_dr();
376         jtag_shift_register();
377     val = cmddata[0];
378     jtag_trans_many(&cmddata[2], val, cmddata[1] );
379     txdata(app,verb,((val+7)/8)+2);
380     break;
381   case JTAGARM7_CHAIN0:
382     jtagarm7tdmi_scan(0, ARM7TDMI_IR_INTEST);
383         jtag_capture_dr();
384         jtag_shift_register();
385     //debughex32(cmddatalong[0]);
386     //debughex(cmddataword[4]);
387     //debughex32(cmddatalong[1]);
388     //debughex32(cmddatalong[3]);
389     cmddatalong[0] = jtag_trans_n(cmddatalong[0], 32, LSB| NOEND| NORETIDLE);
390     cmddatalong[2] = jtag_trans_n(cmddataword[4], 9, MSB| NOEND| NORETIDLE);
391     cmddatalong[1] = jtag_trans_n(cmddatalong[1], 32, MSB| NOEND| NORETIDLE);
392     cmddatalong[3] = jtag_trans_n(cmddatalong[3], 32, MSB);
393     txdata(app,verb,16);
394     break;
395   case JTAGARM7_SCANCHAIN1:
396   case JTAGARM7_DEBUG_INSTR:
397     cmddatalong[0] = jtagarm7tdmi_instr_primitive(cmddatalong[0],cmddata[4]);
398     txdata(app,verb,4);
399     break;
400   case JTAGARM_SCAN1_MANY:
401     cmddatalong[0] = jtagarm_instr_primitive(&cmddata[1],cmddata[0]);
402     txdata(app,verb,4);
403     break;
404   case JTAGARM7_EICE_READ:
405     cmddatalong[0] = eice_read(cmddata[0]);
406     txdata(app,verb,0x4);
407     break;
408   case JTAGARM7_EICE_WRITE:
409     eice_write(cmddata[4], cmddatalong[0]);
410     txdata(app,verb,0);
411     break;
412   case JTAGARM7_GET_REGISTER:
413     val = cmddata[0];
414     cmddatalong[0] = jtagarm7tdmi_get_register(val);
415     txdata(app,verb,4);
416     break;
417   case JTAGARM7_SET_REGISTER:
418     jtagarm7tdmi_set_register(cmddatalong[1], cmddatalong[0]);
419     txdata(app,verb,4);
420     break;
421   case JTAG_RESET_TARGET:
422     //FIXME: BORKEN
423     debugstr("RESET TARGET");
424     //debughex((P3OUT&RST));
425     CLRRST;
426     //debughex((P3OUT&RST));
427     delay(cmddataword[0]);
428     SETRST;
429     //debughex((P3OUT&RST));
430     txdata(app,verb,4);
431     break;
432
433
434   //case JTAGARM7_STEP_INSTR:
435 /*  case JTAGARM7_READ_CODE_MEMORY:
436   case JTAGARM7_WRITE_FLASH_PAGE:
437   case JTAGARM7_READ_FLASH_PAGE:
438   case JTAGARM7_MASS_ERASE_FLASH:
439   case JTAGARM7_PROGRAM_FLASH:
440   case JTAGARM7_LOCKCHIP:
441   case JTAGARM7_CHIP_ERASE:
442   */
443   default:
444     (*(jtag_app.handle))(app,verb,len);
445   }
446 }
447
448 #define min(x,y) ( (x>y) ? y : x )
449 #define max(x,y) ( (x>y) ? x : y )
450
451 uint8_t* jtag_trans_many(uint8_t *data, 
452                       uint8_t bitcount, 
453                       enum eTransFlags flags) 
454 {
455         uint8_t bit;
456         uint16_t high;
457         uint16_t mask;
458         uint16_t hmask;
459         uint8_t bitnum = 0;
460
461         if (!in_state(SHIFT_IR | SHIFT_DR))
462         {
463                 debugstr("jtag_trans_n from invalid TAP state");
464                 return 0;
465         }
466
467         SAVETCLK;
468
469         if (flags & LSB) 
470         {
471         high = (1L << (min(bitcount,8) - 1));
472         mask = high - 1;
473         hmask = (high<<1) - 1;
474                 debugstr(" starting shift:");
475                 //debughex(bit);
476                 debughex(high);
477                 //debughex(hmask);
478                 debughex(mask);
479                 debughex(*data);
480
481                 for (bit = bitcount; bit > 0; bit--,bitnum++) 
482                 {
483             if (bitnum == 8)
484             {
485                 high = (1L << (min(bit,8) - 1));
486                 hmask = (high<<1) - 1;
487                 mask = high - 1;
488                 bitnum = 0;
489
490                 debugstr("");
491                 //debughex(bit);
492                 debughex(high);
493                 //debughex(hmask);
494                 debughex(mask);
495                 debughex(*data);
496                 data ++;
497
498             }
499                         /* write MOSI on trailing edge of previous clock */
500                         if (*data & 1)
501                         {
502                                 SETMOSI;
503                         }
504                         else
505                         {
506                                 CLRMOSI;
507                         }
508                         *data >>= 1;
509
510                         if ((bit == 1) && !(flags & NOEND))
511                                 SETTMS; //TMS high on last bit to exit.
512
513                         jtag_tcktock();
514
515                         if ((bit == 1) && !(flags & NOEND))
516                                 jtag_state <<= 1; // Exit1-DR or Exit1-IR
517
518                         /* read MISO on trailing edge */
519                         if (READMISO)
520                         {
521                 debugstr("MISO: 1");
522                                 *data |= (high);
523                         }
524             else
525             {
526                 debugstr("MISO: 0");
527             }
528             debughex(*data);
529
530                 }
531         debughex(*data);
532         *data &= hmask;
533         } 
534         else 
535         {
536         // MSB... we need to start at the end of the byte array
537         data += (bitcount/8);
538         bitnum = bitcount % 8;
539         high = (1L << (max(bitnum,8) - 1));
540         mask = high - 1;
541         hmask = (high<<1) - 1;
542
543                 for (bit = bitcount; bit > 0; bit--,bitnum--) 
544                 {
545                         /* write MOSI on trailing edge of previous clock */
546                         if (*data & high)
547                         {
548                                 SETMOSI;
549                         }
550                         else
551                         {
552                                 CLRMOSI;
553                         }
554                         *data = (*data & mask) << 1;
555
556                         if ((bit==1) && !(flags & NOEND))
557                                 SETTMS; //TMS high on last bit to exit.
558
559                         jtag_tcktock();
560
561                         if ((bit == 1) && !(flags & NOEND))
562                                 jtag_state <<= 1; // Exit1-DR or Exit1-IR
563
564                         /* read MISO on trailing edge */
565                         *data |= (READMISO);
566
567             if (bitnum == 0)
568             {
569                 high = (1L << (min(bit,8) - 1));
570                 mask = high - 1;
571                 hmask = (high<<1) - 1;
572                 bitnum = 8;
573                 data --;
574             }
575                 }
576         }
577         
578         //This is needed for 20-bit MSP430 chips.
579         //Might break another 20-bit chip, if one exists.
580     //
581     //UGH... this needs to be fixed...  doesn't work with char*
582 /*      if(bitcount==20){
583           *data = ((*data << 16) | (*data >> 4)) & 0x000FFFFF;
584         }*/
585         
586         RESTORETCLK;
587
588         if (!(flags & NOEND))
589         {
590                 // exit state
591                 jtag_tcktock();
592
593                 jtag_state <<= 3; // Update-DR or Update-IR
594
595                 // update state
596                 if (!(flags & NORETIDLE))
597                 {
598                         CLRTMS;
599                         jtag_tcktock();
600
601                         jtag_state = RUN_TEST_IDLE;
602                 }
603         }
604
605         return &data[2];
606 }