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