├── .gitignore ├── LICENSE.txt ├── README.txt ├── build.sh ├── ftdi_async_mode ├── build.sh └── stream_test.c ├── fx2pipe ├── .gitignore ├── AUTHORS ├── COPYING ├── ChangeLog ├── INSTALL ├── Makefile.am ├── Makefile.in ├── NEWS ├── README ├── aclocal.m4 ├── build.sh ├── config.h.in ├── configure ├── configure.ac ├── depcomp ├── firmware │ ├── Makefile │ ├── fx2pipe.c │ ├── fx2pipe.ihx │ ├── fx2pipe_static.cc │ └── include │ │ └── fx2regs.h ├── fx2pipe │ ├── Makefile.am │ ├── Makefile.in │ ├── fx2pipe.cc │ ├── fx2pipe.h │ └── main.cc ├── install-sh ├── lib │ ├── Makefile.am │ ├── Makefile.in │ ├── linearqueue.h │ └── linkedlist.h ├── missing ├── oconfig.h └── usb_io │ ├── Makefile.am │ ├── Makefile.in │ ├── cycfx2dev.cc │ ├── cycfx2dev.h │ ├── fx2usb.cc │ ├── fx2usb.h │ ├── urbcache.cc │ ├── urbcache.h │ ├── usbdevice_fs.h │ ├── wwusb.cc │ └── wwusb.h ├── fx2sharp ├── fx2sharp.sln └── fx2sharp │ ├── App.config │ ├── Program.cs │ ├── Properties │ └── AssemblyInfo.cs │ ├── fx2pipe_hoglet.hex │ ├── fx2sharp.csproj │ ├── fx2sharp.csproj.user │ └── packages.config ├── src ├── defs.h ├── em_6502.c ├── em_6502.h ├── em_65816.c ├── em_65816.h ├── em_6800.c ├── em_6800.h ├── main.c ├── matcher.c ├── memory.c ├── memory.h ├── musl_tsearch.c ├── musl_tsearch.h ├── profiler.c ├── profiler.h ├── profiler_block.c ├── profiler_call.c ├── profiler_instr.c ├── symbols.c ├── symbols.h ├── tube_decode.c └── tube_decode.h └── test ├── 816_blitter ├── hog816_emu.data ├── hog816_interrupt.data ├── hog816_native.data └── snes_tests.data ├── beeb └── reset.bin.gz ├── beebr65c02 └── reset.bin.gz ├── clean_tests.sh ├── elk └── reset.bin.gz ├── master └── reset.bin.gz ├── run_816_tests.sh └── run_tests.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | #* 3 | decode6502 4 | matcher 5 | not_in_git/ 6 | *.log 7 | *.bin 8 | *.tmp 9 | clark_bcd_full.bin.gz 10 | dormann_d6502.bin.gz 11 | dormann_d65c00.bin.gz 12 | dormann_d65c01.bin.gz 13 | dormann_d65c10.bin.gz 14 | dormann_d65c11.bin.gz 15 | extended_tests.zip 16 | /.dir-locals.el 17 | decode6502.dSYM/ 18 | test/**/*.ref 19 | test/**/*.dif 20 | fx2sharp/fx2sharp/bin 21 | fx2sharp/fx2sharp/obj 22 | fx2sharp/.vs 23 | fx2sharp/packages 24 | decode6502.exe 25 | src/main.c.bak 26 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | See the github wiki for more details. 2 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | LIBS="-lm" 4 | INCS="" 5 | DEFS="" 6 | 7 | if [[ $OS = *"Windows"* ]]; then 8 | LIBS="$LIBS -largp" 9 | DEFS="-D_GNU_SOURCE" 10 | elif [[ `uname` = Darwin ]]; then 11 | if [ -f /opt/local/include/argp.h ]; then 12 | # MacPorts packages required: argp-standalone 13 | LIBS="$LIBS -L/opt/local/lib -largp" 14 | INCS="$INCS -I/opt/local/include" 15 | 16 | # (MacPorts md5sha1sum required for tests) 17 | else 18 | echo "argp not found - but will try building anyway" 19 | fi 20 | else 21 | DEFS="-D_GNU_SOURCE" 22 | fi 23 | 24 | gcc -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -O3 $DEFS $INCS -o decode6502 src/main.c src/memory.c src/em_6502.c src/em_65816.c src/em_6800.c src/profiler.c src/profiler_instr.c src/profiler_block.c src/profiler_call.c src/tube_decode.c src/musl_tsearch.c src/symbols.c $LIBS 25 | 26 | gcc -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -O3 -o matcher src/matcher.c 27 | -------------------------------------------------------------------------------- /ftdi_async_mode/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | gcc -I /usr/include/libftdi1 -I /usr/include/libusb-1.0/ stream_test.c -o stream_test -lftdi1 -lusb-1.0 3 | -------------------------------------------------------------------------------- /ftdi_async_mode/stream_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | static FILE *outputFile; 13 | 14 | static int exitRequested = 0; 15 | /* 16 | * sigintHandler -- 17 | * 18 | * SIGINT handler, so we can gracefully exit when the user hits ctrl-C. 19 | */ 20 | 21 | static void 22 | sigintHandler(int signum) 23 | { 24 | exitRequested = 1; 25 | } 26 | 27 | static void 28 | usage(const char *argv0) 29 | { 30 | fprintf(stderr, 31 | "Usage: %s [options...] \n" 32 | "Test streaming read from FT2232H\n" 33 | "[-P string] only look for product with given string\n" 34 | "\n" 35 | "If some filename is given, write data read to that file\n" 36 | "Progess information is printed each second\n" 37 | "Abort with ^C\n" 38 | "\n" 39 | "Options:\n" 40 | "\n" 41 | "Copyright (C) 2009 Micah Dowty \n" 42 | "Adapted for use with libftdi (C) 2010 Uwe Bonnes \n", 43 | argv0); 44 | exit(1); 45 | } 46 | 47 | 48 | static int readCallback(uint8_t *buffer, int length, FTDIProgressInfo *progress, void *userdata) 49 | { 50 | if (length) 51 | { 52 | if (outputFile) 53 | { 54 | if (fwrite(buffer, length, 1, outputFile) != 1) 55 | { 56 | perror("Write error"); 57 | return 1; 58 | } 59 | } 60 | } 61 | if (progress) 62 | { 63 | fprintf(stderr, "%10.02fs total time %9.3f MiB captured %7.1f kB/s curr rate %7.1f kB/s totalrate\n", 64 | progress->totalTime, 65 | progress->current.totalBytes / (1024.0 * 1024.0), 66 | progress->currentRate / 1024.0, 67 | progress->totalRate / 1024.0 68 | ); 69 | } 70 | return exitRequested ? 1 : 0; 71 | } 72 | 73 | typedef struct 74 | { 75 | FTDIStreamCallback *callback; 76 | void *userdata; 77 | int packetsize; 78 | int activity; 79 | int result; 80 | FTDIProgressInfo progress; 81 | } FTDIStreamState; 82 | 83 | /* Handle callbacks 84 | * 85 | * With Exit request, free memory and release the transfer 86 | * 87 | * state->result is only set when some error happens 88 | */ 89 | static void 90 | ftdi_readstream_cb(struct libusb_transfer *transfer) 91 | { 92 | FTDIStreamState *state = transfer->user_data; 93 | int packet_size = state->packetsize; 94 | 95 | state->activity++; 96 | if (transfer->status == LIBUSB_TRANSFER_COMPLETED) 97 | { 98 | int i; 99 | uint8_t *ptr = transfer->buffer; 100 | int length = transfer->actual_length; 101 | int numPackets = (length + packet_size - 1) / packet_size; 102 | int res = 0; 103 | 104 | for (i = 0; i < numPackets; i++) 105 | { 106 | int payloadLen; 107 | int packetLen = length; 108 | 109 | if (packetLen > packet_size) 110 | packetLen = packet_size; 111 | 112 | payloadLen = packetLen - 2; 113 | state->progress.current.totalBytes += payloadLen; 114 | 115 | res = state->callback(ptr + 2, payloadLen, 116 | NULL, state->userdata); 117 | 118 | ptr += packetLen; 119 | length -= packetLen; 120 | } 121 | if (res) 122 | { 123 | free(transfer->buffer); 124 | libusb_free_transfer(transfer); 125 | } 126 | else 127 | { 128 | transfer->status = -1; 129 | state->result = libusb_submit_transfer(transfer); 130 | } 131 | } 132 | else 133 | { 134 | fprintf(stderr, "unknown status %d\n",transfer->status); 135 | state->result = LIBUSB_ERROR_IO; 136 | } 137 | } 138 | 139 | /** 140 | Helper function to calculate (unix) time differences 141 | 142 | \param a timeval 143 | \param b timeval 144 | */ 145 | static double 146 | TimevalDiff(const struct timeval *a, const struct timeval *b) 147 | { 148 | return (a->tv_sec - b->tv_sec) + 1e-6 * (a->tv_usec - b->tv_usec); 149 | } 150 | 151 | /** 152 | Streaming reading of data from the device 153 | 154 | Use asynchronous transfers in libusb-1.0 for high-performance 155 | streaming of data from a device interface back to the PC. This 156 | function continuously transfers data until either an error occurs 157 | or the callback returns a nonzero value. This function returns 158 | a libusb error code or the callback's return value. 159 | 160 | For every contiguous block of received data, the callback will 161 | be invoked. 162 | 163 | \param ftdi pointer to ftdi_context 164 | \param callback to user supplied function for one block of data 165 | \param userdata 166 | \param packetsPerTransfer number of packets per transfer 167 | \param numTransfers Number of transfers per callback 168 | 169 | */ 170 | 171 | static int 172 | ftdi_readstream_async(struct ftdi_context *ftdi, 173 | FTDIStreamCallback *callback, void *userdata, 174 | int packetsPerTransfer, int numTransfers) 175 | { 176 | struct libusb_transfer **transfers; 177 | FTDIStreamState state = { callback, userdata, ftdi->max_packet_size, 1 }; 178 | int bufferSize = packetsPerTransfer * ftdi->max_packet_size; 179 | int xferIndex; 180 | int err = 0; 181 | 182 | /* Only FT2232H and FT232H know about the synchronous FIFO Mode*/ 183 | if ((ftdi->type != TYPE_2232H) && (ftdi->type != TYPE_232H)) 184 | { 185 | fprintf(stderr,"Device doesn't support synchronous FIFO mode\n"); 186 | return 1; 187 | } 188 | 189 | /* We don't know in what state we are, switch to reset*/ 190 | if (ftdi_set_bitmode(ftdi, 0xff, BITMODE_RESET) < 0) 191 | { 192 | fprintf(stderr,"Can't reset mode\n"); 193 | return 1; 194 | } 195 | 196 | /* Purge anything remaining in the buffers*/ 197 | if (ftdi_usb_purge_buffers(ftdi) < 0) 198 | { 199 | fprintf(stderr,"Can't Purge\n"); 200 | return 1; 201 | } 202 | 203 | /* 204 | * Set up all transfers 205 | */ 206 | 207 | transfers = calloc(numTransfers, sizeof *transfers); 208 | if (!transfers) { 209 | err = LIBUSB_ERROR_NO_MEM; 210 | goto cleanup; 211 | } 212 | 213 | for (xferIndex = 0; xferIndex < numTransfers; xferIndex++) 214 | { 215 | struct libusb_transfer *transfer; 216 | 217 | transfer = libusb_alloc_transfer(0); 218 | transfers[xferIndex] = transfer; 219 | if (!transfer) { 220 | err = LIBUSB_ERROR_NO_MEM; 221 | goto cleanup; 222 | } 223 | 224 | libusb_fill_bulk_transfer(transfer, ftdi->usb_dev, ftdi->out_ep, 225 | malloc(bufferSize), bufferSize, 226 | ftdi_readstream_cb, 227 | &state, 0); 228 | 229 | if (!transfer->buffer) { 230 | err = LIBUSB_ERROR_NO_MEM; 231 | goto cleanup; 232 | } 233 | 234 | transfer->status = -1; 235 | err = libusb_submit_transfer(transfer); 236 | if (err) 237 | goto cleanup; 238 | } 239 | 240 | /* Start the transfers only when everything has been set up. 241 | * Otherwise the transfers start stuttering and the PC not 242 | * fetching data for several to several ten milliseconds 243 | * and we skip blocks 244 | */ 245 | #if 0 246 | if (ftdi_set_bitmode(ftdi, 0xff, BITMODE_SYNCFF) < 0) 247 | { 248 | fprintf(stderr,"Can't set synch fifo mode: %s\n", 249 | ftdi_get_error_string(ftdi)); 250 | goto cleanup; 251 | } 252 | #endif 253 | 254 | /* 255 | * Run the transfers, and periodically assess progress. 256 | */ 257 | 258 | gettimeofday(&state.progress.first.time, NULL); 259 | 260 | do 261 | { 262 | FTDIProgressInfo *progress = &state.progress; 263 | const double progressInterval = 1.0; 264 | struct timeval timeout = { 0, ftdi->usb_read_timeout }; 265 | struct timeval now; 266 | 267 | int err = libusb_handle_events_timeout(ftdi->usb_ctx, &timeout); 268 | if (err == LIBUSB_ERROR_INTERRUPTED) 269 | /* restart interrupted events */ 270 | err = libusb_handle_events_timeout(ftdi->usb_ctx, &timeout); 271 | if (!state.result) 272 | { 273 | state.result = err; 274 | } 275 | if (state.activity == 0) 276 | state.result = 1; 277 | else 278 | state.activity = 0; 279 | 280 | // If enough time has elapsed, update the progress 281 | gettimeofday(&now, NULL); 282 | if (TimevalDiff(&now, &progress->current.time) >= progressInterval) 283 | { 284 | progress->current.time = now; 285 | progress->totalTime = TimevalDiff(&progress->current.time, 286 | &progress->first.time); 287 | 288 | if (progress->prev.totalBytes) 289 | { 290 | // We have enough information to calculate rates 291 | 292 | double currentTime; 293 | 294 | currentTime = TimevalDiff(&progress->current.time, 295 | &progress->prev.time); 296 | 297 | progress->totalRate = 298 | progress->current.totalBytes /progress->totalTime; 299 | progress->currentRate = 300 | (progress->current.totalBytes - 301 | progress->prev.totalBytes) / currentTime; 302 | } 303 | 304 | state.callback(NULL, 0, progress, state.userdata); 305 | progress->prev = progress->current; 306 | 307 | } 308 | } while (!state.result); 309 | 310 | /* 311 | * Cancel any outstanding transfers, and free memory. 312 | */ 313 | 314 | cleanup: 315 | fprintf(stderr, "cleanup\n"); 316 | if (transfers) 317 | free(transfers); 318 | if (err) 319 | return err; 320 | else 321 | return state.result; 322 | } 323 | 324 | int main(int argc, char **argv) 325 | { 326 | struct ftdi_context *ftdi; 327 | int err, c; 328 | FILE *of = NULL; 329 | char const *outfile = 0; 330 | outputFile =0; 331 | exitRequested = 0; 332 | char *descstring = NULL; 333 | int option_index; 334 | static struct option long_options[] = {{NULL},}; 335 | 336 | while ((c = getopt_long(argc, argv, "P:n", long_options, &option_index)) !=- 1) 337 | switch (c) 338 | { 339 | case -1: 340 | break; 341 | case 'P': 342 | descstring = optarg; 343 | break; 344 | default: 345 | usage(argv[0]); 346 | } 347 | 348 | if (optind == argc - 1) 349 | { 350 | // Exactly one extra argument- a dump file 351 | outfile = argv[optind]; 352 | } 353 | else if (optind < argc) 354 | { 355 | // Too many extra args 356 | usage(argv[0]); 357 | } 358 | 359 | if ((ftdi = ftdi_new()) == 0) 360 | { 361 | fprintf(stderr, "ftdi_new failed\n"); 362 | return EXIT_FAILURE; 363 | } 364 | 365 | if (ftdi_set_interface(ftdi, INTERFACE_A) < 0) 366 | { 367 | fprintf(stderr, "ftdi_set_interface failed\n"); 368 | ftdi_free(ftdi); 369 | return EXIT_FAILURE; 370 | } 371 | 372 | if (ftdi_usb_open_desc(ftdi, 0x0403, 0x6014, descstring, NULL) < 0) 373 | { 374 | fprintf(stderr,"Can't open ftdi device: %s\n",ftdi_get_error_string(ftdi)); 375 | ftdi_free(ftdi); 376 | return EXIT_FAILURE; 377 | } 378 | 379 | /* A timeout value of 1 results in may skipped blocks */ 380 | if(ftdi_set_latency_timer(ftdi, 2)) 381 | { 382 | fprintf(stderr,"Can't set latency, Error %s\n",ftdi_get_error_string(ftdi)); 383 | ftdi_usb_close(ftdi); 384 | ftdi_free(ftdi); 385 | return EXIT_FAILURE; 386 | } 387 | 388 | /* if(ftdi_usb_purge_rx_buffer(ftdi) < 0) 389 | { 390 | fprintf(stderr,"Can't rx purge\n",ftdi_get_error_string(ftdi)); 391 | return EXIT_FAILURE; 392 | }*/ 393 | if (outfile) 394 | if ((of = fopen(outfile,"w+")) == 0) 395 | fprintf(stderr,"Can't open logfile %s, Error %s\n", outfile, strerror(errno)); 396 | if (of) 397 | if (setvbuf(of, NULL, _IOFBF , 1<<16) == 0) 398 | outputFile = of; 399 | signal(SIGINT, sigintHandler); 400 | 401 | err = ftdi_readstream_async(ftdi, readCallback, NULL, 8, 256); 402 | if (err < 0 && !exitRequested) 403 | exit(1); 404 | 405 | if (outputFile) { 406 | fclose(outputFile); 407 | outputFile = NULL; 408 | } 409 | fprintf(stderr, "Capture ended.\n"); 410 | 411 | if (ftdi_set_bitmode(ftdi, 0xff, BITMODE_RESET) < 0) 412 | { 413 | fprintf(stderr,"Can't set synchronous fifo mode, Error %s\n",ftdi_get_error_string(ftdi)); 414 | ftdi_usb_close(ftdi); 415 | ftdi_free(ftdi); 416 | return EXIT_FAILURE; 417 | } 418 | ftdi_usb_close(ftdi); 419 | ftdi_free(ftdi); 420 | signal(SIGINT, SIG_DFL); 421 | exit (0); 422 | } 423 | -------------------------------------------------------------------------------- /fx2pipe/.gitignore: -------------------------------------------------------------------------------- 1 | /Makefile 2 | /config.h 3 | /config.log 4 | /config.status 5 | /firmware/fx2pipe.asm 6 | #/firmware/fx2pipe.ihx 7 | /firmware/fx2pipe.lk 8 | /firmware/fx2pipe.lst 9 | /firmware/fx2pipe.map 10 | /firmware/fx2pipe.mem 11 | /firmware/fx2pipe.rel 12 | /firmware/fx2pipe.rst 13 | /firmware/fx2pipe.sym 14 | #/firmware/fx2pipe_static.cc 15 | /fx2pipe/.deps/ 16 | /fx2pipe/Makefile 17 | /fx2pipe/fx2pipe 18 | /lib/Makefile 19 | /stamp-h1 20 | /usb_io/.deps/ 21 | /usb_io/Makefile 22 | *.o 23 | *.a 24 | -------------------------------------------------------------------------------- /fx2pipe/AUTHORS: -------------------------------------------------------------------------------- 1 | Author: Wolfgang Wieser 2 | -------------------------------------------------------------------------------- /fx2pipe/ChangeLog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoglet67/6502Decoder/6bfa89ae49c9dffafb0a90026fe0fab44ed14b2a/fx2pipe/ChangeLog -------------------------------------------------------------------------------- /fx2pipe/INSTALL: -------------------------------------------------------------------------------- 1 | BUILD INSTRUCTIONS: 2 | 3 | Usual configure && make voodoo. 4 | 5 | The firmware is not built by "make" since this requires special tools. 6 | Instead source code and pre-compiled binaries are distributed. 7 | To build the firmware, run "make" in firmware. 8 | 9 | Volunteers welcome for any type of improvement! 10 | 11 | -------------------------------------------------------------------------------- /fx2pipe/Makefile.am: -------------------------------------------------------------------------------- 1 | #CFLAGS = @CFLAGS@ -W -Wall -D_GNU_SOURCE 2 | #CXXFLAGS = @CXXFLAGS@ -W -Wall -D_GNU_SOURCE 3 | 4 | OPTCXXFLAGS = -W -Wall -Wformat -Woverloaded-virtual \ 5 | -O2 -march=i586 -fno-rtti -fno-exceptions -fomit-frame-pointer \ 6 | -D_GNU_SOURCE 7 | OPTCFLAGS = -W -Wall -Wformat \ 8 | -O2 -march=i586 -fomit-frame-pointer \ 9 | -D_GNU_SOURCE 10 | 11 | # Pass ADDFLAGS if you want to set -fmessage-length or the like. 12 | ADDFLAGS="" 13 | 14 | SUBDIRS = lib usb_io fx2pipe 15 | 16 | EXTRA_DIST = oconfig.h firmware 17 | 18 | 19 | opt: FORCE 20 | $(MAKE) CFLAGS="$(OPTCFLAGS) $(ADDFLAGS)" CXXFLAGS="$(OPTCXXFLAGS) $(ADDFLAGS)" all 21 | 22 | checkopt: FORCE 23 | $(MAKE) CFLAGS="$(OPTCFLAGS) $(ADDFLAGS)" CXXFLAGS="$(OPTCXXFLAGS) $(ADDFLAGS)" check 24 | 25 | FORCE: 26 | -------------------------------------------------------------------------------- /fx2pipe/NEWS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoglet67/6502Decoder/6bfa89ae49c9dffafb0a90026fe0fab44ed14b2a/fx2pipe/NEWS -------------------------------------------------------------------------------- /fx2pipe/README: -------------------------------------------------------------------------------- 1 | This is a relatively simple USB high speed input or output pipe 2 | program. 3 | 4 | It either reads data from stdin and sends it over the USB or 5 | reads data from the USB and sends it to stdout. 6 | Works with Cypress FX2 chip, hence the name fx2pipe. 7 | 8 | For build instructions, please see INSTALL. 9 | 10 | Wolfgang 11 | -------------------------------------------------------------------------------- /fx2pipe/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd firmware 4 | make clobber 5 | make 6 | cd .. 7 | 8 | ./configure 9 | make clean 10 | make 11 | -------------------------------------------------------------------------------- /fx2pipe/config.h.in: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* Define to 1 if you have the header file. */ 4 | #undef HAVE_INTTYPES_H 5 | 6 | /* Define to 1 if you have the header file. */ 7 | #undef HAVE_MEMORY_H 8 | 9 | /* Define to 1 if you have the header file. */ 10 | #undef HAVE_STDINT_H 11 | 12 | /* Define to 1 if you have the header file. */ 13 | #undef HAVE_STDLIB_H 14 | 15 | /* Define to 1 if you have the header file. */ 16 | #undef HAVE_STRINGS_H 17 | 18 | /* Define to 1 if you have the header file. */ 19 | #undef HAVE_STRING_H 20 | 21 | /* Define to 1 if you have the header file. */ 22 | #undef HAVE_SYS_STAT_H 23 | 24 | /* Define to 1 if you have the header file. */ 25 | #undef HAVE_SYS_TYPES_H 26 | 27 | /* Define to 1 if you have the header file. */ 28 | #undef HAVE_UNISTD_H 29 | 30 | /* Name of package */ 31 | #undef PACKAGE 32 | 33 | /* Define to the address where bug reports for this package should be sent. */ 34 | #undef PACKAGE_BUGREPORT 35 | 36 | /* Define to the full name of this package. */ 37 | #undef PACKAGE_NAME 38 | 39 | /* Define to the full name and version of this package. */ 40 | #undef PACKAGE_STRING 41 | 42 | /* Define to the one symbol short name of this package. */ 43 | #undef PACKAGE_TARNAME 44 | 45 | /* Define to the home page for this package. */ 46 | #undef PACKAGE_URL 47 | 48 | /* Define to the version of this package. */ 49 | #undef PACKAGE_VERSION 50 | 51 | /* Define to 1 if you have the ANSI C header files. */ 52 | #undef STDC_HEADERS 53 | 54 | /* Version number of package */ 55 | #undef VERSION 56 | 57 | /* Define to empty if `const' does not conform to ANSI C. */ 58 | #undef const 59 | 60 | /* Define to `__inline__' or `__inline' if that's what the C compiler 61 | calls it, or to nothing if 'inline' is not supported under any name. */ 62 | #ifndef __cplusplus 63 | #undef inline 64 | #endif 65 | 66 | /* Define to `unsigned int' if does not define. */ 67 | #undef size_t 68 | 69 | /* Define to `int' if does not define. */ 70 | #undef ssize_t 71 | -------------------------------------------------------------------------------- /fx2pipe/configure.ac: -------------------------------------------------------------------------------- 1 | # Process this file with autoconf to produce a configure script. 2 | AC_INIT 3 | AM_INIT_AUTOMAKE(fx2pipe,0.8) 4 | AC_CONFIG_SRCDIR([fx2pipe/fx2pipe.cc]) 5 | AM_CONFIG_HEADER(config.h) 6 | 7 | # Checks for programs. 8 | AC_PROG_CC 9 | AC_PROG_CPP 10 | AC_PROG_INSTALL 11 | AC_PROG_CXX 12 | AC_PROG_RANLIB 13 | 14 | # Checks for header files. 15 | AC_HEADER_STDC 16 | 17 | # Checks for typedefs, structures, and compiler characteristics. 18 | AC_C_CONST 19 | AC_C_INLINE 20 | AC_TYPE_SIZE_T 21 | AC_CHECK_TYPE(ssize_t,int) 22 | 23 | # Checks for library functions. 24 | AC_FUNC_ERROR_AT_LINE 25 | AC_PROG_GCC_TRADITIONAL 26 | #AC_FUNC_MALLOC 27 | 28 | AC_CONFIG_FILES([Makefile 29 | lib/Makefile 30 | usb_io/Makefile 31 | fx2pipe/Makefile ]) 32 | AC_OUTPUT 33 | -------------------------------------------------------------------------------- /fx2pipe/firmware/Makefile: -------------------------------------------------------------------------------- 1 | INCLUDES=-Iinclude 2 | 3 | CC=sdcc -mmcs51 4 | 5 | SHELL=bash 6 | 7 | fx2pipe_static.cc: fx2pipe.ihx 8 | @echo "#include /* For NULL... */" > fx2pipe_static.cc 9 | @echo >> fx2pipe_static.cc 10 | @echo "const char *fx2pipe_static_firmware[]={" >> fx2pipe_static.cc 11 | @bash -c 'while read line ; do echo -e "\t\"$$line\"," >> fx2pipe_static.cc ; done < fx2pipe.ihx' 12 | @echo -e "\tNULL" >> fx2pipe_static.cc 13 | @echo "};" >> fx2pipe_static.cc 14 | @echo "Created fx2pipe_static.cc" 15 | 16 | fx2pipe.ihx: fx2pipe.c 17 | $(CC) $(INCLUDES) fx2pipe.c 18 | ls -l fx2pipe.ihx 19 | 20 | clean: 21 | rm -f fx2pipe.{asm,ihx,lnk,lst,map,mem,rel,rst,sym} 22 | 23 | clobber: clean 24 | rm -f fx2pipe_static.cc 25 | -------------------------------------------------------------------------------- /fx2pipe/firmware/fx2pipe.c: -------------------------------------------------------------------------------- 1 | /* 2 | * firmware/fx2pipe.c 3 | * 4 | * FX2 pipe IO firmware. 5 | * 6 | * Copyright (c) 2006--2009 by Wolfgang Wieser ] wwieser (a) gmx <*> de [ 7 | * 8 | * This file may be distributed and/or modified under the terms of the 9 | * GNU General Public License version 2 as published by the Free Software 10 | * Foundation. (See COPYING.GPL for details.) 11 | * 12 | * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 13 | * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 14 | * 15 | */ 16 | 17 | // Compile with sdcc! 18 | 19 | // Uncomment this to enable debug output at 9600 baud on PA0 20 | // #define SERIAL_DEBUG 21 | 22 | #define BAUD 9600 23 | 24 | #define ALLOCATE_EXTERN 25 | #include 26 | 27 | typedef unsigned char uint8; 28 | typedef unsigned int uint16; // int is 16 bit. 29 | 30 | // TRM states: (p.15-115) 31 | // 32 | // The minimum delay length is a function of the IFCLK and CLKOUT 33 | // (CPU Clock) frequencies, and is determined by the equation: 34 | // 35 | // MinNumberOfCPUCycles = ceil( 1.5 * ( ifclk_period / clkout_period + 1) ); 36 | // 37 | // The required delay length is smallest when the CPU is running at its 38 | // slowest speed (12 MHz, 83.2ns/cycle) and IFCLK is running at its fastest 39 | // speed (48 MHz, 20.8 ns/cycle) --> 2 cycles. 40 | // 41 | // The longest delay is required when the CPU is running at its fastest 42 | // speed (48MHz, 20.8 ns/cycle) and IFCLK is running much slower 43 | // (e.g., 5.2 MHz, 192 ns/cycle) --> 16 cycles 44 | // 45 | // The most-typical EZ-USB configuration, IFCLK and CLKOUT both running at 46 | // 48 MHz, requires a minimum delay of 3 cycles. 47 | // 48 | // Hmm, but experimental results seem to contradict the above calculation. 49 | // E.g. with a 48MHz clock, 17 NOPs require more than 7MHz to work sometimes 50 | // and 10MHz to work reliably while we'd expect 5.2MHz to be more than 51 | // enough... (Wolfgang) 52 | #define NOP __asm nop __endasm 53 | #define SYNCDELAY \ 54 | NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; \ 55 | NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; \ 56 | NOP 57 | 58 | 59 | #ifdef SERIAL_DEBUG 60 | 61 | #define BAUD_TICKS (4000000/BAUD) 62 | 63 | static void debug_putc(int c) 64 | { 65 | int i; 66 | int senddata = (c << 1) | 0x200; 67 | OEA |= 0x01; 68 | for (i = 0; i < 10; i++) { 69 | TH1 = (65536 - BAUD_TICKS) / 256; 70 | TL1 = (65536 - BAUD_TICKS) % 256; 71 | IOA = (IOA & 0xFE) | (senddata & 1); 72 | senddata >>= 1; 73 | while (TH1 > 128); 74 | } 75 | } 76 | 77 | static void debug_puthex1(int i) 78 | { 79 | i &= 0xf; 80 | debug_putc(i + (i < 10 ? '0' : 'A' - 10)); 81 | } 82 | 83 | 84 | static void debug_puthex2(int i) 85 | { 86 | debug_puthex1(i >> 4); 87 | debug_puthex1(i); 88 | } 89 | 90 | static void debug_puts(char *s) 91 | { 92 | while (*s) { 93 | debug_putc(*s); 94 | s++; 95 | } 96 | } 97 | 98 | static void debug_init() { 99 | CPUCS = 0x12; // Clock the 8051 at 48MHz 100 | TMOD = 0x10; // Run T1 at 48MHz / 12 = 4MHz 101 | TCON |= 0x40; // Start T1 102 | } 103 | 104 | #else 105 | 106 | #define debug_put(...) 107 | #define debug_puts(...) 108 | #define debug_init(...) 109 | 110 | #endif 111 | 112 | // Initialize the FX2 in 16bit sync fifo mode. 113 | static void Initialize(void) 114 | { 115 | // Config is put at address 0x3000 by fx2pipe program at firmware 116 | // download. 117 | // NOTE: This is for FX2LP; the FX2 has fewer SRAM and so we cannot use 118 | // 0x3000 but rather 0x1000 or so. 119 | // Now we use 0x1000 to support both devices. 120 | __xdata char *cfg_data=(__xdata char*)0x1003; 121 | // First cfg_data must be 21 or 12 to be considered valid. 122 | char cfg_data_ok = (cfg_data[0]==0x12U || cfg_data[0]==0x21U); 123 | 124 | SYNCDELAY; 125 | 126 | // CPUCS: 0 0 PORTCSTB CLKSPD1 CLKSPD0 CLKINV CLKOE 8051RES 00000010 127 | // PORTCSTB=1: reads/writes to PORTC generate RD# and WR# strobes 128 | // CLKSPD1,0 = 8051 clock speed: 00=12, 01=24, 10=48, 11=X 129 | // CLKINV=1 to invert CLKOUT signal 130 | // CLKOE=1 to drive CLKOUT pin 131 | // 8051RES=1 to reset 8051 132 | // Want: 0001 0010 <-- 48MHz, output enabled. 133 | // 0000 0010 <-- 12MHz, output enabled. 134 | CPUCS = cfg_data_ok ? cfg_data[4] : 0x12; // 0x12 135 | SYNCDELAY; 136 | 137 | // a = 10; b = 11; c = 12; d = 13; e = 14; f = 15 138 | 139 | // Okay, the most important config register: (default: 10000000) 140 | // bit7: 1 = internal clocking of IFCLK; 0 = external 141 | // bit6: 0 = 30MHz; 1 = 48MHz 142 | // bit5: 1 = enable output to IFCLK 143 | // bit4: 1 = invert IFCLK 144 | // bit3: 1 = async mode; 0 = sync 145 | // bit2: 1 = drive GSTATE[0:2] on PORTE[0:2] (irrelevant for 56-pin package) 146 | // bit1,0: 00: ports; 01: reserved; 10: GPIF; 11: Slave FIFO (ext master), 147 | //IFCONFIG = 0x43; // 0100 0011 = 0x43 externally clocked sync mode 148 | //IFCONFIG = 0xcb; // 1100 1011 = 0xcb internally clocked async mode 149 | //IFCONFIG = 0xc3; // 1100 0011 = 0xc3 internally clocked sync mode (perf test) 150 | IFCONFIG = cfg_data_ok ? cfg_data[1] : 0xc3; 151 | SYNCDELAY; 152 | 153 | // Based on TRM and SSRP. 154 | REVCTL = 0x03; // See TRM... 155 | SYNCDELAY; 156 | 157 | // PORTACFG: FLAGD SLCS(*) 0 0 0 0 INT1 INT0 158 | PORTACFG = 0x00; 159 | SYNCDELAY; // maybe not needed 160 | 161 | // All default polarities: except SLWR,... 162 | if (cfg_data[1] & 0x10) { 163 | // SLWR active low, use the rising edge as the sample clock 164 | FIFOPINPOLAR=0x00; 165 | // this is selected if -ifclk=i is specified 166 | } else { 167 | // SLWR active high, use the falling edge as the sample clock 168 | // this is the default, and works forthe 6502 169 | FIFOPINPOLAR=0x04; 170 | } 171 | SYNCDELAY; 172 | 173 | // Reset... 174 | EP6CFG=0x00U; SYNCDELAY; 175 | EP2CFG=0x00U; SYNCDELAY; 176 | EP6FIFOCFG=0x00U; SYNCDELAY; 177 | EP2FIFOCFG=0x00U; SYNCDELAY; 178 | OEA=0x00U; 179 | 180 | if(cfg_data[0]==0x12U) /* INPUT: USB->HOST */ 181 | { 182 | // Configure EP6 (IN): 183 | // EP6CFG: 184 | // 1 bit7: VALID: 1 = enable 185 | // 1 bit6: DIR: 1 = in; 0 = out 186 | // 10 bit5,4: TYPE1,0: 00 = ivalid; 01=isochronous; 10=bulk; 11=interrupt 187 | // 0 bit3: SIZE: 0 = 512 bytes; 1 = 1024 bytes 188 | // 0 bit2: 0 189 | // 10 bit1,0: BUF1,0: 00=quad; 01=; 10=double; 11=triple 190 | // Want: 1110 0010 (enabled, IN, BULK, double-buffered 512 bytes) 191 | EP6CFG = cfg_data[2]; // bulk: 0xe2 double-buffered; 0xe3 triple-; 0xe0 quad 192 | SYNCDELAY; 193 | 194 | // To be sure, clear and reset all FIFOs although 195 | // this is probably not strictly required. 196 | FIFORESET = 0x80; SYNCDELAY; // NAK all requests from host. 197 | FIFORESET = 0x02; SYNCDELAY; // Reset individual EP (2,4,6,8) 198 | FIFORESET = 0x04; SYNCDELAY; 199 | FIFORESET = 0x06; SYNCDELAY; 200 | FIFORESET = 0x08; SYNCDELAY; 201 | FIFORESET = 0x00; SYNCDELAY; // Resume normal operation. 202 | 203 | // EP6FIFOCFG: 204 | // bit7: 0 205 | // bit6: INFM6 See TRM 15-29 (p.351): Signal line one clock earlier. 206 | // bit5: OEP6 207 | // bit4: AUTOOUT 1 = enable 208 | // bit3: AUTOIN 1 = enable 209 | // bit2: ZEROLENIN 1 = enable (?) 210 | // bit1: 0 211 | // bit0: WORDWIDE 1 = 16bit (default) 212 | // Want: 0000 1101 -> 0x0d 213 | EP6FIFOCFG = cfg_data[3]; /*0x0d //&0xfe*/; 214 | SYNCDELAY; 215 | 216 | // This determines how much data is accumulated in the FIFOs before a 217 | // USB packet is committed. Use 512 bytes. 218 | // Not sure if we need the sync delays (WW). 219 | EP6AUTOINLENH = 0x02; // MSB 220 | SYNCDELAY; 221 | EP6AUTOINLENL = 0x00; // LSB 222 | SYNCDELAY; 223 | 224 | // SPECIAL VOODOO: Set the IO pins on port A: 225 | // 7, PKTEND, FIFOADR1, FIFOADR0, 3, SLOE, 1, 0 226 | // Z 1 1 0 Z 1 Z Z 227 | //OEA=0x74U; // 0111 0100 228 | //IOA=0x64U; // 0110 0100 229 | } 230 | else if(cfg_data[0]==0x21U) /* OUTPUT: HOST->USB */ 231 | { 232 | // Configure EP2 (OUT): 233 | // EP2CFG: 234 | // 1 bit7: VALID: 1 = enable 235 | // 0 bit6: DIR: 1 = in; 0 = out 236 | // 10 bit5,4: TYPE1,0: 00 = ivalid; 01=isochronous; 10=bulk; 11=interrupt 237 | // 0 bit3: SIZE: 0 = 512 bytes; 1 = 1024 bytes 238 | // 0 bit2: 0 239 | // 10 bit1,0: BUF1,0: 00=quad; 01=; 10=double; 11=triple 240 | // Want: 1010 0010 (enabled, OUT, BULK, double-buffered 512 bytes) 241 | EP2CFG = cfg_data[2]; // bulk: 0xa2 double-buffered; 0xa3 triple-; 0xa0 quad 242 | SYNCDELAY; 243 | 244 | // To be sure, clear and reset all FIFOs although 245 | // this is probably not strictly required. 246 | FIFORESET = 0x80; SYNCDELAY; // NAK all requests from host. 247 | FIFORESET = 0x82; SYNCDELAY; // Reset individual EP (2,4,6,8) 248 | FIFORESET = 0x84; SYNCDELAY; 249 | FIFORESET = 0x86; SYNCDELAY; 250 | FIFORESET = 0x88; SYNCDELAY; 251 | FIFORESET = 0x00; SYNCDELAY; // Resume normal operation. 252 | 253 | // Arm ouput endpoint TRM p.348 ("prime the pump"): 254 | OUTPKTEND = 0x82; SYNCDELAY; 255 | OUTPKTEND = 0x82; SYNCDELAY; 256 | switch(cfg_data[2]&0x03U) 257 | { // Fall-through switch! 258 | case 0x00U: OUTPKTEND = 0x82; SYNCDELAY; // Quad-buffered. 259 | case 0x03U: OUTPKTEND = 0x82; SYNCDELAY; // Triple-buffered. 260 | } 261 | 262 | // EP2FIFOCFG: 263 | // bit7: 0 264 | // bit6: INFM2 See TRM 15-29 (p.351): Signal line one clock earlier. 265 | // bit5: OEP2 266 | // bit4: AUTOOUT 1 = enable 267 | // bit3: AUTOIN 1 = enable 268 | // bit2: ZEROLENIN 1 = enable (?) 269 | // bit1: 0 270 | // bit0: WORDWIDE 1 = 16bit (default) 271 | // Want: 0001 0001 -> 0x15 272 | EP2FIFOCFG = cfg_data[3]; /*0x11;*/ 273 | SYNCDELAY; 274 | 275 | // SPECIAL VOODOO: Set the IO pins on port A: 276 | // 7, PKTEND, FIFOADR1, FIFOADR0, 3, SLOE, 1, 0 277 | // Z 1 0 0 Z 0 Z Z 278 | //OEA=0x74U; // 0111 0100 279 | //IOA=0x50U; // 0100 0000 280 | } 281 | } 282 | 283 | 284 | void main() 285 | { 286 | 287 | #ifdef SERIAL_DEBUG 288 | int i; 289 | __xdata char *cfg_data=(__xdata char*)0x1003; 290 | debug_init(); 291 | debug_puts("Booted cfg="); 292 | for (i = 0; i< 5; i++) { 293 | debug_puthex2(cfg_data[i]); 294 | debug_putc(' '); 295 | } 296 | debug_puts("\r\n"); 297 | #endif 298 | Initialize(); 299 | #ifdef SERIAL_DEBUG 300 | debug_puts("Looping\r\n"); 301 | #endif 302 | for(;;) { 303 | // Do nothing. 304 | #ifdef SERIAL_DEBUG 305 | debug_puts("ep2468stat="); 306 | debug_puthex2(EP2468STAT); 307 | debug_puts("\r\n"); 308 | #endif 309 | 310 | } 311 | } 312 | -------------------------------------------------------------------------------- /fx2pipe/firmware/fx2pipe.ihx: -------------------------------------------------------------------------------- 1 | :03000000020006F5 2 | :03005F0002000399 3 | :030003000203C332 4 | :20006200901003E0FE3395E0FFBE1205BF0002800CBE2105BF000280047F0080027F01008A 5 | :2000820000000000000000000000000000000000EF6007901007E0FE80027E1290E600EE0D 6 | :2000A200F00000000000000000000000000000000000EF6007901004E0FF80027FC390E63B 7 | :2000C20001EFF0000000000000000000000000000000000090E60B7403F000000000000056 8 | :2000E200000000000000000000000090E670E4F00000000000000000000000000000000044 9 | :2001020000901004E0FF30E40790E609E4F0800690E6097404F0000000000000000000007F 10 | :200122000000000000000090E614E4F0000000000000000000000000000000000090E612D7 11 | :20014200E4F0000000000000000000000000000000000090E61AE4F0000000000000000065 12 | :2001620000000000000000000090E618E4F0000000000000000000000000000000000075A6 13 | :20018200B200901003E0FE3395E0FFBE1205BF00028003020283901005E0FD90E614F000E7 14 | :2001A2000000000000000000000000000000000090E6047480F000000000000000000000DF 15 | :2001C2000000000000000090E6047402F0000000000000000000000000000000000090E6C7 16 | :2001E200047404F0000000000000000000000000000000000090E6047406F00000000000AD 17 | :2002020000000000000000000000000090E6047408F00000000000000000000000000000F6 18 | :2002220000000090E604E4F00000000000000000000000000000000000901006E0FD90E675 19 | :200242001AF0000000000000000000000000000000000090E6247402F00000000000000092 20 | :200262000000000000000000000090E625E4F000000000000000000000000000000000000D 21 | :2002820022BE2105BF0002800122901005E0FF90E612F000000000000000000000000000F6 22 | :2002A2000000000090E6047480F0000000000000000000000000000000000090E60474826E 23 | :2002C200F0000000000000000000000000000000000090E6047484F00000000000000000CA 24 | :2002E20000000000000000000090E6047486F0000000000000000000000000000000000098 25 | :2003020090E6047488F0000000000000000000000000000000000090E604E4F00000000027 26 | :200322000000000000000000000000000090E6497482F00000000000000000000000000016 27 | :200342000000000090E6497482F00000000000000000000000000000000000901005E0FF72 28 | :200362003395E05307037E00BF0005BE00028008BF0333BE0030801790E6497482F00000CD 29 | :2003820000000000000000000000000000000090E6497482F00000000000000000000000B6 30 | :2003A200000000000000901006E0FF90E618F0000000000000000000000000000000000038 31 | :0603C2002212006280FE21 32 | :06003500E478FFF6D8FD9F 33 | :200013007900E94400601B7A009003CC780175A000E493F2A308B8000205A0D9F4DAF275C4 34 | :02003300A0FF2C 35 | :20003B007800E84400600A790175A000E4F309D8FC7800E84400600C7900900001E4F0A3C3 36 | :04005B00D8FCD9FAFA 37 | :0D0006007581071203C8E582600302000344 38 | :0403C8007582002218 39 | :00000001FF 40 | -------------------------------------------------------------------------------- /fx2pipe/firmware/fx2pipe_static.cc: -------------------------------------------------------------------------------- 1 | #include /* For NULL... */ 2 | 3 | const char *fx2pipe_static_firmware[]={ 4 | ":03000000020006F5", 5 | ":03005F0002000399", 6 | ":030003000203C332", 7 | ":20006200901003E0FE3395E0FFBE1205BF0002800CBE2105BF000280047F0080027F01008A", 8 | ":2000820000000000000000000000000000000000EF6007901007E0FE80027E1290E600EE0D", 9 | ":2000A200F00000000000000000000000000000000000EF6007901004E0FF80027FC390E63B", 10 | ":2000C20001EFF0000000000000000000000000000000000090E60B7403F000000000000056", 11 | ":2000E200000000000000000000000090E670E4F00000000000000000000000000000000044", 12 | ":2001020000901004E0FF30E40790E609E4F0800690E6097404F0000000000000000000007F", 13 | ":200122000000000000000090E614E4F0000000000000000000000000000000000090E612D7", 14 | ":20014200E4F0000000000000000000000000000000000090E61AE4F0000000000000000065", 15 | ":2001620000000000000000000090E618E4F0000000000000000000000000000000000075A6", 16 | ":20018200B200901003E0FE3395E0FFBE1205BF00028003020283901005E0FD90E614F000E7", 17 | ":2001A2000000000000000000000000000000000090E6047480F000000000000000000000DF", 18 | ":2001C2000000000000000090E6047402F0000000000000000000000000000000000090E6C7", 19 | ":2001E200047404F0000000000000000000000000000000000090E6047406F00000000000AD", 20 | ":2002020000000000000000000000000090E6047408F00000000000000000000000000000F6", 21 | ":2002220000000090E604E4F00000000000000000000000000000000000901006E0FD90E675", 22 | ":200242001AF0000000000000000000000000000000000090E6247402F00000000000000092", 23 | ":200262000000000000000000000090E625E4F000000000000000000000000000000000000D", 24 | ":2002820022BE2105BF0002800122901005E0FF90E612F000000000000000000000000000F6", 25 | ":2002A2000000000090E6047480F0000000000000000000000000000000000090E60474826E", 26 | ":2002C200F0000000000000000000000000000000000090E6047484F00000000000000000CA", 27 | ":2002E20000000000000000000090E6047486F0000000000000000000000000000000000098", 28 | ":2003020090E6047488F0000000000000000000000000000000000090E604E4F00000000027", 29 | ":200322000000000000000000000000000090E6497482F00000000000000000000000000016", 30 | ":200342000000000090E6497482F00000000000000000000000000000000000901005E0FF72", 31 | ":200362003395E05307037E00BF0005BE00028008BF0333BE0030801790E6497482F00000CD", 32 | ":2003820000000000000000000000000000000090E6497482F00000000000000000000000B6", 33 | ":2003A200000000000000901006E0FF90E618F0000000000000000000000000000000000038", 34 | ":0603C2002212006280FE21", 35 | ":06003500E478FFF6D8FD9F", 36 | ":200013007900E94400601B7A009003CC780175A000E493F2A308B8000205A0D9F4DAF275C4", 37 | ":02003300A0FF2C", 38 | ":20003B007800E84400600A790175A000E4F309D8FC7800E84400600C7900900001E4F0A3C3", 39 | ":04005B00D8FCD9FAFA", 40 | ":0D0006007581071203C8E582600302000344", 41 | ":0403C8007582002218", 42 | ":00000001FF", 43 | NULL 44 | }; 45 | -------------------------------------------------------------------------------- /fx2pipe/fx2pipe/Makefile.am: -------------------------------------------------------------------------------- 1 | INCLUDES = -I. -I$(top_srcdir) -I$(top_builddir) 2 | 3 | bin_PROGRAMS = fx2pipe 4 | fx2pipe_SOURCES = main.cc \ 5 | fx2pipe.h fx2pipe.cc \ 6 | ../firmware/fx2pipe_static.cc 7 | fx2pipe_LDADD = ../usb_io/lib_usb_io.a ../lib/lib_fx2pipe_supp.a -lusb 8 | 9 | # fx2pipe_LDADD = $(QTLIBS) -L/usr/X11R6/lib -lX11 -lXft 10 | -------------------------------------------------------------------------------- /fx2pipe/fx2pipe/fx2pipe.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * usb_io/fx2pipe.cc 3 | * 4 | * Cypress FX2 pipe IO main class. 5 | * 6 | * Copyright (c) 2006 by Wolfgang Wieser ] wwieser (a) gmx <*> de [ 7 | * 8 | * This file may be distributed and/or modified under the terms of the 9 | * GNU General Public License version 2 as published by the Free Software 10 | * Foundation. (See COPYING.GPL for details.) 11 | * 12 | * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 13 | * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 14 | * 15 | */ 16 | 17 | #include "../fx2pipe/fx2pipe.h" 18 | //#include "../lib/databuffer.h" 19 | 20 | #include 21 | #include 22 | #include 23 | //#include 24 | //#include 25 | //#include 26 | 27 | #include 28 | 29 | 30 | // Initialize static data: 31 | URBCache FX2Pipe::MyURB::urb_cache(/*max_elem=*/256, 32 | /*elem_size=*/sizeof(FX2Pipe::MyURB)); 33 | 34 | 35 | int FX2Pipe::_ConnectAndInitUSB() 36 | { 37 | // Be sure: 38 | _CleanupUSB(); 39 | 40 | // Connect and init USB device. 41 | // FIXME: Support bus/device. 42 | FX2USBDevice::ErrorCode ec=FX2USBDevice::connect( 43 | /*initial_vendor=*/search_vid,/*initial_product=*/search_pid, 44 | /*n_th=*/n_th_usb_dev, 45 | /*firmware_path=*/firmware_hex_path, 46 | /*firmware_buf=*/fx2pipe_static_firmware, 47 | (const char*)&fc,sizeof(FirwareConfig),FirmwareConfigAdr); 48 | if(ec) 49 | { 50 | fprintf(stderr,"FX2 initialisation failure (ec=%d)\n",ec); 51 | return(1); 52 | } 53 | 54 | const int rx_interface=0; 55 | const int rx_altinterface=1; // alt interface: 1: bulk, 2: interrupt (?), see TRM 56 | 57 | ec=FX2USBDevice::claim(rx_interface,rx_altinterface); 58 | if(ec) 59 | { 60 | fprintf(stderr,"Failed to claim interface %d,%d: ec=%d\n", 61 | rx_interface,rx_altinterface,ec); 62 | return(2); 63 | } 64 | 65 | return(0); 66 | } 67 | 68 | 69 | void FX2Pipe::_CleanupUSB() 70 | { 71 | // NOTE: This function must be safe to be called several times 72 | // even when the USB is already shut down. 73 | FX2USBDevice::disconnect(); 74 | FX2Pipe::MyURB::urb_cache.clear(); 75 | } 76 | 77 | 78 | int FX2Pipe::_SubmitOneURB() 79 | { 80 | if(stdio_eof) 81 | { return(0); } 82 | 83 | size_t iobs=io_block_size; 84 | if(transfer_limit>=0 && transfer_limit-submitted_bytes=submitted_bytes); 87 | iobs=transfer_limit-submitted_bytes; 88 | 89 | stdio_eof=2; 90 | } 91 | 92 | if(!iobs) 93 | { return(0); } 94 | 95 | MyURB *u = new MyURB(dir<0 ? 0x86U/*EP6 IN*/ : 0x02U/*EP2 OUT*/); 96 | // FIXME: In the OUT case we don't need to allocate buffers all the time 97 | // since the content is copied by the kernel upon submission time. 98 | // FIXME: This means we don't need to zero out the buffer each time if 99 | // no_stdio is set. 100 | u->AllocBuffer(iobs); 101 | 102 | if(dir>0) // Write out to USB. 103 | { 104 | if(no_stdio) 105 | { 106 | u->actual_length=u->buffer_length; 107 | memset(u->buffer,0,u->actual_length); 108 | 109 | //slurped_bytes+=u->buffer_length; 110 | } 111 | else 112 | { 113 | char *raw_buf=(char*)u->buffer; 114 | size_t raw_size=u->buffer_length; 115 | u->actual_length=0; 116 | while(raw_size && !caught_sigint) 117 | { 118 | ssize_t rd=read(0,raw_buf,raw_size); 119 | if(rd>0) 120 | { 121 | assert(size_t(rd)<=raw_size); 122 | raw_size-=rd; 123 | raw_buf+=rd; 124 | u->actual_length+=rd; 125 | //slurped_bytes+=rd; 126 | } 127 | else if(rd<0) 128 | { 129 | if(errno==EINTR) continue; 130 | if(errno==EAGAIN) continue; // <-- SHOULD NOT HAPPEN! 131 | fprintf(stderr,"fx2pipe: read error: %s\n", 132 | strerror(errno)); 133 | ++x_errors; 134 | 135 | delete u; 136 | return(1); 137 | } 138 | else if(!rd) 139 | { 140 | //fprintf(stderr,"fx2pipe: EOF on stdin\n"); 141 | stdio_eof=1; 142 | break; 143 | } 144 | } 145 | // This is to be sure that the kernel uses the correct size. 146 | // And we as well further down... 147 | u->buffer_length=u->actual_length; 148 | } 149 | } 150 | 151 | if(u->buffer_length) 152 | { 153 | ErrorCode ec=SubmitURB(u); 154 | if(ec) 155 | { 156 | // This is a problem because we hereby lose one in the pipeline. 157 | // Let's see if this turns out to be a problem. 158 | fprintf(stderr,"OOPS: URB submission failed (ec=%d)\n",ec); 159 | return(1); 160 | } 161 | 162 | submitted_bytes+=u->buffer_length; 163 | } 164 | else 165 | { delete u; } 166 | 167 | return(0); 168 | } 169 | 170 | 171 | int FX2Pipe::_SubmitInitialURBs() 172 | { 173 | if(!udh) return(2); 174 | 175 | // We submit some URBs with specified iobs. 176 | 177 | fprintf(stderr,"Submitting max. %d URBs to fill pipeline... ", 178 | pipeline_size); 179 | 180 | gettimeofday(&starttime,NULL); 181 | last_update_time=starttime; 182 | 183 | for(int i=0; iprev; 202 | 203 | ErrorCode ec=CancelURB(u); 204 | // We get errno=EINVAL when cancelling an URB which is already 205 | // completed but not yet reaped. Ignore that. 206 | if(ec && ec!=EINVAL) 207 | { fprintf(stderr,"Failed to cancel (data) URB: ec=%d (%s)\n", 208 | ec,strerror(ec)); } 209 | } 210 | } 211 | 212 | 213 | void FX2Pipe::_DisplayTransferStatistics(const timeval *endtime,int final) 214 | { 215 | long long msec = 216 | 1000LL*(endtime->tv_sec-starttime.tv_sec) + 217 | (endtime->tv_usec-starttime.tv_usec+500)/1000; 218 | fprintf(stderr, 219 | "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" 220 | "fx2pipe: %lld bytes in %lld.%03ds", 221 | (long long)transferred_bytes, 222 | (long long)(msec/1000),(int)(msec%1000)); 223 | if(msec>10) 224 | { 225 | double bps = double(transferred_bytes)*1000.0 / double(msec); 226 | fprintf(stderr, 227 | " (avg %ld kb/s", 228 | (long)(bps/1024.0+0.5)); 229 | } 230 | if(final) 231 | { fprintf(stderr,")\n"); } 232 | else 233 | { 234 | long lu_msec = 1000L*(endtime->tv_sec-last_update_time.tv_sec) + 235 | (endtime->tv_usec-last_update_time.tv_usec+500)/1000; 236 | long lu_bytes = (long)(transferred_bytes-last_update_transferred); 237 | double lu_bps = double(lu_bytes)*1000.0 / double(lu_msec); 238 | fprintf(stderr, 239 | ", curr %ld kb/s)", 240 | (long)(lu_bps/1024.0+0.5)); 241 | } 242 | } 243 | 244 | 245 | int FX2Pipe::run() 246 | { 247 | fprintf(stderr,"IO loop running...\n"); 248 | 249 | // LibUSB initialisation: 250 | usb_init(); 251 | usb_find_busses(); 252 | usb_find_devices(); 253 | 254 | if(_ConnectAndInitUSB()) 255 | { ++x_errors; return(1); } 256 | 257 | if(_SubmitInitialURBs()) 258 | { ++x_errors; return(1); } 259 | 260 | // Set scheduler. 261 | if(schedule_policy!=SCHED_OTHER) 262 | { 263 | // Change scheduler. 264 | struct sched_param sp; 265 | memset(&sp,0,sizeof(sp)); 266 | sp.sched_priority=schedule_priority; 267 | int rv=sched_setscheduler(0,schedule_policy,&sp); 268 | if(rv) 269 | { 270 | fprintf(stderr,"Failed to use realtime scheduling: %s\n", 271 | strerror(rv)); 272 | schedule_policy=SCHED_OTHER; 273 | } 274 | } 275 | 276 | int must_break_loop=0; // 2 -> disconnect or other severe error. 277 | while(!must_break_loop) 278 | { 279 | ErrorCode ec=ProcessEvents(/*max_delay=*/-1); 280 | switch(ec) 281 | { 282 | case ECTimeout: 283 | break; 284 | case ECUserQuit: 285 | must_break_loop=1; 286 | break; 287 | case ECUserQuitFatal: 288 | // ECUserQuitFatal is for severe errors. 289 | ++x_errors; 290 | must_break_loop=2; 291 | break; 292 | case ECNotConnected: 293 | must_break_loop=2; 294 | break; 295 | case ECNoURBAvail: 296 | if(stdio_eof) 297 | { must_break_loop=1; } 298 | else 299 | { fprintf(stderr, 300 | "fx2pipe: OOPS no more URBs although not on EOF\n"); 301 | ++x_errors; must_break_loop=2; } 302 | break; 303 | default: 304 | fprintf(stderr,"OOPS: ProcessEvents: ec=%d\n",ec); 305 | // FIXME: What should we do??? 306 | break; 307 | } 308 | if(caught_sigint) must_break_loop=1; 309 | 310 | //write(1,"+",1); 311 | //fprintf(stderr,"+%d",npending); 312 | if(npending(_u); 344 | if(u->actual_length!=u->buffer_length 345 | || u->status || u->error_count || u->cancelled) 346 | { 347 | if(!(u->cancelled==2 && u->status==-ENOENT)) 348 | { fprintf(stderr,"HMM: URB(%d): blen=%d/%d, status=%d, " 349 | "error count=%d, cancelled=%d\n", 350 | u->urb_serial,u->actual_length,u->buffer_length, 351 | u->status,u->error_count,u->cancelled); } 352 | } 353 | 354 | // Simply ignore cancelled URBs. 355 | if(u->cancelled) 356 | { return(ECSuccess); } 357 | 358 | if(u->status==-EPROTO) 359 | { 360 | if(++successive_error_urbs>pipeline_size+4) 361 | { 362 | fprintf(stderr,"Giving up after %d reaped URBs with errors.\n", 363 | successive_error_urbs); 364 | // Seems like it does not make sense to go on here. 365 | return(ECUserQuitFatal); // User quit. 366 | } 367 | } 368 | else 369 | { successive_error_urbs=0; } 370 | 371 | // FIXME: We don't handle frames with protocol error yet. 372 | if(u->status==0) 373 | { 374 | if(dir<0) // Read in from USB. 375 | { 376 | // In benchmarking mode, don't do anything actually. 377 | // Otherwise, write to stdout. 378 | if(no_stdio) 379 | { 380 | //slurped_bytes+=u->actual_length; 381 | transferred_bytes+=u->actual_length; 382 | } 383 | else 384 | { 385 | const char *raw_buf = (const char*)u->buffer; 386 | size_t raw_size = u->actual_length; 387 | 388 | //slurped_bytes+=u->actual_length; 389 | 390 | while(raw_size && !caught_sigint) 391 | { 392 | ssize_t wr=write(1,raw_buf,raw_size); 393 | if(wr>0) 394 | { 395 | assert(size_t(wr)<=raw_size); 396 | raw_size-=wr; 397 | raw_buf+=wr; 398 | 399 | transferred_bytes+=wr; 400 | } 401 | else if(wr<0) 402 | { 403 | if(errno==EINTR) continue; 404 | if(errno==EAGAIN) continue; // <-- SHOULD NOT HAPPEN! 405 | fprintf(stderr,"fx2pipe: write error: %s\n", 406 | strerror(errno)); 407 | ++x_errors; 408 | return(ECUserQuit); 409 | } 410 | else if(!wr) 411 | { 412 | fprintf(stderr,"fx2pipe: EOF on stdout\n"); 413 | return(ECUserQuit); 414 | } 415 | } 416 | } 417 | } 418 | else //if(dir>0) // Write out to USB. 419 | { 420 | // Data successfully written over USB. 421 | transferred_bytes+=u->actual_length; 422 | } 423 | 424 | //write(2,".",1); 425 | } 426 | 427 | { 428 | timeval curr_time; 429 | gettimeofday(&curr_time,NULL); 430 | long msec = 1000L*(curr_time.tv_sec-last_update_time.tv_sec) + 431 | (curr_time.tv_usec-last_update_time.tv_usec+500)/1000; 432 | if(msec>250) 433 | { 434 | _DisplayTransferStatistics(&curr_time,0); 435 | last_update_time=curr_time; 436 | last_update_transferred=transferred_bytes; 437 | } 438 | } 439 | 440 | if(caught_sigint) 441 | { return(ECUserQuit); } 442 | 443 | // For each reaped URB, we submit a new one to keep things running. 444 | if(_SubmitOneURB()) 445 | { return(ECUserQuit); } 446 | 447 | return(ECSuccess); 448 | } 449 | 450 | 451 | void FX2Pipe::DeleteURB(URB *_u) 452 | { 453 | MyURB *u=static_cast(_u); 454 | delete u; 455 | } 456 | 457 | 458 | FX2Pipe::FX2Pipe() : 459 | FX2USBDevice(), 460 | successive_error_urbs(0), 461 | x_errors(0), 462 | //slurped_bytes(0), 463 | submitted_bytes(0), 464 | last_update_transferred(0), 465 | transferred_bytes(0), 466 | stdio_eof(0), 467 | n_th_usb_dev(0), 468 | search_vid(-1), 469 | search_pid(-1), 470 | transfer_limit(-1), 471 | io_block_size(16384), 472 | pipeline_size(16), 473 | dir(-1), 474 | no_stdio(0), 475 | schedule_policy(SCHED_OTHER), 476 | schedule_priority(0), 477 | firmware_hex_path(NULL) 478 | { 479 | memset(&starttime,0,sizeof(starttime)); 480 | memset(&endtime,0,sizeof(endtime)); 481 | memset(&last_update_time,0,sizeof(last_update_time)); 482 | } 483 | 484 | FX2Pipe::~FX2Pipe() 485 | { 486 | _CleanupUSB(); 487 | } 488 | 489 | //------------------------------------------------------------------------------ 490 | 491 | void FX2Pipe::MyURB::AllocBuffer(size_t size) 492 | { 493 | buffer=malloc(size); 494 | if(!buffer) 495 | { fprintf(stderr,"URB buffer allocation failure (%u bytes)\n",size); 496 | abort(); } 497 | buffer_length=size; 498 | } 499 | 500 | FX2Pipe::MyURB::MyURB(uchar dir_ep,uchar _type) : 501 | FX2USBDevice::URB(dir_ep,_type) 502 | { 503 | } 504 | 505 | FX2Pipe::MyURB::~MyURB() 506 | { 507 | if(buffer) 508 | { free(buffer); buffer=NULL; } 509 | } 510 | 511 | -------------------------------------------------------------------------------- /fx2pipe/fx2pipe/fx2pipe.h: -------------------------------------------------------------------------------- 1 | /* 2 | * usb_io/fx2pipe.h 3 | * 4 | * Cypress FX2 pipe IO main class. 5 | * 6 | * Copyright (c) 2006--2009 by Wolfgang Wieser ] wwieser (a) gmx <*> de [ 7 | * 8 | * This file may be distributed and/or modified under the terms of the 9 | * GNU General Public License version 2 as published by the Free Software 10 | * Foundation. (See COPYING.GPL for details.) 11 | * 12 | * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 13 | * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 14 | * 15 | */ 16 | 17 | #ifndef _INCLUDE_USBIO_FX2PIPE_H_ 18 | #define _INCLUDE_USBIO_FX2PIPE_H_ 1 19 | 20 | #include "../oconfig.h" 21 | #include "../lib/linkedlist.h" 22 | #include "../usb_io/fx2usb.h" 23 | #include "../usb_io/urbcache.h" 24 | 25 | #include 26 | 27 | 28 | // This is defined somewhere in main.cc 29 | extern volatile int caught_sigint; 30 | // Builtin firmware from ../firmware/fx2pipe_static.cc: 31 | extern const char *fx2pipe_static_firmware[]; 32 | 33 | /** 34 | * \short Cypress FX2 pipe IO main class. 35 | * \author Wolfgang Wieser ] wwieser (a) gmx <*> de [ 36 | * 37 | * Not C++-safe. Not thread-safe. 38 | */ 39 | class FX2Pipe : public FX2USBDevice 40 | { 41 | public: 42 | /// URB used by USBIOThread. 43 | struct MyURB : FX2Pipe::URB 44 | { 45 | /// URB cache against allocation overhead. 46 | static URBCache urb_cache; 47 | 48 | /// Allocate buffer and attach it. Must be done before submission. 49 | void AllocBuffer(size_t size); 50 | 51 | MyURB(uchar dir_ep,uchar _type=USBDEVFS_URB_TYPE_BULK); 52 | ~MyURB(); 53 | 54 | /** Custom operators new and delete for URB caching. */ 55 | /// \{ 56 | void *operator new(size_t size) 57 | { return(urb_cache.get(size)); } 58 | void operator delete(void *ptr,size_t size) 59 | { urb_cache.put(ptr,size); } 60 | /// \} 61 | }; 62 | 63 | private: 64 | /// Number of successive reaped URBs with errors. 65 | /// May only be accessed by IO thread. 66 | int successive_error_urbs; 67 | 68 | /// Error counter for exit value. 69 | int x_errors; 70 | 71 | /// Start time when we submitted the initial URBs. 72 | timeval starttime; 73 | /// End time when everything's done. 74 | timeval endtime; 75 | /// Time of last status display update. 76 | timeval last_update_time; 77 | /// Number of bytes transferred at last update. 78 | int64 last_update_transferred; 79 | 80 | /// Submitted bytes: Number of bytes submitted but not all of them 81 | /// are yet transferred. 82 | int64 submitted_bytes; 83 | /// Transferred bytes: 84 | /// Number of bytes successfully transferred. 85 | int64 transferred_bytes; 86 | 87 | /// EOF on stdio (1) or transfer limit reached (2). 88 | int stdio_eof; 89 | 90 | /// See FirwareConfig. 91 | static const int FirmwareConfigAdr=0x1003; 92 | 93 | /// Write transferred bytes, time and transfer rate. 94 | void _DisplayTransferStatistics(const timeval *endtime,int final); 95 | 96 | /// Initialize/connect to USB device. Also download firmware. 97 | /// Returns error code. 98 | int _ConnectAndInitUSB(); 99 | /// Counterpart of ConnectAndInitUSB: cleanup. 100 | void _CleanupUSB(); 101 | 102 | /// Submit one URB. 0 on success; 1 on failure. 103 | int _SubmitOneURB(); 104 | /// Submit a bunch of URBs initially to fill the pipeline. 105 | int _SubmitInitialURBs(); 106 | /// Cancel all the pending osci data URBs. 107 | void _CancelAllPendingDataURBs(); 108 | 109 | /// Overriding virtual from WWUSBDevice. 110 | ErrorCode URBNotify(URB *u); 111 | /// Overriding virtual from WWUSBDevice. 112 | void DeleteURB(URB *u); 113 | 114 | public: 115 | /// Some config: 116 | /// This config is meant to be set in the beginning and not to be 117 | /// changed afterwards. 118 | int n_th_usb_dev; /// Connect to n-th matching USB device. Start with 0. 119 | /// VID and PID of device to search; -1 for defaults. 120 | int search_vid,search_pid; 121 | 122 | /// Max number of bytes to transfer; negative for unlimited. 123 | int64 transfer_limit; 124 | 125 | /// IO block size. 126 | uint io_block_size; 127 | /// Pipeline size (number of URBs). 128 | int pipeline_size; 129 | 130 | /// Direction: -1 -> IN (default); +1 -> OUT 131 | int dir; 132 | 133 | /// Don't use stdio but throw away data / write NUL data. 134 | int no_stdio; 135 | 136 | /// SCHED_OTHER or SCHED_FIFO or SCHED_RR 137 | int schedule_policy; 138 | /// Priority; used if schedule_policy!=SCHED_OTHER. 139 | int schedule_priority; 140 | 141 | /// Path to firmware IHX file. NULL for builtin firmware. 142 | const char *firmware_hex_path; 143 | 144 | /// This is at address FirmwareConfigAdr in the FX2. 145 | struct FirwareConfig 146 | { 147 | uchar FC_DIR; // [0] 0x12 or 0x21 148 | uchar FC_IFCONFIG; // [1] 149 | uchar FC_EPCFG; // [2] 150 | uchar FC_EPFIFOCFG; // [3] 151 | uchar FC_CPUCS; // [4] 152 | }__attribute__((__packed__)) fc; 153 | 154 | private: 155 | /// Do not use. 156 | FX2Pipe(const FX2Pipe &); 157 | /// Do not use. 158 | void operator=(const FX2Pipe &); 159 | public: 160 | FX2Pipe(); 161 | ~FX2Pipe(); 162 | 163 | /// Actually run the IO code... 164 | int run(); 165 | }; 166 | 167 | #endif /* _INCLUDE_USBIO_FX2PIPE_H_ */ 168 | -------------------------------------------------------------------------------- /fx2pipe/fx2pipe/main.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * usb_io/main.cc 3 | * 4 | * FX2 pipe program main routine. 5 | * 6 | * Copyright (c) 2006--2009 by Wolfgang Wieser ] wwieser (a) gmx <*> de [ 7 | * 8 | * This file may be distributed and/or modified under the terms of the 9 | * GNU General Public License version 2 as published by the Free Software 10 | * Foundation. (See COPYING.GPL for details.) 11 | * 12 | * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 13 | * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 14 | * 15 | */ 16 | 17 | #include "../oconfig.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "../fx2pipe/fx2pipe.h" 29 | 30 | #include 31 | 32 | 33 | volatile int caught_sigint=0; 34 | 35 | static void SigIntHandler(int) 36 | { 37 | ++caught_sigint; 38 | if(caught_sigint>5) 39 | { 40 | const char *msg= 41 | "fx2pipe: caught too many SIGINT; exiting ungracefully\n"; 42 | write(2,msg,sizeof(msg)); 43 | _exit(1); 44 | } 45 | } 46 | 47 | 48 | static void PrintHelp() 49 | { 50 | fprintf(stderr, 51 | "USAGE: fx2pipe [option|assignment]...\n" 52 | "Long options:\n" 53 | " --help print this\n" 54 | " --version print version information\n" 55 | "Short options: (Can be compined into single option)\n" 56 | " -i run in IN direction, i.e. read data from USB EP6 (default)\n" 57 | " -o run in OUT direction, i.e. write data to USB EP2\n" 58 | " -0 no stdio; send NULs / throw away read data (for timing)\n" 59 | " -8,-w use 8bit / 16bit (default) wide fifo bus on FX2 side\n" 60 | " -2,-3,-4 use double, triple or quad (default) buffered FX2 fifo\n" 61 | " -s,-a run in sync (default) / async slave fifo mode\n" 62 | " -O,-I shortcut for -o0, -i0, respectively\n" 63 | "Assignments: (Leading '-' can be left away)\n" 64 | " -d=NN use n-th (unconfigured) FX2 device (start with NN=0, default)\n" 65 | " -d=VID:PID[:N] use N-th device with specified VID and PID\n" 66 | // " -d=BUS/DEV use BUS/DEV (e.g. 003/047) as device\n" 67 | " -n=NNN stop after NNN bytes; suffix k,M,G for mult. with 2^10,20,30\n" 68 | " -bs=NNN set IO block size to NNN, max 16384 (default 16384)\n" 69 | " -ps=NN set pipeline size (number of URBs; default 16)\n" 70 | " -sched=P[,N] set scheduling policy P (\"fifo\" or \"rr\") and prio N\n" 71 | " -fw=PATH use specified firmware IHX file instead of built-in one\n" 72 | " omit path to not download any firmware (just reset device)\n" 73 | " -ifclk=[x|30[o]|48[o]][i] specify interface clock:\n" 74 | " x -> external; 30,48 -> internal clock 30/48MHz, suffix 'o'\n" 75 | " to enable output to IFCLK pin, 'i' to invert IFCLK\n" 76 | " -cko=[12|24|48][o|z][i] specify 8051 frequency in MHz (default: 48) and\n" 77 | " CLKOUT pin: output 'o' (default), tristate 'z', invert 'i'\n" 78 | "\n" 79 | "fx2pipe - pipe data in or out of an Cypress FX2 device (CY7C6801x[A])\n" 80 | " Copyright (c) 2006--2011 by Wolfgang Wieser; License: GPL\n"); 81 | } 82 | 83 | 84 | int main(int argc,char **arg) 85 | { 86 | FX2Pipe p; 87 | 88 | int errors=0; 89 | int dir_spec=0; 90 | int fifo_width=2; // 1 or 2 (8 or 16 bits) 91 | int fifo_nbuf=4; // 2,3,4 for double, triple, quad buffered 92 | char fifo_mode='s'; 93 | char ifclk_invert=0; 94 | char ifclk_speed=48; // 0 -> external; 30,48 -> internal 30/48 MHz 95 | char ifclk_output=0; 96 | char cko_speed=48; 97 | char cko_output=1; 98 | char cko_invert=0; 99 | for(int i=1; i1) 290 | { 291 | fprintf(stderr,"fx2pipe: more than one direction specification " 292 | "(-iIoO).\n"); 293 | ++errors; 294 | } 295 | 296 | // FIXME: If fifo_width is 2, force even sizes! 297 | if(p.io_block_size<1 || p.io_block_size>16384) 298 | { 299 | fprintf(stderr,"fx2pipe: IO block size (bs) must be in " 300 | "range 1..16384, bs=%u is invalid\n",p.io_block_size); 301 | ++errors; 302 | } 303 | 304 | // Set up config for firmware: 305 | p.fc.FC_DIR = p.dir<0 ? 0x12U : 0x21U; 306 | p.fc.FC_CPUCS = 307 | ((cko_speed==12 ? 0U : cko_speed==24 ? 1U : 2U)<<3) | 308 | (cko_invert ? 0x04U : 0x00U) | 309 | (cko_output ? 0x02U : 0x00U); 310 | p.fc.FC_IFCONFIG = 311 | (ifclk_speed ? 0x80U : 0x00U) | // Internal (1) / external? 312 | (ifclk_speed==30 ? 0x00U : 0x40U) | // 30 (0) / 48 (1) MHz? 313 | (ifclk_output ? 0x20U : 0x00U) | // Enable (1) output to IFCLK? 314 | (ifclk_invert ? 0x10U : 0x00U) | // Invert (1) IFCLK? 315 | (fifo_mode=='a' ? 0x08U : 0x00U) | // Async (1) or sync (0) FIFO mode? 316 | 0x00U | // bit2 irrelevant for us... 317 | 0x03U; // bits 1,0 = 11 for slave FIFO mode 318 | if(p.dir<0) 319 | { 320 | // INPUT: USB->HOST 321 | p.fc.FC_EPCFG = 0xe0U; // 1110 00BB with BB = 2,3,4times buffered? 322 | p.fc.FC_EPFIFOCFG = 0x0cU; // 0000 110W (W = wordwide) 323 | } 324 | else 325 | { 326 | // OUTPUT: HOST->USB 327 | p.fc.FC_EPCFG = 0xa0U; // 1010 00BB with BB = 2,3,4times buffered? 328 | p.fc.FC_EPFIFOCFG = 0x10U; // 0001 000W (W = wordwide) 329 | } 330 | switch(fifo_nbuf) 331 | { 332 | case 2: p.fc.FC_EPCFG|=0x02U; break; 333 | case 3: p.fc.FC_EPCFG|=0x03U; break; 334 | case 4: break; // Do nothing. 335 | default: assert(0); break; 336 | } 337 | if(fifo_width==2) 338 | { p.fc.FC_EPFIFOCFG|=0x01U; } 339 | 340 | // Dump firmware config values: 341 | fprintf(stderr,"Firmware config: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", 342 | (unsigned int)p.fc.FC_DIR, (unsigned int)p.fc.FC_IFCONFIG, 343 | (unsigned int)p.fc.FC_EPCFG, (unsigned int)p.fc.FC_EPFIFOCFG, 344 | (unsigned int)p.fc.FC_CPUCS ); 345 | 346 | if(errors) 347 | { return(1); } 348 | 349 | // Install signal handler for SIGINT. 350 | struct sigaction sa; 351 | memset(&sa,0,sizeof(sa)); 352 | sa.sa_handler=&SigIntHandler; 353 | sigaction(SIGINT,&sa,NULL); 354 | 355 | int ecode=0; 356 | 357 | ecode=p.run(); 358 | 359 | return(ecode); 360 | } 361 | -------------------------------------------------------------------------------- /fx2pipe/lib/Makefile.am: -------------------------------------------------------------------------------- 1 | INCLUDES = -I. -I$(top_srcdir) -I$(top_builddir) 2 | 3 | noinst_LIBRARIES = lib_fx2pipe_supp.a 4 | lib_fx2pipe_supp_a_SOURCES = \ 5 | linkedlist.h \ 6 | linearqueue.h 7 | -------------------------------------------------------------------------------- /fx2pipe/lib/Makefile.in: -------------------------------------------------------------------------------- 1 | # Makefile.in generated by automake 1.10.1 from Makefile.am. 2 | # @configure_input@ 3 | 4 | # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 5 | # 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. 6 | # This Makefile.in is free software; the Free Software Foundation 7 | # gives unlimited permission to copy and/or distribute it, 8 | # with or without modifications, as long as this notice is preserved. 9 | 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY, to the extent permitted by law; without 12 | # even the implied warranty of MERCHANTABILITY or FITNESS FOR A 13 | # PARTICULAR PURPOSE. 14 | 15 | @SET_MAKE@ 16 | 17 | VPATH = @srcdir@ 18 | pkgdatadir = $(datadir)/@PACKAGE@ 19 | pkglibdir = $(libdir)/@PACKAGE@ 20 | pkgincludedir = $(includedir)/@PACKAGE@ 21 | am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd 22 | install_sh_DATA = $(install_sh) -c -m 644 23 | install_sh_PROGRAM = $(install_sh) -c 24 | install_sh_SCRIPT = $(install_sh) -c 25 | INSTALL_HEADER = $(INSTALL_DATA) 26 | transform = $(program_transform_name) 27 | NORMAL_INSTALL = : 28 | PRE_INSTALL = : 29 | POST_INSTALL = : 30 | NORMAL_UNINSTALL = : 31 | PRE_UNINSTALL = : 32 | POST_UNINSTALL = : 33 | subdir = lib 34 | DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in 35 | ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 36 | am__aclocal_m4_deps = $(top_srcdir)/configure.ac 37 | am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ 38 | $(ACLOCAL_M4) 39 | mkinstalldirs = $(install_sh) -d 40 | CONFIG_HEADER = $(top_builddir)/config.h 41 | CONFIG_CLEAN_FILES = 42 | LIBRARIES = $(noinst_LIBRARIES) 43 | AR = ar 44 | ARFLAGS = cru 45 | lib_fx2pipe_supp_a_AR = $(AR) $(ARFLAGS) 46 | lib_fx2pipe_supp_a_LIBADD = 47 | am_lib_fx2pipe_supp_a_OBJECTS = 48 | lib_fx2pipe_supp_a_OBJECTS = $(am_lib_fx2pipe_supp_a_OBJECTS) 49 | DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) 50 | COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ 51 | $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) 52 | CCLD = $(CC) 53 | LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ 54 | SOURCES = $(lib_fx2pipe_supp_a_SOURCES) 55 | DIST_SOURCES = $(lib_fx2pipe_supp_a_SOURCES) 56 | ETAGS = etags 57 | CTAGS = ctags 58 | DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 59 | ACLOCAL = @ACLOCAL@ 60 | AMTAR = @AMTAR@ 61 | AUTOCONF = @AUTOCONF@ 62 | AUTOHEADER = @AUTOHEADER@ 63 | AUTOMAKE = @AUTOMAKE@ 64 | AWK = @AWK@ 65 | CC = @CC@ 66 | CCDEPMODE = @CCDEPMODE@ 67 | CFLAGS = @CFLAGS@ 68 | CPP = @CPP@ 69 | CPPFLAGS = @CPPFLAGS@ 70 | CXX = @CXX@ 71 | CXXDEPMODE = @CXXDEPMODE@ 72 | CXXFLAGS = @CXXFLAGS@ 73 | CYGPATH_W = @CYGPATH_W@ 74 | DEFS = @DEFS@ 75 | DEPDIR = @DEPDIR@ 76 | ECHO_C = @ECHO_C@ 77 | ECHO_N = @ECHO_N@ 78 | ECHO_T = @ECHO_T@ 79 | EGREP = @EGREP@ 80 | EXEEXT = @EXEEXT@ 81 | GREP = @GREP@ 82 | INSTALL = @INSTALL@ 83 | INSTALL_DATA = @INSTALL_DATA@ 84 | INSTALL_PROGRAM = @INSTALL_PROGRAM@ 85 | INSTALL_SCRIPT = @INSTALL_SCRIPT@ 86 | INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ 87 | LDFLAGS = @LDFLAGS@ 88 | LIBOBJS = @LIBOBJS@ 89 | LIBS = @LIBS@ 90 | LTLIBOBJS = @LTLIBOBJS@ 91 | MAKEINFO = @MAKEINFO@ 92 | MKDIR_P = @MKDIR_P@ 93 | OBJEXT = @OBJEXT@ 94 | PACKAGE = @PACKAGE@ 95 | PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ 96 | PACKAGE_NAME = @PACKAGE_NAME@ 97 | PACKAGE_STRING = @PACKAGE_STRING@ 98 | PACKAGE_TARNAME = @PACKAGE_TARNAME@ 99 | PACKAGE_VERSION = @PACKAGE_VERSION@ 100 | PATH_SEPARATOR = @PATH_SEPARATOR@ 101 | RANLIB = @RANLIB@ 102 | SET_MAKE = @SET_MAKE@ 103 | SHELL = @SHELL@ 104 | STRIP = @STRIP@ 105 | VERSION = @VERSION@ 106 | abs_builddir = @abs_builddir@ 107 | abs_srcdir = @abs_srcdir@ 108 | abs_top_builddir = @abs_top_builddir@ 109 | abs_top_srcdir = @abs_top_srcdir@ 110 | ac_ct_CC = @ac_ct_CC@ 111 | ac_ct_CXX = @ac_ct_CXX@ 112 | am__include = @am__include@ 113 | am__leading_dot = @am__leading_dot@ 114 | am__quote = @am__quote@ 115 | am__tar = @am__tar@ 116 | am__untar = @am__untar@ 117 | bindir = @bindir@ 118 | build_alias = @build_alias@ 119 | builddir = @builddir@ 120 | datadir = @datadir@ 121 | datarootdir = @datarootdir@ 122 | docdir = @docdir@ 123 | dvidir = @dvidir@ 124 | exec_prefix = @exec_prefix@ 125 | host_alias = @host_alias@ 126 | htmldir = @htmldir@ 127 | includedir = @includedir@ 128 | infodir = @infodir@ 129 | install_sh = @install_sh@ 130 | libdir = @libdir@ 131 | libexecdir = @libexecdir@ 132 | localedir = @localedir@ 133 | localstatedir = @localstatedir@ 134 | mandir = @mandir@ 135 | mkdir_p = @mkdir_p@ 136 | oldincludedir = @oldincludedir@ 137 | pdfdir = @pdfdir@ 138 | prefix = @prefix@ 139 | program_transform_name = @program_transform_name@ 140 | psdir = @psdir@ 141 | sbindir = @sbindir@ 142 | sharedstatedir = @sharedstatedir@ 143 | srcdir = @srcdir@ 144 | sysconfdir = @sysconfdir@ 145 | target_alias = @target_alias@ 146 | top_build_prefix = @top_build_prefix@ 147 | top_builddir = @top_builddir@ 148 | top_srcdir = @top_srcdir@ 149 | INCLUDES = -I. -I$(top_srcdir) -I$(top_builddir) 150 | noinst_LIBRARIES = lib_fx2pipe_supp.a 151 | lib_fx2pipe_supp_a_SOURCES = \ 152 | linkedlist.h \ 153 | linearqueue.h 154 | 155 | all: all-am 156 | 157 | .SUFFIXES: 158 | $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) 159 | @for dep in $?; do \ 160 | case '$(am__configure_deps)' in \ 161 | *$$dep*) \ 162 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ 163 | && exit 0; \ 164 | exit 1;; \ 165 | esac; \ 166 | done; \ 167 | echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lib/Makefile'; \ 168 | cd $(top_srcdir) && \ 169 | $(AUTOMAKE) --gnu lib/Makefile 170 | .PRECIOUS: Makefile 171 | Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status 172 | @case '$?' in \ 173 | *config.status*) \ 174 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ 175 | *) \ 176 | echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ 177 | cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ 178 | esac; 179 | 180 | $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) 181 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh 182 | 183 | $(top_srcdir)/configure: $(am__configure_deps) 184 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh 185 | $(ACLOCAL_M4): $(am__aclocal_m4_deps) 186 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh 187 | 188 | clean-noinstLIBRARIES: 189 | -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) 190 | lib_fx2pipe_supp.a: $(lib_fx2pipe_supp_a_OBJECTS) $(lib_fx2pipe_supp_a_DEPENDENCIES) 191 | -rm -f lib_fx2pipe_supp.a 192 | $(lib_fx2pipe_supp_a_AR) lib_fx2pipe_supp.a $(lib_fx2pipe_supp_a_OBJECTS) $(lib_fx2pipe_supp_a_LIBADD) 193 | $(RANLIB) lib_fx2pipe_supp.a 194 | 195 | mostlyclean-compile: 196 | -rm -f *.$(OBJEXT) 197 | 198 | distclean-compile: 199 | -rm -f *.tab.c 200 | 201 | ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) 202 | list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ 203 | unique=`for i in $$list; do \ 204 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ 205 | done | \ 206 | $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ 207 | END { if (nonempty) { for (i in files) print i; }; }'`; \ 208 | mkid -fID $$unique 209 | tags: TAGS 210 | 211 | TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ 212 | $(TAGS_FILES) $(LISP) 213 | tags=; \ 214 | here=`pwd`; \ 215 | list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ 216 | unique=`for i in $$list; do \ 217 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ 218 | done | \ 219 | $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ 220 | END { if (nonempty) { for (i in files) print i; }; }'`; \ 221 | if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ 222 | test -n "$$unique" || unique=$$empty_fix; \ 223 | $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ 224 | $$tags $$unique; \ 225 | fi 226 | ctags: CTAGS 227 | CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ 228 | $(TAGS_FILES) $(LISP) 229 | tags=; \ 230 | list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ 231 | unique=`for i in $$list; do \ 232 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ 233 | done | \ 234 | $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ 235 | END { if (nonempty) { for (i in files) print i; }; }'`; \ 236 | test -z "$(CTAGS_ARGS)$$tags$$unique" \ 237 | || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ 238 | $$tags $$unique 239 | 240 | GTAGS: 241 | here=`$(am__cd) $(top_builddir) && pwd` \ 242 | && cd $(top_srcdir) \ 243 | && gtags -i $(GTAGS_ARGS) $$here 244 | 245 | distclean-tags: 246 | -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags 247 | 248 | distdir: $(DISTFILES) 249 | @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ 250 | topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ 251 | list='$(DISTFILES)'; \ 252 | dist_files=`for file in $$list; do echo $$file; done | \ 253 | sed -e "s|^$$srcdirstrip/||;t" \ 254 | -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ 255 | case $$dist_files in \ 256 | */*) $(MKDIR_P) `echo "$$dist_files" | \ 257 | sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ 258 | sort -u` ;; \ 259 | esac; \ 260 | for file in $$dist_files; do \ 261 | if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ 262 | if test -d $$d/$$file; then \ 263 | dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ 264 | if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ 265 | cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ 266 | fi; \ 267 | cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ 268 | else \ 269 | test -f $(distdir)/$$file \ 270 | || cp -p $$d/$$file $(distdir)/$$file \ 271 | || exit 1; \ 272 | fi; \ 273 | done 274 | check-am: all-am 275 | check: check-am 276 | all-am: Makefile $(LIBRARIES) 277 | installdirs: 278 | install: install-am 279 | install-exec: install-exec-am 280 | install-data: install-data-am 281 | uninstall: uninstall-am 282 | 283 | install-am: all-am 284 | @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am 285 | 286 | installcheck: installcheck-am 287 | install-strip: 288 | $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ 289 | install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ 290 | `test -z '$(STRIP)' || \ 291 | echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install 292 | mostlyclean-generic: 293 | 294 | clean-generic: 295 | 296 | distclean-generic: 297 | -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) 298 | 299 | maintainer-clean-generic: 300 | @echo "This command is intended for maintainers to use" 301 | @echo "it deletes files that may require special tools to rebuild." 302 | clean: clean-am 303 | 304 | clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am 305 | 306 | distclean: distclean-am 307 | -rm -f Makefile 308 | distclean-am: clean-am distclean-compile distclean-generic \ 309 | distclean-tags 310 | 311 | dvi: dvi-am 312 | 313 | dvi-am: 314 | 315 | html: html-am 316 | 317 | info: info-am 318 | 319 | info-am: 320 | 321 | install-data-am: 322 | 323 | install-dvi: install-dvi-am 324 | 325 | install-exec-am: 326 | 327 | install-html: install-html-am 328 | 329 | install-info: install-info-am 330 | 331 | install-man: 332 | 333 | install-pdf: install-pdf-am 334 | 335 | install-ps: install-ps-am 336 | 337 | installcheck-am: 338 | 339 | maintainer-clean: maintainer-clean-am 340 | -rm -f Makefile 341 | maintainer-clean-am: distclean-am maintainer-clean-generic 342 | 343 | mostlyclean: mostlyclean-am 344 | 345 | mostlyclean-am: mostlyclean-compile mostlyclean-generic 346 | 347 | pdf: pdf-am 348 | 349 | pdf-am: 350 | 351 | ps: ps-am 352 | 353 | ps-am: 354 | 355 | uninstall-am: 356 | 357 | .MAKE: install-am install-strip 358 | 359 | .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ 360 | clean-noinstLIBRARIES ctags distclean distclean-compile \ 361 | distclean-generic distclean-tags distdir dvi dvi-am html \ 362 | html-am info info-am install install-am install-data \ 363 | install-data-am install-dvi install-dvi-am install-exec \ 364 | install-exec-am install-html install-html-am install-info \ 365 | install-info-am install-man install-pdf install-pdf-am \ 366 | install-ps install-ps-am install-strip installcheck \ 367 | installcheck-am installdirs maintainer-clean \ 368 | maintainer-clean-generic mostlyclean mostlyclean-compile \ 369 | mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ 370 | uninstall-am 371 | 372 | # Tell versions [3.59,3.63) of GNU make to not export all variables. 373 | # Otherwise a system limit (for SysV at least) may be exceeded. 374 | .NOEXPORT: 375 | -------------------------------------------------------------------------------- /fx2pipe/lib/linkedlist.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoglet67/6502Decoder/6bfa89ae49c9dffafb0a90026fe0fab44ed14b2a/fx2pipe/lib/linkedlist.h -------------------------------------------------------------------------------- /fx2pipe/missing: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Common stub for a few missing GNU programs while installing. 3 | 4 | scriptversion=2009-04-28.21; # UTC 5 | 6 | # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, 7 | # 2008, 2009 Free Software Foundation, Inc. 8 | # Originally by Fran,cois Pinard , 1996. 9 | 10 | # This program is free software; you can redistribute it and/or modify 11 | # it under the terms of the GNU General Public License as published by 12 | # the Free Software Foundation; either version 2, or (at your option) 13 | # any later version. 14 | 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program. If not, see . 22 | 23 | # As a special exception to the GNU General Public License, if you 24 | # distribute this file as part of a program that contains a 25 | # configuration script generated by Autoconf, you may include it under 26 | # the same distribution terms that you use for the rest of that program. 27 | 28 | if test $# -eq 0; then 29 | echo 1>&2 "Try \`$0 --help' for more information" 30 | exit 1 31 | fi 32 | 33 | run=: 34 | sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' 35 | sed_minuso='s/.* -o \([^ ]*\).*/\1/p' 36 | 37 | # In the cases where this matters, `missing' is being run in the 38 | # srcdir already. 39 | if test -f configure.ac; then 40 | configure_ac=configure.ac 41 | else 42 | configure_ac=configure.in 43 | fi 44 | 45 | msg="missing on your system" 46 | 47 | case $1 in 48 | --run) 49 | # Try to run requested program, and just exit if it succeeds. 50 | run= 51 | shift 52 | "$@" && exit 0 53 | # Exit code 63 means version mismatch. This often happens 54 | # when the user try to use an ancient version of a tool on 55 | # a file that requires a minimum version. In this case we 56 | # we should proceed has if the program had been absent, or 57 | # if --run hadn't been passed. 58 | if test $? = 63; then 59 | run=: 60 | msg="probably too old" 61 | fi 62 | ;; 63 | 64 | -h|--h|--he|--hel|--help) 65 | echo "\ 66 | $0 [OPTION]... PROGRAM [ARGUMENT]... 67 | 68 | Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an 69 | error status if there is no known handling for PROGRAM. 70 | 71 | Options: 72 | -h, --help display this help and exit 73 | -v, --version output version information and exit 74 | --run try to run the given command, and emulate it if it fails 75 | 76 | Supported PROGRAM values: 77 | aclocal touch file \`aclocal.m4' 78 | autoconf touch file \`configure' 79 | autoheader touch file \`config.h.in' 80 | autom4te touch the output file, or create a stub one 81 | automake touch all \`Makefile.in' files 82 | bison create \`y.tab.[ch]', if possible, from existing .[ch] 83 | flex create \`lex.yy.c', if possible, from existing .c 84 | help2man touch the output file 85 | lex create \`lex.yy.c', if possible, from existing .c 86 | makeinfo touch the output file 87 | tar try tar, gnutar, gtar, then tar without non-portable flags 88 | yacc create \`y.tab.[ch]', if possible, from existing .[ch] 89 | 90 | Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and 91 | \`g' are ignored when checking the name. 92 | 93 | Send bug reports to ." 94 | exit $? 95 | ;; 96 | 97 | -v|--v|--ve|--ver|--vers|--versi|--versio|--version) 98 | echo "missing $scriptversion (GNU Automake)" 99 | exit $? 100 | ;; 101 | 102 | -*) 103 | echo 1>&2 "$0: Unknown \`$1' option" 104 | echo 1>&2 "Try \`$0 --help' for more information" 105 | exit 1 106 | ;; 107 | 108 | esac 109 | 110 | # normalize program name to check for. 111 | program=`echo "$1" | sed ' 112 | s/^gnu-//; t 113 | s/^gnu//; t 114 | s/^g//; t'` 115 | 116 | # Now exit if we have it, but it failed. Also exit now if we 117 | # don't have it and --version was passed (most likely to detect 118 | # the program). This is about non-GNU programs, so use $1 not 119 | # $program. 120 | case $1 in 121 | lex*|yacc*) 122 | # Not GNU programs, they don't have --version. 123 | ;; 124 | 125 | tar*) 126 | if test -n "$run"; then 127 | echo 1>&2 "ERROR: \`tar' requires --run" 128 | exit 1 129 | elif test "x$2" = "x--version" || test "x$2" = "x--help"; then 130 | exit 1 131 | fi 132 | ;; 133 | 134 | *) 135 | if test -z "$run" && ($1 --version) > /dev/null 2>&1; then 136 | # We have it, but it failed. 137 | exit 1 138 | elif test "x$2" = "x--version" || test "x$2" = "x--help"; then 139 | # Could not run --version or --help. This is probably someone 140 | # running `$TOOL --version' or `$TOOL --help' to check whether 141 | # $TOOL exists and not knowing $TOOL uses missing. 142 | exit 1 143 | fi 144 | ;; 145 | esac 146 | 147 | # If it does not exist, or fails to run (possibly an outdated version), 148 | # try to emulate it. 149 | case $program in 150 | aclocal*) 151 | echo 1>&2 "\ 152 | WARNING: \`$1' is $msg. You should only need it if 153 | you modified \`acinclude.m4' or \`${configure_ac}'. You might want 154 | to install the \`Automake' and \`Perl' packages. Grab them from 155 | any GNU archive site." 156 | touch aclocal.m4 157 | ;; 158 | 159 | autoconf*) 160 | echo 1>&2 "\ 161 | WARNING: \`$1' is $msg. You should only need it if 162 | you modified \`${configure_ac}'. You might want to install the 163 | \`Autoconf' and \`GNU m4' packages. Grab them from any GNU 164 | archive site." 165 | touch configure 166 | ;; 167 | 168 | autoheader*) 169 | echo 1>&2 "\ 170 | WARNING: \`$1' is $msg. You should only need it if 171 | you modified \`acconfig.h' or \`${configure_ac}'. You might want 172 | to install the \`Autoconf' and \`GNU m4' packages. Grab them 173 | from any GNU archive site." 174 | files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` 175 | test -z "$files" && files="config.h" 176 | touch_files= 177 | for f in $files; do 178 | case $f in 179 | *:*) touch_files="$touch_files "`echo "$f" | 180 | sed -e 's/^[^:]*://' -e 's/:.*//'`;; 181 | *) touch_files="$touch_files $f.in";; 182 | esac 183 | done 184 | touch $touch_files 185 | ;; 186 | 187 | automake*) 188 | echo 1>&2 "\ 189 | WARNING: \`$1' is $msg. You should only need it if 190 | you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. 191 | You might want to install the \`Automake' and \`Perl' packages. 192 | Grab them from any GNU archive site." 193 | find . -type f -name Makefile.am -print | 194 | sed 's/\.am$/.in/' | 195 | while read f; do touch "$f"; done 196 | ;; 197 | 198 | autom4te*) 199 | echo 1>&2 "\ 200 | WARNING: \`$1' is needed, but is $msg. 201 | You might have modified some files without having the 202 | proper tools for further handling them. 203 | You can get \`$1' as part of \`Autoconf' from any GNU 204 | archive site." 205 | 206 | file=`echo "$*" | sed -n "$sed_output"` 207 | test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` 208 | if test -f "$file"; then 209 | touch $file 210 | else 211 | test -z "$file" || exec >$file 212 | echo "#! /bin/sh" 213 | echo "# Created by GNU Automake missing as a replacement of" 214 | echo "# $ $@" 215 | echo "exit 0" 216 | chmod +x $file 217 | exit 1 218 | fi 219 | ;; 220 | 221 | bison*|yacc*) 222 | echo 1>&2 "\ 223 | WARNING: \`$1' $msg. You should only need it if 224 | you modified a \`.y' file. You may need the \`Bison' package 225 | in order for those modifications to take effect. You can get 226 | \`Bison' from any GNU archive site." 227 | rm -f y.tab.c y.tab.h 228 | if test $# -ne 1; then 229 | eval LASTARG="\${$#}" 230 | case $LASTARG in 231 | *.y) 232 | SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` 233 | if test -f "$SRCFILE"; then 234 | cp "$SRCFILE" y.tab.c 235 | fi 236 | SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` 237 | if test -f "$SRCFILE"; then 238 | cp "$SRCFILE" y.tab.h 239 | fi 240 | ;; 241 | esac 242 | fi 243 | if test ! -f y.tab.h; then 244 | echo >y.tab.h 245 | fi 246 | if test ! -f y.tab.c; then 247 | echo 'main() { return 0; }' >y.tab.c 248 | fi 249 | ;; 250 | 251 | lex*|flex*) 252 | echo 1>&2 "\ 253 | WARNING: \`$1' is $msg. You should only need it if 254 | you modified a \`.l' file. You may need the \`Flex' package 255 | in order for those modifications to take effect. You can get 256 | \`Flex' from any GNU archive site." 257 | rm -f lex.yy.c 258 | if test $# -ne 1; then 259 | eval LASTARG="\${$#}" 260 | case $LASTARG in 261 | *.l) 262 | SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` 263 | if test -f "$SRCFILE"; then 264 | cp "$SRCFILE" lex.yy.c 265 | fi 266 | ;; 267 | esac 268 | fi 269 | if test ! -f lex.yy.c; then 270 | echo 'main() { return 0; }' >lex.yy.c 271 | fi 272 | ;; 273 | 274 | help2man*) 275 | echo 1>&2 "\ 276 | WARNING: \`$1' is $msg. You should only need it if 277 | you modified a dependency of a manual page. You may need the 278 | \`Help2man' package in order for those modifications to take 279 | effect. You can get \`Help2man' from any GNU archive site." 280 | 281 | file=`echo "$*" | sed -n "$sed_output"` 282 | test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` 283 | if test -f "$file"; then 284 | touch $file 285 | else 286 | test -z "$file" || exec >$file 287 | echo ".ab help2man is required to generate this page" 288 | exit $? 289 | fi 290 | ;; 291 | 292 | makeinfo*) 293 | echo 1>&2 "\ 294 | WARNING: \`$1' is $msg. You should only need it if 295 | you modified a \`.texi' or \`.texinfo' file, or any other file 296 | indirectly affecting the aspect of the manual. The spurious 297 | call might also be the consequence of using a buggy \`make' (AIX, 298 | DU, IRIX). You might want to install the \`Texinfo' package or 299 | the \`GNU make' package. Grab either from any GNU archive site." 300 | # The file to touch is that specified with -o ... 301 | file=`echo "$*" | sed -n "$sed_output"` 302 | test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` 303 | if test -z "$file"; then 304 | # ... or it is the one specified with @setfilename ... 305 | infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` 306 | file=`sed -n ' 307 | /^@setfilename/{ 308 | s/.* \([^ ]*\) *$/\1/ 309 | p 310 | q 311 | }' $infile` 312 | # ... or it is derived from the source name (dir/f.texi becomes f.info) 313 | test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info 314 | fi 315 | # If the file does not exist, the user really needs makeinfo; 316 | # let's fail without touching anything. 317 | test -f $file || exit 1 318 | touch $file 319 | ;; 320 | 321 | tar*) 322 | shift 323 | 324 | # We have already tried tar in the generic part. 325 | # Look for gnutar/gtar before invocation to avoid ugly error 326 | # messages. 327 | if (gnutar --version > /dev/null 2>&1); then 328 | gnutar "$@" && exit 0 329 | fi 330 | if (gtar --version > /dev/null 2>&1); then 331 | gtar "$@" && exit 0 332 | fi 333 | firstarg="$1" 334 | if shift; then 335 | case $firstarg in 336 | *o*) 337 | firstarg=`echo "$firstarg" | sed s/o//` 338 | tar "$firstarg" "$@" && exit 0 339 | ;; 340 | esac 341 | case $firstarg in 342 | *h*) 343 | firstarg=`echo "$firstarg" | sed s/h//` 344 | tar "$firstarg" "$@" && exit 0 345 | ;; 346 | esac 347 | fi 348 | 349 | echo 1>&2 "\ 350 | WARNING: I can't seem to be able to run \`tar' with the given arguments. 351 | You may want to install GNU tar or Free paxutils, or check the 352 | command line arguments." 353 | exit 1 354 | ;; 355 | 356 | *) 357 | echo 1>&2 "\ 358 | WARNING: \`$1' is needed, and is $msg. 359 | You might have modified some files without having the 360 | proper tools for further handling them. Check the \`README' file, 361 | it often tells you about the needed prerequisites for installing 362 | this package. You may also peek at any GNU archive site, in case 363 | some other package would contain this missing \`$1' program." 364 | exit 1 365 | ;; 366 | esac 367 | 368 | exit 0 369 | 370 | # Local variables: 371 | # eval: (add-hook 'write-file-hooks 'time-stamp) 372 | # time-stamp-start: "scriptversion=" 373 | # time-stamp-format: "%:y-%02m-%02d.%02H" 374 | # time-stamp-time-zone: "UTC" 375 | # time-stamp-end: "; # UTC" 376 | # End: 377 | -------------------------------------------------------------------------------- /fx2pipe/oconfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oconfig.h 3 | * 4 | * Basic config header for FX2 pipe code. 5 | * 6 | * NOTE: This file must be included first by all other source code files. 7 | * 8 | * Copyright (c) 2006 by Wolfgang Wieser ] wwieser (a) gmx <*> de [ 9 | * 10 | * This file may be distributed and/or modified under the terms of the 11 | * GNU General Public License version 2 as published by the Free Software 12 | * Foundation. (See COPYING.GPL for details.) 13 | * 14 | * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 15 | * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 | * 17 | */ 18 | 19 | #ifndef _INCLUDE_FX2PIPE_OCONFIG_H_ 20 | #define _INCLUDE_FX2PIPE_OCONFIG_H_ 1 21 | 22 | #define QT_THREAD_SUPPORT 1 23 | 24 | // Include autoconf-generated config header: 25 | #include "config.h" 26 | 27 | #include 28 | #include /* for ssize_t... */ 29 | 30 | typedef u_int64_t uint64; 31 | typedef u_int32_t uint32; 32 | typedef u_int16_t uint16; 33 | typedef int64_t int64; 34 | typedef int32_t int32; 35 | typedef int16_t int16; 36 | 37 | // We need to define this for some linux flavours since sometimes 38 | // likely/unlikely are not part of system headers for non-kernel-compiles 39 | // although they are needed at certain other places... 40 | #define likely(x) (x) 41 | #define unlikely(x) (x) 42 | 43 | // Some basics... 44 | 45 | /// Operator delete which will do nothing for NULL pointers and set the passed 46 | /// pointer to NULL after deletion. 47 | template inline void DELETE(T* &ptr) 48 | { if(ptr) { delete ptr; ptr=NULL; } } 49 | 50 | #if 1 51 | # include 52 | #else 53 | /// Operator new with placement. 54 | inline void *operator new(size_t,void *ptr) 55 | { return(ptr); } 56 | #endif 57 | 58 | #endif /* _INCLUDE_FX2PIPE_OCONFIG_H_ */ 59 | -------------------------------------------------------------------------------- /fx2pipe/usb_io/Makefile.am: -------------------------------------------------------------------------------- 1 | INCLUDES = -I. -I$(top_srcdir) -I$(top_builddir) 2 | 3 | noinst_LIBRARIES = lib_usb_io.a 4 | lib_usb_io_a_SOURCES = \ 5 | wwusb.h wwusb.cc \ 6 | fx2usb.h fx2usb.cc \ 7 | urbcache.h urbcache.cc \ 8 | cycfx2dev.h cycfx2dev.cc 9 | -------------------------------------------------------------------------------- /fx2pipe/usb_io/Makefile.in: -------------------------------------------------------------------------------- 1 | # Makefile.in generated by automake 1.10.1 from Makefile.am. 2 | # @configure_input@ 3 | 4 | # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 5 | # 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. 6 | # This Makefile.in is free software; the Free Software Foundation 7 | # gives unlimited permission to copy and/or distribute it, 8 | # with or without modifications, as long as this notice is preserved. 9 | 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY, to the extent permitted by law; without 12 | # even the implied warranty of MERCHANTABILITY or FITNESS FOR A 13 | # PARTICULAR PURPOSE. 14 | 15 | @SET_MAKE@ 16 | 17 | VPATH = @srcdir@ 18 | pkgdatadir = $(datadir)/@PACKAGE@ 19 | pkglibdir = $(libdir)/@PACKAGE@ 20 | pkgincludedir = $(includedir)/@PACKAGE@ 21 | am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd 22 | install_sh_DATA = $(install_sh) -c -m 644 23 | install_sh_PROGRAM = $(install_sh) -c 24 | install_sh_SCRIPT = $(install_sh) -c 25 | INSTALL_HEADER = $(INSTALL_DATA) 26 | transform = $(program_transform_name) 27 | NORMAL_INSTALL = : 28 | PRE_INSTALL = : 29 | POST_INSTALL = : 30 | NORMAL_UNINSTALL = : 31 | PRE_UNINSTALL = : 32 | POST_UNINSTALL = : 33 | subdir = usb_io 34 | DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in 35 | ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 36 | am__aclocal_m4_deps = $(top_srcdir)/configure.ac 37 | am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ 38 | $(ACLOCAL_M4) 39 | mkinstalldirs = $(install_sh) -d 40 | CONFIG_HEADER = $(top_builddir)/config.h 41 | CONFIG_CLEAN_FILES = 42 | LIBRARIES = $(noinst_LIBRARIES) 43 | AR = ar 44 | ARFLAGS = cru 45 | lib_usb_io_a_AR = $(AR) $(ARFLAGS) 46 | lib_usb_io_a_LIBADD = 47 | am_lib_usb_io_a_OBJECTS = wwusb.$(OBJEXT) fx2usb.$(OBJEXT) \ 48 | urbcache.$(OBJEXT) cycfx2dev.$(OBJEXT) 49 | lib_usb_io_a_OBJECTS = $(am_lib_usb_io_a_OBJECTS) 50 | DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) 51 | depcomp = $(SHELL) $(top_srcdir)/depcomp 52 | am__depfiles_maybe = depfiles 53 | CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ 54 | $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) 55 | CXXLD = $(CXX) 56 | CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ 57 | -o $@ 58 | COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ 59 | $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) 60 | CCLD = $(CC) 61 | LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ 62 | SOURCES = $(lib_usb_io_a_SOURCES) 63 | DIST_SOURCES = $(lib_usb_io_a_SOURCES) 64 | ETAGS = etags 65 | CTAGS = ctags 66 | DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 67 | ACLOCAL = @ACLOCAL@ 68 | AMTAR = @AMTAR@ 69 | AUTOCONF = @AUTOCONF@ 70 | AUTOHEADER = @AUTOHEADER@ 71 | AUTOMAKE = @AUTOMAKE@ 72 | AWK = @AWK@ 73 | CC = @CC@ 74 | CCDEPMODE = @CCDEPMODE@ 75 | CFLAGS = @CFLAGS@ 76 | CPP = @CPP@ 77 | CPPFLAGS = @CPPFLAGS@ 78 | CXX = @CXX@ 79 | CXXDEPMODE = @CXXDEPMODE@ 80 | CXXFLAGS = @CXXFLAGS@ 81 | CYGPATH_W = @CYGPATH_W@ 82 | DEFS = @DEFS@ 83 | DEPDIR = @DEPDIR@ 84 | ECHO_C = @ECHO_C@ 85 | ECHO_N = @ECHO_N@ 86 | ECHO_T = @ECHO_T@ 87 | EGREP = @EGREP@ 88 | EXEEXT = @EXEEXT@ 89 | GREP = @GREP@ 90 | INSTALL = @INSTALL@ 91 | INSTALL_DATA = @INSTALL_DATA@ 92 | INSTALL_PROGRAM = @INSTALL_PROGRAM@ 93 | INSTALL_SCRIPT = @INSTALL_SCRIPT@ 94 | INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ 95 | LDFLAGS = @LDFLAGS@ 96 | LIBOBJS = @LIBOBJS@ 97 | LIBS = @LIBS@ 98 | LTLIBOBJS = @LTLIBOBJS@ 99 | MAKEINFO = @MAKEINFO@ 100 | MKDIR_P = @MKDIR_P@ 101 | OBJEXT = @OBJEXT@ 102 | PACKAGE = @PACKAGE@ 103 | PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ 104 | PACKAGE_NAME = @PACKAGE_NAME@ 105 | PACKAGE_STRING = @PACKAGE_STRING@ 106 | PACKAGE_TARNAME = @PACKAGE_TARNAME@ 107 | PACKAGE_VERSION = @PACKAGE_VERSION@ 108 | PATH_SEPARATOR = @PATH_SEPARATOR@ 109 | RANLIB = @RANLIB@ 110 | SET_MAKE = @SET_MAKE@ 111 | SHELL = @SHELL@ 112 | STRIP = @STRIP@ 113 | VERSION = @VERSION@ 114 | abs_builddir = @abs_builddir@ 115 | abs_srcdir = @abs_srcdir@ 116 | abs_top_builddir = @abs_top_builddir@ 117 | abs_top_srcdir = @abs_top_srcdir@ 118 | ac_ct_CC = @ac_ct_CC@ 119 | ac_ct_CXX = @ac_ct_CXX@ 120 | am__include = @am__include@ 121 | am__leading_dot = @am__leading_dot@ 122 | am__quote = @am__quote@ 123 | am__tar = @am__tar@ 124 | am__untar = @am__untar@ 125 | bindir = @bindir@ 126 | build_alias = @build_alias@ 127 | builddir = @builddir@ 128 | datadir = @datadir@ 129 | datarootdir = @datarootdir@ 130 | docdir = @docdir@ 131 | dvidir = @dvidir@ 132 | exec_prefix = @exec_prefix@ 133 | host_alias = @host_alias@ 134 | htmldir = @htmldir@ 135 | includedir = @includedir@ 136 | infodir = @infodir@ 137 | install_sh = @install_sh@ 138 | libdir = @libdir@ 139 | libexecdir = @libexecdir@ 140 | localedir = @localedir@ 141 | localstatedir = @localstatedir@ 142 | mandir = @mandir@ 143 | mkdir_p = @mkdir_p@ 144 | oldincludedir = @oldincludedir@ 145 | pdfdir = @pdfdir@ 146 | prefix = @prefix@ 147 | program_transform_name = @program_transform_name@ 148 | psdir = @psdir@ 149 | sbindir = @sbindir@ 150 | sharedstatedir = @sharedstatedir@ 151 | srcdir = @srcdir@ 152 | sysconfdir = @sysconfdir@ 153 | target_alias = @target_alias@ 154 | top_build_prefix = @top_build_prefix@ 155 | top_builddir = @top_builddir@ 156 | top_srcdir = @top_srcdir@ 157 | INCLUDES = -I. -I$(top_srcdir) -I$(top_builddir) 158 | noinst_LIBRARIES = lib_usb_io.a 159 | lib_usb_io_a_SOURCES = \ 160 | wwusb.h wwusb.cc \ 161 | fx2usb.h fx2usb.cc \ 162 | urbcache.h urbcache.cc \ 163 | cycfx2dev.h cycfx2dev.cc 164 | 165 | all: all-am 166 | 167 | .SUFFIXES: 168 | .SUFFIXES: .cc .o .obj 169 | $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) 170 | @for dep in $?; do \ 171 | case '$(am__configure_deps)' in \ 172 | *$$dep*) \ 173 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ 174 | && exit 0; \ 175 | exit 1;; \ 176 | esac; \ 177 | done; \ 178 | echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu usb_io/Makefile'; \ 179 | cd $(top_srcdir) && \ 180 | $(AUTOMAKE) --gnu usb_io/Makefile 181 | .PRECIOUS: Makefile 182 | Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status 183 | @case '$?' in \ 184 | *config.status*) \ 185 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ 186 | *) \ 187 | echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ 188 | cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ 189 | esac; 190 | 191 | $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) 192 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh 193 | 194 | $(top_srcdir)/configure: $(am__configure_deps) 195 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh 196 | $(ACLOCAL_M4): $(am__aclocal_m4_deps) 197 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh 198 | 199 | clean-noinstLIBRARIES: 200 | -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) 201 | lib_usb_io.a: $(lib_usb_io_a_OBJECTS) $(lib_usb_io_a_DEPENDENCIES) 202 | -rm -f lib_usb_io.a 203 | $(lib_usb_io_a_AR) lib_usb_io.a $(lib_usb_io_a_OBJECTS) $(lib_usb_io_a_LIBADD) 204 | $(RANLIB) lib_usb_io.a 205 | 206 | mostlyclean-compile: 207 | -rm -f *.$(OBJEXT) 208 | 209 | distclean-compile: 210 | -rm -f *.tab.c 211 | 212 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cycfx2dev.Po@am__quote@ 213 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fx2usb.Po@am__quote@ 214 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/urbcache.Po@am__quote@ 215 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wwusb.Po@am__quote@ 216 | 217 | .cc.o: 218 | @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< 219 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po 220 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ 221 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 222 | @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< 223 | 224 | .cc.obj: 225 | @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` 226 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po 227 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ 228 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 229 | @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` 230 | 231 | ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) 232 | list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ 233 | unique=`for i in $$list; do \ 234 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ 235 | done | \ 236 | $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ 237 | END { if (nonempty) { for (i in files) print i; }; }'`; \ 238 | mkid -fID $$unique 239 | tags: TAGS 240 | 241 | TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ 242 | $(TAGS_FILES) $(LISP) 243 | tags=; \ 244 | here=`pwd`; \ 245 | list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ 246 | unique=`for i in $$list; do \ 247 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ 248 | done | \ 249 | $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ 250 | END { if (nonempty) { for (i in files) print i; }; }'`; \ 251 | if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ 252 | test -n "$$unique" || unique=$$empty_fix; \ 253 | $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ 254 | $$tags $$unique; \ 255 | fi 256 | ctags: CTAGS 257 | CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ 258 | $(TAGS_FILES) $(LISP) 259 | tags=; \ 260 | list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ 261 | unique=`for i in $$list; do \ 262 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ 263 | done | \ 264 | $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ 265 | END { if (nonempty) { for (i in files) print i; }; }'`; \ 266 | test -z "$(CTAGS_ARGS)$$tags$$unique" \ 267 | || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ 268 | $$tags $$unique 269 | 270 | GTAGS: 271 | here=`$(am__cd) $(top_builddir) && pwd` \ 272 | && cd $(top_srcdir) \ 273 | && gtags -i $(GTAGS_ARGS) $$here 274 | 275 | distclean-tags: 276 | -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags 277 | 278 | distdir: $(DISTFILES) 279 | @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ 280 | topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ 281 | list='$(DISTFILES)'; \ 282 | dist_files=`for file in $$list; do echo $$file; done | \ 283 | sed -e "s|^$$srcdirstrip/||;t" \ 284 | -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ 285 | case $$dist_files in \ 286 | */*) $(MKDIR_P) `echo "$$dist_files" | \ 287 | sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ 288 | sort -u` ;; \ 289 | esac; \ 290 | for file in $$dist_files; do \ 291 | if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ 292 | if test -d $$d/$$file; then \ 293 | dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ 294 | if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ 295 | cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ 296 | fi; \ 297 | cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ 298 | else \ 299 | test -f $(distdir)/$$file \ 300 | || cp -p $$d/$$file $(distdir)/$$file \ 301 | || exit 1; \ 302 | fi; \ 303 | done 304 | check-am: all-am 305 | check: check-am 306 | all-am: Makefile $(LIBRARIES) 307 | installdirs: 308 | install: install-am 309 | install-exec: install-exec-am 310 | install-data: install-data-am 311 | uninstall: uninstall-am 312 | 313 | install-am: all-am 314 | @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am 315 | 316 | installcheck: installcheck-am 317 | install-strip: 318 | $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ 319 | install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ 320 | `test -z '$(STRIP)' || \ 321 | echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install 322 | mostlyclean-generic: 323 | 324 | clean-generic: 325 | 326 | distclean-generic: 327 | -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) 328 | 329 | maintainer-clean-generic: 330 | @echo "This command is intended for maintainers to use" 331 | @echo "it deletes files that may require special tools to rebuild." 332 | clean: clean-am 333 | 334 | clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am 335 | 336 | distclean: distclean-am 337 | -rm -rf ./$(DEPDIR) 338 | -rm -f Makefile 339 | distclean-am: clean-am distclean-compile distclean-generic \ 340 | distclean-tags 341 | 342 | dvi: dvi-am 343 | 344 | dvi-am: 345 | 346 | html: html-am 347 | 348 | info: info-am 349 | 350 | info-am: 351 | 352 | install-data-am: 353 | 354 | install-dvi: install-dvi-am 355 | 356 | install-exec-am: 357 | 358 | install-html: install-html-am 359 | 360 | install-info: install-info-am 361 | 362 | install-man: 363 | 364 | install-pdf: install-pdf-am 365 | 366 | install-ps: install-ps-am 367 | 368 | installcheck-am: 369 | 370 | maintainer-clean: maintainer-clean-am 371 | -rm -rf ./$(DEPDIR) 372 | -rm -f Makefile 373 | maintainer-clean-am: distclean-am maintainer-clean-generic 374 | 375 | mostlyclean: mostlyclean-am 376 | 377 | mostlyclean-am: mostlyclean-compile mostlyclean-generic 378 | 379 | pdf: pdf-am 380 | 381 | pdf-am: 382 | 383 | ps: ps-am 384 | 385 | ps-am: 386 | 387 | uninstall-am: 388 | 389 | .MAKE: install-am install-strip 390 | 391 | .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ 392 | clean-noinstLIBRARIES ctags distclean distclean-compile \ 393 | distclean-generic distclean-tags distdir dvi dvi-am html \ 394 | html-am info info-am install install-am install-data \ 395 | install-data-am install-dvi install-dvi-am install-exec \ 396 | install-exec-am install-html install-html-am install-info \ 397 | install-info-am install-man install-pdf install-pdf-am \ 398 | install-ps install-ps-am install-strip installcheck \ 399 | installcheck-am installdirs maintainer-clean \ 400 | maintainer-clean-generic mostlyclean mostlyclean-compile \ 401 | mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ 402 | uninstall-am 403 | 404 | # Tell versions [3.59,3.63) of GNU make to not export all variables. 405 | # Otherwise a system limit (for SysV at least) may be exceeded. 406 | .NOEXPORT: 407 | -------------------------------------------------------------------------------- /fx2pipe/usb_io/cycfx2dev.h: -------------------------------------------------------------------------------- 1 | /* 2 | * cycfx2dev.h - Cypress FX2 device class: low-level routines. 3 | * 4 | * Copyright (c) 2006--2009 by Wolfgang Wieser ] wwieser (a) gmx <*> de [ 5 | * 6 | * This file may be distributed and/or modified under the terms of the 7 | * GNU General Public License version 2 as published by the Free Software 8 | * Foundation. (See COPYING.GPL for details.) 9 | * 10 | * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 11 | * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 12 | * 13 | */ 14 | 15 | #ifndef _CYCFX2PROG_CYCFX2DEVICE_ 16 | #define _CYCFX2PROG_CYCFX2DEVICE_ 1 17 | 18 | #include 19 | 20 | 21 | extern struct usb_device *USBFindDevice(const char *bus,const char *dev); 22 | extern struct usb_device *USBFindDevice(int vendor,int product,int nth=0); 23 | 24 | 25 | class CypressFX2Device 26 | { 27 | private: 28 | struct usb_device *usbdev; 29 | struct usb_dev_handle *usbhdl; 30 | 31 | // Force a certail "alt" interface; -1 for none. 32 | int force_alt_interface; 33 | 34 | // Internally used: Program one line of an Intel HEX file. 35 | // The arguments path and line are just needed for error reporting. 36 | int _ProgramIHexLine(const char *buf,const char *path,int line); 37 | private: 38 | CypressFX2Device(const CypressFX2Device &); 39 | void operator=(const CypressFX2Device &); 40 | public: 41 | CypressFX2Device() 42 | { usbdev=NULL; usbhdl=NULL; force_alt_interface=-1; } 43 | ~CypressFX2Device() 44 | { close(); } 45 | 46 | // Is opened? 47 | inline bool IsOpen() const 48 | { return(usbhdl); } 49 | 50 | // Open usb device; will close previous one. 51 | // Returns 0 on success; 1 on error. Errors written to stderr. 52 | int open(struct usb_device *_usbdev); 53 | 54 | // Close device. Returns 0 on success. Errors written to stderr. 55 | int close(); 56 | 57 | // Read an intel hex file and download it. 58 | // Returns 0 on success; 1 on error. Errors written to stderr. 59 | int ProgramIHexFile(const char *path); 60 | // Like ProgramIHexFile() but Intel HEX is supplied as NULL-terminated 61 | // array of strings; each line of the hex file as string element. 62 | int ProgramStaticIHex(const char **ihex); 63 | // Read a flat binary file and download it. 64 | int ProgramBinFile(const char *path,size_t start_addr=0); 65 | // Download/write a chunk of ram into the device. 66 | int WriteRAM(size_t addr,const unsigned char *data,size_t nbytes); 67 | // Read a portion of ram from the device. 68 | int ReadRAM(size_t addr,unsigned char *data,size_t nbytes); 69 | 70 | // Put the Cypress FX2 into reset or release reset. 71 | // running=1 -> running; running=0 -> reset. 72 | int FX2Reset(bool running); 73 | 74 | // Read from endpoint. 75 | // type: 'b','B' -> bulk; 'i','I' -> interrupt 76 | // Capital letters mean that data may be shorter than expected. 77 | // endpoint must be address (like 0x86 for EP 6 in). 78 | // Returns number of read bytes. See source comment!! 79 | int BlockRead(int endpoint,unsigned char *buf,size_t nbytes, 80 | char type='b'); 81 | // Counterpart for BlockRead; type is 'b' or 'i' but not 'B'/'I'. 82 | int BlockWrite(int endpoint,const unsigned char *buf,size_t nbytes, 83 | char type='b'); 84 | // Returns number of written bytes. See source comment!! 85 | 86 | // Benchmark block (bulk/interrupt) reading. 87 | // type: 'b' -> bulk; 'i' -> interrupt 88 | // endpoint must be address (like 0x86 for EP 6 in). 89 | int BenchBlockRead(int endpoint,size_t nbytes,size_t chunk_size, 90 | char type='b'); 91 | 92 | // Set the alt interface to use at next block read/write. 93 | // Use -1 for automatic FX2-default values. 94 | int ForceAltInterface(int alt_if=-1) 95 | { force_alt_interface=alt_if; return(0); } 96 | 97 | // Send a USB control message. 98 | int CtrlMsg(unsigned char requesttype, 99 | unsigned char request,int value,int index, 100 | const unsigned char *ctl_buf=NULL,size_t ctl_buf_size=0); 101 | }; 102 | 103 | #endif /* _CYCFX2PROG_CYCFX2DEVICE_ */ 104 | -------------------------------------------------------------------------------- /fx2pipe/usb_io/fx2usb.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * usb_io/fx2usb.cc 3 | * 4 | * Low-level routines for data IO with Cypress FX2 chip. 5 | * 6 | * Copyright (c) 2006 by Wolfgang Wieser ] wwieser (a) gmx <*> de [ 7 | * 8 | * This file may be distributed and/or modified under the terms of the 9 | * GNU General Public License version 2 as published by the Free Software 10 | * Foundation. (See COPYING.GPL for details.) 11 | * 12 | * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 13 | * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 14 | * 15 | */ 16 | 17 | #include "../usb_io/fx2usb.h" 18 | #include "../usb_io/cycfx2dev.h" /* Needed for programming. */ 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | 26 | FX2USBDevice::ErrorCode FX2USBDevice::_DownloadFirmware( 27 | struct usb_device *usbdev,const char *path,const char **static_firmware, 28 | const char *cfg_buf,size_t cfg_len,size_t cfg_adr) 29 | { 30 | CypressFX2Device fx2dev; 31 | 32 | ErrorCode ec=ECFailure; 33 | do { 34 | if(fx2dev.open(usbdev)) break; 35 | 36 | // [none] means: Just reset. 37 | char what='n'; // none 38 | if(!path && static_firmware) what='b'; // builtin static firmware 39 | if(path && *path) what='f'; // file 40 | 41 | fprintf(stderr,"Downloading firmware %s%s%s...\n", 42 | what=='f' ? "\"" : "", 43 | what=='f' ? path : what=='b' ? "[builtin]" : "[none]", 44 | what=='f' ? "\"" : ""); 45 | 46 | if(fx2dev.FX2Reset(/*running=*/0)) break; 47 | 48 | if(what=='f' && fx2dev.ProgramIHexFile(path)) break; 49 | else if(what=='b' && fx2dev.ProgramStaticIHex(static_firmware)) break; 50 | 51 | if(cfg_buf && 52 | fx2dev.WriteRAM(cfg_adr,(const uchar*)cfg_buf,cfg_len)) break; 53 | 54 | if(fx2dev.FX2Reset(/*running=*/1)) break; 55 | 56 | ec=ECSuccess; 57 | } while(0); 58 | 59 | // Important: Close device again since we need to re-open it using 60 | // our own code. 61 | if(fx2dev.close()) 62 | { ec=ECFailure; } 63 | 64 | if(ec) 65 | { 66 | // FIXME: We should be a bit more precise here... 67 | fprintf(stderr,"Failed to connect FX2 and download firmware.\n"); 68 | } 69 | 70 | return(ec); 71 | } 72 | 73 | 74 | FX2USBDevice::ErrorCode FX2USBDevice::_connect( 75 | struct usb_device *fx2_dev, 76 | const char *firmware_path,const char **static_firmware, 77 | const char *cfg_buf,size_t cfg_len,size_t cfg_adr) 78 | { 79 | if(!fx2_dev) 80 | { 81 | fprintf(stderr,"Device not attached to USB.\n"); 82 | return(ECNoSuchDevice); 83 | } 84 | 85 | char *bus = strdup(fx2_dev->bus->dirname); 86 | char *dev = strdup(fx2_dev->filename); 87 | if(!bus || !dev) 88 | { return(ECFailure); } 89 | 90 | ErrorCode ec=_DownloadFirmware(fx2_dev,firmware_path,static_firmware, 91 | cfg_buf,cfg_len, cfg_adr); 92 | if(ec) 93 | { 94 | free(bus); 95 | free(dev); 96 | return(ec); 97 | } 98 | 99 | // Wait some time for FX2 CPU initialization and maybe re-numeration. 100 | // FIXME: Maybe this is not enough. 101 | usleep(10000); 102 | 103 | // Re-connect using bus and device paths since these should not change. 104 | // FIXME: These DO change if the firmware renumerates (which the 105 | // built-in fx2pipe firmware does not). So, this works only for 106 | // firmware which does not renumerate. 107 | ec=WWUSBDevice::connect(bus,dev); 108 | free(bus); 109 | free(dev); 110 | if(ec) 111 | { 112 | fprintf(stderr,"Failed to re-connect to (configured) FX2 (ec=%d)\n",ec); 113 | return(ec); 114 | } 115 | 116 | return(ECSuccess); 117 | } 118 | 119 | 120 | FX2USBDevice::ErrorCode FX2USBDevice::connect( 121 | int initial_vendor,int initial_product,int n_th, 122 | const char *firmware_path,const char **static_firmware, 123 | const char *cfg_buf,size_t cfg_len,size_t cfg_adr) 124 | { 125 | // Be sure not to be connected. 126 | disconnect(); 127 | 128 | // *** Connect for the first time. *** 129 | struct usb_device *fx2_dev=NULL; 130 | if(initial_vendor>=0 && initial_product>=0) 131 | { fx2_dev=USBFindDevice(/*vendor=*/initial_vendor, 132 | /*product=*/initial_product,n_th); } 133 | // Search for unconfigured FX2: 134 | else 135 | { fx2_dev=USBFindDevice(/*vendor=*/0x04b4,/*product=*/0x8613,n_th); } 136 | 137 | return(_connect(fx2_dev, 138 | firmware_path,static_firmware, 139 | cfg_buf,cfg_len,cfg_adr)); 140 | } 141 | 142 | FX2USBDevice::ErrorCode FX2USBDevice::connect( 143 | const char *bus,const char *dev, 144 | const char *firmware_path,const char **static_firmware, 145 | const char *cfg_buf,size_t cfg_len,size_t cfg_adr) 146 | { 147 | // Be sure not to be connected. 148 | disconnect(); 149 | 150 | // *** Connect for the first time. *** 151 | struct usb_device *fx2_dev=USBFindDevice(bus,dev); 152 | 153 | return(_connect(fx2_dev, 154 | firmware_path,static_firmware, 155 | cfg_buf,cfg_len,cfg_adr)); 156 | } 157 | 158 | 159 | FX2USBDevice::FX2USBDevice() : 160 | WWUSBDevice() 161 | { 162 | } 163 | 164 | FX2USBDevice::~FX2USBDevice() 165 | { 166 | } 167 | -------------------------------------------------------------------------------- /fx2pipe/usb_io/fx2usb.h: -------------------------------------------------------------------------------- 1 | /* 2 | * usb_io/fx2usb.h 3 | * 4 | * Low-level routines for data IO with Cypress FX2 chip. 5 | * 6 | * Copyright (c) 2006 by Wolfgang Wieser ] wwieser (a) gmx <*> de [ 7 | * 8 | * This file may be distributed and/or modified under the terms of the 9 | * GNU General Public License version 2 as published by the Free Software 10 | * Foundation. (See COPYING.GPL for details.) 11 | * 12 | * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 13 | * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 14 | * 15 | */ 16 | 17 | #ifndef _INCLUDE_USBIO_FX2USB_H_ 18 | #define _INCLUDE_USBIO_FX2USB_H_ 1 19 | 20 | #include "../oconfig.h" 21 | #include "../usb_io/wwusb.h" 22 | 23 | 24 | /** 25 | * \short FX2 USB Device representation. 26 | * \author Wolfgang Wieser ] wwieser (a) gmx <*> de [ 27 | * 28 | * Derived from WWUSBDevice; provides a simple extension for certain 29 | * things like firmware downloading. 30 | */ 31 | class FX2USBDevice : public WWUSBDevice 32 | { 33 | private: 34 | 35 | /// Internally used by connect() to download firmware. 36 | ErrorCode _DownloadFirmware(struct usb_device *usbdev,const char *path, 37 | const char **static_firmware, 38 | const char *cfg_buf,size_t cfg_len,size_t cfg_adr); 39 | /// Internally used by connect(). 40 | ErrorCode _connect( 41 | struct usb_device *fx2_dev, 42 | const char *firmware_path,const char **static_firmware, 43 | const char *cfg_buf,size_t cfg_len,size_t cfg_adr); 44 | private: 45 | /// Do not use. 46 | void operator=(const FX2USBDevice &); 47 | /// Do not use. 48 | FX2USBDevice(const FX2USBDevice &); 49 | public: 50 | /// Create not-set-up FX2 device. 51 | FX2USBDevice(); 52 | /// Destructor... 53 | virtual ~FX2USBDevice(); 54 | 55 | /** 56 | * \short Connect to FX2 and dowload firmware. 57 | * 58 | * NOTE: When connecting an FX2 device, do not use one of the 59 | * connect() calls from WWUSBDevice. Instead use this one. 60 | * 61 | * This will first find the FX2 device to use, download the firmware, 62 | * disconnect [to give the FX2 a chance for its re-numeration which is 63 | * probably pointless in this case] and then connect again. 64 | * 65 | * Step-by-step: 66 | * 67 | * Will first trigger a disconnect() first to be sure. 68 | * 69 | * Then, will look for a device with vendor and product IDs 70 | * initial_vendor,initial_product or (if not found) for an 71 | * unconfigured FX2. (Use -1,-1 to switch off.) 72 | * Actually, the code will look for the n_th match; use 0 for the 73 | * first device, 1 for the second, etc. 74 | * 75 | * Then, will connect, download firmware and disconnect. 76 | * The firmware is taken from the file firmware_path which must be 77 | * an Intel HEX file. If firmware_path is NULL, an alternate 78 | * firmware can be specified as static_firmware which is a 79 | * NULL-terminated array of strings; each element being one line of an 80 | * Intel HEX file. If firmware_path is an empty string, no firmware 81 | * will be downloaded. 82 | * 83 | * You can pass an additional config in cfg_buf of size cfg_len 84 | * which will be put at address cfg_adr before taking the FX2 out 85 | * of the reset. If unused, use NULL,0,0. 86 | * 87 | * Then, will connect to the device again. We use bus and device 88 | * paths ("IDs") since these will not change even if the USB IDs 89 | * change due to re-numeration. 90 | * 91 | * Errors are written to stderr. 92 | */ 93 | ErrorCode connect(int initial_vendor,int initial_product,int n_th, 94 | const char *firmware_path,const char **static_firmware, 95 | const char *cfg_buf,size_t cfg_len,size_t cfg_adr); 96 | ErrorCode connect( 97 | const char *bus,const char *dev, 98 | const char *firmware_path,const char **static_firmware, 99 | const char *cfg_buf,size_t cfg_len,size_t cfg_adr); 100 | }; 101 | 102 | #endif /* _INCLUDE_USBIO_FX2USB_H_ */ 103 | -------------------------------------------------------------------------------- /fx2pipe/usb_io/urbcache.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * usb_io/urbcache.cc 3 | * 4 | * URB cache class. 5 | * 6 | * Copyright (c) 2006 by Wolfgang Wieser ] wwieser (a) gmx <*> de [ 7 | * 8 | * This file may be distributed and/or modified under the terms of the 9 | * GNU General Public License version 2 as published by the Free Software 10 | * Foundation. (See COPYING.GPL for details.) 11 | * 12 | * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 13 | * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 14 | * 15 | */ 16 | 17 | #include "urbcache.h" 18 | 19 | #include 20 | 21 | 22 | void URBCache::_size_oops() 23 | { 24 | assert(0); 25 | } 26 | 27 | 28 | void *URBCache::_GetAlloc() 29 | { 30 | void *ptr=malloc(elem_size); 31 | if(!ptr) 32 | { fprintf(stderr,"URB alloc failire\n"); abort(); } 33 | return(ptr); 34 | } 35 | 36 | 37 | void URBCache::clear() 38 | { 39 | for(int i=0; i de [ 7 | * 8 | * This file may be distributed and/or modified under the terms of the 9 | * GNU General Public License version 2 as published by the Free Software 10 | * Foundation. (See COPYING.GPL for details.) 11 | * 12 | * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 13 | * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 14 | * 15 | */ 16 | 17 | #ifndef _INCLUDE_FX2PIPE_USBIO_URBCACHE_H_ 18 | #define _INCLUDE_FX2PIPE_USBIO_URBCACHE_H_ 1 19 | 20 | #include "../oconfig.h" 21 | #include "../lib/linkedlist.h" 22 | 23 | #include 24 | 25 | 26 | /** 27 | * \short User request block cache. 28 | * \author Wolfgang Wieser ] wwieser (a) gmx <*> de [ 29 | * 30 | * This is a generic memory chunk chache for equally-sized memory 31 | * chunks. 32 | * 33 | * It has a size limit and get() and put() statements which use 34 | * normal libc-malloc/free (de)allocation if limits are exceeded. 35 | * 36 | * Not thread-safe. Not "C++-safe". 37 | */ 38 | class URBCache 39 | { 40 | private: 41 | /// Max number of elements to store. 42 | int stack_size; 43 | /// Index of next free element on stack; 0 if empty. 44 | int top_idx; 45 | /// Stack of elements; array of size stack_size. 46 | void **stack; 47 | /// Size of each element just for enforcing equal sizes. 48 | /// This is only needed to enforce that get() and put() are 49 | /// dealing with equally-sized memory chunks all the time... 50 | size_t elem_size; 51 | 52 | /// Slow path of the get() operation. 53 | void *_GetAlloc(); 54 | /// Internally used; see get(), put(). 55 | void _size_oops(); 56 | 57 | private: 58 | /// Do not use. 59 | void operator=(const URBCache &); 60 | /// Do not use. 61 | URBCache(const URBCache &); 62 | 63 | public: 64 | /** 65 | * \short Create an URB cache. 66 | * 67 | * The cache will store at most max_elem URBs. 68 | * Each URB must have the size elem_size. 69 | */ 70 | URBCache(int max_elem,size_t _elem_size); 71 | /// Destructor will free all elements in the free list. 72 | ~URBCache(); 73 | 74 | /// Clear the cache freeing all elements. 75 | void clear(); 76 | 77 | /// Get a memory chunk of passed size which must match elem_size. 78 | inline void *get(size_t size) 79 | { 80 | if(size>elem_size) _size_oops(); 81 | return(top_idx ? stack[--top_idx] : _GetAlloc()); 82 | } 83 | 84 | /// Put back ("free") memory chunk; passed size must match again... 85 | inline void put(void *ptr,size_t size) 86 | { 87 | if(size>elem_size) _size_oops(); 88 | if(top_idx 34 | #include 35 | 36 | /* --------------------------------------------------------------------- */ 37 | 38 | /* usbdevfs ioctl codes */ 39 | 40 | struct usbdevfs_ctrltransfer { 41 | __u8 bRequestType; 42 | __u8 bRequest; 43 | __u16 wValue; 44 | __u16 wIndex; 45 | __u16 wLength; 46 | __u32 timeout; /* in milliseconds */ 47 | void *data; 48 | }; 49 | 50 | struct usbdevfs_bulktransfer { 51 | unsigned int ep; 52 | unsigned int len; 53 | unsigned int timeout; /* in milliseconds */ 54 | void *data; 55 | }; 56 | 57 | struct usbdevfs_setinterface { 58 | unsigned int interface; 59 | unsigned int altsetting; 60 | }; 61 | 62 | struct usbdevfs_disconnectsignal { 63 | unsigned int signr; 64 | void *context; 65 | }; 66 | 67 | #define USBDEVFS_MAXDRIVERNAME 255 68 | 69 | struct usbdevfs_getdriver { 70 | unsigned int interface; 71 | char driver[USBDEVFS_MAXDRIVERNAME + 1]; 72 | }; 73 | 74 | struct usbdevfs_connectinfo { 75 | unsigned int devnum; 76 | unsigned char slow; 77 | }; 78 | 79 | struct usbdevfs_conninfo_ex { 80 | __u32 size; /* Size of the structure from the kernel's */ 81 | /* point of view. Can be used by userspace */ 82 | /* to determine how much data can be */ 83 | /* used/trusted. */ 84 | __u32 busnum; /* USB bus number, as enumerated by the */ 85 | /* kernel, the device is connected to. */ 86 | __u32 devnum; /* Device address on the bus. */ 87 | __u32 speed; /* USB_SPEED_* constants from ch9.h */ 88 | __u8 num_ports; /* Number of ports the device is connected */ 89 | /* to on the way to the root hub. It may */ 90 | /* be bigger than size of 'ports' array so */ 91 | /* userspace can detect overflows. */ 92 | __u8 ports[7]; /* List of ports on the way from the root */ 93 | /* hub to the device. Current limit in */ 94 | /* USB specification is 7 tiers (root hub, */ 95 | /* 5 intermediate hubs, device), which */ 96 | /* gives at most 6 port entries. */ 97 | }; 98 | 99 | #define USBDEVFS_URB_SHORT_NOT_OK 0x01 100 | #define USBDEVFS_URB_ISO_ASAP 0x02 101 | #define USBDEVFS_URB_BULK_CONTINUATION 0x04 102 | #define USBDEVFS_URB_NO_FSBR 0x20 /* Not used */ 103 | #define USBDEVFS_URB_ZERO_PACKET 0x40 104 | #define USBDEVFS_URB_NO_INTERRUPT 0x80 105 | 106 | #define USBDEVFS_URB_TYPE_ISO 0 107 | #define USBDEVFS_URB_TYPE_INTERRUPT 1 108 | #define USBDEVFS_URB_TYPE_CONTROL 2 109 | #define USBDEVFS_URB_TYPE_BULK 3 110 | 111 | struct usbdevfs_iso_packet_desc { 112 | unsigned int length; 113 | unsigned int actual_length; 114 | unsigned int status; 115 | }; 116 | 117 | struct usbdevfs_urb { 118 | unsigned char type; 119 | unsigned char endpoint; 120 | int status; 121 | unsigned int flags; 122 | void *buffer; 123 | int buffer_length; 124 | int actual_length; 125 | int start_frame; 126 | union { 127 | int number_of_packets; /* Only used for isoc urbs */ 128 | unsigned int stream_id; /* Only used with bulk streams */ 129 | }; 130 | int error_count; 131 | unsigned int signr; /* signal to be sent on completion, 132 | or 0 if none should be sent. */ 133 | void *usercontext; 134 | struct usbdevfs_iso_packet_desc iso_frame_desc[0]; 135 | }; 136 | 137 | /* ioctls for talking directly to drivers */ 138 | struct usbdevfs_ioctl { 139 | int ifno; /* interface 0..N ; negative numbers reserved */ 140 | int ioctl_code; /* MUST encode size + direction of data so the 141 | * macros in give correct values */ 142 | void *data; /* param buffer (in, or out) */ 143 | }; 144 | 145 | /* You can do most things with hubs just through control messages, 146 | * except find out what device connects to what port. */ 147 | struct usbdevfs_hub_portinfo { 148 | char nports; /* number of downstream ports in this hub */ 149 | char port [127]; /* e.g. port 3 connects to device 27 */ 150 | }; 151 | 152 | /* System and bus capability flags */ 153 | #define USBDEVFS_CAP_ZERO_PACKET 0x01 154 | #define USBDEVFS_CAP_BULK_CONTINUATION 0x02 155 | #define USBDEVFS_CAP_NO_PACKET_SIZE_LIM 0x04 156 | #define USBDEVFS_CAP_BULK_SCATTER_GATHER 0x08 157 | #define USBDEVFS_CAP_REAP_AFTER_DISCONNECT 0x10 158 | #define USBDEVFS_CAP_MMAP 0x20 159 | #define USBDEVFS_CAP_DROP_PRIVILEGES 0x40 160 | #define USBDEVFS_CAP_CONNINFO_EX 0x80 161 | #define USBDEVFS_CAP_SUSPEND 0x100 162 | 163 | /* USBDEVFS_DISCONNECT_CLAIM flags & struct */ 164 | 165 | /* disconnect-and-claim if the driver matches the driver field */ 166 | #define USBDEVFS_DISCONNECT_CLAIM_IF_DRIVER 0x01 167 | /* disconnect-and-claim except when the driver matches the driver field */ 168 | #define USBDEVFS_DISCONNECT_CLAIM_EXCEPT_DRIVER 0x02 169 | 170 | struct usbdevfs_disconnect_claim { 171 | unsigned int interface; 172 | unsigned int flags; 173 | char driver[USBDEVFS_MAXDRIVERNAME + 1]; 174 | }; 175 | 176 | struct usbdevfs_streams { 177 | unsigned int num_streams; /* Not used by USBDEVFS_FREE_STREAMS */ 178 | unsigned int num_eps; 179 | unsigned char eps[]; 180 | }; 181 | 182 | /* 183 | * USB_SPEED_* values returned by USBDEVFS_GET_SPEED are defined in 184 | * linux/usb/ch9.h 185 | */ 186 | 187 | #define USBDEVFS_CONTROL _IOWR('U', 0, struct usbdevfs_ctrltransfer) 188 | #define USBDEVFS_CONTROL32 _IOWR('U', 0, struct usbdevfs_ctrltransfer32) 189 | #define USBDEVFS_BULK _IOWR('U', 2, struct usbdevfs_bulktransfer) 190 | #define USBDEVFS_BULK32 _IOWR('U', 2, struct usbdevfs_bulktransfer32) 191 | #define USBDEVFS_RESETEP _IOR('U', 3, unsigned int) 192 | #define USBDEVFS_SETINTERFACE _IOR('U', 4, struct usbdevfs_setinterface) 193 | #define USBDEVFS_SETCONFIGURATION _IOR('U', 5, unsigned int) 194 | #define USBDEVFS_GETDRIVER _IOW('U', 8, struct usbdevfs_getdriver) 195 | #define USBDEVFS_SUBMITURB _IOR('U', 10, struct usbdevfs_urb) 196 | #define USBDEVFS_SUBMITURB32 _IOR('U', 10, struct usbdevfs_urb32) 197 | #define USBDEVFS_DISCARDURB _IO('U', 11) 198 | #define USBDEVFS_REAPURB _IOW('U', 12, void *) 199 | #define USBDEVFS_REAPURB32 _IOW('U', 12, __u32) 200 | #define USBDEVFS_REAPURBNDELAY _IOW('U', 13, void *) 201 | #define USBDEVFS_REAPURBNDELAY32 _IOW('U', 13, __u32) 202 | #define USBDEVFS_DISCSIGNAL _IOR('U', 14, struct usbdevfs_disconnectsignal) 203 | #define USBDEVFS_DISCSIGNAL32 _IOR('U', 14, struct usbdevfs_disconnectsignal32) 204 | #define USBDEVFS_CLAIMINTERFACE _IOR('U', 15, unsigned int) 205 | #define USBDEVFS_RELEASEINTERFACE _IOR('U', 16, unsigned int) 206 | #define USBDEVFS_CONNECTINFO _IOW('U', 17, struct usbdevfs_connectinfo) 207 | #define USBDEVFS_IOCTL _IOWR('U', 18, struct usbdevfs_ioctl) 208 | #define USBDEVFS_IOCTL32 _IOWR('U', 18, struct usbdevfs_ioctl32) 209 | #define USBDEVFS_HUB_PORTINFO _IOR('U', 19, struct usbdevfs_hub_portinfo) 210 | #define USBDEVFS_RESET _IO('U', 20) 211 | #define USBDEVFS_CLEAR_HALT _IOR('U', 21, unsigned int) 212 | #define USBDEVFS_DISCONNECT _IO('U', 22) 213 | #define USBDEVFS_CONNECT _IO('U', 23) 214 | #define USBDEVFS_CLAIM_PORT _IOR('U', 24, unsigned int) 215 | #define USBDEVFS_RELEASE_PORT _IOR('U', 25, unsigned int) 216 | #define USBDEVFS_GET_CAPABILITIES _IOR('U', 26, __u32) 217 | #define USBDEVFS_DISCONNECT_CLAIM _IOR('U', 27, struct usbdevfs_disconnect_claim) 218 | #define USBDEVFS_ALLOC_STREAMS _IOR('U', 28, struct usbdevfs_streams) 219 | #define USBDEVFS_FREE_STREAMS _IOR('U', 29, struct usbdevfs_streams) 220 | #define USBDEVFS_DROP_PRIVILEGES _IOW('U', 30, __u32) 221 | #define USBDEVFS_GET_SPEED _IO('U', 31) 222 | /* 223 | * Returns struct usbdevfs_conninfo_ex; length is variable to allow 224 | * extending size of the data returned. 225 | */ 226 | #define USBDEVFS_CONNINFO_EX(len) _IOC(_IOC_READ, 'U', 32, len) 227 | #define USBDEVFS_FORBID_SUSPEND _IO('U', 33) 228 | #define USBDEVFS_ALLOW_SUSPEND _IO('U', 34) 229 | #define USBDEVFS_WAIT_FOR_RESUME _IO('U', 35) 230 | 231 | #endif /* _LINUX_USBDEVICE_FS_H */ 232 | -------------------------------------------------------------------------------- /fx2pipe/usb_io/wwusb.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * usb_io/wwusb.cc 3 | * 4 | * USB async low-level routines. 5 | * 6 | * Copyright (c) 2006 by Wolfgang Wieser ] wwieser (a) gmx <*> de [ 7 | * 8 | * The idea behind this code is inspired from fusb_linux.cc from the GNU 9 | * radio project (Copyright 2003 Free Software Foundation, Inc.) and the 10 | * first version of the code was based on it. 11 | * However, this is a major re-write for the second version. 12 | * 13 | * This file may be distributed and/or modified under the terms of the 14 | * GNU General Public License version 2 as published by the Free Software 15 | * Foundation. (See COPYING.GPL for details.) 16 | * 17 | * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 18 | * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 | * 20 | */ 21 | 22 | #include "wwusb.h" 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | // Initialize static data: 32 | int WWUSBDevice::URB::urb_serial_counter=1; 33 | 34 | #define DEBUG_ASYNC_IO 0 35 | 36 | 37 | // Totally evil and fragile extraction of file descriptor from 38 | // guts of libusb. They don't install usbi.h, which is what we'd need 39 | // to do this nicely. 40 | // 41 | // FIXME if everything breaks someday in the future, look here... 42 | static inline int fd_from_usb_dev_handle(usb_dev_handle *udh) 43 | { 44 | return( *((int*)udh) ); 45 | } 46 | 47 | // This function is from SSRP: Actually, we don't need it any more. 48 | // Danger, big, fragile KLUDGE. The problem is that we want to be 49 | // able to get from a usb_dev_handle back to a usb_device, and the 50 | // right way to do this is buried in a non-installed include file. 51 | static inline struct usb_device *dev_handle_to_dev(usb_dev_handle *udh) 52 | { 53 | struct usb_dev_handle_kludge { 54 | int fd; 55 | struct usb_bus *bus; 56 | struct usb_device *device; 57 | }; 58 | 59 | return(((struct usb_dev_handle_kludge *) udh)->device); 60 | } 61 | 62 | //============================================================================== 63 | 64 | struct usb_device *WWUSBDevice::USBFindDevice(int vendor,int product,int nth) 65 | { 66 | // We re-scan now to make sure not to miss devices which were plugged 67 | // in in the meantime... 68 | // FIXME: The only problem is that this may make our udev pointer invalid 69 | // if the corresponding device was unplugged in the mean time (?). 70 | // You may see crashes here... 71 | usb_find_busses(); 72 | usb_find_devices(); 73 | 74 | for(usb_bus *b=usb_busses; b; b=b->next) 75 | { 76 | for(struct usb_device *d=b->devices; d; d=d->next) 77 | { 78 | if(d->descriptor.idVendor==vendor && 79 | d->descriptor.idProduct==product ) 80 | { 81 | if(!nth--) 82 | { return(d); } 83 | } 84 | } 85 | } 86 | 87 | return(NULL); 88 | } 89 | 90 | struct usb_device *WWUSBDevice::USBFindDevice(const char *bus,const char *dev) 91 | { 92 | // We re-scan now to make sure not to miss devices which were plugged 93 | // in in the meantime... 94 | ::usb_find_busses(); 95 | ::usb_find_devices(); 96 | 97 | for(usb_bus *b=usb_busses; b; b=b->next) 98 | { 99 | if(strcmp(b->dirname,bus)) continue; 100 | for(struct usb_device *d=b->devices; d; d=d->next) 101 | { 102 | if(strcmp(d->filename,dev)) continue; 103 | return(d); 104 | } 105 | } 106 | 107 | return(NULL); 108 | } 109 | 110 | //============================================================================== 111 | 112 | WWUSBDevice::ErrorCode WWUSBDevice::_ErrorCodeRV(int e) 113 | { 114 | assert(e>=0); 115 | return((ErrorCode)e); 116 | } 117 | 118 | 119 | WWUSBDevice::ErrorCode WWUSBDevice::_DoConnect(struct usb_device *d) 120 | { 121 | if(udev || udh) 122 | { return(ECConnected); } 123 | 124 | udev=d; 125 | udh=::usb_open(udev); 126 | if(!udh) 127 | { udev=NULL; return(_ErrorCodeRV(errno)); } 128 | 129 | assert(dev_handle_to_dev(udh)==udev); 130 | 131 | return(ECSuccess); 132 | } 133 | 134 | 135 | WWUSBDevice::ErrorCode WWUSBDevice::connect(int vendor,int product,int nth) 136 | { 137 | if(udev || udh) 138 | { return(ECConnected); } 139 | 140 | struct usb_device *ud=USBFindDevice(vendor,product,nth); 141 | if(!ud) 142 | { return(ECNoSuchDevice); } 143 | 144 | return(_DoConnect(ud)); 145 | } 146 | 147 | 148 | WWUSBDevice::ErrorCode WWUSBDevice::connect(const char *bus,const char *dev) 149 | { 150 | if(udev || udh) 151 | { return(ECConnected); } 152 | 153 | struct usb_device *ud=USBFindDevice(bus,dev); 154 | if(!ud) 155 | { return(ECNoSuchDevice); } 156 | 157 | return(_DoConnect(ud)); 158 | } 159 | 160 | 161 | WWUSBDevice::ErrorCode WWUSBDevice::claim(int interface,int alt_interface) 162 | { 163 | if(!udh) 164 | { return(ECNotConnected); } 165 | 166 | if(interface>=0) 167 | { 168 | if(::usb_claim_interface(udh,/*interface=*/interface)<0) 169 | { return(_ErrorCodeRV(errno)); } 170 | } 171 | 172 | if(alt_interface>=0) 173 | { 174 | if(::usb_set_altinterface(udh,/*alt_interface=*/alt_interface)<0) 175 | { return(_ErrorCodeRV(errno)); } 176 | } 177 | 178 | return(ECSuccess); 179 | } 180 | 181 | 182 | void WWUSBDevice::CancelAllPendingURBs(bool also_delete) 183 | { 184 | int cnt=0; 185 | for(URB *_u=pending.last(); _u; cnt++) 186 | { 187 | URB *u=_u; 188 | _u=_u->prev; 189 | 190 | ErrorCode ec=_CancelURB(u); 191 | // We get errno=EINVAL when cancelling an URB which is already 192 | // completed but not yet reaped. Ignore that. 193 | if(ec && ec!=EINVAL) 194 | { 195 | fprintf(stderr,"Failed to cancel URB: ec=%d (%s)\n", 196 | ec,strerror(ec)); 197 | // In case we get ENODEV (after a hot disconnect), the 198 | // URB was already killed in kernel space. 199 | if(ec==ENODEV) 200 | { 201 | pending.dequeue(u); 202 | --npending; 203 | DeleteURB(u); 204 | } 205 | } 206 | } 207 | 208 | if(cnt) 209 | { fprintf(stderr,"Cancelled %d pending URBs (npending=%d)%s", 210 | cnt,npending,(also_delete && udh) ? ", reaping..." : "\n"); } 211 | 212 | if(also_delete && udh) 213 | { 214 | // Reap as much as we can. 215 | int nreap=0; 216 | for(;;) 217 | { 218 | ErrorCode ec=ECSuccess; 219 | URB *u=_ReapURB(&ec,/*may_wait=*/0); 220 | if(u) 221 | { ++nreap; continue; } 222 | if(ec==ECNoURBAvail) break; 223 | // In all other cases, we break as well. Most notably 224 | // when we get ECNotConnected... 225 | break; 226 | } 227 | 228 | if(cnt) 229 | { fprintf(stderr," done reaping (%d): npending=%d\n", 230 | nreap,npending); } 231 | } 232 | 233 | if(also_delete) 234 | { assert(npending==0); } 235 | } 236 | 237 | 238 | WWUSBDevice::ErrorCode WWUSBDevice::disconnect() 239 | { 240 | // Cancel everything, free requests, close everything... 241 | CancelAllPendingURBs(/*also_delete=*/1); 242 | 243 | if(udh) 244 | { ::usb_close(udh); udh=NULL; } 245 | udev=NULL; 246 | 247 | return(ECSuccess); 248 | } 249 | 250 | 251 | WWUSBDevice::ErrorCode WWUSBDevice::_SubmitURB(URB *u) 252 | { 253 | #if DEBUG_ASYNC_IO 254 | fprintf(stderr,"S(%d) ",u->urb_serial); 255 | #endif 256 | 257 | usbdevfs_urb *dev_u=u; 258 | u->usercontext=u; // <-- This is just some "magic" for checks... 259 | int rv=ioctl(fd_from_usb_dev_handle(udh),USBDEVFS_SUBMITURB,dev_u); 260 | if(rv<0) 261 | { return(_ErrorCodeRV(errno)); } 262 | 263 | pending.append(u); 264 | ++npending; 265 | //fprintf(stderr,"<<%d>>",npending); 266 | 267 | return(ECSuccess); 268 | } 269 | 270 | 271 | WWUSBDevice::ErrorCode WWUSBDevice::_CancelURB(URB *u) 272 | { 273 | #if DEBUG_ASYNC_IO 274 | fprintf(stderr,"C(%d) ",u->urb_serial); 275 | #endif 276 | 277 | if(u->cancelled==2) return(ECSuccess); 278 | 279 | usbdevfs_urb *dev_u=u; 280 | int rv=ioctl(fd_from_usb_dev_handle(udh),USBDEVFS_DISCARDURB,dev_u); 281 | if(rv<0) 282 | { 283 | u->cancelled=1; 284 | return(_ErrorCodeRV(errno)); 285 | } 286 | 287 | u->cancelled=2; 288 | return(ECSuccess); 289 | } 290 | 291 | 292 | WWUSBDevice::URB *WWUSBDevice::_ReapURB(ErrorCode *ec_rv,bool may_wait) 293 | { 294 | int fd=fd_from_usb_dev_handle(udh); 295 | usbdevfs_urb *dev_u=NULL; 296 | int reap_rv = may_wait ? 297 | ioctl(fd,USBDEVFS_REAPURB,&dev_u) : 298 | ioctl(fd,USBDEVFS_REAPURBNDELAY,&dev_u); 299 | int errn=errno; 300 | 301 | if(reap_rv<0) 302 | { 303 | if(errn==EAGAIN) 304 | { 305 | // Currently no URB to reap available. 306 | *ec_rv=ECNoURBAvail; 307 | } 308 | else if(errn==ENODEV) 309 | { 310 | fprintf(stderr,"USB hot disconnect... What'chew doin' dude?\n"); 311 | *ec_rv=ECNotConnected; 312 | } 313 | else 314 | { 315 | *ec_rv=_ErrorCodeRV(errn); 316 | fprintf(stderr,"reap_rv=%d, errno=%s\n",reap_rv,strerror(errn)); 317 | } 318 | return(NULL); 319 | } 320 | 321 | assert(dev_u); 322 | URB *u=static_cast(dev_u); 323 | assert(u->usercontext==u); // <-- Here's the magic check. 324 | 325 | // If this assert fails, you probably messed around with libusb... 326 | assert(pending.search(u)); 327 | pending.dequeue(u); 328 | --npending; assert(npending>=0); 329 | 330 | #if DEBUG_ASYNC_IO 331 | fprintf(stderr,"R(%d) ",u->urb_serial); 332 | #endif 333 | 334 | if(u->status && !(u->status==-ENOENT && u->cancelled==2)) 335 | { 336 | fprintf(stderr,"URB (just reaped) status=%d (%s), cancelled=%d\n", 337 | u->status,strerror(u->status),u->cancelled); 338 | } 339 | 340 | *ec_rv=ECSuccess; 341 | return(u); 342 | } 343 | 344 | 345 | WWUSBDevice::ErrorCode WWUSBDevice::_ResetEP(uchar dir_ep) 346 | { 347 | unsigned int ep=dir_ep; 348 | int rv=ioctl(fd_from_usb_dev_handle(udh),USBDEVFS_RESETEP,&ep); 349 | if(rv<0) 350 | { 351 | int errn=errno; 352 | fprintf(stderr,"Reset EP 0x%02x: %s\n",(int)ep,strerror(errn)); 353 | _ErrorCodeRV(errn); 354 | } 355 | else { fprintf(stderr,"Reset EP 0x%02x: OK\n",(int)ep); } 356 | 357 | return(ECSuccess); 358 | } 359 | 360 | 361 | WWUSBDevice::ErrorCode WWUSBDevice::ProcessEvents(int max_delay) 362 | { 363 | if(!udh) 364 | { return(ECNotConnected); } 365 | 366 | int fd=fd_from_usb_dev_handle(udh); 367 | //fprintf(stderr,"fd=%d\n",fd); 368 | 369 | // First, see what we can get without waiting. 370 | bool gather_phase=1; 371 | 372 | ErrorCode ec=ECSuccess; 373 | int errn=0; 374 | for(;;) 375 | { 376 | if(!npending) 377 | { return(ECNoURBAvail); } 378 | 379 | //fprintf(stderr,"loop: gather_phase=%d\n",gather_phase); 380 | usbdevfs_urb *dev_u=NULL; 381 | bool may_wait; 382 | if(gather_phase || max_delay==0) 383 | { may_wait=0; } 384 | else if(max_delay>0) 385 | { 386 | struct pollfd pfd[1]; 387 | pfd[0].fd=fd; 388 | pfd[0].events=POLLIN|POLLHUP; 389 | pfd[0].revents=0; 390 | int poll_rv=::poll(pfd,1,max_delay); 391 | // FIXME!!! This does not work!!!!!!!!!!!!!! 392 | fprintf(stderr,"fd=%d, poll_rv=%d, revents=0x%x \n", 393 | pfd[0].fd,poll_rv,pfd[0].revents); 394 | if(poll_rv<0) 395 | { 396 | fprintf(stderr,"poll: rv=%d (%s)\n",poll_rv,strerror(errno)); 397 | // Actually, this may make the actual delay longer than 398 | // max_delay (e.g. by periodically sending a singal to 399 | // the process) but is not supposed to be a real problem. 400 | continue; // FIXME: This may be dangerous (except for EINTR). 401 | } 402 | else if(poll_rv==0) 403 | { 404 | // Timeout. 405 | ec=ECTimeout; 406 | break; 407 | } 408 | else 409 | { may_wait=0; } 410 | } 411 | else // max_delay<0. 412 | { may_wait=1; } 413 | 414 | URB *u=_ReapURB(&ec,may_wait); 415 | if(!u) 416 | { 417 | if(ec==ECNoURBAvail) 418 | { 419 | // Currently no URB to reap available. 420 | if((max_delay>0 && !gather_phase) || 421 | (max_delay==0 && gather_phase) ) 422 | { 423 | ec=ECTimeout; 424 | break; 425 | } 426 | gather_phase=0; 427 | continue; 428 | } 429 | else if(ec==ECNotConnected) 430 | { return(ECNotConnected); } 431 | 432 | gather_phase=0; 433 | break; 434 | } 435 | 436 | // Tell user. 437 | ErrorCode urv=URBNotify(u); 438 | 439 | // Now free the URB. 440 | DeleteURB(u); 441 | 442 | if(urv) 443 | { 444 | ec = urv==ECUserQuitFatal ? ECUserQuitFatal : ECUserQuit; 445 | break; 446 | } 447 | } 448 | 449 | return(ec); 450 | } 451 | 452 | 453 | WWUSBDevice::ErrorCode WWUSBDevice::URBNotify(URB *) 454 | { 455 | assert(!"Not overridden."); 456 | return(ECSuccess); 457 | } 458 | 459 | 460 | void WWUSBDevice::DeleteURB(URB *u) 461 | { 462 | // Hope that's right... 463 | delete u; 464 | } 465 | 466 | 467 | WWUSBDevice::WWUSBDevice() : 468 | udev(NULL), 469 | udh(NULL), 470 | pending(), 471 | npending(0) 472 | { 473 | // Nothing to do... 474 | } 475 | 476 | WWUSBDevice::~WWUSBDevice() 477 | { 478 | disconnect(); 479 | } 480 | 481 | //------------------------------------------------------------------------------ 482 | 483 | void WWUSBDevice::URB::_buffer_oops() 484 | { 485 | assert(buffer==NULL); 486 | } 487 | -------------------------------------------------------------------------------- /fx2pipe/usb_io/wwusb.h: -------------------------------------------------------------------------------- 1 | /* 2 | * usb_io/wwusb.h 3 | * 4 | * USB async low-level routines. 5 | * 6 | * Copyright (c) 2006 by Wolfgang Wieser ] wwieser (a) gmx <*> de [ 7 | * 8 | * This file may be distributed and/or modified under the terms of the 9 | * GNU General Public License version 2 as published by the Free Software 10 | * Foundation. (See COPYING.GPL for details.) 11 | * 12 | * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 13 | * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 14 | * 15 | */ 16 | 17 | #ifndef _INCLUDE_USBIO_WWUSB_H_ 18 | #define _INCLUDE_USBIO_WWUSB_H_ 1 19 | 20 | #include "../oconfig.h" 21 | #include "../lib/linkedlist.h" 22 | 23 | #include 24 | #include 25 | 26 | #include "usbdevice_fs.h" /* usbdevfs_urb */ 27 | 28 | 29 | typedef unsigned char uchar; 30 | struct usb_device; 31 | 32 | /* 33 | struct usbdevfs_urb { 34 | unsigned char type; 35 | unsigned char endpoint; 36 | int status; 37 | unsigned int flags; 38 | void __user *buffer; 39 | int buffer_length; // <-- Max: MAX_USBFS_BUFFER_SIZE=16384 40 | int actual_length; 41 | int start_frame; 42 | int number_of_packets; 43 | int error_count; 44 | unsigned int signr; 45 | void *usercontext; 46 | struct usbdevfs_iso_packet_desc iso_frame_desc[0]; 47 | }; 48 | */ 49 | 50 | /** 51 | * \short USB Device representation. 52 | * \author Wolfgang Wieser ] wwieser (a) gmx <*> de [ 53 | * 54 | * The WWUSBDevice represents an USB device which can have several endpoints 55 | * and communication in both directions (IN and OUT). 56 | * 57 | * The idea is to derive a class from this one and override some virtual 58 | * functions to actually implement USB communication. 59 | * 60 | * NOTE: You canNOT use libusb routines in order to talk to a device while 61 | * having it opened using WWUSBDevice. Even not if the libusb code is 62 | * talking to a different endpoint of the device. The reason is that 63 | * libusb is likely to reap URBs which were submitted by us and vice 64 | * versa. So, be sure to know what you're doing. 65 | * 66 | * Not thread-safe. Only one thread should to all the USB actions. Otherwise 67 | * a synchronisation layer must be added. 68 | * 69 | * Not "C++-safe", i.e. do not copy or assign; corresponding operators are 70 | * made private by purpose. 71 | */ 72 | class WWUSBDevice 73 | { 74 | public: 75 | /// Error code enum. 76 | /// Negative codes are private codes; positive ones are errno values. 77 | enum ErrorCode 78 | { 79 | ECSuccess=0, ///< No error. You can rely on this being 0. 80 | ECConnected=-100, ///< (Already) connected. 81 | ECNotConnected, ///< Not connected to a device. 82 | ECNoSuchDevice, ///< No such USB device. 83 | ECFailure, ///< Unspecified failure. 84 | ECTimeout, ///< Timeout. 85 | ECUserQuit, ///< Event loop left by user request. 86 | ECUserQuitFatal, ///< Fatal version of ECUserQuit. 87 | ECNoURBAvail, ///< Internally used by _ReapURB(). 88 | }; 89 | 90 | /** 91 | * \short User request block base struct. 92 | * 93 | * URB handling is somewhat ciritcal since we want little overhead 94 | * and hence need to be careful with buffer allocation to avoid 95 | * spurious copying. 96 | * 97 | * So, it works as follows: URBs are allocated via operator new 98 | * and deleted via operator delete. URBs are always allocated from 99 | * user code and then get an apropriate buffer attached. Deallocation 100 | * from within WWUSBDevice is done via WWUSBDevice::DeleteURB() which 101 | * can be overridden to provide URB caching, see below. Note that 102 | * kernel copies the URB data buffer of OUT URBs upon submission so 103 | * buffer re-use is possible. The URB destructor must be able to 104 | * correctly deallocate an attached buffer so that the URB 105 | * cancellation code does not introducing a mem leak when deleting 106 | * a pending URB. 107 | * 108 | * Note that it is recommended to use URB caching to avoid 109 | * (de)allocation overhead. For that, implement custom operators 110 | * for new and delete: Operator new dequeues the memory chunk from 111 | * a list and operator delete will put it back (after the destructor 112 | * has been called). To make sure that the correct operators are 113 | * called, WWUSBDevice uses WWUSBDevice::DeleteURB() for URB deletion 114 | * which should be overridden with a "delete" statement first applying 115 | * the apropriate type cast. 116 | */ 117 | struct URB : LinkedListBase, usbdevfs_urb 118 | { 119 | /// 0 -> not cancelled; 1 -> cancellation failed; 2 -> cancelled. 120 | int cancelled; 121 | 122 | /// For debugging: serial number. 123 | int urb_serial; 124 | static int urb_serial_counter; 125 | 126 | /// See destructor. 127 | void _buffer_oops(); 128 | 129 | /** 130 | * \short URB constructor without buffer assignment. 131 | * 132 | * dir_ep is direction and endpoint (bit 7 = 0x80 set for IN). 133 | * Construcor will NUL out all the struct first. 134 | * 135 | * In order to allocate a new URB, use operator new or use 136 | * the URB cache (urbcache.h) which is most easily implemented 137 | * by overriding operators new and delete with URB cache's 138 | * get() and put() functions. 139 | */ 140 | inline URB(uchar dir_ep,uchar _type=USBDEVFS_URB_TYPE_BULK) : 141 | LinkedListBase() 142 | { 143 | usbdevfs_urb *u=this; memset(u,0,sizeof(usbdevfs_urb)); 144 | endpoint=dir_ep; type=_type; cancelled=0; 145 | urb_serial=urb_serial_counter++; 146 | } 147 | /// URB destructor of derived class MUST also free attached buffer. 148 | virtual inline ~URB() 149 | { if(buffer) _buffer_oops(); } 150 | 151 | // Get direction: -1 -> IN; +1 -> OUT. 152 | inline int dir() const 153 | { return((endpoint & 0x80) ? -1 : +1); } 154 | // Get endpoint. 155 | inline int ep() const 156 | { return(endpoint & 0x7f); } 157 | }; 158 | 159 | /// Find n-th (nth) device with specified vendor and product ID. 160 | static struct usb_device *USBFindDevice( 161 | int vendor,int product,int nth=0); 162 | /// Find device with specified vendor and device number. 163 | static struct usb_device *USBFindDevice( 164 | const char *bus,const char *dev); 165 | 166 | protected: 167 | /// USB device descriptor from libusb. 168 | struct usb_device *udev; 169 | /// USB device handle from libusb. 170 | struct usb_dev_handle *udh; 171 | 172 | /** 173 | * \short Notification of URB completion. 174 | * 175 | * This is called when an URB got processed and was just reaped. 176 | * 177 | * The URB will be deleted (using DeleteURB()) after returning 178 | * from the call to URBNotify() (so you need to detach the URB 179 | * buffer in URBNotify() if you still need it afterwards to prevent 180 | * it from being free'd in DeleteURB()). 181 | * 182 | * The return value should normally be 0; use ECUserQuit or 183 | * ECUserQuitFatal to exit the event loop. 184 | */ 185 | virtual ErrorCode URBNotify(URB *u); 186 | 187 | /// Delete an URB. Never uses delete directly; see URB for details. 188 | /// Default implementation will use operator delete directly. 189 | virtual void DeleteURB(URB *u); 190 | 191 | /** 192 | * \short Submit an URB. 193 | * 194 | * Call this to have an URB queued in the kernel. 195 | * 196 | * May be called from within URBNotify() but NOT with the 197 | * "original" URB (passed to URBNotify()). 198 | */ 199 | ErrorCode SubmitURB(URB *u) 200 | { return(_SubmitURB(u)); } 201 | /** 202 | * \short Cancel a submitted URB. 203 | * 204 | * Used to get rid of an URB which may not yet be processed. 205 | * 206 | * May be called from within URBNotify() but NOT with the 207 | * "original" URB (passed to URBNotify()). 208 | * 209 | * NOTE: A canceled URB will still be reaped. So don't delete them 210 | * unless you close the device afterwards anyways. 211 | */ 212 | ErrorCode CancelURB(URB *u) 213 | { return(_CancelURB(u)); } 214 | 215 | /** 216 | * \short Cancel all pending URBs. 217 | * 218 | * May be called from within URBNotify(). 219 | * 220 | * If also_delete is set, the URBs are also reaped and deleted. 221 | * See CancelURB(). 222 | */ 223 | void CancelAllPendingURBs(bool also_delete=0); 224 | 225 | /** 226 | * \short Reap and URB. 227 | * 228 | * Will reap one URB (wait for it if may_wait it set, otherwise 229 | * return immediately) and remove it from the pending list. 230 | * Magic check is performed and errors are reported. 231 | * 232 | * Returns an URB or NULL. 233 | * If NULL, see *ec_rv for details; this may be an errno value or 234 | * ECNoURBAvail if currently no URB available (and may_wait was set 235 | * to 0), ECNotConnected if disconnected. 236 | */ 237 | URB *_ReapURB(ErrorCode *ec_rv,bool may_wait); 238 | 239 | /// Reset endpoint (if needed). 240 | ErrorCode _ResetEP(uchar ep); 241 | 242 | protected: 243 | /// List of pending (i.e submitted but not yet completed) requests. 244 | LinkedList pending; 245 | /// Number of pending URBs. 246 | int npending; 247 | 248 | private: 249 | /// Internal function for error code "conversion". 250 | ErrorCode _ErrorCodeRV(int errno_val); 251 | 252 | /// Connect to the passed USB device. 253 | ErrorCode _DoConnect(struct usb_device *d); 254 | 255 | /// Submit URB and append it to pending on success. Usual return value. 256 | ErrorCode _SubmitURB(URB *u); 257 | /// Cancel the URB. This will NOT remove it from the pending list 258 | /// since cancelled URBs can still be reaped. 259 | ErrorCode _CancelURB(URB *u); 260 | 261 | private: 262 | /// Do not use. 263 | void operator=(const WWUSBDevice &); 264 | /// Do not use. 265 | WWUSBDevice(const WWUSBDevice &); 266 | public: 267 | /// Constructor creates a non-set-up device. Use connect(). 268 | WWUSBDevice(); 269 | /// Destructor. Will also disconnect. 270 | virtual ~WWUSBDevice(); 271 | 272 | /// Get number of pending (not yet reaped) URBs. 273 | inline int NPending() const 274 | { return(npending); } 275 | 276 | /** 277 | * \short Connect to a (physical) USB device attached to the USB. 278 | * 279 | * If already connected, use disconnect() before. 280 | * 281 | * There are 2 versions available which differ only in the way 282 | * the device to connect is chosen, e.g. if the output of "lsusb" 283 | * is the following: 284 | * \code 285 | * Bus 006 Device 002: ID 04b4:8613 Cypress CY7C68013 EZ-USB... 286 | * \endcode 287 | * then you can use vendor=0x04b4, product=0x8613 or you can use 288 | * bus="006", dev="002". The latter has the advantage that if 289 | * two identical devices are plugged into the box, they can be 290 | * uniquely addressed while the former version will choose the 291 | * one listed first (nth=0) or second (nth=1), etc. 292 | * 293 | * Return codes: 294 | * ECSuccess\n 295 | * ECConnected (already connected to some device; disconnect() first)\n 296 | * ECNoSuchDevice (specified device is not present)\n 297 | */ 298 | /// \{ 299 | ErrorCode connect(int vendor,int product,int nth=0); 300 | ErrorCode connect(const char *bus,const char *dev); 301 | /// \} 302 | 303 | /** 304 | * \short Claim interface. 305 | * 306 | * Call after connect() to claim the specified interface (if>=0) and 307 | * use the alternate interface alt_interface (if >=0). 308 | */ 309 | ErrorCode claim(int interface,int alt_interface); 310 | 311 | /** 312 | * \short Disconnect from device. 313 | * 314 | * This will also cancel all URBs and free them. 315 | * 316 | * Will return ECSuccess if not connected so it's safe to call 317 | * more often than needed. 318 | */ 319 | ErrorCode disconnect(); 320 | 321 | /** 322 | * \short Main (event) loop. 323 | * 324 | * Call this to have URBs reaped (URBNotify()). 325 | * 326 | * The loop will generally process as many URBs as possible. 327 | * Exiting the event loop can be achieved by returning 1 in 328 | * URBNotify(). 329 | * If you set max_delay>=0, the function will also return as soon 330 | * as an URB reap request will block for more than max_delay msec. 331 | * If max_delay<0, the function may block infinitely. 332 | * 333 | * NOTE: max_delay is the max delay between URBs, NOT the max. 334 | * total delay spent in the function. 335 | * 336 | * Return value: \n 337 | * ECUserQuit: URBNotify() returned 1. \n 338 | * ECTimeout: max_delay timeout. \n 339 | * ECNotConnected: if disconnected in action \n 340 | * ECNoURBAvail: no more pending URBs \n 341 | * other errno codes 342 | */ 343 | ErrorCode ProcessEvents(int max_delay); 344 | }; 345 | 346 | #endif /* _INCLUDE_USBIO_WWUSB_H_ */ 347 | -------------------------------------------------------------------------------- /fx2sharp/fx2sharp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.136 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "fx2sharp", "fx2sharp\fx2sharp.csproj", "{C629F22F-2110-460D-A8E0-ADEEACE0CEEF}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {C629F22F-2110-460D-A8E0-ADEEACE0CEEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {C629F22F-2110-460D-A8E0-ADEEACE0CEEF}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {C629F22F-2110-460D-A8E0-ADEEACE0CEEF}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {C629F22F-2110-460D-A8E0-ADEEACE0CEEF}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {C33A9E65-9866-4340-988E-AAC19789B28A} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /fx2sharp/fx2sharp/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /fx2sharp/fx2sharp/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("fx2sharp")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("fx2sharp")] 13 | [assembly: AssemblyCopyright("Copyright © 2020")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("c629f22f-2110-460d-a8e0-adeeace0ceef")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /fx2sharp/fx2sharp/fx2pipe_hoglet.hex: -------------------------------------------------------------------------------- 1 | :03000000020006F5 2 | :03005F0002000399 3 | :030003000203B441 4 | :20006200901003E0FE3395E0FFBE1205BF0002800CBE2105BF000280047F0080027F01008A 5 | :2000820000000000000000000000000000000000EF6007901007E0FE80027E1290E600EE0D 6 | :2000A200F00000000000000000000000000000000000EF6007901004E0FF80027FC390E63B 7 | :2000C20001EFF0000000000000000000000000000000000090E60B7403F000000000000056 8 | :2000E200000000000000000000000090E670E4F00000000000000000000000000000000044 9 | :200102000090E6097404F0000000000000000000000000000000000090E614E4F000000098 10 | :20012200000000000000000000000000000090E612E4F00000000000000000000000000061 11 | :200142000000000090E61AE4F0000000000000000000000000000000000090E618E4F000D7 12 | :200162000000000000000000000000000000000075B200901003E0FE3395E0FFBE1205BF9A 13 | :2001820000028003020274901005E0FD90E614F00000000000000000000000000000000064 14 | :2001A2000090E6047480F0000000000000000000000000000000000090E6047482F000007F 15 | :2001C20000000000000000000000000000000090E6047484F00000000000000000000000BB 16 | :2001E20000000000000090E6047486F0000000000000000000000000000000000090E6041F 17 | :200202007488F0000000000000000000000000000000000090E604E4F000000000000000A2 18 | :2002220000000000000000000000901006E0FD90E61AF000000000000000000000000000B9 19 | :200242000000000090E6247402F0000000000000000000000000000000000090E625E4F02D 20 | :20026200000000000000000000000000000000000022BE2105BF0002800122901005E0FF8E 21 | :2002820090E612F0000000000000000000000000000000000090E6047480F0000000000086 22 | :2002A20000000000000000000000000090E6047482F00000000000000000000000000000DC 23 | :2002C20000000090E6047484F0000000000000000000000000000000000090E6047486F056 24 | :2002E200000000000000000000000000000000000090E6047488F000000000000000000096 25 | :20030200000000000000000090E604E4F0000000000000000000000000000000000090E617 26 | :20032200497482F0000000000000000000000000000000000090E6497482F00000000000E7 27 | :20034200000000000000000000000000901005E0FF3395E05307037E00BF0005BE00028090 28 | :2003620008BF0333BE0030801790E6497482F0000000000000000000000000000000000054 29 | :2003820090E6497482F00000000000000000000000000000000000901006E0FF90E618F0B3 30 | :1703A20000000000000000000000000000000000002212006280FE30 31 | :06003500E478FFF6D8FD9F 32 | :200013007900E94400601B7A009003BD780175A000E493F2A308B8000205A0D9F4DAF275D3 33 | :02003300A0FF2C 34 | :20003B007800E84400600A790175A000E4F309D8FC7800E84400600C7900900001E4F0A3C3 35 | :04005B00D8FCD9FAFA 36 | :0D0006007581071203B9E582600302000353 37 | :0403B9007582002227 38 | :00000001FF 39 | -------------------------------------------------------------------------------- /fx2sharp/fx2sharp/fx2sharp.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Debug 7 | AnyCPU 8 | {C629F22F-2110-460D-A8E0-ADEEACE0CEEF} 9 | Exe 10 | fx2sharp 11 | fx2sharp 12 | v4.6 13 | 512 14 | true 15 | true 16 | 17 | 18 | 19 | 20 | 21 | AnyCPU 22 | true 23 | full 24 | false 25 | bin\Debug\ 26 | DEBUG;TRACE 27 | prompt 28 | 4 29 | true 30 | 31 | 32 | AnyCPU 33 | pdbonly 34 | true 35 | bin\Release\ 36 | TRACE 37 | prompt 38 | 4 39 | true 40 | 41 | 42 | 43 | C:\Program Files (x86)\Cypress\EZ-USB FX3 SDK\1.3\library\c_sharp\lib\CyUSB.dll 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | Always 62 | 63 | 64 | 65 | 66 | 67 | 68 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /fx2sharp/fx2sharp/fx2sharp.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | ShowAllFiles 5 | 6 | 7 | --debug -n=1M d:\temp\temp.bin 8 | 9 | 10 | -n=16M --debug d:\temp\temp.bin 11 | 12 | -------------------------------------------------------------------------------- /fx2sharp/fx2sharp/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /src/defs.h: -------------------------------------------------------------------------------- 1 | #ifndef DEFS 2 | #define DEFS 3 | 4 | #include 5 | 6 | typedef enum { 7 | MACHINE_DEFAULT, 8 | MACHINE_BEEB, 9 | MACHINE_MASTER, 10 | MACHINE_ELK, 11 | MACHINE_ATOM, 12 | MACHINE_MEK6800D2, 13 | MACHINE_BLITTER, 14 | } machine_t; 15 | 16 | typedef enum { 17 | CPU_UNKNOWN, 18 | CPU_6502, 19 | CPU_6502_ARLET, 20 | CPU_65C02, 21 | CPU_65C02_ROCKWELL, 22 | CPU_65C02_WDC, 23 | CPU_65C02_ARLET, 24 | CPU_65C02_ALAND, 25 | CPU_65C816, 26 | CPU_6800, 27 | } cpu_t; 28 | 29 | // Sample Queue Depth - needs to fit the longest instruction 30 | #define DEPTH 13 31 | 32 | // Sample_type_t is an abstraction of both the 6502 SYNC and the 65816 VDA/VPA 33 | 34 | typedef enum { // 6502 Sync 65815 VDA/VPA 35 | UNKNOWN, // ? ? ? 36 | INTERNAL, // - 0 0 37 | PROGRAM, // - 0 1 38 | DATA, // 0 1 0 39 | OPCODE, // 1 1 1 40 | LAST // a marker for the end of stream 41 | } sample_type_t; 42 | 43 | typedef struct { 44 | uint32_t sample_count; 45 | uint32_t cycle_count; 46 | sample_type_t type; 47 | uint8_t data; 48 | int8_t rnw; // -1 indicates unknown 49 | int8_t rst; // -1 indicates unknown 50 | int8_t e; // -1 indicates unknown (65816 e pin) 51 | int8_t user; // -1 indicates unknown (user defined signal) 52 | } sample_t; 53 | 54 | 55 | typedef struct { 56 | int pc; 57 | int pb; 58 | uint8_t opcode; 59 | uint8_t op1; 60 | uint8_t op2; 61 | uint8_t op3; 62 | uint8_t opcount; 63 | } instruction_t; 64 | 65 | void write_hex1(char *buffer, int value); 66 | void write_hex2(char *buffer, int value); 67 | void write_hex4(char *buffer, int value); 68 | void write_hex6(char *buffer, int value); 69 | int write_s (char *buffer, const char *s); 70 | 71 | typedef struct { 72 | cpu_t cpu_type; 73 | machine_t machine; 74 | int idx_data; 75 | int idx_rnw; 76 | int idx_sync; 77 | int idx_rdy; 78 | int idx_phi1; 79 | int idx_phi2; 80 | int idx_user; 81 | int idx_rst; 82 | int idx_vda; 83 | int idx_vpa; 84 | int idx_e; 85 | int vec_rst; 86 | int show_address; 87 | int show_hex; 88 | int show_instruction; 89 | int show_state; 90 | int show_bbcfwa; 91 | int show_cycles; 92 | int show_samplenums; 93 | int show_something; 94 | int bbctube; 95 | int undocumented; 96 | int e_flag; 97 | int ms_flag; 98 | int xs_flag; 99 | int sp_reg; 100 | int pb_reg; 101 | int db_reg; 102 | int dp_reg; 103 | int byte; 104 | int debug; 105 | int skip; 106 | int skew_rd; 107 | int skew_wr; 108 | char *labels_file; 109 | int mem_model; 110 | int profile; 111 | int trigger_start; 112 | int trigger_stop; 113 | int trigger_skipint; 114 | char *filename; 115 | int show_romno; 116 | } arguments_t; 117 | 118 | typedef struct { 119 | void (*init)(arguments_t *args); 120 | int (*match_interrupt)(sample_t *sample_q, int num_samples); 121 | int (*count_cycles)(sample_t *sample_q, int intr_seen); 122 | void (*reset)(sample_t *sample_q, int num_cycles, instruction_t *instruction); 123 | void (*interrupt)(sample_t *sample_q, int num_cycles, instruction_t *instruction); 124 | void (*emulate)(sample_t *sample_q, int num_cycles, instruction_t *instruction); 125 | int (*disassemble)(char *bp, instruction_t *instruction); 126 | int (*get_PC)(); 127 | int (*get_PB)(); 128 | int (*read_memory)(int address); 129 | char *(*get_state)(); 130 | int (*get_and_clear_fail)(); 131 | } cpu_emulator_t; 132 | 133 | extern int failflag; 134 | 135 | #endif 136 | -------------------------------------------------------------------------------- /src/em_6502.h: -------------------------------------------------------------------------------- 1 | #ifndef _INCLUDE_EM_6502_H 2 | #define _INCLUDE_EM_6502_H 3 | 4 | #include "defs.h" 5 | 6 | extern cpu_emulator_t em_6502; 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/em_65816.h: -------------------------------------------------------------------------------- 1 | #ifndef _INCLUDE_EM_65816_H 2 | #define _INCLUDE_EM_65816_H 3 | 4 | #include "defs.h" 5 | 6 | extern cpu_emulator_t em_65816; 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/em_6800.h: -------------------------------------------------------------------------------- 1 | #ifndef _INCLUDE_EM_6800_H 2 | #define _INCLUDE_EM_6800_H 3 | 4 | #include "defs.h" 5 | 6 | extern cpu_emulator_t em_6800; 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/matcher.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define N 24 6 | 7 | #define SIZE (1< 27 | #include "musl_tsearch.h" 28 | 29 | /* AVL tree height < 1.44*log2(nodes+2)-0.3, MAXH is a safe upper bound. */ 30 | #define MAXH (sizeof(void*)*8*3/2) 31 | 32 | struct node { 33 | const void *key; 34 | void *a[2]; 35 | int h; 36 | }; 37 | 38 | void ttdestroy(void *root, void (*freekey)(void *)) 39 | { 40 | struct node *r = root; 41 | 42 | if (r == 0) 43 | return; 44 | ttdestroy(r->a[0], freekey); 45 | ttdestroy(r->a[1], freekey); 46 | if (freekey) freekey((void *)r->key); 47 | free(r); 48 | } 49 | 50 | void *ttfind(const void *key, void *const *rootp, 51 | int(*cmp)(const void *, const void *)) 52 | { 53 | if (!rootp) 54 | return 0; 55 | 56 | struct node *n = *rootp; 57 | for (;;) { 58 | if (!n) 59 | break; 60 | int c = cmp(key, n->key); 61 | if (!c) 62 | break; 63 | n = n->a[c>0]; 64 | } 65 | return n; 66 | } 67 | 68 | static inline int height(struct node *n) { return n ? n->h : 0; } 69 | 70 | static int rot(void **p, struct node *x, int dir /* deeper side */) 71 | { 72 | struct node *y = x->a[dir]; 73 | struct node *z = y->a[!dir]; 74 | int hx = x->h; 75 | int hz = height(z); 76 | if (hz > height(y->a[dir])) { 77 | /* 78 | * x 79 | * / \ dir z 80 | * A y / \ 81 | * / \ --> x y 82 | * z D /| |\ 83 | * / \ A B C D 84 | * B C 85 | */ 86 | x->a[dir] = z->a[!dir]; 87 | y->a[!dir] = z->a[dir]; 88 | z->a[!dir] = x; 89 | z->a[dir] = y; 90 | x->h = hz; 91 | y->h = hz; 92 | z->h = hz+1; 93 | } else { 94 | /* 95 | * x y 96 | * / \ / \ 97 | * A y --> x D 98 | * / \ / \ 99 | * z D A z 100 | */ 101 | x->a[dir] = z; 102 | y->a[!dir] = x; 103 | x->h = hz+1; 104 | y->h = hz+2; 105 | z = y; 106 | } 107 | *p = z; 108 | return z->h - hx; 109 | } 110 | 111 | /* balance *p, return 0 if height is unchanged. */ 112 | static int __tsearch_balance(void **p) 113 | { 114 | struct node *n = *p; 115 | int h0 = height(n->a[0]); 116 | int h1 = height(n->a[1]); 117 | if (h0 - h1 + 1u < 3u) { 118 | int old = n->h; 119 | n->h = h0

h - old; 121 | } 122 | return rot(p, n, h0key); 140 | if (!c) 141 | return n; 142 | a[i++] = &n->a[c>0]; 143 | n = n->a[c>0]; 144 | } 145 | r = malloc(sizeof *r); 146 | if (!r) 147 | return 0; 148 | r->key = key; 149 | r->a[0] = r->a[1] = 0; 150 | r->h = 1; 151 | /* insert new node, rebalance ancestors. */ 152 | *a[--i] = r; 153 | while (i && __tsearch_balance(a[--i])); 154 | return r; 155 | } 156 | 157 | void *ttdelete(const void *restrict key, void **restrict rootp, 158 | int(*cmp)(const void *, const void *)) 159 | { 160 | if (!rootp) 161 | return 0; 162 | 163 | void **a[MAXH+1]; 164 | struct node *n = *rootp; 165 | struct node *parent; 166 | struct node *child; 167 | int i=0; 168 | /* *a[0] is an arbitrary non-null pointer that is returned when 169 | the root node is deleted. */ 170 | a[i++] = rootp; 171 | a[i++] = rootp; 172 | for (;;) { 173 | if (!n) 174 | return 0; 175 | int c = cmp(key, n->key); 176 | if (!c) 177 | break; 178 | a[i++] = &n->a[c>0]; 179 | n = n->a[c>0]; 180 | } 181 | parent = *a[i-2]; 182 | if (n->a[0]) { 183 | /* free the preceding node instead of the deleted one. */ 184 | struct node *deleted = n; 185 | a[i++] = &n->a[0]; 186 | n = n->a[0]; 187 | while (n->a[1]) { 188 | a[i++] = &n->a[1]; 189 | n = n->a[1]; 190 | } 191 | deleted->key = n->key; 192 | child = n->a[0]; 193 | } else { 194 | child = n->a[1]; 195 | } 196 | /* freed node has at most one child, move it up and rebalance. */ 197 | free(n); 198 | *a[--i] = child; 199 | while (--i && __tsearch_balance(a[i])); 200 | return parent; 201 | } 202 | 203 | static void walk(const struct node *r, void (*action)(const void *, TVISIT, int), int d) 204 | { 205 | if (!r) 206 | return; 207 | if (r->h == 1) 208 | action(r, tleaf, d); 209 | else { 210 | action(r, tpreorder, d); 211 | walk(r->a[0], action, d+1); 212 | action(r, tpostorder, d); 213 | walk(r->a[1], action, d+1); 214 | action(r, tendorder, d); 215 | } 216 | } 217 | 218 | void ttwalk(const void *root, void (*action)(const void *, TVISIT, int)) 219 | { 220 | walk(root, action, 0); 221 | } 222 | -------------------------------------------------------------------------------- /src/musl_tsearch.h: -------------------------------------------------------------------------------- 1 | #ifndef HEADER_DBD91B1DA09E43B1B27A0CE43D8B5E7B 2 | #define HEADER_DBD91B1DA09E43B1B27A0CE43D8B5E7B 3 | 4 | typedef enum { tpreorder, tpostorder, tendorder, tleaf } TVISIT; 5 | 6 | void ttdestroy(void *root, void (*freekey)(void *)); 7 | 8 | void *ttfind(const void *key, void *const *rootp, int(*cmp)(const void *, const void *)); 9 | 10 | void *ttsearch(const void *key, void **rootp, int (*cmp)(const void *, const void *)); 11 | 12 | void *ttdelete(const void *restrict key, void **restrict rootp, int(*cmp)(const void *, const void *)); 13 | 14 | void ttwalk(const void *root, void (*action)(const void *, TVISIT, int)); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/profiler.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "profiler.h" 5 | #include "symbols.h" 6 | 7 | extern profiler_t *profiler_instr_create(char *arg); 8 | extern profiler_t *profiler_block_create(char *arg); 9 | extern profiler_t *profiler_call_create(char *arg); 10 | 11 | #define MAX_PROFILERS 10 12 | 13 | static profiler_t *active_list[MAX_PROFILERS] = { NULL } ; 14 | 15 | void profiler_parse_opt(int key, char *arg, struct argp_state *state) { 16 | static int active_count = 0; 17 | switch (key) { 18 | case 'p': 19 | if (arg && strlen(arg) > 0) { 20 | char *type = strtok(arg, ","); 21 | char *rest = strtok(NULL, ""); 22 | // Act as a factory method for profilers 23 | profiler_t *instance = NULL; 24 | if (strcasecmp(type, "instr") == 0) { 25 | instance = profiler_instr_create(rest); 26 | } else if (strcasecmp(type, "block") == 0) { 27 | instance = profiler_block_create(rest); 28 | } else if (strcasecmp(type, "call") == 0) { 29 | instance = profiler_call_create(rest); 30 | } 31 | if (instance) { 32 | active_list[active_count++] = instance; 33 | active_list[active_count] = NULL; 34 | } else { 35 | argp_error(state, "unknown profiler type %s", type); 36 | } 37 | } 38 | break; 39 | } 40 | } 41 | 42 | void profiler_init(cpu_emulator_t *em) { 43 | profiler_t **pp = active_list; 44 | while (*pp) { 45 | (*pp)->init(*pp, em); 46 | pp++; 47 | } 48 | } 49 | 50 | void profiler_profile_instruction(int pc, int opcode, int op1, int op2, int num_cycles) { 51 | profiler_t **pp = active_list; 52 | while (*pp) { 53 | (*pp)->profile_instruction(*pp, pc, opcode, op1, op2, num_cycles); 54 | pp++; 55 | } 56 | } 57 | 58 | void profiler_done() { 59 | profiler_t **pp = active_list; 60 | while (*pp) { 61 | printf("==============================================================================\n"); 62 | printf("Profiler: %s; Args: %s\n", (*pp)->name, (*pp)->arg); 63 | printf("==============================================================================\n"); 64 | (*pp)->done(*pp); 65 | pp++; 66 | } 67 | } 68 | 69 | void profiler_output_helper(address_t *profile_counts, int show_bars, int show_other, cpu_emulator_t *em) { 70 | address_t *ptr; 71 | 72 | uint32_t max_cycles = 0; 73 | uint64_t total_cycles = 0; 74 | uint64_t page_crossing_cycles = 0; 75 | uint64_t total_instr = 0; 76 | double total_percent = 0.0; 77 | double bar_scale; 78 | 79 | char buffer[256]; 80 | 81 | ptr = profile_counts; 82 | 83 | for (int addr = 0; addr <= OTHER_CONTEXT; addr++) { 84 | if (ptr->cycles > max_cycles) { 85 | max_cycles = ptr->cycles; 86 | } 87 | total_cycles += ptr->cycles; 88 | total_instr += ptr->instructions; 89 | if (em && ptr->cycles) { 90 | int opcode = em->read_memory(addr); 91 | // TODO: BRA (0x80) should only be counted on the C02/C816 92 | if (((opcode & 0x1f) == 0x10) || (opcode == 0x80)) { 93 | int offset = em->read_memory(addr + 1); 94 | // Is the target in a different page? 95 | if (((addr + 2) & 0xff00) != ((addr + 2 + (int8_t)offset) & 0xff00)) { 96 | // A small amount of maths gives us the cycles that could be saved if the branch were in the same page 97 | page_crossing_cycles += (ptr->cycles - 2 * ptr->instructions) / 2; 98 | } 99 | } 100 | } 101 | ptr++; 102 | } 103 | 104 | bar_scale = (double) BAR_WIDTH / (double) max_cycles; 105 | 106 | ptr = profile_counts; 107 | for (int addr = 0; addr <= OTHER_CONTEXT; addr++) { 108 | char *name = symbol_lookup(addr); 109 | if (name) { 110 | printf("\n%s\n", name); 111 | } 112 | if (ptr->cycles) { 113 | double percent = 100.0 * (ptr->cycles) / (double) total_cycles; 114 | total_percent += percent; 115 | if (addr == OTHER_CONTEXT) { 116 | printf("****"); 117 | } else { 118 | printf("%04x", addr); 119 | if (em) { 120 | instruction_t instruction; 121 | instruction.pc = addr; 122 | instruction.opcode = em->read_memory(addr); 123 | instruction.op1 = em->read_memory(addr + 1); 124 | instruction.op2 = em->read_memory(addr + 2); 125 | int n = em->disassemble(buffer, &instruction); 126 | printf(" %s", buffer); 127 | for (int i = n; i < 12; i++) { 128 | putchar(' '); 129 | } 130 | } 131 | } 132 | printf(" : %8d cycles (%10.6f%%) %8d ins (%4.2f cpi)", ptr->cycles, percent, ptr->instructions, (double) ptr->cycles / (double) ptr->instructions); 133 | if (show_other) { 134 | printf(" %8d calls", ptr->calls); 135 | printf(" ("); 136 | printf(ptr->flags & FLAG_JSR ? "J" : " "); 137 | printf(ptr->flags & FLAG_JMP ? "j" : " "); 138 | printf(ptr->flags & FLAG_BB_TAKEN ? "B" : " "); 139 | printf(ptr->flags & FLAG_FB_TAKEN ? "F" : " "); 140 | printf(ptr->flags & FLAG_BB_NOT_TAKEN ? "b" : " "); 141 | printf(ptr->flags & FLAG_FB_NOT_TAKEN ? "f" : " "); 142 | printf(ptr->flags & FLAG_JMP_IND ? "i" : " "); 143 | printf(ptr->flags & FLAG_JMP_INDX ? "x" : " "); 144 | printf(")"); 145 | } 146 | if (show_bars) { 147 | printf(" "); 148 | for (int i = 0; i < (int) (bar_scale * ptr->cycles); i++) { 149 | printf("*"); 150 | } 151 | } 152 | printf("\n"); 153 | } 154 | ptr++; 155 | } 156 | printf(" : %8" PRIu64 " cycles (%10.6f%%) %8" PRIu64 " ins (%4.2f cpi)\n", total_cycles, total_percent, total_instr, (double) total_cycles / (double) total_instr); 157 | printf(" : %8" PRIu64 " branch page crossing cycles (%10.6f%%)\n",page_crossing_cycles, (double) page_crossing_cycles * 100.0 / (double) total_cycles); 158 | } 159 | -------------------------------------------------------------------------------- /src/profiler.h: -------------------------------------------------------------------------------- 1 | #ifndef _INCLUDE_PROFILER_H 2 | #define _INCLUDE_PROFILER_H 3 | 4 | #include 5 | #include 6 | 7 | #include "defs.h" 8 | 9 | // Slot for instructions that fall outside the region of interest 10 | // (don't change this or lots of things will break!) 11 | #define OTHER_CONTEXT 0x10000 12 | 13 | // Maximum length of bar of asterisks 14 | #define BAR_WIDTH 50 15 | 16 | // Flags are currently specific to the block profiler 17 | #define FLAG_IMP 1 18 | #define FLAG_JSR 2 19 | #define FLAG_JMP 4 20 | #define FLAG_BB_TAKEN 8 21 | #define FLAG_FB_TAKEN 16 22 | #define FLAG_BB_NOT_TAKEN 32 23 | #define FLAG_FB_NOT_TAKEN 64 24 | #define FLAG_JMP_IND 128 25 | #define FLAG_JMP_INDX 256 26 | 27 | // A common data type, useful for several of the profilers 28 | typedef struct { 29 | uint32_t cycles; 30 | uint32_t instructions; 31 | uint32_t calls; 32 | int flags; 33 | } address_t; 34 | 35 | // All profiler instance data should start with this type 36 | 37 | typedef struct { 38 | const char *name; 39 | const char *arg; 40 | void (*init)(void *ptr, cpu_emulator_t *em); 41 | void (*profile_instruction)(void *ptr, int pc, int opcode, int op1, int op2, int num_cycles); 42 | void (*done)(void *ptr); 43 | } profiler_t; 44 | 45 | // Public methods, called from main program 46 | 47 | void profiler_parse_opt(int key, char *arg, struct argp_state *state); 48 | void profiler_init(cpu_emulator_t *em); 49 | void profiler_profile_instruction(int pc, int opcode, int op1, int op2, int num_cycles); 50 | void profiler_done(); 51 | 52 | // Helper methods, for use by profiler implementations 53 | 54 | void profiler_output_helper(address_t *profile_counts, int show_bars, int show_other, cpu_emulator_t *em); 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/profiler_block.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "profiler.h" 7 | 8 | typedef struct { 9 | profiler_t profiler; 10 | int profile_min; 11 | int profile_max; 12 | address_t profile_counts[OTHER_CONTEXT + 1]; 13 | int last_opcode; 14 | cpu_emulator_t *em; 15 | } profiler_block_t; 16 | 17 | static void p_init(void *ptr, cpu_emulator_t *em) { 18 | profiler_block_t *instance = (profiler_block_t *)ptr; 19 | memset((void *)instance->profile_counts, 0, sizeof(instance->profile_counts)); 20 | instance->profile_counts[OTHER_CONTEXT].flags = 1; 21 | instance->em = em; 22 | } 23 | 24 | static void p_profile_instruction(void *ptr, int pc, int opcode, int op1, int op2, int num_cycles) { 25 | profiler_block_t *instance = (profiler_block_t *)ptr; 26 | int addr; 27 | if (pc >= instance->profile_min && pc <= instance->profile_max) { 28 | addr = pc & 0xffff; 29 | } else { 30 | addr = OTHER_CONTEXT; 31 | } 32 | instance->profile_counts[addr].instructions++; 33 | instance->profile_counts[addr].cycles += num_cycles; 34 | // Test the test instruction to catch the destination of an indiect JMP 35 | // (this will break if the following instruction is interrupted) 36 | if (instance->last_opcode == 0x6c) { 37 | instance->profile_counts[addr].flags |= FLAG_JMP_IND; 38 | } else if (instance->last_opcode == 0x7c) { 39 | instance->profile_counts[addr].flags |= FLAG_JMP_INDX; 40 | } 41 | if (opcode == 0x20) { 42 | // Note the destination of JSR 43 | addr = (op2 << 8 | op1) & 0xffff; 44 | instance->profile_counts[addr].flags |= FLAG_JSR; 45 | } else if (opcode == 0x4c) { 46 | // Note the destination of JMP 47 | addr = (op2 << 8 | op1) & 0xffff; 48 | instance->profile_counts[addr].flags |= FLAG_JMP; 49 | } else if (pc >= 0 && (((opcode & 0x1f) == 0x10) || (opcode == 0x80))) { 50 | // Note the destination of Bxx 51 | addr = ((pc + 2) + ((int8_t)(op1))) & 0xffff; 52 | instance->profile_counts[addr ].flags |= addr < pc ? FLAG_BB_TAKEN : FLAG_FB_TAKEN; 53 | instance->profile_counts[pc + 2].flags |= addr < pc ? FLAG_BB_NOT_TAKEN : FLAG_FB_NOT_TAKEN; 54 | } 55 | instance->last_opcode = opcode; 56 | } 57 | 58 | static void p_done(void *ptr) { 59 | profiler_block_t *instance = (profiler_block_t *)ptr; 60 | address_t block_counts[OTHER_CONTEXT + 1]; 61 | memset((void *)block_counts, 0, sizeof(block_counts)); 62 | int current_block = OTHER_CONTEXT; 63 | int addr; 64 | for (addr = 0; addr <= OTHER_CONTEXT; addr++) { 65 | if (instance->profile_counts[addr].flags) { 66 | current_block = addr; 67 | block_counts[current_block].flags = instance->profile_counts[addr].flags; 68 | block_counts[current_block].calls = instance->profile_counts[addr].instructions; 69 | } 70 | block_counts[current_block].cycles += instance->profile_counts[addr].cycles; 71 | block_counts[current_block].instructions += instance->profile_counts[addr].instructions; 72 | } 73 | profiler_output_helper(block_counts, 0, 1, instance->em); 74 | } 75 | 76 | void *profiler_block_create(char *arg) { 77 | 78 | profiler_block_t *instance = (profiler_block_t *)calloc(1, sizeof(profiler_block_t)); 79 | 80 | instance->profiler.name = "block"; 81 | instance->profiler.arg = arg ? strdup(arg) : ""; 82 | instance->profiler.init = p_init; 83 | instance->profiler.profile_instruction = p_profile_instruction; 84 | instance->profiler.done = p_done; 85 | instance->profile_min = 0x0000; 86 | instance->profile_max = 0xffff; 87 | 88 | if (arg && strlen(arg) > 0) { 89 | char *min = strtok(arg, ","); 90 | char *max = strtok(NULL, ","); 91 | if (min && strlen(min) > 0) { 92 | instance->profile_min = strtol(min, (char **)NULL, 16); 93 | } 94 | if (max && strlen(max) > 0) { 95 | instance->profile_max = strtol(max, (char **)NULL, 16); 96 | } 97 | } 98 | 99 | return instance; 100 | } 101 | -------------------------------------------------------------------------------- /src/profiler_call.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "musl_tsearch.h" 7 | #include "profiler.h" 8 | #include "symbols.h" 9 | 10 | #define DEBUG 0 11 | 12 | // Constants for call based profiling 13 | // (6502 stack can only hold 128 addresses) 14 | #define CALL_STACK_SIZE 128 15 | 16 | static cpu_emulator_t *my_em; 17 | 18 | typedef struct call_stack { 19 | int stack[CALL_STACK_SIZE]; 20 | struct call_stack *parent; 21 | int index; 22 | uint64_t call_count; 23 | uint64_t cycle_count; 24 | } call_stack_t; 25 | 26 | 27 | typedef struct { 28 | profiler_t profiler; 29 | void *root; 30 | call_stack_t *current; 31 | int profile_enabled; 32 | cpu_emulator_t *em; 33 | } profiler_call_t; 34 | 35 | 36 | // One copy of these means profile_done is not thread safe, not concerned about this 37 | static uint64_t total_cycles; 38 | static double total_percent; 39 | 40 | static int compare_nodes(const void *av, const void *bv) { 41 | const call_stack_t *a = (call_stack_t *) av; 42 | const call_stack_t *b = (call_stack_t *) bv; 43 | int ret = 0; 44 | for (int i = 0; i < a->index && i < b->index; i++) { 45 | if (a->stack[i] < b->stack[i]) { 46 | ret = -1; 47 | break; 48 | } else if (a->stack[i] > b->stack[i]) { 49 | ret = 1; 50 | break; 51 | } 52 | } 53 | if (ret == 0) { 54 | if (a->index < b->index) { 55 | ret = -1; 56 | } else if (a->index > b->index) { 57 | ret = 1; 58 | } 59 | } 60 | return ret; 61 | } 62 | 63 | static void p_init(void *ptr, cpu_emulator_t *em) { 64 | profiler_call_t *instance = (profiler_call_t *)ptr; 65 | call_stack_t *root_context = (call_stack_t *)malloc(sizeof(call_stack_t)); 66 | root_context->index = 0; 67 | root_context->cycle_count = 0; 68 | root_context->call_count = 0; 69 | root_context->parent = NULL; 70 | if (instance->root) { 71 | ttdestroy(instance->root, free); 72 | } 73 | instance->root = NULL; 74 | instance->current = *(call_stack_t **)ttsearch(root_context, &instance->root, compare_nodes); 75 | instance->profile_enabled = 1; 76 | instance->em = em; 77 | my_em = em; 78 | } 79 | 80 | static void p_profile_instruction(void *ptr, int pc, int opcode, int op1, int op2, int num_cycles) { 81 | profiler_call_t *instance = (profiler_call_t *)ptr; 82 | if (!instance->profile_enabled) { 83 | return; 84 | } 85 | instance->current->cycle_count += num_cycles; 86 | if (opcode == 0x20) { 87 | // TODO: What about interrupts 88 | if (instance->current->index < CALL_STACK_SIZE) { 89 | int addr = (op2 << 8 | op1) & 0xffff; 90 | #if DEBUG 91 | printf("*** pushing %04x to %d\n", addr, current->index); 92 | #endif 93 | // Create a new child node, in case it's not already in the tree 94 | call_stack_t *child = (call_stack_t *) malloc(sizeof(call_stack_t)); 95 | memcpy((void*) child, (void *)(instance->current), sizeof(call_stack_t)); 96 | child->stack[child->index] = addr; 97 | child->index++; 98 | child->parent = instance->current; 99 | child->cycle_count = 0; 100 | child->call_count = 0; 101 | instance->current = *(call_stack_t **)ttsearch(child, &instance->root, compare_nodes); 102 | // If the child already existed, then free the just created node 103 | if (instance->current != child) { 104 | free(child); 105 | } 106 | instance->current->call_count++; 107 | } else { 108 | printf("warning: call stack overflowed, disabling further profiling\n"); 109 | for (int i = 0; i < instance->current->index; i++) { 110 | printf("warning: stack[%3d] = %04x\n", i, instance->current->stack[i]); 111 | } 112 | instance->profile_enabled = 0; 113 | } 114 | } 115 | if (opcode == 0x60) { 116 | if (instance->current->parent) { 117 | #if DEBUG 118 | printf("*** popping %d\n", current->index); 119 | #endif 120 | instance->current = instance->current->parent; 121 | } else { 122 | printf("warning: call stack underflowed, re-initialize call graph\n"); 123 | p_init(ptr, instance->em); 124 | } 125 | } 126 | } 127 | 128 | static void print_node(const call_stack_t *node) { 129 | int first = 1; 130 | double percent = 100.0 * (double) node->cycle_count / (double) total_cycles; 131 | total_percent += percent; 132 | printf("%8" PRIu64 " cycles (%10.6f%%) %8" PRIu64 " calls: ", node->cycle_count, percent, node->call_count); 133 | for (int i = 0; i < node->index; i++) { 134 | if (!first) { 135 | printf("->"); 136 | } 137 | first = 0; 138 | char *name=symbol_lookup(node->stack[i]); 139 | if (name) { 140 | if (name[0] == '.') name++; 141 | printf("%s", name); 142 | } else { 143 | printf("%04X", node->stack[i]); 144 | } 145 | } 146 | printf("\n"); 147 | } 148 | 149 | static void count_call_walker(const void *nodep, const TVISIT which, const int depth) { 150 | if (which == tpostorder || which == tleaf) { 151 | total_cycles += (*(call_stack_t **)nodep)->cycle_count; 152 | } 153 | } 154 | 155 | static void dump_call_walker(const void *nodep, const TVISIT which, const int depth) { 156 | if (which == tpostorder || which == tleaf) { 157 | print_node(*(call_stack_t **)nodep); 158 | } 159 | } 160 | 161 | static void p_done(void *ptr) { 162 | profiler_call_t *instance = (profiler_call_t *)ptr; 163 | total_cycles = 0; 164 | ttwalk(instance->root, count_call_walker); 165 | total_percent = 0; 166 | ttwalk(instance->root, dump_call_walker); 167 | printf("%8" PRIu64 " cycles (%10.6f%%)\n", total_cycles, total_percent); 168 | } 169 | 170 | void *profiler_call_create(char *arg) { 171 | profiler_call_t *instance = (profiler_call_t *)calloc(1, sizeof(profiler_call_t)); 172 | 173 | instance->profiler.name = "call"; 174 | instance->profiler.arg = arg ? strdup(arg) : ""; 175 | instance->profiler.init = p_init; 176 | instance->profiler.profile_instruction = p_profile_instruction; 177 | instance->profiler.done = p_done; 178 | 179 | return instance; 180 | } 181 | -------------------------------------------------------------------------------- /src/profiler_instr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "profiler.h" 7 | 8 | typedef struct { 9 | profiler_t profiler; 10 | int profile_min; 11 | int profile_max; 12 | int profile_bucket; 13 | address_t profile_counts[OTHER_CONTEXT + 1]; 14 | cpu_emulator_t *em; 15 | } profiler_instr_t; 16 | 17 | static void p_init(void *ptr, cpu_emulator_t *em) { 18 | profiler_instr_t *instance = (profiler_instr_t *)ptr; 19 | memset((void *)instance->profile_counts, 0, sizeof(instance->profile_counts)); 20 | instance->em = em; 21 | } 22 | 23 | static void p_profile_instruction(void *ptr, int pc, int opcode, int op1, int op2, int num_cycles) { 24 | profiler_instr_t *instance = (profiler_instr_t *)ptr; 25 | int bucket = OTHER_CONTEXT; 26 | if (pc >= instance->profile_min && pc <= instance->profile_max) { 27 | if (instance->profile_bucket < 2) { 28 | bucket = pc & 0xffff; 29 | } else { 30 | bucket = ((pc & 0xffff) / instance->profile_bucket) * instance->profile_bucket; 31 | } 32 | } 33 | instance->profile_counts[bucket].instructions++; 34 | instance->profile_counts[bucket].cycles += num_cycles; 35 | } 36 | 37 | static void p_done(void *ptr) { 38 | profiler_instr_t *instance = (profiler_instr_t *)ptr; 39 | profiler_output_helper(instance->profile_counts, 1, 0, instance->em); 40 | } 41 | 42 | void *profiler_instr_create(char *arg) { 43 | 44 | profiler_instr_t *instance = (profiler_instr_t *)calloc(1, sizeof(profiler_instr_t)); 45 | 46 | instance->profiler.name = "instr"; 47 | instance->profiler.arg = arg ? strdup(arg) : ""; 48 | instance->profiler.init = p_init; 49 | instance->profiler.profile_instruction = p_profile_instruction; 50 | instance->profiler.done = p_done; 51 | instance->profile_min = 0x0000; 52 | instance->profile_max = 0xffff; 53 | instance->profile_bucket = 1; 54 | 55 | if (arg && strlen(arg) > 0) { 56 | char *min = strtok(arg, ","); 57 | char *max = strtok(NULL, ","); 58 | char *bucket = strtok(NULL, ","); 59 | if (min && strlen(min) > 0) { 60 | instance->profile_min = strtol(min, (char **)NULL, 16); 61 | } 62 | if (max && strlen(max) > 0) { 63 | instance->profile_max = strtol(max, (char **)NULL, 16); 64 | } 65 | if (bucket && strlen(bucket) > 0) { 66 | instance->profile_bucket = strtol(bucket, (char **)NULL, 16); 67 | } 68 | } 69 | 70 | return instance; 71 | } 72 | -------------------------------------------------------------------------------- /src/symbols.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "defs.h" 7 | #include "symbols.h" 8 | 9 | typedef enum { 10 | SWS_GROUND, 11 | SWS_GOT_SQUARE, 12 | SWS_GOT_CURLY, 13 | SWS_IN_NAME, 14 | SWS_TOO_LONG, 15 | SWS_NAME_END, 16 | SWS_IN_VALUE, 17 | SWS_AWAIT_COMMA 18 | } swstate; 19 | 20 | // Being very lazy here using an array! 21 | static char **symbol_table = NULL; 22 | 23 | static int max_address = -1; 24 | 25 | void symbol_init(int size) { 26 | symbol_table = (char **)malloc(size * sizeof(char *)); 27 | for (int i = 0; i < size;i++) { 28 | symbol_table[i] = NULL; 29 | } 30 | max_address = size - 1; 31 | } 32 | 33 | void symbol_add(char *name, int address) { 34 | if (address >= 0 && address <= max_address) { 35 | char *copy = (char *)malloc(strlen(name)+1); 36 | strcpy(copy, name); 37 | symbol_table[address] = copy; 38 | } else { 39 | // This case should never happen 40 | fprintf(stderr, "symbol %s:%04x out of range\r\n", name, address); 41 | exit(1); 42 | } 43 | } 44 | 45 | char *symbol_lookup(int address) { 46 | if (address >= 0 && address <= max_address) { 47 | return symbol_table[address]; 48 | } else { 49 | return NULL; 50 | } 51 | } 52 | 53 | void symbol_import_swift(char *filename) 54 | { 55 | FILE *fp = fopen(filename, "r"); 56 | if (fp) { 57 | swstate state = SWS_GROUND; 58 | char name[80], *name_ptr, *name_end = name+sizeof(name); 59 | uint32_t addr; 60 | int ch, syms = 0; 61 | while ((ch = getc(fp)) != EOF) { 62 | switch(state) { 63 | case SWS_GROUND: 64 | if (ch == '[') 65 | state = SWS_GOT_SQUARE; 66 | break; 67 | case SWS_GOT_SQUARE: 68 | if (ch == '{') 69 | state = SWS_GOT_CURLY; 70 | else if (ch != '[') 71 | state = SWS_GROUND; 72 | break; 73 | case SWS_GOT_CURLY: 74 | if (ch == '\'') { 75 | name_ptr = name; 76 | state = SWS_IN_NAME; 77 | } 78 | else if (!strchr(" \t\r\n", ch)) 79 | state = SWS_GROUND; 80 | break; 81 | case SWS_IN_NAME: 82 | if (ch == '\'') { 83 | *name_ptr = 0; 84 | state = SWS_NAME_END; 85 | } 86 | else if (name_ptr >= name_end) { 87 | fprintf(stderr, "swift import name too long"); 88 | state = SWS_TOO_LONG; 89 | } 90 | else 91 | *name_ptr++ = ch; 92 | break; 93 | case SWS_TOO_LONG: 94 | if (ch == '\'') { 95 | name_ptr = 0; 96 | state = SWS_NAME_END; 97 | } 98 | break; 99 | case SWS_NAME_END: 100 | if (ch == ':') { 101 | addr = 0; 102 | state = SWS_IN_VALUE; 103 | } 104 | else if (!strchr(" \t\r\n", ch)) 105 | state = SWS_GROUND; 106 | break; 107 | case SWS_IN_VALUE: 108 | if (ch >= '0' && ch <= '9') 109 | addr = addr * 10 + ch - '0'; 110 | else if (ch == 'L') { 111 | symbol_add(name, addr); 112 | state = SWS_AWAIT_COMMA; 113 | syms++; 114 | } 115 | else if (ch == ',') { 116 | symbol_add(name, addr); 117 | state = SWS_GOT_CURLY; 118 | syms++; 119 | } 120 | else 121 | state = SWS_GROUND; 122 | break; 123 | case SWS_AWAIT_COMMA: 124 | if (ch == ',') 125 | state = SWS_GOT_CURLY; 126 | else if (!strchr(" \t\r\n", ch)) 127 | state = SWS_GROUND; 128 | } 129 | } 130 | fclose(fp); 131 | } 132 | else 133 | fprintf(stderr, "unable to open '%s': %s\n", filename, strerror(errno)); 134 | } 135 | -------------------------------------------------------------------------------- /src/symbols.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYMBOLS_H 2 | 3 | #define _SYMBOLS_H 4 | 5 | void symbol_init(int size); 6 | 7 | void symbol_add(char *name, int address); 8 | 9 | char *symbol_lookup(int address); 10 | 11 | void symbol_import_swift(char *filename); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /src/tube_decode.h: -------------------------------------------------------------------------------- 1 | #ifndef _TUBE_DECODE_H 2 | #define _TUBE_DECODE_H 3 | 4 | #include 5 | 6 | void tube_read(int reg, uint8_t data); 7 | void tube_write(int reg, uint8_t data); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /test/816_blitter/hog816_emu.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoglet67/6502Decoder/6bfa89ae49c9dffafb0a90026fe0fab44ed14b2a/test/816_blitter/hog816_emu.data -------------------------------------------------------------------------------- /test/816_blitter/hog816_interrupt.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoglet67/6502Decoder/6bfa89ae49c9dffafb0a90026fe0fab44ed14b2a/test/816_blitter/hog816_interrupt.data -------------------------------------------------------------------------------- /test/816_blitter/hog816_native.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoglet67/6502Decoder/6bfa89ae49c9dffafb0a90026fe0fab44ed14b2a/test/816_blitter/hog816_native.data -------------------------------------------------------------------------------- /test/816_blitter/snes_tests.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoglet67/6502Decoder/6bfa89ae49c9dffafb0a90026fe0fab44ed14b2a/test/816_blitter/snes_tests.data -------------------------------------------------------------------------------- /test/beeb/reset.bin.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoglet67/6502Decoder/6bfa89ae49c9dffafb0a90026fe0fab44ed14b2a/test/beeb/reset.bin.gz -------------------------------------------------------------------------------- /test/beebr65c02/reset.bin.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoglet67/6502Decoder/6bfa89ae49c9dffafb0a90026fe0fab44ed14b2a/test/beebr65c02/reset.bin.gz -------------------------------------------------------------------------------- /test/clean_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | declare -a machine_names 4 | 5 | machine_names=( 6 | master 7 | beeb 8 | elk 9 | beebr65c02 10 | ) 11 | 12 | for machine in "${machine_names[@]}" 13 | do 14 | rm -f ${machine}/*.tmp 15 | rm -f ${machine}/*.log 16 | done 17 | -------------------------------------------------------------------------------- /test/elk/reset.bin.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoglet67/6502Decoder/6bfa89ae49c9dffafb0a90026fe0fab44ed14b2a/test/elk/reset.bin.gz -------------------------------------------------------------------------------- /test/master/reset.bin.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoglet67/6502Decoder/6bfa89ae49c9dffafb0a90026fe0fab44ed14b2a/test/master/reset.bin.gz -------------------------------------------------------------------------------- /test/run_816_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [[ `uname` = Darwin ]]; then 4 | STATARGS=-f%z 5 | else 6 | STATARGS=-c%s 7 | fi 8 | 9 | 10 | # Parse the command line options 11 | POSITIONAL=() 12 | REF=0 13 | while [[ $# -gt 0 ]] 14 | do 15 | key="$1" 16 | 17 | case $key in 18 | -r|--ref|--reference) 19 | REF=1 20 | shift # past argument 21 | ;; 22 | *) # unknown option 23 | POSITIONAL+=("$1") # save it in an array for later 24 | shift # past argument 25 | ;; 26 | esac 27 | done 28 | 29 | DECODE=../decode6502 30 | 31 | common_options="--machine=beeb --debug=0 --mem=FFF --cpu=65816 -a -h -i -y -s --sp=01E0 --phi2= --rdy= --rst= --e=" 32 | 33 | declare -A test_options 34 | 35 | # Tests to run in emulation mode 36 | test_options[drass]="--emul=1 --pb=00 --db=00 --dp=0000" 37 | test_options[brk]="--emul=1 --pb=00 --db=00 --dp=0000" 38 | test_options[optest1]="--emul=1 --pb=00 --db=00 --dp=0000 --sp=01FD" 39 | test_options[optest2]="--emul=1 --pb=00 --db=00 --dp=0000 --sp=01FD" 40 | test_options[optest3]="--emul=1 --pb=00 --db=00 --dp=0000" 41 | test_options[romcopy_hipoke_17]="--emul=1 --pb=00 --db=00 --dp=0000" 42 | test_options[reset]="--emul=1 --pb=00 --db=00 --dp=0000" 43 | test_options[test]="--emul=1 --pb=00 --db=00 --dp=0000" 44 | test_options[hog816_emu]="--emul=1 --pb=00 --db=00 --dp=0000" 45 | test_options[dormann_d6502]="--emul=1 --pb=00 --db=00 --dp=0000 --sp= --quiet --mem=00F" 46 | test_options[dp2100]="--emul=1 --pb=00 --db=00 --dp=0000" 47 | test_options[dp2101]="--emul=1 --pb=00 --db=00 --dp=0000" 48 | test_options[dp2180]="--emul=1 --pb=00 --db=00 --dp=0000" 49 | test_options[dp21ff]="--emul=1 --pb=00 --db=00 --dp=0000" 50 | 51 | 52 | # Tests to run in native mode 53 | test_options[hog816_interrupt]="--emul=0 --pb=01 --db=01 --dp=1900 --sp=01FD" 54 | test_options[hog816_native]="--emul=0 --pb=01 --db=01 --dp=1900" 55 | test_options[snes_tests]="--machine=blitter --emul=0 --pb=00 --db=00 --dp=0000" 56 | 57 | for data in `find 816* -name '*.data' | sort` 58 | do 59 | 60 | 61 | name=`basename ${data}` 62 | name=${name%.data} 63 | 64 | echo $name; 65 | 66 | log=${data%.data}.log 67 | ref=${data%.data}.ref 68 | dif=${data%.data}.dif 69 | 70 | echo "${DECODE} ${common_options} ${test_options[${name}]} ${data} > ${log}" 71 | ${DECODE} ${common_options} ${test_options[${name}]} ${data} > ${log} 72 | 73 | fail_count=`grep fail ${log} | wc -l` 74 | md5=`md5sum ${log} | cut -c1-8` 75 | size=$(stat ${STATARGS} "${log}") 76 | 77 | 78 | diff_count="-1" 79 | 80 | # If the --ref option is given, then save the current log file as a reference 81 | if [ "${REF}" == "1" ]; then 82 | mv ${log} ${ref} 83 | else 84 | if [ -f ${ref} ]; then 85 | diff ${ref} ${log} | head -10000 > ${dif} 86 | diff_count=`wc -l <${dif}` 87 | fi 88 | fi 89 | 90 | echo " Trace MD5: ${md5}; Prediction fail count: ${fail_count}; Reference diff count: ${diff_count}" 91 | 92 | 93 | echo 94 | 95 | 96 | # if [ "${fail_count}" != "0" ]; then 97 | # echo 98 | # grep -10 -m 100 fail ${log} 99 | # echo 100 | # fi 101 | 102 | done 103 | -------------------------------------------------------------------------------- /test/run_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DECODE=../decode6502 4 | 5 | EXTENDED_TEST_FILE_BASE="https://github.com/hoglet67/6502Decoder/releases/download/test_data" 6 | EXTENDED_TEST_FILE_NAME="extended_tests.zip" 7 | 8 | MAXDIFFSIZE=500000000 9 | 10 | common_options="--phi2= --mem=FFF" 11 | 12 | machine_names=( 13 | beeb 14 | master 15 | elk 16 | beebr65c02 17 | ) 18 | 19 | declare -A machine_options 20 | 21 | machine_options[master]="--machine=master" 22 | machine_options[beeb]="--machine=beeb" 23 | machine_options[elk]="--machine=elk" 24 | machine_options[beebr65c02]="--machine=beeb --cpu=r65c02" 25 | 26 | data_names=( 27 | reset 28 | ) 29 | 30 | extended_data_names=( 31 | dormann_d6502 32 | dormann_d65c00 33 | dormann_d65c01 34 | dormann_d65c10 35 | dormann_d65c11 36 | clark_bcd_full 37 | ) 38 | 39 | declare -A data_options 40 | 41 | data_options[reset]="-h -s" 42 | data_options[dormann_d6502]="--quiet" 43 | data_options[dormann_d65c00]="--quiet" 44 | data_options[dormann_d65c01]="--quiet" 45 | data_options[dormann_d65c10]="--quiet" 46 | data_options[dormann_d65c11]="--quiet" 47 | data_options[clark_bcd_full]="--quiet" 48 | 49 | test_names=( 50 | sync 51 | sync_nornw 52 | sync_norst 53 | sync_nordy 54 | sync_nornw_norst 55 | sync_nornw_nordy 56 | sync_norst_nordy 57 | sync_nornw_norst_nordy 58 | nosync 59 | nosync_nornw 60 | nosync_norst 61 | nosync_nordy 62 | nosync_nornw_norst 63 | nosync_nornw_nordy 64 | nosync_norst_nordy 65 | nosync_nornw_norst_nordy 66 | ) 67 | 68 | declare -A test_options 69 | 70 | test_options[sync]="" 71 | test_options[sync_nornw]="--rnw=" 72 | test_options[sync_norst]="--rst=" 73 | test_options[sync_nordy]="--rdy=" 74 | test_options[sync_nornw_norst]="--rnw= --rst=" 75 | test_options[sync_nornw_nordy]="--rnw= --rdy=" 76 | test_options[sync_norst_nordy]="--rst= --rdy=" 77 | test_options[sync_nornw_norst_nordy]="--rnw= --rst= --rdy=" 78 | test_options[nosync]="--sync=" 79 | test_options[nosync_nornw]="--sync= --rnw=" 80 | test_options[nosync_norst]="--sync= --rst=" 81 | test_options[nosync_nordy]="--sync= --rdy=" 82 | test_options[nosync_nornw_norst]="--sync= --rnw= --rst=" 83 | test_options[nosync_nornw_nordy]="--sync= --rnw= --rdy=" 84 | test_options[nosync_norst_nordy]="--sync= --rst= --rdy=" 85 | test_options[nosync_nornw_norst_nordy]="--sync= --rnw= --rst= --rdy=" 86 | 87 | # Use the sync based decoder as the deference 88 | ref=${test_names[0]} 89 | 90 | # Parse the command line options 91 | POSITIONAL=() 92 | EXTENDED=0 93 | while [[ $# -gt 0 ]] 94 | do 95 | key="$1" 96 | 97 | case $key in 98 | -e|--extended) 99 | EXTENDED=1 100 | shift # past argument 101 | ;; 102 | *) # unknown option 103 | POSITIONAL+=("$1") # save it in an array for later 104 | shift # past argument 105 | ;; 106 | esac 107 | done 108 | 109 | if [ "${EXTENDED}" == "1" ]; then 110 | echo "Running extended tests:" 111 | wget -nv -N ${EXTENDED_TEST_FILE_BASE}/${EXTENDED_TEST_FILE_NAME} 112 | unzip -o ${EXTENDED_TEST_FILE_NAME} 113 | data_names+=(${extended_data_names[@]}) 114 | else 115 | echo "Running basic tests:" 116 | fi 117 | 118 | if [[ `uname` = Darwin ]]; then 119 | STATARGS=-f%z 120 | else 121 | STATARGS=-c%s 122 | fi 123 | 124 | for data in "${data_names[@]}" 125 | do 126 | for machine in "${machine_names[@]}" 127 | do 128 | if [ -f ${machine}/${data}.bin.gz ]; then 129 | # First, generate all the data for the test cases 130 | echo "==============================================================================" 131 | echo "Running ${machine} ${data} tests" 132 | echo "==============================================================================" 133 | echo 134 | gunzip < ${machine}/${data}.bin.gz > ${machine}/${data}.tmp 135 | refmd5="" 136 | reflog="" 137 | for test in "${test_names[@]}" 138 | do 139 | log=${machine}/trace_${data}_${test}.log 140 | runcmd="${DECODE} ${common_options} ${data_options[${data}]} ${machine_options[${machine}]} ${test_options[${test}]} ${machine}/${data}.tmp > ${log}" 141 | echo "Test: ${test}" 142 | echo " % ${runcmd}" 143 | eval $runcmd 144 | # If the file contains a RESET marker, prune any lines before this 145 | if grep -q RESET ${log}; then 146 | sed -n '/RESET/,$p' < ${log} > tmp.log 147 | mv tmp.log ${log} 148 | fi 149 | fail_count=`grep fail ${log} | wc -l` 150 | md5=`md5sum ${log} | cut -c1-8` 151 | size=$(stat ${STATARGS} "${log}") 152 | echo " Trace MD5: ${md5}; Prediction fail count: ${fail_count}" 153 | # Log some context around each failure (limit to 100 failures) 154 | # Compare md5 of results with ref, rather than using diff, as diff can blow up 155 | if [ "${test}" == "${ref}" ]; then 156 | refmd5=${md5} 157 | reflog=${machine}/trace_${data}_${ref}.log 158 | echo " this is the reference trace" 159 | if [ "${fail_count}" != "0" ]; then 160 | echo 161 | grep -10 -m 100 fail ${log} 162 | echo 163 | fi 164 | elif [ "${md5}" == "${refmd5}" ]; then 165 | echo -e " \e[32mPASS\e[97m: test trace matches reference trace" 166 | else 167 | if [ "${fail_count}" != "0" ]; then 168 | echo 169 | grep -10 -m 100 fail ${log} 170 | echo 171 | fi 172 | difcmd="diff ${reflog} ${log}" 173 | if (( size < MAXDIFFSIZE )); then 174 | diff_count=`${difcmd} | wc -l` 175 | echo -e " \e[31mFAIL\e[97m: test trace doesn't match reference trace; Diff Count: " ${diff_count} 176 | else 177 | echo -e " \e[31mFAIL\e[97m: test trace doesn't match reference trace; file too large too diff" 178 | fi 179 | echo " % ${difcmd}" 180 | fi 181 | echo 182 | done 183 | fi 184 | done 185 | done 186 | --------------------------------------------------------------------------------