reworking get/set_register() to write twice for sanity.
[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  *     *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 shift_ir(u8 ir, u8 flags){
59   u8 retval;
60   jtag_goto_shift_ir();
61   retval = jtagtransn(ir, 4, LSB|flags); 
62   return retval;
63 }
64
65 //!  Connect the appropriate scan chain to TDO/TDI.  SCAN_N, INTEST
66 unsigned long jtagarm7tdmi_scan(u8 chain, u8 testmode) {               // PROVEN
67 /*
68 When selecting a scan chain the “Run Test/Idle” state should never be reached, other-
69 wise, when in debug state, the core will not be correctly isolated and intrusive
70 commands occur. Therefore, it is recommended to pass directly from the “Update”
71 state” to the “Select DR” state each time the “Update” state is reached.
72 */
73   unsigned long retval;
74   shift_ir(ARM7TDMI_IR_SCAN_N, NORETIDLE);
75   jtag_goto_shift_dr();
76   retval = jtagtransn(chain, 4, LSB | NORETIDLE);
77   shift_ir(testmode, NORETIDLE); 
78   return(retval);
79 }
80
81
82 /************************* EmbeddedICE Primitives ****************************/
83 //! shifter for writing to chain2 (EmbeddedICE). 
84 unsigned long eice_write(unsigned char reg, unsigned long data){
85   unsigned long retval, temp;
86   jtagarm7tdmi_scan(2, ARM7TDMI_IR_INTEST);
87   jtag_goto_shift_dr();
88   retval = jtagtransn(data, 32, LSB| NOEND| NORETIDLE);         // send in the data - 32-bits lsb
89   temp = jtagtransn(reg, 5, LSB| NOEND| NORETIDLE);             // send in the register address - 5 bits lsb
90   jtagtransn(1, 1, LSB);                                        // send in the WRITE bit
91   return(retval); 
92 }
93
94 //! shifter for reading from chain2 (EmbeddedICE).
95 unsigned long eice_read(unsigned char reg){               // PROVEN
96   unsigned long temp, retval;
97   jtagarm7tdmi_scan(2, ARM7TDMI_IR_INTEST);
98   jtag_goto_shift_dr();                                         // send in the register address - 5 bits LSB
99   temp = jtagtransn(reg, 5, LSB| NOEND| NORETIDLE);
100   jtagtransn(0L, 1, LSB);                                       // clear TDI to select "read only"
101   jtag_goto_shift_dr();                                         // Now shift out the 32 bits
102   retval = jtagtransn(0L, 32, LSB);                             // atmel arm jtag docs pp.10-11: LSB first
103   return(retval);
104   
105 }
106
107 //! push an instruction into the pipeline
108 unsigned long jtagarm7tdmi_instr_primitive(unsigned long instr, char breakpt){  // PROVEN
109   unsigned long retval;
110   jtagarm7tdmi_scan(1, ARM7TDMI_IR_INTEST);
111
112   debughex32(instr);
113   jtag_goto_shift_dr();
114   // if the next instruction is to run using MCLK (master clock), set TDI
115   if (breakpt)
116     {
117     SETMOSI;
118     } 
119   else
120     {
121     CLRMOSI; 
122     }
123   jtag_tcktock();
124   
125   // Now shift in the 32 bits
126   retval = jtagtransn(instr, 32, 0);    // Must return to RUN-TEST/IDLE state for instruction to enter pipeline, and causes debug clock.
127   return(retval);
128 }
129
130 u32 jtagarm7tdmi_nop(u8 brkpt){
131     //  WARNING: current_dbgstate must be up-to-date before calling this function!!!!!
132     if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT)
133         return jtagarm7tdmi_instr_primitive(THUMB_INSTR_NOP, brkpt);
134     return jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, brkpt);
135 }
136
137 /******************** Complex Commands **************************/
138
139 //! Retrieve a 32-bit Register value
140 unsigned long jtagarm7tdmi_get_register(unsigned long reg) {                    //PROVEN
141   unsigned long retval=0L, instr;
142   current_dbgstate = eice_read(EICE_DBGSTATUS);
143   if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT)
144     instr = (unsigned long)(THUMB_READ_REG | (unsigned long)reg | (unsigned long)(reg<<16L));
145   else
146     instr = (unsigned long)(reg<<12L) | (unsigned long)ARM_READ_REG;   // STR Rx, [R14] 
147
148   //debughex32(instr);
149   jtagarm7tdmi_nop( 0);
150   jtagarm7tdmi_instr_primitive(instr, 0);
151   jtagarm7tdmi_nop( 0);
152   jtagarm7tdmi_nop( 0);
153   jtagarm7tdmi_nop( 0);
154   retval = jtagarm7tdmi_nop( 0);                        // recover 32-bit word
155   return retval;
156 }
157
158 //! Set a 32-bit Register value
159 //  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.
160 //  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
161 //  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
162 //
163 void jtagarm7tdmi_set_register(unsigned long reg, unsigned long val) {          // PROVEN (assuming target reg is word aligned)
164   unsigned long instr;
165   current_dbgstate = eice_read(EICE_DBGSTATUS);
166   if (current_dbgstate & JTAG_ARM7TDMI_DBG_TBIT){
167     instr = THUMB_WRITE_REG | (reg&7) | ((reg&7)<<16) | ((reg&7)<<3) | ((reg&7)<<19);
168   } else {
169     instr = ARM_WRITE_REG | (reg<<12L) | (reg<<16); //  LDR Rx, [R14]
170   }
171   
172   //debughex32(instr);
173   //  --- first time to clear the register... this ensures the write is not 8-bit offset ---
174   jtagarm7tdmi_nop( 0);            // push nop into pipeline - clean out the pipeline...
175   jtagarm7tdmi_nop( 0);            // push nop into pipeline - clean out the pipeline...
176   jtagarm7tdmi_instr_primitive(instr, 0); // push instr into pipeline - fetch
177   if (reg == ARM_REG_PC){
178     jtagarm7tdmi_instr_primitive(0, 0); // push 32-bit word on data bus
179     jtagarm7tdmi_nop( 0);            // push nop into pipeline - executed 
180     jtagarm7tdmi_nop( 0);            // push nop into pipeline - executed 
181   } else {
182     jtagarm7tdmi_nop( 0);            // push nop into pipeline - decode
183     jtagarm7tdmi_nop( 0);            // push nop into pipeline - execute
184     jtagarm7tdmi_instr_primitive(0, 0); // push 32-bit word on data bus
185   }
186   //  --- now we actually write to the register ---
187   jtagarm7tdmi_nop( 0);            // push nop into pipeline - executed 
188   jtagarm7tdmi_nop( 0);            // push nop into pipeline - executed 
189   jtagarm7tdmi_instr_primitive(instr, 0); // push instr into pipeline - fetch
190   if (reg == ARM_REG_PC){
191     jtagarm7tdmi_instr_primitive(val, 0); // push 32-bit word on data bus
192     jtagarm7tdmi_nop( 0);            // push nop into pipeline - executed 
193     jtagarm7tdmi_nop( 0);            // push nop into pipeline - executed 
194   } else {
195     jtagarm7tdmi_nop( 0);            // push nop into pipeline - decode
196     jtagarm7tdmi_nop( 0);            // push nop into pipeline - execute
197     jtagarm7tdmi_instr_primitive(val, 0); // push 32-bit word on data bus
198   }
199   jtagarm7tdmi_nop( 0);            // push nop into pipeline - executed 
200   jtagarm7tdmi_nop( 0);            // push nop into pipeline - executed 
201   jtagarm7tdmi_nop( 0);
202 }
203
204
205 ///////////////////////////////////////////////////////////////////////////////////////////////////
206 //! Handles ARM7TDMI JTAG commands.  Forwards others to JTAG.
207 void jtagarm7tdmihandle(unsigned char app, unsigned char verb, unsigned long len){
208   unsigned int val;
209  
210   switch(verb){
211   case START:
212     //Enter JTAG mode.
213     jtagarm7tdmi_start();
214     txdata(app,verb,0);
215     break;
216   case JTAG_IR_SHIFT:
217     cmddataword[0] = shift_ir(cmddata[0], cmddata[1]);
218     txdata(app,verb,1);
219     break;
220   case JTAG_DR_SHIFT:
221     jtag_goto_shift_dr();
222     cmddatalong[0] = jtagtransn(cmddatalong[1],cmddata[0],cmddata[1]);
223     txdata(app,verb,4);
224     break;
225   case JTAGARM7_CHAIN0:
226     jtagarm7tdmi_scan(0, ARM7TDMI_IR_INTEST);
227     jtag_goto_shift_dr();
228     //debughex32(cmddatalong[0]);
229     //debughex(cmddataword[4]);
230     //debughex32(cmddatalong[1]);
231     //debughex32(cmddatalong[3]);
232     cmddatalong[0] = jtagtransn(cmddatalong[0], 32, LSB| NOEND| NORETIDLE);
233     cmddatalong[2] = jtagtransn(cmddataword[4], 9, MSB| NOEND| NORETIDLE);
234     cmddatalong[1] = jtagtransn(cmddatalong[1], 32, MSB| NOEND| NORETIDLE);
235     cmddatalong[3] = jtagtransn(cmddatalong[3], 32, MSB);
236     txdata(app,verb,16);
237     break;
238   case JTAGARM7_SCANCHAIN1:
239   case JTAGARM7_DEBUG_INSTR:
240     cmddatalong[0] = jtagarm7tdmi_instr_primitive(cmddatalong[0],cmddata[4]);
241     txdata(app,verb,4);
242     break;
243   case JTAGARM7_EICE_READ:
244     cmddatalong[0] = eice_read(cmddata[0]);
245     txdata(app,verb,0x4);
246     break;
247   case JTAGARM7_EICE_WRITE:
248     eice_write(cmddata[4], cmddatalong[0]);
249     txdata(app,verb,0);
250     break;
251   case JTAGARM7_GET_REGISTER:
252     val = cmddata[0];
253     cmddatalong[0] = jtagarm7tdmi_get_register(val);
254     txdata(app,verb,4);
255     break;
256   case JTAGARM7_SET_REGISTER:
257     jtagarm7tdmi_set_register(cmddatalong[1], cmddatalong[0]);
258     txdata(app,verb,4);
259     break;
260   case JTAG_RESETTARGET:
261     CLRTST;
262     delay(10);
263     SETTST;
264     break;
265
266
267   //case JTAGARM7_STEP_INSTR:
268 /*  case JTAGARM7_READ_CODE_MEMORY:
269   case JTAGARM7_WRITE_FLASH_PAGE:
270   case JTAGARM7_READ_FLASH_PAGE:
271   case JTAGARM7_MASS_ERASE_FLASH:
272   case JTAGARM7_PROGRAM_FLASH:
273   case JTAGARM7_LOCKCHIP:
274   case JTAGARM7_CHIP_ERASE:
275   */
276   default:
277     jtaghandle(app,verb,len);
278   }
279 }
280
281