├── ujprog ├── ftd2xx.h ├── ftd2xx.lib ├── ulx2s_prep.sh ├── Makefile.osx ├── Makefile.bsd ├── Makefile.win ├── Makefile.linux ├── Makefile.ming32_64 ├── Makefile.ming32 ├── ft232r_flash.c ├── README.md └── ujprog.c └── f32cup ├── README.md ├── f32cup.ino └── f32cup.py /ujprog/ftd2xx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f32c/tools/HEAD/ujprog/ftd2xx.h -------------------------------------------------------------------------------- /ujprog/ftd2xx.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/f32c/tools/HEAD/ujprog/ftd2xx.lib -------------------------------------------------------------------------------- /ujprog/ulx2s_prep.sh: -------------------------------------------------------------------------------- 1 | #!/bin/csh 2 | 3 | ft232r_flash -p $1 4 | ujprog -p $1 -e fprog.bin ulx2s_8e.jed 5 | ujprog -p $1 -j flash ulx2s_8e.jed 6 | -------------------------------------------------------------------------------- /ujprog/Makefile.osx: -------------------------------------------------------------------------------- 1 | CFLAGS += -Wall `pkg-config --cflags libusb libftdi` 2 | LDFLAGS += `pkg-config --libs libusb libftdi` 3 | 4 | # Install libusb-compat, libftdi0, pkg-config with 'brew install libusb-compat libftdi0 pkg-config' 5 | 6 | ujprog: ujprog.c 7 | ${CC} ${CFLAGS} $^ ${LDFLAGS} -o $@ 8 | 9 | flash: ft232r_flash.c 10 | ${CC} ${CFLAGS} $^ ${LDFLAGS} -lusb -o $@ 11 | 12 | install: ujprog 13 | install -m 4755 ujprog /usr/local/bin 14 | 15 | clean: 16 | rm -f ujprog flash 17 | 18 | depend: 19 | mkdep ${INCLUDES} ${SRCS} 20 | -------------------------------------------------------------------------------- /ujprog/Makefile.bsd: -------------------------------------------------------------------------------- 1 | 2 | SRCS = ujprog.c 3 | INCLUDES = -I/usr/local/include 4 | LIBDIRS = -L/usr/local/lib 5 | CFLAGS += -Wall -Wextra ${INCLUDES} 6 | FTLIB = /usr/local/lib/libftdi.a 7 | 8 | ujprog: ${SRCS} 9 | ${CC} ${CFLAGS} ${LIBDIRS} -lusb ${SRCS} ${FTLIB} -o ujprog 10 | 11 | flash: ft232r_flash.c 12 | ${CC} ${CFLAGS} ${LIBDIRS} -lusb ft232r_flash.c ${FTLIB} -o ft232r_flash 13 | 14 | install: ujprog 15 | install -m 4755 ujprog /usr/local/bin 16 | 17 | clean: 18 | rm -f ujprog ujprog.o 19 | 20 | depend: 21 | mkdep ${INCLUDES} ${SRCS} 22 | -------------------------------------------------------------------------------- /ujprog/Makefile.win: -------------------------------------------------------------------------------- 1 | # Project: ujprog 2 | 3 | CPP = g++.exe 4 | CC = gcc.exe 5 | WINDRES = windres.exe 6 | RES = 7 | OBJ = ujprog.o $(RES) 8 | LINKOBJ = ujprog.o $(RES) 9 | LIBS = -s -static -L. -lftd2xx 10 | INCS = -I. 11 | CXXINCS = -I. 12 | BIN = ujprog.exe 13 | CXXFLAGS = $(CXXINCS) -wAll 14 | CFLAGS = $(INCS) 15 | RM = rm -f 16 | 17 | .PHONY: all all-before all-after clean clean-custom 18 | 19 | all: all-before ujprog.exe all-after 20 | 21 | 22 | clean: clean-custom 23 | ${RM} $(OBJ) $(BIN) 24 | 25 | $(BIN): $(OBJ) 26 | $(CC) $(LINKOBJ) -lftd2xx -o "ujprog.exe" $(LIBS) 27 | 28 | ujprog.o: ujprog.c 29 | $(CC) -c ujprog.c -o ujprog.o $(CFLAGS) 30 | -------------------------------------------------------------------------------- /ujprog/Makefile.linux: -------------------------------------------------------------------------------- 1 | 2 | SRCS = ujprog.c 3 | CFLAGS += -Wall -D__linux__ -std=gnu99 -static 4 | 5 | # for linux on PC (i386/amd64) 6 | ARCHNAME = $(shell uname -m)-linux-gnu 7 | # for linux on raspberrypi-3 8 | # ARCHNAME = arm-linux-gnueabihf 9 | 10 | FTLIB = /usr/lib/${ARCHNAME}/libftdi.a 11 | #FTLIB = -lftdi 12 | USBLIB = /usr/lib/${ARCHNAME}/libusb.a 13 | 14 | ujprog: ${SRCS} 15 | ${CC} ${CFLAGS} ${SRCS} ${FTLIB} ${USBLIB} -o ujprog 16 | 17 | flash: ft232r_flash.c 18 | ${CC} ${CFLAGS} -lusb ft232r_flash.c ${FTLIB} -o ft232r_flash 19 | 20 | install: ujprog 21 | install -m 4755 ujprog /usr/local/bin 22 | 23 | clean: 24 | rm -f ujprog ujprog.o *~ 25 | 26 | depend: 27 | mkdep ${INCLUDES} ${SRCS} 28 | -------------------------------------------------------------------------------- /f32cup/README.md: -------------------------------------------------------------------------------- 1 | # f32c binary uploader (python and arduino) 2 | 3 | Simple source code for uploading f32c binary executable over serial port. 4 | (The port where "f32l>" prompt appears). 5 | 6 | # Python 7 | 8 | Python source to upload and execute f32c binary code. 9 | Tested on linux. Default speed 115200, optionally it 10 | can do 3 Mbit upload: 11 | 12 | f32cup.py -b3e6 file.bin 13 | 14 | # Arduino 15 | 16 | Arduino source to upload and execute f32c binary code. 17 | Tested on ESP32 arduino. 18 | 19 | Needs f32c bistream with auto pass-thru option but 20 | still it's not enough auto, serial break must be sent 21 | from PC first then it will work: 22 | 23 | ujprog -r -P /dev/ttyUSB0 24 | 25 | TODO 26 | 27 | [x] High speed upload (3 Mbit) 28 | [ ] How to send Serial break on ESP32 29 | [ ] Make f32c bitstream auto-switch to ESP32 30 | when serial break is detected on ESP32 line 31 | -------------------------------------------------------------------------------- /ujprog/Makefile.ming32_64: -------------------------------------------------------------------------------- 1 | # Project: ujprog 2 | 3 | # apt-get install mingw-w64) 4 | # Note this uses the 64bit ftd2xx.amd64.lib (CDM v2.12.28 WHQL Certified\amd64\ftd2xx.lib) 5 | 6 | CPP = x86_64-w64-mingw32-gcc 7 | CC = x86_64-w64-mingw32-gcc 8 | 9 | FTDI_ZIP_URL = "https://ftdichip.com/wp-content/uploads/2023/09/CDM-v2.12.36.4-WHQL-Certified.zip" 10 | FTDI_ZIP_FILE = ftdi.zip 11 | FTDI_LIB_UNZIPPED = amd64/ftd2xx 12 | 13 | WINDRES = windres.exe 14 | RES = 15 | OBJ = ujprog.o $(RES) 16 | LINKOBJ = ujprog.o $(RES) 17 | LIBS = -s -static -L. -l$(FTDI_LIB_UNZIPPED) 18 | INCS = -I. 19 | CXXINCS = -I. 20 | BIN = ujprog.exe 21 | CXXFLAGS = $(CXXINCS) -wAll 22 | CFLAGS = $(INCS) 23 | RM = rm -f 24 | 25 | .PHONY: all all-before all-after clean clean-custom 26 | 27 | all: all-before ujprog.exe all-after 28 | 29 | 30 | clean: clean-custom 31 | ${RM} $(OBJ) $(BIN) $(FTDI_LIB_UNZIPPED).lib $(FTDI_ZIP_FILE) 32 | 33 | $(FTDI_ZIP_FILE): 34 | wget -c $(FTDI_ZIP_URL) -O ftdi.zip 35 | 36 | $(FTDI_LIB_UNZIPPED).lib: $(FTDI_ZIP_FILE) 37 | unzip $< $@ 38 | touch $@ 39 | 40 | $(BIN): $(OBJ) $(FTDI_LIB_UNZIPPED).lib 41 | $(CC) $(LINKOBJ) -o "ujprog.exe" $(LIBS) 42 | 43 | ujprog.o: ujprog.c 44 | $(CC) -c ujprog.c -o ujprog.o $(CFLAGS) 45 | -------------------------------------------------------------------------------- /ujprog/Makefile.ming32: -------------------------------------------------------------------------------- 1 | # Project: ujprog 2 | 3 | # dpkg --add-architecture i386 4 | # apt-get update 5 | # apt-get install gcc-mingw-w64 6 | # this uses the same ftd2xx.lib as used for linux (CDM v2.12.28 WHQL Certified\i386\ftd2xx.lib) 7 | 8 | CPP = i686-w64-mingw32-gcc 9 | CC = i686-w64-mingw32-gcc 10 | 11 | FTDI_ZIP_URL = "https://www.ftdichip.com/Drivers/CDM/CDM%20v2.12.28%20WHQL%20Certified.zip" 12 | FTDI_ZIP_FILE = ftdi.zip 13 | FTDI_LIB_UNZIPPED = i386/ftd2xx 14 | 15 | WINDRES = windres.exe 16 | RES = 17 | OBJ = ujprog.o $(RES) 18 | LINKOBJ = ujprog.o $(RES) 19 | LIBS = -m32 -s -static -L. -l$(FTDI_LIB_UNZIPPED) 20 | INCS = -I. 21 | CXXINCS = -I. 22 | BIN = ujprog.exe 23 | CXXFLAGS = $(CXXINCS) -wAll 24 | CFLAGS = $(INCS) -m32 25 | RM = rm -f 26 | 27 | .PHONY: all all-before all-after clean clean-custom 28 | 29 | all: all-before ujprog.exe all-after 30 | 31 | 32 | clean: clean-custom 33 | ${RM} $(OBJ) $(BIN) $(FTDI_LIB_UNZIPPED).lib $(FTDI_ZIP_FILE) 34 | 35 | $(FTDI_ZIP_FILE): 36 | wget -c $(FTDI_ZIP_URL) -O ftdi.zip 37 | 38 | $(FTDI_LIB_UNZIPPED).lib: $(FTDI_ZIP_FILE) 39 | unzip $< $@ 40 | touch $@ 41 | 42 | $(BIN): $(OBJ) $(FTDI_LIB_UNZIPPED).lib 43 | $(CC) $(LINKOBJ) -o "ujprog.exe" $(LIBS) 44 | 45 | ujprog.o: ujprog.c 46 | $(CC) -c ujprog.c -o ujprog.o $(CFLAGS) 47 | -------------------------------------------------------------------------------- /ujprog/ft232r_flash.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | 10 | #define FT232_EEPROM_SIZE 128 11 | 12 | static struct ftdi_context fc; /* USB port handle */ 13 | 14 | unsigned char buf[FT232_EEPROM_SIZE] = { 15 | 0x00, 0x40, 0x03, 0x04, 0x01, 0x60, 0x00, 0x06, 16 | 0x80, 0xAF, 0x00, 0x00, 0x00, 0x00, 0x98, 0x08, 17 | 0xA0, 0x38, 0xC2, 0x12, 0xA1, 0xAA, 0x01, 0x00, 18 | 0x08, 0x03, 0x46, 0x00, 0x45, 0x00, 0x52, 0x00, 19 | 0x38, 0x03, 0x46, 0x00, 0x45, 0x00, 0x52, 0x00, 20 | 0x20, 0x00, 0x55, 0x00, 0x4C, 0x00, 0x58, 0x00, 21 | 0x32, 0x00, 0x53, 0x00, 0x20, 0x00, 0x62, 0x00, 22 | 0x6F, 0x00, 0x61, 0x00, 0x72, 0x00, 0x64, 0x00, 23 | 0x20, 0x00, 0x4A, 0x00, 0x54, 0x00, 0x41, 0x00, 24 | 0x47, 0x00, 0x20, 0x00, 0x2F, 0x00, 0x20, 0x00, 25 | 0x55, 0x00, 0x41, 0x00, 0x52, 0x00, 0x54, 0x00, 26 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 27 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 28 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 29 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 30 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAE, 0xD3, 31 | }; 32 | 33 | 34 | int 35 | main(int argc, char *argv[]) { 36 | int res, c, port_index = 0; 37 | 38 | while ((c = getopt(argc, argv, "p:")) != -1) { 39 | switch (c) { 40 | case 'p': 41 | port_index = atoi(optarg); 42 | break; 43 | default: 44 | exit (EXIT_FAILURE); 45 | } 46 | } 47 | 48 | res = ftdi_init(&fc); 49 | if (res < 0) { 50 | fprintf(stderr, "ftdi_init() failed\n"); 51 | return (res); 52 | } 53 | 54 | res = ftdi_usb_open_desc_index(&fc, 0x0403, 0x6001, 55 | NULL, NULL, port_index); 56 | if (res < 0) { 57 | fprintf(stderr, "ftdi_usb_open() failed\n"); 58 | return (res); 59 | } 60 | 61 | #if 0 62 | res = ftdi_read_eeprom(&fc, buf); 63 | if (res < 0) { 64 | fprintf(stderr, "ftdi_read_eprom() failed\n"); 65 | return (res); 66 | } 67 | 68 | for (int i = 0; i < FT232_EEPROM_SIZE; i++) { 69 | #if 1 70 | printf("0x%02X, ", buf[i]); 71 | #else 72 | if (buf[i] >= 32 && buf[i] < 127) 73 | printf("%c ", buf[i]); 74 | else 75 | printf(". "); 76 | #endif 77 | if ((i & 7) == 7) 78 | printf("\n"); 79 | } 80 | #else 81 | res = ftdi_write_eeprom(&fc, buf); 82 | if (res < 0) { 83 | fprintf(stderr, "ftdi_read_eprom() failed\n"); 84 | return (res); 85 | } 86 | 87 | #endif 88 | 89 | res = ftdi_usb_reset(&fc); 90 | if (res < 0) { 91 | fprintf(stderr, "ftdi_usb_reset() failed\n"); 92 | return (res); 93 | } 94 | 95 | sleep(1); 96 | libusb_reset_device((void *) fc.usb_dev); 97 | 98 | res = ftdi_usb_close(&fc); 99 | return (res); 100 | } 101 | -------------------------------------------------------------------------------- /ujprog/README.md: -------------------------------------------------------------------------------- 1 | # ULX2S / ULX3S JTAG programmer usage: 2 | 3 | ``` 4 | ULX2S / ULX3S JTAG programmer v 3.0.92 5 | Usage: ujprog [option(s)] [bitstream_file] 6 | 7 | Valid options: 8 | -p PORT Select USB JTAG / UART PORT (default is 0) 9 | -P TTY Select TTY port (valid only with -t or -a) 10 | -j TARGET Select bitstream TARGET as SRAM (default) or FLASH (XP2 only) 11 | -f ADDR Start writing to SPI flash at ADDR, optional with -j flash 12 | -s FILE Convert bitstream to SVF FILE and exit 13 | -r Reload FPGA configuration from internal Flash (XP2 only) 14 | -t Enter terminal emulation mode after completing JTAG operations 15 | -b SPEED Set baudrate to SPEED (300 to 3000000 bauds) 16 | -e FILE Send and execute a f32c (MIPS/RISCV) binary FILE 17 | -x SPEED Set binary transfer speed, optional with -e 18 | -a FILE Send a raw FILE 19 | -d debug (verbose) 20 | -D DELAY Delay transmission of each byte by DELAY ms 21 | -q Suppress messages 22 | ``` 23 | 24 | # Compiling 25 | 26 | Unless regularly compiling for different targets, consider copying or 27 | symlinking the respective `Makefile.[target]` to your `Makefile` and 28 | use just "make" to compile, for example 29 | 30 | `ln -s Makefile.linux Makefile` 31 | 32 | `make` 33 | 34 | 35 | ## BSD 36 | 37 | `make -f Makefile.bsd` 38 | 39 | 40 | ## Linux PC (i386/amd64) 41 | Native linux Debian/Ubuntu, maybe many others too, 42 | including WSL Ubuntu, but reminder there's no WSL support for USB devices, only tty! 43 | 44 | `make -f Makefile.linux` 45 | 46 | 47 | ## Linux RaspberryPI-3 (armhf) 48 | 49 | Edit Makefile.linux and enable this: 50 | `ARCHNAME = arm-linux-gnueabihf` 51 | 52 | `make -f Makefile.linux` 53 | 54 | 55 | ## OSX 56 | 57 | `make -f Makefile.osx` 58 | 59 | 60 | ## Windows 61 | 62 | `make -f Makefile.win` 63 | 64 | # Troubleshooting 65 | 66 | *** WINDOWS *** 67 | 68 | Most issues come from windows platform. In some cases 69 | ujprog doesn't work. Sometimes it is just a matter of dynamic 70 | linking (DLL file "ftd2xx.dll" or "ftd2xx64.dll", easiest is 71 | just to copy this file from FTDI D2XX CDM driver to the same 72 | directory where ujprog.exe is) 73 | 74 | On VoIFS there is strange problem related with ujprog.exe 75 | compiled with mingw. ujprog.exe, if started from "wrong" directory 76 | doesn't work. When started from "wrong" directory, ujprog.exe 77 | will exit without printing any error or any other message while 78 | it should print help/usage message shown on top of this page. 79 | Possible cause of this problem is that "ftd2xx64.dll" (for win64) 80 | is found copied to System32 directory under name "ftd2xx.dll" (for win32). 81 | 82 | Possible solution would be to remove all ftd2xx copies and copy 83 | ujprog.exe and dll to another directory and try again. 84 | 85 | *** LINUX *** 86 | 87 | Here we have much better success, ujprog is statically linked and 88 | doesn't depend on any other file. Most issues come from user permissions 89 | so ujprog should be either run as root or the user should be given 90 | permissions to access USB and serial device, that's usually done 91 | easily with some udev rule: 92 | 93 | # /etc/udev/rules.d/80-fpga-ulx3s.rules 94 | # this is for usb-serial tty device 95 | SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", \ 96 | MODE="664", GROUP="dialout" 97 | # this is for ujprog libusb access 98 | ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", \ 99 | GROUP="dialout", MODE="666" 100 | 101 | *** APPLE *** 102 | 103 | There can be many problems, I don't know what to do 104 | one of the issues is that ujprog executable may needs 105 | some dynamic linked library of specific version like libusb 106 | 107 | -------------------------------------------------------------------------------- /f32cup/f32cup.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | String Filename = "/ULX3S/f32c-bin/autoexec.bin"; 4 | uint32_t Start_addr = 0x80000000; // the adress to load the binary 5 | 6 | uint8_t Retry_block = 5, Retry_crc = 4; 7 | uint32_t serial_baud_default = 115200; // don't touch 8 | uint32_t serial_baud_upload = 115200; 9 | uint32_t serial_break_duration = 150; // ms (serial break currenty doesn't work) 10 | uint32_t serial_baud_current = serial_baud_default; 11 | 12 | int File_len = 0; 13 | 14 | #define __CS_SD 13 15 | #define __CS_TFT 17 16 | #define __DC_TFT 16 17 | #define __RES_TFT 25 18 | #define __MOSI_TFT 15 19 | #define __MISO_TFT 2 20 | #define __SCL_TFT 14 21 | 22 | #define TXD_PIN 1 23 | 24 | int SD_mounted = -999; 25 | 26 | void setup() 27 | { 28 | Serial.begin(serial_baud_default); 29 | serial_baud_current = serial_baud_default; 30 | pinMode(LED_BUILTIN, OUTPUT); 31 | } 32 | 33 | void serial_port_send_break(int duration) 34 | { 35 | #if 1 36 | Serial.write((char)0xFF); 37 | delay(duration); 38 | return; 39 | #endif 40 | // following code code does not work 41 | // TODO: how to make serial break on ESP32 ? 42 | #if 0 43 | //Serial.end(); 44 | delay(100); 45 | pinMode(TXD_PIN, OUTPUT); 46 | digitalWrite(TXD_PIN, HIGH); 47 | delay(100); 48 | //Serial.write(0); 49 | digitalWrite(TXD_PIN, LOW); 50 | delay(duration); 51 | digitalWrite(TXD_PIN, HIGH); 52 | //Serial.begin(serial_baud_default); 53 | #endif 54 | } 55 | 56 | void serial_port_reset_input_buffer() 57 | { 58 | } 59 | 60 | void serial_port_reset_output_buffer() 61 | { 62 | } 63 | 64 | uint32_t crc_block(uint8_t *data, uint32_t len) 65 | { 66 | uint32_t crc = 0; 67 | for(uint32_t i = 0; i < len; i++) 68 | { 69 | crc = ((crc >> 31) | (crc << 1)); 70 | crc += *data; 71 | data++; 72 | } 73 | return crc; 74 | } 75 | 76 | int try_to_get_prompt(int retries) 77 | { 78 | uint8_t reply[255]; 79 | if(serial_baud_current != serial_baud_default) 80 | { 81 | Serial.begin(serial_baud_default); 82 | serial_baud_current = serial_baud_default; 83 | } 84 | serial_port_send_break(serial_break_duration); 85 | while(retries > 0) 86 | { 87 | serial_port_reset_input_buffer(); 88 | serial_port_reset_output_buffer(); 89 | Serial.write('\r'); 90 | delay(20); 91 | Serial.readBytes(reply, 20); 92 | String str_reply = (char *)reply; 93 | if(str_reply.indexOf("m32l> ") >= 0) 94 | return 1; // MIPS little-endian prompt is found 95 | if(str_reply.indexOf("rv32> ") >= 0) 96 | return 5; // RISC-V prompt is found 97 | retries--; 98 | } 99 | return 0; // failure 100 | } 101 | 102 | uint32_t read32(uint8_t *addr) 103 | { 104 | uint32_t value = 0; 105 | for(int i = 0; i < 4; i++) 106 | value = (value << 8) | addr[i]; 107 | return value; 108 | } 109 | 110 | uint32_t receive_crc(uint8_t retry_crc, int sleep_ms) 111 | { 112 | uint32_t crc; 113 | uint8_t read_crc[4]; 114 | size_t read_crc_len; 115 | while(retry_crc > 0) 116 | { 117 | if( (retry_crc & 0) == 0 ) 118 | { 119 | serial_port_reset_input_buffer(); 120 | serial_port_reset_output_buffer(); 121 | Serial.write((char)0x81); // request f32c to send checksum 122 | } 123 | read_crc_len = Serial.readBytes(read_crc, sizeof(read_crc)); // read 4 bytes of checksum 124 | crc = read32(read_crc); 125 | if(read_crc_len == sizeof(read_crc)) 126 | return crc; 127 | crc++; // hopfully should destroy previous crc 128 | delay(sleep_ms); 129 | retry_crc--; 130 | } 131 | return crc; 132 | } 133 | 134 | 135 | void write32(uint8_t *addr, uint32_t value) 136 | { 137 | for(int i = 3; i >= 0; i--) 138 | { 139 | addr[i] = (uint8_t) value; 140 | value >>= 8; 141 | } 142 | } 143 | 144 | int upload_block(uint32_t addr, uint32_t len, uint8_t *chunk, uint8_t first) 145 | { 146 | uint32_t expected_crc = crc_block(chunk, len); 147 | uint32_t received_crc = ~expected_crc; 148 | int8_t retry_block = Retry_block; 149 | uint32_t serial_port_baudrate; 150 | static uint8_t cmd_baud[6] = {0x80, 0,0,0,0, 0xB0}; 151 | static uint8_t cmd_block[12] = {0x80, 0,0,0,0, 0x90, 0x80, 0,0,0,0, 0xA0}; 152 | while(retry_block > 0) 153 | { 154 | if(first) 155 | { 156 | serial_port_baudrate = serial_baud_default; 157 | if(try_to_get_prompt(3) > 0) 158 | { 159 | Serial.write((char)0xFF); 160 | if(serial_baud_upload != serial_baud_default) 161 | { 162 | write32(cmd_baud+1, serial_baud_upload); 163 | Serial.write(cmd_baud, sizeof(cmd_baud)); 164 | Serial.flush(); 165 | //Serial.end(); 166 | //delay(100); 167 | Serial.begin(serial_baud_upload); 168 | serial_baud_current = serial_baud_upload; 169 | } 170 | } 171 | } 172 | serial_port_reset_input_buffer(); 173 | serial_port_reset_output_buffer(); 174 | write32(cmd_block+1, len); 175 | write32(cmd_block+7, addr); 176 | Serial.write(cmd_block, sizeof(cmd_block)); 177 | Serial.write(chunk, len); 178 | received_crc = receive_crc(Retry_crc, 20); 179 | if(received_crc == expected_crc) 180 | return 1; // success 181 | retry_block--; 182 | } 183 | return 0; // failure after retries 184 | } 185 | 186 | void jump(uint32_t addr) 187 | { 188 | static uint8_t cmd_jump[6] = {0x80, 0,0,0,0, 0xB1}; 189 | write32(cmd_jump+1, addr); 190 | Serial.write(cmd_jump, sizeof(cmd_jump)); 191 | } 192 | 193 | #define DEBUG 0 194 | int sd_mount() 195 | { 196 | // initialize the SD card 197 | if(!SD.begin(__CS_SD, SPI, 20000000, "/sd")) 198 | { 199 | #if DEBUG 200 | Serial.println("Card Mount Failed"); 201 | #endif 202 | return -1; 203 | } 204 | uint8_t cardType = SD.cardType(); 205 | if(cardType == CARD_NONE) 206 | { 207 | SD.end(); 208 | #if DEBUG 209 | Serial.println("No SD card attached"); 210 | #endif 211 | return -2; 212 | } 213 | return 0; // success 214 | } 215 | 216 | void sd_unmount() 217 | { 218 | SD.end(); 219 | } 220 | 221 | int exec_binary(fs::FS &storage, String filename, uint32_t start_addr) 222 | { 223 | File binary_file = storage.open(Filename); 224 | File_len = binary_file.size(); 225 | if(File_len <= 0) 226 | return 0; 227 | int block_retval = 1; 228 | uint32_t index = 0; 229 | const int buflen = 512; 230 | uint8_t data[buflen]; 231 | while(binary_file.available() > 0 && block_retval == 1) 232 | { 233 | int len = binary_file.read(data, buflen); 234 | int first = index == 0 ? 1 : 0; 235 | int last = index + len >= File_len ? 1 : 0; 236 | block_retval = upload_block(start_addr + index, len, data, first); 237 | if(last == 1 && block_retval == 1) 238 | jump(start_addr); 239 | index += len; 240 | } 241 | return block_retval; 242 | } 243 | 244 | void loop() 245 | { 246 | static int led = 0; 247 | #if 0 248 | // test serial break 249 | serial_port_send_break(serial_break_duration); 250 | led = ~led; 251 | digitalWrite(LED_BUILTIN, led); 252 | delay(1000); 253 | #else 254 | // upload and execute binary code 255 | int upload_retval; 256 | SD_mounted = sd_mount(); 257 | if(SD_mounted == 0) 258 | { 259 | upload_retval = exec_binary(SD, Filename, Start_addr); 260 | if(upload_retval) 261 | led = ~led; 262 | sd_unmount(); 263 | } 264 | digitalWrite(LED_BUILTIN, led); 265 | delay(3000); 266 | #endif 267 | } 268 | 269 | -------------------------------------------------------------------------------- /f32cup/f32cup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | import getopt 6 | import serial 7 | import time 8 | import struct 9 | 10 | 11 | print("f32c python uploader v1.0") 12 | f32c_serial_device_name = "/dev/ttyUSB0" 13 | f32c_filename = sys.argv[-1] 14 | 15 | # byte length of chunked file read and upload 16 | chunksize = 8192 17 | # seconds to hold serial break 18 | serial_break_duration = 0.1 19 | # bps serial 20 | serial_baud_default = 115200 # normal f32c prompt speed after reset (don't touch) 21 | serial_baud_upload = 115200 # upload speed - 115200 or 3000000 (3 Mbit) 22 | # seconds for serial port timeout 23 | serial_timeout = 0.2 24 | # serial file open descriptor 25 | serial_port = None 26 | # file open descriptor 27 | input_fd = None 28 | 29 | def get_cmdline_options(): 30 | global opts 31 | global extraparams 32 | 33 | global chunksize 34 | global serial_break_duration 35 | global serial_baud_default 36 | global serial_baud_upload 37 | global f32c_filename 38 | global f32c_serial_device_name 39 | 40 | opts, extraparams = getopt.getopt( 41 | sys.argv[1:], 42 | 'p:b:f:h', 43 | ['port=', 'baud=', 'break=', 'chunk=', 'file=', "help"] 44 | ) 45 | 46 | for o,p in opts: 47 | if o in ['-b','--baud']: 48 | serial_baud_upload = int(float(p)+0.5) 49 | elif o in ['--chunk']: 50 | chunksize = int(p) 51 | elif o in ['--break']: 52 | serial_break_duration = float(p) 53 | elif o in ['-f','--file']: 54 | f32c_filename = p 55 | elif o in ['-p','--port']: 56 | f32c_serial_device_name = p 57 | elif o in ['-h','--help']: 58 | print("usage: options filename") 59 | print(" option unit meaning:"); 60 | print(" [-p|--port=string] serial port (default /dev/ttyUSB0)") 61 | print(" [-b|--baud=float] bps baudrate (default 115200)") 62 | print(" [--chunk=int] bytes chunk size (default 8192)") 63 | print(" [--break=float] s chunk size (default 0.1)") 64 | print(" [-h|--help] this help message") 65 | return 0 66 | return 1 67 | 68 | 69 | 70 | def parse_cmd_options(): 71 | return 72 | 73 | # keep on resetting several times 74 | # by sending serial break until 75 | # prompt is received or give up 76 | def try_to_get_prompt(retries = 2): 77 | global serial_port 78 | global serial_break_duration 79 | while retries > 0: 80 | serial_port.reset_input_buffer() 81 | serial_port.reset_output_buffer() 82 | serial_port.send_break(duration = 1000.0 * serial_break_duration) # ms duration 83 | serial_port.write(b" ") 84 | reply = serial_port.read(20) 85 | if reply.find(b"m32l> "): 86 | return 1 # MIPS little-endian prompt is found 87 | #if reply.find(b"m32b> "): 88 | # return 2 # MIPS big-endian prompt is found (unsupported) 89 | if reply.find(b"rv32> "): 90 | return 5 # RISC-V prompt is found 91 | print(reply) 92 | print("retry %d" % (retries,) ) 93 | retries -= 1 94 | return 0 # prompt not found 95 | 96 | 97 | # calculate block's CRC 98 | def crc_block(chunk): 99 | crc = 0 100 | for byte in chunk: 101 | crc = ((crc >> 31) | (crc << 1)) 102 | crc = (crc + byte) & 0xFFFFFFFF 103 | return crc 104 | 105 | 106 | def receive_crc(retry_crc = 4, sleep_s = 10.0e-3): 107 | global serial_port 108 | crc = (None, ) 109 | while retry_crc > 0: 110 | if (retry_crc & 0) == 0: # every other retry time request checksum 111 | serial_port.reset_input_buffer() 112 | serial_port.reset_output_buffer() 113 | serial_port.write(b"\x81") # request to read checksum 114 | read_crc = serial_port.read(4) # read 4 bytes of potential CRC response 115 | if len(read_crc) == 4: 116 | # print(read_crc) 117 | crc = struct.unpack(">L", read_crc) 118 | break 119 | #else: 120 | # print(read_crc) 121 | time.sleep(sleep_s) # after not receiving, sleep 10 ms 122 | retry_crc -= 1 # decrement and try again to receive crc 123 | return crc[0] 124 | 125 | 126 | def upload_block(addr, chunk, first = True, retry_block = 5, retry_crc = 4): 127 | global serial_port 128 | global serial_baud_default 129 | global serial_baud_upload 130 | # print("%08X" % addr) 131 | length = len(chunk) 132 | expected_crc = crc_block(chunk) 133 | # print("BASE=%08X CRC=%08X LEN=%d" % (addr, expected_crc, length) ) 134 | while retry_block > 0: 135 | # first block will reset f32c and initialize binary transfer 136 | if first: 137 | serial_port.baudrate = serial_baud_default 138 | if try_to_get_prompt() > 0: 139 | # print("got f32c prompt") 140 | serial_port.write(b"\xFF") # request binary upload 141 | # time.sleep(10.0e-3) 142 | # change baudrate if not default 143 | if serial_baud_upload != serial_baud_default: 144 | header = b"\x80" + struct.pack(">L", serial_baud_upload) + b"\xB0" 145 | serial_port.write(header) 146 | serial_port.flush() 147 | serial_port.baudrate = serial_baud_upload 148 | else: 149 | break # go to retry 150 | # construct header that requests block upload packet, 151 | # with encoded length and block start address 152 | serial_port.reset_input_buffer() 153 | serial_port.reset_output_buffer() 154 | header = b"\x80" + struct.pack(">L", length) + b"\x90" \ 155 | + b"\x80" + struct.pack(">L", addr) + b"\xA0" 156 | serial_port.write(header + chunk) 157 | received_crc = receive_crc() 158 | if received_crc != None: 159 | if received_crc == expected_crc: 160 | print("ADDR 0x%08X LEN %d CRC 0x%08X OK" % (addr, length, expected_crc) ) 161 | return 1 # success 162 | else: 163 | # print("crc mismatch") 164 | print("ADDR 0x%08X LEN %d CRC expected:0x%08X, received:0x%08X RETRY %d" % (addr, length, expected_crc, received_crc, retry_block,) ) 165 | else: 166 | # serial_port.write(b"\xFF") # request binary upload 167 | # time.sleep(0.1) 168 | print("CRC not received, RETRY %d" % retry_block) 169 | retry_block -= 1 170 | return 0 # failure after retries 171 | 172 | 173 | def jump(start_address): 174 | global serial_port 175 | header = b"\x80" + struct.pack(">L", start_address) + b"\xb1" 176 | serial_port.write(header) 177 | 178 | 179 | def read_upload_jump(): 180 | global f32c_filename 181 | input_fd=open(os.path.expanduser(f32c_filename), "rb") 182 | if input_fd: 183 | # HEADER: read first 16 bytes from input file 184 | # to determine file type and start address 185 | header = input_fd.read(16) 186 | start_address = 0 187 | if header[2:4] == b"\x10\x3C" \ 188 | and header[6:8] == b"\x10\x26" \ 189 | and header[10:12] == b"\x11\x3C" \ 190 | and header[14:16] == b"\x31\x26": 191 | print("MIPS Little-Endian file") 192 | start_address = (header[1] << 24) + (header[0] << 16) + (header[5] << 8) + header[4] 193 | if header[0:2] == b"\x97\x0F" \ 194 | and header[4:6] == b"\x93\x81": 195 | print("RISC-V Little-Endian file") 196 | start_address = 0x400 # FIXME HARDCODED LOAD ADDRESS FIXME 197 | # print("start_address:0x%08X" % start_address) 198 | chunk = header 199 | block_start = start_address 200 | success = 1 # assume success 201 | while True: 202 | chunk += input_fd.read(chunksize) 203 | if not chunk: 204 | break 205 | if upload_block(block_start, chunk, first=(block_start==start_address) ) == 0: 206 | success = 0 # failure, don't jumo 207 | break 208 | block_start += len(chunk) 209 | chunk = b"" 210 | input_fd.close() 211 | # return serial port to default baudrate before starting the binary 212 | if serial_baud_upload != serial_baud_default: 213 | header = b"\x80" + struct.pack(">L", serial_baud_default) + b"\xb0" 214 | serial_port.write(header) 215 | time.sleep(50.0e-3) 216 | serial_port.baudrate = serial_baud_default 217 | if success > 0: 218 | jump(start_address) 219 | print("JUMP 0x%08X" % (start_address,) ) 220 | 221 | 222 | def main(): 223 | global f32c_serial_device_name 224 | global serial_baud_default 225 | global serial_port 226 | 227 | if get_cmdline_options(): 228 | serial_port=serial.Serial(f32c_serial_device_name, serial_baud_default, rtscts=False, timeout=serial_timeout) 229 | read_upload_jump() 230 | serial_port.close() 231 | 232 | main() 233 | -------------------------------------------------------------------------------- /ujprog/ujprog.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FT-232R / FT-231X USB JTAG programmer 3 | * 4 | * Copyright (c) 2010 - 2025 Marko Zec 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 | * SUCH DAMAGE. 26 | */ 27 | 28 | /* 29 | * TODO: 30 | * 31 | * - WIN32: check for USB device string description 32 | * 33 | * - JTAG scan / identify chain on entry. 34 | * 35 | * - verify SRAM / FLASH 36 | * 37 | * - RUN TEST delay downscaling. 38 | * 39 | * - disable resetting the TAP on entry / leave? 40 | * 41 | * - execute SVF commands provided as command line args? 42 | */ 43 | 44 | static const char *verstr = "ULX2S / ULX3S JTAG programmer v 3.2"; 45 | 46 | 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | 56 | #define USE_RAW 57 | 58 | #ifdef __FreeBSD__ 59 | #define USE_PPI 60 | #endif 61 | 62 | #if defined(__linux__) || defined(WIN32) 63 | #define isnumber(x) (x >= '0' && x <= '9') 64 | #endif 65 | 66 | #ifdef WIN32 67 | #include 68 | #include 69 | #include 70 | #else 71 | #include 72 | #include 73 | #include 74 | #ifdef USE_PPI 75 | #include 76 | #include 77 | #endif 78 | #include 79 | #endif 80 | 81 | #ifdef WIN32 82 | #define BITMODE_OFF 0x0 83 | #define BITMODE_BITBANG 0x1 84 | #define BITMODE_SYNCBB 0x4 85 | #define BITMODE_CBUS 0x20 86 | #endif 87 | 88 | /* Forward declarations */ 89 | static int commit(int); 90 | static void set_state(int); 91 | static int exec_svf_tokenized(int, char **); 92 | static int send_dr(int, char *, char *, char *); 93 | static int send_ir(int, char *, char *, char *); 94 | static int exec_svf_mem(char *, int, int); 95 | static int cmp_chip_ids(char *, char *); 96 | 97 | 98 | enum svf_cmd { 99 | SVF_SDR, SVF_SIR, SVF_STATE, SVF_RUNTEST, SVF_HDR, SVF_HIR, 100 | SVF_TDR, SVF_TIR, SVF_ENDDR, SVF_ENDIR, SVF_FREQUENCY, 101 | SVF_TRST, SVF_UNKNOWN 102 | }; 103 | 104 | static struct svf_cmdtable { 105 | enum svf_cmd cmd_id; 106 | char *cmd_str; 107 | } svf_cmdtable[] = { 108 | {SVF_SDR, "SDR"}, 109 | {SVF_SIR, "SIR"}, 110 | {SVF_STATE, "STATE"}, 111 | {SVF_RUNTEST, "RUNTEST"}, 112 | {SVF_HDR, "HDR"}, 113 | {SVF_HIR, "HIR"}, 114 | {SVF_TDR, "TDR"}, 115 | {SVF_TIR, "TIR"}, 116 | {SVF_ENDDR, "ENDDR"}, 117 | {SVF_ENDIR, "ENDIR"}, 118 | {SVF_FREQUENCY, "FREQUENCY"}, 119 | {SVF_TRST, "TRST"}, 120 | {SVF_UNKNOWN, NULL} 121 | }; 122 | 123 | 124 | enum tap_state { 125 | RESET, IDLE, 126 | DRSELECT, DRCAPTURE, DRSHIFT, DREXIT1, DRPAUSE, DREXIT2, DRUPDATE, 127 | IRSELECT, IRCAPTURE, IRSHIFT, IREXIT1, IRPAUSE, IREXIT2, IRUPDATE, 128 | UNDEFINED, UNSUPPORTED, 129 | }; 130 | 131 | static struct tap_statetable { 132 | enum tap_state state_id; 133 | char *state_str; 134 | } tap_statetable[] = { 135 | {RESET, "RESET"}, 136 | {IDLE, "IDLE"}, 137 | {DRSELECT, "DRSELECT"}, 138 | {DRCAPTURE, "DRCAPTURE"}, 139 | {DRSHIFT, "DRSHIFT"}, 140 | {DREXIT1, "DREXIT1"}, 141 | {DRPAUSE, "DRPAUSE"}, 142 | {DREXIT2, "DREXIT2"}, 143 | {DRUPDATE, "DRUPDATE"}, 144 | {IRSELECT, "IRSELECT"}, 145 | {IRCAPTURE, "IRCAPTURE"}, 146 | {IRSHIFT, "IRSHIFT"}, 147 | {IREXIT1, "IREXIT1"}, 148 | {IRPAUSE, "IRPAUSE"}, 149 | {IREXIT2, "IREXIT2"}, 150 | {IRUPDATE, "IRUPDATE"}, 151 | {UNDEFINED, "UNDEFINED"}, 152 | {UNSUPPORTED, NULL} 153 | }; 154 | 155 | #define STATE2STR(state) (tap_statetable[state].state_str) 156 | 157 | 158 | enum port_mode { 159 | PORT_MODE_ASYNC, PORT_MODE_SYNC, PORT_MODE_UART, PORT_MODE_UNKNOWN 160 | }; 161 | typedef enum port_mode port_mode_t; 162 | static port_mode_t port_mode = PORT_MODE_UNKNOWN; 163 | 164 | 165 | static enum cable_hw { 166 | CABLE_HW_USB, CABLE_HW_PPI, CABLE_HW_COM, CABLE_RAW, CABLE_UNKNOWN 167 | } cable_hw = CABLE_UNKNOWN; 168 | 169 | 170 | static struct cable_hw_map { 171 | int cable_hw; 172 | int usb_vid; 173 | int usb_pid; 174 | char *cable_path; 175 | char tck, tms, tdi, tdo; 176 | char cbus_led; 177 | } cable_hw_map[] = { 178 | #ifdef USE_RAW 179 | { 180 | .cable_hw = CABLE_RAW, 181 | .cable_path = "raw bitstream output", 182 | .tms = 0x02, 183 | .tdi = 0x01, 184 | }, 185 | #endif 186 | { 187 | .cable_hw = CABLE_HW_USB, 188 | .usb_vid = 0x0403, 189 | .usb_pid = 0x6001, 190 | .cable_path = "FER ULXP2 board JTAG / UART", 191 | .tck = 0x20, 192 | .tms = 0x80, 193 | .tdi = 0x08, 194 | .tdo = 0x40, 195 | .cbus_led = 0x02 196 | }, 197 | { 198 | .cable_hw = CABLE_HW_USB, 199 | .usb_vid = 0x0403, 200 | .usb_pid = 0x6001, 201 | .cable_path = "FER ULX2S board JTAG / UART", 202 | .tck = 0x20, 203 | .tms = 0x80, 204 | .tdi = 0x08, 205 | .tdo = 0x40, 206 | .cbus_led = 0x02 207 | }, 208 | { 209 | .cable_hw = CABLE_HW_USB, 210 | .usb_vid = 0x0403, 211 | .usb_pid = 0x6015, 212 | .cable_path = "ULX3S FPGA board", 213 | .tck = 0x20, 214 | .tms = 0x40, 215 | .tdi = 0x80, 216 | .tdo = 0x08, 217 | .cbus_led = 0x00 218 | }, 219 | { 220 | .cable_hw = CABLE_HW_USB, 221 | .usb_vid = 0x0403, 222 | .usb_pid = 0x6015, 223 | .cable_path = "ULX3S FPGA v1.7", 224 | .tck = 0x20, 225 | .tms = 0x40, 226 | .tdi = 0x80, 227 | .tdo = 0x08, 228 | .cbus_led = 0x00 229 | }, 230 | { 231 | .cable_hw = CABLE_HW_USB, 232 | .usb_vid = 0x0403, 233 | .usb_pid = 0x6015, 234 | .cable_path = "ULX3S FPGA 25K v1.7", 235 | .tck = 0x20, 236 | .tms = 0x40, 237 | .tdi = 0x80, 238 | .tdo = 0x08, 239 | .cbus_led = 0x00 240 | }, 241 | { 242 | .cable_hw = CABLE_HW_USB, 243 | .usb_vid = 0x0403, 244 | .usb_pid = 0x6015, 245 | .cable_path = "ULX3S FPGA 45K v1.7", 246 | .tck = 0x20, 247 | .tms = 0x40, 248 | .tdi = 0x80, 249 | .tdo = 0x08, 250 | .cbus_led = 0x00 251 | }, 252 | { 253 | .cable_hw = CABLE_HW_USB, 254 | .usb_vid = 0x0403, 255 | .usb_pid = 0x6015, 256 | .cable_path = "ULX3S FPGA 12K v2.1.2", 257 | .tck = 0x20, 258 | .tms = 0x40, 259 | .tdi = 0x80, 260 | .tdo = 0x08, 261 | .cbus_led = 0x00 262 | }, 263 | { 264 | .cable_hw = CABLE_HW_USB, 265 | .usb_vid = 0x0403, 266 | .usb_pid = 0x6015, 267 | .cable_path = "ULX3S FPGA 25K v2.1.2", 268 | .tck = 0x20, 269 | .tms = 0x40, 270 | .tdi = 0x80, 271 | .tdo = 0x08, 272 | .cbus_led = 0x00 273 | }, 274 | { 275 | .cable_hw = CABLE_HW_USB, 276 | .usb_vid = 0x0403, 277 | .usb_pid = 0x6015, 278 | .cable_path = "ULX3S FPGA 45K v2.1.2", 279 | .tck = 0x20, 280 | .tms = 0x40, 281 | .tdi = 0x80, 282 | .tdo = 0x08, 283 | .cbus_led = 0x00 284 | }, 285 | { 286 | .cable_hw = CABLE_HW_USB, 287 | .usb_vid = 0x0403, 288 | .usb_pid = 0x6015, 289 | .cable_path = "ULX3S FPGA 85K v2.1.2", 290 | .tck = 0x20, 291 | .tms = 0x40, 292 | .tdi = 0x80, 293 | .tdo = 0x08, 294 | .cbus_led = 0x00 295 | }, 296 | { 297 | .cable_hw = CABLE_HW_USB, 298 | .usb_vid = 0x0403, 299 | .usb_pid = 0x6015, 300 | .cable_path = "ULX3S FPGA 12K v3.0.3", 301 | .tck = 0x20, 302 | .tms = 0x40, 303 | .tdi = 0x80, 304 | .tdo = 0x08, 305 | .cbus_led = 0x00 306 | }, 307 | { 308 | .cable_hw = CABLE_HW_USB, 309 | .usb_vid = 0x0403, 310 | .usb_pid = 0x6015, 311 | .cable_path = "ULX3S FPGA 25K v3.0.3", 312 | .tck = 0x20, 313 | .tms = 0x40, 314 | .tdi = 0x80, 315 | .tdo = 0x08, 316 | .cbus_led = 0x00 317 | }, 318 | { 319 | .cable_hw = CABLE_HW_USB, 320 | .usb_vid = 0x0403, 321 | .usb_pid = 0x6015, 322 | .cable_path = "ULX3S FPGA 45K v3.0.3", 323 | .tck = 0x20, 324 | .tms = 0x40, 325 | .tdi = 0x80, 326 | .tdo = 0x08, 327 | .cbus_led = 0x00 328 | }, 329 | { 330 | .cable_hw = CABLE_HW_USB, 331 | .usb_vid = 0x0403, 332 | .usb_pid = 0x6015, 333 | .cable_path = "ULX3S FPGA 85K v3.0.3", 334 | .tck = 0x20, 335 | .tms = 0x40, 336 | .tdi = 0x80, 337 | .tdo = 0x08, 338 | .cbus_led = 0x00 339 | }, 340 | { 341 | .cable_hw = CABLE_HW_USB, 342 | .usb_vid = 0x0403, 343 | .usb_pid = 0x6015, 344 | .cable_path = "ULX3S FPGA 12K v3.0.7", 345 | .tck = 0x20, 346 | .tms = 0x40, 347 | .tdi = 0x80, 348 | .tdo = 0x08, 349 | .cbus_led = 0x00 350 | }, 351 | { 352 | .cable_hw = CABLE_HW_USB, 353 | .usb_vid = 0x0403, 354 | .usb_pid = 0x6015, 355 | .cable_path = "ULX3S FPGA 25K v3.0.7", 356 | .tck = 0x20, 357 | .tms = 0x40, 358 | .tdi = 0x80, 359 | .tdo = 0x08, 360 | .cbus_led = 0x00 361 | }, 362 | { 363 | .cable_hw = CABLE_HW_USB, 364 | .usb_vid = 0x0403, 365 | .usb_pid = 0x6015, 366 | .cable_path = "ULX3S FPGA 45K v3.0.7", 367 | .tck = 0x20, 368 | .tms = 0x40, 369 | .tdi = 0x80, 370 | .tdo = 0x08, 371 | .cbus_led = 0x00 372 | }, 373 | { 374 | .cable_hw = CABLE_HW_USB, 375 | .usb_vid = 0x0403, 376 | .usb_pid = 0x6015, 377 | .cable_path = "ULX3S FPGA 85K v3.0.7", 378 | .tck = 0x20, 379 | .tms = 0x40, 380 | .tdi = 0x80, 381 | .tdo = 0x08, 382 | .cbus_led = 0x00 383 | }, 384 | { 385 | .cable_hw = CABLE_HW_USB, 386 | .usb_vid = 0x0403, 387 | .usb_pid = 0x6010, 388 | .cable_path = "Lattice ECP5 Evaluation Board", 389 | .tck = 0x01, 390 | .tms = 0x08, 391 | .tdi = 0x02, 392 | .tdo = 0x04, 393 | .cbus_led = 0x10 394 | }, 395 | { 396 | .cable_hw = CABLE_HW_USB, 397 | .usb_vid = 0x0403, 398 | .usb_pid = 0x6011, 399 | .cable_path = "Digilent FFC", 400 | .tck = 0x01, 401 | .tms = 0x08, 402 | .tdi = 0x02, 403 | .tdo = 0x04, 404 | .cbus_led = 0x00 405 | }, 406 | { 407 | .cable_hw = CABLE_HW_USB, 408 | .usb_vid = 0x0403, 409 | .usb_pid = 0x6015, 410 | .cable_path = "ISP UART / JTAG", 411 | .tck = 0x20, 412 | .tms = 0x40, 413 | .tdi = 0x80, 414 | .tdo = 0x08, 415 | .cbus_led = 0x00 416 | }, 417 | { 418 | .cable_hw = CABLE_UNKNOWN, 419 | .cable_path = "UNKNOWN" 420 | } 421 | }; 422 | 423 | 424 | #define USB_BAUDS 1000000 425 | 426 | #define JTAG_TCK (hmp->tck) 427 | #define JTAG_TMS (hmp->tms) 428 | #define JTAG_TDI (hmp->tdi) 429 | #define JTAG_TDO (hmp->tdo) 430 | 431 | #define USB_CBUS_LED (hmp->cbus_led) 432 | 433 | #define PPI_TCK 0x02 434 | #define PPI_TMS 0x04 435 | #define PPI_TDI 0x01 436 | #define PPI_TDO 0x40 437 | 438 | #define USB_BUFLEN_ASYNC 8192 439 | #ifdef WIN32 440 | #define USB_BUFLEN_SYNC 4096 441 | #else 442 | #define USB_BUFLEN_SYNC 384 443 | #endif 444 | 445 | #define BUFLEN_MAX USB_BUFLEN_ASYNC /* max(SYNC, ASYNC) */ 446 | 447 | #define LED_BLINK_RATE 250 448 | 449 | #define BREAK_MS 250 450 | #define PULSE_MS 50 451 | 452 | #define SPI_PAGE_SIZE 256 453 | #define SPI_SECTOR_SIZE (256 * SPI_PAGE_SIZE) 454 | 455 | static char *statc = "-\\|/"; 456 | 457 | /* Runtime globals */ 458 | static int cur_s = UNDEFINED; 459 | static uint8_t txbuf[32 * 1024 * 1024]; 460 | static uint8_t rxbuf[32 * 1024 * 1024]; 461 | static char svfbuf[32 * 1024 * 1024]; 462 | static unsigned txpos; 463 | static int need_led_blink; /* Schedule CBUS led toggle */ 464 | static int last_ledblink_ms; /* Last time we toggled the CBUS LED */ 465 | static int led_state; /* CBUS LED indicator state */ 466 | static int blinker_phase; 467 | static int progress_perc; 468 | static int bauds = 115200; /* async terminal emulation baudrate */ 469 | static int xbauds; /* binary transfer baudrate */ 470 | static int port_index; 471 | static int terminal; /* terminal emulation mode */ 472 | static int reload; /* send break to reset f32c */ 473 | static int quiet; /* suppress standard messages */ 474 | char *svf_name; /* SVF output name */ 475 | static int txfu_ms; /* txt file upload character delay (ms) */ 476 | static int tx_binary; /* send in raw (0) or binary (1) format */ 477 | static const char *txfname; /* file to send */ 478 | static const char *com_name; /* COM / TTY port name for -a or -t */ 479 | static int spi_addr; /* Base address for -j flash programming */ 480 | static int global_debug; 481 | static int cbusval = -1; 482 | 483 | static struct cable_hw_map *hmp; /* Selected cable hardware map */ 484 | #ifdef WIN32 485 | static FT_HANDLE ftHandle; /* USB port handle */ 486 | static HANDLE com_port; /* COM port file */ 487 | static struct _DCB tty; /* COM port TTY handle */ 488 | #else 489 | static struct ftdi_context fc; /* USB port handle */ 490 | static int com_port; /* COM port file */ 491 | static struct termios tty; /* COM port TTY handle */ 492 | #ifdef USE_PPI 493 | static int ppi; /* Parallel port handle */ 494 | #endif 495 | #endif 496 | 497 | 498 | /* ms_sleep() sleeps for at least the number of milliseconds given as arg */ 499 | #define ms_sleep(delay_ms) usleep((delay_ms) * 1000) 500 | 501 | 502 | static long 503 | ms_uptime(void) 504 | { 505 | long ms; 506 | #ifndef WIN32 507 | struct timeval tv; 508 | 509 | gettimeofday(&tv, 0); 510 | ms = tv.tv_sec * 1000 + tv.tv_usec / 1000; 511 | #else 512 | ms = GetTickCount(); 513 | #endif 514 | return (ms); 515 | } 516 | 517 | 518 | static int 519 | set_port_mode(port_mode_t mode) 520 | { 521 | int res = 0; 522 | 523 | /* No-op if already in requested mode, or not using USB */ 524 | if (!need_led_blink && 525 | (port_mode == mode || cable_hw != CABLE_HW_USB)) { 526 | port_mode = mode; 527 | return (0); 528 | } 529 | 530 | /* Flush any stale TX buffers */ 531 | commit(1); 532 | 533 | /* Blink status LED by deactivating CBUS pulldown pin */ 534 | if (need_led_blink) { 535 | need_led_blink = 0; 536 | led_state ^= USB_CBUS_LED; 537 | if (!quiet && progress_perc < 100) { 538 | fprintf(stderr, "\rProgramming: %d%% %c ", 539 | progress_perc, statc[blinker_phase]); 540 | fflush(stderr); 541 | } 542 | blinker_phase = (blinker_phase + 1) & 0x3; 543 | } 544 | 545 | #ifdef WIN32 546 | if (mode == PORT_MODE_ASYNC) 547 | mode = PORT_MODE_SYNC; 548 | #endif 549 | 550 | switch (mode) { 551 | case PORT_MODE_SYNC: 552 | #ifdef WIN32 553 | /* 554 | * If switching to SYNC mode, attempt to allow for TX 555 | * buffers to drain first. 556 | */ 557 | if (port_mode != PORT_MODE_SYNC) 558 | ms_sleep(20); 559 | 560 | res = FT_SetBitMode(ftHandle, 561 | #else 562 | res = ftdi_set_bitmode(&fc, 563 | #endif 564 | JTAG_TCK | JTAG_TMS | JTAG_TDI | led_state, 565 | BITMODE_SYNCBB | (BITMODE_CBUS * (USB_CBUS_LED != 0))); 566 | 567 | if (port_mode == PORT_MODE_SYNC) 568 | break; 569 | 570 | /* Flush any stale RX buffers */ 571 | #ifdef WIN32 572 | for (res = 0; res < 2; res++) { 573 | do { 574 | ms_sleep(10); 575 | } while (FT_StopInTask(ftHandle) != FT_OK); 576 | FT_Purge(ftHandle, FT_PURGE_RX); 577 | do {} while (FT_RestartInTask(ftHandle) != FT_OK); 578 | ms_sleep(10); 579 | } 580 | #else 581 | do { 582 | res = ftdi_read_data(&fc, &txbuf[0], sizeof(txbuf)); 583 | } while (res == sizeof(txbuf)); 584 | #endif 585 | break; 586 | 587 | case PORT_MODE_ASYNC: 588 | #ifdef WIN32 589 | res = FT_SetBitMode(ftHandle, 590 | #else 591 | res = ftdi_set_bitmode(&fc, 592 | #endif 593 | JTAG_TCK | JTAG_TMS | JTAG_TDI | led_state, 594 | BITMODE_BITBANG | (BITMODE_CBUS * (USB_CBUS_LED != 0))); 595 | break; 596 | 597 | case PORT_MODE_UART: 598 | res = 0; 599 | if (port_mode == PORT_MODE_UART) 600 | break; 601 | /* Pull TCK low so that we don't incidentally pulse it. */ 602 | memset(txbuf, 0, 10); 603 | #ifdef WIN32 604 | FT_Write(ftHandle, txbuf, 10, (DWORD *) &res); 605 | if (res < 0) { 606 | fprintf(stderr, "FT_Write() failed\n"); 607 | return (res); 608 | } 609 | res = FT_SetBitMode(ftHandle, 0, BITMODE_OFF); 610 | #else 611 | res = ftdi_write_data(&fc, &txbuf[0], 10); 612 | if (res < 0) { 613 | fprintf(stderr, "ftdi_write_data() failed\n"); 614 | return (res); 615 | } 616 | res = ftdi_disable_bitbang(&fc); 617 | #endif 618 | break; 619 | 620 | default: 621 | res = -1; 622 | } 623 | 624 | port_mode = mode; 625 | return (res); 626 | } 627 | 628 | 629 | #ifdef WIN32 630 | static int 631 | setup_usb(void) 632 | { 633 | FT_STATUS res; 634 | FT_DEVICE ftDevice; 635 | DWORD deviceID; 636 | char SerialNumber[16]; 637 | char Description[64]; 638 | 639 | res = FT_Open(port_index, &ftHandle); 640 | if (res != FT_OK) { 641 | fprintf(stderr, "FT_Open() failed\n"); 642 | return (res); 643 | } 644 | 645 | res = FT_GetDeviceInfo(ftHandle, &ftDevice, &deviceID, SerialNumber, 646 | Description, NULL); 647 | if (res != FT_OK) { 648 | fprintf(stderr, "FT_GetDeviceInfo() failed\n"); 649 | return (res); 650 | } 651 | for (hmp = cable_hw_map; hmp->cable_hw != CABLE_UNKNOWN; hmp++) { 652 | if ((deviceID == hmp->usb_vid << 16 | hmp->usb_pid) 653 | && strcmp(Description, hmp->cable_path) == 0) 654 | break; 655 | } 656 | if (hmp->cable_hw == CABLE_UNKNOWN) 657 | return (-1); 658 | 659 | if (!quiet) 660 | printf("Using USB cable: %s\n", hmp->cable_path); 661 | 662 | res = FT_SetBaudRate(ftHandle, USB_BAUDS); 663 | if (res != FT_OK) { 664 | fprintf(stderr, "FT_SetBaudRate() failed\n"); 665 | return (res); 666 | } 667 | 668 | #ifdef NOTYET 669 | FT_setUSB_Parameters(); 670 | res = ftdi_write_data_set_chunksize(&fc, BUFLEN_MAX); 671 | if (res < 0) { 672 | fprintf(stderr, "ftdi_write_data_set_chunksize() failed\n"); 673 | return (res); 674 | } 675 | #endif 676 | 677 | res = FT_SetLatencyTimer(ftHandle, 1); 678 | if (res != FT_OK) { 679 | fprintf(stderr, "FT_SetLatencyTimer() failed\n"); 680 | return (res); 681 | } 682 | 683 | res = FT_SetFlowControl(ftHandle, FT_FLOW_NONE, 0, 0); 684 | if (res != FT_OK) { 685 | fprintf(stderr, "FT_SetFlowControl() failed\n"); 686 | return (res); 687 | } 688 | 689 | res = FT_SetBitMode(ftHandle, 0, BITMODE_BITBANG); 690 | if (res != FT_OK) { 691 | fprintf(stderr, "FT_SetBitMode() failed\n"); 692 | return (res); 693 | } 694 | 695 | res = FT_SetTimeouts(ftHandle, 1000, 1000); 696 | if (res != FT_OK) { 697 | fprintf(stderr, "FT_SetTimeouts() failed\n"); 698 | return (res); 699 | } 700 | 701 | FT_Purge(ftHandle, FT_PURGE_TX); 702 | FT_Purge(ftHandle, FT_PURGE_RX); 703 | 704 | return (0); 705 | } 706 | 707 | 708 | static int 709 | shutdown_usb(void) 710 | { 711 | 712 | int res; 713 | 714 | /* Allow for the USB FIFO to drain, just in case. */ 715 | ms_sleep(10); 716 | 717 | /* Clean up */ 718 | res = set_port_mode(PORT_MODE_UART); 719 | if (res < 0) { 720 | fprintf(stderr, "set_port_mode() failed\n"); 721 | return (res); 722 | } 723 | 724 | res = FT_SetLatencyTimer(ftHandle, 20); 725 | if (res < 0) { 726 | fprintf(stderr, "FT_SetLatencyTimer() failed\n"); 727 | return (res); 728 | } 729 | 730 | res = FT_Close(ftHandle); 731 | if (res < 0) { 732 | fprintf(stderr, "FT_Close() failed\n"); 733 | return (res); 734 | } 735 | 736 | return (0); 737 | } 738 | #endif /* WIN32 */ 739 | 740 | 741 | #ifdef USE_RAW 742 | static int raw_pos; 743 | static int raw_csum; 744 | static char raw_ch; 745 | 746 | static int 747 | setup_raw(void) 748 | { 749 | 750 | for (hmp = cable_hw_map; hmp->cable_hw != CABLE_RAW; hmp++) { 751 | } 752 | 753 | /* XXX try to open output file for writing */ 754 | return (0); 755 | } 756 | 757 | static void 758 | srec_header(const char *name) 759 | { 760 | unsigned i; 761 | int csum; 762 | 763 | csum = strlen(name) + 3; 764 | printf("S0%02X0000", csum); 765 | 766 | for (i = 0; i < strlen(name); i++) { 767 | printf("%02X", name[i]); 768 | csum += name[i]; 769 | } 770 | 771 | printf("%02X\n", 0xff - (csum & 0xff)); 772 | } 773 | 774 | static int 775 | commit_raw(void) 776 | { 777 | unsigned i; 778 | 779 | for (i = 0; i < txpos; i += 2) { 780 | /* SREC line header */ 781 | if ((raw_pos & 0x7f) == 0) { 782 | printf("S224%06X", raw_pos >> 2); 783 | raw_csum = 0x24; 784 | raw_csum += (raw_pos >> 18) & 0xff; 785 | raw_csum += (raw_pos >> 10) & 0xff; 786 | raw_csum += (raw_pos >> 2) & 0xff; 787 | } 788 | 789 | raw_ch <<= 2; 790 | raw_ch |= txbuf[i] & 0x3; 791 | if ((raw_pos & 0x3) == 0x3) { 792 | printf("%02X", raw_ch & 0xff); 793 | raw_csum += raw_ch; 794 | } 795 | 796 | if ((raw_pos & 0x7f) == 0x7f) { 797 | printf("%02X\n", 0xff - (raw_csum & 0xff)); 798 | raw_csum = 0; 799 | } 800 | raw_pos++; 801 | } 802 | 803 | txpos = 0; 804 | return (0); 805 | } 806 | 807 | static void 808 | shutdown_raw(void) 809 | { 810 | 811 | /* Pad and flush SREC line */ 812 | if ((raw_pos & 0x7f) != 0x7f) { 813 | txpos = (0x80 - (raw_pos & 0x7f)) * 2; 814 | memset(txbuf, 0, txpos); 815 | commit_raw(); 816 | } 817 | printf("S804000000FB\n"); 818 | } 819 | #endif 820 | 821 | #ifndef WIN32 822 | #ifdef USE_PPI 823 | static int 824 | setup_ppi(void) 825 | { 826 | char c = 0; 827 | 828 | ppi = open("/dev/ppi0", O_RDWR); 829 | if (ppi < 0) 830 | return (errno); 831 | 832 | ioctl(ppi, PPISDATA, &c); 833 | ioctl(ppi, PPISSTATUS, &c); 834 | ioctl(ppi, PPIGSTATUS, &c); 835 | if ((c & 0xb6) != 0x06) { 836 | close (ppi); 837 | return (EINVAL); 838 | } 839 | 840 | return (0); 841 | } 842 | 843 | 844 | static void 845 | shutdown_ppi(void) 846 | { 847 | 848 | /* Pull TCK low so that we don't incidentally pulse it on next run. */ 849 | txbuf[0] = 0; 850 | ioctl(ppi, PPISDATA, &txbuf[0]); 851 | 852 | close (ppi); 853 | } 854 | #endif 855 | 856 | 857 | static int 858 | setup_usb(void) 859 | { 860 | int res; 861 | 862 | #ifdef __APPLE__ 863 | setuid(0); 864 | system("/sbin/kextunload" 865 | " -bundle-id com.FTDI.driver.FTDIUSBSerialDriver"); 866 | system("/sbin/kextunload" 867 | " -bundle-id com.apple.driver.AppleUSBFTDI"); 868 | #endif 869 | 870 | res = ftdi_init(&fc); 871 | if (res < 0) { 872 | fprintf(stderr, "ftdi_init() failed\n"); 873 | return (res); 874 | } 875 | 876 | for (hmp = cable_hw_map; hmp->cable_hw != CABLE_UNKNOWN; hmp++) { 877 | res = ftdi_usb_open_desc_index(&fc, hmp->usb_vid, hmp->usb_pid, 878 | hmp->cable_path, NULL, port_index); 879 | if (res == 0) 880 | break; 881 | } 882 | if (res < 0) { 883 | res = ftdi_usb_open_desc_index(&fc, 0x0403, 0x6001, 884 | NULL, NULL, port_index); 885 | if (res < 0) { 886 | #ifdef __APPLE__ 887 | system("/sbin/kextload" 888 | " -bundle-id com.FTDI.driver.FTDIUSBSerialDriver"); 889 | system("/sbin/kextload" 890 | " -bundle-id com.apple.driver.AppleUSBFTDI"); 891 | #endif 892 | return (res); 893 | } 894 | } 895 | 896 | res = ftdi_set_baudrate(&fc, USB_BAUDS); 897 | if (res < 0) { 898 | fprintf(stderr, "ftdi_set_baudrate() failed\n"); 899 | return (res); 900 | } 901 | 902 | res = ftdi_write_data_set_chunksize(&fc, BUFLEN_MAX); 903 | if (res < 0) { 904 | fprintf(stderr, "ftdi_write_data_set_chunksize() failed\n"); 905 | return (res); 906 | } 907 | 908 | /* Reducing latency to 1 ms for BITMODE_SYNCBB is crucial! */ 909 | res = ftdi_set_latency_timer(&fc, 1); 910 | if (res < 0) { 911 | fprintf(stderr, "ftdi_set_latency_timer() failed\n"); 912 | return (res); 913 | } 914 | 915 | res = ftdi_set_bitmode(&fc, JTAG_TCK | JTAG_TMS | JTAG_TDI, 916 | BITMODE_BITBANG); 917 | if (res < 0) { 918 | fprintf(stderr, "ftdi_set_bitmode() failed\n"); 919 | return (EXIT_FAILURE); 920 | } 921 | 922 | res = ftdi_setdtr_rts(&fc, 0, 0); 923 | if (res < 0) { 924 | fprintf(stderr, "ftdi_setdtr_rts() failed\n"); 925 | return (EXIT_FAILURE); 926 | } 927 | 928 | 929 | return (0); 930 | } 931 | 932 | 933 | static int 934 | shutdown_usb(void) 935 | { 936 | int res; 937 | 938 | /* Clean up */ 939 | res = set_port_mode(PORT_MODE_UART); 940 | if (res < 0) { 941 | fprintf(stderr, "ftdi_disable_bitbang() failed\n"); 942 | return (res); 943 | } 944 | 945 | res = ftdi_set_latency_timer(&fc, 20); 946 | if (res < 0) { 947 | fprintf(stderr, "ftdi_set_latency_timer() failed\n"); 948 | return (res); 949 | } 950 | 951 | #ifdef __linux__ 952 | usb_reset((void *) fc.usb_dev); 953 | #else 954 | res = ftdi_usb_close(&fc); 955 | if (res < 0) { 956 | fprintf(stderr, "unable to close ftdi device: %d (%s)\n", 957 | res, ftdi_get_error_string(&fc)); 958 | return (res); 959 | } 960 | #endif 961 | 962 | ftdi_deinit(&fc); 963 | 964 | #ifdef __APPLE__ 965 | system("/sbin/kextload" 966 | " -bundle-id com.FTDI.driver.FTDIUSBSerialDriver"); 967 | system("/sbin/kextload" 968 | " -bundle-id com.apple.driver.AppleUSBFTDI"); 969 | #endif 970 | 971 | return (0); 972 | } 973 | #endif /* !WIN32 */ 974 | 975 | 976 | static void 977 | set_tms_tdi(int tms, int tdi) 978 | { 979 | int val = 0; 980 | 981 | if (cable_hw != CABLE_HW_PPI) { 982 | if (tms) 983 | val |= JTAG_TMS; 984 | if (tdi) 985 | val |= JTAG_TDI; 986 | txbuf[txpos++] = val; 987 | txbuf[txpos++] = val | JTAG_TCK; 988 | } else { /* PPI */ 989 | if (tms) 990 | val |= PPI_TMS; 991 | if (tdi) 992 | val |= PPI_TDI; 993 | txbuf[txpos++] = val; 994 | txbuf[txpos++] = val | PPI_TCK; 995 | } 996 | 997 | if (txpos > sizeof(txbuf)) { 998 | fprintf(stderr, "txbuf overflow\n"); 999 | if (cable_hw == CABLE_HW_USB) 1000 | shutdown_usb(); 1001 | exit(EXIT_FAILURE); 1002 | } 1003 | } 1004 | 1005 | 1006 | static int 1007 | send_generic(unsigned bits, char *tdi, char *tdo, char *mask) 1008 | { 1009 | int res, bitpos, tdomask, tdoval, maskval, val = 0, txval = 0; 1010 | unsigned i, rxpos, rxlen; 1011 | 1012 | if (cable_hw != CABLE_HW_PPI) 1013 | tdomask = JTAG_TDO; 1014 | else 1015 | tdomask = PPI_TDO; 1016 | 1017 | i = strlen(tdi); 1018 | if (i != (bits + 3) / 4) { 1019 | fprintf(stderr, "send_generic(): bitcount and tdi " 1020 | "data length do not match\n"); 1021 | return (EXIT_FAILURE); 1022 | } 1023 | if (tdo != NULL && strlen(tdo) != i) { 1024 | if (mask != NULL && strlen(mask) != i) { 1025 | fprintf(stderr, "send_generic(): tdi, tdo and mask " 1026 | "must be of same length\n"); 1027 | return (EXIT_FAILURE); 1028 | } 1029 | fprintf(stderr, "send_generic(): tdi and tdo " 1030 | "must be of same length\n"); 1031 | return (EXIT_FAILURE); 1032 | } 1033 | 1034 | if (cur_s == DRPAUSE || cur_s == IRPAUSE ) { 1035 | /* Move from *PAUSE to *EXIT2 state */ 1036 | set_tms_tdi(1, 0); 1037 | } 1038 | 1039 | /* Move from *CAPTURE or *EXIT2 to *SHIFT state */ 1040 | set_tms_tdi(0, 0); 1041 | 1042 | /* Set up receive index / length */ 1043 | rxpos = txpos + 2; 1044 | rxlen = bits; 1045 | 1046 | for (bitpos = 0; bits > 0; bits--) { 1047 | if (bitpos == 0) { 1048 | i--; 1049 | val = tdi[i]; 1050 | if (val >= '0' && val <= '9') 1051 | val = val - '0'; 1052 | else if (val >= 'A' && val <= 'F') 1053 | val = val + 10 - 'A'; 1054 | else { 1055 | fprintf(stderr, "send_generic():" 1056 | "TDI data not in hex format\n"); 1057 | return (EXIT_FAILURE); 1058 | } 1059 | } 1060 | 1061 | txval = val & 0x1; 1062 | if (bits > 1) 1063 | set_tms_tdi(0, txval); 1064 | else 1065 | set_tms_tdi(1, txval); 1066 | 1067 | val = val >> 1; 1068 | bitpos = (bitpos + 1) & 0x3; 1069 | } 1070 | 1071 | /* Move from *EXIT1 to *PAUSE state */ 1072 | set_tms_tdi(0, txval); 1073 | 1074 | /* Send / receive data on JTAG port */ 1075 | res = commit(0); 1076 | 1077 | /* Translate received bitstream into hex, apply mask, store in tdi */ 1078 | if (port_mode == PORT_MODE_SYNC) { 1079 | if (mask != NULL) 1080 | mask += strlen(tdi); 1081 | if (tdo != NULL) 1082 | tdo += strlen(tdi); 1083 | tdi += strlen(tdi); 1084 | val = 0; 1085 | for (i = rxpos, bits = 0; bits < rxlen; i += 2) { 1086 | val += (((txbuf[i] & tdomask) != 0) << (bits & 0x3)); 1087 | bits++; 1088 | if ((bits & 0x3) == 0 || bits == rxlen) { 1089 | if (mask != NULL) { 1090 | /* Apply mask to received data */ 1091 | mask--; 1092 | maskval = *mask; 1093 | if (maskval >= '0' && maskval <= '9') 1094 | maskval = maskval - '0'; 1095 | else if (maskval >= 'A' && 1096 | maskval <= 'F') 1097 | maskval = maskval + 10 - 'A'; 1098 | val &= maskval; 1099 | /* Apply mask to expected TDO as well */ 1100 | if (tdo != NULL) { 1101 | tdo--; 1102 | tdoval = *tdo; 1103 | if (tdoval >= '0' && 1104 | tdoval <= '9') 1105 | tdoval = tdoval - '0'; 1106 | else if (tdoval >= 'A' && 1107 | tdoval <= 'F') 1108 | tdoval = 1109 | tdoval + 10 - 'A'; 1110 | tdoval &= maskval; 1111 | if (tdoval < 10) 1112 | *tdo = tdoval + '0'; 1113 | else 1114 | *tdo = 1115 | tdoval - 10 + 'A'; 1116 | } 1117 | } 1118 | tdi--; 1119 | if (val < 10) 1120 | *tdi = val + '0'; 1121 | else 1122 | *tdi = val - 10 + 'A'; 1123 | val = 0; 1124 | } 1125 | } 1126 | } 1127 | 1128 | return (res); 1129 | } 1130 | 1131 | 1132 | static int 1133 | send_dr(int bits, char *tdi, char *tdo, char *mask) 1134 | { 1135 | int res; 1136 | 1137 | if (cur_s != DRPAUSE) { 1138 | fprintf(stderr, "Must be in DRPAUSE on entry to send_dr()!\n"); 1139 | return (EXIT_FAILURE); 1140 | } 1141 | res = send_generic(bits, tdi, tdo, mask); 1142 | cur_s = DRPAUSE; 1143 | return (res); 1144 | } 1145 | 1146 | 1147 | static int 1148 | send_ir(int bits, char *tdi, char *tdo, char *mask) 1149 | { 1150 | int res; 1151 | 1152 | if (cur_s != IRPAUSE) { 1153 | fprintf(stderr, "Must be in IRPAUSE on entry to send_ir()!\n"); 1154 | return (EXIT_FAILURE); 1155 | } 1156 | res = send_generic(bits, tdi, tdo, mask); 1157 | cur_s = IRPAUSE; 1158 | return (res); 1159 | } 1160 | 1161 | 1162 | static int 1163 | commit_usb(void) 1164 | { 1165 | unsigned txchunklen, i, res; 1166 | 1167 | for (i = 0; i < txpos; i += txchunklen) { 1168 | txchunklen = txpos - i; 1169 | if (port_mode == PORT_MODE_SYNC && txchunklen > USB_BUFLEN_SYNC) 1170 | txchunklen = USB_BUFLEN_SYNC; 1171 | #ifdef WIN32 1172 | FT_Write(ftHandle, &txbuf[i], txchunklen, (DWORD *) &res); 1173 | #else 1174 | res = ftdi_write_data(&fc, &txbuf[i], txchunklen); 1175 | #endif 1176 | if (res != txchunklen) { 1177 | fprintf(stderr, "ftdi_write_data() failed\n"); 1178 | return (EXIT_FAILURE); 1179 | } 1180 | 1181 | if (port_mode == PORT_MODE_SYNC) { 1182 | #ifdef WIN32 1183 | FT_Read(ftHandle, &txbuf[i], txchunklen, 1184 | (DWORD *) &res); 1185 | #else 1186 | int rep = 0; 1187 | for (res = 0; res < txchunklen && rep < 8; 1188 | rep++) { 1189 | res += ftdi_read_data(&fc, &txbuf[i], 1190 | txchunklen - res); 1191 | } 1192 | #endif 1193 | if (res != txchunklen) { 1194 | #ifdef WIN32 1195 | fprintf(stderr, "FT_Read() failed: " 1196 | "expected %d, received %d bytes\n", 1197 | txchunklen, res); 1198 | #else 1199 | fprintf(stderr, "ftdi_read_data() failed\n"); 1200 | #endif 1201 | return (EXIT_FAILURE); 1202 | } 1203 | } 1204 | } 1205 | txpos = 0; 1206 | 1207 | /* Schedule CBUS LED blinking */ 1208 | i = ms_uptime(); 1209 | if (i - last_ledblink_ms >= LED_BLINK_RATE) { 1210 | last_ledblink_ms += LED_BLINK_RATE; 1211 | need_led_blink = 1; 1212 | } 1213 | 1214 | return (0); 1215 | } 1216 | 1217 | 1218 | #ifdef USE_PPI 1219 | static int 1220 | commit_ppi(void) 1221 | { 1222 | unsigned i, val; 1223 | 1224 | for (i = 0; i < txpos; i++) { 1225 | val = txbuf[i]; 1226 | if (port_mode == PORT_MODE_SYNC && !(i & 1)) { 1227 | ioctl(ppi, PPIGSTATUS, &txbuf[i]); 1228 | } 1229 | ioctl(ppi, PPISDATA, &val); 1230 | } 1231 | 1232 | txpos = 0; 1233 | return (0); 1234 | } 1235 | #endif 1236 | 1237 | 1238 | static int 1239 | commit(int force) 1240 | { 1241 | 1242 | if (txpos == 0 || (!force && port_mode != PORT_MODE_SYNC && 1243 | txpos < BUFLEN_MAX)) 1244 | return (0); 1245 | 1246 | if (!quiet && progress_perc < 100) { 1247 | fprintf(stderr, "\rProgramming: %d%% %c ", 1248 | progress_perc, statc[blinker_phase]); 1249 | fflush(stderr); 1250 | } 1251 | 1252 | #ifdef USE_PPI 1253 | if (cable_hw == CABLE_HW_PPI) 1254 | return (commit_ppi()); 1255 | #endif 1256 | #ifdef USE_RAW 1257 | if (cable_hw == CABLE_RAW) 1258 | return (commit_raw()); 1259 | #endif 1260 | if (cable_hw == CABLE_HW_USB) 1261 | return (commit_usb()); 1262 | else 1263 | return (EINVAL); 1264 | } 1265 | 1266 | 1267 | static int 1268 | str2tapstate(char *str) 1269 | { 1270 | int i; 1271 | 1272 | for (i = 0; tap_statetable[i].state_str != NULL; i++) { 1273 | if (strcmp(str, tap_statetable[i].state_str) == 0) 1274 | break; 1275 | } 1276 | return (tap_statetable[i].state_id); 1277 | } 1278 | 1279 | 1280 | static void 1281 | set_state(int tgt_s) { 1282 | int i, res = 0; 1283 | 1284 | switch (tgt_s) { 1285 | case RESET: 1286 | for (i = 0; i < 6; i++) 1287 | set_tms_tdi(1, 0); 1288 | break; 1289 | 1290 | case IDLE: 1291 | switch (cur_s) { 1292 | case RESET: 1293 | case DRUPDATE: 1294 | case IRUPDATE: 1295 | case IDLE: 1296 | set_tms_tdi(0, 0); 1297 | break; 1298 | 1299 | case UNDEFINED: 1300 | set_state(RESET); 1301 | set_state(IDLE); 1302 | break; 1303 | 1304 | case DRPAUSE: 1305 | set_state(DREXIT2); 1306 | set_state(DRUPDATE); 1307 | set_state(IDLE); 1308 | break; 1309 | 1310 | case IRPAUSE: 1311 | set_state(IREXIT2); 1312 | set_state(IRUPDATE); 1313 | set_state(IDLE); 1314 | break; 1315 | 1316 | default: 1317 | res = -1; 1318 | } 1319 | break; 1320 | 1321 | case DRSELECT: 1322 | switch (cur_s) { 1323 | case IDLE: 1324 | case DRUPDATE: 1325 | case IRUPDATE: 1326 | set_tms_tdi(1, 0); 1327 | break; 1328 | 1329 | default: 1330 | res = -1; 1331 | } 1332 | break; 1333 | 1334 | case DRCAPTURE: 1335 | switch (cur_s) { 1336 | case DRSELECT: 1337 | set_tms_tdi(0, 0); 1338 | break; 1339 | 1340 | case IDLE: 1341 | set_state(DRSELECT); 1342 | set_state(DRCAPTURE); 1343 | break; 1344 | 1345 | case IRPAUSE: 1346 | set_state(IDLE); 1347 | set_state(DRSELECT); 1348 | set_state(DRCAPTURE); 1349 | break; 1350 | 1351 | default: 1352 | res = -1; 1353 | } 1354 | break; 1355 | 1356 | case DREXIT1: 1357 | switch (cur_s) { 1358 | case DRCAPTURE: 1359 | set_tms_tdi(1, 0); 1360 | break; 1361 | 1362 | default: 1363 | res = -1; 1364 | } 1365 | break; 1366 | 1367 | case DRPAUSE: 1368 | switch (cur_s) { 1369 | case DREXIT1: 1370 | set_tms_tdi(0, 0); 1371 | break; 1372 | 1373 | case IDLE: 1374 | set_state(DRSELECT); 1375 | set_state(DRCAPTURE); 1376 | set_state(DREXIT1); 1377 | set_state(DRPAUSE); 1378 | break; 1379 | 1380 | case IRPAUSE: 1381 | set_state(IREXIT2); 1382 | set_state(IRUPDATE); 1383 | set_state(DRSELECT); 1384 | set_state(DRCAPTURE); 1385 | set_state(DREXIT1); 1386 | set_state(DRPAUSE); 1387 | break; 1388 | 1389 | case DRPAUSE: 1390 | break; 1391 | 1392 | default: 1393 | res = -1; 1394 | } 1395 | break; 1396 | 1397 | case DREXIT2: 1398 | switch (cur_s) { 1399 | case DRPAUSE: 1400 | set_tms_tdi(1, 0); 1401 | break; 1402 | 1403 | default: 1404 | res = -1; 1405 | } 1406 | break; 1407 | 1408 | case DRUPDATE: 1409 | switch (cur_s) { 1410 | case DREXIT2: 1411 | set_tms_tdi(1, 0); 1412 | break; 1413 | 1414 | default: 1415 | res = -1; 1416 | } 1417 | break; 1418 | 1419 | case IRSELECT: 1420 | switch (cur_s) { 1421 | case DRSELECT: 1422 | set_tms_tdi(1, 0); 1423 | break; 1424 | 1425 | default: 1426 | res = -1; 1427 | } 1428 | break; 1429 | 1430 | case IRCAPTURE: 1431 | switch (cur_s) { 1432 | case IRSELECT: 1433 | set_tms_tdi(0, 0); 1434 | break; 1435 | 1436 | case IDLE: 1437 | set_state(DRSELECT); 1438 | set_state(IRSELECT); 1439 | set_state(IRCAPTURE); 1440 | break; 1441 | 1442 | case DRPAUSE: 1443 | set_state(DREXIT2); 1444 | set_state(DRUPDATE); 1445 | set_state(DRSELECT); 1446 | set_state(IRSELECT); 1447 | set_state(IRCAPTURE); 1448 | break; 1449 | 1450 | default: 1451 | res = -1; 1452 | } 1453 | break; 1454 | 1455 | case IREXIT1: 1456 | switch (cur_s) { 1457 | case IRCAPTURE: 1458 | set_tms_tdi(1, 0); 1459 | break; 1460 | 1461 | default: 1462 | res = -1; 1463 | } 1464 | break; 1465 | 1466 | case IRPAUSE: 1467 | switch (cur_s) { 1468 | case IREXIT1: 1469 | set_tms_tdi(0, 0); 1470 | break; 1471 | 1472 | case IDLE: 1473 | set_state(DRSELECT); 1474 | set_state(IRSELECT); 1475 | set_state(IRCAPTURE); 1476 | set_state(IREXIT1); 1477 | set_state(IRPAUSE); 1478 | break; 1479 | 1480 | case DRPAUSE: 1481 | set_state(DREXIT2); 1482 | set_state(DRUPDATE); 1483 | set_state(DRSELECT); 1484 | set_state(IRSELECT); 1485 | set_state(IRCAPTURE); 1486 | set_state(IREXIT1); 1487 | set_state(IRPAUSE); 1488 | break; 1489 | 1490 | case IRPAUSE: 1491 | break; 1492 | 1493 | default: 1494 | res = -1; 1495 | } 1496 | break; 1497 | 1498 | case IREXIT2: 1499 | switch (cur_s) { 1500 | case IRPAUSE: 1501 | set_tms_tdi(1, 0); 1502 | break; 1503 | 1504 | default: 1505 | res = -1; 1506 | } 1507 | break; 1508 | 1509 | case IRUPDATE: 1510 | switch (cur_s) { 1511 | case IREXIT2: 1512 | set_tms_tdi(1, 0); 1513 | break; 1514 | 1515 | default: 1516 | res = -1; 1517 | } 1518 | break; 1519 | 1520 | default: 1521 | res = -1; 1522 | } 1523 | 1524 | if (res) { 1525 | fprintf(stderr, "Don't know how to proceed: %s -> %s\n", 1526 | STATE2STR(cur_s), STATE2STR(tgt_s)); 1527 | if (cable_hw == CABLE_HW_USB) 1528 | shutdown_usb(); 1529 | exit(EXIT_FAILURE); 1530 | } 1531 | 1532 | cur_s = tgt_s; 1533 | } 1534 | 1535 | 1536 | static int 1537 | exec_svf_tokenized(int tokc, char *tokv[]) 1538 | { 1539 | static int last_sdr = PORT_MODE_UNKNOWN; 1540 | int cmd, i, res = 0; 1541 | int repeat = 1, delay_ms = 0; 1542 | 1543 | for (i = 0; svf_cmdtable[i].cmd_str != NULL; i++) { 1544 | if (strcmp(tokv[0], svf_cmdtable[i].cmd_str) == 0) 1545 | break; 1546 | } 1547 | 1548 | cmd = svf_cmdtable[i].cmd_id; 1549 | switch (cmd) { 1550 | case SVF_SDR: 1551 | case SVF_SIR: 1552 | if (tokc == 4) { 1553 | if (cmd == SVF_SDR && last_sdr == PORT_MODE_ASYNC) 1554 | set_port_mode(PORT_MODE_ASYNC); 1555 | tokv[5] = NULL; 1556 | tokv[7] = NULL; 1557 | if (cmd == SVF_SDR) 1558 | last_sdr = PORT_MODE_ASYNC; 1559 | } else if (tokc == 6 || tokc == 8) { 1560 | set_port_mode(PORT_MODE_SYNC); 1561 | if (tokc == 5) 1562 | tokv[7] = NULL; 1563 | if (cmd == SVF_SDR) 1564 | last_sdr = PORT_MODE_SYNC; 1565 | } else { 1566 | res = EXIT_FAILURE; 1567 | break; 1568 | } 1569 | if (cmd == SVF_SDR) { 1570 | set_state(DRPAUSE); 1571 | res = send_dr(atoi(tokv[1]), tokv[3], tokv[5], tokv[7]); 1572 | } else { 1573 | set_state(IRPAUSE); 1574 | res = send_ir(atoi(tokv[1]), tokv[3], tokv[5], tokv[7]); 1575 | } 1576 | if (res) 1577 | break; 1578 | if (cable_hw == CABLE_RAW) 1579 | break; /* Ignore non-existing TDO response */ 1580 | if ((tokc == 6 || tokc == 8) && strcmp(tokv[3], tokv[5]) != 0) { 1581 | if (strlen(tokv[3]) == 8 && strlen(tokv[5]) == 8 && 1582 | strcmp(tokv[7], "FFFFFFFF") == 0 && 1583 | cmp_chip_ids(tokv[3], tokv[5]) == 0) 1584 | return (ENODEV); 1585 | fprintf(stderr, "Received and expected data " 1586 | "do not match!\n"); 1587 | if (tokc == 6) 1588 | fprintf(stderr, "TDO: %s Expected: %s\n", 1589 | tokv[3], tokv[5]); 1590 | if (tokc == 8) 1591 | fprintf(stderr, "TDO: %s Expected: %s " 1592 | "mask: %s\n", tokv[3], tokv[5], tokv[7]); 1593 | res = EXIT_FAILURE; 1594 | } 1595 | break; 1596 | 1597 | case SVF_STATE: 1598 | set_state(str2tapstate(tokv[1])); 1599 | res = commit(0); 1600 | break; 1601 | 1602 | case SVF_RUNTEST: 1603 | if (isnumber(tokv[1][0])) { 1604 | i = 1; 1605 | set_state(IDLE); 1606 | } else { 1607 | set_state(str2tapstate(tokv[1])); 1608 | i = 2; 1609 | } 1610 | for (; i < tokc; i += 2) { 1611 | if (strcmp(tokv[i + 1], "TCK") == 0) { 1612 | repeat = atoi(tokv[i]); 1613 | if (repeat < 1 || repeat > 100000) { 1614 | fprintf(stderr, 1615 | "Unexpected token: %s\n", 1616 | tokv[i]); 1617 | res = EXIT_FAILURE; 1618 | break; 1619 | } 1620 | } else if (strcmp(tokv[i + 1], "SEC") == 0) { 1621 | float f; 1622 | sscanf(tokv[i], "%f", &f); 1623 | delay_ms = (f + 0.0005) * 1000; 1624 | if (delay_ms < 1 || delay_ms > 120000) { 1625 | fprintf(stderr, 1626 | "Unexpected token: %s\n", 1627 | tokv[i]); 1628 | res = EXIT_FAILURE; 1629 | break; 1630 | } 1631 | /* Silently reduce insanely long waits */ 1632 | if (delay_ms > 3000) 1633 | delay_ms = 3000; 1634 | } else { 1635 | fprintf(stderr, "Unexpected token: %s\n", 1636 | tokv[i + 1]); 1637 | res = EXIT_FAILURE; 1638 | break; 1639 | } 1640 | } 1641 | i = delay_ms * (USB_BAUDS / 2000); 1642 | #ifdef USE_PPI 1643 | /* libftdi is relatively slow in sync mode on FreeBSD */ 1644 | if (port_mode == PORT_MODE_SYNC && i > USB_BUFLEN_SYNC / 2) 1645 | i /= 2; 1646 | #endif 1647 | if (i > repeat) 1648 | repeat = i; 1649 | for (i = 0; i < repeat; i++) { 1650 | txbuf[txpos++] = 0; 1651 | txbuf[txpos++] = JTAG_TCK; 1652 | if (txpos >= sizeof(txbuf) / 2) { 1653 | commit(0); 1654 | if (need_led_blink) 1655 | set_port_mode(port_mode); 1656 | } 1657 | } 1658 | break; 1659 | 1660 | case SVF_HDR: 1661 | case SVF_HIR: 1662 | case SVF_TDR: 1663 | case SVF_TIR: 1664 | if (tokc != 2 || strcmp(tokv[1], "0") != 0) 1665 | res = EINVAL; 1666 | break; 1667 | 1668 | case SVF_ENDDR: 1669 | if (tokc != 2 || 1670 | (strcmp(tokv[1], "DRPAUSE") != 0 && 1671 | strcmp(tokv[1], "IDLE") != 0)) 1672 | res = EINVAL; 1673 | break; 1674 | 1675 | case SVF_ENDIR: 1676 | if (tokc != 2 || 1677 | (strcmp(tokv[1], "IRPAUSE") != 0 && 1678 | strcmp(tokv[1], "IDLE") != 0)) 1679 | res = EINVAL; 1680 | break; 1681 | 1682 | case SVF_FREQUENCY: 1683 | case SVF_TRST: 1684 | /* Silently ignored. */ 1685 | break; 1686 | 1687 | default: 1688 | res = EOPNOTSUPP; 1689 | } 1690 | 1691 | return (res); 1692 | } 1693 | 1694 | 1695 | enum jed_states { 1696 | JED_INIT, JED_PACK_KNOWN, JED_SIZE_KNOWN, JED_PROG_INITIATED, 1697 | JED_FUSES, JED_FUSES_DONE, JED_SED_CRC, JED_HAVE_SED_CRC, JED_USER_SIG 1698 | }; 1699 | 1700 | enum jed_target { 1701 | JED_TGT_SRAM, JED_TGT_FLASH, JED_TGT_UNKNOWN 1702 | }; 1703 | 1704 | static struct jed_devices { 1705 | char *name; 1706 | int id; 1707 | int fuses; 1708 | int col_width; 1709 | int row_width; 1710 | } jed_devices[] = { 1711 | { 1712 | .name = "LFXP2-5E", 1713 | .id = 0x01299043, 1714 | .fuses = 1236476, 1715 | .col_width = 638, 1716 | .row_width = 1938, 1717 | }, 1718 | { 1719 | .name = "LFXP2-8E", 1720 | .id = 0x0129A043, 1721 | .fuses = 1954736, 1722 | .col_width = 772, 1723 | .row_width= 2532, 1724 | }, 1725 | { 1726 | .name = "LFXP2-17E", 1727 | .id = 0x0129B043, 1728 | .fuses = 3627704, 1729 | .col_width = 2188, 1730 | .row_width = 1658, 1731 | }, 1732 | { 1733 | .name = "LFXP2-30E", 1734 | .id = 0x0129D043, 1735 | .fuses = 5954320, 1736 | .col_width = 2644, 1737 | .row_width = 2532, 1738 | }, 1739 | { 1740 | .name = "LFXP2-40E", 1741 | .id = 0x0129E043, 1742 | .fuses = 8304368, 1743 | .col_width = 3384, 1744 | .row_width = 2454, 1745 | }, 1746 | { 1747 | .name = "LFE5U-12F", 1748 | .id = 0x21111043, 1749 | .fuses = 5681848, 1750 | .col_width = 592, 1751 | .row_width = 7562, 1752 | }, 1753 | { 1754 | .name = "LFE5U-25F", 1755 | .id = 0x41111043, 1756 | .fuses = 5681848, 1757 | .col_width = 592, 1758 | .row_width = 7562, 1759 | }, 1760 | { 1761 | .name = "LFE5U-45F", 1762 | .id = 0x41112043, 1763 | .fuses = 10208312, 1764 | .col_width = 848, 1765 | .row_width = 9470, 1766 | }, 1767 | { 1768 | .name = "LFE5U-85F", 1769 | .id = 0x41113043, 1770 | .fuses = 19244856, 1771 | .col_width = 1136, 1772 | .row_width = 13294, 1773 | }, 1774 | { 1775 | .name = "LFE5UM-25F", 1776 | .id = 0x01111043, 1777 | .fuses = 5681848, 1778 | .col_width = 592, 1779 | .row_width = 7562, 1780 | }, 1781 | { 1782 | .name = "LFE5UM-45F", 1783 | .id = 0x01112043, 1784 | .fuses = 10208312, 1785 | .col_width = 848, 1786 | .row_width = 9470, 1787 | }, 1788 | { 1789 | .name = "LFE5UM-85F", 1790 | .id = 0x01113043, 1791 | .fuses = 19244856, 1792 | .col_width = 1136, 1793 | .row_width = 13294, 1794 | }, 1795 | {NULL, 0, 0, 0, 0} 1796 | }; 1797 | 1798 | 1799 | static int 1800 | cmp_chip_ids(char *got, char *exp) 1801 | { 1802 | int got_id, exp_id; 1803 | struct jed_devices *got_jd, *exp_jd; 1804 | 1805 | sscanf(got, "%x", &got_id); 1806 | sscanf(exp, "%x", &exp_id); 1807 | 1808 | for (got_jd = jed_devices; got_jd->name != NULL; got_jd++) 1809 | if (got_jd->id == got_id) 1810 | break; 1811 | for (exp_jd = jed_devices; exp_jd->name != NULL; exp_jd++) 1812 | if (exp_jd->id == exp_id) 1813 | break; 1814 | 1815 | if (exp_jd->name == NULL && got_jd->name == NULL) 1816 | return (EXIT_FAILURE); 1817 | 1818 | fprintf(stderr, "\nFound "); 1819 | if (got_jd->name) 1820 | fprintf(stderr, "%s", got_jd->name); 1821 | else 1822 | fprintf(stderr, "unknown (%s)", got); 1823 | fprintf(stderr, " device, but the bitstream is for "); 1824 | if (exp_jd->name) 1825 | fprintf(stderr, "%s", exp_jd->name); 1826 | else 1827 | fprintf(stderr, "unknown (%s)", exp); 1828 | fprintf(stderr, ".\n"); 1829 | return (0); 1830 | } 1831 | 1832 | /* 1833 | * Parse a Lattice XP2 JEDEC file and convert it into a SVF stream stored 1834 | * in a contiguos chunk of memory. If parsing is sucessfull proceed with 1835 | * calling exec_svf_mem(). 1836 | */ 1837 | static int 1838 | exec_jedec_file(char *path, int target, int debug) 1839 | { 1840 | char *inbuf, *outbuf, *incp, *outcp; 1841 | char tmpbuf[2048]; 1842 | FILE *fd; 1843 | long flen; 1844 | int jed_state = JED_INIT; 1845 | int jed_dev = -1; 1846 | int i, j, val, row, res; 1847 | 1848 | fd = fopen(path, "r"); 1849 | if (fd == NULL) { 1850 | fprintf(stderr, "open(%s) failed\n", path); 1851 | return (EXIT_FAILURE); 1852 | } 1853 | 1854 | fseek(fd, 0, SEEK_END); 1855 | flen = ftell(fd); 1856 | fseek(fd, 0, SEEK_SET); 1857 | 1858 | inbuf = malloc(flen); 1859 | outbuf = malloc(flen * 2); /* XXX rough estimate */ 1860 | if (inbuf == NULL || outbuf == NULL) { 1861 | fprintf(stderr, "malloc(%ld) failed\n", flen); 1862 | return (EXIT_FAILURE); 1863 | } 1864 | 1865 | incp = inbuf; 1866 | outcp = outbuf; 1867 | while (!feof(fd) && fgets(incp, flen, fd) != NULL) { 1868 | /* Trim CR / LF chars from the tail of the line */ 1869 | incp += strlen(incp) - 1; 1870 | while (incp >= inbuf && (*incp == 10 || *incp == 13)) 1871 | incp--; 1872 | incp[1] = 0; 1873 | 1874 | /* Is this the first line of an "L" command? */ 1875 | if (*inbuf == 'L') { 1876 | if (jed_state < JED_PROG_INITIATED) { 1877 | fprintf(stderr, "Invalid bitstream file\n"); 1878 | return (EXIT_FAILURE); 1879 | } 1880 | if (jed_state == JED_PROG_INITIATED) 1881 | jed_state = JED_FUSES; 1882 | else 1883 | jed_state = JED_SED_CRC; 1884 | incp = inbuf; 1885 | continue; 1886 | } 1887 | 1888 | /* Does the command terminate on this line? */ 1889 | if (*incp != '*') { 1890 | incp++; 1891 | continue; 1892 | } else 1893 | *incp = 0; 1894 | 1895 | /* Is this the SED_CRC fuses string? */ 1896 | if (jed_state == JED_SED_CRC) { 1897 | val = 0; 1898 | for (i = 32, j = 0; i > 0; i--, val <<= 1) { 1899 | val += (inbuf[i - 1] == '1'); 1900 | if ((i & 0x3) == 1) { 1901 | if (val < 10) 1902 | tmpbuf[j++] = '0' + 1903 | val; 1904 | else 1905 | tmpbuf[j++] = 'A' + 1906 | val - 10; 1907 | val = 0; 1908 | } 1909 | } 1910 | tmpbuf[j++] = 0; 1911 | if (strlen(tmpbuf) != 8) { 1912 | fprintf(stderr, "Invalid bitstream file\n"); 1913 | return (EXIT_FAILURE); 1914 | } 1915 | jed_state = JED_HAVE_SED_CRC; 1916 | } 1917 | 1918 | /* Is this the main fuses string? */ 1919 | if (jed_state == JED_FUSES) { 1920 | 1921 | outcp += sprintf(outcp, "\n\n! Program Fuse Map\n\n"); 1922 | *outcp++ = 0; 1923 | outcp += sprintf(outcp, "SIR 8 TDI (21);\n"); 1924 | *outcp++ = 0; 1925 | outcp += sprintf(outcp, 1926 | "RUNTEST IDLE 3 TCK 1.00E-002 SEC;\n"); 1927 | *outcp++ = 0; 1928 | 1929 | if (target == JED_TGT_SRAM) { 1930 | outcp += sprintf(outcp, 1931 | "SIR 8 TDI (67);\n"); 1932 | *outcp++ = 0; 1933 | } 1934 | 1935 | for (incp = inbuf, row = 1; 1936 | row <= jed_devices[jed_dev].row_width; row++) { 1937 | if (target == JED_TGT_FLASH) { 1938 | outcp += sprintf(outcp, 1939 | "SIR 8 TDI (67);\n"); 1940 | *outcp++ = 0; 1941 | } 1942 | 1943 | val = 0; 1944 | for (i = jed_devices[jed_dev].col_width, j = 0; 1945 | i > 0; i--, val <<= 1) { 1946 | val += (incp[i - 1] == '1'); 1947 | if ((i & 0x3) == 1) { 1948 | if (val < 10) 1949 | tmpbuf[j++] = '0' + 1950 | val; 1951 | else 1952 | tmpbuf[j++] = 'A' + 1953 | val - 10; 1954 | val = 0; 1955 | } 1956 | } 1957 | tmpbuf[j++] = 0; 1958 | incp += jed_devices[jed_dev].col_width; 1959 | 1960 | outcp += sprintf(outcp, 1961 | "! Shift in Data Row = %d\n", row); 1962 | *outcp++ = 0; 1963 | outcp += sprintf(outcp, 1964 | "SDR %d TDI (%s);\n", 1965 | jed_devices[jed_dev].col_width, tmpbuf); 1966 | *outcp++ = 0; 1967 | if (target == JED_TGT_FLASH) { 1968 | outcp += sprintf(outcp, 1969 | "RUNTEST IDLE" 1970 | " 3 TCK 1.00E-003 SEC;\n"); 1971 | } else { 1972 | outcp += sprintf(outcp, 1973 | "RUNTEST IDLE 3 TCK;\n"); 1974 | } 1975 | *outcp++ = 0; 1976 | 1977 | if (target == JED_TGT_FLASH) { 1978 | outcp += sprintf(outcp, 1979 | "SIR 8 TDI (52);\n"); 1980 | *outcp++ = 0; 1981 | 1982 | outcp += sprintf(outcp, 1983 | "SDR 1 TDI (0)\n"); 1984 | *outcp++ = 0; 1985 | outcp += sprintf(outcp, 1986 | " TDO (1);\n"); 1987 | *outcp++ = 0; 1988 | } 1989 | } 1990 | 1991 | /* Check that we have consumed all fuse bits */ 1992 | if (strlen(incp) != 0) { 1993 | fprintf(stderr, "Invalid bitstream file\n"); 1994 | return (EXIT_FAILURE); 1995 | } 1996 | 1997 | jed_state++; 1998 | } 1999 | 2000 | /* Is this a comment line? */ 2001 | if (*inbuf == 'N') { 2002 | if (jed_state == JED_INIT) { 2003 | outcp += sprintf(outcp, "! %s\n", inbuf); 2004 | *outcp++ = 0; 2005 | } 2006 | if (strncmp(inbuf, "NOTE DEVICE NAME:", 17) == 0) { 2007 | incp = &inbuf[18]; 2008 | for (jed_dev = 0; 2009 | jed_devices[jed_dev].name != NULL; 2010 | jed_dev++) { 2011 | if (strncmp(jed_devices[jed_dev].name, 2012 | incp, strlen( 2013 | jed_devices[jed_dev].name)) == 0) 2014 | break; 2015 | } 2016 | if (jed_devices[jed_dev].name == NULL) { 2017 | fprintf(stderr, "Bitstream for " 2018 | "unsupported target: %s\n", incp); 2019 | return (EXIT_FAILURE); 2020 | } 2021 | } 2022 | incp = inbuf; 2023 | continue; 2024 | } 2025 | 2026 | /* Packaging line? */ 2027 | if (*inbuf == 'Q') { 2028 | i = atoi(&inbuf[2]); 2029 | if (inbuf[1] == 'P') { 2030 | if (jed_dev < 0 || jed_state != JED_INIT) { 2031 | fprintf(stderr, 2032 | "Invalid bitstream file\n"); 2033 | return (EXIT_FAILURE); 2034 | } 2035 | jed_state = JED_PACK_KNOWN; 2036 | } else if (inbuf[1] == 'F') { 2037 | if (jed_dev < 0 || jed_state != JED_PACK_KNOWN 2038 | || jed_devices[jed_dev].fuses != i) { 2039 | fprintf(stderr, 2040 | "Invalid bitstream file\n"); 2041 | return (EXIT_FAILURE); 2042 | } 2043 | jed_state = JED_SIZE_KNOWN; 2044 | } else { 2045 | fprintf(stderr, "Invalid bitstream file\n"); 2046 | return (EXIT_FAILURE); 2047 | } 2048 | } 2049 | 2050 | /* "F" line? */ 2051 | if (*inbuf == 'F') { 2052 | if (jed_state != JED_SIZE_KNOWN) { 2053 | fprintf(stderr, "Invalid bitstream file\n"); 2054 | return (EXIT_FAILURE); 2055 | } 2056 | jed_state = JED_PROG_INITIATED; 2057 | 2058 | outcp += sprintf(outcp, "\n\n! Check the IDCODE\n\n"); 2059 | *outcp++ = 0; 2060 | outcp += sprintf(outcp, "STATE RESET;\n"); 2061 | *outcp++ = 0; 2062 | outcp += sprintf(outcp, "STATE IDLE;\n"); 2063 | *outcp++ = 0; 2064 | outcp += sprintf(outcp, "SIR 8 TDI (16);\n"); 2065 | *outcp++ = 0; 2066 | outcp += sprintf(outcp, 2067 | "SDR 32 TDI (FFFFFFFF)\n"); 2068 | *outcp++ = 0; 2069 | outcp += sprintf(outcp, " TDO (%08X)\n", 2070 | jed_devices[jed_dev].id); 2071 | *outcp++ = 0; 2072 | outcp += sprintf(outcp, 2073 | " MASK (FFFFFFFF);\n"); 2074 | *outcp++ = 0; 2075 | 2076 | if (target == JED_TGT_SRAM) { 2077 | outcp += sprintf(outcp, 2078 | "\n\n! Program Bscan register\n\n"); 2079 | *outcp++ = 0; 2080 | outcp += sprintf(outcp, 2081 | "SIR 8 TDI (1C);\n"); 2082 | *outcp++ = 0; 2083 | outcp += sprintf(outcp, "STATE DRPAUSE;\n"); 2084 | *outcp++ = 0; 2085 | outcp += sprintf(outcp, "STATE IDLE;\n"); 2086 | *outcp++ = 0; 2087 | 2088 | outcp += sprintf(outcp, 2089 | "\n\n! Enable SRAM programming mode\n\n"); 2090 | *outcp++ = 0; 2091 | outcp += sprintf(outcp, 2092 | "SIR 8 TDI (55);\n"); 2093 | *outcp++ = 0; 2094 | outcp += sprintf(outcp, "RUNTEST IDLE" 2095 | " 3 TCK 1.00E-003 SEC;\n"); 2096 | *outcp++ = 0; 2097 | 2098 | outcp += sprintf(outcp, 2099 | "\n\n! Erase the device\n\n"); 2100 | *outcp++ = 0; 2101 | outcp += sprintf(outcp, 2102 | "SIR 8 TDI (03);\n"); 2103 | *outcp++ = 0; 2104 | outcp += sprintf(outcp, "RUNTEST IDLE" 2105 | " 3 TCK 1.00E-003 SEC;\n"); 2106 | *outcp++ = 0; 2107 | } else { 2108 | outcp += sprintf(outcp, 2109 | "\n\n! Enable XPROGRAM mode\n\n"); 2110 | *outcp++ = 0; 2111 | outcp += sprintf(outcp, 2112 | "SIR 8 TDI (35);\n"); 2113 | *outcp++ = 0; 2114 | outcp += sprintf(outcp, "RUNTEST IDLE" 2115 | " 3 TCK 1.00E-003 SEC;\n"); 2116 | *outcp++ = 0; 2117 | 2118 | outcp += sprintf(outcp, 2119 | "\n\n! Check the Key Protection fuses\n\n"); 2120 | *outcp++ = 0; 2121 | 2122 | outcp += sprintf(outcp, 2123 | "SIR 8 TDI (B2);\n"); 2124 | *outcp++ = 0; 2125 | outcp += sprintf(outcp, "RUNTEST IDLE" 2126 | " 3 TCK 1.00E-003 SEC;\n"); 2127 | *outcp++ = 0; 2128 | outcp += sprintf(outcp, 2129 | "SDR 8 TDI (00)\n"); 2130 | *outcp++ = 0; 2131 | outcp += sprintf(outcp, 2132 | " TDO (00)\n"); 2133 | *outcp++ = 0; 2134 | outcp += sprintf(outcp, 2135 | " MASK (10);\n"); 2136 | *outcp++ = 0; 2137 | 2138 | outcp += sprintf(outcp, 2139 | "SIR 8 TDI (B2);\n"); 2140 | *outcp++ = 0; 2141 | outcp += sprintf(outcp, "RUNTEST IDLE" 2142 | " 3 TCK 1.00E-003 SEC;\n"); 2143 | *outcp++ = 0; 2144 | outcp += sprintf(outcp, 2145 | "SDR 8 TDI (00)\n"); 2146 | *outcp++ = 0; 2147 | outcp += sprintf(outcp, 2148 | " TDO (00)\n"); 2149 | *outcp++ = 0; 2150 | outcp += sprintf(outcp, 2151 | " MASK (40);\n"); 2152 | *outcp++ = 0; 2153 | 2154 | outcp += sprintf(outcp, 2155 | "SIR 8 TDI (B2);\n"); 2156 | *outcp++ = 0; 2157 | outcp += sprintf(outcp, "RUNTEST IDLE" 2158 | " 3 TCK 1.00E-003 SEC;\n"); 2159 | *outcp++ = 0; 2160 | outcp += sprintf(outcp, 2161 | "SDR 8 TDI (00)\n"); 2162 | *outcp++ = 0; 2163 | outcp += sprintf(outcp, 2164 | " TDO (00)\n"); 2165 | *outcp++ = 0; 2166 | outcp += sprintf(outcp, 2167 | " MASK (04);\n"); 2168 | *outcp++ = 0; 2169 | 2170 | outcp += sprintf(outcp, 2171 | "\n\n! Erase the device\n\n"); 2172 | *outcp++ = 0; 2173 | outcp += sprintf(outcp, 2174 | "SIR 8 TDI (03);\n"); 2175 | *outcp++ = 0; 2176 | outcp += sprintf(outcp, "RUNTEST IDLE" 2177 | " 3 TCK 1.20E+002 SEC;\n"); 2178 | *outcp++ = 0; 2179 | 2180 | outcp += sprintf(outcp, 2181 | "SIR 8 TDI (52);\n"); 2182 | *outcp++ = 0; 2183 | outcp += sprintf(outcp, 2184 | "SDR 1 TDI (0)\n"); 2185 | *outcp++ = 0; 2186 | outcp += sprintf(outcp, 2187 | " TDO (1);\n"); 2188 | *outcp++ = 0; 2189 | 2190 | outcp += sprintf(outcp, 2191 | "SIR 8 TDI (B2);\n"); 2192 | *outcp++ = 0; 2193 | outcp += sprintf(outcp, "RUNTEST IDLE" 2194 | " 3 TCK 1.00E-003 SEC;\n"); 2195 | *outcp++ = 0; 2196 | outcp += sprintf(outcp, 2197 | "SDR 8 TDI (00)\n"); 2198 | *outcp++ = 0; 2199 | outcp += sprintf(outcp, 2200 | " TDO (00)\n"); 2201 | *outcp++ = 0; 2202 | outcp += sprintf(outcp, 2203 | " MASK (01);\n"); 2204 | *outcp++ = 0; 2205 | } 2206 | } 2207 | 2208 | /* "U" line? */ 2209 | if (*inbuf == 'U') { 2210 | if (inbuf[1] != 'H' || jed_state != JED_HAVE_SED_CRC) { 2211 | fprintf(stderr, "Invalid bitstream file\n"); 2212 | return (EXIT_FAILURE); 2213 | } 2214 | 2215 | outcp += sprintf(outcp, "\n\n! Program USERCODE\n\n"); 2216 | *outcp++ = 0; 2217 | outcp += sprintf(outcp, "SIR 8 TDI (1A);\n"); 2218 | *outcp++ = 0; 2219 | outcp += sprintf(outcp, 2220 | "SDR 32 TDI (%s);\n", &inbuf[2]); 2221 | *outcp++ = 0; 2222 | outcp += sprintf(outcp, 2223 | "RUNTEST IDLE 3 TCK 1.00E-002 SEC;\n"); 2224 | *outcp++ = 0; 2225 | 2226 | if (target == JED_TGT_FLASH) { 2227 | outcp += sprintf(outcp, 2228 | "\n\n! Read the status bit;\n\n"); 2229 | *outcp++ = 0; 2230 | outcp += sprintf(outcp, 2231 | "SIR 8 TDI (B2);\n"); 2232 | *outcp++ = 0; 2233 | outcp += sprintf(outcp, "RUNTEST IDLE" 2234 | " 3 TCK 1.00E-003 SEC;\n"); 2235 | *outcp++ = 0; 2236 | outcp += sprintf(outcp, 2237 | "SDR 8 TDI (00)\n"); 2238 | *outcp++ = 0; 2239 | outcp += sprintf(outcp, 2240 | " TDO (00)\n"); 2241 | *outcp++ = 0; 2242 | outcp += sprintf(outcp, 2243 | " MASK (01);\n"); 2244 | *outcp++ = 0; 2245 | } 2246 | 2247 | outcp += sprintf(outcp, 2248 | "\n\n! Program and Verify 32 bits SED_CRC\n\n"); 2249 | *outcp++ = 0; 2250 | outcp += sprintf(outcp, "SIR 8 TDI (45);\n"); 2251 | *outcp++ = 0; 2252 | outcp += sprintf(outcp, 2253 | "SDR 32 TDI (%s);\n", tmpbuf); 2254 | *outcp++ = 0; 2255 | outcp += sprintf(outcp, 2256 | "RUNTEST IDLE 3 TCK 1.00E-002 SEC;\n"); 2257 | *outcp++ = 0; 2258 | 2259 | outcp += sprintf(outcp, "SIR 8 TDI (44);\n"); 2260 | *outcp++ = 0; 2261 | outcp += sprintf(outcp, 2262 | "RUNTEST IDLE 3 TCK 1.00E-003 SEC;\n"); 2263 | *outcp++ = 0; 2264 | 2265 | outcp += sprintf(outcp, 2266 | "SDR 32 TDI (00000000)\n"); 2267 | *outcp++ = 0; 2268 | outcp += sprintf(outcp, 2269 | " TDO (%s);\n", tmpbuf); 2270 | *outcp++ = 0; 2271 | 2272 | outcp += sprintf(outcp, "SIR 8 TDI (B2);\n"); 2273 | *outcp++ = 0; 2274 | outcp += sprintf(outcp, 2275 | "RUNTEST IDLE 3 TCK 1.00E-003 SEC;\n"); 2276 | *outcp++ = 0; 2277 | outcp += sprintf(outcp, "SDR 8 TDI (00)\n"); 2278 | *outcp++ = 0; 2279 | outcp += sprintf(outcp, " TDO (00)\n"); 2280 | *outcp++ = 0; 2281 | outcp += sprintf(outcp, " MASK (01);\n"); 2282 | *outcp++ = 0; 2283 | 2284 | outcp += sprintf(outcp, 2285 | "\n\n! Program DONE bit\n\n"); 2286 | *outcp++ = 0; 2287 | outcp += sprintf(outcp, "SIR 8 TDI (2F);\n"); 2288 | *outcp++ = 0; 2289 | if (target == JED_TGT_FLASH) { 2290 | outcp += sprintf(outcp, "RUNTEST IDLE" 2291 | " 3 TCK 2.00E-001 SEC;\n"); 2292 | } else { 2293 | outcp += sprintf(outcp, "RUNTEST IDLE" 2294 | " 3 TCK;\n"); 2295 | } 2296 | *outcp++ = 0; 2297 | outcp += sprintf(outcp, "SIR 8 TDI (B2);\n"); 2298 | *outcp++ = 0; 2299 | outcp += sprintf(outcp, 2300 | "RUNTEST IDLE 3 TCK 1.00E-003 SEC;\n"); 2301 | *outcp++ = 0; 2302 | outcp += sprintf(outcp, "SDR 8 TDI (00)\n"); 2303 | *outcp++ = 0; 2304 | outcp += sprintf(outcp, " TDO (02)\n"); 2305 | *outcp++ = 0; 2306 | outcp += sprintf(outcp, " MASK (03);\n"); 2307 | *outcp++ = 0; 2308 | 2309 | if (target == JED_TGT_FLASH) { 2310 | outcp += sprintf(outcp, 2311 | "\n\n! Verify DONE bit\n\n"); 2312 | *outcp++ = 0; 2313 | outcp += sprintf(outcp, 2314 | "SIR 8 TDI (B2)\n"); 2315 | *outcp++ = 0; 2316 | outcp += sprintf(outcp, 2317 | " TDO (FF)\n"); 2318 | *outcp++ = 0; 2319 | outcp += sprintf(outcp, 2320 | " MASK (04);\n"); 2321 | *outcp++ = 0; 2322 | } 2323 | 2324 | outcp += sprintf(outcp, 2325 | "\n\n! Exit the programming mode\n\n"); 2326 | *outcp++ = 0; 2327 | outcp += sprintf(outcp, "SIR 8 TDI (1E);\n"); 2328 | *outcp++ = 0; 2329 | outcp += sprintf(outcp, 2330 | "RUNTEST IDLE 3 TCK 2.00E-003 SEC;\n"); 2331 | *outcp++ = 0; 2332 | outcp += sprintf(outcp, "SIR 8 TDI (FF);\n"); 2333 | *outcp++ = 0; 2334 | outcp += sprintf(outcp, 2335 | "RUNTEST IDLE 3 TCK 1.00E-003 SEC;\n"); 2336 | *outcp++ = 0; 2337 | outcp += sprintf(outcp, 2338 | "STATE RESET;\n"); 2339 | *outcp++ = 0; 2340 | } 2341 | 2342 | incp = inbuf; 2343 | } 2344 | fclose(fd); 2345 | 2346 | /* Count number of lines in outbuf, store in j */ 2347 | for (i = 0, j = 0; outcp > outbuf; outcp--) 2348 | if (*outcp == 0) 2349 | j++; 2350 | 2351 | if (svf_name) { 2352 | int of; 2353 | 2354 | if (strncmp(svf_name, "-", 1) == 0) 2355 | of = 0; 2356 | else 2357 | of = open(svf_name, O_RDWR | O_CREAT | O_TRUNC, 0644); 2358 | if (of < 0) { 2359 | res = errno; 2360 | goto done; 2361 | } 2362 | res = 0; 2363 | for (i = 0, outcp = outbuf; i < j; i++) { 2364 | write(of, outcp, strlen(outcp)); 2365 | outcp += (strlen(outcp) + 1); 2366 | } 2367 | if (of) 2368 | close(of); 2369 | } else 2370 | res = exec_svf_mem(outbuf, j, debug); 2371 | 2372 | done: 2373 | free(outbuf); 2374 | free(inbuf); 2375 | return (res); 2376 | } 2377 | 2378 | 2379 | #define bitrev(a) ((a & 0x1) << 7) | ((a & 0x2) << 5) | ((a & 0x4) << 3) | ((a & 0x8) << 1) | ((a & 0x10) >> 1) | ((a & 0x20) >> 3) | ((a & 0x40) >> 5) | ((a & 0x80) >> 7) 2380 | 2381 | #define buf_sprintf(p, ...) do { \ 2382 | (p) += sprintf((p), ## __VA_ARGS__); \ 2383 | *(p)++ = 0; \ 2384 | } while (0) 2385 | 2386 | /* 2387 | * Parse a Lattice ECP5 bitstream file and convert it into a SVF stream, 2388 | * stored in a contiguos chunk of memory. If parsing is sucessfull proceed 2389 | * with calling exec_svf_mem(). 2390 | */ 2391 | static int 2392 | exec_bit_file(char *path, int jed_target, int debug) 2393 | { 2394 | uint8_t *inbuf; 2395 | char *outbuf, *op; 2396 | char *outcp; 2397 | FILE *fd; 2398 | long flen, got; 2399 | uint32_t idcode; 2400 | int i, j, n, addr; 2401 | int row_size = 64000 / 8; 2402 | int hexlen = 50; 2403 | int res; 2404 | 2405 | fd = fopen(path, "rb"); 2406 | if (fd == NULL) { 2407 | fprintf(stderr, "open(%s) failed\n", path); 2408 | return (EXIT_FAILURE); 2409 | } 2410 | 2411 | fseek(fd, 0, SEEK_END); 2412 | flen = ftell(fd); 2413 | fseek(fd, 0, SEEK_SET); 2414 | 2415 | inbuf = malloc(flen); 2416 | outbuf = malloc(flen * 4); /* XXX rough estimate */ 2417 | if (inbuf == NULL || outbuf == NULL) { 2418 | fprintf(stderr, "malloc(%ld) failed\n", flen); 2419 | return (EXIT_FAILURE); 2420 | } 2421 | op = outbuf; 2422 | 2423 | got = fread(inbuf, 1, flen, fd); 2424 | fclose(fd); 2425 | if (got != flen) { 2426 | fprintf(stderr, "short read: %ld instead of %ld\n", 2427 | got, flen); 2428 | return (EXIT_FAILURE); 2429 | } 2430 | 2431 | buf_sprintf(op, "STATE IDLE;\n"); 2432 | buf_sprintf(op, "STATE RESET;\n"); 2433 | buf_sprintf(op, "STATE IDLE;\n\n"); 2434 | 2435 | if (strcasecmp(&path[strlen(path) - 4], ".img") != 0) { 2436 | /* Search for bitstream preamble and IDCODE markers */ 2437 | for (i = 0, j = 0; i < flen - 32 && i < 2000; i++) 2438 | if (inbuf[i] == 0xbd && inbuf[i + 1] == 0xb3 2439 | && inbuf[i + 10] == 0xe2 && inbuf[i + 11] == 0 2440 | && inbuf[i + 12] == 0 && inbuf[i + 13] == 0) { 2441 | j = i; 2442 | break; 2443 | } 2444 | if (j == 0) { 2445 | fprintf(stderr, 2446 | "can't find IDCODE, invalid bitstream\n"); 2447 | return (EXIT_FAILURE); 2448 | } 2449 | idcode = inbuf[i + 14] << 24; 2450 | idcode += inbuf[i + 15] << 16; 2451 | idcode += inbuf[i + 16] << 8; 2452 | idcode += inbuf[i + 17]; 2453 | 2454 | /* IDCODE_PUB(0xE0): check IDCODE */ 2455 | buf_sprintf(op, "SIR 8 TDI (E0);\n"); 2456 | buf_sprintf(op, "SDR 32 TDI (00000000)\n"); 2457 | buf_sprintf(op, " TDO (%08X)\n", idcode); 2458 | buf_sprintf(op, " MASK (FFFFFFFF);\n\n"); 2459 | } 2460 | 2461 | /* LSC_PRELOAD(0x1C): Program Bscan register */ 2462 | buf_sprintf(op, "SIR 8 TDI (1C);\n"); 2463 | buf_sprintf(op, "SDR 510 TDI (3FFFFFFFFFFFFFF" 2464 | "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" 2465 | "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);\n\n"); 2466 | 2467 | /* ISC ENABLE(0xC6): Enable SRAM programming mode */ 2468 | buf_sprintf(op, "SIR 8 TDI (C6);\n"); 2469 | buf_sprintf(op, "SDR 8 TDI (00);\n"); 2470 | buf_sprintf(op, "RUNTEST IDLE 2 TCK;\n\n"); 2471 | 2472 | /* ISC ERASE(0x0e): Erase the SRAM */ 2473 | buf_sprintf(op, "SIR 8 TDI (0e);\n"); 2474 | buf_sprintf(op, "SDR 8 TDI (01);\n"); 2475 | buf_sprintf(op, "RUNTEST IDLE 32 TCK 1.00E-01 SEC;\n\n"); 2476 | 2477 | /* LSC_READ_STATUS(0x3c) */ 2478 | buf_sprintf(op, "SIR 8 TDI (3C);\n"); 2479 | buf_sprintf(op, "SDR 32 TDI (00000000)\n"); 2480 | buf_sprintf(op, " TDO (00000000)\n"); 2481 | buf_sprintf(op, " MASK (0000B000);\n\n"); 2482 | 2483 | if (jed_target == JED_TGT_FLASH) { 2484 | buf_sprintf(op, "STATE RESET;\n"); 2485 | buf_sprintf(op, "STATE IDLE;\n"); 2486 | 2487 | /* BYPASS(0xFF) */ 2488 | buf_sprintf(op, "SIR 8 TDI(FF);\n"); 2489 | buf_sprintf(op, "RUNTEST IDLE 32 TCK;\n"); 2490 | 2491 | /* LSC_PROG_SPI(0x3A) */ 2492 | buf_sprintf(op, "SIR 8 TDI(3A);\n"); 2493 | buf_sprintf(op, "SDR 16 TDI(68FE);\n"); 2494 | buf_sprintf(op, "RUNTEST IDLE 32 TCK;\n\n"); 2495 | 2496 | /* Erase sectors */ 2497 | for (i = 0; i < flen; i += SPI_SECTOR_SIZE) { 2498 | addr = i + spi_addr; 2499 | 2500 | /* SPI write enable */ 2501 | buf_sprintf(op, "SDR 8 TDI(60);\n"); 2502 | 2503 | /* Read status register (some chips won't clear WIP without this) */ 2504 | buf_sprintf(op, "SDR 16 TDI(00A0)\n"); 2505 | buf_sprintf(op, " TDO(40FF)\n"); 2506 | buf_sprintf(op, " MASK(C100);\n\n"); 2507 | 2508 | buf_sprintf(op, "SDR 32 TDI(0000%02x1B);\n", 2509 | bitrev(addr / SPI_SECTOR_SIZE)); 2510 | buf_sprintf(op, "RUNTEST DRPAUSE 5.50E-01 SEC;\n"); 2511 | 2512 | /* Read status register */ 2513 | buf_sprintf(op, "SDR 16 TDI(00A0)\n"); 2514 | buf_sprintf(op, " TDO(00FF)\n"); 2515 | buf_sprintf(op, " MASK(C100);\n\n"); 2516 | } 2517 | 2518 | /* SPI write disable */ 2519 | buf_sprintf(op, "SDR 8 TDI(20);\n\n"); 2520 | 2521 | row_size = SPI_PAGE_SIZE; 2522 | } else { 2523 | /* LSC_INIT_ADDRESS(0x46) */ 2524 | buf_sprintf(op, "SIR 8 TDI (46);\n"); 2525 | buf_sprintf(op, "SDR 8 TDI (01);\n"); 2526 | buf_sprintf(op, "RUNTEST IDLE 2 TCK;\n\n"); 2527 | 2528 | /* LSC_BITSTREAM_BURST(0x7a) */ 2529 | buf_sprintf(op, "SIR 8 TDI (7A);\n"); 2530 | buf_sprintf(op, "RUNTEST IDLE 2 TCK;\n\n"); 2531 | } 2532 | 2533 | for (i = 0; i < flen; i += row_size) { 2534 | n = flen - i; 2535 | if (n > row_size) 2536 | n = row_size; 2537 | if (jed_target == JED_TGT_FLASH) { 2538 | /* Skip write if all bits set in a block */ 2539 | for (j = 0; j < n; j++) 2540 | if (inbuf[i + j] != 0xff) 2541 | break; 2542 | if (j == n) 2543 | continue; 2544 | 2545 | buf_sprintf(op, "SDR 8 TDI(60);\n"); 2546 | buf_sprintf(op, "SDR %d TDI (", n * 8 + 32); 2547 | } else 2548 | buf_sprintf(op, "SDR %d TDI (", n * 8); 2549 | do { 2550 | n--; 2551 | op += sprintf(op, "%02X", bitrev(inbuf[i + n])); 2552 | if (n % hexlen == 0 && n > 0) 2553 | buf_sprintf(op, "\n\t"); 2554 | } while (n > 0); 2555 | if (jed_target == JED_TGT_FLASH) { 2556 | addr = i + spi_addr; 2557 | 2558 | buf_sprintf(op, "%02x%02x%02x40);\n\n", 2559 | bitrev(addr % 256), bitrev((addr / 256) % 256), 2560 | bitrev((addr / 65536) % 256)); 2561 | buf_sprintf(op, "RUNTEST DRPAUSE 2.00E-03 SEC;\n"); 2562 | buf_sprintf(op, "SDR 16 TDI(00A0)\n"); 2563 | buf_sprintf(op, " TDO(00FF)\n"); 2564 | buf_sprintf(op, " MASK(C100);\n\n"); 2565 | } else 2566 | buf_sprintf(op, ");\n\n"); 2567 | } 2568 | 2569 | /* BYPASS(0xFF) */ 2570 | buf_sprintf(op, "SIR 8 TDI (FF);\n"); 2571 | buf_sprintf(op, "RUNTEST IDLE 100 TCK;\n\n"); 2572 | 2573 | /* ISC DISABLE(Ox26): exit the programming mode */ 2574 | buf_sprintf(op, "SIR 8 TDI (26);\n"); 2575 | buf_sprintf(op, "RUNTEST IDLE 2 TCK 2.00E-03 SEC;\n\n"); 2576 | buf_sprintf(op, "SIR 8 TDI (FF);\n"); 2577 | buf_sprintf(op, "RUNTEST IDLE 2 TCK 1.00E-03 SEC;\n\n"); 2578 | 2579 | if (jed_target == JED_TGT_FLASH) { 2580 | /* LSC_REFRESH(0x79) */ 2581 | buf_sprintf(op, "SIR 8 TDI (79);\n"); 2582 | buf_sprintf(op, "SDR 24 TDI (000000);\n"); 2583 | buf_sprintf(op, "RUNTEST IDLE 2 TCK 1.00E-01 SEC;\n\n"); 2584 | } else { 2585 | /* LSC_READ_STATUS(0x3c): verify status register */ 2586 | buf_sprintf(op, "SIR 8 TDI (3C);\n"); 2587 | buf_sprintf(op, "SDR 32 TDI (00000000)\n"); 2588 | buf_sprintf(op, " TDO (00000100)\n"); 2589 | buf_sprintf(op, " MASK (00002100);\n\n"); 2590 | } 2591 | op--; 2592 | i = 0; 2593 | do { 2594 | if (*op == '\n') 2595 | i++; 2596 | } while (op-- != outbuf); 2597 | 2598 | if (svf_name) { 2599 | int of; 2600 | 2601 | if (strncmp(svf_name, "-", 1) == 0) 2602 | of = 0; 2603 | else 2604 | of = open(svf_name, O_RDWR | O_CREAT | O_TRUNC, 0644); 2605 | if (of < 0) { 2606 | res = errno; 2607 | return(res); 2608 | } 2609 | res = 0; 2610 | for (j = 0, outcp = outbuf; j < i; j++) { 2611 | write(of, outcp, strlen(outcp)); 2612 | outcp += (strlen(outcp) + 1); 2613 | } 2614 | if (of) 2615 | close(of); 2616 | } else 2617 | res = exec_svf_mem(outbuf, i, debug); 2618 | 2619 | free(outbuf); 2620 | free(inbuf); 2621 | return (res); 2622 | } 2623 | 2624 | 2625 | /* 2626 | * Load a SVF file in a contiguos chunk of memory, count number of lines, 2627 | * and then call exec_svf_mem(). 2628 | */ 2629 | static int 2630 | exec_svf_file(char *path, int debug) 2631 | { 2632 | char *linebuf, *fbuf; 2633 | FILE *fd; 2634 | long flen; 2635 | int lines_tot = 1; 2636 | int res; 2637 | 2638 | fd = fopen(path, "r"); 2639 | if (fd == NULL) { 2640 | fprintf(stderr, "open(%s) failed\n", path); 2641 | return (EXIT_FAILURE); 2642 | } 2643 | 2644 | fseek(fd, 0, SEEK_END); 2645 | flen = 2 * ftell(fd); 2646 | fseek(fd, 0, SEEK_SET); 2647 | 2648 | fbuf = malloc(flen); 2649 | if (fbuf == NULL) { 2650 | fprintf(stderr, "malloc(%ld) failed\n", flen); 2651 | return (EXIT_FAILURE); 2652 | } 2653 | 2654 | for (linebuf = fbuf; !feof(fd); linebuf += strlen(linebuf) + 1) { 2655 | if (fgets(linebuf, flen, fd) == NULL) 2656 | break; 2657 | lines_tot++; 2658 | flen -= strlen(linebuf) + 1; 2659 | } 2660 | fclose(fd); 2661 | *linebuf = 0; 2662 | 2663 | res = exec_svf_mem(fbuf, lines_tot, debug); 2664 | free(fbuf); 2665 | return (res); 2666 | } 2667 | 2668 | 2669 | /* 2670 | * Parse SVF command lines stored in a contiguos chunk of memory and 2671 | * execute appropriate JTAG actions, line by line, all in a single pass. 2672 | */ 2673 | static int 2674 | exec_svf_mem(char *fbuf, int lines_tot, int debug) 2675 | { 2676 | int lno, tokc, cmd_complete, parentheses_open; 2677 | int res = 0; 2678 | int llen = 0; 2679 | char *cp, *c1; 2680 | char *sep = " \t\n\r"; 2681 | char *linebuf, *item, *brkt; 2682 | char *tokv[256]; 2683 | 2684 | cp = svfbuf; 2685 | cmd_complete = 0; 2686 | parentheses_open = 0; 2687 | linebuf = fbuf; 2688 | 2689 | for (lno = 1; lno < lines_tot; lno++, linebuf += llen) { 2690 | if (debug) 2691 | printf("%d: %s", lno, linebuf); 2692 | 2693 | llen = strlen(linebuf) + 1; 2694 | progress_perc = lno * 1005 / (lines_tot * 10); 2695 | 2696 | /* Pre-parse input, join multiple lines to a single command */ 2697 | for (item = strtok_r(linebuf, sep, &brkt); item; 2698 | item = strtok_r(NULL, sep, &brkt)) { 2699 | /* Skip comments */ 2700 | if (item[0] == '!') 2701 | break; 2702 | if (item[0] == '/' && item[1] == '/') 2703 | break; 2704 | 2705 | /* If command is complete we shouldn't end up here! */ 2706 | if (cmd_complete) { 2707 | fprintf(stderr, "Line %d: multiple commands " 2708 | "on single line\n", lno); 2709 | return (EXIT_FAILURE); 2710 | } 2711 | 2712 | /* End of command? */ 2713 | c1 = item + strlen(item) - 1; 2714 | if (*c1 == ';') { 2715 | *c1-- = 0; 2716 | cmd_complete = 1; 2717 | } 2718 | 2719 | /* Check for parentheses */ 2720 | if (*item == '(') { 2721 | item++; 2722 | if (parentheses_open) { 2723 | fprintf(stderr, 2724 | "Line %d: too many '('s\n", lno); 2725 | return (EXIT_FAILURE); 2726 | } 2727 | parentheses_open = 1; 2728 | } 2729 | if (!parentheses_open) 2730 | for (char *ct = item; ct < c1; ct++) 2731 | if (*ct == '(') { 2732 | *ct = ' '; 2733 | parentheses_open = 1; 2734 | break; 2735 | } 2736 | if (*c1 == ')') { 2737 | *c1 = 0; 2738 | if (!parentheses_open) { 2739 | fprintf(stderr, 2740 | "Line %d: too many ')'s\n", lno); 2741 | return (EXIT_FAILURE); 2742 | } 2743 | parentheses_open = 0; 2744 | } 2745 | 2746 | /* Copy to command buffer */ 2747 | strcpy(cp, item); 2748 | cp += strlen(item); 2749 | if (!parentheses_open && !cmd_complete) 2750 | *cp++ = ' '; 2751 | } 2752 | 2753 | /* Proceed to next line if command is not complete yet */ 2754 | if (!cmd_complete) 2755 | continue; 2756 | 2757 | /* Unmatched parentheses are not permitted */ 2758 | if (parentheses_open) { 2759 | fprintf(stderr, "Line %d: missing ')'\n", lno); 2760 | return (EXIT_FAILURE); 2761 | } 2762 | 2763 | /* Normalize to all upper case letters, separate tokens */ 2764 | tokc = 0; 2765 | tokv[0] = svfbuf; 2766 | for (cp = svfbuf; *cp != 0; cp++) { 2767 | if (*cp == ' ') { 2768 | *cp++ = 0; 2769 | tokc++; 2770 | tokv[tokc] = cp; 2771 | } 2772 | *cp = toupper(*cp); 2773 | } 2774 | if (*tokv[tokc] != 0) 2775 | tokc++; 2776 | 2777 | /* Execute command */ 2778 | res = exec_svf_tokenized(tokc, tokv); 2779 | if (res) { 2780 | if (res != ENODEV) 2781 | fprintf(stderr, "Line %d: %s\n", lno, 2782 | strerror(res)); 2783 | return (res); 2784 | } 2785 | 2786 | cp = svfbuf; 2787 | cmd_complete = 0; 2788 | } 2789 | 2790 | /* Flush any buffered data */ 2791 | commit(1); 2792 | 2793 | return (res); 2794 | } 2795 | 2796 | 2797 | static void 2798 | terminal_help(void) 2799 | { 2800 | 2801 | printf( 2802 | " ~> send file\n" 2803 | " ~b change baudrate\n" 2804 | " ~r reprogram / reload " 2805 | "the FPGA\n" 2806 | " ~# send a BREAK signal\n" 2807 | " ~d enter f32c debugger\n" 2808 | " ~. exit from ujprog\n" 2809 | " ~? get this summary\n" 2810 | ); 2811 | } 2812 | 2813 | 2814 | static void 2815 | usage(void) 2816 | { 2817 | 2818 | printf("Usage: ujprog [option(s)] [bitstream_file]\n\n"); 2819 | 2820 | printf(" Valid options:\n"); 2821 | #ifdef USE_PPI 2822 | printf(" -c CABLE Select USB (default) or PPI JTAG CABLE\n"); 2823 | #endif 2824 | printf(" -C value Set CBUS pin values (FTDI only)\n"); 2825 | printf(" -p PORT Select USB JTAG / UART PORT (default is 0)\n"); 2826 | #ifdef WIN32 2827 | printf(" -P COM Select COM port (valid only with -t or -a)\n"); 2828 | #else 2829 | printf(" -P TTY Select TTY port (valid only with -t or -a)\n"); 2830 | #endif 2831 | printf(" -j TARGET Select bitstream TARGET as SRAM (default)" 2832 | " or FLASH\n"); 2833 | printf(" -f ADDR Start writing to SPI flash at ADDR, " 2834 | "optional with -j flash\n"); 2835 | printf(" -s FILE Convert bitstream to SVF FILE and exit\n"); 2836 | printf(" -r Reload FPGA configuration from" 2837 | " FLASH\n"); 2838 | printf(" -t Enter terminal emulation mode after" 2839 | " completing JTAG operations\n"); 2840 | printf(" -b SPEED Set baudrate to SPEED (300 to 3000000" 2841 | " bauds)\n"); 2842 | printf(" -e FILE Send and execute a f32c (MIPS/RISCV) binary " 2843 | "FILE\n"); 2844 | printf(" -x SPEED Set binary transfer speed, optional with -e\n"); 2845 | printf(" -a FILE Send a raw FILE\n"); 2846 | printf(" -d debug (verbose)\n"); 2847 | printf(" -D DELAY Delay transmission of each byte by" 2848 | " DELAY ms\n"); 2849 | printf(" -q Suppress messages\n"); 2850 | 2851 | if (terminal) { 2852 | printf("\n Terminal emulation mode commands:\n"); 2853 | terminal_help(); 2854 | } 2855 | #ifndef WIN32 2856 | printf("\n"); 2857 | #endif 2858 | } 2859 | 2860 | 2861 | static int 2862 | gets1(char *cp, int size) 2863 | { 2864 | char *lp, *end; 2865 | char c; 2866 | int error = 0; 2867 | 2868 | lp = cp; 2869 | end = cp + size - 1; 2870 | for (;;) { 2871 | #ifdef WIN32 2872 | c = getch() & 0177; 2873 | #else 2874 | while (read(0, &c, 1) < 0) 2875 | ms_sleep(10); 2876 | #endif 2877 | switch (c) { 2878 | case 3: /* CTRL + C */ 2879 | error = -1; 2880 | case '\n': 2881 | case '\r': 2882 | printf("\n"); 2883 | *lp = '\0'; 2884 | return (error); 2885 | case '\b': 2886 | case '\177': 2887 | if (lp > cp) { 2888 | printf("%c \b", c); 2889 | fflush(stdout); 2890 | lp--; 2891 | } 2892 | continue; 2893 | case '\0': 2894 | continue; 2895 | default: 2896 | if (lp < end) { 2897 | printf("%c", c); 2898 | fflush(stdout); 2899 | *lp++ = c; 2900 | } 2901 | } 2902 | } 2903 | } 2904 | 2905 | 2906 | static int 2907 | prog(char *fname, int target, int debug) 2908 | { 2909 | int res, c, tstart, tend; 2910 | 2911 | c = strlen(fname) - 4; 2912 | if (c < 0) { 2913 | usage(); 2914 | exit(EXIT_FAILURE); 2915 | } 2916 | 2917 | if (cable_hw == CABLE_RAW) 2918 | srec_header(fname); 2919 | 2920 | tstart = ms_uptime(); 2921 | last_ledblink_ms = tstart; 2922 | 2923 | /* Move TAP into RESET state. */ 2924 | set_port_mode(PORT_MODE_ASYNC); 2925 | set_state(RESET); 2926 | 2927 | commit(1); 2928 | 2929 | if (strcasecmp(&fname[c], ".jed") == 0) 2930 | res = exec_jedec_file(fname, target, debug); 2931 | else if (strcasecmp(&fname[c], ".bit") == 0 || 2932 | (strcasecmp(&fname[c], ".img") == 0 && target == JED_TGT_FLASH)) 2933 | res = exec_bit_file(fname, target, debug); 2934 | else if (strcasecmp(&fname[c], ".svf") == 0) 2935 | res = exec_svf_file(fname, debug); 2936 | else 2937 | res = -1; 2938 | 2939 | /* Leave TAP in RESET state. */ 2940 | set_port_mode(PORT_MODE_ASYNC); 2941 | set_state(IDLE); 2942 | set_state(RESET); 2943 | commit(1); 2944 | 2945 | tend = ms_uptime(); 2946 | if (res == 0) { 2947 | if (!quiet) { 2948 | fprintf(stderr, "\rProgramming: 100%% "); 2949 | fprintf(stderr, "\nCompleted in %.2f seconds.\n", 2950 | (tend - tstart) / 1000.0); 2951 | } 2952 | } else 2953 | fprintf(stderr, "\nFailed.\n"); 2954 | 2955 | return (res); 2956 | } 2957 | 2958 | 2959 | #if 0 2960 | static void 2961 | reload_xp2_flash(int debug) 2962 | { 2963 | char buf[128]; 2964 | char *c; 2965 | 2966 | if (!quiet) 2967 | printf("Reconfiguring FPGA...\n"); 2968 | last_ledblink_ms = ms_uptime(); 2969 | need_led_blink = 0; 2970 | 2971 | /* Move TAP into RESET state. */ 2972 | set_port_mode(PORT_MODE_SYNC); 2973 | set_state(IDLE); 2974 | set_state(RESET); 2975 | commit(1); 2976 | 2977 | /* Reset sequence */ 2978 | c = buf; 2979 | c += sprintf(c, "RUNTEST IDLE 30 TCK;\n"); 2980 | *c++ = 0; 2981 | c += sprintf(c, "SIR 8 TDI (1E);\n"); 2982 | *c++ = 0; 2983 | c += sprintf(c, "SIR 8 TDI (23);\n"); 2984 | *c++ = 0; 2985 | c += sprintf(c, "!\n"); 2986 | exec_svf_mem(buf, 4, debug); 2987 | 2988 | /* Leave TAP in RESET state. */ 2989 | set_state(IDLE); 2990 | set_state(RESET); 2991 | commit(1); 2992 | } 2993 | #endif 2994 | 2995 | 2996 | static int 2997 | async_read_block(int len) 2998 | { 2999 | int res, got = 0, backoff = 0, backoff_lim = 5; 3000 | int i; 3001 | #if defined(__FreeBSD__) || defined(__linux__) 3002 | if (cable_hw == CABLE_HW_COM) 3003 | backoff_lim = 10; 3004 | #endif 3005 | do { 3006 | if (cable_hw == CABLE_HW_USB) { 3007 | #ifdef WIN32 3008 | DWORD ev_stat, avail; 3009 | FT_GetStatus(ftHandle, &avail, &ev_stat, &ev_stat); 3010 | if (avail > len - got) 3011 | avail = len - got; 3012 | if (avail) 3013 | FT_Read(ftHandle, &rxbuf[got], avail, 3014 | (DWORD *) &res); 3015 | else 3016 | res = 0; 3017 | #else 3018 | res = ftdi_read_data(&fc, &rxbuf[got], len - got); 3019 | #endif 3020 | } else { 3021 | #ifdef WIN32 3022 | DWORD n; 3023 | n = len - got; 3024 | if (n > 32) 3025 | n = 32; 3026 | ReadFile(com_port, &rxbuf[got], n, 3027 | (DWORD *) &res, NULL); 3028 | #else 3029 | res = read(com_port, &rxbuf[got], len - got); 3030 | if (res == -1) 3031 | res = 0; 3032 | #endif 3033 | } 3034 | if (res > 0) { 3035 | got += res; 3036 | backoff = 0; 3037 | } else { 3038 | backoff++; 3039 | ms_sleep(backoff * 4); 3040 | } 3041 | } while (got < len && backoff < backoff_lim); 3042 | if(global_debug) 3043 | { 3044 | fprintf(stderr, "<"); 3045 | for(i = 0; i < got; i++) 3046 | fprintf(stderr, " %02x", rxbuf[i]); 3047 | fprintf(stderr, "\n"); 3048 | } 3049 | return (got); 3050 | } 3051 | 3052 | 3053 | static int 3054 | async_send_block(int len) 3055 | { 3056 | int sent; 3057 | int i; 3058 | 3059 | if (cable_hw == CABLE_HW_USB) { 3060 | #ifdef WIN32 3061 | FT_Write(ftHandle, txbuf, len, (DWORD *) &sent); 3062 | #else 3063 | sent = ftdi_write_data(&fc, txbuf, len); 3064 | #endif 3065 | } else { 3066 | #ifdef WIN32 3067 | WriteFile(com_port, txbuf, len, (DWORD *) &sent, NULL); 3068 | #else 3069 | fcntl(com_port, F_SETFL, 0); 3070 | sent = write(com_port, txbuf, len); 3071 | tcdrain(com_port); // flush data to hardware 3072 | fcntl(com_port, F_SETFL, O_NONBLOCK); 3073 | #endif 3074 | } 3075 | if(global_debug) 3076 | { 3077 | fprintf(stderr, ">"); 3078 | for(i = 0; i < sent && i < 20; i++) 3079 | fprintf(stderr, " %02x", txbuf[i]); 3080 | if(sent >= 20) 3081 | fprintf(stderr, "..."); 3082 | fprintf(stderr, "\n"); 3083 | } 3084 | if (sent == len) 3085 | return (0); 3086 | else 3087 | return (1); 3088 | } 3089 | 3090 | 3091 | static void 3092 | async_send_uint8(uint32_t data) 3093 | { 3094 | 3095 | txbuf[0] = data; 3096 | async_send_block(1); 3097 | } 3098 | 3099 | 3100 | static void 3101 | async_send_uint32(uint32_t data) 3102 | { 3103 | int i; 3104 | 3105 | for (i = 0; i < 4; i++) { 3106 | txbuf[i] = (data >> 24); 3107 | data <<= 8; 3108 | } 3109 | async_send_block(4); 3110 | } 3111 | 3112 | 3113 | static int 3114 | async_set_baudrate(int speed) 3115 | { 3116 | 3117 | if (cable_hw == CABLE_HW_USB) { 3118 | #ifdef WIN32 3119 | FT_SetBaudRate(ftHandle, speed); 3120 | #else 3121 | ftdi_set_baudrate(&fc, speed); 3122 | #endif 3123 | } else { 3124 | #ifdef WIN32 3125 | if (GetCommState(com_port, &tty) == 0) { 3126 | fprintf(stderr, "%s is not a COM port\n", com_name); 3127 | exit(EXIT_FAILURE); 3128 | } 3129 | tty.BaudRate = speed; 3130 | tty.StopBits = 0; 3131 | tty.Parity = 0; 3132 | tty.ByteSize = 8; 3133 | if (SetCommState(com_port, &tty) == 0) { 3134 | fprintf(stderr, "Can't set baudrate to %d\n", speed); 3135 | exit(EXIT_FAILURE); 3136 | } 3137 | #else 3138 | cfsetspeed(&tty, speed); 3139 | if (tcsetattr(com_port, TCSAFLUSH, &tty) != 0) { 3140 | fprintf(stderr, "Can't set baudrate to %d\n", speed); 3141 | exit(EXIT_FAILURE); 3142 | } 3143 | #endif 3144 | } 3145 | return (0); 3146 | } 3147 | 3148 | 3149 | static void 3150 | txfile(void) 3151 | { 3152 | int infile, res; 3153 | int crc_retry; 3154 | int tx_retry, tx_success; 3155 | uint32_t rx_crc, local_crc, crc_i, tx_cnt; 3156 | uint32_t i, base, bootaddr; 3157 | uint8_t hdrbuf[16]; 3158 | 3159 | if (tx_binary) { 3160 | infile = open(txfname, 3161 | #ifdef WIN32 3162 | O_RDONLY | O_BINARY 3163 | #else 3164 | O_RDONLY 3165 | #endif 3166 | ); 3167 | if (infile < 0) { 3168 | fprintf(stderr, "%s: cannot open\n", txfname); 3169 | return; 3170 | } 3171 | i = read(infile, hdrbuf, 16); 3172 | close(infile); 3173 | if (i != 16) { 3174 | fprintf(stderr, "%s: short read: got %d instead of " 3175 | "16 bytes\n", txfname, i); 3176 | return; 3177 | } 3178 | if (hdrbuf[2] == 0x10 && hdrbuf[3] == 0x3c && 3179 | hdrbuf[6] == 0x10 && hdrbuf[7] == 0x26 && 3180 | hdrbuf[10] == 0x11 && hdrbuf[11] == 0x3c && 3181 | hdrbuf[14] == 0x31 && hdrbuf[7] == 0x26) { 3182 | /* MIPS, little-endian cookie found */ 3183 | base = (hdrbuf[1] << 24) + (hdrbuf[0] << 16) 3184 | + (hdrbuf[5] << 8) + hdrbuf[4]; 3185 | if (!quiet) 3186 | printf("MIPS little-endian"); 3187 | } else if (hdrbuf[2] == 0x10 && hdrbuf[3] == 0x3c && 3188 | hdrbuf[6] == 0x10 && hdrbuf[7] == 0x26 && 3189 | hdrbuf[10] == 0x11 && hdrbuf[11] == 0x3c) { 3190 | /* MIPS, big-endian cookie found */ 3191 | /* XXX fixme */ 3192 | fprintf(stderr, "%s: MIPS, big-endian UNSUPPORTED\n", 3193 | txfname); 3194 | return; 3195 | } else if ((hdrbuf[1] & 0xf) == 1 && hdrbuf[0] == 0x97 && 3196 | hdrbuf[4] == 0x93 && hdrbuf[5] == 0x81) { 3197 | /* RISC-V, little-endian cookie found */ 3198 | /* XXX hardcoded load address - fixme */ 3199 | base = 0x400; 3200 | if (!quiet) 3201 | printf("RISC-V (PIC)"); 3202 | } else { 3203 | fprintf(stderr, 3204 | "invalid file type, missing header cookie\n"); 3205 | return; 3206 | } 3207 | bootaddr = base; 3208 | if (!quiet) 3209 | printf(" binary, loading at 0x%08x, " 3210 | "TX speed %d bauds\n", base, xbauds); 3211 | } 3212 | 3213 | infile = open(txfname, 3214 | #ifdef WIN32 3215 | O_RDONLY | O_BINARY 3216 | #else 3217 | O_RDONLY 3218 | #endif 3219 | ); 3220 | if (infile < 0) { 3221 | fprintf(stderr, "%s: cannot open\n", txfname); 3222 | return; 3223 | } 3224 | 3225 | async_set_baudrate(bauds); 3226 | if (cable_hw == CABLE_HW_USB) { 3227 | set_port_mode(PORT_MODE_UART); 3228 | #ifdef WIN32 3229 | FT_SetDataCharacteristics(ftHandle, FT_BITS_8, FT_STOP_BITS_1, 3230 | FT_PARITY_NONE); 3231 | FT_SetFlowControl(ftHandle, FT_FLOW_NONE, 0, 0); 3232 | do {} while (FT_StopInTask(ftHandle) != FT_OK); 3233 | ms_sleep(50); 3234 | FT_Purge(ftHandle, FT_PURGE_RX); 3235 | do {} while (FT_RestartInTask(ftHandle) != FT_OK); 3236 | #else 3237 | ftdi_set_line_property(&fc, BITS_8, STOP_BIT_1, NONE); 3238 | ftdi_setflowctrl(&fc, SIO_DISABLE_FLOW_CTRL); 3239 | ftdi_usb_purge_buffers(&fc); 3240 | ms_sleep(50); 3241 | #endif 3242 | } 3243 | 3244 | /* Send a space mark to break into SIO loader prompt */ 3245 | async_send_uint8(' '); 3246 | 3247 | /* Wait for f32c ROM to catch up */ 3248 | if (tx_binary) 3249 | ms_sleep(200); 3250 | else 3251 | ms_sleep(100); 3252 | 3253 | /* Prune any stale data from rx buffer */ 3254 | async_read_block(2048); 3255 | 3256 | if (tx_binary) { 3257 | /* Start of binary transfer marker */ 3258 | async_send_uint8(255); 3259 | 3260 | async_send_uint8(0x80); /* CMD: set base */ 3261 | async_send_uint32(xbauds); 3262 | async_send_uint8(0xb0); /* CMD: set baudrate */ 3263 | ms_sleep(50); 3264 | async_set_baudrate(xbauds); 3265 | } 3266 | 3267 | i = bauds / 300; 3268 | if (bauds < 4800) 3269 | i = 16; 3270 | if (txfu_ms) 3271 | i = 1; 3272 | if (tx_binary) 3273 | i = 8192; 3274 | do { 3275 | if (!quiet) { 3276 | printf("%c ", statc[blinker_phase]); 3277 | printf("\rSending %s: ", txfname); 3278 | fflush(stdout); 3279 | blinker_phase = (blinker_phase + 1) & 0x3; 3280 | } 3281 | res = read(infile, &txbuf[8192], i); 3282 | if (!tx_binary && txfu_ms) 3283 | ms_sleep(txfu_ms); 3284 | if (res <= 0) { 3285 | tx_cnt = 0; 3286 | } else 3287 | tx_cnt = res; 3288 | 3289 | if (tx_cnt == 0) 3290 | break; 3291 | 3292 | if (tx_binary) { 3293 | tx_success = 0; 3294 | for(tx_retry = 0; tx_retry < 4 && tx_success == 0; tx_retry++) 3295 | { 3296 | async_send_uint8(0x80); /* CMD: set base */ 3297 | async_send_uint32(tx_cnt); 3298 | async_send_uint8(0x90); /* CMD: len = base */ 3299 | 3300 | async_send_uint8(0x80); /* CMD: set base */ 3301 | async_send_uint32(base); 3302 | 3303 | async_send_uint8(0xa0); /* CMD: Write block */ 3304 | local_crc = 0; 3305 | for (crc_i = 0; crc_i < tx_cnt; crc_i++) { 3306 | local_crc = 3307 | (local_crc >> 31) | (local_crc << 1); 3308 | txbuf[crc_i] = txbuf[crc_i + 8192]; 3309 | local_crc += txbuf[crc_i]; 3310 | } 3311 | #if 0 3312 | if(1) // intentionally damage tx packet to test CRC 3313 | { 3314 | // srandom(time(NULL)); // randomize seed, each run will be different 3315 | if( (rand() % 256) > 100 ) // error probability 100/256 3316 | txbuf[rand() % tx_cnt] = rand() % 0xFF; // error byte at random place 3317 | } 3318 | #endif 3319 | if (async_send_block(tx_cnt)) { 3320 | fprintf(stderr, "Block sending failed!\n"); 3321 | tx_cnt = -1; 3322 | continue; 3323 | } 3324 | if(txfu_ms > 0) 3325 | ms_sleep(txfu_ms); 3326 | async_send_uint8(0x81); // read checksum 3327 | res = 0; 3328 | for(crc_retry = 4; crc_retry > 0 && res != 4; ms_sleep(10), crc_retry--) 3329 | { 3330 | res = async_read_block(4); 3331 | if(crc_retry == 2 && res != 4) 3332 | async_send_uint8(0x81); // try again to read checksum 3333 | } 3334 | if(res != 4) 3335 | { 3336 | fprintf(stderr, "Checksum not received: " 3337 | "got %d bytes, should be 4 (0x%08X)\n", res, local_crc); 3338 | continue; 3339 | } 3340 | rx_crc = rxbuf[0] << 24; 3341 | rx_crc += rxbuf[1] << 16; 3342 | rx_crc += rxbuf[2] << 8; 3343 | rx_crc += rxbuf[3]; 3344 | if (rx_crc != local_crc) { 3345 | fprintf(stderr, "CRC error: " 3346 | "got 0x%08x, should be 0x%08x\n", 3347 | rx_crc, local_crc); 3348 | continue; 3349 | } 3350 | else 3351 | { 3352 | tx_success = 1; // checksum ok 3353 | tx_retry = 0; // reset number of retries 3354 | } 3355 | } 3356 | if(tx_success == 0) 3357 | { 3358 | tx_cnt = -1; // give up, no more retries retries 3359 | break; 3360 | } 3361 | } else { 3362 | memcpy(txbuf, &txbuf[8192], tx_cnt); 3363 | if (async_send_block(tx_cnt)) { 3364 | fprintf(stderr, "Block sending failed!\n"); 3365 | tx_cnt = -1; 3366 | break; 3367 | } 3368 | tx_success = 1; 3369 | } 3370 | if(tx_success) 3371 | base += tx_cnt; 3372 | } while (tx_cnt > 0); 3373 | 3374 | 3375 | if (tx_cnt >= 0 && !quiet) 3376 | printf("done.\n"); 3377 | close(infile); 3378 | fflush(stdout); 3379 | 3380 | if (tx_success == 0) 3381 | fprintf(stderr, "TX error at %08x\n", base); 3382 | else if (tx_binary) { 3383 | async_send_uint8(0x80); /* CMD: set base */ 3384 | async_send_uint32(bauds); 3385 | async_send_uint8(0xb0); /* CMD: set baudrate */ 3386 | ms_sleep(50); 3387 | async_set_baudrate(bauds); 3388 | 3389 | async_send_uint8(0x80); /* CMD: set base */ 3390 | async_send_uint32(bootaddr); 3391 | async_send_uint8(0xb1); /* CMD: jump to base */ 3392 | } 3393 | } 3394 | 3395 | 3396 | static void 3397 | genbrk(int ms) 3398 | { 3399 | 3400 | if (cable_hw == CABLE_HW_USB) { 3401 | #ifdef WIN32 3402 | FT_SetBreakOn(ftHandle); 3403 | ms_sleep(ms); 3404 | FT_SetBreakOff(ftHandle); 3405 | #else 3406 | ftdi_set_line_property2(&fc, BITS_8, STOP_BIT_1, NONE, 3407 | BREAK_ON); 3408 | ms_sleep(ms); 3409 | ftdi_set_line_property2(&fc, BITS_8, STOP_BIT_1, NONE, 3410 | BREAK_OFF); 3411 | #endif 3412 | } else { 3413 | #ifdef WIN32 3414 | EscapeCommFunction(com_port, SETBREAK); 3415 | ms_sleep(ms); 3416 | EscapeCommFunction(com_port, CLRBREAK); 3417 | #else 3418 | ioctl(com_port, TIOCSBRK, NULL); 3419 | ms_sleep(ms); 3420 | ioctl(com_port, TIOCCBRK, NULL); 3421 | #endif 3422 | } 3423 | ms_sleep(20); 3424 | } 3425 | 3426 | 3427 | static const char *riscv_reg_names[] = { 3428 | "zr", "ra", "sp", "gp", "tp", "t0", "t1", "t2", 3429 | "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", 3430 | "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", 3431 | "s8", "s9", "sA", "sB", "t3", "t4", "t5", "t6" 3432 | }; 3433 | 3434 | static const char *mips_reg_names[] = { 3435 | "zr", "at", "v0", "v1", "a0", "a1", "a2", "a3", 3436 | "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", 3437 | "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", 3438 | "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra" 3439 | }; 3440 | 3441 | 3442 | static int deb_seqn; 3443 | static int deb_big_endian; 3444 | static int deb_riscv; 3445 | 3446 | 3447 | static void 3448 | deb_print_reg(int off) 3449 | { 3450 | int i; 3451 | 3452 | for (i = 0; i < 4; i++) 3453 | printf("%02x", rxbuf[off * 4 + (3 - i)]); 3454 | } 3455 | 3456 | 3457 | static int 3458 | deb_get_seqn() 3459 | { 3460 | int i; 3461 | 3462 | i = async_read_block(1); 3463 | if (i == 0) { 3464 | printf("Error: got no sequence number, " 3465 | "debugger disfunctional!\n"); 3466 | return (1); 3467 | } 3468 | if (rxbuf[0] != ((deb_seqn + 1) & 0xff)) { 3469 | printf("Error: bad sequence number: " 3470 | "got %d, should have %d\n", rxbuf[0], 3471 | (deb_seqn + 1) & 0xff); 3472 | return (1); 3473 | } 3474 | deb_seqn = rxbuf[0]; 3475 | return (0); 3476 | } 3477 | 3478 | 3479 | #define BREAKPOINTS 2 3480 | 3481 | static int 3482 | deb_print_breakpoints(void) 3483 | { 3484 | int i, enabled, trapped; 3485 | 3486 | async_send_uint8(0xa1); /* DEB_CMD_BREAKPOINT_RD */ 3487 | async_send_uint8(0); /* start at breakpoint #0 */ 3488 | async_send_uint8(BREAKPOINTS - 1);/* fetch values */ 3489 | deb_get_seqn(); 3490 | i = async_read_block(BREAKPOINTS * 4); 3491 | if (i != BREAKPOINTS * 4) { 3492 | printf("\nError: short read " 3493 | "(%d instead of %d)\n", i, BREAKPOINTS * 4); 3494 | return (-1); 3495 | } 3496 | 3497 | for (i = 0; i < BREAKPOINTS; i++) { 3498 | enabled = rxbuf[i * 4] & 1; 3499 | trapped = rxbuf[i * 4] & 2; 3500 | rxbuf[i * 4] &= ~3; 3501 | printf("breakpoint #%d: ", i); 3502 | if (enabled) { 3503 | deb_print_reg(i); 3504 | if (trapped) 3505 | printf(" (trapped)"); 3506 | printf("\n"); 3507 | } else 3508 | printf("disabled\n"); 3509 | } 3510 | 3511 | return (0); 3512 | } 3513 | 3514 | 3515 | static int 3516 | deb_print_registers(void) 3517 | { 3518 | int r, c, i; 3519 | 3520 | async_send_uint8(0xa0); /* DEB_CMD_REG_RD */ 3521 | async_send_uint8(0); /* start at reg #0 */ 3522 | async_send_uint8(63); /* fetch 64 values */ 3523 | deb_get_seqn(); 3524 | i = async_read_block(64 * 4); 3525 | if (i != 64 * 4) { 3526 | printf("\nError: short read " 3527 | "(%d instead of %d)\n", i, 64 * 4); 3528 | return (-1); 3529 | } 3530 | 3531 | for (r = 0; r < 8; r++) { 3532 | for (c = 0; c < 4; c++) { 3533 | if (r + 8 * c < 10) 3534 | printf(" "); 3535 | if (deb_riscv) 3536 | printf("x%d (%s): ", r + 8 * c, 3537 | riscv_reg_names[r + 8 * c]); 3538 | else 3539 | printf("$%d (%s): ", r + 8 * c, 3540 | mips_reg_names[r + 8 * c]); 3541 | deb_print_reg(r + 8 * c); 3542 | if (c != 3) 3543 | printf(" "); 3544 | } 3545 | printf("\n"); 3546 | } 3547 | printf("\n"); 3548 | 3549 | printf(" HI: "); 3550 | deb_print_reg(32); 3551 | printf(" LO: "); 3552 | deb_print_reg(33); 3553 | printf(" SR: "); 3554 | deb_print_reg(34); 3555 | printf(" CS: "); 3556 | deb_print_reg(35); 3557 | printf(" EPC: "); 3558 | deb_print_reg(36); 3559 | printf(" EB: "); 3560 | deb_print_reg(37); 3561 | printf("\n"); 3562 | 3563 | printf("\n"); 3564 | printf(" IF A: "); 3565 | deb_print_reg(40); 3566 | printf(" ID A: "); 3567 | deb_print_reg(42); 3568 | printf(" EX A: "); 3569 | deb_print_reg(44); 3570 | printf(" MA A: "); 3571 | deb_print_reg(46); 3572 | printf(" WB A: "); 3573 | deb_print_reg(48); 3574 | printf("\n"); 3575 | 3576 | printf(" IF I: "); 3577 | deb_print_reg(41); 3578 | printf(" ID I: "); 3579 | deb_print_reg(43); 3580 | printf(" EX I: "); 3581 | deb_print_reg(45); 3582 | printf(" MA I: "); 3583 | deb_print_reg(47); 3584 | printf(" WB I: "); 3585 | deb_print_reg(49); 3586 | printf("\n"); 3587 | 3588 | printf("\n"); 3589 | printf(" Count: "); 3590 | deb_print_reg(38); 3591 | printf(" Exec: "); 3592 | deb_print_reg(52); 3593 | printf(" Branch: "); 3594 | deb_print_reg(53); 3595 | printf(" Mispred: "); 3596 | deb_print_reg(54); 3597 | printf("\n"); 3598 | 3599 | return (0); 3600 | } 3601 | 3602 | 3603 | static void 3604 | debug_help(void) 3605 | { 3606 | 3607 | printf( 3608 | " r show registers\n" 3609 | " R show registers until a key is pressed\n" 3610 | " s execute a single clock cycle\n" 3611 | " s N execute at most N clock cycles\n" 3612 | " c continue execution\n" 3613 | " b show breakpoints\n" 3614 | " b N deactivate breakpoint N\n" 3615 | " b N,A set breakpoint N at address A\n" 3616 | " . exit from debugger\n" 3617 | " h get this summary\n" 3618 | " ? get this summary\n" 3619 | ); 3620 | } 3621 | 3622 | 3623 | static void 3624 | debug_cmd(void) 3625 | { 3626 | char cmdbuf[256]; 3627 | int i, j, c, r; 3628 | #ifdef WIN32 3629 | HANDLE cons_out = GetStdHandle(STD_OUTPUT_HANDLE); 3630 | CONSOLE_SCREEN_BUFFER_INFO screen_info; 3631 | #endif 3632 | 3633 | /* Enable debugger */ 3634 | printf("\n*** Entering debug mode ***\n"); 3635 | async_send_uint8(0x9d); 3636 | async_send_uint8(0xed); 3637 | 3638 | /* Flush read buffer */ 3639 | async_read_block(BUFLEN_MAX); 3640 | 3641 | /* Fetch initial sequence number and config register */ 3642 | async_send_uint8(0xa0); /* DEB_CMD_REG_RD */ 3643 | async_send_uint8(55); /* start at reg #55 */ 3644 | async_send_uint8(0); /* fetch 1 value */ 3645 | i = async_read_block(1); 3646 | if (i == 0) { 3647 | printf("Error: got no sequence number\n"); 3648 | printf("Debugger disfunctional, exiting.\n"); 3649 | return; 3650 | } 3651 | deb_seqn = rxbuf[0]; 3652 | i = async_read_block(4); 3653 | if (i != 4) { 3654 | printf("\nError: short read (%d instead of %d)\n", i, 4); 3655 | printf("Debugger disfunctional, exiting.\n"); 3656 | return; 3657 | } 3658 | printf("Detected "); 3659 | if (rxbuf[1] & 0x80) { 3660 | printf("big-endian "); 3661 | deb_big_endian = 1; 3662 | } else { 3663 | printf("little-endian "); 3664 | deb_big_endian = 0; 3665 | } 3666 | if (rxbuf[1] & 0x40) { 3667 | printf("f32c/riscv"); 3668 | deb_riscv = 1; 3669 | } else { 3670 | printf("f32c/mips"); 3671 | deb_riscv = 0; 3672 | } 3673 | printf(" core, clk ticks at %f MHz.\n", 1.0 * 3674 | (((rxbuf[3] & 0xf) << 8) + rxbuf[2]) / ((rxbuf[3] >> 5) + 1)); 3675 | 3676 | do { 3677 | printf("db> "); 3678 | fflush(stdout); 3679 | gets1(cmdbuf, sizeof(cmdbuf)); 3680 | for (i = 0; cmdbuf[i] != 0 ; i++) 3681 | if (cmdbuf[i] != ' ' && cmdbuf[i] != 9) 3682 | break; 3683 | switch (cmdbuf[i]) { 3684 | case 's': /* single step */ 3685 | c = atoi(&cmdbuf[i + 1]); 3686 | if (c < 1) 3687 | c = 1; 3688 | async_send_uint8(0xef); /* DEB_CMD_CLK_STEP */ 3689 | async_send_uint32(0); /* disable clk when done */ 3690 | async_send_uint32(c); /* how many cycles */ 3691 | deb_get_seqn(); 3692 | printf("Single-stepping %d cycle(s)...\n", c); 3693 | /* XXX ugly hack, wait for cycles to pass... */ 3694 | ms_sleep(c / 50000); 3695 | deb_print_registers(); 3696 | break; 3697 | case 'b': /* set / clear breakpoints */ 3698 | i++; 3699 | while (cmdbuf[i] == ' ' || cmdbuf[i] == 8) 3700 | i++; 3701 | if (cmdbuf[i] == 0) { 3702 | deb_print_breakpoints(); 3703 | break; 3704 | } 3705 | j = i; 3706 | while (isnumber(cmdbuf[j])) 3707 | j++; 3708 | r = atoi(&cmdbuf[i]); 3709 | i = j; 3710 | while (cmdbuf[i] == ' ' || cmdbuf[i] == 8 || 3711 | cmdbuf[i] == ',') 3712 | i++; 3713 | c = strtoul(&cmdbuf[i], NULL, 16); 3714 | c &= ~3; /* Word align */ 3715 | if (cmdbuf[i] != 0) 3716 | c |= 1; /* Set breakpoint enable flag */ 3717 | async_send_uint8(0xe1); /* DEB_CMD_BREAKPOINT_WR */ 3718 | async_send_uint32(r); /* dst reg */ 3719 | async_send_uint32(c); /* value */ 3720 | deb_get_seqn(); 3721 | break; 3722 | case 'c': /* continue */ 3723 | async_send_uint8(0xef); /* DEB_CMD_CLK_STEP */ 3724 | async_send_uint32(1); /* enable clk */ 3725 | async_send_uint32(0); /* don't wait */ 3726 | deb_get_seqn(); 3727 | break; 3728 | case 'r': /* print registers */ 3729 | deb_print_registers(); 3730 | break; 3731 | case 'R': /* continuously print registers */ 3732 | do { 3733 | if (deb_print_registers() != 0) 3734 | break; 3735 | #ifdef WIN32 3736 | if (kbhit()) { 3737 | c = getch(); 3738 | #else 3739 | if (read(0, &c, 1) > 0) { 3740 | #endif 3741 | break; 3742 | } 3743 | #ifdef WIN32 3744 | GetConsoleScreenBufferInfo(cons_out, 3745 | &screen_info); 3746 | screen_info.dwCursorPosition.X = 0; 3747 | screen_info.dwCursorPosition.Y -= 15; 3748 | SetConsoleCursorPosition(cons_out, 3749 | screen_info.dwCursorPosition); 3750 | #else 3751 | printf("\r\033[15A"); 3752 | #endif 3753 | } while (1); 3754 | break; 3755 | case 'q': 3756 | cmdbuf[i] = '.'; 3757 | break; 3758 | case '.': 3759 | case 0: 3760 | break; 3761 | case 'h': 3762 | case '?': 3763 | debug_help(); 3764 | break; 3765 | default: 3766 | printf("Unknown command\n"); 3767 | break; 3768 | } 3769 | } while (cmdbuf[i] != '.'); 3770 | 3771 | /* Exit debugger */ 3772 | printf("*** Exiting debug mode ***\n"); 3773 | async_send_uint8(0x9d); 3774 | async_send_uint8(0xdd); 3775 | async_read_block(1); 3776 | } 3777 | 3778 | 3779 | static int 3780 | term_emul(void) 3781 | { 3782 | #ifdef WIN32 3783 | DWORD saved_cons_mode; 3784 | DWORD rx_cnt, tx_cnt, ev_stat, sent; 3785 | HANDLE cons_in = GetStdHandle(STD_INPUT_HANDLE); 3786 | HANDLE cons_out = GetStdHandle(STD_OUTPUT_HANDLE); 3787 | CONSOLE_CURSOR_INFO cursor_info; 3788 | CONSOLE_SCREEN_BUFFER_INFO screen_info; 3789 | COORD cursor_pos, saved_cursor_pos; 3790 | int color0, cons_color; 3791 | int rx_esc_seqn = 0; 3792 | int tx_esc_seqn = 0; 3793 | int esc_arg, esc_arg0; 3794 | int prev_char = 0; 3795 | char *keystr; 3796 | char vt100buf[20]; 3797 | #else 3798 | int rx_cnt, tx_cnt, sent; 3799 | #endif 3800 | int key_phase = 1; /* 0 .. normal; 1 .. CR; 2 .. CR + ~ */ 3801 | int c, res; 3802 | int infile = -1; 3803 | int sleep_t = 0; 3804 | char argbuf[256]; 3805 | int i; 3806 | 3807 | #ifdef WIN32 3808 | if (cable_hw == CABLE_HW_USB) { 3809 | FT_SetLatencyTimer(ftHandle, 20); 3810 | FT_SetBaudRate(ftHandle, bauds); 3811 | FT_SetDataCharacteristics(ftHandle, FT_BITS_8, FT_STOP_BITS_1, 3812 | FT_PARITY_NONE); 3813 | FT_SetFlowControl(ftHandle, FT_FLOW_NONE, 0, 0); 3814 | if (port_mode != PORT_MODE_UART) { 3815 | set_port_mode(PORT_MODE_UART); 3816 | do {} while (FT_StopInTask(ftHandle) != FT_OK); 3817 | ms_sleep(50); 3818 | FT_Purge(ftHandle, FT_PURGE_RX); 3819 | do {} while (FT_RestartInTask(ftHandle) != FT_OK); 3820 | } 3821 | } 3822 | 3823 | /* Disable CTRL-C, XON/XOFF etc. processing on console input. */ 3824 | GetConsoleMode(cons_in, &saved_cons_mode); 3825 | SetConsoleMode(cons_in, 0x40); /* ENABLE_QUICK_EDIT_MODE */ 3826 | GetConsoleScreenBufferInfo(cons_out, &screen_info); 3827 | color0 = screen_info.wAttributes; 3828 | color0 = FOREGROUND_GREEN | FOREGROUND_INTENSITY; 3829 | cursor_info.bVisible = 1; 3830 | cursor_info.dwSize = 100; 3831 | SetConsoleCursorInfo(cons_out, &cursor_info); 3832 | SetConsoleTextAttribute(cons_out, color0); 3833 | #else 3834 | if (cable_hw == CABLE_HW_USB) { 3835 | if (port_mode != PORT_MODE_UART) { 3836 | set_port_mode(PORT_MODE_UART); 3837 | ftdi_usb_purge_buffers(&fc); 3838 | } 3839 | ftdi_set_latency_timer(&fc, 20); 3840 | ftdi_set_baudrate(&fc, bauds); 3841 | ftdi_set_line_property(&fc, BITS_8, STOP_BIT_1, NONE); 3842 | ftdi_setflowctrl(&fc, SIO_DISABLE_FLOW_CTRL); 3843 | } 3844 | 3845 | /* Disable CTRL-C, XON/XOFF etc. processing on console input. */ 3846 | fcntl(0, F_SETFL, O_NONBLOCK); 3847 | system("stty -echo -isig -icanon -iexten -ixon -ixoff -icrnl"); 3848 | #endif 3849 | 3850 | printf("Terminal emulation mode, using %d bauds\n", bauds); 3851 | printf("Press ENTER, ~, ? for help\n"); 3852 | 3853 | do { 3854 | tx_cnt = 0; 3855 | if (infile > 0) { 3856 | i = bauds / 300; 3857 | if (bauds < 4800) 3858 | i = 16; 3859 | res = read(infile, txbuf, i); 3860 | if (res <= 0) { 3861 | close(infile); 3862 | infile = -1; 3863 | tx_cnt = 0; 3864 | } else 3865 | tx_cnt = res; 3866 | #ifdef WIN32 3867 | if (kbhit()) { 3868 | c = getch(); 3869 | #else 3870 | if (read(0, &c, 1) > 0) { 3871 | #endif 3872 | if (c == 3) { 3873 | close(infile); 3874 | infile = -1; 3875 | tx_cnt = 0; 3876 | printf("\nTransfer interrupted!\n\n"); 3877 | } 3878 | } 3879 | } else 3880 | #ifdef WIN32 3881 | while (kbhit()) { 3882 | c = getch(); 3883 | txbuf[tx_cnt] = c; 3884 | #else 3885 | while (read(0, &txbuf[tx_cnt], 1) > 0) { 3886 | c = txbuf[tx_cnt]; 3887 | #endif 3888 | #ifdef WIN32 3889 | /* 3890 | * Translate cursor / function keys to vt100 sequences. 3891 | */ 3892 | if (c == 224) { 3893 | tx_esc_seqn = 1; /* Cursor keys */ 3894 | continue; 3895 | } 3896 | if (c == 0) { 3897 | tx_esc_seqn = 2; /* FN keys / cygwin */ 3898 | continue; 3899 | } 3900 | if (tx_esc_seqn == 1) { 3901 | keystr = ""; 3902 | switch (c) { 3903 | case 75: /* cursor left */ 3904 | keystr = "\x1b[D"; 3905 | break; 3906 | case 77: /* cursor right */ 3907 | keystr = "\x1b[C"; 3908 | break; 3909 | case 72: /* cursor up */ 3910 | keystr = "\x1b[A"; 3911 | break; 3912 | case 80: /* cursor down */ 3913 | keystr = "\x1b[B"; 3914 | break; 3915 | case 82: /* INS */ 3916 | keystr = "\x1b[2\x7e"; 3917 | break; 3918 | case 83: /* DEL */ 3919 | keystr = "\x1b[3\x7e"; 3920 | break; 3921 | case 73: /* PgUP */ 3922 | break; 3923 | case 81: /* PgDOWN */ 3924 | break; 3925 | case 71: /* Home */ 3926 | keystr = "\x1b[H"; 3927 | break; 3928 | case 79: /* End */ 3929 | keystr = "\x1b[F"; 3930 | break; 3931 | default: 3932 | break; 3933 | } 3934 | tx_cnt += sprintf(&txbuf[tx_cnt], "%s", keystr); 3935 | tx_esc_seqn = 0; 3936 | continue; 3937 | } 3938 | if (tx_esc_seqn == 2) { 3939 | keystr = ""; 3940 | switch (c) { 3941 | case 'K': /* cursor left */ 3942 | keystr = "\x1b[D"; 3943 | break; 3944 | case 'M': /* cursor right */ 3945 | keystr = "\x1b[C"; 3946 | break; 3947 | case 'H': /* cursor up */ 3948 | keystr = "\x1b[A"; 3949 | break; 3950 | case 'P': /* cursor down */ 3951 | keystr = "\x1b[B"; 3952 | break; 3953 | case 'R': /* INS */ 3954 | keystr = "\x1b[2\x7e"; 3955 | break; 3956 | case 'S': /* DEL */ 3957 | keystr = "\x1b[3\x7e"; 3958 | break; 3959 | case 'I': /* PgUP */ 3960 | break; 3961 | case 'Q': /* PgDOWN */ 3962 | break; 3963 | case 'G': /* Home */ 3964 | keystr = "\x1b[H"; 3965 | break; 3966 | case 'O': /* End */ 3967 | keystr = "\x1b[F"; 3968 | break; 3969 | default: 3970 | break; 3971 | } 3972 | tx_cnt += sprintf(&txbuf[tx_cnt], "%s", keystr); 3973 | tx_esc_seqn = 0; 3974 | continue; 3975 | } 3976 | #endif 3977 | 3978 | /* 3979 | * Catch and process ~ escape sequences. 3980 | */ 3981 | if (key_phase == 2) { 3982 | key_phase = 1; 3983 | switch (c) { 3984 | case '?': 3985 | printf("~?\n"); 3986 | terminal_help(); 3987 | continue; 3988 | case '#': 3989 | genbrk(BREAK_MS); 3990 | continue; 3991 | case '1' ... '9': 3992 | for (c -= '0'; c > 0; c--) 3993 | genbrk(PULSE_MS); 3994 | continue; 3995 | case 'r': 3996 | reload = 1; 3997 | res = 0; 3998 | goto done; 3999 | case '.': 4000 | res = 1; 4001 | goto done; 4002 | case 'b': 4003 | printf("~>New baudrate? "); 4004 | fflush(stdout); 4005 | gets1(argbuf, sizeof(argbuf)); 4006 | c = atoi(argbuf); 4007 | if (c > 0 && 4008 | cable_hw == CABLE_HW_USB) { 4009 | #ifdef WIN32 4010 | res = FT_SetBaudRate(ftHandle, 4011 | c); 4012 | if (res == FT_OK) { 4013 | #else 4014 | res = ftdi_set_baudrate(&fc, 4015 | c); 4016 | if (res == 0) { 4017 | #endif 4018 | bauds = c; 4019 | printf("new" 4020 | " baudrate: %d\n", 4021 | bauds); 4022 | } else 4023 | printf("%d: invalid" 4024 | " baudrate\n", c); 4025 | } 4026 | continue; 4027 | case '>': 4028 | printf("~>Local file name? "); 4029 | fflush(stdout); 4030 | gets1(argbuf, sizeof(argbuf)); 4031 | infile = open(argbuf, 4032 | #ifdef WIN32 4033 | O_RDONLY | O_BINARY 4034 | #else 4035 | O_RDONLY 4036 | #endif 4037 | ); 4038 | if (infile < 0) 4039 | printf("%s: cannot open\n", 4040 | argbuf); 4041 | continue; 4042 | case 'd': 4043 | debug_cmd(); 4044 | continue; 4045 | default: 4046 | if (c != '~') { 4047 | txbuf[tx_cnt] = '~'; 4048 | tx_cnt++; 4049 | txbuf[tx_cnt] = c; 4050 | } 4051 | key_phase = 0; 4052 | break; 4053 | } 4054 | } 4055 | if (key_phase == 1 && c == '~') { 4056 | key_phase = 2; 4057 | continue; 4058 | } 4059 | if (c == 13) 4060 | key_phase = 1; 4061 | else 4062 | key_phase = 0; 4063 | tx_cnt++; 4064 | if (tx_cnt >= 16) 4065 | break; 4066 | } 4067 | if (tx_cnt) { 4068 | if (cable_hw == CABLE_HW_USB) { 4069 | #ifdef WIN32 4070 | FT_Write(ftHandle, txbuf, tx_cnt, &sent); 4071 | #else 4072 | sent = ftdi_write_data(&fc, txbuf, tx_cnt); 4073 | #endif 4074 | } else {/* cable_hw == CABLE_HW_COM */ 4075 | #ifdef WIN32 4076 | WriteFile(com_port, txbuf, tx_cnt, 4077 | (DWORD *) &sent, NULL); 4078 | #else 4079 | fcntl(com_port, F_SETFL, 0); 4080 | sent = write(com_port, txbuf, tx_cnt); 4081 | fcntl(com_port, F_SETFL, O_NONBLOCK); 4082 | #endif 4083 | } 4084 | if (sent != tx_cnt) { 4085 | res = 1; 4086 | goto done; 4087 | } 4088 | } 4089 | 4090 | #ifdef WIN32 4091 | if (cable_hw == CABLE_HW_USB) { 4092 | FT_GetStatus(ftHandle, &rx_cnt, &ev_stat, &ev_stat); 4093 | if (rx_cnt > BUFLEN_MAX) 4094 | rx_cnt = BUFLEN_MAX; 4095 | if (rx_cnt) 4096 | FT_Read(ftHandle, txbuf, rx_cnt, &rx_cnt); 4097 | } else { 4098 | rx_cnt = 32; 4099 | ReadFile(com_port, txbuf, rx_cnt, 4100 | (DWORD *) &rx_cnt, NULL); 4101 | } 4102 | #else 4103 | rx_cnt = 1; 4104 | if (cable_hw == CABLE_HW_USB) { 4105 | if (rx_cnt < (int) fc.readbuffer_remaining) 4106 | rx_cnt = fc.readbuffer_remaining; 4107 | if (rx_cnt > BUFLEN_MAX) 4108 | rx_cnt = BUFLEN_MAX; 4109 | rx_cnt = ftdi_read_data(&fc, txbuf, rx_cnt); 4110 | } else { 4111 | rx_cnt = read(com_port, txbuf, rx_cnt); 4112 | if (rx_cnt == -1) 4113 | rx_cnt = 0; 4114 | } 4115 | #endif 4116 | if (rx_cnt) { 4117 | if (rx_cnt < 0) { 4118 | res = 1; 4119 | goto done; 4120 | } 4121 | #ifdef WIN32 4122 | for (i = 0; i < rx_cnt; i++) { 4123 | c = txbuf[i]; 4124 | /* 4125 | * Interpret selected VT-100 control sequences 4126 | */ 4127 | if (c == 27) { 4128 | prev_char = c; 4129 | continue; 4130 | } 4131 | if (prev_char == 27) { 4132 | prev_char = c; 4133 | switch (c) { 4134 | case '[': 4135 | rx_esc_seqn = 1; 4136 | esc_arg = 0; 4137 | esc_arg0 = 0; 4138 | break; 4139 | case 'D': /* scroll up one line */ 4140 | SMALL_RECT rs, rd; 4141 | CHAR_INFO chi; 4142 | 4143 | GetConsoleScreenBufferInfo( 4144 | cons_out, &screen_info); 4145 | rs.Top = 0; 4146 | rs.Bottom = 4147 | screen_info.dwSize.Y - 2; 4148 | rs.Left = 0; 4149 | rs.Right = 4150 | screen_info.dwSize.X - 1; 4151 | rd.Top = 1; 4152 | rd.Bottom = 4153 | screen_info.dwSize.Y - 1; 4154 | rd.Left = 0; 4155 | rd.Right = 4156 | screen_info.dwSize.X - 1; 4157 | cursor_pos.X = 0; 4158 | cursor_pos.Y = 0; 4159 | chi.Attributes = color0; 4160 | chi.Char.AsciiChar = ' '; 4161 | ScrollConsoleScreenBuffer( 4162 | cons_out, &rs, &rd, 4163 | cursor_pos, &chi); 4164 | break; 4165 | default: 4166 | break; 4167 | } 4168 | continue; 4169 | } 4170 | if (rx_esc_seqn) { 4171 | if (c >= '0' && c <= '9') { 4172 | esc_arg = esc_arg * 10 + 4173 | c - '0'; 4174 | continue; 4175 | } 4176 | if (c == ';') { 4177 | esc_arg0 = esc_arg; 4178 | esc_arg = 0; 4179 | continue; 4180 | } 4181 | switch (c) { 4182 | case 'm': /* Set char attribute */ 4183 | cons_color = color0; 4184 | if (esc_arg == 1 || 4185 | esc_arg == 4) { 4186 | cons_color |= 4187 | FOREGROUND_RED; 4188 | } 4189 | SetConsoleTextAttribute( 4190 | cons_out, cons_color); 4191 | break; 4192 | case 'n': /* Query cursor position */ 4193 | if (esc_arg != 6) 4194 | break; 4195 | break; 4196 | GetConsoleScreenBufferInfo( 4197 | cons_out, &screen_info); 4198 | c = sprintf(vt100buf, 4199 | "\x1b[%d;%dR", 4200 | screen_info.dwCursorPosition.Y 4201 | - screen_info.srWindow.Top, 4202 | screen_info.dwCursorPosition.X 4203 | - screen_info.srWindow.Left); 4204 | FT_Write(ftHandle, vt100buf, 4205 | c, &sent); 4206 | break; 4207 | case 's': /* Save cursor position */ 4208 | GetConsoleScreenBufferInfo( 4209 | cons_out, &screen_info); 4210 | saved_cursor_pos = 4211 | screen_info.dwCursorPosition; 4212 | break; 4213 | case 'u': /* Restore cursor position */ 4214 | SetConsoleCursorPosition( 4215 | cons_out, saved_cursor_pos); 4216 | break; 4217 | case 'A': /* Cursor up */ 4218 | GetConsoleScreenBufferInfo( 4219 | cons_out, &screen_info); 4220 | cursor_pos = 4221 | screen_info.dwCursorPosition; 4222 | if (esc_arg) 4223 | cursor_pos.Y -= esc_arg; 4224 | else 4225 | cursor_pos.Y--; 4226 | SetConsoleCursorPosition( 4227 | cons_out, cursor_pos); 4228 | break; 4229 | case 'B': /* Cursor down */ 4230 | GetConsoleScreenBufferInfo( 4231 | cons_out, &screen_info); 4232 | cursor_pos = 4233 | screen_info.dwCursorPosition; 4234 | if (esc_arg) 4235 | cursor_pos.Y += esc_arg; 4236 | else 4237 | cursor_pos.Y++; 4238 | SetConsoleCursorPosition( 4239 | cons_out, cursor_pos); 4240 | break; 4241 | case 'C': /* Cursor right */ 4242 | GetConsoleScreenBufferInfo( 4243 | cons_out, &screen_info); 4244 | cursor_pos = 4245 | screen_info.dwCursorPosition; 4246 | if (esc_arg) 4247 | cursor_pos.X += esc_arg; 4248 | else 4249 | cursor_pos.X++; 4250 | SetConsoleCursorPosition( 4251 | cons_out, cursor_pos); 4252 | break; 4253 | case 'D': /* Cursor left */ 4254 | GetConsoleScreenBufferInfo( 4255 | cons_out, &screen_info); 4256 | cursor_pos = 4257 | screen_info.dwCursorPosition; 4258 | if (esc_arg) 4259 | cursor_pos.X -= esc_arg; 4260 | else 4261 | cursor_pos.X--; 4262 | SetConsoleCursorPosition( 4263 | cons_out, cursor_pos); 4264 | break; 4265 | case 'H': /* Move cursor */ 4266 | case 'f': /* Move cursor */ 4267 | GetConsoleScreenBufferInfo( 4268 | cons_out, &screen_info); 4269 | cursor_pos.X = 4270 | screen_info.srWindow.Right 4271 | - 1; 4272 | cursor_pos.Y = 4273 | screen_info.srWindow.Bottom 4274 | - 1; 4275 | if (esc_arg0 < cursor_pos.X) 4276 | cursor_pos.X = esc_arg0; 4277 | if (esc_arg < cursor_pos.Y) 4278 | cursor_pos.Y = esc_arg; 4279 | SetConsoleCursorPosition( 4280 | cons_out, cursor_pos); 4281 | break; 4282 | case 'J': /* Clear screen */ 4283 | GetConsoleScreenBufferInfo( 4284 | cons_out, &screen_info); 4285 | cursor_pos.X = 4286 | screen_info.srWindow.Left; 4287 | cursor_pos.Y = 4288 | screen_info.srWindow.Top; 4289 | FillConsoleOutputCharacter( 4290 | cons_out, ' ', 4291 | (screen_info.srWindow.Bottom 4292 | - screen_info.srWindow.Top) * 4293 | (screen_info.srWindow.Right 4294 | - screen_info.srWindow.Left), 4295 | cursor_pos, &sent); 4296 | SetConsoleCursorPosition( 4297 | cons_out, cursor_pos); 4298 | break; 4299 | case 'K': /* Erase to end of line */ 4300 | GetConsoleScreenBufferInfo( 4301 | cons_out, &screen_info); 4302 | cursor_pos = 4303 | screen_info.dwCursorPosition; 4304 | FillConsoleOutputCharacter( 4305 | cons_out, ' ', 4306 | screen_info.srWindow.Right 4307 | - cursor_pos.X, 4308 | cursor_pos, &sent); 4309 | SetConsoleCursorPosition( 4310 | cons_out, cursor_pos); 4311 | break; 4312 | default: 4313 | break; 4314 | } 4315 | rx_esc_seqn = 0; 4316 | continue; 4317 | } 4318 | rx_esc_seqn = 0; 4319 | fwrite(&c, 1, 1, stdout); 4320 | } 4321 | #else 4322 | fwrite(txbuf, 1, rx_cnt, stdout); 4323 | #endif 4324 | fflush(stdout); 4325 | } 4326 | if (tx_cnt == 0 && rx_cnt == 0) { 4327 | ms_sleep(sleep_t); 4328 | if (sleep_t < 5) 4329 | sleep_t++; 4330 | } else 4331 | sleep_t = 0; 4332 | } while (1); 4333 | 4334 | done: 4335 | printf("\n"); 4336 | 4337 | /* Restore special key processing on console input. */ 4338 | #ifdef WIN32 4339 | SetConsoleMode(cons_in, saved_cons_mode); 4340 | cursor_info.bVisible = 1; 4341 | cursor_info.dwSize = 20; 4342 | SetConsoleCursorInfo(cons_out, &cursor_info); 4343 | FT_SetLatencyTimer(ftHandle, 1); 4344 | FT_SetBaudRate(ftHandle, USB_BAUDS); 4345 | #else 4346 | system("stty echo isig icanon iexten ixon ixoff icrnl"); 4347 | ftdi_set_latency_timer(&fc, 1); 4348 | ftdi_set_baudrate(&fc, USB_BAUDS); 4349 | #endif 4350 | 4351 | return (res); 4352 | } 4353 | 4354 | 4355 | int 4356 | main(int argc, char *argv[]) 4357 | { 4358 | int res = EXIT_FAILURE; 4359 | int jed_target = JED_TGT_SRAM; 4360 | int debug = 0; 4361 | int c; 4362 | #ifdef WIN32 4363 | int had_terminal = 0; 4364 | COMMTIMEOUTS com_to; 4365 | #endif 4366 | 4367 | #if defined(USE_PPI) || defined(USE_RAW) 4368 | #define OPTS "qtdj:b:p:x:p:P:a:e:f:D:rs:C:c:" 4369 | #else 4370 | #define OPTS "qtdj:b:p:x:p:P:a:e:f:D:rs:C:" 4371 | #endif 4372 | while ((c = getopt(argc, argv, OPTS)) != -1) { 4373 | switch (c) { 4374 | case 'a': 4375 | txfname = optarg; 4376 | tx_binary = 0; 4377 | break; 4378 | case 'b': 4379 | bauds = atoi(optarg); 4380 | break; 4381 | case 'x': 4382 | xbauds = atoi(optarg); 4383 | break; 4384 | #if defined(USE_PPI) || defined(USE_RAW) 4385 | case 'c': 4386 | if (strcasecmp(optarg, "usb") == 0) 4387 | cable_hw = CABLE_HW_USB; 4388 | else if (strcasecmp(optarg, "ppi") == 0) 4389 | cable_hw = CABLE_HW_PPI; 4390 | else if (strcasecmp(optarg, "raw") == 0) 4391 | cable_hw = CABLE_RAW; 4392 | else { 4393 | usage(); 4394 | exit(EXIT_FAILURE); 4395 | } 4396 | break; 4397 | #endif 4398 | case 'C': 4399 | cbusval = strtol(optarg, NULL, 0); 4400 | if (cbusval < 0 || cbusval > 0xf) { 4401 | fprintf(stderr, "CBUS value %d " 4402 | "out of range 0..15\n", cbusval); 4403 | exit(EXIT_FAILURE); 4404 | } 4405 | cbusval |= 0xf0; 4406 | break; 4407 | case 'd': 4408 | debug = 1; 4409 | global_debug = 1; 4410 | break; 4411 | case 'D': 4412 | txfu_ms = atoi(optarg); 4413 | break; 4414 | case 'e': 4415 | txfname = optarg; 4416 | tx_binary = 1; 4417 | break; 4418 | case 'j': 4419 | if (strcasecmp(optarg, "sram") == 0) 4420 | jed_target = JED_TGT_SRAM; 4421 | else if (strcasecmp(optarg, "flash") == 0) 4422 | jed_target = JED_TGT_FLASH; 4423 | else { 4424 | usage(); 4425 | exit(EXIT_FAILURE); 4426 | } 4427 | break; 4428 | case 'f': 4429 | if (optarg[0] == '0' && optarg[1] == 'x') 4430 | sscanf(&optarg[2], "%x", &spi_addr); 4431 | else if (isdigit(*optarg)) 4432 | spi_addr = atoi(optarg); 4433 | else { 4434 | printf("Invalid address format\n"); 4435 | exit(EXIT_FAILURE); 4436 | } 4437 | if ((spi_addr & (SPI_SECTOR_SIZE - 1)) != 0) { 4438 | printf("SPI address must be a multiple of %d\n", 4439 | SPI_SECTOR_SIZE); 4440 | exit(EXIT_FAILURE); 4441 | } 4442 | break; 4443 | case 'p': 4444 | port_index = atoi(optarg); 4445 | break; 4446 | case 'P': 4447 | com_name = optarg; 4448 | cable_hw = CABLE_HW_COM; 4449 | break; 4450 | case 'q': 4451 | quiet = 1; 4452 | break; 4453 | case 'r': 4454 | reload = 1; 4455 | break; 4456 | case 's': 4457 | svf_name = optarg; 4458 | break; 4459 | case 't': 4460 | terminal = 1; 4461 | #ifdef WIN32 4462 | had_terminal = 1; 4463 | #endif 4464 | break; 4465 | case '?': 4466 | default: 4467 | usage(); 4468 | exit(EXIT_FAILURE); 4469 | } 4470 | } 4471 | argc -= optind; 4472 | argv += optind; 4473 | 4474 | if (!quiet) 4475 | printf("%s (built %s %s)\n", verstr, __DATE__, __TIME__); 4476 | 4477 | if (svf_name) { 4478 | if (terminal || reload || txfname || com_name || argc == 0) { 4479 | usage(); 4480 | exit(EXIT_FAILURE); 4481 | } 4482 | res = exec_bit_file(argv[0], jed_target, debug); 4483 | return(res); 4484 | } 4485 | 4486 | if (argc == 0 && terminal == 0 && txfname == NULL && reload == 0 4487 | && cbusval < 0) { 4488 | usage(); 4489 | exit(EXIT_FAILURE); 4490 | } 4491 | 4492 | if (com_name && terminal == 0 && txfname == NULL && reload == 0) { 4493 | fprintf(stderr, "error: " 4494 | "option -P must be used with -r, -t or -a\n"); 4495 | exit(EXIT_FAILURE); 4496 | } 4497 | 4498 | if (com_name && cable_hw != CABLE_HW_COM) { 4499 | fprintf(stderr, "error: " 4500 | "options -P and -c are mutualy exclusive\n"); 4501 | exit(EXIT_FAILURE); 4502 | } 4503 | 4504 | if (spi_addr && jed_target != JED_TGT_FLASH) { 4505 | fprintf(stderr, "error: " 4506 | "-f may be specified only with -j flash\n"); 4507 | exit(EXIT_FAILURE); 4508 | } 4509 | 4510 | switch (cable_hw) { 4511 | case CABLE_UNKNOWN: 4512 | case CABLE_HW_USB: 4513 | res = setup_usb(); 4514 | if (res == 0) 4515 | cable_hw = CABLE_HW_USB; 4516 | if (cable_hw == CABLE_HW_USB) { 4517 | if (xbauds == 0) 4518 | xbauds = 3000000; 4519 | break; 4520 | } 4521 | #ifdef USE_PPI 4522 | case CABLE_HW_PPI: 4523 | res = setup_ppi(); 4524 | #endif 4525 | break; 4526 | #ifdef USE_RAW 4527 | case CABLE_RAW: 4528 | res = setup_raw(); 4529 | break; 4530 | #endif 4531 | case CABLE_HW_COM: 4532 | if (xbauds == 0) 4533 | xbauds = bauds; 4534 | #ifdef WIN32 4535 | sprintf(txbuf, "\\\\.\\%s", com_name); 4536 | com_port = CreateFile(txbuf, GENERIC_READ | GENERIC_WRITE, 4537 | 0, NULL, OPEN_EXISTING, 0, NULL); 4538 | if (com_port == INVALID_HANDLE_VALUE) { 4539 | fprintf(stderr, "Can't open %s\n", com_name); 4540 | exit(EXIT_FAILURE); 4541 | } 4542 | async_set_baudrate(bauds); 4543 | if (GetCommTimeouts(com_port, &com_to) == 0) { 4544 | fprintf(stderr, "Can't configure %s\n", com_port); 4545 | exit(EXIT_FAILURE); 4546 | } 4547 | com_to.ReadIntervalTimeout = 1; 4548 | com_to.ReadTotalTimeoutConstant = 1; 4549 | com_to.ReadTotalTimeoutMultiplier = 1; 4550 | SetCommTimeouts(com_port, &com_to); 4551 | res = 0; 4552 | #else 4553 | com_port = open(com_name, O_RDWR); 4554 | if (com_port < 0 || tcgetattr(com_port, &tty)) { 4555 | fprintf(stderr, "Can't open %s\n", com_name); 4556 | exit(EXIT_FAILURE); 4557 | } 4558 | tty.c_cflag &= ~(CSIZE|PARENB); 4559 | tty.c_cflag |= CS8; 4560 | tty.c_cflag |= CLOCAL; 4561 | tty.c_cflag &= ~CRTSCTS; 4562 | tty.c_iflag &= ~(ISTRIP|ICRNL); 4563 | tty.c_iflag &= ~(IXON|IXOFF); 4564 | tty.c_oflag &= ~OPOST; 4565 | tty.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO); 4566 | tty.c_cc[VMIN] = 1; 4567 | tty.c_cc[VTIME] = 0; 4568 | async_set_baudrate(bauds); 4569 | res = fcntl(com_port, F_SETFL, O_NONBLOCK); 4570 | #if defined(__FreeBSD__) || defined(__linux__) 4571 | /* XXX w/o this a BREAK won't be sent properly on FreeBSD ?!?*/ 4572 | ms_sleep(300); 4573 | #endif 4574 | #endif /* !WIN32 */ 4575 | default: 4576 | /* can't happen, shut up gcc warnings */ 4577 | break; 4578 | } 4579 | 4580 | if (res) { 4581 | fprintf(stderr, "Cannot find JTAG cable.\n"); 4582 | exit(EXIT_FAILURE); 4583 | } 4584 | 4585 | 4586 | if (cbusval >= 0) { 4587 | #ifdef WIN32 4588 | res = FT_SetBitMode(ftHandle, 4589 | #else 4590 | res = ftdi_set_bitmode(&fc, 4591 | #endif 4592 | cbusval, BITMODE_CBUS); 4593 | if (res != 0) { 4594 | fprintf(stderr, "CBUS config failed.\n"); 4595 | exit(EXIT_FAILURE); 4596 | } 4597 | } 4598 | 4599 | if (!quiet && cable_hw != CABLE_HW_COM) { 4600 | #ifndef WIN32 4601 | if (cable_hw == CABLE_HW_USB) 4602 | printf("Using USB cable: %s\n", hmp->cable_path); 4603 | #ifdef USE_PPI 4604 | else if (cable_hw == CABLE_RAW) { 4605 | printf("Generating %s\n", hmp->cable_path); 4606 | } 4607 | #endif 4608 | else 4609 | #ifdef USE_PPI 4610 | printf("Using parallel port JTAG cable.\n"); 4611 | #else 4612 | printf("Parallel port JTAG cable not supported!\n"); 4613 | #endif 4614 | #endif /* !WIN32 */ 4615 | } 4616 | 4617 | do { 4618 | if (reload) { 4619 | set_port_mode(PORT_MODE_UART); 4620 | async_set_baudrate(bauds); 4621 | genbrk(BREAK_MS); 4622 | reload = 0; 4623 | } 4624 | if (argc) 4625 | prog(argv[0], jed_target, debug); 4626 | jed_target = JED_TGT_SRAM; /* for subsequent prog() calls */ 4627 | if (txfname) 4628 | txfile(); 4629 | } while (terminal && term_emul() == 0); 4630 | 4631 | #ifdef WIN32 4632 | if (had_terminal) 4633 | system("color"); 4634 | #endif 4635 | 4636 | if (cable_hw == CABLE_HW_COM) { 4637 | #ifdef WIN32 4638 | CloseHandle(com_port); 4639 | #else 4640 | close(com_port); 4641 | #endif 4642 | } else if (cable_hw == CABLE_HW_USB) { 4643 | ms_sleep(1); // small delay for f32c to start 4644 | shutdown_usb(); 4645 | } 4646 | #ifdef USE_RAW 4647 | else if (cable_hw == CABLE_RAW) 4648 | shutdown_raw(); 4649 | #endif 4650 | #ifdef USE_PPI 4651 | else 4652 | shutdown_ppi(); 4653 | #endif 4654 | 4655 | return (res); 4656 | } 4657 | --------------------------------------------------------------------------------