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