1 /* JTAG low level functions and base class for cables
2 
3 Copyright (C) 2004 Andrew Rogers
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 
19 Changes:
20 Sandro Amato [sdroamt@netscape.net] 26 Jun 2006 [applied 13 Jul 2006]:
21    Added a 'dotted' progress bar
22 Dmitry Teytelman [dimtey@gmail.com] 14 Jun 2006 [applied 13 Aug 2006]:
23     Code cleanup for clean -Wall compile.
24     Extensive changes to support FT2232 driver.
25     Moved progress bar to ioparport.cpp and ioftdi.cpp.
26 */
27 
28 
29 
30 #include "iobase.h"
31 
32 #include <unistd.h>
33 #include <stdio.h>
34 
35 using namespace std;
36 
IOBase()37 IOBase::IOBase()
38 {
39   verbose = false;
40   current_state=UNKNOWN;
41 }
42 
shiftTDITDO(const unsigned char * tdi,unsigned char * tdo,int length,bool last)43 void IOBase::shiftTDITDO(const unsigned char *tdi, unsigned char *tdo, int length, bool last)
44 {
45   if(length==0) return;
46 
47   int i=0;
48   int j=0;
49   unsigned char tdo_byte=0;
50   unsigned char tdi_byte=tdi[j];
51   while(i<length-1){
52     tdo_byte=tdo_byte+(txrx(false, (tdi_byte&1)==1)<<(i%8));
53     tdi_byte=tdi_byte>>1;
54     i++;
55     if((i%8)==0){ // Next byte
56       tdo[j]=tdo_byte; // Save the TDO byte
57       tdo_byte=0;
58       j++;
59       tdi_byte=tdi[j]; // Get the next TDI byte
60     }
61   };
62   tdo_byte=tdo_byte+(txrx(last, (tdi_byte&1)==1)<<(i%8)); // TMS set if last=true
63   tdo[j]=tdo_byte;
64   nextTapState(last); // If TMS is set the the state of the tap changes
65   return;
66 }
67 
shiftTDI(const unsigned char * tdi,int length,bool last)68 void IOBase::shiftTDI(const unsigned char *tdi, int length, bool last)
69 {
70   unsigned char *buf = (unsigned char *)tdi;
71   int i, j, k, bytes = length / 8;
72 
73   if (length==0) return;
74 
75   if (bytes > 1)
76   {
77     for (k = 0; k < bytes/BLOCK_SIZE; k++)
78       tx_tdi_block(buf + k*BLOCK_SIZE, BLOCK_SIZE);
79 
80     tx_tdi_block(buf + k*BLOCK_SIZE, bytes - 1 - k*BLOCK_SIZE);
81     j = bytes - 1;
82     i = (bytes - 1) * 8;
83   }
84   else
85   {
86     i = 0;
87     j = 0;
88   }
89 /*
90   for (; j < bytes - 1; j++, i += 8)
91   {
92     tx_tdi_byte(tdi[j]);
93     if (verbose && j != 0 && (j % TICK_COUNT == 0))
94       write(0, ".", 1);
95   }
96 */
97   unsigned char tdi_byte=tdi[j];
98   while(i<length-1){
99     tx(false, (tdi_byte&1)==1);
100     tdi_byte=tdi_byte>>1;
101     i++;
102     if((i%8)==0){ // Next byte
103       j++;
104       tdi_byte=tdi[j]; //Get the next TDI byte
105     }
106   };
107   tx(last, (tdi_byte&1)==1); // TMS set if last=true
108   nextTapState(last); // If TMS is set the the state of the tap changes
109   return;
110 }
111 
112 // TDI gets a load of zeros, we just record TDO.
shiftTDO(unsigned char * tdo,int length,bool last)113 void IOBase::shiftTDO(unsigned char *tdo, int length, bool last)
114 {
115   if (length==0) return;
116   int i=0;
117   int j=0;
118   unsigned char tdo_byte=0;
119   while(i<length-1){
120     tdo_byte=tdo_byte+(txrx(false, false)<<(i%8));
121     i++;
122     if((i%8)==0){ // Next byte
123       tdo[j]=tdo_byte; // Save the TDO byte
124       tdo_byte=0;
125       j++;
126     }
127   };
128   tdo_byte=tdo_byte+(txrx(last, false)<<(i%8)); // TMS set if last=true
129   tdo[j]=tdo_byte;
130   nextTapState(last); // If TMS is set the the state of the tap changes
131   return;
132 }
133 
134 // TDI gets a load of zeros or ones, and we ignore TDO
shift(bool tdi,int length,bool last)135 void IOBase::shift(bool tdi, int length, bool last)
136 {
137   if (length==0) return;
138   int i=0;
139   while(i<length-1){
140     tx(false, tdi);
141     i++;
142   };
143   tx(last, tdi); // TMS set if last=true
144   nextTapState(last); // If TMS is set the the state of the tap changes
145   return;
146 }
147 
setTapState(tapState_t state)148 void IOBase::setTapState(tapState_t state)
149 {
150   bool tms;
151   while(current_state!=state){
152     switch(current_state){
153 
154     case TEST_LOGIC_RESET:
155       switch(state){
156       case TEST_LOGIC_RESET:
157 	tms=true;
158 	break;
159       default:
160 	tms=false;
161 	current_state=RUN_TEST_IDLE;
162       };
163       break;
164 
165     case RUN_TEST_IDLE:
166       switch(state){
167       case RUN_TEST_IDLE:
168 	tms=false;
169 	break;
170       default:
171 	tms=true;
172 	current_state=SELECT_DR_SCAN;
173       };
174       break;
175 
176     case SELECT_DR_SCAN:
177       switch(state){
178       case CAPTURE_DR:
179       case SHIFT_DR:
180       case EXIT1_DR:
181       case PAUSE_DR:
182       case EXIT2_DR:
183       case UPDATE_DR:
184 	tms=false;
185 	current_state=CAPTURE_DR;
186 	break;
187       default:
188 	tms=true;
189 	current_state=SELECT_IR_SCAN;
190       };
191       break;
192 
193     case CAPTURE_DR:
194       switch(state){
195       case SHIFT_DR:
196 	tms=false;
197 	current_state=SHIFT_DR;
198 	break;
199       default:
200 	tms=true;
201 	current_state=EXIT1_DR;
202       };
203       break;
204 
205     case SHIFT_DR:
206       switch(state){
207       case SHIFT_DR:
208 	tms=false;
209 	break;
210       default:
211 	tms=true;
212 	current_state=EXIT1_DR;
213       };
214       break;
215 
216     case EXIT1_DR:
217       switch(state){
218       case PAUSE_DR:
219       case EXIT2_DR:
220       case SHIFT_DR:
221       case EXIT1_DR:
222 	tms=false;
223 	current_state=PAUSE_DR;
224 	break;
225       default:
226 	tms=true;
227 	current_state=UPDATE_DR;
228       };
229       break;
230 
231     case PAUSE_DR:
232       switch(state){
233       case PAUSE_DR:
234 	tms=false;
235 	break;
236       default:
237 	tms=true;
238 	current_state=EXIT2_DR;
239       };
240       break;
241 
242     case EXIT2_DR:
243       switch(state){
244       case SHIFT_DR:
245       case EXIT1_DR:
246       case PAUSE_DR:
247 	tms=false;
248 	current_state=SHIFT_DR;
249 	break;
250       default:
251 	tms=true;
252 	current_state=UPDATE_DR;
253       };
254       break;
255 
256     case UPDATE_DR:
257       switch(state){
258       case RUN_TEST_IDLE:
259 	tms=false;
260 	current_state=RUN_TEST_IDLE;
261 	break;
262       default:
263 	tms=true;
264 	current_state=SELECT_DR_SCAN;
265       };
266       break;
267 
268     case SELECT_IR_SCAN:
269       switch(state){
270       case CAPTURE_IR:
271       case SHIFT_IR:
272       case EXIT1_IR:
273       case PAUSE_IR:
274       case EXIT2_IR:
275       case UPDATE_IR:
276 	tms=false;
277 	current_state=CAPTURE_IR;
278 	break;
279       default:
280 	tms=true;
281 	current_state=TEST_LOGIC_RESET;
282       };
283       break;
284 
285     case CAPTURE_IR:
286       switch(state){
287       case SHIFT_IR:
288 	tms=false;
289 	current_state=SHIFT_IR;
290 	break;
291       default:
292 	tms=true;
293 	current_state=EXIT1_IR;
294       };
295       break;
296 
297     case SHIFT_IR:
298       switch(state){
299       case SHIFT_IR:
300 	tms=false;
301 	break;
302       default:
303 	tms=true;
304 	current_state=EXIT1_IR;
305       };
306       break;
307 
308     case EXIT1_IR:
309       switch(state){
310       case PAUSE_IR:
311       case EXIT2_IR:
312       case SHIFT_IR:
313       case EXIT1_IR:
314 	tms=false;
315 	current_state=PAUSE_IR;
316 	break;
317       default:
318 	tms=true;
319 	current_state=UPDATE_IR;
320       };
321       break;
322 
323     case PAUSE_IR:
324       switch(state){
325       case PAUSE_IR:
326 	tms=false;
327 	break;
328       default:
329 	tms=true;
330 	current_state=EXIT2_IR;
331       };
332       break;
333 
334     case EXIT2_IR:
335       switch(state){
336       case SHIFT_IR:
337       case EXIT1_IR:
338       case PAUSE_IR:
339 	tms=false;
340 	current_state=SHIFT_IR;
341 	break;
342       default:
343 	tms=true;
344 	current_state=UPDATE_IR;
345       };
346       break;
347 
348     case UPDATE_IR:
349       switch(state){
350       case RUN_TEST_IDLE:
351 	tms=false;
352 	current_state=RUN_TEST_IDLE;
353 	break;
354       default:
355 	tms=true;
356 	current_state=SELECT_DR_SCAN;
357       };
358       break;
359 
360     default:
361       tapTestLogicReset();
362       tms=true;
363     };
364     tx(tms,false);
365   };
366 }
367 
368 // After shift data into the DR or IR we goto the next state
369 // This function should only be called from the end of a shift function
nextTapState(bool tms)370 void IOBase::nextTapState(bool tms)
371 {
372   if(current_state==SHIFT_DR){
373     if(tms)current_state=EXIT1_DR; // If TMS was set then goto next state
374   }
375   else if(current_state==SHIFT_IR){
376     if(tms)current_state=EXIT1_IR; // If TMS was set then goto next state
377   }
378   else tapTestLogicReset(); // We were in an unexpected state
379 }
380 
tapTestLogicReset()381 void IOBase::tapTestLogicReset()
382 {
383   for(int i=0; i<5; i++)tx(true,false);
384   current_state=TEST_LOGIC_RESET;
385 }
386 
cycleTCK(int n,bool tdi)387 void IOBase::cycleTCK(int n, bool tdi)
388 {
389   bool tms=false;
390   if(current_state==TEST_LOGIC_RESET)tms=true;
391   for(int i=0; i<n; i++)tx(tms,tdi);
392 }
393