cc6ef169e874bac278989732913352d1f5359a73
[goodfet] / firmware / apps / jtag / jtag.c
1 /*! \file jtag.c
2   \author Travis Goodspeed <travis at radiantmachines.com>
3   \brief Low-level JTAG
4 */
5
6
7 #include "platform.h"
8 #include "command.h"
9 #include "jtag.h"
10
11
12 //! Set up the pins for JTAG mode.
13 void jtagsetup(){
14   P5DIR|=MOSI+SCK+TMS;
15   P5DIR&=~MISO;
16   /*
17   P5OUT|=0xFFFF;
18   P5OUT=0;
19   */
20   P4DIR|=TST;
21   P2DIR|=RST;
22   msdelay(100);
23 }
24
25 /************************** JTAG Primitives ****************************/
26 // these have been turned into functions to save flash space
27 void jtag_tcktock() {
28   CLRTCK; 
29   PLEDOUT^=PLEDPIN; 
30   SETTCK; 
31   PLEDOUT^=PLEDPIN;
32 }
33
34 void jtag_goto_shift_ir() {
35   SETTMS;
36   jtag_tcktock();
37   jtag_tcktock();
38   CLRTMS;
39   jtag_tcktock();
40   jtag_tcktock();
41
42 }
43 void jtag_goto_shift_dr() {
44   SETTMS;
45   jtag_tcktock();
46   CLRTMS;
47   jtag_tcktock();
48   jtag_tcktock();
49 }
50
51 void jtag_resettap(){
52   SETTMS;
53   jtag_tcktock();
54   jtag_tcktock();
55   jtag_tcktock();
56   jtag_tcktock();
57   jtag_tcktock();  // now in Reset state
58   CLRTMS;
59   jtag_tcktock();  // now in Run-Test/Idle state
60 }
61
62
63 int savedtclk=0;
64 //  NOTE: important: THIS MODULE REVOLVES AROUND RETURNING TO RUNTEST/IDLE, OR THE FUNCTIONAL EQUIVALENT
65 //! 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
66 //      flags should be 0 for most uses.  
67 //      for the extreme case, flags should be  (NOEND|NORETDLE|LSB)
68 //      other edge cases can involve a combination of those three flags
69 //
70 //      the max bit-size that can be be shifted is 32-bits.  
71 //      for longer shifts, use the NOEND flag (which infers NORETIDLE so the additional flag is unnecessary)
72 //
73 //      NORETIDLE is used for special cases where (as with arm) the debug subsystem does not want to 
74 //      return to the RUN-TEST/IDLE state between setting IR and DR
75 unsigned long jtagtransn(unsigned long word, unsigned char bitcount, unsigned char flags){            
76   unsigned char bit;
77   unsigned long high = 1L;
78   unsigned long mask;
79
80   //for (bit=(bitcount-1)/8; bit>0; bit--)
81   //  high <<= 8;
82   //high <<= ((bitcount-1)%8);
83   high <<= (bitcount-1);
84
85   mask = high-1;
86
87   SAVETCLK;
88   if (flags & LSB) {
89     for (bit = bitcount; bit > 0; bit--) {
90       /* write MOSI on trailing edge of previous clock */
91       if (word & 1)
92         {SETMOSI;}
93       else
94         {CLRMOSI;}
95       word >>= 1;
96
97       if (bit==1 && !(flags & NOEND))
98         SETTMS;//TMS high on last bit to exit.
99        
100       jtag_tcktock();
101
102       /* read MISO on trailing edge */
103       if (READMISO){
104         word += (high);
105       }
106     }
107   } else {
108     for (bit = bitcount; bit > 0; bit--) {
109       /* write MOSI on trailing edge of previous clock */
110       if (word & high)
111         {SETMOSI;}
112       else
113         {CLRMOSI;}
114       word = (word & mask) << 1;
115
116       if (bit==1 && !(flags & NOEND))
117         SETTMS;//TMS high on last bit to exit.
118
119       jtag_tcktock();
120
121       /* read MISO on trailing edge */
122       word |= (READMISO);
123     }
124   }
125  
126
127   RESTORETCLK;
128   //SETMOSI;
129
130   if (!(flags & NOEND)){
131     // exit state
132     jtag_tcktock();
133     // update state
134     if (!(flags & NORETIDLE)){
135       CLRTMS;
136       jtag_tcktock();
137     }
138   }
139   return word;
140 }
141
142 //! Shift 8 bits in and out.
143 unsigned char jtagtrans8(unsigned char byte){
144   unsigned int bit;
145   SAVETCLK;
146   for (bit = 0; bit < 8; bit++) {
147     /* write MOSI on trailing edge of previous clock */
148     if (byte & 0x80)
149       {SETMOSI;}
150     else
151       {CLRMOSI;}
152     byte <<= 1;
153     
154     if(bit==7)
155       SETTMS;//TMS high on last bit to exit.
156     
157     TCKTOCK;
158     /* read MISO on trailing edge */
159     byte |= READMISO;
160   }
161   RESTORETCLK;
162   
163   // exit state
164   TCKTOCK;
165   // update state
166   CLRTMS;
167   TCKTOCK;
168   
169   return byte;
170 }
171
172 //! Shift n bits in and out.
173 /*unsigned long jtagtransn(unsigned long word,
174                          unsigned int bitcount){
175   unsigned int bit;
176   //0x8000
177   unsigned long high=0x8000;
178   
179   if(bitcount==20)
180     high=0x80000;
181   if(bitcount==16)
182     high= 0x8000;
183   
184   SAVETCLK;
185   
186   for (bit = 0; bit < bitcount; bit++) {
187     // write MOSI on trailing edge of previous clock *
188     if (word & high)
189       {SETMOSI;}
190     else
191       {CLRMOSI;}
192     word <<= 1;
193     
194     if(bit==bitcount-1)
195       SETTMS;//TMS high on last bit to exit.
196     
197     TCKTOCK;
198     // read MISO on trailing edge *
199     word |= READMISO;
200   }
201   
202   if(bitcount==20){
203     word = ((word << 16) | (word >> 4)) & 0x000FFFFF;
204   }
205   
206   RESTORETCLK;
207   
208   // exit state
209   TCKTOCK;
210   // update state
211   CLRTMS;
212   TCKTOCK;
213   
214   return word;
215 }
216 */
217
218 //! Stop JTAG, release pins
219 void jtag_stop(){
220   P5OUT=0;
221   P4OUT=0;
222 }
223
224 unsigned int drwidth=16;
225 //! Shift all bits of the DR.
226 unsigned long jtag_dr_shift20(unsigned long in){
227   // idle
228   SETTMS;
229   TCKTOCK;
230   // select DR
231   CLRTMS;
232   TCKTOCK;
233   // capture IR
234   TCKTOCK;
235   
236   // shift DR, then idle
237   return(jtagtransn(in,20,0));
238 }
239
240
241 //! Shift 16 bits of the DR.
242 unsigned int jtag_dr_shift16(unsigned int in){
243   // idle
244   SETTMS;
245   TCKTOCK;
246   // select DR
247   CLRTMS;
248   TCKTOCK;
249   // capture IR
250   TCKTOCK;
251   
252   // shift DR, then idle
253   return(jtagtransn(in,16,0));
254 }
255
256 //! Shift native width of the DR
257 unsigned long jtag_dr_shiftadr(unsigned long in){
258   unsigned long out=0;
259   
260   // idle
261   SETTMS;
262   TCKTOCK;
263   // select DR
264   CLRTMS;
265   TCKTOCK;
266   // capture IR
267   TCKTOCK;
268
269   
270   out=jtagtransn(in,drwidth,0);
271   
272   // shift DR, then idle
273   return(out);
274 }
275
276
277 //! Shift 8 bits of the IR.
278 unsigned char jtag_ir_shift8(unsigned char in){
279   // idle
280   SETTMS;
281   TCKTOCK;
282   // select DR
283   TCKTOCK;
284   // select IR
285   CLRTMS;
286   TCKTOCK;
287   // capture IR
288   TCKTOCK;
289   
290   // shift IR, then idle.
291   return(jtagtrans8(in));
292 }
293
294 //! Handles a monitor command.
295 void jtaghandle(unsigned char app,
296                unsigned char verb,
297                unsigned long len){
298   switch(verb){
299     //START handled by specific JTAG
300   case STOP:
301     jtag_stop();
302     txdata(app,verb,0);
303     break;
304   case SETUP:
305     jtagsetup();
306     txdata(app,verb,0);
307     break;
308   case JTAG_IR_SHIFT:
309     cmddata[0]=jtag_ir_shift8(cmddata[0]);
310     txdata(app,verb,1);
311     break;
312   case JTAG_DR_SHIFT:
313     cmddataword[0]=jtag_dr_shift16(cmddataword[0]);
314     txdata(app,verb,2);
315     break;
316   case JTAG_RESETTAP:
317     jtag_resettap();
318     txdata(app,verb,0);
319     break;
320   default:
321     txdata(app,NOK,0);
322   }
323 }
324
325