fixed a small bug with writing
[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   //debugstr("jtagarm7tdmi_instr_primitive");
154   jtagarm7tdmi_scan(1, ARM7TDMI_IR_INTEST);
155
156   //debugstr("instruction:");
157   //debughex32(instr);
158   //if (!(last_instr == instr && last_sysstate == breakpt))
159   {
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       //debugstr("--breakpt flag set");
166       SETMOSI;
167       } 
168     else
169       {
170       CLRMOSI; 
171       }
172     jtag_tcktock();
173     
174     // Now shift in the 32 bits
175     retval = jtag_trans_n(instr, 32, 0);    // Must return to RUN-TEST/IDLE state for instruction to enter pipeline, and causes debug clock.
176     //debugstr("hot off the pipeline!");
177     //debughex32(retval);
178     last_instr = instr;
179     last_sysstate = breakpt;
180   }// else
181   //{ // this assumes we don't want retval!  wtfo!?
182   //  jtag_tcktock();
183   //}
184   return(retval);
185 }
186
187 u32 jtagarm7tdmi_nop(u8 brkpt){
188     //  WARNING: current_dbgstate must be up-to-date before calling this function!!!!!
189     //debugstr("jtagarm7tdmi_nop");
190     if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT)
191         return jtagarm7tdmi_instr_primitive(THUMB_INSTR_NOP, brkpt);
192     return jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, brkpt);
193 }
194
195 /******************** Complex Commands **************************/
196
197 //! Retrieve a 32-bit Register value
198 unsigned long jtagarm7_get_reg_prim(unsigned long instr){
199   //debugstr("jtagarm7_get_reg_prim");
200   jtagarm7tdmi_nop( 0);
201   jtagarm7tdmi_instr_primitive(instr, 0);
202   jtagarm7tdmi_nop( 0);
203   jtagarm7tdmi_nop( 0);
204   jtagarm7tdmi_nop( 0);
205   return jtagarm7tdmi_nop( 0);                          // recover 32-bit word
206 }
207
208 //! Set a 32-bit Register value
209 void jtagarm7_set_reg_prim(unsigned long instr, unsigned long reg, unsigned long val){      // PROVEN - 100827 (non-PC)
210   jtagarm7tdmi_nop( 0);                                 // push nop into pipeline - executed 
211   jtagarm7tdmi_instr_primitive(instr, 0);               // push instr into pipeline - fetch
212     jtagarm7tdmi_nop( 0);                               // push nop into pipeline - decode 
213     jtagarm7tdmi_nop( 0);                               // push nop into pipeline - execute 
214     jtagarm7tdmi_instr_primitive(val, 0);               // push 32-bit word on data bus
215   if (reg == ARM_REG_PC){
216     //debugstr("setting pc...");
217     jtagarm7tdmi_nop( 0);                               // push nop into pipeline - refill 
218     jtagarm7tdmi_nop( 0);                               // push nop into pipeline - refill 
219   }
220   jtagarm7tdmi_nop( 0);                               // push nop into pipeline - decode 
221   jtagarm7tdmi_nop( 0);                               // push nop into pipeline - execute 
222 }
223
224 void jtagarm7_thumb_swap_reg(unsigned char dir, unsigned long reg){                         // PROVEN - 100827
225   reg = reg & 7;
226   jtagarm7tdmi_nop( 0);
227   if (dir){
228     jtagarm7tdmi_instr_primitive((unsigned long)(THUMB_INSTR_MOV_LoHi | (reg) | (reg<<16)), 0);
229   } else {
230     jtagarm7tdmi_instr_primitive((unsigned long)(THUMB_INSTR_MOV_HiLo | (reg<<3) | (reg<<19)), 0);
231   }
232   jtagarm7tdmi_nop( 0);
233   jtagarm7tdmi_nop( 0);
234   jtagarm7tdmi_nop( 0);
235 }
236   
237 unsigned long jtagarm7tdmi_get_register(unsigned long reg) {                                // PROVEN - 100827
238   unsigned long retval=0L, instr, r0;
239   current_dbgstate = eice_read(EICE_DBGSTATUS);
240   //debugstr("current_dbgstate:");
241   //debughex32(current_dbgstate);
242
243   if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT){
244     if (reg > 7){
245       //debugstr("debug: jtagarm7tdmi_get_register: thumb reg > 15");
246       reg = reg & 7;
247       r0 = jtagarm7_get_reg_prim( THUMB_READ_REG);          // save reg0
248       jtagarm7_thumb_swap_reg(THUMB_SWAP_HiLo, reg);        // clobber reg0 with hi reg
249       retval = jtagarm7_get_reg_prim( THUMB_READ_REG);      // recover 32-bit word
250       jtagarm7_set_reg_prim( THUMB_WRITE_REG, 0, r0);       // restore r0
251       return retval;
252     } else {
253       //debugstr("debug: jtagarm7tdmi_get_register: thumb reg < 15");
254       instr = (unsigned long)(THUMB_READ_REG | (unsigned long)reg | (unsigned long)(reg<<16L));
255     }
256   } else
257   {
258     //debugstr("debug: jtagarm7tdmi_get_register: arm");
259     instr = (reg<<12L) | ARM_READ_REG;    // STR Rx, [R14] 
260   }
261   return jtagarm7_get_reg_prim(instr);
262 }
263
264 //! Set a 32-bit Register value
265 //  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.
266 //  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
267 //  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
268 //
269 void jtagarm7tdmi_set_register(unsigned long reg, unsigned long val) {                      // PROVEN - 100827
270   unsigned long instr, r0;
271   current_dbgstate = eice_read(EICE_DBGSTATUS);
272   if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT){
273     if (reg > 7){
274       
275       r0 = jtagarm7_get_reg_prim(THUMB_READ_REG);
276       jtagarm7_set_reg_prim(THUMB_WRITE_REG, 0, 0);
277       instr = (unsigned long)(THUMB_WRITE_REG | (unsigned long)reg | (unsigned long)(reg<<16L));
278       jtagarm7_set_reg_prim(instr, reg, val);
279       jtagarm7_thumb_swap_reg(THUMB_SWAP_LoHi, reg);                // place 32-bit word into a high register
280       jtagarm7_set_reg_prim( THUMB_WRITE_REG, 0, r0);               // restore r0
281     } else
282       instr = THUMB_WRITE_REG | (reg) | ((reg)<<16) | ((reg)<<3) | ((reg)<<19);
283   } else {
284     instr = ARM_WRITE_REG | (reg<<12L) | (reg<<16); //  LDR Rx, [R14]
285   }
286   
287   //debughex32(instr);
288   //  --- first time to clear the register... this ensures the write is not 8-bit offset ---
289   jtagarm7_set_reg_prim(instr, reg, 0);
290   //  --- now we actually write to the register ---
291   jtagarm7_set_reg_prim(instr, reg, val);
292 }
293
294
295 ///////////////////////////////////////////////////////////////////////////////////////////////////
296 //! Handles ARM7TDMI JTAG commands.  Forwards others to JTAG.
297 void jtagarm7_handle_fn( uint8_t const app,
298                                                  uint8_t const verb,
299                                                  uint32_t const len)
300 {
301   unsigned int val;
302  
303   switch(verb){
304   case START:
305     //Enter JTAG mode.
306     jtagarm7tdmi_start();
307     txdata(app,verb,0);
308     break;
309   case JTAGARM7_SCAN_N_SIZE:
310     g_jtagarm_scan_n_bitsize = cmddata[0];
311     txdata(app,verb,1);
312     break;
313   case JTAGARM7_IR_SIZE:
314     g_jtag_ir_size = cmddata[0];
315     txdata(app,verb,1);
316     break;
317   case JTAG_IR_SHIFT:
318     cmddataword[0] = jtagarm_shift_ir(cmddata[0], cmddata[1]);
319     txdata(app,verb,1);
320     break;
321   case JTAG_DR_SHIFT:
322         jtag_capture_dr();
323         jtag_shift_register();
324     val = cmddata[0];
325     if (cmddata[0] > 32)
326     {
327         //debughex32(cmddatalong[0]);
328         //debughex32(cmddatalong[1]);
329         cmddatalong[1] = jtag_trans_n(cmddatalong[2], val - 32 ,cmddata[1] | NOEND |NORETIDLE);
330         cmddatalong[0] = jtag_trans_n(cmddatalong[2], 32, cmddata[1]);
331     }
332     else
333     {
334         //debughex32(cmddatalong[0]);
335         cmddatalong[0] = jtag_trans_n(cmddatalong[1], val, cmddata[1]);
336     }
337     txdata(app,verb,val/8);
338     break;
339   case JTAG_DR_SHIFT_MORE:
340     // assumes you just executed JTAG_DR_SHIFT with NOEND flag set
341     debugstr("JTAG_DR_SHIFT_MORE");
342     val = cmddata[0];
343     if (cmddata[0] > 32)
344     {
345         //debughex32(cmddatalong[0]);
346         //debughex32(cmddatalong[1]);
347         cmddatalong[1] = jtag_trans_n(cmddatalong[2], val - 32 ,cmddata[1] | NOEND |NORETIDLE);
348         cmddatalong[0] = jtag_trans_n(cmddatalong[2], 32, cmddata[1]);
349     }
350     else
351     {
352         debughex32(cmddatalong[0]);
353         cmddatalong[0] = jtag_trans_n(cmddatalong[1], val, cmddata[1]);
354     }
355     txdata(app,verb,val/8);
356     break;
357   case JTAGARM7_CHAIN0:
358     jtagarm7tdmi_scan(0, ARM7TDMI_IR_INTEST);
359         jtag_capture_dr();
360         jtag_shift_register();
361     //debughex32(cmddatalong[0]);
362     //debughex(cmddataword[4]);
363     //debughex32(cmddatalong[1]);
364     //debughex32(cmddatalong[3]);
365     cmddatalong[0] = jtag_trans_n(cmddatalong[0], 32, LSB| NOEND| NORETIDLE);
366     cmddatalong[2] = jtag_trans_n(cmddataword[4], 9, MSB| NOEND| NORETIDLE);
367     cmddatalong[1] = jtag_trans_n(cmddatalong[1], 32, MSB| NOEND| NORETIDLE);
368     cmddatalong[3] = jtag_trans_n(cmddatalong[3], 32, MSB);
369     txdata(app,verb,16);
370     break;
371   case JTAGARM7_SCANCHAIN1:
372   case JTAGARM7_DEBUG_INSTR:
373     cmddatalong[0] = jtagarm7tdmi_instr_primitive(cmddatalong[0],cmddata[4]);
374     txdata(app,verb,4);
375     break;
376   case JTAGARM7_EICE_READ:
377     cmddatalong[0] = eice_read(cmddata[0]);
378     txdata(app,verb,0x4);
379     break;
380   case JTAGARM7_EICE_WRITE:
381     eice_write(cmddata[4], cmddatalong[0]);
382     txdata(app,verb,0);
383     break;
384   case JTAGARM7_GET_REGISTER:
385     val = cmddata[0];
386     cmddatalong[0] = jtagarm7tdmi_get_register(val);
387     txdata(app,verb,4);
388     break;
389   case JTAGARM7_SET_REGISTER:
390     jtagarm7tdmi_set_register(cmddatalong[1], cmddatalong[0]);
391     txdata(app,verb,4);
392     break;
393   case JTAG_RESET_TARGET:
394     //FIXME: BORKEN
395     debugstr("RESET TARGET");
396     //debughex((P3OUT&RST));
397     CLRRST;
398     //debughex((P3OUT&RST));
399     delay(cmddataword[0]);
400     SETRST;
401     //debughex((P3OUT&RST));
402     txdata(app,verb,4);
403     break;
404
405
406   //case JTAGARM7_STEP_INSTR:
407 /*  case JTAGARM7_READ_CODE_MEMORY:
408   case JTAGARM7_WRITE_FLASH_PAGE:
409   case JTAGARM7_READ_FLASH_PAGE:
410   case JTAGARM7_MASS_ERASE_FLASH:
411   case JTAGARM7_PROGRAM_FLASH:
412   case JTAGARM7_LOCKCHIP:
413   case JTAGARM7_CHIP_ERASE:
414   */
415   default:
416     (*(jtag_app.handle))(app,verb,len);
417   }
418 }
419
420