Rev Author Line No. Line
2697 miho 1 // MLAB Xilinx Virtual Cable Network Server
2 // ----------------------------------------
3 //
4 // (c) miho 2012 http://www.mlab.cz/PermaLink/XVC_SOFTWARE
5 //
6 // This program if free.
7 //
8 //
9 // History:
10 //
11 // 1.00 2012_09 Proof of concept (no configuration, not for public release)
12 // 1.01 2012_09 Added parameter for device selection
13 // 1.02 2012_12 Error handling and debugged
14 // 1.03 2012_12 Release version ready to publish
2933 miho 15 // 1.04 2013_04 Socket Bind Error with eplanation (multiple instance of XVC Server)
2697 miho 16 //
17 //
18 // Purpose:
19 //
20 // XILINX development software (ISE, WebPack) supports several types of JTAG programming
21 // cables. Among them there is one particularly interesting. It is Xilinx Virtual Cable
22 // which uses (documented) XVC network protocol to send JTAG commands across TCP/IP network.
23 // So it is possible to realize own hardware/software and have it directly supported by
24 // XILINX development software (both IMPACT and ChipScope).
25 //
26 // This program listens TCP data send by XILINX ISE IMAPACT (or ChipScope) and sends it
27 // to the JTAG device (typically FPGA) connected to FTDI USB Chip. You can use ordinary
28 // USB/RS232 translator based on FT232R chip or you can use our own module from
29 // http://www.mlab.cz/PermaLink/XVC_FT220X
30 //
31 // Target device JTAG port is connected to pins on FTDI USB chip. Program writes to standard
32 // output Which pins are used. Program writes what to set in ISE to enable XVC plugin.
33 //
34 //
35 // Environment:
36 //
37 // This is Win32 Console Application and run in WinXP / Win7 / Win8 both 32 and 64 bit.
38 //
39 // Program needs to listen to the network so it is necessary to allow doing so. In Windows
40 // firewall configuration enable networking for the exe file.
41 // WinXP: run as Administrator c:\WINDOWS\System32\firewall.cpl and add the exe file
42 // Win7: the system asks directly to do so
43 //
44 //
45 // Technology:
46 //
47 // The program uses Windows WINSOCK2 library for network communication
48 // and FTDI ftd2xx library for communication with FTDI USB chip.
49 // It can be staticly linked to minimize dependencies on libraries.
50 // Program requires FTDI drivers installed.
51 // Because of the usage of standard libraries you don't need to solve how to sign drivers.
52 //
53 // The program was debug with FT232R and FT220X device.
54 // It should work with any similar FTDI USB chip.
55 //
56 // XVC protocol is documented (you have to ask XILINX support to gain access).
57 // The program is inspired by the work http://debugmo.de/2012/02/xvcd-the-xilinx-virtual-cable-daemon/
58 // Ask Google about Xilinx Virtual Cable.
59 //
60 //
61 // Translation:
62 //
63 // MS Visual C++ 2010 Express (free, registration required)
64 // Create new empty project for Win32 Console Application and name project mlab_xvcd (to build mlab_xvcd.exe)
65 // Header Files / Add / Existing Items - all .h files
66 // Resource Files / Add / Existing Items - all .lib files
67 // Source Files / Add / Existing Items - all .cpp files
68 // Select Release version (no debug info)
69 // Set static linkage Project Properties / Configuration Release / Configuration Properties
70 // / Code Generation / Runtime Library = Multithreaded (/MT)
71 //
72 //
73 // Problems:
74 //
75 // Programming of SPI FLASH configuration memory connected to FPGA does not work. No idea why.
76 // It does not work for internal FLASH of Spartan XC3SxxAN either.
77 //
78 //
79 // Possible improvements:
80 //
81 // Linux version (Winsock library differs).
82 // External definition of JTAG pins.
2933 miho 83 // Enable Socket Number (to be able to run multiple XVC Servers), now it is constant XVC_TCP_PORT (should be only a default)
2697 miho 84  
85  
86 // Library Definitions
87 // -------------------
88  
89 #undef UNICODE
90 #define WIN32_LEAN_AND_MEAN
91  
92 #include "mlab_xvcd.h" // Program Configuration
93 #include <windows.h> // Windows Console Application
94 #include <winsock2.h> // Windows WinSock2
95 #include <ws2tcpip.h> // Windows WinSock2
96 #include <stdlib.h> // Standard Library (exit, atoi, ...)
97 #include <stdio.h> // Standard IO (printf, ...)
98 #include <signal.h> // CTRL+C handling
99  
100 // Link with library
101 #pragma comment (lib, "Ws2_32.lib")
102  
103 #define XVC_RX_BUFLEN (XVC_JTAG_LEN/8*2+20) // Length of receive buffer in bytes (command+length+TMSbuffer+TDIbuffer)
104 #define XVC_TX_BUFLEN (XVC_JTAG_LEN/8) // Length of transmit buffer in bytes (TDObuffer)
105  
106  
107 // JTAG state machine
108 // ------------------
109  
110 // JTAG States
111 enum
112 {
113 test_logic_reset, run_test_idle, // Starts from 0
114  
115 select_dr_scan, capture_dr, shift_dr,
116 exit1_dr, pause_dr, exit2_dr, update_dr,
117  
118 select_ir_scan, capture_ir, shift_ir,
119 exit1_ir, pause_ir, exit2_ir, update_ir,
120  
121 num_states
122 };
123  
124  
125 // JTAG State Machine transfer Function
126 static int jtagStep(int state, int tms)
127 {
128 static const int next_state[num_states][2] =
129 {
130 /* JTAG State -->> New State */
131 /* -------------------------------------------------------------*/
132 /* | TMS=0 | TMS=1 */
133 /* -------------------------------------------------------------*/
134 /* [test_logic_reset] -> */ { run_test_idle, test_logic_reset },
135 /* [run_test_idle] -> */ { run_test_idle, select_dr_scan },
136 /* [select_dr_scan] -> */ { capture_dr, select_ir_scan },
137 /* [capture_dr] -> */ { shift_dr, exit1_dr },
138 /* [shift_dr] -> */ { shift_dr, exit1_dr },
139 /* [exit1_dr] -> */ { pause_dr, update_dr },
140 /* [pause_dr] -> */ { pause_dr, exit2_dr },
141 /* [exit2_dr] -> */ { shift_dr, update_dr },
142 /* [update_dr] -> */ { run_test_idle, select_dr_scan },
143 /* [select_ir_scan] -> */ { capture_ir, test_logic_reset },
144 /* [capture_ir] -> */ { shift_ir, exit1_ir },
145 /* [shift_ir] -> */ { shift_ir, exit1_ir },
146 /* [exit1_ir] -> */ { pause_ir, update_ir },
147 /* [pause_ir] -> */ { pause_ir, exit2_ir },
148 /* [exit2_ir] -> */ { shift_ir, update_ir },
149 /* [update_ir] -> */ { run_test_idle, select_dr_scan }
150 };
151  
152 return next_state[state][tms];
153 }
154  
155  
156 int handleData(SOCKET ClientSocket)
157 {
158  
159 bool seen_tlr = false;
160 bool jtagError = false;
161  
162 static int jtag_state;
163  
164 do
165 {
166 int iResult;
167  
168 // Read Command
169 char command[16];
170 int commandLen = 0;
171  
172 // Read String terminated by ':'
173 do
174 {
175 iResult = recv(ClientSocket, command+commandLen, 1, 0);
176 if (iResult==0)
177 {
178 printf("\n Connection Closed\n\n");
179 return -1;
180 }
181 else if (iResult==1)
182 {
183 commandLen++;
184 }
185 else
186 {
187 fprintf(stderr, "Error Reading Command\n");
188 return -2;
189 }
190 }
191 while (command[commandLen-1]!=':' && commandLen<sizeof(command)-1 );
192 command[commandLen] = char(0);
193  
194 if (0==strncmp(command, "shift:", sizeof(command)))
195 {
196  
197 }
198 else
199 {
200 fprintf(stderr, "Invalid Command '%s'\n", command);
201 return -2;
202 }
203  
204 // Read Length (in bits, 32bit integer)
205 int len;
206  
207 iResult = recv(ClientSocket, (char *)&len, 4, 0); // pøepsat pøenositelnì
208 if (iResult==0)
209 {
210 printf("\n Connection Closed\n\n");
211 return -1;
212 }
213 if (iResult != 4)
214 {
215 fprintf(stderr, "Reading Length Failed\n");
216 return -2;
217 }
218  
219 char buffer[2048];
220  
221 // Read Data (data string for TMS and TDI)
222 int nr_bytes = (len + 7) / 8;
223 if (nr_bytes * 2 > sizeof(buffer))
224 {
225 fprintf(stderr, "Buffer Size Exceeded\n");
226 return -2;
227 }
228  
229 int iReceivedBytes=0;
230 while (iReceivedBytes<nr_bytes * 2)
231 {
232 iResult = recv(ClientSocket, buffer+iReceivedBytes, nr_bytes * 2 - iReceivedBytes, 0);
233 if (iResult==0)
234 {
235 printf("\n Connection Closed\n\n");
236 return -1;
237 }
238 if (iResult<=0)
239 {
240 fprintf(stderr, "Reading Data Failed %d %d\n", iResult, nr_bytes * 2);
241 return -2;
242 }
243 iReceivedBytes += iResult;
244 }
245  
246 char result[1024];
247 memset(result, 0, nr_bytes);
248  
249 // Deal with JTAG
250  
251 // Only allow exiting if the state is rti and the IR
252 // has the default value (IDCODE) by going through test_logic_reset.
253 // As soon as going through capture_dr or capture_ir no exit is
254 // allowed as this will change DR/IR.
255 seen_tlr = (seen_tlr || jtag_state == test_logic_reset) && (jtag_state != capture_dr) && (jtag_state != capture_ir);
256  
257 // Due to a weird bug(??) xilinx impacts goes through another "capture_ir"/"capture_dr" cycle after
258 // reading IR/DR which unfortunately sets IR to the read-out IR value.
259 // Just ignore these transactions.
260 if ((jtag_state == exit1_ir && len == 5 && buffer[0] == 0x17) || (jtag_state == exit1_dr && len == 4 && buffer[0] == 0x0b))
261 {
262 // printf("Ignoring Bogus jtag State movement at jtag_state %d\n", jtag_state);
263 }
264 else
265 {
266 for (int i = 0; i < len; ++i)
267 {
268 //
269 // Do the actual cycle.
270 //
271 int tms = !!(buffer[i/8] & (1<<(i&7)));
272 //
273 // Track the state.
274 //
275 jtag_state = jtagStep(jtag_state, tms);
276 }
277 if (jtagScan((unsigned char *) buffer, (unsigned char *) buffer + nr_bytes, (unsigned char *) result, len) < 0)
278 {
279 //fprintf(stderr, "jtagScan failed\n");
280 // Can't stop now, have to sent (any) answer not to hung the IMPACT
281 jtagError = true;
282 }
283 }
284  
285 // Send the Ansver
286 iResult = send(ClientSocket, result, nr_bytes, 0 );
287 if (iResult == SOCKET_ERROR)
288 {
289 printf("Send Failed with Error: %d\n", WSAGetLastError());
290 closesocket(ClientSocket);
291 WSACleanup();
292 return -2;
293 }
294 // printf("Bytes Sent: %d\n", iSendResult);
295 // printf("jtag state %d\n", jtag_state);
296 }
297 while (!(seen_tlr && jtag_state == run_test_idle));
298  
299 return jtagError ? -2 : 0;
300 }
301  
302  
303 // Stop Handler - switch JTAG port off and stop program
304 void stopHandler(int sig)
305 {
306 jtagClosePort();
307 exit(1);
308 }
309  
310  
311 // Print help and stop program with error
312 void Help(char *progName)
313 {
314 fprintf(stderr, "Bad Parameters\n");
315 fprintf(stderr, "\n");
316 fprintf(stderr, "Usage: %s [arg]\n", progName);
317 fprintf(stderr, "\n");
318 fprintf(stderr, " Where [arg] is one of: \n");
319 fprintf(stderr, " -d Description Fing FTDI device by Description\n");
320 fprintf(stderr, " -l Location Fing FTDI device by Loaction\n");
321 fprintf(stderr, " -s Serial_number Fing FTDI device by it's SN\n");
322 fprintf(stderr, " -n Number Use N-th FTDI device\n");
323 fprintf(stderr, " The first FTDI device is used if no argument\n");
324 exit(2);
325 }
326  
327  
328 int __cdecl main(int argc, char *argv[])
329 {
330 // Variables
331 bool verbose = true;
332  
333 // Program Info
334 printf("\n");
335 printf("Xilinx Virtual Cable Network Server\n");
336 printf("===================================\n");
337 printf("(c) miho 2012 v " VERSION "\n\n");
338  
339 // Get program name
340 char *cp;
341 char *progName;
342 cp = argv[0];
343 progName=cp;
344 while (cp[0]!='\0')
345 {
346 if (cp[0]=='/' || cp[0]=='\\')
347 progName=cp+1;
348 cp++;
349 }
350  
351 // Process command line params
352 char *findDeviceByStr = 0; // String parameter
353 int findDeviceBy = 0; // What does the string means
354  
355 if (argc>1)
356 {
357 if (argc==3)
358 {
359 findDeviceByStr = argv[2];
360 if (strcmp(argv[1], "-d")==0)
361 {
362 findDeviceBy = OPEN_BY_DESCRIPTION;
363 }
364 else if (strcmp(argv[1], "-l")==0)
365 {
366 findDeviceBy = OPEN_BY_LOCATION;
367 }
368 else if (strcmp(argv[1], "-s")==0)
369 {
370 findDeviceBy = OPEN_BY_SERIAL_NUMBER;
371 }
372 else if (strcmp(argv[1], "-n")==0)
373 {
374 findDeviceBy = 0;
375 }
376 else
377 {
378 Help(progName);
379 }
380 }
381 else
382 {
383 Help(progName);
384 }
385 }
386 else
387 {
388 // Empty String - find device by number and number is empty
389 findDeviceBy = 0;
390 findDeviceByStr = "";
391 }
392  
393 // Find, Init and Open FTDI USB Chip
394 if (jtagOpenPort(findDeviceBy, findDeviceByStr)<0) {
395 // No Device Found
396 fprintf(stderr, "ERROR: No Device Found\n");
397 return -1;
398 }
399  
400 // Signal Handler (for CRTL+C)
401 signal(SIGINT, &stopHandler);
402  
403 printf("Starting Network Server\n");
404 WSADATA wsaData;
405 int iResult;
406  
407 SOCKET ListenSocket = INVALID_SOCKET;
408 SOCKET ClientSocket = INVALID_SOCKET;
409  
410 // Initialize Winsock
411 iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
412 if (iResult != 0)
413 {
414 fprintf(stderr, "WSAStartup failed with error: %d\n", iResult);
415 jtagClosePort();
416 return -2;
417 }
418  
419 // Display HostName and Address
420 char sMyName[255];
421 gethostname(sMyName, sizeof(sMyName));
422 printf(" Host Name %s\n", sMyName);
423 hostent * pHostInfo;
424 pHostInfo = gethostbyname(sMyName);
425 printf(" Network Name %s\n", pHostInfo->h_name);
426 if (pHostInfo->h_length>0 && pHostInfo->h_length<=16)
427 {
428 printf(" Host Address ");
429 for (int i=0; i<pHostInfo->h_length-1; i++)
430 {
431 printf("%d.", (unsigned char)pHostInfo->h_addr_list[0][i]);
432 }
433 printf("%d\n", (unsigned char)pHostInfo->h_addr_list[0][pHostInfo->h_length-1]);
434 }
435  
436 // Create Protocol Structure
437 struct addrinfo hints;
438 ZeroMemory(&hints, sizeof(hints));
439 hints.ai_family = AF_INET; // IP6
440 hints.ai_socktype = SOCK_STREAM; // Reliable two-way connection
441 hints.ai_protocol = IPPROTO_TCP; // Protocol TCP
442 hints.ai_flags = AI_PASSIVE;
443  
444 // Resolve the server address and port (allocate structure "result")
445 struct addrinfo *result = NULL;
446 iResult = getaddrinfo(NULL, XVC_TCP_PORT, &hints, &result);
447 if ( iResult != 0 )
448 {
449 fprintf(stderr, "getaddrinfo failed with error: %d\n", iResult);
450 WSACleanup();
451 jtagClosePort();
452 return -2;
453 }
454  
455 // Create a SOCKET
456 ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
457 if (ListenSocket == INVALID_SOCKET)
458 {
459 fprintf(stderr, "socket failed with error: %ld\n", WSAGetLastError());
460 freeaddrinfo(result);
461 WSACleanup();
462 jtagClosePort();
463 return -2;
464 }
465  
466 // Bind the SOCKED (assign the address)
467 iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
468 if (iResult == SOCKET_ERROR)
469 {
2933 miho 470 int LastError=WSAGetLastError();
471 fprintf(stderr, "Bind failed with error: %d\n", LastError);
472 if (LastError==10048) fprintf(stderr, "Trying to start second instance of XVC Server?\n");
2697 miho 473 freeaddrinfo(result);
474 closesocket(ListenSocket);
475 WSACleanup();
476 jtagClosePort();
477 return -2;
478 }
479  
480 if (verbose)
481 {
482 printf(" Bound Socket %s\n", XVC_TCP_PORT);
483 }
484  
485 // Help for user
486 printf(" Set in IMPACT xilinx_xvc host=%s:%s disableversioncheck=true\n", sMyName, XVC_TCP_PORT);
487  
488 freeaddrinfo(result);
489  
490 // Listen SOCKET
491 iResult = listen(ListenSocket, SOMAXCONN);
492 if (iResult == SOCKET_ERROR)
493 {
2933 miho 494 fprintf(stderr, "listen failed with error: %d\n", WSAGetLastError());
2697 miho 495 closesocket(ListenSocket);
496 WSACleanup();
497 jtagClosePort();
498 return -2;
499 }
500  
501 printf("\n");
502  
503 do
504 {
505 printf(" Listen\n");
506 jtagSetLED(true);
507  
508 // Accept a client SOCKET
509 sockaddr ClientSocetAddr;
510 int ClientSocetAddrLen = sizeof(sockaddr);
511 ClientSocket = accept(ListenSocket, &ClientSocetAddr, &ClientSocetAddrLen);
512 if (ClientSocket == INVALID_SOCKET)
513 {
2933 miho 514 fprintf(stderr, "accept failed with error: %d\n", WSAGetLastError());
2697 miho 515 closesocket(ListenSocket);
516 WSACleanup();
517 jtagClosePort();
518 return -2;
519 }
520  
521 // Print Accepted + Address
522 printf(" Accepted ");
523 jtagSetLED(false);
524 for (int i=2; i<2+4-1; i++)
525 {
526 printf("%d.", (unsigned char)ClientSocetAddr.sa_data[i]);
527 }
528 printf("%d:%d\n", (unsigned char)ClientSocetAddr.sa_data[2+4-1], (unsigned char)ClientSocetAddr.sa_data[0]*256+(unsigned char)ClientSocetAddr.sa_data[1]);
529  
530 // Process Data until the peer shuts down the connection
531 int Cnt = 0;
532 printf(" Handle Data ");
533 do
534 {
535 iResult = handleData(ClientSocket);
536 if (iResult>=0)
537 {
538 printf(".");
539 Cnt++;
540 if (Cnt>40)
541 {
542 Cnt = 0;
543 printf("\n ");
544 }
545 }
546 }
547 while (iResult >= 0);
548  
549 // Connection Closed by peer
550 if (iResult==-1)
551 {
552 // JTAG port
553 jtagSetIdle();
554 }
555  
556 // Error - shutdown the connection
557 if (iResult==-2)
558 {
559 fprintf(stderr, " Disconnect\n");
560 iResult = shutdown(ClientSocket, SD_SEND);
561 if (iResult == SOCKET_ERROR)
562 {
563 fprintf(stderr, "shutdown failed with error: %d\n", WSAGetLastError());
564 }
565 iResult=-2; // Error
566 }
567  
568 // cleanup
569 closesocket(ClientSocket);
570  
571 }
572 // If not Error Listen Again
573 while (iResult!=-2);
574  
575 // cleanup
576 closesocket(ListenSocket);
577 WSACleanup();
578 jtagClosePort();
579  
580 return 1;
581 }