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