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