still bug hunting, but code reads cleaner. comments moved to the line they refer...
[goodfet] / firmware / apps / jtag / jtagarm7tdmi.c
1 /*! \file jtagarm7tdmi.c
2   \brief ARM7TDMI JTAG (AT91R40008)
3 */
4
5 #include "platform.h"
6 #include "command.h"
7 #include "jtag.h"
8 #include "jtagarm7tdmi.h"
9
10
11 /**** 20-pin Connection Information (pin1 is on top-right for both connectors)****
12 GoodFET  ->  7TDMI 20-pin connector (HE-10 connector)
13   1               13 (TDO)
14   2               1  (Vdd)
15   3               5  (TDI)
16   5               7  (TMS)
17   7               9  (TCK)
18   8               15 (nRST)
19   9               4,6,8,10,12,14,16,18,20 (GND)
20   11              17/3 (nTRST)  (different sources suggest 17 or 3 alternately)
21 ********************************/
22
23 /**** 14-pin Connection Information (pin1 is on top-right for both connectors)****
24 GoodFET  ->  7TDMI 14-pin connector
25   1               11 (TDO)
26   2               1  (Vdd)
27   3               5  (TDI)
28   5               7  (TMS)
29   7               9  (TCK)
30   8               12 (nRST)
31   9               2,4,6,8,10,14 (GND)
32   11              3 (nTRST)
33
34 http://hri.sourceforge.net/tools/jtag_faq_org.html
35 ********************************/
36
37
38
39
40
41
42 /****************************************************************
43 Enabling jtag likely differs with most platforms.  We will attempt to enable most from here.  Override jtagarm7tdmi_start() to extend for other implementations
44 ARM7TDMI enables three different scan chains:
45     * Chain0 - "entire periphery" including data bus
46     * Chain1 - core data bus (subset of Chain0)  - Instruction Pipeline
47     * Chain2 - EmbeddedICE Logic Registers - This is our way into the fun stuff.
48     
49
50 ---
51 You can disable EmbeddedICE-RT by setting the DBGEN input LOW.
52 Caution
53 Hard wiring the DBGEN input LOW permanently disables all debug functionality.
54 When DBGEN is LOW, it inhibits DBGDEWPT, DBGIEBKPT, and EDBGRQ to
55 the core, and DBGACK from the ARM9E-S core is always LOW.
56 ---
57
58
59 ---
60 When the ARM9E-S core is in debug state, you can examine the core and system state
61 by forcing the load and store multiples into the instruction pipeline.
62 Before you can examine the core and system state, the debugger must determine
63 whether the processor entered debug from Thumb state or ARM state, by examining
64 bit 4 of the EmbeddedICE-RT debug status register. If bit 4 is HIGH, the core has
65 entered debug from Thumb state.
66 For more details about determining the core state, see Determining the core and system
67 state on page B-18.
68 ---
69
70
71 --- olimex - http://www.olimex.com/dev/pdf/arm-jtag.pdf
72 JTAG signals description:
73 PIN.1 (VTREF) Target voltage sense. Used to indicate the target’s operating voltage to thedebug tool.
74 PIN.2 (VTARGET) Target voltage. May be used to supply power to the debug tool.
75 PIN.3 (nTRST) JTAG TAP reset, this signal should be pulled up to Vcc in target board.
76 PIN4,6, 8, 10,12,14,16,18,20 Ground. The Gnd-Signal-Gnd-Signal strategy implemented on the 20-way connection scheme improves noiseimmunity on the target connect cable.
77 *PIN.5 (TDI) JTAG serial data in, should be pulled up to Vcc on target board.
78 *PIN.7 (TMS) JTAG TAP Mode Select, should be pulled up to Vcc on target board.
79 *PIN.9 (TCK) JTAG clock.
80 PIN.11 (RTCK) JTAG retimed clock.Implemented on certain ASIC ARM implementations the host ASIC may need to synchronize external inputs (such as JTAG inputs) with its own internal clock.
81 *PIN.13 (TDO) JTAG serial data out.
82 *PIN.15 (nSRST) Target system reset.
83 *PIN.17 (DBGRQ) Asynchronous debug request.  DBGRQ allows an external signal to force the ARM core into debug mode, should be pull down to GND.
84 PIN.19 (DBGACK) Debug acknowledge. The ARM core acknowledges debug-mode inresponse to a DBGRQ input.
85
86 ****************************************************************/
87
88
89 /************************** JTAGARM7TDMI Primitives ****************************/
90 void jtag_goto_shift_ir() {
91   SETTMS;
92   jtag_arm_tcktock();
93   jtag_arm_tcktock();
94   CLRTMS;
95   jtag_arm_tcktock();
96   jtag_arm_tcktock();
97
98 }
99
100 void jtag_goto_shift_dr() {
101   SETTMS;
102   jtag_arm_tcktock();
103   CLRTMS;
104   jtag_arm_tcktock();
105   jtag_arm_tcktock();
106 }
107
108 void jtag_reset_to_runtest_idle() {
109   SETTMS;
110   jtag_arm_tcktock();
111   jtag_arm_tcktock();
112   jtag_arm_tcktock();
113   jtag_arm_tcktock();
114   jtag_arm_tcktock();
115   jtag_arm_tcktock();
116   jtag_arm_tcktock();
117   jtag_arm_tcktock();  // now in Reset state
118   CLRTMS;
119   jtag_arm_tcktock();  // now in Run-Test/Idle state
120 }
121
122 void jtag_arm_tcktock() {
123   CLRTCK; 
124   PLEDOUT^=PLEDPIN; 
125   SETTCK; 
126   PLEDOUT^=PLEDPIN;
127 }
128
129 // ! Start JTAG, setup pins, reset TAP and return IDCODE
130 unsigned long jtagarm7tdmi_start() {
131   jtagsetup();
132   //Known-good starting position.
133   //Might be unnecessary.
134   SETTST;
135   SETRST;
136   
137   delay(0xF);
138   
139   CLRRST;
140   delay(20);
141   CLRTST;
142
143   msdelay(10);
144   SETRST;
145   /*
146   P5DIR &=~RST;
147   */
148   delay(0xF);
149   jtagarm7tdmi_resettap();
150   return jtagarm7tdmi_idcode();
151 }
152
153
154 //! Reset TAP State Machine       
155 void jtagarm7tdmi_resettap(){               // PROVEN
156   current_chain = -1;
157   jtag_reset_to_runtest_idle();
158 }
159
160
161 //  NOTE: important: THIS MODULE REVOLVES AROUND RETURNING TO RUNTEST/IDLE, OR THE FUNCTIONAL EQUIVALENT
162
163
164 //! Shift N bits over TDI/TDO.  May choose LSB or MSB, and select whether to terminate (TMS-high on last bit) and whether to return to RUNTEST/IDLE
165 unsigned long jtagarmtransn(unsigned long word, unsigned char bitcount, unsigned char lsb, unsigned char end, unsigned char retidle){               // PROVEN
166   unsigned int bit;
167   unsigned long high = 1;
168   unsigned long mask;
169
170   for (bit=(bitcount-1)/16; bit>0; bit--)
171     high <<= 16;
172   high <<= ((bitcount-1)%16);
173
174   mask = high-1;
175
176   if (lsb) {
177     for (bit = bitcount; bit > 0; bit--) {
178       /* write MOSI on trailing edge of previous clock */
179       if (word & 1)
180         {SETMOSI;}
181       else
182         {CLRMOSI;}
183       word >>= 1;
184
185       if (bit==1 && end)
186         SETTMS;//TMS high on last bit to exit.
187        
188       jtag_arm_tcktock();
189
190       /* read MISO on trailing edge */
191       if (READMISO){
192         word += (high);
193       }
194     }
195   } else {
196     for (bit=bitcount; bit>0; bit++) {
197       /* write MOSI on trailing edge of previous clock */
198       if (word & high)
199         {SETMOSI;}
200       else
201         {CLRMOSI;}
202       word = (word & mask) << 1;
203
204       if (bit==1 && end)
205         SETTMS;//TMS high on last bit to exit.
206
207       jtag_arm_tcktock();
208
209       /* read MISO on trailing edge */
210       word |= (READMISO);
211     }
212   }
213  
214
215   SETMOSI;
216
217   if (end){
218     // exit state
219     jtag_arm_tcktock();
220     // update state
221     if (retidle){
222       CLRTMS;
223       jtag_arm_tcktock();
224     }
225   }
226   return word;
227 }
228
229
230
231 /************************************************************************
232 * ARM7TDMI core has 6 primary registers to be connected between TDI/TDO
233 *   * Bypass Register
234 *   * ID Code Register
235 *   * Scan Chain Select Register    (4 bits_lsb)
236 *   * Scan Chain 0                  (64+* bits: 32_databits_lsb + ctrlbits + 32_addrbits_msb)
237 *   * Scan Chain 1                  (33 bits: 32_bits + BREAKPT)
238 *   * Scan Chain 2                  (38 bits: rw + 5_regbits_msb + 32_databits_msb)
239 ************************************************************************/
240
241
242
243 /************************** Basic JTAG Verb Commands *******************************/
244 //! Grab the core ID.
245 unsigned long jtagarm7tdmi_idcode(){               // PROVEN
246   jtagarm7tdmi_resettap();
247   SHIFT_IR;
248   jtagarmtransn(ARM7TDMI_IR_IDCODE, 4, LSB, END, RETIDLE);
249   SHIFT_DR;
250   return jtagarmtransn(0,32, LSB, END, RETIDLE);
251 }
252
253 //!  Connect Bypass Register to TDO/TDI
254 unsigned char jtagarm7tdmi_bypass(){               // PROVEN
255   jtagarm7tdmi_resettap();
256   SHIFT_IR;
257   return jtagarmtransn(ARM7TDMI_IR_BYPASS, 4, LSB, END, NORETIDLE);
258 }
259 //!  INTEST verb - do internal test
260 unsigned char jtagarm7tdmi_intest() { 
261   jtagarm7tdmi_resettap();
262   SHIFT_IR;
263   return jtagarmtransn(ARM7TDMI_IR_INTEST, 4, LSB, END, NORETIDLE); 
264 }
265
266 //!  EXTEST verb
267 unsigned char jtagarm7tdmi_extest() { 
268   jtagarm7tdmi_resettap();
269   SHIFT_IR;
270   return jtagarmtransn(ARM7TDMI_IR_EXTEST, 4, LSB, END, NORETIDLE);
271 }
272
273 //!  SAMPLE verb
274 //unsigned long jtagarm7tdmi_sample() { 
275 //  jtagarm7tdmi_ir_shift4(ARM7TDMI_IR_SAMPLE);        // ???? same here.
276 //  return jtagtransn(0,32);
277 //}
278
279 //!  RESTART verb
280 unsigned char jtagarm7tdmi_restart() { 
281   jtagarm7tdmi_resettap();
282   SHIFT_IR;
283   return jtagarmtransn(ARM7TDMI_IR_RESTART, 4, LSB, END, RETIDLE); 
284 }
285
286 //!  ARM7TDMI_IR_CLAMP               0x5
287 //unsigned long jtagarm7tdmi_clamp() { 
288 //  jtagarm7tdmi_resettap();
289 //  SHIFT_IR;
290 //  jtagarmtransn(ARM7TDMI_IR_CLAMP, 4, LSB, END, NORETIDLE);
291 //  SHIFT_DR;
292 //  return jtagarmtransn(0, 32, LSB, END, RETIDLE);
293 //}
294
295 //!  ARM7TDMI_IR_HIGHZ               0x7
296 //unsigned char jtagarm7tdmi_highz() { 
297 //  jtagarm7tdmi_resettap();
298 //  SHIFT_IR;
299 //  return jtagarmtransn(ARM7TDMI_IR_HIGHZ, 4, LSB, END, NORETIDLE);
300 //}
301
302 //! define ARM7TDMI_IR_CLAMPZ              0x9
303 //unsigned char jtagarm7tdmi_clampz() { 
304 //  jtagarm7tdmi_resettap();
305 //  SHIFT_IR;
306 //  return jtagarmtransn(ARM7TDMI_IR_CLAMPZ, 4, LSB, END, NORETIDLE);
307 //}
308
309
310 //!  Connect the appropriate scan chain to TDO/TDI.  SCAN_N, INTEST, ENDS IN SHIFT_DR!!!!!
311 unsigned long jtagarm7tdmi_scan(int chain, int testmode) {               // PROVEN
312 /*
313 When selecting a scan chain the “Run Test/Idle” state should never be reached, other-
314 wise, when in debug state, the core will not be correctly isolated and intrusive
315 commands occur. Therefore, it is recommended to pass directly from the “Update”
316 state” to the “Select DR” state each time the “Update” state is reached.
317 */
318   unsigned long retval;
319   if (current_chain != chain) {     // breaks shit when going from idcode back to scan chain
320     SHIFT_IR;
321     jtagarmtransn(ARM7TDMI_IR_SCAN_N, 4, LSB, END, NORETIDLE);
322     SHIFT_DR;
323     retval = jtagarmtransn(chain, 4, LSB, END, NORETIDLE);
324     current_chain = chain;
325   }    else
326     retval = current_chain;
327   // put in test mode...
328   SHIFT_IR;
329   jtagarmtransn(testmode, 4, LSB, END, RETIDLE); 
330   return(retval);
331 }
332
333
334 //!  Connect the appropriate scan chain to TDO/TDI.  SCAN_N, INTEST, ENDS IN SHIFT_DR!!!!!
335 unsigned long jtagarm7tdmi_scan_intest(int chain) {               // PROVEN
336   return jtagarm7tdmi_scan(chain, ARM7TDMI_IR_INTEST);
337 }
338
339
340
341
342 //! push an instruction into the pipeline  - Assumes scan-chain 1 is already INTEST
343 unsigned long jtagarm7tdmi_instr_primitive(unsigned long instr, char breakpt){
344   unsigned long retval;
345   jtagarm7tdmi_scan_intest(1);
346
347   SHIFT_DR;
348   // if the next instruction is to run using MCLK (master clock), set TDI
349   if (breakpt)
350     {
351     SETMOSI;
352     count_sysspd_instr_since_debug++;
353     } 
354   else
355     {
356     CLRMOSI; 
357     count_dbgspd_instr_since_debug++;
358     }
359   jtag_arm_tcktock();
360   
361   // Now shift in the 32 bits
362   retval = jtagarmtransn(instr, 32, MSB, END, RETIDLE);    // Must return to RUN-TEST/IDLE state for instruction to enter pipeline, and causes debug clock.
363   //jtag_arm_tcktock();
364   return(retval);
365   
366 }
367
368
369 unsigned long jtagarm7tdmi_nop(char breakpt){
370   return jtagarm7tdmi_instr_primitive(ARM_INSTR_NOP, breakpt);
371 }
372
373 /*    stolen from ARM DDI0029G documentation, translated using ARM Architecture Reference Manual (14128.pdf)
374 STR R0, [R0]; Save R0 before use
375 MOV R0, PC ; Copy PC into R0
376 STR R0, [R0]; Now save the PC in R0
377 BX PC ; Jump into ARM state
378 MOV R8, R8 ;
379 MOV R8, R8 ;
380 NOP
381 NOP
382
383 */
384 //! set the current mode to ARM, returns PC (FIXME).  Should be used by haltcpu(), which should also store PC and the THUMB state, for use by releasecpu();
385 unsigned long jtagarm7tdmi_setMode_ARM(){               // PROVEN
386   unsigned long retval = 0xff;
387   while ((jtagarm7tdmi_get_dbgstate() & JTAG_ARM7TDMI_DBG_TBIT)&& retval-- > 0){
388     cmddataword[6] = jtagarm7tdmi_instr_primitive(THUMB_INSTR_NOP,0);
389     cmddataword[1] = jtagarm7tdmi_instr_primitive(THUMB_INSTR_STR_R0_r0,0);
390     cmddataword[2] = jtagarm7tdmi_instr_primitive(THUMB_INSTR_MOV_R0_PC,0);
391     cmddataword[3] = jtagarm7tdmi_instr_primitive(THUMB_INSTR_STR_R0_r0,0);
392     cmddataword[4] = jtagarm7tdmi_instr_primitive(THUMB_INSTR_BX_PC,0);
393     cmddataword[5] = jtagarm7tdmi_instr_primitive(THUMB_INSTR_NOP,0);
394     cmddataword[6] = jtagarm7tdmi_instr_primitive(THUMB_INSTR_NOP,0);
395     delay(10);
396     jtagarm7tdmi_resettap();                  // seems necessary for some reason.  ugh.
397   }
398   return(retval);
399 }
400
401
402
403
404 /************************* EmbeddedICE Primitives ****************************/
405 //! shifter for writing to chain2 (EmbeddedICE). 
406 unsigned long eice_write(unsigned char reg, unsigned long data){
407   unsigned long retval, temp;
408   jtagarm7tdmi_scan_intest(2);
409   // Now shift in the 32 bits
410   SHIFT_DR;
411   retval = jtagarmtransn(data, 32, LSB, NOEND, NORETIDLE);          // send in the data - 32-bits lsb
412   temp = jtagarmtransn(reg, 5, LSB, NOEND, NORETIDLE);              // send in the register address - 5 bits lsb
413   jtagarmtransn(1, 1, LSB, END, RETIDLE);                           // send in the WRITE bit
414   
415   //SETTMS;   // Last Bit - Exit UPDATE_DR
416   //// is this update a read/write or just read?
417   //SETMOSI;
418   //jtag_arm_tcktock();
419   
420   return(retval); 
421 }
422
423 //! shifter for reading from chain2 (EmbeddedICE).
424 unsigned long eice_read(unsigned char reg){               // PROVEN
425   unsigned long temp;
426   jtagarm7tdmi_scan_intest(2);
427
428   // send in the register address - 5 bits LSB
429   SHIFT_DR;
430   temp = jtagarmtransn(reg, 5, LSB, NOEND, NORETIDLE);
431   
432   // clear TDI to select "read only"
433   jtagarmtransn(0, 1, LSB, END, RETIDLE);
434   
435   SHIFT_DR;
436   // Now shift out the 32 bits
437   return(jtagarmtransn(0, 32, LSB, END, RETIDLE));   // atmel arm jtag docs pp.10-11: LSB first
438   
439 }
440
441
442
443
444 /************************* ICEBreaker/EmbeddedICE Stuff ******************************/
445 //! Grab debug register
446 unsigned long jtagarm7tdmi_get_dbgstate() {       // ICE Debug register, *NOT* ARM register DSCR    //    PROVEN
447   //jtagarm7tdmi_resettap();
448   return eice_read(EICE_DBGSTATUS);
449 }
450
451 //! Grab debug register
452 unsigned long jtagarm7tdmi_get_dbgctrl() {
453   return eice_read(EICE_DBGCTRL);
454 }
455
456 //! Update debug register
457 unsigned long jtagarm7tdmi_set_dbgctrl(unsigned long bits) {
458   return eice_write(EICE_DBGCTRL, bits);
459 }
460
461
462
463 //!  Set and Enable Watchpoint 0
464 void jtagarm7tdmi_set_watchpoint0(unsigned long addr, unsigned long addrmask, unsigned long data, unsigned long datamask, unsigned long ctrl, unsigned long ctrlmask){
465   // store watchpoint info?  - not right now
466     // FIXME: store info
467
468   eice_write(EICE_WP0ADDR, addr);           // write 0 in watchpoint 0 address
469   eice_write(EICE_WP0ADDRMASK, addrmask);   // write 0xffffffff in watchpoint 0 address mask
470   eice_write(EICE_WP0DATA, data);           // write 0 in watchpoint 0 data
471   eice_write(EICE_WP0DATAMASK, datamask);   // write 0xffffffff in watchpoint 0 data mask
472   eice_write(EICE_WP0CTRL, ctrlmask);       // write 0x00000100 in watchpoint 0 control value register (enables watchpoint)
473   eice_write(EICE_WP0CTRLMASK, ctrlmask);   // write 0xfffffff7 in watchpoint 0 control mask - only detect the fetch instruction
474 }
475
476 //!  Set and Enable Watchpoint 1
477 void jtagarm7tdmi_set_watchpoint1(unsigned long addr, unsigned long addrmask, unsigned long data, unsigned long datamask, unsigned long ctrl, unsigned long ctrlmask){
478   // store watchpoint info?  - not right now
479     // FIXME: store info
480
481   eice_write(EICE_WP1ADDR, addr);           // write 0 in watchpoint 1 address
482   eice_write(EICE_WP1ADDRMASK, addrmask);   // write 0xffffffff in watchpoint 1 address mask
483   eice_write(EICE_WP1DATA, data);           // write 0 in watchpoint 1 data
484   eice_write(EICE_WP1DATAMASK, datamask);   // write 0xffffffff in watchpoint 1 data mask
485   eice_write(EICE_WP1CTRL, ctrl);           // write 0x00000100 in watchpoint 1 control value register (enables watchpoint)
486   eice_write(EICE_WP1CTRLMASK, ctrlmask);   // write 0xfffffff7 in watchpoint 1 control mask - only detect the fetch instruction
487 }
488
489 //!  Disable Watchpoint 0
490 void jtagarm7tdmi_disable_watchpoint0(){
491   eice_write(EICE_WP0CTRL, 0x0); // write 0 in watchpoint 0 control value - disables watchpoint 0
492 }
493   
494 //!  Disable Watchpoint 1
495 void jtagarm7tdmi_disable_watchpoint1(){
496   eice_write(EICE_WP1CTRL, 0x0);            // write 0 in watchpoint 0 control value - disables watchpoint 0
497 }
498
499
500
501 /******************** Complex Commands **************************/
502 //! Push an instruction into the CPU pipeline
503 //  NOTE!  Must provide EXECNOPARM for parameter if no parm is required.
504 unsigned long test_exec(unsigned long instr, unsigned long parameter, unsigned char systemspeed) {
505   unsigned long retval;
506
507   cmddatalong[1] = jtagarm7tdmi_nop( 0);
508   cmddatalong[2] = jtagarm7tdmi_nop(systemspeed);
509   cmddatalong[3] = jtagarm7tdmi_instr_primitive(instr, 0);      // write 32-bit instruction code into DR
510   cmddatalong[4] = jtagarm7tdmi_nop( 0);
511   cmddatalong[5] = jtagarm7tdmi_nop( 0);
512   cmddatalong[6] = jtagarm7tdmi_instr_primitive(parameter, 0);  // inject long
513   cmddatalong[7] = jtagarm7tdmi_nop( 0);
514   cmddatalong[8] = jtagarm7tdmi_nop( 0);
515   cmddatalong[9] = jtagarm7tdmi_nop( 0);
516   retval = cmddatalong[9];
517
518   return(retval);
519 }
520
521
522 //! Push an instruction into the CPU pipeline
523 //  NOTE!  Must provide EXECNOPARM for parameter if no parm is required.
524 unsigned long jtagarm7tdmi_exec(unsigned long instr, unsigned long parameter, unsigned char systemspeed) {
525   unsigned long retval;
526
527   cmddatalong[1] = jtagarm7tdmi_nop( 0);
528   cmddatalong[2] = jtagarm7tdmi_nop(systemspeed);
529   cmddatalong[3] = jtagarm7tdmi_instr_primitive(instr, 0);      // write 32-bit instruction code into DR
530   cmddatalong[4] = jtagarm7tdmi_nop( 0);
531   cmddatalong[5] = jtagarm7tdmi_nop( 0);
532   cmddatalong[6] = jtagarm7tdmi_instr_primitive(parameter, 0);  // inject long
533   cmddatalong[7] = jtagarm7tdmi_nop( 0);
534   retval = jtagarm7tdmi_nop( 0);
535   cmddatalong[9] = jtagarm7tdmi_nop( 0);
536   cmddatalong[8] = retval;
537
538   return(retval);
539 }
540
541 //! Retrieve a 32-bit Register value
542 unsigned long jtagarm7tdmi_get_register(unsigned char reg) {
543   unsigned long retval = 0, instr;
544   // push nop into pipeline - clean out the pipeline...
545   cmddatalong[2] = jtagarm7tdmi_nop( 0);
546
547   instr = ARM_READ_REG | (reg<<12);                     // push STR Rx, [R14] into pipeline
548   cmddatalong[1] = jtagarm7tdmi_instr_primitive(instr, 0);
549   cmddatalong[2] = jtagarm7tdmi_nop( 0);                // push nop into pipeline - fetched
550   cmddatalong[3] = jtagarm7tdmi_nop( 0);                // push nop into pipeline - decoded
551   cmddatalong[4] = jtagarm7tdmi_nop( 0);                // push nop into pipeline - executed 
552   retval = jtagarm7tdmi_nop( 0);                        // recover 32-bit word
553   cmddatalong[5] = retval;
554   cmddatalong[6] = jtagarm7tdmi_nop( 0);
555   cmddatalong[7] = jtagarm7tdmi_nop( 0);
556   cmddatalong[8] = jtagarm7tdmi_nop( 0);
557   return retval;
558 }
559
560 //! Set a 32-bit Register value
561 unsigned long jtagarm7tdmi_set_register(unsigned char reg, unsigned long val) {
562   unsigned long retval = 0, instr;
563   cmddatalong[2] = jtagarm7tdmi_nop( 0); // push nop into pipeline - clean out the pipeline...
564
565   instr = ARM_WRITE_REG | (reg<<12);     // push LDR Rx, [R14] into pipeline
566   cmddatalong[1] = jtagarm7tdmi_instr_primitive(instr, 0);
567   cmddatalong[2] = jtagarm7tdmi_nop( 0); // push nop into pipeline - fetched
568   cmddatalong[3] = jtagarm7tdmi_nop( 0); // push nop into pipeline - decoded
569   
570   cmddatalong[4] = jtagarm7tdmi_instr_primitive(val, 0); // push 32-bit word on data bus - execute state
571   cmddatalong[5] = jtagarm7tdmi_nop( 0); // push nop into pipeline - executed 
572
573   if (reg == ARM_REG_PC){
574     cmddatalong[6] = jtagarm7tdmi_nop( 0);
575     cmddatalong[7] = jtagarm7tdmi_nop( 0);
576   }
577   cmddatalong[8] = jtagarm7tdmi_nop( 0);
578
579   retval = cmddatalong[5];
580   return(retval);
581 }
582
583
584
585 //! Get all registers.  Return an array
586 unsigned long* jtagarm7tdmi_get_registers() {
587   cmddatalong[1] = jtagarm7tdmi_instr_primitive(ARM_INSTR_SKANKREGS,0);
588   cmddatalong[2] = jtagarm7tdmi_nop( 0);
589   cmddatalong[3] = jtagarm7tdmi_nop( 0);
590   cmddatalong[4] = jtagarm7tdmi_nop( 0);
591   cmddatalong[5] = jtagarm7tdmi_nop( 0);
592   cmddatalong[6] = jtagarm7tdmi_nop( 0);
593   cmddatalong[7] = jtagarm7tdmi_nop( 0);
594   cmddatalong[8] = jtagarm7tdmi_nop( 0);
595   cmddatalong[9] = jtagarm7tdmi_nop( 0);
596   cmddatalong[10] = jtagarm7tdmi_nop( 0);
597   cmddatalong[11] = jtagarm7tdmi_nop( 0);
598   cmddatalong[12] = jtagarm7tdmi_nop( 0);
599   cmddatalong[13] = jtagarm7tdmi_nop( 0);
600   cmddatalong[14] = jtagarm7tdmi_nop( 0);
601   cmddatalong[15] = jtagarm7tdmi_nop( 0);
602   cmddatalong[16] = jtagarm7tdmi_nop( 0);
603   cmddatalong[17] = jtagarm7tdmi_nop( 0);
604   cmddatalong[18] = jtagarm7tdmi_nop( 0);
605   cmddatalong[19] = jtagarm7tdmi_nop( 0);
606   cmddatalong[20] = jtagarm7tdmi_nop( 0);
607   return registers;
608 }
609
610 //! Retrieve the CPSR Register value
611 unsigned long jtagarm7tdmi_get_regCPSR() {
612   unsigned long retval = 0;
613
614   cmddatalong[1] = jtagarm7tdmi_nop( 0); // push nop into pipeline - clean out the pipeline...
615   cmddatalong[2] = jtagarm7tdmi_instr_primitive(ARM_INSTR_MRS_R0_CPSR, 0); // push MRS_R0, CPSR into pipeline
616   cmddatalong[3] = jtagarm7tdmi_nop( 0); // push nop into pipeline - fetched
617   cmddatalong[4] = jtagarm7tdmi_nop( 0); // push nop into pipeline - decoded
618   cmddatalong[5] = jtagarm7tdmi_nop( 0); // push nop into pipeline - executed 
619   retval = jtagarm7tdmi_nop( 0);        // recover 32-bit word
620   cmddatalong[6] = retval;
621   return retval;
622 }
623
624 //! Retrieve the CPSR Register value
625 unsigned long jtagarm7tdmi_set_regCPSR(unsigned long val) {
626   unsigned long retval = 0;
627
628   cmddatalong[1] = jtagarm7tdmi_nop( 0);        // push nop into pipeline - clean out the pipeline...
629   cmddatalong[1] = jtagarm7tdmi_instr_primitive(ARM_INSTR_MSR_cpsr_cxsf_R0, 0); // push MSR cpsr_cxsf, R0 into pipeline
630   cmddatalong[2] = jtagarm7tdmi_nop( 0);        // push nop into pipeline - fetched
631   cmddatalong[3] = jtagarm7tdmi_nop( 0);        // push nop into pipeline - decoded
632   
633   retval = jtagarm7tdmi_instr_primitive(val, 0);// push 32-bit word on data bus
634   cmddatalong[5] = jtagarm7tdmi_nop( 0);        // push nop into pipeline - executed 
635   cmddatalong[4] = retval;
636   return(retval);
637 }
638
639 //! Write data to address - Assume TAP in run-test/idle state
640 unsigned long jtagarm7tdmi_writemem(unsigned long adr, unsigned long data){
641   unsigned long r0=0, r1=-1;
642
643   r0 = jtagarm7tdmi_get_register(0);        // store R0 and R1
644   r1 = jtagarm7tdmi_get_register(1);
645   jtagarm7tdmi_set_register(0, adr);        // write address into R0
646   jtagarm7tdmi_set_register(1, data);       // write data in R1
647   jtagarm7tdmi_nop( 0);                     // push nop into pipeline to "clean" it ???
648   jtagarm7tdmi_nop( 1);                     // push nop into pipeline with BREAKPT set
649   jtagarm7tdmi_instr_primitive(ARM_INSTR_LDR_R1_r0_4, 0); // push LDR R1, R0, #4 into instruction pipeline
650   jtagarm7tdmi_nop( 0);                     // push nop into pipeline
651   jtagarm7tdmi_set_register(1, r1);         // restore R0 and R1 
652   jtagarm7tdmi_set_register(0, r0);
653   return(-1);
654 }
655
656
657
658
659 //! Read data from address
660 unsigned long jtagarm7tdmi_readmem(unsigned long adr){
661   unsigned long retval = 0;
662   unsigned long r0=0, r1=-1;
663   int waitcount = 0xfff;
664
665   r0 = jtagarm7tdmi_get_register(0);        // store R0 and R1
666   r1 = jtagarm7tdmi_get_register(1);
667   jtagarm7tdmi_set_register(0, adr);        // write address into R0
668   jtagarm7tdmi_nop( 0);                     // push nop into pipeline to "clean" it ???
669   jtagarm7tdmi_nop( 1);                     // push nop into pipeline with BREAKPT set
670   jtagarm7tdmi_instr_primitive(ARM_INSTR_LDR_R1_r0_4, 0); // push LDR R1, R0, #4 into instruction pipeline
671   jtagarm7tdmi_nop( 0);                     // push nop into pipeline
672   jtagarm7tdmi_restart();                   // SHIFT_IR with RESTART instruction
673
674   // Poll the Debug Status Register for DBGACK and nMREQ to be HIGH
675   while ((jtagarm7tdmi_get_dbgstate() & 9) == 0  && waitcount > 0){
676     delay(1);
677     waitcount --;
678   }
679   if (waitcount == 0xffff){
680     return (-1);
681   } else {
682     retval = jtagarm7tdmi_get_register(1);  // read memory value from R1 register
683   jtagarm7tdmi_set_register(1, r1);         // restore R0 and R1 
684   jtagarm7tdmi_set_register(0, r0);
685   }
686   return retval;
687 }
688
689
690 //! Read Program Counter
691 unsigned long jtagarm7tdmi_getpc(){
692   return jtagarm7tdmi_get_register(ARM_REG_PC);
693 }
694
695 //! Set Program Counter
696 unsigned long jtagarm7tdmi_setpc(unsigned long adr){
697   return jtagarm7tdmi_set_register(ARM_REG_PC, adr);
698 }
699
700 //! Halt CPU - returns 0xffff if the operation fails to complete within 
701 unsigned long jtagarm7tdmi_haltcpu(){                   //  PROVEN
702   int waitcount = 0xfff;
703
704   // store watchpoint info?  - not right now
705   eice_write(EICE_WP1ADDR, 0);              // write 0 in watchpoint 1 address
706   eice_write(EICE_WP1ADDRMASK, 0xffffffff); // write 0xffffffff in watchpoint 1 address mask
707   eice_write(EICE_WP1DATA, 0);              // write 0 in watchpoint 1 data
708   eice_write(EICE_WP1DATAMASK, 0xffffffff); // write 0xffffffff in watchpoint 1 data mask
709   eice_write(EICE_WP1CTRL, 0x100);          //!!!!! WTF!  THIS IS SUPPOSED TO BE 9 bits wide?!?  // write 0x00000100 in watchpoint 1 control value register (enables watchpoint)
710   eice_write(EICE_WP1CTRLMASK, 0xfffffff7); //!!!!! WTF!  THIS IS SUPPOSED TO BE 8 bits wide?!?  // write 0xfffffff7 in watchpoint 1 control mask - only detect the fetch instruction
711
712   // poll until debug status says the cpu is in debug mode
713   while (!(jtagarm7tdmi_get_dbgstate() & 0x1)   && waitcount-- > 0){
714     delay(5);
715   }
716   eice_write(EICE_WP1CTRL, 0x0);            // write 0 in watchpoint 0 control value - disables watchpoint 0
717
718   // store the debug state
719   last_halt_debug_state = jtagarm7tdmi_get_dbgstate();
720   last_halt_pc = jtagarm7tdmi_getpc() - 4;  // assume -4 for entering debug mode via watchpoint.
721   count_dbgspd_instr_since_debug = 0;
722   count_sysspd_instr_since_debug = 0;
723
724   // get into ARM mode if the T flag is set (Thumb mode)
725   while (jtagarm7tdmi_get_dbgstate() & JTAG_ARM7TDMI_DBG_TBIT && waitcount-- > 0) {
726     jtagarm7tdmi_setMode_ARM();
727   }
728   return waitcount;
729 }
730
731 unsigned long jtagarm7tdmi_releasecpu(){
732   int waitcount = 0xfff;
733   unsigned long instr;
734   // somehow determine what PC should be (a couple ways possible, calculations required)
735   jtagarm7tdmi_nop(0);                          // NOP
736   jtagarm7tdmi_nop(1);                          // NOP/BREAKPT
737
738   if (last_halt_debug_state & JTAG_ARM7TDMI_DBG_TBIT){      // FIXME:  FORNICATED!  BX requires register, thus more instrs... could we get away with the same instruction but +1 to offset?
739     instr = ARM_INSTR_B_PC + 0x1000001 - (count_dbgspd_instr_since_debug) - (count_sysspd_instr_since_debug*3);  //FIXME: make this right  - can't we just do an a7solute b/bx?
740     jtagarm7tdmi_instr_primitive(instr,0);
741   } else {
742     instr = ARM_INSTR_B_PC + 0x1000000 - (count_dbgspd_instr_since_debug) - (count_sysspd_instr_since_debug*3);  //FIXME: make this right  - can't we just do an absolute b/bx?
743     jtagarm7tdmi_instr_primitive(instr,0);
744   }
745
746   SHIFT_IR;
747   jtagarmtransn(ARM7TDMI_IR_RESTART,4,LSB,END,RETIDLE); // VERB_RESTART
748
749   // wait until restart-bit set in debug state register
750   while ((jtagarm7tdmi_get_dbgstate() & JTAG_ARM7TDMI_DBG_DBGACK) && waitcount > 0){
751     //delay(1);
752     waitcount --;
753   }
754   last_halt_debug_state = -1;
755   last_halt_pc = -1;
756   return 0;
757 }
758  
759
760
761
762 ///////////////////////////////////////////////////////////////////////////////////////////////////
763 //! Handles ARM7TDMI JTAG commands.  Forwards others to JTAG.
764 void jtagarm7tdmihandle(unsigned char app, unsigned char verb, unsigned long len){
765   register char blocks;
766   
767   unsigned int i,val;
768   unsigned long at;
769   
770   jtagarm7tdmi_resettap();
771  
772   switch(verb){
773   case START:
774     //Enter JTAG mode.
775     cmddatalong[0] = jtagarm7tdmi_start();
776     cmddatalong[2] = jtagarm7tdmi_haltcpu();
777     //jtagarm7tdmi_resettap();
778     cmddatalong[1] = jtagarm7tdmi_get_dbgstate();
779
780     txdata(app,verb,0xc);
781     break;
782   case JTAGARM7TDMI_READMEM:
783   case PEEK:
784     blocks=(len>4?cmddata[4]:1);
785     at=cmddatalong[0];
786     
787     len=0x80;
788     txhead(app,verb,len);
789     
790     while(blocks--){
791       for(i=0;i<len;i+=2){
792         jtagarm7tdmi_resettap();
793         delay(10);
794         
795         val=jtagarm7tdmi_readmem(at);
796                 
797         at+=2;
798         serial_tx(val&0xFF);
799         serial_tx((val&0xFF00)>>8);
800       }
801     }
802     
803     break;
804   case JTAGARM7TDMI_GET_CHIP_ID:
805         jtagarm7tdmi_resettap();
806     cmddatalong[0] = jtagarm7tdmi_idcode();
807     txdata(app,verb,4);
808     break;
809
810
811   case JTAGARM7TDMI_WRITEMEM:
812   case POKE:
813         jtagarm7tdmi_resettap();
814     jtagarm7tdmi_writemem(cmddatalong[0],
815                        cmddataword[2]);
816     cmddataword[0]=jtagarm7tdmi_readmem(cmddatalong[0]);
817     txdata(app,verb,2);
818     break;
819
820   case JTAGARM7TDMI_HALTCPU:  
821     cmddatalong[0] = jtagarm7tdmi_haltcpu();
822     txdata(app,verb,4);
823     break;
824   case JTAGARM7TDMI_RELEASECPU:
825         jtagarm7tdmi_resettap();
826     cmddatalong[0] = jtagarm7tdmi_releasecpu();
827     txdata(app,verb,4);
828     break;
829   //unimplemented functions
830   //case JTAGARM7TDMI_SETINSTRFETCH:
831   //case JTAGARM7TDMI_WRITEFLASH:
832   //case JTAGARM7TDMI_ERASEFLASH:
833   case JTAGARM7TDMI_SET_PC:
834     cmddatalong[0] = jtagarm7tdmi_setpc(cmddatalong[0]);
835     txdata(app,verb,4);
836     break;
837   case JTAGARM7TDMI_GET_DEBUG_CTRL:
838     cmddatalong[0] = jtagarm7tdmi_get_dbgctrl();
839     txdata(app,verb,1);
840     break;
841   case JTAGARM7TDMI_SET_DEBUG_CTRL:
842     cmddatalong[0] = jtagarm7tdmi_set_dbgctrl(cmddata[0]);
843     txdata(app,verb,4);
844     break;
845   case JTAGARM7TDMI_GET_PC:
846     cmddatalong[0] = jtagarm7tdmi_getpc();
847     txdata(app,verb,4);
848     break;
849   case JTAGARM7TDMI_GET_DEBUG_STATE:
850     //jtagarm7tdmi_resettap();            // Shouldn't need this, but currently do.  FIXME!
851     cmddatalong[0] = jtagarm7tdmi_get_dbgstate();
852     txdata(app,verb,4);
853     break;
854   //case JTAGARM7TDMI_GET_WATCHPOINT:
855   //case JTAGARM7TDMI_SET_WATCHPOINT:
856   case JTAGARM7TDMI_GET_REGISTER:
857         jtagarm7tdmi_resettap();
858     cmddatalong[0] = jtagarm7tdmi_get_register(cmddata[0]);
859     txdata(app,verb,96);
860     break;
861   case JTAGARM7TDMI_SET_REGISTER:
862         jtagarm7tdmi_resettap();
863     cmddatalong[0] = cmddatalong[1];
864     jtagarm7tdmi_set_register(cmddata[0], cmddatalong[1]);
865     txdata(app,verb,96);
866     break;
867   case JTAGARM7TDMI_GET_REGISTERS:
868         jtagarm7tdmi_resettap();
869     jtagarm7tdmi_get_registers();
870     txdata(app,verb,80);
871     break;
872   //case JTAGARM7TDMI_SET_REGISTERS:
873   case JTAGARM7TDMI_DEBUG_INSTR:
874         jtagarm7tdmi_resettap();
875     cmddataword[0] = jtagarm7tdmi_exec(cmddataword[0], cmddataword[1], cmddata[9]);
876     txdata(app,verb,80);
877     break;
878   case JTAGARM7TDMI_STEP_INSTR:
879 /*  case JTAGARM7TDMI_READ_CODE_MEMORY:
880   case JTAGARM7TDMI_WRITE_FLASH_PAGE:
881   case JTAGARM7TDMI_READ_FLASH_PAGE:
882   case JTAGARM7TDMI_MASS_ERASE_FLASH:
883   case JTAGARM7TDMI_PROGRAM_FLASH:
884   case JTAGARM7TDMI_LOCKCHIP:
885   case JTAGARM7TDMI_CHIP_ERASE:
886   */
887 // Really ARM specific stuff
888   case JTAGARM7TDMI_GET_CPSR:
889         jtagarm7tdmi_resettap();
890     cmddatalong[0] = jtagarm7tdmi_get_regCPSR();
891     txdata(app,verb,4);
892     break;
893   case JTAGARM7TDMI_SET_CPSR:
894         jtagarm7tdmi_resettap();
895     cmddatalong[0] = jtagarm7tdmi_set_regCPSR(cmddatalong[0]);
896     txdata(app,verb,4);
897     break;
898   case JTAGARM7TDMI_GET_SPSR:           // FIXME: NOT CORRECT
899         jtagarm7tdmi_resettap();
900     cmddatalong[0] = jtagarm7tdmi_get_regCPSR();
901     txdata(app,verb,4);
902     break;
903   case JTAGARM7TDMI_SET_SPSR:           // FIXME: NOT CORRECT
904         jtagarm7tdmi_resettap();
905     cmddatalong[0] = jtagarm7tdmi_set_regCPSR(cmddatalong[0]);
906     txdata(app,verb,4);
907     break;
908   case JTAGARM7TDMI_SET_MODE_THUMB:
909   case JTAGARM7TDMI_SET_MODE_ARM:
910         jtagarm7tdmi_resettap();
911     cmddataword[0] = jtagarm7tdmi_setMode_ARM();
912     txdata(app,verb,4);
913     break;
914     
915   case 0xD0:          // loopback test
916     jtagarm7tdmi_resettap();
917     cmddatalong[0] = jtagarm7tdmi_bypass(cmddatalong[0]);
918     txdata(app,verb,4);
919     break;
920   case 0xD8:          // EICE_READ
921     jtagarm7tdmi_resettap();
922     cmddatalong[0] = eice_read(cmddatalong[0]);
923     txdata(app,verb,4);
924     break;
925   case 0xD9:          // EICE_WRITE
926     jtagarm7tdmi_resettap();
927     cmddatalong[0] = eice_write(cmddatalong[0], cmddatalong[1]);
928     txdata(app,verb,4);
929     break;
930   case 0xDA:          // TEST MSB THROUGH CHAIN0 and CHAIN1
931     jtagarm7tdmi_resettap();
932     jtagarm7tdmi_scan_intest(0);
933     cmddatalong[0] = jtagarmtransn(0x41414141, 32, LSB, NOEND, NORETIDLE);
934     cmddatalong[1] = jtagarmtransn(0x42424242, 32, MSB, NOEND, NORETIDLE);
935     cmddatalong[2] = jtagarmtransn(0x43434343,  9, MSB, NOEND, NORETIDLE);
936     cmddatalong[3] = jtagarmtransn(0x44444444, 32, MSB, NOEND, NORETIDLE);
937     cmddatalong[4] = jtagarmtransn(cmddatalong[0], 32, LSB, NOEND, NORETIDLE);
938     cmddatalong[5] = jtagarmtransn(cmddatalong[1], 32, MSB, NOEND, NORETIDLE);
939     cmddatalong[6] = jtagarmtransn(cmddatalong[2],  9, MSB, NOEND, NORETIDLE);
940     cmddatalong[7] = jtagarmtransn(cmddatalong[3], 32, MSB, END, RETIDLE);
941     jtagarm7tdmi_resettap();
942     jtagarm7tdmi_scan_intest(1);
943     cmddatalong[8] = jtagarmtransn(0x41414141, 32, MSB, NOEND, NORETIDLE);
944     cmddatalong[9] = jtagarmtransn(0x44444444,  1, MSB, NOEND, NORETIDLE);
945     cmddatalong[10] = jtagarmtransn(cmddatalong[8], 32, MSB, NOEND, NORETIDLE);
946     cmddatalong[11] = jtagarmtransn(cmddatalong[9],  1, MSB, END, RETIDLE);
947     txdata(app,verb,48);
948     break;
949     
950   default:
951     jtaghandle(app,verb,len);
952   }
953 }