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