A major refactor of the GoodFET firmware build system and apps to give better
[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   jtagsetup();
84   SETTST;
85   jtag_resettap();
86 }
87
88
89 u8 jtagarm_shift_ir(u8 ir, u8 flags){
90   u8 retval = 0;
91   if (last_ir != ir){
92     jtag_goto_shift_ir();
93     retval = jtagtransn(ir, 4, LSB|flags); 
94     tapstate = RunTest_Idle;
95     last_ir = ir;
96   }
97   return retval;
98 }
99
100 //!  Connect the appropriate scan chain to TDO/TDI.  SCAN_N, INTEST
101 unsigned long jtagarm7tdmi_scan(u8 chain, u8 testmode) {               // PROVEN
102 /*
103 When selecting a scan chain the “Run Test/Idle” state should never be reached, other-
104 wise, when in debug state, the core will not be correctly isolated and intrusive
105 commands occur. Therefore, it is recommended to pass directly from the “Update”
106 state” to the “Select DR” state each time the “Update” state is reached.
107 */
108   unsigned long retval = 0;
109   if (last_scanchain != chain){
110     jtagarm_shift_ir(ARM7TDMI_IR_SCAN_N, NORETIDLE);
111     last_scanchain = chain;
112     jtag_goto_shift_dr();
113     retval = jtagtransn(chain, 4, LSB | NORETIDLE);
114     tapstate = Update_DR;
115   }
116   jtagarm_shift_ir(testmode, NORETIDLE); 
117   return(retval);
118 }
119
120
121 /************************* EmbeddedICE Primitives ****************************/
122 //! shifter for writing to chain2 (EmbeddedICE). 
123 unsigned long eice_write(unsigned char reg, unsigned long data){
124   unsigned long retval, temp;
125   jtagarm7tdmi_scan(2, ARM7TDMI_IR_INTEST);
126   jtag_goto_shift_dr();
127   retval = jtagtransn(data, 32, LSB| NOEND| NORETIDLE);         // send in the data - 32-bits lsb
128   temp = jtagtransn(reg, 5, LSB| NOEND| NORETIDLE);             // send in the register address - 5 bits lsb
129   jtagtransn(1, 1, LSB);                                        // send in the WRITE bit
130   tapstate = RunTest_Idle;
131   return(retval); 
132 }
133
134 //! shifter for reading from chain2 (EmbeddedICE).
135 unsigned long eice_read(unsigned char reg){               // PROVEN
136   unsigned long temp, retval;
137   jtagarm7tdmi_scan(2, ARM7TDMI_IR_INTEST);
138   jtag_goto_shift_dr();                                         // send in the register address - 5 bits LSB
139   temp = jtagtransn(reg, 5, LSB| NOEND| NORETIDLE);
140   jtagtransn(0L, 1, LSB);                                       // clear TDI to select "read only"
141   jtag_goto_shift_dr();                                         // Now shift out the 32 bits
142   retval = jtagtransn(0L, 32, LSB);                             // atmel arm jtag docs pp.10-11: LSB first
143   tapstate = RunTest_Idle;
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   jtagarm7tdmi_scan(1, ARM7TDMI_IR_INTEST);
152
153   //debughex32(instr);
154   if (last_instr != instr && last_sysstate != breakpt){
155     jtag_goto_shift_dr();
156     // if the next instruction is to run using MCLK (master clock), set TDI
157     if (breakpt)
158       {
159       SETMOSI;
160       } 
161     else
162       {
163       CLRMOSI; 
164       }
165     jtag_tcktock();
166     
167     // Now shift in the 32 bits
168     retval = jtagtransn(instr, 32, 0);    // Must return to RUN-TEST/IDLE state for instruction to enter pipeline, and causes debug clock.
169     tapstate = RunTest_Idle;
170     last_instr = instr;
171     last_sysstate = breakpt;
172   } else
173     jtag_tcktock();
174   return(retval);
175 }
176
177 u32 jtagarm7tdmi_nop(u8 brkpt){
178     //  WARNING: current_dbgstate must be up-to-date before calling this function!!!!!
179     if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT)
180         return jtagarm7tdmi_instr_primitive(THUMB_INSTR_NOP, brkpt);
181     return jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, brkpt);
182 }
183
184 /******************** Complex Commands **************************/
185
186 //! Retrieve a 32-bit Register value
187 unsigned long jtagarm7_get_reg_prim(unsigned long instr){
188   jtagarm7tdmi_nop( 0);
189   jtagarm7tdmi_instr_primitive(instr, 0);
190   jtagarm7tdmi_nop( 0);
191   jtagarm7tdmi_nop( 0);
192   jtagarm7tdmi_nop( 0);
193   return jtagarm7tdmi_nop( 0);                          // recover 32-bit word
194 }
195
196 //! Set a 32-bit Register value
197 void jtagarm7_set_reg_prim(unsigned long instr, unsigned long reg, unsigned long val){      // PROVEN - 100827 (non-PC)
198   jtagarm7tdmi_nop( 0);                                 // push nop into pipeline - executed 
199   jtagarm7tdmi_instr_primitive(instr, 0);               // push instr into pipeline - fetch
200     jtagarm7tdmi_nop( 0);                               // push nop into pipeline - decode 
201     jtagarm7tdmi_nop( 0);                               // push nop into pipeline - execute 
202     jtagarm7tdmi_instr_primitive(val, 0);               // push 32-bit word on data bus
203   if (reg == ARM_REG_PC){
204     //debugstr("setting pc...");
205     jtagarm7tdmi_nop( 0);                               // push nop into pipeline - refill 
206     jtagarm7tdmi_nop( 0);                               // push nop into pipeline - refill 
207   }
208   jtagarm7tdmi_nop( 0);                               // push nop into pipeline - decode 
209   jtagarm7tdmi_nop( 0);                               // push nop into pipeline - execute 
210 }
211
212 void jtagarm7_thumb_swap_reg(unsigned char dir, unsigned long reg){                         // PROVEN - 100827
213   reg = reg & 7;
214   jtagarm7tdmi_nop( 0);
215   if (dir){
216     jtagarm7tdmi_instr_primitive((unsigned long)(THUMB_INSTR_MOV_LoHi | (reg) | (reg<<16)), 0);
217     //debughex32((unsigned long)(THUMB_INSTR_MOV_LoHi | (reg) | (reg<<16)));
218   } else {
219     jtagarm7tdmi_instr_primitive((unsigned long)(THUMB_INSTR_MOV_HiLo | (reg<<3) | (reg<<19)), 0);
220     //debughex32((unsigned long)(THUMB_INSTR_MOV_HiLo | (reg<<3) | (reg<<19)));
221   }
222   jtagarm7tdmi_nop( 0);
223   jtagarm7tdmi_nop( 0);
224   jtagarm7tdmi_nop( 0);
225 }
226   
227 unsigned long jtagarm7tdmi_get_register(unsigned long reg) {                                // PROVEN - 100827
228   unsigned long retval=0L, instr, r0;
229   current_dbgstate = eice_read(EICE_DBGSTATUS);
230   if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT){
231     if (reg > 7){
232       //debugstr("debug: jtagarm7tdmi_get_register: thumb reg > 15");
233       reg = reg & 7;
234       r0 = jtagarm7_get_reg_prim( THUMB_READ_REG);          // save reg0
235       jtagarm7_thumb_swap_reg(THUMB_SWAP_HiLo, reg);        // clobber reg0 with hi reg
236       retval = jtagarm7_get_reg_prim( THUMB_READ_REG);      // recover 32-bit word
237       jtagarm7_set_reg_prim( THUMB_WRITE_REG, 0, r0);       // restore r0
238       return retval;
239     } else {
240       instr = (unsigned long)(THUMB_READ_REG | (unsigned long)reg | (unsigned long)(reg<<16L));
241     }
242   } else
243     instr = (reg<<12L) | ARM_READ_REG;    // STR Rx, [R14] 
244   return jtagarm7_get_reg_prim(instr);
245 }
246
247 //! Set a 32-bit Register value
248 //  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.
249 //  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
250 //  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
251 //
252 void jtagarm7tdmi_set_register(unsigned long reg, unsigned long val) {                      // PROVEN - 100827
253   unsigned long instr, r0;
254   current_dbgstate = eice_read(EICE_DBGSTATUS);
255   if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT){
256     if (reg > 7){
257       
258       r0 = jtagarm7_get_reg_prim(THUMB_READ_REG);
259       jtagarm7_set_reg_prim(THUMB_WRITE_REG, 0, 0);
260       instr = (unsigned long)(THUMB_WRITE_REG | (unsigned long)reg | (unsigned long)(reg<<16L));
261       jtagarm7_set_reg_prim(instr, reg, val);
262       jtagarm7_thumb_swap_reg(THUMB_SWAP_LoHi, reg);                // place 32-bit word into a high register
263       jtagarm7_set_reg_prim( THUMB_WRITE_REG, 0, r0);               // restore r0
264     } else
265       instr = THUMB_WRITE_REG | (reg) | ((reg)<<16) | ((reg)<<3) | ((reg)<<19);
266   } else {
267     instr = ARM_WRITE_REG | (reg<<12L) | (reg<<16); //  LDR Rx, [R14]
268   }
269   
270   //debughex32(instr);
271   //  --- first time to clear the register... this ensures the write is not 8-bit offset ---
272   jtagarm7_set_reg_prim(instr, reg, 0);
273   //  --- now we actually write to the register ---
274   jtagarm7_set_reg_prim(instr, reg, val);
275 }
276
277
278 ///////////////////////////////////////////////////////////////////////////////////////////////////
279 //! Handles ARM7TDMI JTAG commands.  Forwards others to JTAG.
280 void jtagarm7_handle_fn( uint8_t const app,
281                                                  uint8_t const verb,
282                                                  uint32_t const len)
283 {
284   unsigned int val;
285  
286   switch(verb){
287   case START:
288     //Enter JTAG mode.
289     jtagarm7tdmi_start();
290     txdata(app,verb,0);
291     break;
292   case JTAG_IR_SHIFT:
293     cmddataword[0] = jtagarm_shift_ir(cmddata[0], cmddata[1]);
294     txdata(app,verb,1);
295     break;
296   case JTAG_DR_SHIFT:
297     jtag_goto_shift_dr();
298     cmddatalong[0] = jtagtransn(cmddatalong[1],cmddata[0],cmddata[1]);
299     tapstate = (cmddata[1]&NORETIDLE)>0?Update_DR:RunTest_Idle;
300     txdata(app,verb,4);
301     break;
302   case JTAGARM7_CHAIN0:
303     jtagarm7tdmi_scan(0, ARM7TDMI_IR_INTEST);
304     jtag_goto_shift_dr();
305     //debughex32(cmddatalong[0]);
306     //debughex(cmddataword[4]);
307     //debughex32(cmddatalong[1]);
308     //debughex32(cmddatalong[3]);
309     cmddatalong[0] = jtagtransn(cmddatalong[0], 32, LSB| NOEND| NORETIDLE);
310     cmddatalong[2] = jtagtransn(cmddataword[4], 9, MSB| NOEND| NORETIDLE);
311     cmddatalong[1] = jtagtransn(cmddatalong[1], 32, MSB| NOEND| NORETIDLE);
312     cmddatalong[3] = jtagtransn(cmddatalong[3], 32, MSB);
313     tapstate = RunTest_Idle;
314     txdata(app,verb,16);
315     break;
316   case JTAGARM7_SCANCHAIN1:
317   case JTAGARM7_DEBUG_INSTR:
318     cmddatalong[0] = jtagarm7tdmi_instr_primitive(cmddatalong[0],cmddata[4]);
319     txdata(app,verb,4);
320     break;
321   case JTAGARM7_EICE_READ:
322     cmddatalong[0] = eice_read(cmddata[0]);
323     txdata(app,verb,0x4);
324     break;
325   case JTAGARM7_EICE_WRITE:
326     eice_write(cmddata[4], cmddatalong[0]);
327     txdata(app,verb,0);
328     break;
329   case JTAGARM7_GET_REGISTER:
330     val = cmddata[0];
331     cmddatalong[0] = jtagarm7tdmi_get_register(val);
332     txdata(app,verb,4);
333     break;
334   case JTAGARM7_SET_REGISTER:
335     jtagarm7tdmi_set_register(cmddatalong[1], cmddatalong[0]);
336     txdata(app,verb,4);
337     break;
338   case JTAG_RESETTARGET:
339     //FIXME: BORKEN
340     debugstr("RESET TARGET");
341     CLRTST;
342     delay(cmddataword[0]);
343     SETTST;
344     txdata(app,verb,4);
345     break;
346
347
348   //case JTAGARM7_STEP_INSTR:
349 /*  case JTAGARM7_READ_CODE_MEMORY:
350   case JTAGARM7_WRITE_FLASH_PAGE:
351   case JTAGARM7_READ_FLASH_PAGE:
352   case JTAGARM7_MASS_ERASE_FLASH:
353   case JTAGARM7_PROGRAM_FLASH:
354   case JTAGARM7_LOCKCHIP:
355   case JTAGARM7_CHIP_ERASE:
356   */
357   default:
358     (*(jtag_app.handle))(app,verb,len);
359   }
360 }
361
362