├── .gitignore ├── wifi.h ├── events.cpp ├── data ├── ace.js.gz ├── favicon.ico ├── mode-css.js.gz ├── mode-html.js.gz ├── worker-html.js.gz ├── ext-searchbox.js.gz ├── mode-javascript.js.gz └── index.htm ├── events.h ├── tools ├── __pycache__ │ └── commands.cpython-38.pyc ├── setwificonfig.py ├── commands.py ├── upload.py └── uploadwifi.py ├── webserver.h ├── storage.h ├── netlog.h ├── program.h ├── README.md ├── programmer.h ├── esp32-rjtag.ino ├── src └── libxsvf │ ├── COPYING │ ├── statename.c │ ├── scan.c │ ├── play.c │ ├── memname.c │ ├── Makefile │ ├── tap.c │ ├── libxsvf.h │ ├── xsvftool-esp.c │ ├── xsvftool-gpio.c │ ├── README │ ├── xsvf.c │ └── svf.c ├── wifi.cpp ├── program.cpp ├── storage.cpp ├── programmer.cpp ├── webserver.cpp └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | *.svf 2 | *.pyc 3 | -------------------------------------------------------------------------------- /wifi.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void SetupWiFi(); 4 | bool InOTA(); 5 | -------------------------------------------------------------------------------- /events.cpp: -------------------------------------------------------------------------------- 1 | #include "events.h" 2 | 3 | AsyncWebSocket websocket("/ws"); 4 | -------------------------------------------------------------------------------- /data/ace.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/racerxdl/esp32-rjtag/HEAD/data/ace.js.gz -------------------------------------------------------------------------------- /data/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/racerxdl/esp32-rjtag/HEAD/data/favicon.ico -------------------------------------------------------------------------------- /data/mode-css.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/racerxdl/esp32-rjtag/HEAD/data/mode-css.js.gz -------------------------------------------------------------------------------- /data/mode-html.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/racerxdl/esp32-rjtag/HEAD/data/mode-html.js.gz -------------------------------------------------------------------------------- /data/worker-html.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/racerxdl/esp32-rjtag/HEAD/data/worker-html.js.gz -------------------------------------------------------------------------------- /data/ext-searchbox.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/racerxdl/esp32-rjtag/HEAD/data/ext-searchbox.js.gz -------------------------------------------------------------------------------- /data/mode-javascript.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/racerxdl/esp32-rjtag/HEAD/data/mode-javascript.js.gz -------------------------------------------------------------------------------- /events.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | extern AsyncWebSocket websocket; 6 | -------------------------------------------------------------------------------- /tools/__pycache__/commands.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/racerxdl/esp32-rjtag/HEAD/tools/__pycache__/commands.cpython-38.pyc -------------------------------------------------------------------------------- /webserver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | void InitWebServer(); 6 | void WebServerLoop(); 7 | uint8_t isWifiProgramming(); -------------------------------------------------------------------------------- /storage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Arduino.h" 4 | 5 | String GetWifiSSID(); 6 | String GetWifiPassword(); 7 | String GetHostname(); 8 | String GetOTAPassword(); 9 | 10 | void SaveWifiSSID(String ssid); 11 | void SaveWifiPassword(String pass); 12 | void SaveHostname(String hostname); 13 | void SaveOTAPassword(String password); 14 | 15 | void InitStorage(); -------------------------------------------------------------------------------- /netlog.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "events.h" 3 | 4 | template void Info(const char * fmt, Args... args) { 5 | websocket.printfAll(fmt, args...); 6 | Serial.printf(fmt, args...); 7 | } 8 | 9 | template void Debug(const char * fmt, Args... args) { 10 | // websocket.printfAll(fmt, args...); 11 | // Serial.printf(fmt, args...); 12 | } 13 | 14 | template void Error(const char * fmt, Args... args) { 15 | websocket.printfAll(fmt, args...); 16 | Serial.printf(fmt, args...); 17 | } 18 | 19 | -------------------------------------------------------------------------------- /program.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #define BUFFER_SIZE 4 * 1024 6 | 7 | #define DATA_TYPE_SVF 0 8 | #define DATA_TYPE_XSVF 1 9 | 10 | #define MODE_SERIAL 0 11 | #define MODE_WIFI 1 12 | 13 | // External function to fetch next block to play 14 | extern int fetch_next_block(uint8_t *buffer, int length); 15 | extern int fetch_next_block_wifi(uint8_t *buffer, int length); 16 | 17 | int jtag_program(int dataType, uint8_t mode); 18 | void set_pins(uint8_t tdi, uint8_t tdo, uint8_t tck, uint8_t tms, uint8_t led); 19 | uint32_t jtag_chip_id(); 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ESP32 Remote JTAG 2 | ================= 3 | 4 | WIP 5 | 6 | 7 | Everything here is licensed at Apache (see LICENSE) except for libxsvf which is done by Clifford Wolf and licensed under ISC License (See src/libxsvf/COPYING) and `data` folder which for now is LGPL. The original library is at [http://www.clifford.at/libxsvf/](http://www.clifford.at/libxsvf/) and I modified a little to work with ESP32. 8 | 9 | The `upload.py` program can upload SVF files to ESP32 through serial port and `uploadwifi.py` to upload through wireless network. 10 | 11 | ```bash 12 | python3 uploadwifi.py [IP] [SVF FILE] 13 | ``` -------------------------------------------------------------------------------- /programmer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define PIN_TDI 33 4 | #define PIN_TDO 32 5 | #define PIN_TCK 27 6 | #define PIN_TMS 26 7 | #define PIN_LED 2 8 | 9 | #define CMD_DATA 'd' 10 | #define CMD_SET_HOSTNAME 'h' 11 | #define CMD_START_SVF 'i' 12 | #define CMD_SET_WIFI_PASS 'l' 13 | #define CMD_SET_OTA_PASS 'o' 14 | #define CMD_PASSTHROUGH 'p' 15 | #define CMD_QUERY 'q' 16 | #define CMD_REBOOT 'r' 17 | #define CMD_STOP 's' 18 | #define CMD_SET_WIFI_SSID 'u' 19 | #define CMD_START_XSVF 'x' 20 | #define CMD_GET_STATE 'g' 21 | 22 | void ProgrammerLoop(); 23 | void ProgrammerInit(); 24 | -------------------------------------------------------------------------------- /esp32-rjtag.ino: -------------------------------------------------------------------------------- 1 | // #define DEBUG 2 | 3 | #define BAUD_RATE 921600 4 | 5 | #include 6 | #include "storage.h" 7 | #include "programmer.h" 8 | #include "wifi.h" 9 | #include "webserver.h" 10 | 11 | void setup() { 12 | Serial.begin(BAUD_RATE); 13 | delay(1000); 14 | Serial.println("[START]"); 15 | InitStorage(); 16 | SetupWiFi(); 17 | ProgrammerInit(); 18 | InitWebServer(); 19 | 20 | Serial.println("[RDY]"); 21 | } 22 | 23 | 24 | void loop() { 25 | ArduinoOTA.handle(); 26 | ProgrammerLoop(); 27 | if (isWifiProgramming()) { 28 | delay(1000); // Give enough time to programmer work 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/libxsvf/COPYING: -------------------------------------------------------------------------------- 1 | 2 | Lib(X)SVF - A library for implementing SVF and XSVF JTAG players 3 | 4 | Copyright (C) 2009 RIEGL Research ForschungsGmbH 5 | Copyright (C) 2009 Clifford Wolf 6 | 7 | Permission to use, copy, modify, and/or distribute this software for any 8 | purpose with or without fee is hereby granted, provided that the above 9 | copyright notice and this permission notice appear in all copies. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | 19 | -------------------------------------------------------------------------------- /tools/setwificonfig.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import serial, time, struct, os, sys 4 | from commands import * 5 | 6 | device = "/dev/ttyUSB0" 7 | baudrate = 921600 8 | 9 | if len(sys.argv) < 6: 10 | print("Usage: setwificonfig.py /dev/ttyUSB0 WIFI_SSID WIFI_PASSWORD OTA_PASSWORD [hostname]") 11 | exit(1) 12 | 13 | usbport = sys.argv[1] 14 | wifissid = sys.argv[2] 15 | wifipass = sys.argv[3] 16 | otapass = sys.argv[4] 17 | hostname = None 18 | 19 | if len(sys.argv) >= 6: 20 | hostname = sys.argv[5] 21 | 22 | print("[HOST] Connecting to %s at %d" %(usbport, baudrate)) 23 | ser = serial.Serial(usbport, baudrate, timeout=1, xonxoff=0, rtscts=0) # open serial port 24 | 25 | print("[HOST] Resetting") 26 | ser.setDTR(False) 27 | time.sleep(0.1) 28 | ser.flushInput() 29 | ser.setDTR(True) 30 | 31 | offset = 0 32 | 33 | 34 | print("[HOST] Waiting ESP32 to be ready") 35 | while True: 36 | try: 37 | line = ser.readline().decode("utf-8", errors="ignore") 38 | if "[RDY]" in line: 39 | if hostname != None: 40 | SetHostname(ser, hostname) 41 | SetWifiSSID(ser, wifissid) 42 | SetWifiPassword(ser, wifipass) 43 | SetOTAPassword(ser, otapass) 44 | Reboot(ser) 45 | break 46 | except UnicodeDecodeError as e: 47 | print(e) 48 | continue 49 | except Exception as e: 50 | raise e 51 | break 52 | 53 | ser.close() # close port 54 | -------------------------------------------------------------------------------- /tools/commands.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import struct 4 | 5 | CMD_DATA = 'd' 6 | CMD_SET_HOSTNAME = 'h' 7 | CMD_START_SVF = 'i' 8 | CMD_SET_WIFI_PASS = 'l' 9 | CMD_SET_OTA_PASS = 'o' 10 | CMD_PASSTHROUGH = 'p' 11 | CMD_QUERY = 'q' 12 | CMD_REBOOT = 'r' 13 | CMD_STOP = 's' 14 | CMD_SET_WIFI_SSID = 'u' 15 | CMD_START_XSVF = 'x' 16 | 17 | 18 | def __sendStringCMD(ser, cmd, data): 19 | l = len(data) 20 | packet = struct.pack(">BI", ord(cmd), l) + bytearray(data, encoding="utf8") 21 | ser.write(packet) 22 | 23 | def SetHostname(ser, name): 24 | ''' 25 | Sets the ESP32-RJTAG Hostname 26 | ''' 27 | __sendStringCMD(ser, CMD_SET_HOSTNAME, name) 28 | print(ser.readline().decode("utf-8", errors="ignore").strip()) 29 | 30 | def SetWifiSSID(ser, ssid): 31 | ''' 32 | Sets the ESP32-RJTAG Wifi SSID 33 | ''' 34 | __sendStringCMD(ser, CMD_SET_WIFI_SSID, ssid) 35 | print(ser.readline().decode("utf-8", errors="ignore").strip()) 36 | 37 | 38 | def SetWifiPassword(ser, password): 39 | ''' 40 | Sets the ESP32-RJTAG Wifi Password 41 | ''' 42 | __sendStringCMD(ser, CMD_SET_WIFI_PASS, password) 43 | print(ser.readline().decode("utf-8", errors="ignore").strip()) 44 | 45 | 46 | def SetOTAPassword(ser, password): 47 | ''' 48 | Sets the ESP32-RJTAG Over-The-Air Update Password 49 | ''' 50 | __sendStringCMD(ser, CMD_SET_OTA_PASS, password) 51 | print(ser.readline().decode("utf-8", errors="ignore").strip()) 52 | 53 | 54 | def Reboot(ser): 55 | __sendStringCMD(ser, CMD_REBOOT, "") 56 | print(ser.readline().decode("utf-8", errors="ignore").strip()) 57 | 58 | -------------------------------------------------------------------------------- /src/libxsvf/statename.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Lib(X)SVF - A library for implementing SVF and XSVF JTAG players 3 | * 4 | * Copyright (C) 2009 RIEGL Research ForschungsGmbH 5 | * Copyright (C) 2009 Clifford Wolf 6 | * 7 | * Permission to use, copy, modify, and/or distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | * 19 | */ 20 | 21 | #include "libxsvf.h" 22 | 23 | const char *libxsvf_state2str(enum libxsvf_tap_state tap_state) 24 | { 25 | #define X(_s) if (tap_state == _s) return #_s; 26 | X(LIBXSVF_TAP_INIT) 27 | X(LIBXSVF_TAP_RESET) 28 | X(LIBXSVF_TAP_IDLE) 29 | X(LIBXSVF_TAP_DRSELECT) 30 | X(LIBXSVF_TAP_DRCAPTURE) 31 | X(LIBXSVF_TAP_DRSHIFT) 32 | X(LIBXSVF_TAP_DREXIT1) 33 | X(LIBXSVF_TAP_DRPAUSE) 34 | X(LIBXSVF_TAP_DREXIT2) 35 | X(LIBXSVF_TAP_DRUPDATE) 36 | X(LIBXSVF_TAP_IRSELECT) 37 | X(LIBXSVF_TAP_IRCAPTURE) 38 | X(LIBXSVF_TAP_IRSHIFT) 39 | X(LIBXSVF_TAP_IREXIT1) 40 | X(LIBXSVF_TAP_IRPAUSE) 41 | X(LIBXSVF_TAP_IREXIT2) 42 | X(LIBXSVF_TAP_IRUPDATE) 43 | #undef X 44 | return "UNKOWN_STATE"; 45 | } 46 | 47 | -------------------------------------------------------------------------------- /src/libxsvf/scan.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Lib(X)SVF - A library for implementing SVF and XSVF JTAG players 3 | * 4 | * Copyright (C) 2009 RIEGL Research ForschungsGmbH 5 | * Copyright (C) 2009 Clifford Wolf 6 | * 7 | * Permission to use, copy, modify, and/or distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | * 19 | */ 20 | 21 | #include "libxsvf.h" 22 | 23 | int libxsvf_scan(struct libxsvf_host *h) 24 | { 25 | int i, j; 26 | 27 | if (libxsvf_tap_walk(h, LIBXSVF_TAP_RESET) < 0) 28 | return -1; 29 | 30 | if (libxsvf_tap_walk(h, LIBXSVF_TAP_DRSHIFT) < 0) 31 | return -1; 32 | 33 | for (i=0; i<256; i++) 34 | { 35 | int bit = LIBXSVF_HOST_PULSE_TCK(0, 1, -1, 0, 1); 36 | 37 | if (bit < 0) 38 | return -1; 39 | 40 | if (bit == 0) { 41 | // LIBXSVF_HOST_REPORT_DEVICE(0); 42 | } else { 43 | unsigned long idcode = 1; 44 | for (j=1; j<32; j++) { 45 | int bit = LIBXSVF_HOST_PULSE_TCK(0, 1, -1, 0, 1); 46 | if (bit < 0) 47 | return -1; 48 | idcode |= ((unsigned long)bit) << j; 49 | } 50 | if (idcode == 0xffffffff) 51 | break; 52 | LIBXSVF_HOST_REPORT_DEVICE(idcode); 53 | } 54 | } 55 | 56 | return 0; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /src/libxsvf/play.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Lib(X)SVF - A library for implementing SVF and XSVF JTAG players 3 | * 4 | * Copyright (C) 2009 RIEGL Research ForschungsGmbH 5 | * Copyright (C) 2009 Clifford Wolf 6 | * 7 | * Permission to use, copy, modify, and/or distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | * 19 | */ 20 | 21 | #include "libxsvf.h" 22 | 23 | int libxsvf_play(struct libxsvf_host *h, enum libxsvf_mode mode) 24 | { 25 | int rc = -1; 26 | 27 | h->tap_state = LIBXSVF_TAP_INIT; 28 | if (LIBXSVF_HOST_SETUP() < 0) { 29 | LIBXSVF_HOST_REPORT_ERROR("Setup of JTAG interface failed."); 30 | return -1; 31 | } 32 | 33 | if (mode == LIBXSVF_MODE_SVF) { 34 | #ifdef LIBXSVF_WITHOUT_SVF 35 | LIBXSVF_HOST_REPORT_ERROR("SVF support in libxsvf is disabled."); 36 | #else 37 | rc = libxsvf_svf(h); 38 | #endif 39 | } 40 | 41 | if (mode == LIBXSVF_MODE_XSVF) { 42 | #ifdef LIBXSVF_WITHOUT_XSVF 43 | LIBXSVF_HOST_REPORT_ERROR("XSVF support in libxsvf is disabled."); 44 | #else 45 | rc = libxsvf_xsvf(h); 46 | #endif 47 | } 48 | 49 | if (mode == LIBXSVF_MODE_SCAN) { 50 | #ifdef LIBXSVF_WITHOUT_SCAN 51 | LIBXSVF_HOST_REPORT_ERROR("SCAN support in libxsvf is disabled."); 52 | #else 53 | rc = libxsvf_scan(h); 54 | #endif 55 | } 56 | 57 | libxsvf_tap_walk(h, LIBXSVF_TAP_RESET); 58 | if (LIBXSVF_HOST_SYNC() != 0 && rc >= 0 ) { 59 | LIBXSVF_HOST_REPORT_ERROR("TDO mismatch in TAP reset. (this is not possible!)"); 60 | rc = -1; 61 | } 62 | 63 | int shutdown_rc = LIBXSVF_HOST_SHUTDOWN(); 64 | 65 | if (shutdown_rc < 0) { 66 | LIBXSVF_HOST_REPORT_ERROR("Shutdown of JTAG interface failed."); 67 | rc = rc < 0 ? rc : shutdown_rc; 68 | } 69 | 70 | return rc; 71 | } 72 | 73 | -------------------------------------------------------------------------------- /wifi.cpp: -------------------------------------------------------------------------------- 1 | #include "Arduino.h" 2 | #include "ArduinoOTA.h" 3 | #include "WiFi.h" 4 | #include "wifi.h" 5 | #include "storage.h" 6 | 7 | String ssid = ""; 8 | String password = ""; 9 | String otaPassword = ""; 10 | String hostname = ""; 11 | 12 | bool inOTA = false; 13 | 14 | void SetupWiFi() { 15 | ssid = GetWifiSSID(); 16 | password = GetWifiPassword(); 17 | hostname = GetHostname(); 18 | inOTA = false; 19 | Serial.println("[INFO] Setting up WiFi"); 20 | Serial.print("[INFO] SSID: "); 21 | Serial.println(ssid); 22 | 23 | if (WiFi.getMode() != WIFI_STA) { 24 | WiFi.mode(WIFI_STA); 25 | delay(10); 26 | } 27 | 28 | if (WiFi.SSID() != ssid || WiFi.psk() != password) { 29 | Serial.println("[INFO] WiFi config changed."); 30 | // ... Try to connect to WiFi station. 31 | WiFi.begin(ssid.c_str(), password.c_str()); 32 | } else { 33 | WiFi.begin(); 34 | } 35 | 36 | WiFi.setHostname(hostname.c_str()); 37 | 38 | unsigned long startTime = millis(); 39 | while (WiFi.status() != WL_CONNECTED && millis() - startTime < 10000) { 40 | delay(100); 41 | yield(); 42 | } 43 | 44 | // Check connection 45 | if (WiFi.status() == WL_CONNECTED) { 46 | // ... print IP Address 47 | Serial.print("[INFO] IP address: "); 48 | Serial.println(WiFi.localIP()); 49 | } else { 50 | Serial.println("[INFO] Can not connect to WiFi station. Configure using CLI"); 51 | } 52 | 53 | // Start OTA server. 54 | ArduinoOTA.setHostname((const char *)hostname.c_str()); 55 | 56 | ArduinoOTA.onStart([]() { 57 | inOTA = true; 58 | Serial.println("[INFO] OTA Update Start"); 59 | }); 60 | 61 | ArduinoOTA.onEnd([]() { 62 | Serial.println("[INFO] OTA Update End"); 63 | }); 64 | 65 | ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { 66 | String progressStr; 67 | progressStr = String((progress / (total / 100))) + String("%"); 68 | Serial.print("[INFO] Progress: "); 69 | Serial.println(progressStr); 70 | }); 71 | 72 | ArduinoOTA.onError([](ota_error_t error) { 73 | Serial.printf("[ERROR] %u: ", error); 74 | if (error == OTA_AUTH_ERROR) Serial.println("Auth failed"); 75 | else if (error == OTA_BEGIN_ERROR) Serial.println("Start Failed"); 76 | else if (error == OTA_CONNECT_ERROR) Serial.println("Connection failed"); 77 | else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Error"); 78 | else if (error == OTA_END_ERROR) Serial.println("End Fail"); 79 | }); 80 | 81 | ArduinoOTA.begin(); 82 | } -------------------------------------------------------------------------------- /program.cpp: -------------------------------------------------------------------------------- 1 | #include "program.h" 2 | #include 3 | #include 4 | #include "netlog.h" 5 | 6 | uint8_t codeBuffer[BUFFER_SIZE]; 7 | 8 | extern "C" { 9 | int xsvftool_esp_scan (void); 10 | uint32_t xsvftool_esp_id (void); 11 | int xsvftool_esp_program (int (*file_getbyte)(), int x); 12 | int xsvftool_esp_svf_packet (int (*packet_getbyte)(), int index, int final, char *report); 13 | void xsvftool_esp_set_pins (uint8_t tdi, uint8_t tdo, uint8_t tck, uint8_t tms); 14 | } 15 | 16 | uint8_t ledpin = 2; 17 | 18 | struct buffer_state { 19 | int count; // how many bytes in buffer 20 | int ptr; // current reading pointer 21 | uint8_t blink; // for the LED 22 | uint8_t mode; 23 | } rd; 24 | 25 | int get_next_byte() { 26 | if(rd.ptr >= rd.count) { 27 | // refill the buffer and update content 28 | rd.ptr = 0; 29 | 30 | if (rd.mode == MODE_SERIAL) { 31 | rd.count = fetch_next_block(codeBuffer, BUFFER_SIZE); 32 | } else { 33 | rd.count = fetch_next_block_wifi(codeBuffer, BUFFER_SIZE); 34 | } 35 | 36 | if(rd.count <= 0 || rd.count > BUFFER_SIZE) { 37 | return -1; 38 | } 39 | 40 | digitalWrite(ledpin, (rd.blink++) & 1); 41 | } 42 | 43 | return codeBuffer[rd.ptr++]; 44 | } 45 | 46 | uint32_t jtag_chip_id() { 47 | xsvftool_esp_scan(); 48 | return xsvftool_esp_id(); 49 | } 50 | 51 | int jtag_program(int dataType, uint8_t mode) { 52 | int retval = -1; 53 | if (dataType != DATA_TYPE_SVF && dataType != DATA_TYPE_XSVF) { 54 | Error("[JTAG] Invalid data type\r\n"); 55 | return retval; 56 | } 57 | 58 | uint32_t chipId = xsvftool_esp_id(); 59 | 60 | if (!chipId) { 61 | Error("[JTAG] No devices found!\r\n"); 62 | return retval; 63 | } 64 | 65 | Info("[JTAG] Found device %08x\r\n", chipId); 66 | Info("[JTAG] Waiting first block\r\n"); 67 | 68 | rd.ptr = 0; 69 | rd.mode = mode; 70 | 71 | if (mode == MODE_SERIAL) { 72 | rd.count = fetch_next_block(codeBuffer, BUFFER_SIZE); 73 | } else { 74 | rd.count = fetch_next_block_wifi(codeBuffer, BUFFER_SIZE); 75 | } 76 | 77 | if (rd.count <= 0) { 78 | Error("[JTAG] No data available\r\n"); 79 | return retval; 80 | } 81 | 82 | Info("[JTAG] Programming...\r\n"); 83 | 84 | pinMode(LED_BUILTIN, OUTPUT); 85 | retval = xsvftool_esp_program(get_next_byte, dataType); 86 | pinMode(LED_BUILTIN, INPUT); 87 | 88 | Info("[JTAG] Programming finished with status %d\r\n", retval); 89 | 90 | return retval; 91 | } 92 | 93 | void set_pins(uint8_t tdi, uint8_t tdo, uint8_t tck, uint8_t tms, uint8_t led) { 94 | xsvftool_esp_set_pins(tdi, tdo, tck, tms); 95 | ledpin = led; 96 | } -------------------------------------------------------------------------------- /src/libxsvf/memname.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Lib(X)SVF - A library for implementing SVF and XSVF JTAG players 3 | * 4 | * Copyright (C) 2009 RIEGL Research ForschungsGmbH 5 | * Copyright (C) 2009 Clifford Wolf 6 | * 7 | * Permission to use, copy, modify, and/or distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | * 19 | */ 20 | 21 | #include "libxsvf.h" 22 | 23 | const char *libxsvf_mem2str(enum libxsvf_mem which) 24 | { 25 | #define X(_w, _t) if (which == LIBXSVF_MEM_ ## _w) return #_t; 26 | X(XSVF_TDI_DATA, xsvf_tdi_data) 27 | X(XSVF_TDO_DATA, xsvf_tdo_data) 28 | X(XSVF_TDO_MASK, xsvf_tdo_mask) 29 | X(XSVF_ADDR_MASK, xsvf_addr_mask) 30 | X(XSVF_DATA_MASK, xsvf_data_mask) 31 | X(SVF_COMMANDBUF, svf_commandbuf) 32 | X(SVF_HDR_TDI_DATA, svf_hdr_tdi_data) 33 | X(SVF_HDR_TDI_MASK, svf_hdr_tdi_mask) 34 | X(SVF_HDR_TDO_DATA, svf_hdr_tdo_data) 35 | X(SVF_HDR_TDO_MASK, svf_hdr_tdo_mask) 36 | X(SVF_HDR_RET_MASK, svf_hdr_ret_mask) 37 | X(SVF_HIR_TDI_DATA, svf_hir_tdi_data) 38 | X(SVF_HIR_TDI_MASK, svf_hir_tdi_mask) 39 | X(SVF_HIR_TDO_DATA, svf_hir_tdo_data) 40 | X(SVF_HIR_TDO_MASK, svf_hir_tdo_mask) 41 | X(SVF_HIR_RET_MASK, svf_hir_ret_mask) 42 | X(SVF_TDR_TDI_DATA, svf_tdr_tdi_data) 43 | X(SVF_TDR_TDI_MASK, svf_tdr_tdi_mask) 44 | X(SVF_TDR_TDO_DATA, svf_tdr_tdo_data) 45 | X(SVF_TDR_TDO_MASK, svf_tdr_tdo_mask) 46 | X(SVF_TDR_RET_MASK, svf_tdr_ret_mask) 47 | X(SVF_TIR_TDI_DATA, svf_tir_tdi_data) 48 | X(SVF_TIR_TDI_MASK, svf_tir_tdi_mask) 49 | X(SVF_TIR_TDO_DATA, svf_tir_tdo_data) 50 | X(SVF_TIR_TDO_MASK, svf_tir_tdo_mask) 51 | X(SVF_TIR_RET_MASK, svf_tir_ret_mask) 52 | X(SVF_SDR_TDI_DATA, svf_sdr_tdi_data) 53 | X(SVF_SDR_TDI_MASK, svf_sdr_tdi_mask) 54 | X(SVF_SDR_TDO_DATA, svf_sdr_tdo_data) 55 | X(SVF_SDR_TDO_MASK, svf_sdr_tdo_mask) 56 | X(SVF_SDR_RET_MASK, svf_sdr_ret_mask) 57 | X(SVF_SIR_TDI_DATA, svf_sir_tdi_data) 58 | X(SVF_SIR_TDI_MASK, svf_sir_tdi_mask) 59 | X(SVF_SIR_TDO_DATA, svf_sir_tdo_data) 60 | X(SVF_SIR_TDO_MASK, svf_sir_tdo_mask) 61 | X(SVF_SIR_RET_MASK, svf_sir_ret_mask) 62 | #undef X 63 | return (void*)0; 64 | } 65 | 66 | -------------------------------------------------------------------------------- /tools/upload.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import serial, time, struct, os, sys 4 | 5 | from commands import * 6 | 7 | device = "/dev/ttyUSB0" 8 | baudrate = 921600 9 | 10 | if len(sys.argv) < 3: 11 | print("Usage: upload.py /dev/ttyUSB0 file.svf") 12 | exit(1) 13 | 14 | usbport = sys.argv[1] 15 | filename = sys.argv[2] 16 | 17 | f = open(filename, "rb") 18 | 19 | filelen = os.fstat(f.fileno()).st_size 20 | 21 | print("[HOST] Connecting to %s at %d" %(usbport, baudrate)) 22 | ser = serial.Serial(usbport, baudrate, timeout=1, xonxoff=0, rtscts=0) # open serial port 23 | 24 | print("[HOST] Resetting") 25 | ser.setDTR(False) 26 | time.sleep(0.1) 27 | ser.flushInput() 28 | ser.setDTR(True) 29 | 30 | offset = 0 31 | 32 | def processCtrl(line): 33 | global offset 34 | global ser 35 | 36 | line = line[7:] 37 | ctrl = line[0] 38 | data = line[1:] 39 | 40 | if ctrl == "R": 41 | length = int(data) 42 | # print("Requested %d bytes" % length) 43 | buff = f.read(length) 44 | # print("Read %d bytes" % len(buff)) 45 | if len(buff) == 0: 46 | ser.write(struct.pack(">BI", ord(CMD_STOP[0]), 0)) 47 | # print("\nFinished") 48 | else: 49 | l = struct.pack(">BI", ord(CMD_DATA[0]), len(buff)) 50 | ser.write(l) 51 | ser.write(buff) 52 | if offset > 0: # Skip progressing first block 53 | offset += len(buff) 54 | sys.stdout.write("\r[HOST] Progress: %8d / %8d - %0.2f%%" % (offset, filelen, 100 * offset / filelen)) 55 | else: 56 | offset += len(buff) 57 | elif ctrl == "A": 58 | # print("Received ACK") 59 | pass 60 | elif ctrl == "M": 61 | # print("Control Message: %s" % data) 62 | pass 63 | if offset == filelen: 64 | sys.stdout.write("\n") 65 | 66 | qb = CMD_QUERY + b'\x00\x00\x00\x00' 67 | qs = CMD_START_SVF + b'\x00\x00\x00\x00' 68 | 69 | qp = CMD_PASSTHROUGH + struct.pack(">I", 115200) 70 | 71 | start = None 72 | 73 | print("[HOST] Waiting ESP32 to be ready") 74 | while True: 75 | try: 76 | line = ser.readline().decode("utf-8", errors="ignore") 77 | if "[RDY]" in line: 78 | ser.write(qb) # write a string 79 | elif "[QUERY]" in line: 80 | print(line.strip()) 81 | ser.write(qs) 82 | start = time.time() 83 | elif "[JTAG]" in line: 84 | print(line.strip()) 85 | if "Programming finished" in line: 86 | delta = time.time() - start 87 | print("[HOST] Took %f seconds to upload" % delta) 88 | print("[HOST] Enabling passthrough") 89 | ser.write(qp) 90 | elif "[CTRL]" in line: 91 | processCtrl(line) 92 | elif "[PASS] READY" in line: 93 | print("[PASS] READY") 94 | else: 95 | if len(line) > 0: 96 | print(line.strip()) 97 | except UnicodeDecodeError as e: 98 | print(e) 99 | continue 100 | 101 | ser.close() # close port 102 | f.close() -------------------------------------------------------------------------------- /src/libxsvf/Makefile: -------------------------------------------------------------------------------- 1 | # Lib(X)SVF - A library for implementing SVF and XSVF JTAG players 2 | # 3 | # Copyright (C) 2009 RIEGL Research ForschungsGmbH 4 | # Copyright (C) 2009 Clifford Wolf 5 | # 6 | # Permission to use, copy, modify, and/or distribute this software for any 7 | # purpose with or without fee is hereby granted, provided that the above 8 | # copyright notice and this permission notice appear in all copies. 9 | # 10 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | 18 | #AR = ppc_6xx-ar 19 | #RANLIB = ppc_6xx-ranlib 20 | #CC = ppc_6xx-gcc 21 | #CFLAGS += -DXSVFTOOL_RLMS_VLINE 22 | 23 | AR = ar 24 | RANLIB = ranlib 25 | CC = gcc 26 | 27 | CFLAGS += -Wall -Os -ggdb -MD 28 | #CFLAGS += -Wextra -Wno-unused-parameter -Werror 29 | 30 | help: 31 | @echo "" 32 | @echo "Usage:" 33 | @echo "" 34 | @echo " $(MAKE) libxsvf.a" 35 | @echo " .... build only the library" 36 | @echo "" 37 | @echo " $(MAKE) xsvftool-gpio" 38 | @echo " .... build the library and xsvftool-gpio" 39 | @echo "" 40 | @echo " $(MAKE) xsvftool-ft232h" 41 | @echo " .... build the library and xsvftool-ft232h" 42 | @echo "" 43 | @echo " $(MAKE) xsvftool-xpcu" 44 | @echo " .... build the library and xsvftool-xpcu" 45 | @echo "" 46 | @echo " $(MAKE) all" 47 | @echo " .... build the library and all examples" 48 | @echo "" 49 | @echo " $(MAKE) install" 50 | @echo " .... install everything in /usr/local/" 51 | @echo "" 52 | 53 | all: libxsvf.a xsvftool-gpio xsvftool-ft232h xsvftool-xpcu 54 | 55 | install: all 56 | install -Dt /usr/local/bin/ xsvftool-gpio xsvftool-ft232h xsvftool-xpcu 57 | install -Dt /usr/local/include/ -m 644 libxsvf.h 58 | install -Dt /usr/local/lib/ -m 644 libxsvf.a 59 | 60 | libxsvf.a: tap.o statename.o memname.o svf.o xsvf.o scan.o play.o 61 | rm -f libxsvf.a 62 | $(AR) qc $@ $^ 63 | $(RANLIB) $@ 64 | 65 | xsvftool-gpio: libxsvf.a xsvftool-gpio.o 66 | 67 | xsvftool-ft232h: LDLIBS+=-lftdi -lm 68 | xsvftool-ft232h: LDFLAGS+=-pthread 69 | xsvftool-ft232h.o: CFLAGS+=-pthread 70 | xsvftool-ft232h: libxsvf.a xsvftool-ft232h.o 71 | 72 | xsvftool-xpcu: libxsvf.a xsvftool-xpcu.src/*.c xsvftool-xpcu.src/*.h \ 73 | xsvftool-xpcu.src/*.v xsvftool-xpcu.src/*.ucf 74 | $(MAKE) -C xsvftool-xpcu.src 75 | cp xsvftool-xpcu.src/xsvftool-xpcu xsvftool-xpcu 76 | 77 | clean: 78 | $(MAKE) -C xsvftool-xpcu.src clean 79 | rm -f xsvftool-gpio xsvftool-ft232h xsvftool-xpcu 80 | rm -f libxsvf.a *.o *.d 81 | 82 | -include *.d 83 | 84 | -------------------------------------------------------------------------------- /tools/uploadwifi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import serial, time, struct, os, sys 4 | 5 | from commands import * 6 | 7 | import asyncio 8 | import websockets 9 | 10 | if len(sys.argv) < 3: 11 | print("Usage: upload.py IP file.svf") 12 | exit(1) 13 | 14 | ip = sys.argv[1] 15 | filename = sys.argv[2] 16 | 17 | f = open(filename, "rb") 18 | 19 | filelen = os.fstat(f.fileno()).st_size 20 | 21 | JTAGRESULT = "JTAG Result" 22 | 23 | async def queryChip(websocket): 24 | ''' 25 | Queries the CHIP ID 26 | ''' 27 | data = bytearray(CMD_QUERY + "\x00\x00", encoding="utf8") 28 | # print(f"> [CMD_QUERY]") 29 | await websocket.send(data) 30 | data = await websocket.recv() 31 | expectedPath = "[INFO] Chip ID:" 32 | if len(data) > len(expectedPath): 33 | return data[len(expectedPath):].strip() 34 | return None 35 | 36 | async def startXSVF(websocket): 37 | ''' 38 | Start XSVF Transfer 39 | ''' 40 | data = bytearray(CMD_START_XSVF + "\x00\x00", encoding="utf8") 41 | # print(f"> [CMD_START_XSVF]") 42 | await websocket.send(data) 43 | 44 | async def startSVF(websocket): 45 | ''' 46 | Start SVF Transfer 47 | ''' 48 | data = bytearray(CMD_START_SVF + "\x00\x00", encoding="utf8") 49 | # print(f"> [CMD_START_SVF]") 50 | await websocket.send(data) 51 | 52 | async def putData(websocket, data): 53 | ''' 54 | Puts DATA into CMD_DATA queue 55 | ''' 56 | senddata = struct.pack(">BH", ord(CMD_DATA), len(data)) 57 | senddata += bytearray(data) 58 | #print(f"> [CMD_DATA]") 59 | await websocket.send(senddata) 60 | 61 | def GetRequestLength(data): 62 | prefix = "[CTRL] R" 63 | if len(data) < len(prefix): 64 | return 0 65 | 66 | data = data[len(prefix):] 67 | return int(data) 68 | 69 | async def WaitRequestLength(websocket): 70 | prefix = "[CTRL] R" 71 | resp = "" 72 | while not prefix in str(resp): 73 | resp = await websocket.recv() 74 | if JTAGRESULT in str(resp): # Early result 75 | raise Exception(resp) 76 | #print(f"< %s" % resp) 77 | return GetRequestLength(resp) 78 | 79 | async def Stop(websocket): 80 | ''' 81 | Send STOP command 82 | ''' 83 | senddata = struct.pack(">BH", ord(CMD_STOP), 0) 84 | #print(f"> [CMD_DATA]") 85 | await websocket.send(senddata) 86 | 87 | 88 | async def hello(): 89 | uri = "ws://%s/ws" % ip 90 | print(f"> [INFO] Connecting to %s" % uri) 91 | async with websockets.connect(uri) as websocket: 92 | print(f"> [INFO] Connected to %s" %uri) 93 | greeting = await websocket.recv() 94 | print(f"< {greeting}") 95 | 96 | chipId = await queryChip(websocket) 97 | print(f"< [INFO] Chip ID: %s" % chipId) 98 | 99 | await Stop(websocket) 100 | 101 | print(f"> [INFO] Starting SVF") 102 | await startSVF(websocket) 103 | 104 | print(f"> [INFO] Sending file %s" % filename) 105 | readBytes = 0 106 | start = time.time() 107 | while readBytes < filelen: 108 | reqLen = await WaitRequestLength(websocket) 109 | #print(f"Requested chunk length: %d" % reqLen) 110 | data = f.read(reqLen) 111 | readBytes += len(data) 112 | sys.stdout.write("\r> [INFO] Progress: %8d / %8d - %0.2f%%" % (readBytes, filelen, 100 * readBytes / filelen)) 113 | await putData(websocket, data) 114 | delta = time.time() - start 115 | print("\n> [INFO] Took %f seconds to upload" % delta) 116 | print("> [INFO] Sending STOP") 117 | time.sleep(2) 118 | await Stop(websocket) 119 | print("> [INFO] DONE...") 120 | return None 121 | 122 | asyncio.get_event_loop().run_until_complete(hello()) -------------------------------------------------------------------------------- /storage.cpp: -------------------------------------------------------------------------------- 1 | #include "storage.h" 2 | #include 3 | 4 | #define SSID_LENGTH 64 5 | #define PASSWORD_LENGTH 64 6 | #define HOSTNAME_LENGTH 32 7 | 8 | struct Config { 9 | // WIFI 10 | char SSID[SSID_LENGTH]; 11 | char WifiPassword[PASSWORD_LENGTH]; 12 | char Hostname[HOSTNAME_LENGTH]; 13 | char OTAPassword[PASSWORD_LENGTH]; 14 | } currentConfig; 15 | 16 | const size_t ConfigLength = sizeof(currentConfig); 17 | 18 | void ReadConfig() { 19 | char *c = (char *)(¤tConfig); 20 | for (int i=0; i= 0; i--) { 21 | dataLengthbytes[i] = Serial.read(); 22 | } 23 | } 24 | 25 | String ReadParam(int32_t length) { 26 | String param = ""; 27 | for (int32_t i = 0; i < length; i++) { 28 | param += (char)Serial.read(); 29 | } 30 | return param; 31 | } 32 | 33 | void ProgrammerInit() { 34 | set_pins(PIN_TDI, PIN_TDO, PIN_TCK, PIN_TMS, PIN_LED); 35 | 36 | pinMode(PIN_TDI, OUTPUT); 37 | pinMode(PIN_TDO, INPUT_PULLUP); 38 | pinMode(PIN_TCK, OUTPUT); 39 | pinMode(PIN_TMS, OUTPUT); 40 | } 41 | 42 | String tmpParam; 43 | 44 | void ProgrammerLoop() { 45 | if (passthrough) { 46 | // Serial passthrough 47 | if(Serial.available()) { 48 | Serial2.write(Serial.read()); 49 | digitalWrite(PIN_LED, (lastled++)&1); 50 | } 51 | 52 | if(Serial2.available()) { 53 | Serial.write(Serial2.read()); 54 | digitalWrite(PIN_LED, (lastled++)&1); 55 | } 56 | 57 | return; 58 | } 59 | 60 | // Programming Mode 61 | if (Serial.available() >= 5) { 62 | ReadCmdLength(&cmd, &length); 63 | switch (cmd) { 64 | case CMD_START_SVF: 65 | jtag_program(DATA_TYPE_SVF, MODE_SERIAL); 66 | break; 67 | case CMD_START_XSVF: 68 | jtag_program(DATA_TYPE_XSVF, MODE_SERIAL); 69 | break; 70 | case CMD_QUERY: 71 | Serial.print("[QUERY] Chip ID: "); 72 | printf("%08x\n", jtag_chip_id()); 73 | break; 74 | case CMD_STOP: 75 | Serial.println("[RDY]"); 76 | break; 77 | case CMD_PASSTHROUGH: 78 | Serial.println("[PASS] Switching to Serial Passthrough"); 79 | Serial.print("[PASS] Serial2 baudrate set to "); 80 | Serial.println(length); 81 | Serial2.begin(length); 82 | passthrough = 1; 83 | pinMode(PIN_LED, OUTPUT); 84 | digitalWrite(PIN_LED, LOW); 85 | Serial.println("[PASS] READY"); 86 | return; 87 | case CMD_SET_WIFI_PASS: 88 | tmpParam = ReadParam(length); 89 | SaveWifiPassword(tmpParam); 90 | Serial.print("[INFO] Wifi Password set to "); 91 | Serial.println(tmpParam); 92 | tmpParam = ""; 93 | break; 94 | case CMD_SET_WIFI_SSID: 95 | tmpParam = ReadParam(length); 96 | SaveWifiSSID(tmpParam); 97 | Serial.print("[INFO] Wifi SSID set to "); 98 | Serial.println(tmpParam); 99 | tmpParam = ""; 100 | break; 101 | case CMD_SET_OTA_PASS: 102 | tmpParam = ReadParam(length); 103 | SaveOTAPassword(tmpParam); 104 | Serial.print("[INFO] OTA Password set to "); 105 | Serial.println(tmpParam); 106 | tmpParam = ""; 107 | break; 108 | case CMD_SET_HOSTNAME: 109 | tmpParam = ReadParam(length); 110 | SaveHostname(tmpParam); 111 | Serial.print("[INFO] Hostname set to "); 112 | Serial.println(tmpParam); 113 | tmpParam = ""; 114 | break; 115 | case CMD_REBOOT: 116 | Serial.println("[INFO] Received reboot"); 117 | ESP.restart(); 118 | break; 119 | default: 120 | Serial.println("[CTRL] ERROR"); 121 | } 122 | } 123 | } 124 | 125 | int fetch_next_block(uint8_t *buffer, int length) { 126 | Serial.print("[CTRL] R"); 127 | Serial.println(length); 128 | 129 | uint8_t cmd; 130 | int32_t dataLength; 131 | ReadCmdLength(&cmd, &dataLength); 132 | 133 | if (dataLength <= 0) { 134 | return -1; 135 | } 136 | 137 | int readBytes = 0; 138 | 139 | while (readBytes < dataLength) { 140 | while(!Serial.available()); 141 | buffer[readBytes] = Serial.read(); 142 | readBytes++; 143 | } 144 | Serial.println("[CTRL] A"); 145 | 146 | return readBytes; 147 | } 148 | -------------------------------------------------------------------------------- /data/index.htm: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | WebSocketTester 23 | 52 | 124 | 125 | 126 |

127 |     
128 | $ 129 |
130 | 131 | 132 | -------------------------------------------------------------------------------- /src/libxsvf/tap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Lib(X)SVF - A library for implementing SVF and XSVF JTAG players 3 | * 4 | * Copyright (C) 2009 RIEGL Research ForschungsGmbH 5 | * Copyright (C) 2009 Clifford Wolf 6 | * 7 | * Permission to use, copy, modify, and/or distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | * 19 | */ 20 | 21 | #include "libxsvf.h" 22 | 23 | static void tap_transition(struct libxsvf_host *h, int v) 24 | { 25 | LIBXSVF_HOST_PULSE_TCK(v, -1, -1, 0, 0); 26 | } 27 | 28 | int libxsvf_tap_walk(struct libxsvf_host *h, enum libxsvf_tap_state s) 29 | { 30 | int i, j; 31 | for (i=0; s != h->tap_state; i++) 32 | { 33 | switch (h->tap_state) 34 | { 35 | /* Special States */ 36 | case LIBXSVF_TAP_INIT: 37 | for (j = 0; j < 6; j++) 38 | tap_transition(h, 1); 39 | h->tap_state = LIBXSVF_TAP_RESET; 40 | break; 41 | case LIBXSVF_TAP_RESET: 42 | tap_transition(h, 0); 43 | h->tap_state = LIBXSVF_TAP_IDLE; 44 | break; 45 | case LIBXSVF_TAP_IDLE: 46 | tap_transition(h, 1); 47 | h->tap_state = LIBXSVF_TAP_DRSELECT; 48 | break; 49 | 50 | /* DR States */ 51 | case LIBXSVF_TAP_DRSELECT: 52 | if (s >= LIBXSVF_TAP_IRSELECT || s == LIBXSVF_TAP_RESET) { 53 | tap_transition(h, 1); 54 | h->tap_state = LIBXSVF_TAP_IRSELECT; 55 | } else { 56 | tap_transition(h, 0); 57 | h->tap_state = LIBXSVF_TAP_DRCAPTURE; 58 | } 59 | break; 60 | case LIBXSVF_TAP_DRCAPTURE: 61 | if (s == LIBXSVF_TAP_DRSHIFT) { 62 | tap_transition(h, 0); 63 | h->tap_state = LIBXSVF_TAP_DRSHIFT; 64 | } else { 65 | tap_transition(h, 1); 66 | h->tap_state = LIBXSVF_TAP_DREXIT1; 67 | } 68 | break; 69 | case LIBXSVF_TAP_DRSHIFT: 70 | tap_transition(h, 1); 71 | h->tap_state = LIBXSVF_TAP_DREXIT1; 72 | break; 73 | case LIBXSVF_TAP_DREXIT1: 74 | if (s == LIBXSVF_TAP_DRPAUSE) { 75 | tap_transition(h, 0); 76 | h->tap_state = LIBXSVF_TAP_DRPAUSE; 77 | } else { 78 | tap_transition(h, 1); 79 | h->tap_state = LIBXSVF_TAP_DRUPDATE; 80 | } 81 | break; 82 | case LIBXSVF_TAP_DRPAUSE: 83 | tap_transition(h, 1); 84 | h->tap_state = LIBXSVF_TAP_DREXIT2; 85 | break; 86 | case LIBXSVF_TAP_DREXIT2: 87 | if (s == LIBXSVF_TAP_DRSHIFT) { 88 | tap_transition(h, 0); 89 | h->tap_state = LIBXSVF_TAP_DRSHIFT; 90 | } else { 91 | tap_transition(h, 1); 92 | h->tap_state = LIBXSVF_TAP_DRUPDATE; 93 | } 94 | break; 95 | case LIBXSVF_TAP_DRUPDATE: 96 | if (s == LIBXSVF_TAP_IDLE) { 97 | tap_transition(h, 0); 98 | h->tap_state = LIBXSVF_TAP_IDLE; 99 | } else { 100 | tap_transition(h, 1); 101 | h->tap_state = LIBXSVF_TAP_DRSELECT; 102 | } 103 | break; 104 | 105 | /* IR States */ 106 | case LIBXSVF_TAP_IRSELECT: 107 | if (s == LIBXSVF_TAP_RESET) { 108 | tap_transition(h, 1); 109 | h->tap_state = LIBXSVF_TAP_RESET; 110 | } else { 111 | tap_transition(h, 0); 112 | h->tap_state = LIBXSVF_TAP_IRCAPTURE; 113 | } 114 | break; 115 | case LIBXSVF_TAP_IRCAPTURE: 116 | if (s == LIBXSVF_TAP_IRSHIFT) { 117 | tap_transition(h, 0); 118 | h->tap_state = LIBXSVF_TAP_IRSHIFT; 119 | } else { 120 | tap_transition(h, 1); 121 | h->tap_state = LIBXSVF_TAP_IREXIT1; 122 | } 123 | break; 124 | case LIBXSVF_TAP_IRSHIFT: 125 | tap_transition(h, 1); 126 | h->tap_state = LIBXSVF_TAP_IREXIT1; 127 | break; 128 | case LIBXSVF_TAP_IREXIT1: 129 | if (s == LIBXSVF_TAP_IRPAUSE) { 130 | tap_transition(h, 0); 131 | h->tap_state = LIBXSVF_TAP_IRPAUSE; 132 | } else { 133 | tap_transition(h, 1); 134 | h->tap_state = LIBXSVF_TAP_IRUPDATE; 135 | } 136 | break; 137 | case LIBXSVF_TAP_IRPAUSE: 138 | tap_transition(h, 1); 139 | h->tap_state = LIBXSVF_TAP_IREXIT2; 140 | break; 141 | case LIBXSVF_TAP_IREXIT2: 142 | if (s == LIBXSVF_TAP_IRSHIFT) { 143 | tap_transition(h, 0); 144 | h->tap_state = LIBXSVF_TAP_IRSHIFT; 145 | } else { 146 | tap_transition(h, 1); 147 | h->tap_state = LIBXSVF_TAP_IRUPDATE; 148 | } 149 | break; 150 | case LIBXSVF_TAP_IRUPDATE: 151 | if (s == LIBXSVF_TAP_IDLE) { 152 | tap_transition(h, 0); 153 | h->tap_state = LIBXSVF_TAP_IDLE; 154 | } else { 155 | tap_transition(h, 1); 156 | h->tap_state = LIBXSVF_TAP_DRSELECT; 157 | } 158 | break; 159 | 160 | default: 161 | LIBXSVF_HOST_REPORT_ERROR("Illegal tap state."); 162 | return -1; 163 | } 164 | if (h->report_tapstate) 165 | LIBXSVF_HOST_REPORT_TAPSTATE(); 166 | if (i>10) { 167 | LIBXSVF_HOST_REPORT_ERROR("Loop in tap walker."); 168 | return -1; 169 | } 170 | } 171 | 172 | return 0; 173 | } 174 | -------------------------------------------------------------------------------- /src/libxsvf/libxsvf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Lib(X)SVF - A library for implementing SVF and XSVF JTAG players 3 | * 4 | * Copyright (C) 2009 RIEGL Research ForschungsGmbH 5 | * Copyright (C) 2009 Clifford Wolf 6 | * 7 | * Permission to use, copy, modify, and/or distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | * 19 | */ 20 | 21 | #ifndef LIBXSVF_H 22 | #define LIBXSVF_H 23 | 24 | 25 | enum libxsvf_mode { 26 | LIBXSVF_MODE_SVF = 1, 27 | LIBXSVF_MODE_XSVF = 2, 28 | LIBXSVF_MODE_SCAN = 3 29 | }; 30 | 31 | enum libxsvf_tap_state { 32 | /* Special States */ 33 | LIBXSVF_TAP_INIT = 0, 34 | LIBXSVF_TAP_RESET = 1, 35 | LIBXSVF_TAP_IDLE = 2, 36 | /* DR States */ 37 | LIBXSVF_TAP_DRSELECT = 3, 38 | LIBXSVF_TAP_DRCAPTURE = 4, 39 | LIBXSVF_TAP_DRSHIFT = 5, 40 | LIBXSVF_TAP_DREXIT1 = 6, 41 | LIBXSVF_TAP_DRPAUSE = 7, 42 | LIBXSVF_TAP_DREXIT2 = 8, 43 | LIBXSVF_TAP_DRUPDATE = 9, 44 | /* IR States */ 45 | LIBXSVF_TAP_IRSELECT = 10, 46 | LIBXSVF_TAP_IRCAPTURE = 11, 47 | LIBXSVF_TAP_IRSHIFT = 12, 48 | LIBXSVF_TAP_IREXIT1 = 13, 49 | LIBXSVF_TAP_IRPAUSE = 14, 50 | LIBXSVF_TAP_IREXIT2 = 15, 51 | LIBXSVF_TAP_IRUPDATE = 16 52 | }; 53 | 54 | enum libxsvf_mem { 55 | LIBXSVF_MEM_XSVF_TDI_DATA = 0, 56 | LIBXSVF_MEM_XSVF_TDO_DATA = 1, 57 | LIBXSVF_MEM_XSVF_TDO_MASK = 2, 58 | LIBXSVF_MEM_XSVF_ADDR_MASK = 3, 59 | LIBXSVF_MEM_XSVF_DATA_MASK = 4, 60 | LIBXSVF_MEM_SVF_COMMANDBUF = 5, 61 | LIBXSVF_MEM_SVF_SDR_TDI_DATA = 6, 62 | LIBXSVF_MEM_SVF_SDR_TDI_MASK = 7, 63 | LIBXSVF_MEM_SVF_SDR_TDO_DATA = 8, 64 | LIBXSVF_MEM_SVF_SDR_TDO_MASK = 9, 65 | LIBXSVF_MEM_SVF_SDR_RET_MASK = 10, 66 | LIBXSVF_MEM_SVF_SIR_TDI_DATA = 11, 67 | LIBXSVF_MEM_SVF_SIR_TDI_MASK = 12, 68 | LIBXSVF_MEM_SVF_SIR_TDO_DATA = 13, 69 | LIBXSVF_MEM_SVF_SIR_TDO_MASK = 14, 70 | LIBXSVF_MEM_SVF_SIR_RET_MASK = 15, 71 | LIBXSVF_MEM_SVF_HDR_TDI_DATA = 16, 72 | LIBXSVF_MEM_SVF_HDR_TDI_MASK = 17, 73 | LIBXSVF_MEM_SVF_HDR_TDO_DATA = 18, 74 | LIBXSVF_MEM_SVF_HDR_TDO_MASK = 19, 75 | LIBXSVF_MEM_SVF_HDR_RET_MASK = 20, 76 | LIBXSVF_MEM_SVF_HIR_TDI_DATA = 21, 77 | LIBXSVF_MEM_SVF_HIR_TDI_MASK = 22, 78 | LIBXSVF_MEM_SVF_HIR_TDO_DATA = 23, 79 | LIBXSVF_MEM_SVF_HIR_TDO_MASK = 24, 80 | LIBXSVF_MEM_SVF_HIR_RET_MASK = 25, 81 | LIBXSVF_MEM_SVF_TDR_TDI_DATA = 26, 82 | LIBXSVF_MEM_SVF_TDR_TDI_MASK = 27, 83 | LIBXSVF_MEM_SVF_TDR_TDO_DATA = 28, 84 | LIBXSVF_MEM_SVF_TDR_TDO_MASK = 29, 85 | LIBXSVF_MEM_SVF_TDR_RET_MASK = 30, 86 | LIBXSVF_MEM_SVF_TIR_TDI_DATA = 31, 87 | LIBXSVF_MEM_SVF_TIR_TDI_MASK = 32, 88 | LIBXSVF_MEM_SVF_TIR_TDO_DATA = 33, 89 | LIBXSVF_MEM_SVF_TIR_TDO_MASK = 34, 90 | LIBXSVF_MEM_SVF_TIR_RET_MASK = 35, 91 | LIBXSVF_MEM_NUM = 36 92 | }; 93 | 94 | struct libxsvf_host { 95 | int (*setup)(struct libxsvf_host *h); 96 | int (*shutdown)(struct libxsvf_host *h); 97 | void (*udelay)(struct libxsvf_host *h, long usecs, int tms, long num_tck); 98 | int (*getbyte)(struct libxsvf_host *h); 99 | int (*sync)(struct libxsvf_host *h); 100 | int (*pulse_tck)(struct libxsvf_host *h, int tms, int tdi, int tdo, int rmask, int sync); 101 | void (*pulse_sck)(struct libxsvf_host *h); 102 | void (*set_trst)(struct libxsvf_host *h, int v); 103 | int (*set_frequency)(struct libxsvf_host *h, int v); 104 | void (*report_tapstate)(struct libxsvf_host *h); 105 | void (*report_device)(struct libxsvf_host *h, unsigned long idcode); 106 | void (*report_status)(struct libxsvf_host *h, const char *message); 107 | void (*report_error)(struct libxsvf_host *h, const char *file, int line, const char *message); 108 | void *(*realloc)(struct libxsvf_host *h, void *ptr, int size, enum libxsvf_mem which); 109 | enum libxsvf_tap_state tap_state; 110 | void *user_data; 111 | }; 112 | 113 | int libxsvf_play(struct libxsvf_host *, enum libxsvf_mode mode); 114 | const char *libxsvf_state2str(enum libxsvf_tap_state tap_state); 115 | const char *libxsvf_mem2str(enum libxsvf_mem which); 116 | 117 | /* Internal API */ 118 | int libxsvf_svf(struct libxsvf_host *h); 119 | int libxsvf_svf_packet(struct libxsvf_host *h, int index, int final); 120 | int libxsvf_xsvf(struct libxsvf_host *h); 121 | int libxsvf_scan(struct libxsvf_host *h); 122 | int libxsvf_tap_walk(struct libxsvf_host *, enum libxsvf_tap_state); 123 | 124 | /* Host accessor macros (see README) */ 125 | #define LIBXSVF_HOST_SETUP() h->setup(h) 126 | #define LIBXSVF_HOST_SHUTDOWN() h->shutdown(h) 127 | #define LIBXSVF_HOST_UDELAY(_usecs, _tms, _num_tck) h->udelay(h, _usecs, _tms, _num_tck) 128 | #define LIBXSVF_HOST_GETBYTE() h->getbyte(h) 129 | #define LIBXSVF_HOST_SYNC() (h->sync ? h->sync(h) : 0) 130 | #define LIBXSVF_HOST_PULSE_TCK(_tms, _tdi, _tdo, _rmask, _sync) h->pulse_tck(h, _tms, _tdi, _tdo, _rmask, _sync) 131 | #define LIBXSVF_HOST_PULSE_SCK() do { if (h->pulse_sck) h->pulse_sck(h); } while (0) 132 | #define LIBXSVF_HOST_SET_TRST(_v) do { if (h->set_trst) h->set_trst(h, _v); } while (0) 133 | #define LIBXSVF_HOST_SET_FREQUENCY(_v) (h->set_frequency ? h->set_frequency(h, _v) : -1) 134 | #define LIBXSVF_HOST_REPORT_TAPSTATE() do { if (h->report_tapstate) h->report_tapstate(h); } while (0) 135 | #define LIBXSVF_HOST_REPORT_DEVICE(_v) do { if (h->report_device) h->report_device(h, _v); } while (0) 136 | #define LIBXSVF_HOST_REPORT_STATUS(_msg) do { if (h->report_status) h->report_status(h, _msg); } while (0) 137 | #define LIBXSVF_HOST_REPORT_ERROR(_msg) h->report_error(h, __FILE__, __LINE__, _msg) 138 | #define LIBXSVF_HOST_REALLOC(_ptr, _size, _which) h->realloc(h, _ptr, _size, _which) 139 | 140 | #endif 141 | 142 | -------------------------------------------------------------------------------- /webserver.cpp: -------------------------------------------------------------------------------- 1 | #include "webserver.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include "events.h" 13 | 14 | #include "program.h" 15 | #include "programmer.h" 16 | #include "netlog.h" 17 | 18 | AsyncWebServer server(80); 19 | 20 | #define STATE_IDLE 1 21 | #define STATE_WAITING_PACKET 2 22 | #define STATE_BLOCK_READY 3 23 | 24 | #define MULTI_FRAME_SIZE (BUFFER_SIZE + 80) 25 | 26 | struct ClientState { 27 | uint8_t codeBuffer[BUFFER_SIZE]; 28 | size_t length; 29 | uint8_t currentState; 30 | AsyncWebSocketClient *currentClient; 31 | int dataType; 32 | 33 | // Multi-frame suport 34 | uint8_t multiFrameBuffer[MULTI_FRAME_SIZE]; 35 | size_t multiFrameBufferPos; 36 | uint8_t multiFrameValid; 37 | 38 | // Running JTAG Task 39 | uint8_t programming; 40 | } cs; 41 | 42 | 43 | TaskHandle_t task_jtag; 44 | 45 | uint8_t isWifiProgramming() { 46 | return cs.programming; 47 | } 48 | 49 | void vJTAG(void *pvParameters){ 50 | cs.programming = 1; 51 | Info("[INFO] JTAG Task Started\r\n"); 52 | int result = jtag_program(cs.dataType, MODE_WIFI); 53 | Info("[INFO] JTAG Result: %d\r\n", result); 54 | cs.programming = 0; 55 | vTaskDelete(NULL); 56 | } 57 | 58 | int fetch_next_block_wifi(uint8_t *buffer, int length) { 59 | while (cs.currentState != STATE_BLOCK_READY) { 60 | if (cs.currentState == STATE_IDLE) { // Close task 61 | Debug("[DEBUG] JTAG Stop Block fetching\r\n"); 62 | return 0; 63 | } 64 | delay(1); // Wait 1ms, that also yields the processor to other tasks 65 | } 66 | 67 | if (cs.length > length) { 68 | Error("[ERROR] Data bigger than expected buffer size\r\n"); 69 | return -1; 70 | } 71 | 72 | int readBytes = 0; 73 | 74 | while (readBytes < cs.length) { 75 | buffer[readBytes] = cs.codeBuffer[readBytes]; 76 | readBytes++; 77 | } 78 | 79 | cs.currentState = STATE_WAITING_PACKET; 80 | 81 | if (cs.currentClient != NULL) { 82 | cs.currentClient->printf("[CTRL] R%d", BUFFER_SIZE); 83 | } 84 | Debug("[INFO] Received %d bytes of data...\r\n", readBytes); 85 | 86 | return readBytes; 87 | // return -1; 88 | } 89 | 90 | void onText(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len) { 91 | data[len] = 0x00; // Ensure null-terminated 92 | Debug("[WS][%u]: %s\r\n", client->id(), data); 93 | client->text("[ERROR] Thanks, but no text here..."); 94 | } 95 | 96 | void notSupported(AsyncWebSocketClient *client, uint8_t cmd) { 97 | Error("[ERROR] Command '%c' not supported...\r\n", cmd); 98 | } 99 | 100 | void notImplemented(AsyncWebSocketClient *client, uint8_t cmd) { 101 | Error("[ERROR] Command '%c' not implemented...\r\n", cmd); 102 | } 103 | 104 | void cmdQuery(AsyncWebSocketClient *client) { 105 | uint32_t chipId = jtag_chip_id(); 106 | Info("[INFO] Chip ID: %08x\r\n", chipId); 107 | } 108 | 109 | void cmdStop(AsyncWebSocketClient *client) { 110 | Info("[INFO] Stopping JTAG\r\n"); 111 | cs.currentState = STATE_IDLE; 112 | } 113 | 114 | void cmdReboot(AsyncWebSocketClient *client) { 115 | Info("[INFO] Received reboot\r\n"); 116 | ESP.restart(); 117 | } 118 | 119 | void cmdStart(AsyncWebSocketClient *client, int dataType) { 120 | Info("[INFO] Starting JTAG\r\n"); 121 | cs.currentState = STATE_WAITING_PACKET; 122 | cs.currentClient = client; 123 | cs.dataType = dataType; 124 | xTaskCreatePinnedToCore(vJTAG, "vJTAG", 10000, NULL, tskIDLE_PRIORITY + 1, &task_jtag, 1); 125 | client->printf("[CTRL] R%d", BUFFER_SIZE); 126 | } 127 | 128 | void cmdData(AsyncWebSocketClient *client, uint8_t *data, size_t len) { 129 | if (len > BUFFER_SIZE) { 130 | Error("[ERROR] Max buffer length %d but got %d bytes in data packet.\r\n", BUFFER_SIZE, len); 131 | cs.currentState = STATE_IDLE; 132 | return; 133 | } 134 | 135 | cs.length = len; 136 | memcpy(cs.codeBuffer, data, len); 137 | cs.currentState = STATE_BLOCK_READY; 138 | } 139 | 140 | void onBinary(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len) { 141 | uint8_t cmd = data[0]; 142 | Debug("[WS][%u]: Received command '%c'\r\n", client->id(), cmd); 143 | 144 | switch (cmd) { 145 | case CMD_DATA: 146 | return cmdData(client, &data[3], len-3); 147 | case CMD_SET_HOSTNAME: 148 | return notImplemented(client, cmd); 149 | case CMD_START_SVF: 150 | return cmdStart(client, DATA_TYPE_SVF); 151 | case CMD_SET_WIFI_PASS: 152 | case CMD_SET_OTA_PASS: 153 | case CMD_PASSTHROUGH: 154 | return notImplemented(client, cmd); 155 | case CMD_QUERY: return cmdQuery(client); 156 | case CMD_REBOOT: return cmdReboot(client); 157 | case CMD_STOP: 158 | return cmdStop(client); 159 | case CMD_SET_WIFI_SSID: 160 | return notImplemented(client, cmd); 161 | case CMD_START_XSVF: 162 | return cmdStart(client, DATA_TYPE_XSVF); 163 | case CMD_GET_STATE: 164 | default: 165 | return notSupported(client, cmd); 166 | } 167 | } 168 | 169 | void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){ 170 | if(type == WS_EVT_CONNECT){ 171 | Debug("[WS][%u] connect\r\n", client->id()); 172 | client->printf("[INFO] Hello Client %u :)", client->id()); 173 | // client->ping(); 174 | } else if(type == WS_EVT_DISCONNECT){ 175 | cs.currentClient = NULL; 176 | Debug("[WS][%u] disconnect\r\n", client->id()); 177 | } else if(type == WS_EVT_ERROR){ 178 | Error("[WS][%u] error(%u): %s\r\n", client->id(), *((uint16_t*)arg), (char*)data); 179 | } else if(type == WS_EVT_PONG){ 180 | Debug("[WS][%u] pong[%u]: %s\r\n", client->id(), len, (len)?(char*)data:""); 181 | } else if(type == WS_EVT_DATA){ 182 | AwsFrameInfo * info = (AwsFrameInfo*)arg; 183 | String msg = ""; 184 | if(info->final && info->index == 0 && info->len == len) { 185 | if (info->opcode == WS_TEXT) { 186 | onText(server, client, type, arg, data, len); 187 | } else { 188 | onBinary(server, client, type, arg, data, len); 189 | } 190 | } else { 191 | if (info->index == 0) { 192 | Debug("[WS][%u] Frame start %d\r\n", client->id(), info->len); 193 | cs.multiFrameBufferPos = 0; 194 | cs.multiFrameValid = 1; 195 | } 196 | 197 | if (!cs.multiFrameValid) { 198 | Error("[ERROR] Invalid piece of data\r\n"); 199 | return; 200 | } 201 | 202 | if (info->index + len > MULTI_FRAME_SIZE) { 203 | Error("[ERROR] Current frame exceeds max storage capacity of %d.\r\n", MULTI_FRAME_SIZE); 204 | cs.multiFrameValid = 0; 205 | return; 206 | } 207 | 208 | memcpy(&cs.multiFrameBuffer[info->index], data, len); 209 | cs.multiFrameBufferPos = info->index + len; 210 | Debug("[WS][%u] Received %d bytes.\r\n", client->id(), cs.multiFrameBufferPos); 211 | 212 | if(cs.multiFrameBufferPos == info->len){ 213 | Debug("[WS][%u] Frame end. Received %d bytes.\r\n", client->id(), cs.multiFrameBufferPos); 214 | if (info->opcode == WS_TEXT) { 215 | onText(server, client, type, arg, cs.multiFrameBuffer, cs.multiFrameBufferPos); 216 | } else { 217 | onBinary(server, client, type, arg, cs.multiFrameBuffer, cs.multiFrameBufferPos); 218 | } 219 | cs.multiFrameValid = 0; 220 | cs.multiFrameBufferPos = 0; 221 | } 222 | } 223 | } 224 | } 225 | 226 | 227 | void InitWebServer() { 228 | cs.currentState = STATE_IDLE; 229 | cs.programming = 0; 230 | 231 | MDNS.addService("http","tcp",80); 232 | SPIFFS.begin(); 233 | websocket.onEvent(onWsEvent); 234 | server.addHandler(&websocket); 235 | 236 | server.on("/heap", HTTP_GET, [](AsyncWebServerRequest *request){ 237 | request->send(200, "text/plain", String(ESP.getFreeHeap())); 238 | }); 239 | 240 | server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.htm"); 241 | 242 | server.onFileUpload([](AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final){ 243 | if(!index) 244 | Serial.printf("[WEB] UploadStart: %s\n", filename.c_str()); 245 | Serial.printf("%s", (const char*)data); 246 | if(final) 247 | Serial.printf("[WEB] UploadEnd: %s (%u)\n", filename.c_str(), index+len); 248 | }); 249 | 250 | server.onRequestBody([](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) { 251 | if(!index) 252 | Serial.printf("[WEB] BodyStart: %u\n", total); 253 | Serial.printf("%s", (const char*)data); 254 | if(index + len == total) 255 | Serial.printf("[WEB] BodyEnd: %u\n", total); 256 | }); 257 | 258 | server.begin(); 259 | } 260 | 261 | 262 | void WebServerLoop() { 263 | websocket.cleanupClients(); 264 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /src/libxsvf/xsvftool-esp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Lib(X)SVF - A library for implementing SVF and XSVF JTAG players 3 | * 4 | * Copyright (C) 2009 RIEGL Research ForschungsGmbH 5 | * Copyright (C) 2009 Clifford Wolf 6 | * 7 | * Permission to use, copy, modify, and/or distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | * 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "libxsvf.h" 31 | 32 | #define PIN_TDI 33 33 | #define PIN_TDO 32 34 | #define PIN_TCK 27 35 | #define PIN_TMS 26 36 | 37 | static uint8_t TDI = PIN_TDI; 38 | static uint8_t TDO = PIN_TDO; 39 | static uint8_t TCK = PIN_TCK; 40 | static uint8_t TMS = PIN_TMS; 41 | 42 | /** BEGIN: Low-Level I/O Implementation **/ 43 | 44 | static void io_setup(void) 45 | { 46 | pinMode(TCK, OUTPUT); 47 | pinMode(TMS, OUTPUT); 48 | pinMode(TDI, OUTPUT); 49 | pinMode(TDO, INPUT); 50 | } 51 | 52 | static void io_shutdown(void) 53 | { 54 | pinMode(TCK, INPUT); 55 | pinMode(TMS, INPUT); 56 | pinMode(TDO, INPUT); 57 | pinMode(TDI, INPUT); 58 | } 59 | 60 | static inline void io_tms(int val) 61 | { 62 | digitalWrite(TMS, val); 63 | } 64 | 65 | static inline void io_tdi(int val) 66 | { 67 | digitalWrite(TDI, val); 68 | } 69 | 70 | static inline void io_tck(int val) 71 | { 72 | digitalWrite(TCK, val); 73 | } 74 | 75 | static inline void io_sck(int val) 76 | { 77 | } 78 | 79 | static inline void io_trst(int val) 80 | { 81 | } 82 | 83 | static inline int io_tdo() 84 | { 85 | return digitalRead(TDO); 86 | } 87 | 88 | /** END: Low-Level I/O Implementation **/ 89 | 90 | struct udata_s { 91 | int (*file_getbyte)(); 92 | int line; 93 | int verbose; 94 | int clockcount; 95 | int bitcount_tdi; 96 | int bitcount_tdo; 97 | int retval_i; 98 | int retval[256]; 99 | char report[256]; 100 | uint32_t idcode; 101 | }; 102 | 103 | static int h_setup(struct libxsvf_host *h) 104 | { 105 | struct udata_s *u = h->user_data; 106 | if (u->verbose >= 2) { 107 | printf("[SETUP]\n"); 108 | } 109 | io_setup(); 110 | return 0; 111 | } 112 | 113 | static int h_shutdown(struct libxsvf_host *h) 114 | { 115 | struct udata_s *u = h->user_data; 116 | if (u->verbose >= 2) { 117 | printf("[SHUTDOWN]\n"); 118 | } 119 | io_shutdown(); 120 | return 0; 121 | } 122 | 123 | static void h_udelay(struct libxsvf_host *h, long usecs, int tms, long num_tck) 124 | { 125 | struct udata_s *u = h->user_data; 126 | if (u->verbose >= 3) { 127 | printf("[DELAY:%ld, TMS:%d, NUM_TCK:%ld]\n", usecs, tms, num_tck); 128 | } 129 | if (num_tck > 0) { 130 | struct timeval tv1, tv2; 131 | gettimeofday(&tv1, NULL); 132 | io_tms(tms); 133 | while (num_tck > 0) { 134 | io_tck(0); 135 | io_tck(1); 136 | num_tck--; 137 | } 138 | gettimeofday(&tv2, NULL); 139 | if (tv2.tv_sec > tv1.tv_sec) { 140 | usecs -= (1000000 - tv1.tv_usec) + (tv2.tv_sec - tv1.tv_sec - 1) * 1000000; 141 | tv1.tv_usec = 0; 142 | } 143 | usecs -= tv2.tv_usec - tv1.tv_usec; 144 | if (u->verbose >= 3) { 145 | printf("[DELAY_AFTER_TCK:%ld]\n", usecs > 0 ? usecs : 0); 146 | } 147 | } 148 | if (usecs > 0) { 149 | delayMicroseconds(usecs); 150 | } 151 | } 152 | 153 | static int h_getbyte(struct libxsvf_host *h) 154 | { 155 | struct udata_s *u = h->user_data; 156 | int retval = u->file_getbyte(); 157 | if(retval == '\n') 158 | u->line++; 159 | return retval; // returns same as fgetc() 160 | } 161 | 162 | static int h_pulse_tck(struct libxsvf_host *h, int tms, int tdi, int tdo, int rmask, int sync) 163 | { 164 | struct udata_s *u = h->user_data; 165 | 166 | io_tms(tms); 167 | 168 | if (tdi >= 0) { 169 | u->bitcount_tdi++; 170 | io_tdi(tdi); 171 | } 172 | 173 | io_tck(0); 174 | io_tck(1); 175 | 176 | int line_tdo = io_tdo(); 177 | int rc = line_tdo >= 0 ? line_tdo : 0; 178 | 179 | if (rmask == 1 && u->retval_i < 256) 180 | u->retval[u->retval_i++] = line_tdo; 181 | 182 | if (tdo >= 0 && line_tdo >= 0) { 183 | u->bitcount_tdo++; 184 | if (tdo != line_tdo) 185 | rc = -1; 186 | } 187 | 188 | if (u->verbose >= 4) { 189 | printf("[TMS:%d, TDI:%d, TDO_ARG:%d, TDO_LINE:%d, RMASK:%d, RC:%d]\n", tms, tdi, tdo, line_tdo, rmask, rc); 190 | } 191 | 192 | u->clockcount++; 193 | return rc; 194 | } 195 | 196 | static void h_pulse_sck(struct libxsvf_host *h) 197 | { 198 | struct udata_s *u = h->user_data; 199 | if (u->verbose >= 4) { 200 | printf("[SCK]\n"); 201 | } 202 | io_sck(0); 203 | io_sck(1); 204 | } 205 | 206 | static void h_set_trst(struct libxsvf_host *h, int v) 207 | { 208 | struct udata_s *u = h->user_data; 209 | if (u->verbose >= 4) { 210 | printf("[TRST:%d]\n", v); 211 | } 212 | io_trst(v); 213 | } 214 | 215 | static int h_set_frequency(struct libxsvf_host *h, int v) 216 | { 217 | printf("WARNING: Setting JTAG clock frequency to %d ignored!\n", v); 218 | return 0; 219 | } 220 | 221 | static void h_report_tapstate(struct libxsvf_host *h) 222 | { 223 | struct udata_s *u = h->user_data; 224 | if (u->verbose >= 3) { 225 | printf("[%s]\n", libxsvf_state2str(h->tap_state)); 226 | } 227 | } 228 | 229 | static void h_report_device(struct libxsvf_host *h, unsigned long idcode) 230 | { 231 | struct udata_s *u = h->user_data; 232 | u->idcode = idcode; 233 | // printf("idcode=0x%08lx, revision=0x%01lx, part=0x%04lx, manufactor=0x%03lx\n", idcode, 234 | // (idcode >> 28) & 0xf, (idcode >> 12) & 0xffff, (idcode >> 1) & 0x7ff); 235 | } 236 | 237 | static void h_report_status(struct libxsvf_host *h, const char *message) 238 | { 239 | struct udata_s *u = h->user_data; 240 | if (u->verbose >= 2) { 241 | printf("[STATUS] %s\n", message); 242 | } 243 | } 244 | 245 | static void h_report_error(struct libxsvf_host *h, const char *file, int line, const char *message) 246 | { 247 | struct udata_s *u = h->user_data; 248 | // snprintf(u->report, 256, "[%s:%d] %s", file, line, message); 249 | snprintf(u->report, 256, "line %d: %s", u->line, message); 250 | puts(u->report); 251 | // printf("[%s:%d] %s\n", file, line, message); 252 | } 253 | 254 | static int realloc_maxsize[LIBXSVF_MEM_NUM]; 255 | 256 | static void *h_realloc(struct libxsvf_host *h, void *ptr, int size, enum libxsvf_mem which) 257 | { 258 | struct udata_s *u = h->user_data; 259 | if (size > realloc_maxsize[which]) 260 | realloc_maxsize[which] = size; 261 | if (u->verbose >= 3) { 262 | printf("[REALLOC:%s:%d]\n", libxsvf_mem2str(which), size); 263 | } 264 | return realloc(ptr, size); 265 | } 266 | 267 | static struct udata_s u; 268 | 269 | static struct libxsvf_host h = { 270 | .udelay = h_udelay, 271 | .setup = h_setup, 272 | .shutdown = h_shutdown, 273 | .getbyte = h_getbyte, 274 | .pulse_tck = h_pulse_tck, 275 | .pulse_sck = h_pulse_sck, 276 | .set_trst = h_set_trst, 277 | .set_frequency = h_set_frequency, 278 | .report_tapstate = h_report_tapstate, 279 | .report_device = h_report_device, 280 | .report_status = h_report_status, 281 | .report_error = h_report_error, 282 | .realloc = h_realloc, 283 | .user_data = &u 284 | }; 285 | 286 | 287 | #if 0 288 | int main(int argc, char **argv) 289 | { 290 | int rc = 0; 291 | int gotaction = 0; 292 | int hex_mode = 0; 293 | const char *realloc_name = NULL; 294 | int opt, i, j; 295 | 296 | progname = argc >= 1 ? argv[0] : "xvsftool"; 297 | while ((opt = getopt(argc, argv, "r:vLBx:s:c")) != -1) 298 | { 299 | switch (opt) 300 | { 301 | case 'r': 302 | realloc_name = optarg; 303 | break; 304 | case 'v': 305 | copyleft(); 306 | u.verbose++; 307 | break; 308 | case 'x': 309 | case 's': 310 | gotaction = 1; 311 | if (u.verbose) 312 | fprintf(stderr, "Playing %s file `%s'.\n", opt == 's' ? "SVF" : "XSVF", optarg); 313 | if (!strcmp(optarg, "-")) 314 | u.f = stdin; 315 | else 316 | u.f = fopen(optarg, "rb"); 317 | if (u.f == NULL) { 318 | fprintf(stderr, "Can't open %s file `%s': %s\n", opt == 's' ? "SVF" : "XSVF", optarg, strerror(errno)); 319 | rc = 1; 320 | break; 321 | } 322 | if (libxsvf_play(&h, opt == 's' ? LIBXSVF_MODE_SVF : LIBXSVF_MODE_XSVF) < 0) { 323 | fprintf(stderr, "Error while playing %s file `%s'.\n", opt == 's' ? "SVF" : "XSVF", optarg); 324 | rc = 1; 325 | } 326 | if (strcmp(optarg, "-")) 327 | fclose(u.f); 328 | break; 329 | case 'c': 330 | gotaction = 1; 331 | if (libxsvf_play(&h, LIBXSVF_MODE_SCAN) < 0) { 332 | fprintf(stderr, "Error while scanning JTAG chain.\n"); 333 | rc = 1; 334 | } 335 | break; 336 | case 'L': 337 | hex_mode = 1; 338 | break; 339 | case 'B': 340 | hex_mode = 2; 341 | break; 342 | default: 343 | help(); 344 | break; 345 | } 346 | } 347 | 348 | if (!gotaction) 349 | help(); 350 | 351 | if (u.verbose) { 352 | fprintf(stderr, "Total number of clock cycles: %d\n", u.clockcount); 353 | fprintf(stderr, "Number of significant TDI bits: %d\n", u.bitcount_tdi); 354 | fprintf(stderr, "Number of significant TDO bits: %d\n", u.bitcount_tdo); 355 | if (rc == 0) { 356 | fprintf(stderr, "Finished without errors.\n"); 357 | } else { 358 | fprintf(stderr, "Finished with errors!\n"); 359 | } 360 | } 361 | 362 | if (u.retval_i) { 363 | if (hex_mode) { 364 | printf("0x"); 365 | for (i=0; i < u.retval_i; i+=4) { 366 | int val = 0; 367 | for (j=i; j 1 ? j : u.retval_i - j - 1]; 369 | printf("%x", val); 370 | } 371 | } else { 372 | printf("%d rmask bits:", u.retval_i); 373 | for (i=0; i < u.retval_i; i++) 374 | printf(" %d", u.retval[i]); 375 | } 376 | printf("\n"); 377 | } 378 | 379 | if (realloc_name) { 380 | int num = 0; 381 | for (i = 0; i < LIBXSVF_MEM_NUM; i++) { 382 | if (realloc_maxsize[i] > 0) 383 | num = i+1; 384 | } 385 | printf("void *%s(void *h, void *ptr, int size, int which) {\n", realloc_name); 386 | for (i = 0; i < num; i++) { 387 | if (realloc_maxsize[i] > 0) 388 | printf("\tstatic unsigned char buf_%s[%d];\n", libxsvf_mem2str(i), realloc_maxsize[i]); 389 | } 390 | printf("\tstatic unsigned char *buflist[%d] = {", num); 391 | for (i = 0; i < num; i++) { 392 | if (realloc_maxsize[i] > 0) 393 | printf("%sbuf_%s", i ? ", " : " ", libxsvf_mem2str(i)); 394 | else 395 | printf("%s(void*)0", i ? ", " : " "); 396 | } 397 | printf(" };\n\tstatic int sizelist[%d] = {", num); 398 | for (i = 0; i < num; i++) { 399 | if (realloc_maxsize[i] > 0) 400 | printf("%ssizeof(buf_%s)", i ? ", " : " ", libxsvf_mem2str(i)); 401 | else 402 | printf("%s0", i ? ", " : " "); 403 | } 404 | printf(" };\n"); 405 | printf("\treturn which < %d && size <= sizelist[which] ? buflist[which] : (void*)0;\n", num); 406 | printf("};\n"); 407 | } 408 | 409 | return rc; 410 | } 411 | #endif 412 | 413 | int xsvftool_esp_scan(void) 414 | { 415 | u.idcode = 0; // clear previous scan result 416 | return libxsvf_play(&h, LIBXSVF_MODE_SCAN); 417 | } 418 | 419 | // return scan result (idcode) 420 | uint32_t xsvftool_esp_id(void) 421 | { 422 | return u.idcode; 423 | } 424 | 425 | int xsvftool_esp_program(int (*file_getbyte)(), int x) 426 | { 427 | u.file_getbyte = file_getbyte; 428 | if(u.file_getbyte) 429 | return libxsvf_play(&h, x ? LIBXSVF_MODE_XSVF : LIBXSVF_MODE_SVF); 430 | return -1; // NULL file_getbyte pointer supplied 431 | } 432 | 433 | int xsvftool_esp_svf_packet(int (*packet_getbyte)(), int index, int final, char *report) 434 | { 435 | u.verbose = 0; 436 | u.file_getbyte = packet_getbyte; 437 | if(u.file_getbyte) 438 | { 439 | if(index == 0) 440 | u.line = 1; 441 | int retval = libxsvf_svf_packet(&h, index, final); 442 | strcpy(report, u.report); 443 | return retval; 444 | } 445 | return -1; // NULL file_getbyte pointer supplied 446 | } 447 | 448 | void xsvftool_esp_set_pins(uint8_t tdi, uint8_t tdo, uint8_t tck, uint8_t tms) 449 | { 450 | TDI = tdi; 451 | TDO = tdo; 452 | TCK = tck; 453 | TMS = tms; 454 | } 455 | -------------------------------------------------------------------------------- /src/libxsvf/xsvftool-gpio.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Lib(X)SVF - A library for implementing SVF and XSVF JTAG players 3 | * 4 | * Copyright (C) 2009 RIEGL Research ForschungsGmbH 5 | * Copyright (C) 2009 Clifford Wolf 6 | * 7 | * Permission to use, copy, modify, and/or distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | * 19 | */ 20 | 21 | #include "libxsvf.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | 31 | /** BEGIN: Low-Level I/O Implementation **/ 32 | 33 | #ifdef XSVFTOOL_RLMS_VLINE 34 | 35 | // Simple example with MPC8349E GPIO pins 36 | // (RIEGL LMS V-Line motherboard) 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #define IO_PORT_ADDR 0xE0000C00 44 | 45 | struct io_layout { 46 | unsigned long tdi:1; 47 | unsigned long tdo:1; 48 | unsigned long tms:1; 49 | unsigned long tck:1; 50 | unsigned long reserved:28; 51 | }; 52 | 53 | static volatile struct io_layout *io_direction; 54 | static volatile struct io_layout *io_opendrain; 55 | static volatile struct io_layout *io_data; 56 | 57 | static void io_setup(void) 58 | { 59 | /* open /dev/mem device file */ 60 | int fd = open("/dev/mem", O_RDWR); 61 | if (fd < 0) { 62 | fprintf(stderr, "Can't open /dev/mem: %s\n", strerror(errno)); 63 | exit(1); 64 | } 65 | 66 | /* calculate offsets to page and within page */ 67 | unsigned long psize = getpagesize(); 68 | unsigned long off_inpage = IO_PORT_ADDR % psize; 69 | unsigned long off_topage = IO_PORT_ADDR - off_inpage; 70 | unsigned long mapsize = off_inpage + sizeof(struct io_layout) * 3; 71 | 72 | /* map it into logical memory */ 73 | void *io_addr_map = mmap(0, mapsize, PROT_WRITE, MAP_SHARED, fd, off_topage); 74 | if (io_addr_map == MAP_FAILED) { 75 | fprintf(stderr, "Can't map physical memory: %s\n", strerror(errno)); 76 | exit(1); 77 | } 78 | 79 | /* calculate register addresses */ 80 | io_direction = io_addr_map + off_inpage; 81 | io_opendrain = io_addr_map + off_inpage + 4; 82 | io_data = io_addr_map + off_inpage + 8; 83 | 84 | /* set direction reg */ 85 | io_direction->tms = 1; 86 | io_direction->tck = 1; 87 | io_direction->tdo = 0; 88 | io_direction->tdi = 1; 89 | 90 | /* set open drain reg */ 91 | io_opendrain->tms = 0; 92 | io_opendrain->tck = 0; 93 | io_opendrain->tdo = 0; 94 | io_opendrain->tdi = 0; 95 | 96 | #ifdef HAVE_TRST 97 | /* for boards with TRST, must be driven high */ 98 | io_data->trst = 1; 99 | io_direction->trst = 1; 100 | io_opendrain->trst = 0; 101 | #endif 102 | } 103 | 104 | static void io_shutdown(void) 105 | { 106 | /* set all to z-state */ 107 | io_direction->tms = 0; 108 | io_direction->tck = 0; 109 | io_direction->tdo = 0; 110 | io_direction->tdi = 0; 111 | 112 | #ifdef HAVE_TRST 113 | /* for boards with TRST, assuming there is a pull-down resistor */ 114 | io_direction->trst = 0; 115 | #endif 116 | } 117 | 118 | static void io_tms(int val) 119 | { 120 | io_data->tms = val; 121 | } 122 | 123 | static void io_tdi(int val) 124 | { 125 | io_data->tdi = val; 126 | } 127 | 128 | static void io_tck(int val) 129 | { 130 | io_data->tck = val; 131 | // usleep(1); 132 | } 133 | 134 | static void io_sck(int val) 135 | { 136 | /* not available */ 137 | } 138 | 139 | static void io_trst(int val) 140 | { 141 | /* not available */ 142 | } 143 | 144 | static int io_tdo() 145 | { 146 | return io_data->tdo ? 1 : 0; 147 | } 148 | 149 | #else 150 | 151 | static void io_setup(void) 152 | { 153 | } 154 | 155 | static void io_shutdown(void) 156 | { 157 | } 158 | 159 | static void io_tms(int val) 160 | { 161 | } 162 | 163 | static void io_tdi(int val) 164 | { 165 | } 166 | 167 | static void io_tck(int val) 168 | { 169 | } 170 | 171 | static void io_sck(int val) 172 | { 173 | } 174 | 175 | static void io_trst(int val) 176 | { 177 | } 178 | 179 | static int io_tdo() 180 | { 181 | return -1; 182 | } 183 | 184 | #endif 185 | 186 | /** END: Low-Level I/O Implementation **/ 187 | 188 | 189 | struct udata_s { 190 | FILE *f; 191 | int verbose; 192 | int clockcount; 193 | int bitcount_tdi; 194 | int bitcount_tdo; 195 | int retval_i; 196 | int retval[256]; 197 | }; 198 | 199 | static int h_setup(struct libxsvf_host *h) 200 | { 201 | struct udata_s *u = h->user_data; 202 | if (u->verbose >= 2) { 203 | fprintf(stderr, "[SETUP]\n"); 204 | fflush(stderr); 205 | } 206 | io_setup(); 207 | return 0; 208 | } 209 | 210 | static int h_shutdown(struct libxsvf_host *h) 211 | { 212 | struct udata_s *u = h->user_data; 213 | if (u->verbose >= 2) { 214 | fprintf(stderr, "[SHUTDOWN]\n"); 215 | fflush(stderr); 216 | } 217 | io_shutdown(); 218 | return 0; 219 | } 220 | 221 | static void h_udelay(struct libxsvf_host *h, long usecs, int tms, long num_tck) 222 | { 223 | struct udata_s *u = h->user_data; 224 | if (u->verbose >= 3) { 225 | fprintf(stderr, "[DELAY:%ld, TMS:%d, NUM_TCK:%ld]\n", usecs, tms, num_tck); 226 | fflush(stderr); 227 | } 228 | if (num_tck > 0) { 229 | struct timeval tv1, tv2; 230 | gettimeofday(&tv1, NULL); 231 | io_tms(tms); 232 | while (num_tck > 0) { 233 | io_tck(0); 234 | io_tck(1); 235 | num_tck--; 236 | } 237 | gettimeofday(&tv2, NULL); 238 | if (tv2.tv_sec > tv1.tv_sec) { 239 | usecs -= (1000000 - tv1.tv_usec) + (tv2.tv_sec - tv1.tv_sec - 1) * 1000000; 240 | tv1.tv_usec = 0; 241 | } 242 | usecs -= tv2.tv_usec - tv1.tv_usec; 243 | if (u->verbose >= 3) { 244 | fprintf(stderr, "[DELAY_AFTER_TCK:%ld]\n", usecs > 0 ? usecs : 0); 245 | fflush(stderr); 246 | } 247 | } 248 | if (usecs > 0) { 249 | usleep(usecs); 250 | } 251 | } 252 | 253 | static int h_getbyte(struct libxsvf_host *h) 254 | { 255 | struct udata_s *u = h->user_data; 256 | return fgetc(u->f); 257 | } 258 | 259 | static int h_pulse_tck(struct libxsvf_host *h, int tms, int tdi, int tdo, int rmask, int sync) 260 | { 261 | struct udata_s *u = h->user_data; 262 | 263 | io_tms(tms); 264 | 265 | if (tdi >= 0) { 266 | u->bitcount_tdi++; 267 | io_tdi(tdi); 268 | } 269 | 270 | io_tck(0); 271 | io_tck(1); 272 | 273 | int line_tdo = io_tdo(); 274 | int rc = line_tdo >= 0 ? line_tdo : 0; 275 | 276 | if (rmask == 1 && u->retval_i < 256) 277 | u->retval[u->retval_i++] = line_tdo; 278 | 279 | if (tdo >= 0 && line_tdo >= 0) { 280 | u->bitcount_tdo++; 281 | if (tdo != line_tdo) 282 | rc = -1; 283 | } 284 | 285 | if (u->verbose >= 4) { 286 | fprintf(stderr, "[TMS:%d, TDI:%d, TDO_ARG:%d, TDO_LINE:%d, RMASK:%d, RC:%d]\n", tms, tdi, tdo, line_tdo, rmask, rc); 287 | } 288 | 289 | u->clockcount++; 290 | return rc; 291 | } 292 | 293 | static void h_pulse_sck(struct libxsvf_host *h) 294 | { 295 | struct udata_s *u = h->user_data; 296 | if (u->verbose >= 4) { 297 | fprintf(stderr, "[SCK]\n"); 298 | } 299 | io_sck(0); 300 | io_sck(1); 301 | } 302 | 303 | static void h_set_trst(struct libxsvf_host *h, int v) 304 | { 305 | struct udata_s *u = h->user_data; 306 | if (u->verbose >= 4) { 307 | fprintf(stderr, "[TRST:%d]\n", v); 308 | } 309 | io_trst(v); 310 | } 311 | 312 | static int h_set_frequency(struct libxsvf_host *h, int v) 313 | { 314 | fprintf(stderr, "WARNING: Setting JTAG clock frequency to %d ignored!\n", v); 315 | return 0; 316 | } 317 | 318 | static void h_report_tapstate(struct libxsvf_host *h) 319 | { 320 | struct udata_s *u = h->user_data; 321 | if (u->verbose >= 3) { 322 | fprintf(stderr, "[%s]\n", libxsvf_state2str(h->tap_state)); 323 | } 324 | } 325 | 326 | static void h_report_device(struct libxsvf_host *h, unsigned long idcode) 327 | { 328 | // struct udata_s *u = h->user_data; 329 | // printf("idcode=0x%08lx, revision=0x%01lx, part=0x%04lx, manufactor=0x%03lx\n", idcode, 330 | // (idcode >> 28) & 0xf, (idcode >> 12) & 0xffff, (idcode >> 1) & 0x7ff); 331 | } 332 | 333 | static void h_report_status(struct libxsvf_host *h, const char *message) 334 | { 335 | struct udata_s *u = h->user_data; 336 | if (u->verbose >= 2) { 337 | fprintf(stderr, "[STATUS] %s\n", message); 338 | } 339 | } 340 | 341 | static void h_report_error(struct libxsvf_host *h, const char *file, int line, const char *message) 342 | { 343 | fprintf(stderr, "[%s:%d] %s\n", file, line, message); 344 | } 345 | 346 | static int realloc_maxsize[LIBXSVF_MEM_NUM]; 347 | 348 | static void *h_realloc(struct libxsvf_host *h, void *ptr, int size, enum libxsvf_mem which) 349 | { 350 | struct udata_s *u = h->user_data; 351 | if (size > realloc_maxsize[which]) 352 | realloc_maxsize[which] = size; 353 | if (u->verbose >= 3) { 354 | fprintf(stderr, "[REALLOC:%s:%d]\n", libxsvf_mem2str(which), size); 355 | } 356 | return realloc(ptr, size); 357 | } 358 | 359 | static struct udata_s u; 360 | 361 | static struct libxsvf_host h = { 362 | .udelay = h_udelay, 363 | .setup = h_setup, 364 | .shutdown = h_shutdown, 365 | .getbyte = h_getbyte, 366 | .pulse_tck = h_pulse_tck, 367 | .pulse_sck = h_pulse_sck, 368 | .set_trst = h_set_trst, 369 | .set_frequency = h_set_frequency, 370 | .report_tapstate = h_report_tapstate, 371 | .report_device = h_report_device, 372 | .report_status = h_report_status, 373 | .report_error = h_report_error, 374 | .realloc = h_realloc, 375 | .user_data = &u 376 | }; 377 | 378 | const char *progname; 379 | 380 | static void copyleft() 381 | { 382 | static int already_printed = 0; 383 | if (already_printed) 384 | return; 385 | fprintf(stderr, "xsvftool-gpio, part of Lib(X)SVF (http://www.clifford.at/libxsvf/).\n"); 386 | fprintf(stderr, "Copyright (C) 2009 RIEGL Research ForschungsGmbH\n"); 387 | fprintf(stderr, "Copyright (C) 2009 Clifford Wolf \n"); 388 | fprintf(stderr, "Lib(X)SVF is free software licensed under the ISC license.\n"); 389 | already_printed = 1; 390 | } 391 | 392 | static void help() 393 | { 394 | copyleft(); 395 | fprintf(stderr, "\n"); 396 | fprintf(stderr, "Usage: %s [ -r funcname ] [ -v ... ] [ -L | -B ] { -s svf-file | -x xsvf-file | -c } ...\n", progname); 397 | fprintf(stderr, "\n"); 398 | fprintf(stderr, " -r funcname\n"); 399 | fprintf(stderr, " Dump C-code for pseudo-allocator based on example files\n"); 400 | fprintf(stderr, "\n"); 401 | fprintf(stderr, " -v, -vv, -vvv, -vvvv\n"); 402 | fprintf(stderr, " Verbose, more verbose and even more verbose\n"); 403 | fprintf(stderr, "\n"); 404 | fprintf(stderr, " -L, -B\n"); 405 | fprintf(stderr, " Print RMASK bits as hex value (little or big endian)\n"); 406 | fprintf(stderr, "\n"); 407 | fprintf(stderr, " -s svf-file\n"); 408 | fprintf(stderr, " Play the specified SVF file\n"); 409 | fprintf(stderr, "\n"); 410 | fprintf(stderr, " -x xsvf-file\n"); 411 | fprintf(stderr, " Play the specified XSVF file\n"); 412 | fprintf(stderr, "\n"); 413 | fprintf(stderr, " -c\n"); 414 | fprintf(stderr, " List devices in JTAG chain\n"); 415 | fprintf(stderr, "\n"); 416 | exit(1); 417 | } 418 | 419 | int main(int argc, char **argv) 420 | { 421 | int rc = 0; 422 | int gotaction = 0; 423 | int hex_mode = 0; 424 | const char *realloc_name = NULL; 425 | int opt, i, j; 426 | 427 | progname = argc >= 1 ? argv[0] : "xvsftool"; 428 | while ((opt = getopt(argc, argv, "r:vLBx:s:c")) != -1) 429 | { 430 | switch (opt) 431 | { 432 | case 'r': 433 | realloc_name = optarg; 434 | break; 435 | case 'v': 436 | copyleft(); 437 | u.verbose++; 438 | break; 439 | case 'x': 440 | case 's': 441 | gotaction = 1; 442 | if (u.verbose) 443 | fprintf(stderr, "Playing %s file `%s'.\n", opt == 's' ? "SVF" : "XSVF", optarg); 444 | if (!strcmp(optarg, "-")) 445 | u.f = stdin; 446 | else 447 | u.f = fopen(optarg, "rb"); 448 | if (u.f == NULL) { 449 | fprintf(stderr, "Can't open %s file `%s': %s\n", opt == 's' ? "SVF" : "XSVF", optarg, strerror(errno)); 450 | rc = 1; 451 | break; 452 | } 453 | if (libxsvf_play(&h, opt == 's' ? LIBXSVF_MODE_SVF : LIBXSVF_MODE_XSVF) < 0) { 454 | fprintf(stderr, "Error while playing %s file `%s'.\n", opt == 's' ? "SVF" : "XSVF", optarg); 455 | rc = 1; 456 | } 457 | if (strcmp(optarg, "-")) 458 | fclose(u.f); 459 | break; 460 | case 'c': 461 | gotaction = 1; 462 | if (libxsvf_play(&h, LIBXSVF_MODE_SCAN) < 0) { 463 | fprintf(stderr, "Error while scanning JTAG chain.\n"); 464 | rc = 1; 465 | } 466 | break; 467 | case 'L': 468 | hex_mode = 1; 469 | break; 470 | case 'B': 471 | hex_mode = 2; 472 | break; 473 | default: 474 | help(); 475 | break; 476 | } 477 | } 478 | 479 | if (!gotaction) 480 | help(); 481 | 482 | if (u.verbose) { 483 | fprintf(stderr, "Total number of clock cycles: %d\n", u.clockcount); 484 | fprintf(stderr, "Number of significant TDI bits: %d\n", u.bitcount_tdi); 485 | fprintf(stderr, "Number of significant TDO bits: %d\n", u.bitcount_tdo); 486 | if (rc == 0) { 487 | fprintf(stderr, "Finished without errors.\n"); 488 | } else { 489 | fprintf(stderr, "Finished with errors!\n"); 490 | } 491 | } 492 | 493 | if (u.retval_i) { 494 | if (hex_mode) { 495 | printf("0x"); 496 | for (i=0; i < u.retval_i; i+=4) { 497 | int val = 0; 498 | for (j=i; j 1 ? j : u.retval_i - j - 1]; 500 | printf("%x", val); 501 | } 502 | } else { 503 | printf("%d rmask bits:", u.retval_i); 504 | for (i=0; i < u.retval_i; i++) 505 | printf(" %d", u.retval[i]); 506 | } 507 | printf("\n"); 508 | } 509 | 510 | if (realloc_name) { 511 | int num = 0; 512 | for (i = 0; i < LIBXSVF_MEM_NUM; i++) { 513 | if (realloc_maxsize[i] > 0) 514 | num = i+1; 515 | } 516 | printf("void *%s(void *h, void *ptr, int size, int which) {\n", realloc_name); 517 | for (i = 0; i < num; i++) { 518 | if (realloc_maxsize[i] > 0) 519 | printf("\tstatic unsigned char buf_%s[%d];\n", libxsvf_mem2str(i), realloc_maxsize[i]); 520 | } 521 | printf("\tstatic unsigned char *buflist[%d] = {", num); 522 | for (i = 0; i < num; i++) { 523 | if (realloc_maxsize[i] > 0) 524 | printf("%sbuf_%s", i ? ", " : " ", libxsvf_mem2str(i)); 525 | else 526 | printf("%s(void*)0", i ? ", " : " "); 527 | } 528 | printf(" };\n\tstatic int sizelist[%d] = {", num); 529 | for (i = 0; i < num; i++) { 530 | if (realloc_maxsize[i] > 0) 531 | printf("%ssizeof(buf_%s)", i ? ", " : " ", libxsvf_mem2str(i)); 532 | else 533 | printf("%s0", i ? ", " : " "); 534 | } 535 | printf(" };\n"); 536 | printf("\treturn which < %d && size <= sizelist[which] ? buflist[which] : (void*)0;\n", num); 537 | printf("};\n"); 538 | } 539 | 540 | return rc; 541 | } 542 | 543 | 544 | 545 | -------------------------------------------------------------------------------- /src/libxsvf/README: -------------------------------------------------------------------------------- 1 | 2 | Lib(X)SVF - A library for implementing SVF and XSVF JTAG players 3 | ****************************************************************** 4 | 5 | Please check the subversion repository for updates: 6 | http://svn.clifford.at/libxsvf/trunk/ 7 | 8 | You also might want to have a look at the project homepage: 9 | http://www.clifford.at/libxsvf/ 10 | 11 | In papers and reports, please refer to Lib(X)SVF as follows: "Clifford Wolf, 12 | Lib(X)SVF: A library for implementing SVF and XSVF JTAG players. 13 | http://www.clifford.at/libxsvf/", e.g. using the following BibTeX code: 14 | 15 | @MISC{LibXSVF, 16 | author = {Clifford Wolf}, 17 | title = {Lib(X)SVF: A library for implementing SVF and XSVF JTAG players}, 18 | howpublished = "\url{http://www.clifford.at/libxsvf/}" 19 | } 20 | 21 | Please send bug reports and fixes to . 22 | 23 | 24 | Copyright and Disclaimer 25 | ------------------------ 26 | 27 | Copyright (C) 2009 RIEGL Research ForschungsGmbH 28 | Copyright (C) 2009 Clifford Wolf 29 | 30 | Permission to use, copy, modify, and/or distribute this software for any 31 | purpose with or without fee is hereby granted, provided that the above 32 | copyright notice and this permission notice appear in all copies. 33 | 34 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 35 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 36 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 37 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 38 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 39 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 40 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 41 | 42 | 43 | Introduction 44 | ------------ 45 | 46 | JTAG (IEEE 1149.1, aka "Boundary Scan", [1], [2]) is a standard IC 47 | testing, debugging and programming port. 48 | 49 | SVF (Serial Vector Format, [3], [4]) is a file format for storing the 50 | patterns that should be sent to the JTAG interface, as well as the 51 | expected response. It is used as an exchange format between programms 52 | that generate the JTAG input/output patterns and devices that can 53 | physically talk to a JTAG interface. 54 | 55 | XSVF (Xilinx Serial Vector Format, [5]) is a binary variant of the SVF 56 | file format, optimized but not limited to programming Xilinx FPGA and 57 | CPLD devices. 58 | 59 | Often one wants to use an embedded host processor or microcontroller 60 | to access the JTAG interface on an embedded device instead of using 61 | an external JTAG probe. This library can be used to implement such a 62 | solution. In addition to playing SVF and XSVF files this library is 63 | also capable of scanning the devices in the JTAG chain. 64 | 65 | Lib(X)SVF is free software licensed under the ISC license (a licence 66 | that is functionally equivalent to the 2-clause BSD license). 67 | 68 | [1] http://en.wikipedia.org/wiki/JTAG 69 | [2] http://www.fpga4fun.com/JTAG.html 70 | [3] http://en.wikipedia.org/wiki/Serial_Vector_Format 71 | [4] http://www.asset-intertech.com/support/svf.pdf 72 | [5] http://www.xilinx.com/bvdocs/appnotes/xapp503.pdf 73 | 74 | 75 | Limitations and non-standard extensions 76 | --------------------------------------- 77 | 78 | The SVF commands 'PIO' and 'PIOMAP' are unsupported. Any use of this 79 | commands in an SVF input file is reported as error. 80 | 81 | The SVF 'RUNTEST' command is implemented in a limited manner: The 82 | 'MAXIMUM' time parameter is ignored. Combining 'SCK' with a time 83 | parameter results in first executing the specified number of clock 84 | pulses followed by a delay of the specified timespan, instead of 85 | performing the clock cycles and the delay in parallel. 86 | 87 | The SVF commands 'HDR', 'HIR', 'SDR', 'SIR', 'TDR' and 'TIR' support 88 | an additional non-standard 'RMASK' parameter. This is a mask for the 89 | TDO bits, simmilar to the standard 'MASK' parameter. All TDO bits 90 | marked using a '1' in 'RMASK' are reported back to the host application 91 | using the the ret_tdo() callback function. This can be used to read 92 | data (such as device serial numbers) using JTAG by providing SVF 93 | templates. 94 | 95 | 96 | Using and Porting 97 | ----------------- 98 | 99 | The library itself is written in plain C and does not depend on any 100 | library calls or headers, not even from the standard C library. So it 101 | can be ported easily even to restricted environment, such as embedded 102 | systems. 103 | 104 | So far the libary has only been tested on 32 bit hosts. Using it on 105 | 16 bit processors might not be possible without performing some minor 106 | fixes in the code. 107 | 108 | The program 'xsvftool-gpio' (see xsvftool-gpio.c) is a good example 109 | of how to use the library. Please have a look at this program first. 110 | 111 | Note: See 'Host accessor macros' below for an alternative way of 112 | integrating libxsvf into your host environment. 113 | 114 | The host application must provide an libxsvf_host struct as defined 115 | in libxsvf.h. This struct contains some function pointers that must 116 | be set to implementations of the following functions: 117 | 118 | int setup(struct libxsvf_host *h); 119 | 120 | This function is called by libxsvf to setup/initialize the 121 | jtag interface. It is executed before any other libxsvf_host 122 | callback function is called. 123 | 124 | This function should return 0 when setting up the jtag 125 | interface went fine and -1 on an error. 126 | 127 | int shutdown(struct libxsvf_host *h); 128 | 129 | This function is called by libxsvf to shutdown the jtag 130 | interface. No other libxsvf_host callback function will 131 | be called after this function has been executed. 132 | 133 | This function should return 0 when shutting down the jtag 134 | interface went fine and -1 on an error. 135 | 136 | void udelay(struct libxsvf_host *h, long usecs, int tms, long num_tck) 137 | 138 | A function that delays execution for at least the specified 139 | number of microseconds. 140 | 141 | When the 'num_tck' argument is not 0 also the specified number tck 142 | clock cycles (i.e. 1-0-1 transitions) must be generated with TMS set 143 | to the value specified in the 'tms' argument. 144 | 145 | A simple implementation may perform the delay and the clock cycles 146 | after another instead of parallel. This only has an impact on the 147 | runtime of the player, not on its functionality. 148 | 149 | int getbyte(struct libxsvf_host *h); 150 | 151 | A function that returns the next byte from the input file 152 | or -1 on end of file. 153 | 154 | int sync(struct libxsvf_host *h); 155 | 156 | This function is only needed when writing bindings for an asynchronous 157 | hardware interface (see 'Using libxsvf with asynchronous interfaces' below). 158 | 159 | This function is optional and the function pointer may be set to a NULL 160 | pointer on implementations using the simple synchronous interface. 161 | 162 | int pulse_tck(struct libxsvf_host *h, int tms, int tdi, int tdo, int rmask, int sync) 163 | 164 | This is the main JTAG I/O callback function. 165 | It must perform the following tasks: 166 | 167 | * Set the tms line to the value specified in the 'tms' argument. 168 | 169 | * Set the tdi line to the value specified in the 'tdi' argument. 170 | This argument may be '-1' to indicate that the value of the tdi 171 | line is not important. In this case the tdi line may be set to 172 | any value or may be left unchanged. 173 | 174 | * Create a negative pulse (1-0-1) on the JTAG TCK line. 175 | 176 | * Check the tdo line against the should-be value specified in 177 | the 'tdo' argument. This argument may be '-1' to indicate that 178 | the value of the tdo line doesn't need to be checked. 179 | 180 | * Store the current tdo value if the 'rmask' value is set to '1'. 181 | This step may be ignored if the RMASK feature (see "Limitations 182 | and non-standard extensions" above) is not used. 183 | 184 | The function must return the current value of the tdo line, or -1 on 185 | a TDO-mismatch-error. 186 | 187 | A simple implementation of this function would look like this: 188 | 189 | --snip-- 190 | int my_pulse_tck(struct libxsvf_host *h, int tms, int tdi, int tdo, int rmask, int sync) { 191 | int line_tdo; 192 | setPort(TMS, tms); 193 | if (tdi >= 0) 194 | setPort(TDI, tdi); 195 | setPort(TCK, 0); 196 | setPort(TCK, 1); 197 | line_tdo = getPort(TDO); 198 | return tdo < 0 || line_tdo == tdo ? line_tdo : -1; 199 | } 200 | --snap-- 201 | 202 | The 'sync' argument can safely be ignored unless you are writing 203 | bindings for an asynchronous hardware interface (see 'Using libxsvf 204 | with asynchronous interfaces' below). 205 | 206 | void pulse_sck(struct libxsvf_host *h); 207 | 208 | A function to create a pulse on the JTAG SCK line. 209 | 210 | This function is optional and the function pointer may 211 | be set to a NULL pointer on implementations without an 212 | SCK line. In this cases an SVF 'RUNTEST n SCK' command 213 | has no effect. 214 | 215 | void set_trst(struct libxsvf_host *h, int v); 216 | 217 | A function to set the JTAG TRST line to the specified 218 | value: 219 | 1 ... drive the line high 220 | 0 ... drive the line low 221 | -1 ... do not drive the line (high impedance) 222 | -2 ... got SVF 'TRST ABSENT' command 223 | 224 | This function is optional and the function pointer may 225 | be set to a NULL pointer on implementations without an 226 | TRST line. In this cases an SVF 'TRST' command has no 227 | effect. 228 | 229 | int set_frequency(struct libxsvf_host *h, int v); 230 | 231 | A function to set the JTAG CLK frequency to the specified 232 | value in Hz. This function should return 0 when setting 233 | the frequency was successful and -1 on error. 234 | 235 | This function pointer is optional (may be set to NULL). 236 | In this case an SVF FREQUENCY command always results in 237 | an error. 238 | 239 | void report_tapstate(struct libxsvf_host *h); 240 | 241 | This function is called whenever the state of the TAP 242 | state machine has changed. The TAP state can be read 243 | using the h->tap_state enum. 244 | 245 | This function pointer is optional (may be set to NULL) 246 | and is for debugging purposes only. 247 | 248 | void report_device(struct libxsvf_host *h, unsigned long idcode); 249 | 250 | This function is called in scan mode for each device found 251 | in the JTAG chain. 252 | 253 | This function pointer is optional (may be set to NULL) 254 | and is only called in the SCAN mode. 255 | 256 | void report_status(struct libxsvf_host *h, const char *message); 257 | 258 | This function is called each time before an SVF or XSVF 259 | command is executed. 260 | 261 | This function pointer is optional (may be set to NULL) 262 | and is for debugging purposes only. 263 | 264 | void report_error(struct libxsvf_host *h, const char *file, int line, const char *message); 265 | 266 | This function is called whenever an error is detected 267 | in libxsvf. It is not optional and should provide a 268 | way to notify a user about the error. 269 | 270 | void *realloc(struct libxsvf_host *h, void *ptr, int size, enum libxsvf_mem which); 271 | 272 | This function must provide a way to allocate dynamic 273 | memory. In cases where there is a standard c library 274 | it may be a simple wrapper for the realloc() function. 275 | 276 | The xsvftool-gpio command line option '-r' can be used to 277 | auto-generate a realloc function for static buffers, based 278 | on the requirements from an example svf or xsvf file. 279 | Example given: 280 | 281 | ./xsvftool-gpio -r my_host_realloc -s demo.svf 282 | 283 | (Re-)allocation may fail. In this cases a NULL pointer 284 | must be returned. The library then generates an error, 285 | frees all resources and returns. 286 | 287 | After such a struct is prepared, the function libxsvf_play() 288 | can be called, passing the libxsvf_host struct as first and the 289 | mode (LIBXSVF_MODE_SVF, LIBXSVF_MODE_XSVF or LIBXSVF_MODE_SCAN) 290 | as second argument. 291 | 292 | Example given: 293 | 294 | if (libxsvf_play(&h, LIBXSVF_MODE_XSVF) < 0) { 295 | /* Error handling */ 296 | } 297 | 298 | The libxsvf_host struct is passed back to all callback functions 299 | and the 'user_data' member (a void pointer) can be used to pass 300 | additional data (such as a file handle) to the callbacks. 301 | 302 | 303 | Host accessor macros 304 | -------------------- 305 | 306 | Despite its great flexibility, APIs based on callback functions 307 | as the one used by libxsvf are unusual in the embedded community. 308 | Basically because they introduce a slight overhead in the memory 309 | footprint. 310 | 311 | For those who prefer a more direct integration with their host 312 | environments libxsvf also provides 'host accessor macros' in the 313 | libxsvf.h header file. Simply remove the callback functions from 314 | the libxsvf_host struct and modify the LIBXSVF_HOST_ macros 315 | to fit your needs. 316 | 317 | 318 | Using libxsvf with asynchronous interfaces 319 | ------------------------------------------ 320 | 321 | This library has been designed at first for a register mapped bit banging 322 | interface as it can be found on many microcontrollers or host CPUs. But 323 | some interfaces might require the JTAG data to be send and recivied in 324 | blocks and/or asynchronously. This is not trivial with this library because the 325 | pulse_tck() callback function is expected to transfer one single bit at a time. 326 | The solution to this is to buffer all data sent to pulse_tck() and always 327 | return a valid status (i.e. 'tdo < 0 ? 1 : tdo') and do the transfers when the 328 | buffer is full or when an interface shutdown is requested. 329 | 330 | However, some JTAG transaction must be performed synchronously (e.g. the last 331 | transaction in an XSVF XREPEAT data shift. In this cases pulse_tck() is called 332 | with the 'sync' argument set to 1. The pulse_tck() function must then perform 333 | all buffered JTAG transactions and return the actual tdo value for this last 334 | JTAG transaction or -1 if an error was detected before. 335 | 336 | An asynchronous interface binding also must implement the sync() function. It 337 | must perform all buffered JTAG transactions and return -1 if a TDO error was 338 | detected an 0 otherwise. 339 | 340 | Note: The returncode of pulse_tck is not checked in all conditions! So whenever 341 | an error is detected all further calls to pulse_tck() up to and including 342 | the next call of pulse_tck() with the 'sync' argument set or the next call to 343 | sync() or shutdown() must return -1. 344 | 345 | Have a look at the example program 'xsvftool-ft232h.c' for a reference 346 | implementation. 347 | 348 | 349 | Stripping down libxsvf 350 | ---------------------- 351 | 352 | It is possible to disable SVF, XSVF and/or SCAN support by setting the 353 | LIBXSVF_WITHOUT_SVF, LIBXSVF_WITHOUT_XSVF or LIBXSVF_WITHOUT_SCAN 354 | defines. In this cases one would not want to link against svf.o, xsvf.o 355 | or scan.o. 356 | 357 | One does not need to link agains statename.o and memname.o if the 358 | libxsvf_state2str() and libxsvf_mem2str() functions are not needed. 359 | Usually this functions are used for debugging purposes only. 360 | 361 | It is possible to modify the LIBXSVF_HOST_REPORT_STATUS() and 362 | LIBXSVF_HOST_REPORT_ERROR() macros in libxsvf.h to be empty 363 | instructions. This drastically reduces the number of string 364 | constants in the code. 365 | 366 | -------------------------------------------------------------------------------- /src/libxsvf/xsvf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Lib(X)SVF - A library for implementing SVF and XSVF JTAG players 3 | * 4 | * Copyright (C) 2009 RIEGL Research ForschungsGmbH 5 | * Copyright (C) 2009 Clifford Wolf 6 | * 7 | * Permission to use, copy, modify, and/or distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | * 19 | */ 20 | 21 | #include "libxsvf.h" 22 | 23 | /* command codes as defined in xilinx xapp503 */ 24 | enum xsvf_cmd { 25 | XCOMPLETE = 0x00, 26 | XTDOMASK = 0x01, 27 | XSIR = 0x02, 28 | XSDR = 0x03, 29 | XRUNTEST = 0x04, 30 | XREPEAT = 0x07, 31 | XSDRSIZE = 0x08, 32 | XSDRTDO = 0x09, 33 | XSETSDRMASKS = 0x0A, 34 | XSDRINC = 0x0B, 35 | XSDRB = 0x0C, 36 | XSDRC = 0x0D, 37 | XSDRE = 0x0E, 38 | XSDRTDOB = 0x0F, 39 | XSDRTDOC = 0x10, 40 | XSDRTDOE = 0x11, 41 | XSTATE = 0x12, 42 | XENDIR = 0x13, 43 | XENDDR = 0x14, 44 | XSIR2 = 0x15, 45 | XCOMMENT = 0x16, 46 | XWAIT = 0x17, 47 | /* Extensions used in svf2xsvf.py */ 48 | XWAITSTATE = 0x18, 49 | XTRST = 0x1c 50 | }; 51 | 52 | // This is to not confuse the VIM syntax highlighting 53 | #define VAL_OPEN ( 54 | #define VAL_CLOSE ) 55 | 56 | #define READ_BITS(_buf, _len) do { \ 57 | unsigned char *_p = _buf; int _i; \ 58 | for (_i=0; _i<(_len); _i+=8) { \ 59 | int tmp = LIBXSVF_HOST_GETBYTE(); \ 60 | if (tmp < 0) { \ 61 | LIBXSVF_HOST_REPORT_ERROR("Unexpected EOF."); \ 62 | goto error; \ 63 | } \ 64 | *(_p++) = tmp; \ 65 | } \ 66 | } while (0) 67 | 68 | #define READ_LONG() VAL_OPEN{ \ 69 | long _buf = 0; int _i; \ 70 | for (_i=0; _i<4; _i++) { \ 71 | int tmp = LIBXSVF_HOST_GETBYTE(); \ 72 | if (tmp < 0) { \ 73 | LIBXSVF_HOST_REPORT_ERROR("Unexpected EOF."); \ 74 | goto error; \ 75 | } \ 76 | _buf = _buf << 8 | tmp; \ 77 | } \ 78 | _buf; \ 79 | }VAL_CLOSE 80 | 81 | #define READ_BYTE() VAL_OPEN{ \ 82 | int _tmp = LIBXSVF_HOST_GETBYTE(); \ 83 | if (_tmp < 0) { \ 84 | LIBXSVF_HOST_REPORT_ERROR("Unexpected EOF."); \ 85 | goto error; \ 86 | } \ 87 | _tmp; \ 88 | }VAL_CLOSE 89 | 90 | #define SHIFT_DATA(_inp, _outp, _maskp, _len, _state, _estate, _edelay, _ret) do { \ 91 | if (shift_data(h, _inp, _outp, _maskp, _len, _state, _estate, _edelay, _ret) < 0) { \ 92 | goto error; \ 93 | } \ 94 | } while (0) 95 | 96 | #define TAP(_state) do { \ 97 | if (libxsvf_tap_walk(h, _state) < 0) \ 98 | goto error; \ 99 | } while (0) 100 | 101 | static int bits2bytes(int bits) 102 | { 103 | return (bits+7) / 8; 104 | } 105 | 106 | static int getbit(unsigned char *data, int n) 107 | { 108 | return (data[n/8] & (1 << (7 - n%8))) ? 1 : 0; 109 | } 110 | 111 | static void setbit(unsigned char *data, int n, int v) 112 | { 113 | unsigned char mask = 1 << (7 - n%8); 114 | if (v) 115 | data[n/8] |= mask; 116 | else 117 | data[n/8] &= ~mask; 118 | } 119 | 120 | static int xilinx_tap(int state) 121 | { 122 | /* state codes as defined in xilinx xapp503 */ 123 | switch (state) 124 | { 125 | case 0x00: 126 | return LIBXSVF_TAP_RESET; 127 | break; 128 | case 0x01: 129 | return LIBXSVF_TAP_IDLE; 130 | break; 131 | case 0x02: 132 | return LIBXSVF_TAP_DRSELECT; 133 | break; 134 | case 0x03: 135 | return LIBXSVF_TAP_DRCAPTURE; 136 | break; 137 | case 0x04: 138 | return LIBXSVF_TAP_DRSHIFT; 139 | break; 140 | case 0x05: 141 | return LIBXSVF_TAP_DREXIT1; 142 | break; 143 | case 0x06: 144 | return LIBXSVF_TAP_DRPAUSE; 145 | break; 146 | case 0x07: 147 | return LIBXSVF_TAP_DREXIT2; 148 | break; 149 | case 0x08: 150 | return LIBXSVF_TAP_DRUPDATE; 151 | break; 152 | case 0x09: 153 | return LIBXSVF_TAP_IRSELECT; 154 | break; 155 | case 0x0A: 156 | return LIBXSVF_TAP_IRCAPTURE; 157 | break; 158 | case 0x0B: 159 | return LIBXSVF_TAP_IRSHIFT; 160 | break; 161 | case 0x0C: 162 | return LIBXSVF_TAP_IREXIT1; 163 | break; 164 | case 0x0D: 165 | return LIBXSVF_TAP_IRPAUSE; 166 | break; 167 | case 0x0E: 168 | return LIBXSVF_TAP_IREXIT2; 169 | break; 170 | case 0x0F: 171 | return LIBXSVF_TAP_IRUPDATE; 172 | break; 173 | } 174 | return -1; 175 | } 176 | 177 | static int shift_data(struct libxsvf_host *h, unsigned char *inp, unsigned char *outp, unsigned char *maskp, int len, enum libxsvf_tap_state state, enum libxsvf_tap_state estate, int edelay, int retries) 178 | { 179 | int left_padding = (8 - len % 8) % 8; 180 | int with_retries = retries > 0; 181 | int i; 182 | 183 | if (with_retries && LIBXSVF_HOST_SYNC() < 0) { 184 | LIBXSVF_HOST_REPORT_ERROR("TDO mismatch."); 185 | return -1; 186 | } 187 | 188 | while (1) 189 | { 190 | int tdo_error = 0; 191 | int tms = 0; 192 | 193 | TAP(state); 194 | tms = 0; 195 | 196 | for (i=len+left_padding-1; i>=left_padding; i--) { 197 | if (i == left_padding && h->tap_state != estate) { 198 | h->tap_state++; 199 | tms = 1; 200 | } 201 | int tdi = getbit(inp, i); 202 | int tdo = -1; 203 | if (maskp && getbit(maskp, i)) 204 | tdo = outp && getbit(outp, i); 205 | int sync = with_retries && i == left_padding; 206 | if (LIBXSVF_HOST_PULSE_TCK(tms, tdi, tdo, 0, sync) < 0) 207 | tdo_error = 1; 208 | } 209 | 210 | if (tms) 211 | LIBXSVF_HOST_REPORT_TAPSTATE(); 212 | 213 | if (edelay) { 214 | TAP(LIBXSVF_TAP_IDLE); 215 | LIBXSVF_HOST_UDELAY(edelay, 0, edelay); 216 | } else { 217 | TAP(estate); 218 | } 219 | 220 | if (!tdo_error) 221 | return 0; 222 | 223 | if (retries <= 0) { 224 | LIBXSVF_HOST_REPORT_ERROR("TDO mismatch."); 225 | return -1; 226 | } 227 | 228 | retries--; 229 | } 230 | 231 | error: 232 | return -1; 233 | } 234 | 235 | int libxsvf_xsvf(struct libxsvf_host *h) 236 | { 237 | int rc = 0; 238 | int i, j; 239 | 240 | unsigned char *buf_tdi_data = (void*)0; 241 | unsigned char *buf_tdo_data = (void*)0; 242 | unsigned char *buf_tdo_mask = (void*)0; 243 | unsigned char *buf_addr_mask = (void*)0; 244 | unsigned char *buf_data_mask = (void*)0; 245 | 246 | long state_dr_size = 0; 247 | long state_data_size = 0; 248 | long state_runtest = 0; 249 | unsigned char state_xendir = 0; 250 | unsigned char state_xenddr = 0; 251 | unsigned char state_retries = 0; 252 | unsigned char cmd = 0; 253 | 254 | while (1) 255 | { 256 | unsigned char last_cmd = cmd; 257 | cmd = LIBXSVF_HOST_GETBYTE(); 258 | 259 | #define STATUS(_c) LIBXSVF_HOST_REPORT_STATUS("XSVF Command " #_c); 260 | 261 | switch (cmd) 262 | { 263 | case XCOMPLETE: { 264 | STATUS(XCOMPLETE); 265 | goto got_complete_command; 266 | } 267 | case XTDOMASK: { 268 | STATUS(XTDOMASK); 269 | READ_BITS(buf_tdo_mask, state_dr_size); 270 | break; 271 | } 272 | case XSIR: { 273 | STATUS(XSIR); 274 | int length = READ_BYTE(); 275 | unsigned char buf[bits2bytes(length)]; 276 | READ_BITS(buf, length); 277 | SHIFT_DATA(buf, (void*)0, (void*)0, length, LIBXSVF_TAP_IRSHIFT, 278 | state_xendir ? LIBXSVF_TAP_IRPAUSE : LIBXSVF_TAP_IDLE, 279 | state_runtest, state_retries); 280 | break; 281 | } 282 | case XSDR: { 283 | STATUS(XSDR); 284 | READ_BITS(buf_tdi_data, state_dr_size); 285 | SHIFT_DATA(buf_tdi_data, buf_tdo_data, buf_tdo_mask, state_dr_size, LIBXSVF_TAP_DRSHIFT, 286 | state_xenddr ? LIBXSVF_TAP_DRPAUSE : LIBXSVF_TAP_IDLE, 287 | state_runtest, state_retries); 288 | break; 289 | } 290 | case XRUNTEST: { 291 | STATUS(XRUNTEST); 292 | state_runtest = READ_LONG(); 293 | break; 294 | } 295 | case XREPEAT: { 296 | STATUS(XREPEAT); 297 | state_retries = READ_BYTE(); 298 | break; 299 | } 300 | case XSDRSIZE: { 301 | STATUS(XSDRSIZE); 302 | state_dr_size = READ_LONG(); 303 | buf_tdi_data = LIBXSVF_HOST_REALLOC(buf_tdi_data, bits2bytes(state_dr_size), LIBXSVF_MEM_XSVF_TDI_DATA); 304 | buf_tdo_data = LIBXSVF_HOST_REALLOC(buf_tdo_data, bits2bytes(state_dr_size), LIBXSVF_MEM_XSVF_TDO_DATA); 305 | buf_tdo_mask = LIBXSVF_HOST_REALLOC(buf_tdo_mask, bits2bytes(state_dr_size), LIBXSVF_MEM_XSVF_TDO_MASK); 306 | buf_addr_mask = LIBXSVF_HOST_REALLOC(buf_addr_mask, bits2bytes(state_dr_size), LIBXSVF_MEM_XSVF_ADDR_MASK); 307 | buf_data_mask = LIBXSVF_HOST_REALLOC(buf_data_mask, bits2bytes(state_dr_size), LIBXSVF_MEM_XSVF_DATA_MASK); 308 | if (!buf_tdi_data || !buf_tdo_data || !buf_tdo_mask || !buf_addr_mask || !buf_data_mask) { 309 | LIBXSVF_HOST_REPORT_ERROR("Allocating memory failed."); 310 | goto error; 311 | } 312 | break; 313 | } 314 | case XSDRTDO: { 315 | STATUS(XSDRTDO); 316 | READ_BITS(buf_tdi_data, state_dr_size); 317 | READ_BITS(buf_tdo_data, state_dr_size); 318 | SHIFT_DATA(buf_tdi_data, buf_tdo_data, buf_tdo_mask, state_dr_size, LIBXSVF_TAP_DRSHIFT, 319 | state_xenddr ? LIBXSVF_TAP_DRPAUSE : LIBXSVF_TAP_IDLE, 320 | state_runtest, state_retries); 321 | break; 322 | } 323 | case XSETSDRMASKS: { 324 | STATUS(XSETSDRMASKS); 325 | READ_BITS(buf_addr_mask, state_dr_size); 326 | READ_BITS(buf_data_mask, state_dr_size); 327 | state_data_size = 0; 328 | for (i=0; i=0; i--) { 344 | if (getbit(buf_addr_mask, i) == 0) 345 | continue; 346 | if (getbit(buf_tdi_data, i)) { 347 | setbit(buf_tdi_data, i, !carry); 348 | } else { 349 | setbit(buf_tdi_data, i, carry); 350 | carry = 0; 351 | } 352 | } 353 | unsigned char this_byte = 0; 354 | for (i=0, j=0; i= 0 ) { 474 | LIBXSVF_HOST_REPORT_ERROR("TDO mismatch."); 475 | rc = -1; 476 | } 477 | 478 | LIBXSVF_HOST_REALLOC(buf_tdi_data, 0, LIBXSVF_MEM_XSVF_TDI_DATA); 479 | LIBXSVF_HOST_REALLOC(buf_tdo_data, 0, LIBXSVF_MEM_XSVF_TDO_DATA); 480 | LIBXSVF_HOST_REALLOC(buf_tdo_mask, 0, LIBXSVF_MEM_XSVF_TDO_MASK); 481 | LIBXSVF_HOST_REALLOC(buf_addr_mask, 0, LIBXSVF_MEM_XSVF_ADDR_MASK); 482 | LIBXSVF_HOST_REALLOC(buf_data_mask, 0, LIBXSVF_MEM_XSVF_DATA_MASK); 483 | 484 | return rc; 485 | } 486 | 487 | -------------------------------------------------------------------------------- /src/libxsvf/svf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Lib(X)SVF - A library for implementing SVF and XSVF JTAG players 3 | * 4 | * Copyright (C) 2009 RIEGL Research ForschungsGmbH 5 | * Copyright (C) 2009 Clifford Wolf 6 | * 7 | * Permission to use, copy, modify, and/or distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | * 19 | */ 20 | 21 | #include "libxsvf.h" 22 | #include 23 | 24 | /* 25 | this function will filter out comments, whitespaces 26 | nad line terminations and return one by one command as 27 | contiguous string in the buffer. 28 | return value: 29 | -2 buffer empty. try again later 30 | -1 error or unexpected EOF 31 | 0 expected EOF, normal end of data 32 | 1 normal data, proceed with processing 33 | */ 34 | static int read_command(struct libxsvf_host *h, char **buffer_p, int *len_p) 35 | { 36 | char *buffer = *buffer_p; 37 | int len; 38 | static int braket_mode = 0; 39 | static int comment_mode = 0; 40 | static int p = 0; 41 | if(len_p == NULL) 42 | { 43 | p = 0; 44 | braket_mode = 0; 45 | comment_mode = 0; 46 | return 0; 47 | } 48 | 49 | len = *len_p; 50 | 51 | while (1) 52 | { 53 | if (len < p+10) { 54 | len = len < 64 ? 96 : len*2; 55 | buffer = LIBXSVF_HOST_REALLOC(buffer, len, LIBXSVF_MEM_SVF_COMMANDBUF); 56 | *buffer_p = buffer; 57 | *len_p = len; 58 | if (!buffer) { 59 | LIBXSVF_HOST_REPORT_ERROR("Allocating memory failed."); 60 | p = 0; 61 | return -1; 62 | } 63 | } 64 | buffer[p] = 0; 65 | 66 | int ch = LIBXSVF_HOST_GETBYTE(); 67 | if (ch < 0) { 68 | handle_eof: 69 | if (ch == -2) /* temporary buffer empty */ 70 | return -2; /* keep value of 'p', exit now and try again later */ 71 | if (p == 0) 72 | return 0; 73 | p = 0; 74 | comment_mode = 0; 75 | braket_mode = 0; 76 | LIBXSVF_HOST_REPORT_ERROR("Unexpected EOF."); 77 | return -1; 78 | } 79 | if (comment_mode != 0) 80 | { 81 | if (ch < 0) 82 | goto handle_eof; 83 | if (ch < ' ' && ch != '\t') 84 | goto insert_eol; 85 | continue; // keep running while() loop 86 | } 87 | if (ch <= ' ') { 88 | insert_eol: 89 | if (comment_mode == 0 && braket_mode == 0 && p > 0 && buffer[p-1] != ' ') 90 | buffer[p++] = ' '; 91 | comment_mode = 0; 92 | continue; // keep running while() loop 93 | } 94 | if (ch == '!') { 95 | comment_mode = 1; 96 | continue; // keep running while() loop 97 | } 98 | if (ch == '/' && p > 0 && buffer[p-1] == '/') { 99 | p--; 100 | comment_mode = 1; 101 | continue; // keep running while() loop 102 | } 103 | if (ch == ';') 104 | break; // exit while loop immediately 105 | if (ch == '(') { 106 | if (!braket_mode && p > 0 && buffer[p-1] != ' ') 107 | buffer[p++] = ' '; 108 | braket_mode++; 109 | } 110 | if (ch >= 'a' && ch <= 'z') 111 | buffer[p++] = ch - ('a' - 'A'); 112 | else 113 | buffer[p++] = ch; 114 | if (ch == ')') { 115 | braket_mode--; 116 | if (!braket_mode) 117 | buffer[p++] = ' '; 118 | } 119 | } 120 | p = 0; 121 | return 1; 122 | } 123 | 124 | static int strtokencmp(const char *str1, const char *str2) 125 | { 126 | int i = 0; 127 | while (1) { 128 | if ((str1[i] == ' ' || str1[i] == 0) && (str2[i] == ' ' || str2[i] == 0)) 129 | return 0; 130 | if (str1[i] < str2[i]) 131 | return -1; 132 | if (str1[i] > str2[i]) 133 | return +1; 134 | i++; 135 | } 136 | } 137 | 138 | static int strtokenskip(const char *str1) 139 | { 140 | int i = 0; 141 | while (str1[i] != 0 && str1[i] != ' ') i++; 142 | while (str1[i] == ' ') i++; 143 | return i; 144 | } 145 | 146 | static int token2tapstate(const char *str1) 147 | { 148 | #define X(_t) if (!strtokencmp(str1, #_t)) return LIBXSVF_TAP_ ## _t; 149 | X(RESET) 150 | X(IDLE) 151 | X(DRSELECT) 152 | X(DRCAPTURE) 153 | X(DRSHIFT) 154 | X(DREXIT1) 155 | X(DRPAUSE) 156 | X(DREXIT2) 157 | X(DRUPDATE) 158 | X(IRSELECT) 159 | X(IRCAPTURE) 160 | X(IRSHIFT) 161 | X(IREXIT1) 162 | X(IRPAUSE) 163 | X(IREXIT2) 164 | X(IRUPDATE) 165 | #undef X 166 | return -1; 167 | } 168 | 169 | struct bitdata_s { 170 | int len, alloced_len; 171 | int alloced_bytes; 172 | unsigned char *tdi_data; 173 | unsigned char *tdi_mask; 174 | unsigned char *tdo_data; 175 | unsigned char *tdo_mask; 176 | unsigned char *ret_mask; 177 | int has_tdo_data; 178 | }; 179 | 180 | static void bitdata_zero(struct libxsvf_host *h, struct bitdata_s *bd) 181 | { 182 | bd->len = 0; 183 | #if 0 184 | // we don't initialize this at start of each 185 | // file upload to avoid memory leaks from 186 | // lost memory allocation information in case 187 | // connection is lost. 188 | // Realloc will always be called on 189 | // bitdata pointers. 190 | // static initializer will set them 191 | // at zero (NULL) so first realloc will effectively 192 | // do malloc for the first time and they are supposed 193 | // to be realloced many times. Only when tey are free()'d 194 | // (realloced to 0-size) then they can be overwritten with zero 195 | bd->alloced_len = 0; 196 | bd->alloced_bytes = 0; 197 | if(bd->tdi_data) 198 | LIBXSVF_HOST_REPORT_ERROR("Leak warning: Zeroing allocated bd->tdi_data"); 199 | if(bd->tdi_mask) 200 | LIBXSVF_HOST_REPORT_ERROR("Leak warning: Zeroing allocated bd->tdi_mask"); 201 | if(bd->tdo_data) 202 | LIBXSVF_HOST_REPORT_ERROR("Leak warning: Zeroing allocated bd->tdo_data"); 203 | if(bd->tdo_mask) 204 | LIBXSVF_HOST_REPORT_ERROR("Leak warning: Zeroing allocated bd->tdo_mask"); 205 | if(bd->ret_mask) 206 | LIBXSVF_HOST_REPORT_ERROR("Leak warning: Zeroing allocated bd->ret_mask"); 207 | bd->tdi_data = (void*)0; 208 | bd->tdi_mask = (void*)0; 209 | bd->tdo_data = (void*)0; 210 | bd->tdo_mask = (void*)0; 211 | bd->ret_mask = (void*)0; 212 | #endif 213 | bd->has_tdo_data = 0; 214 | } 215 | 216 | static void bitdata_free(struct libxsvf_host *h, struct bitdata_s *bd, int offset) 217 | { 218 | LIBXSVF_HOST_REALLOC(bd->tdi_data, 0, offset+0); 219 | LIBXSVF_HOST_REALLOC(bd->tdi_mask, 0, offset+1); 220 | LIBXSVF_HOST_REALLOC(bd->tdo_data, 0, offset+2); 221 | LIBXSVF_HOST_REALLOC(bd->tdo_mask, 0, offset+3); 222 | LIBXSVF_HOST_REALLOC(bd->ret_mask, 0, offset+4); 223 | 224 | bd->tdi_data = (void*)0; 225 | bd->tdi_mask = (void*)0; 226 | bd->tdo_data = (void*)0; 227 | bd->tdo_mask = (void*)0; 228 | bd->ret_mask = (void*)0; 229 | } 230 | 231 | static int hex(char ch) 232 | { 233 | if (ch >= 'A' && ch <= 'Z') 234 | return (ch - 'A') + 10; 235 | if (ch >= '0' && ch <= '9') 236 | return ch - '0'; 237 | return 0; 238 | } 239 | 240 | static const char *bitdata_parse(struct libxsvf_host *h, const char *p, struct bitdata_s *bd, int offset) 241 | { 242 | int i, j; 243 | bd->len = 0; 244 | bd->has_tdo_data = 0; 245 | while (*p >= '0' && *p <= '9') { 246 | bd->len = bd->len * 10 + (*p - '0'); 247 | p++; 248 | } 249 | while (*p == ' ') { 250 | p++; 251 | } 252 | if (bd->len != bd->alloced_len) { 253 | bd->alloced_len = bd->len; 254 | bd->alloced_bytes = (bd->len+7) / 8; 255 | } 256 | while (*p) 257 | { 258 | int memnum = 0; 259 | unsigned char **dp = (void*)0; 260 | if (!strtokencmp(p, "TDI")) { 261 | p += strtokenskip(p); 262 | dp = &bd->tdi_data; 263 | memnum = 0; 264 | } 265 | if (!strtokencmp(p, "TDO")) { 266 | p += strtokenskip(p); 267 | dp = &bd->tdo_data; 268 | bd->has_tdo_data = 1; 269 | memnum = 1; 270 | } 271 | if (!strtokencmp(p, "SMASK")) { 272 | p += strtokenskip(p); 273 | dp = &bd->tdi_mask; 274 | memnum = 2; 275 | } 276 | if (!strtokencmp(p, "MASK")) { 277 | p += strtokenskip(p); 278 | dp = &bd->tdo_mask; 279 | memnum = 3; 280 | } 281 | if (!strtokencmp(p, "RMASK")) { 282 | p += strtokenskip(p); 283 | dp = &bd->ret_mask; 284 | memnum = 4; 285 | } 286 | if (!dp) 287 | return (void*)0; 288 | *dp = LIBXSVF_HOST_REALLOC(*dp, bd->alloced_bytes, offset+memnum); 289 | if (*dp == (void*)0) { 290 | LIBXSVF_HOST_REPORT_ERROR("Allocating memory failed."); 291 | return (void*)0; 292 | } 293 | 294 | unsigned char *d = *dp; 295 | for (i=0; ialloced_bytes; i++) 296 | d[i] = 0; 297 | 298 | if (*p != '(') 299 | return (void*)0; 300 | p++; 301 | 302 | int hexdigits = 0; 303 | for (i=0; (p[i] >= 'A' && p[i] <= 'F') || (p[i] >= '0' && p[i] <= '9'); i++) 304 | hexdigits++; 305 | 306 | i = bd->alloced_bytes*2 - hexdigits; 307 | for (j=0; j */ 324 | printf("--- Parsed bitdata [%d] ---\n", bd->len); 325 | if (bd->tdi_data) { 326 | printf("TDI DATA:"); 327 | for (i=0; ialloced_bytes; i++) 328 | printf(" %02x", bd->tdi_data[i]); 329 | printf("\n"); 330 | } 331 | if (bd->tdo_data && has_tdo_data) { 332 | printf("TDO DATA:"); 333 | for (i=0; ialloced_bytes; i++) 334 | printf(" %02x", bd->tdo_data[i]); 335 | printf("\n"); 336 | } 337 | if (bd->tdi_mask) { 338 | printf("TDI MASK:"); 339 | for (i=0; ialloced_bytes; i++) 340 | printf(" %02x", bd->tdi_mask[i]); 341 | printf("\n"); 342 | } 343 | if (bd->tdo_mask) { 344 | printf("TDO MASK:"); 345 | for (i=0; ialloced_bytes; i++) 346 | printf(" %02x", bd->tdo_mask[i]); 347 | printf("\n"); 348 | } 349 | #endif 350 | return p; 351 | } 352 | 353 | static int getbit(unsigned char *data, int n) 354 | { 355 | return (data[n/8] & (1 << (7 - n%8))) ? 1 : 0; 356 | } 357 | 358 | static int bitdata_play(struct libxsvf_host *h, struct bitdata_s *bd, enum libxsvf_tap_state estate) 359 | { 360 | int left_padding = (8 - bd->len % 8) % 8; 361 | int tdo_error = 0; 362 | int tms = 0; 363 | int i; 364 | 365 | for (i=bd->len+left_padding-1; i >= left_padding; i--) { 366 | if (i == left_padding && h->tap_state != estate) { 367 | h->tap_state++; 368 | tms = 1; 369 | } 370 | int tdi = -1; 371 | if (bd->tdi_data) { 372 | if (!bd->tdi_mask || getbit(bd->tdi_mask, i)) 373 | tdi = getbit(bd->tdi_data, i); 374 | } 375 | int tdo = -1; 376 | if (bd->tdo_data && bd->has_tdo_data && (!bd->tdo_mask || getbit(bd->tdo_mask, i))) 377 | tdo = getbit(bd->tdo_data, i); 378 | int rmask = bd->ret_mask && getbit(bd->ret_mask, i); 379 | if (LIBXSVF_HOST_PULSE_TCK(tms, tdi, tdo, rmask, 0) < 0) 380 | tdo_error = 1; 381 | } 382 | 383 | if (tms) 384 | LIBXSVF_HOST_REPORT_TAPSTATE(); 385 | 386 | if (!tdo_error) 387 | return 0; 388 | 389 | LIBXSVF_HOST_REPORT_ERROR("TDO mismatch."); 390 | return -1; 391 | } 392 | 393 | /* 394 | Streaming feed the SVF file, repeatedy call this 395 | as each data packet becomes available 396 | len is not used as length but as a command to initialize or finish 397 | Start: len == 0 398 | Normal: len > 0 399 | End: len == -1 400 | repeat-call it while return value > 0 401 | Return: -1 on error 402 | */ 403 | int libxsvf_feed(struct libxsvf_host *h, int len) 404 | { 405 | static char *command_buffer = (void*)0; 406 | static int command_buffer_len = 0; 407 | static int rc, i; 408 | 409 | static struct bitdata_s bd_hdr = { 0, 0, 0, (void*)0, (void*)0, (void*)0, (void*)0, (void*)0 }; 410 | static struct bitdata_s bd_hir = { 0, 0, 0, (void*)0, (void*)0, (void*)0, (void*)0, (void*)0 }; 411 | static struct bitdata_s bd_tdr = { 0, 0, 0, (void*)0, (void*)0, (void*)0, (void*)0, (void*)0 }; 412 | static struct bitdata_s bd_tir = { 0, 0, 0, (void*)0, (void*)0, (void*)0, (void*)0, (void*)0 }; 413 | static struct bitdata_s bd_sdr = { 0, 0, 0, (void*)0, (void*)0, (void*)0, (void*)0, (void*)0 }; 414 | static struct bitdata_s bd_sir = { 0, 0, 0, (void*)0, (void*)0, (void*)0, (void*)0, (void*)0 }; 415 | 416 | static int state_endir = LIBXSVF_TAP_IDLE; 417 | static int state_enddr = LIBXSVF_TAP_IDLE; 418 | static int state_run = LIBXSVF_TAP_IDLE; 419 | static int state_endrun = LIBXSVF_TAP_IDLE; 420 | 421 | static char cmd_reportstring[256]; 422 | 423 | if(len == 0) 424 | { 425 | /* 0 len means stream start, reset all state vars and exit */ 426 | command_buffer = (void*)0; 427 | command_buffer_len = 0; 428 | rc = 0; /* allow further processing */ 429 | 430 | bitdata_zero(h, &bd_hdr); 431 | bitdata_zero(h, &bd_hir); 432 | bitdata_zero(h, &bd_tdr); 433 | bitdata_zero(h, &bd_tir); 434 | bitdata_zero(h, &bd_sdr); 435 | bitdata_zero(h, &bd_sir); 436 | 437 | state_endir = LIBXSVF_TAP_IDLE; 438 | state_enddr = LIBXSVF_TAP_IDLE; 439 | state_run = LIBXSVF_TAP_IDLE; 440 | state_endrun = LIBXSVF_TAP_IDLE; 441 | 442 | cmd_reportstring[0] = '\0'; 443 | 444 | read_command(h, &command_buffer, NULL); /* zero buffer reading pointer */ 445 | 446 | return 0; 447 | } 448 | 449 | if(len == -1) 450 | { 451 | /* -1 len means the end of stream, free the buffers */ 452 | if (LIBXSVF_HOST_SYNC() != 0 && rc >= 0 ) { 453 | LIBXSVF_HOST_REPORT_ERROR("TDO mismatch."); 454 | rc = -1; 455 | } 456 | 457 | bitdata_free(h, &bd_hdr, LIBXSVF_MEM_SVF_HDR_TDI_DATA); 458 | bitdata_free(h, &bd_hir, LIBXSVF_MEM_SVF_HIR_TDI_DATA); 459 | bitdata_free(h, &bd_tdr, LIBXSVF_MEM_SVF_TDR_TDI_DATA); 460 | bitdata_free(h, &bd_tir, LIBXSVF_MEM_SVF_TIR_TDI_DATA); 461 | bitdata_free(h, &bd_sdr, LIBXSVF_MEM_SVF_SDR_TDI_DATA); 462 | bitdata_free(h, &bd_sir, LIBXSVF_MEM_SVF_SIR_TDI_DATA); 463 | 464 | LIBXSVF_HOST_REALLOC(command_buffer, 0, LIBXSVF_MEM_SVF_COMMANDBUF); 465 | return -1; 466 | } 467 | 468 | if(rc < 0) 469 | return rc; /* after first error, don't process anything further */ 470 | 471 | #if 0 472 | // debugging read_command() parser 473 | while(rc >= 0) 474 | { 475 | rc = read_command(h, &command_buffer, &command_buffer_len); 476 | if(rc == -2) 477 | { 478 | rc = 0; 479 | return -2; 480 | } 481 | read_command(h, &command_buffer, NULL); // reset internal p 482 | if(rc >= 0) 483 | printf(">>%s<<\n", command_buffer); 484 | } 485 | return 2; 486 | #endif 487 | 488 | /* len > 0, process chunk of data */ 489 | while (1) 490 | { 491 | rc = read_command(h, &command_buffer, &command_buffer_len); 492 | if(rc == -2) /* buffer empty */ 493 | { 494 | rc = 0; /* allow continuation when called next time */ 495 | return -2; 496 | } 497 | read_command(h, &command_buffer, NULL); // reset internal p 498 | 499 | if (rc <= 0) 500 | break; 501 | 502 | const char *p = command_buffer; 503 | 504 | LIBXSVF_HOST_REPORT_STATUS(command_buffer); 505 | 506 | if (!strtokencmp(p, "ENDIR")) { 507 | p += strtokenskip(p); 508 | state_endir = token2tapstate(p); 509 | if (state_endir < 0) 510 | goto syntax_error; 511 | p += strtokenskip(p); 512 | goto eol_check; 513 | } 514 | 515 | if (!strtokencmp(p, "ENDDR")) { 516 | p += strtokenskip(p); 517 | state_enddr = token2tapstate(p); 518 | if (state_endir < 0) 519 | goto syntax_error; 520 | p += strtokenskip(p); 521 | goto eol_check; 522 | } 523 | 524 | if (!strtokencmp(p, "FREQUENCY")) { 525 | unsigned long number = 0; 526 | int got_decimal_point = 0; 527 | int decimal_digits = 0; 528 | int exp = 0; 529 | p += strtokenskip(p); 530 | if (*p < '0' || *p > '9') 531 | goto syntax_error; 532 | while ((*p >= '0' && *p <= '9') || (*p == '.')) { 533 | if (*p == '.') { 534 | got_decimal_point = 1; 535 | } else { 536 | if (got_decimal_point) 537 | decimal_digits++; 538 | number = number*10 + (*p - '0'); 539 | } 540 | p++; 541 | } 542 | if(*p == 'E' || *p == 'e') { 543 | p++; 544 | if (*p == '+') 545 | p++; 546 | while (*p >= '0' && *p <= '9') { 547 | exp = exp*10 + (*p - '0'); 548 | p++; 549 | } 550 | exp -= decimal_digits; 551 | if (exp < 0) 552 | goto syntax_error; 553 | for(i=0; i= 0) { 607 | p += strtokenskip(p); 608 | if (got_endstate) 609 | state_endrun = st; 610 | else 611 | state_run = st; 612 | continue; 613 | } 614 | if (*p < '0' || *p > '9') 615 | goto syntax_error; 616 | int number = 0; 617 | int exp = 0, expsign = 1; 618 | int number_e6, exp_e6; 619 | while (*p >= '0' && *p <= '9') { 620 | number = number*10 + (*p - '0'); 621 | p++; 622 | } 623 | if(*p == '.') 624 | { 625 | p++; 626 | while (*p >= '0' && *p <= '9') 627 | p++; 628 | // FIXME: accept fractional part 629 | } 630 | if(*p == 'E' || *p == 'e') { 631 | p++; 632 | if(*p == '-') { 633 | expsign = -1; 634 | p++; 635 | } 636 | if(*p == '+') { 637 | expsign = 1; 638 | p++; 639 | } 640 | while (*p >= '0' && *p <= '9') { 641 | exp = exp*10 + (*p - '0'); 642 | p++; 643 | } 644 | exp = exp * expsign; 645 | number_e6 = number; 646 | exp_e6 = exp + 6; 647 | while (exp < 0) { 648 | number /= 10; 649 | exp++; 650 | } 651 | while (exp > 0) { 652 | number *= 10; 653 | exp--; 654 | } 655 | while (exp_e6 < 0) { 656 | number_e6 /= 10; 657 | exp_e6++; 658 | } 659 | while (exp_e6 > 0) { 660 | number_e6 *= 10; 661 | exp_e6--; 662 | } 663 | } else { 664 | number_e6 = number * 1000000; 665 | } 666 | while (*p == ' ') { 667 | p++; 668 | } 669 | if (!strtokencmp(p, "SEC")) { 670 | p += strtokenskip(p); 671 | if (got_maximum) 672 | max_time = number_e6; 673 | else 674 | min_time = number_e6; 675 | continue; 676 | } 677 | if (!strtokencmp(p, "TCK")) { 678 | p += strtokenskip(p); 679 | tck_count = number; 680 | continue; 681 | } 682 | if (!strtokencmp(p, "SCK")) { 683 | p += strtokenskip(p); 684 | sck_count = number; 685 | continue; 686 | } 687 | goto syntax_error; 688 | } 689 | if (libxsvf_tap_walk(h, state_run) < 0) 690 | goto error; 691 | if (max_time >= 0) { 692 | LIBXSVF_HOST_REPORT_ERROR("WARNING: Maximum time in SVF RUNTEST command is ignored."); 693 | } 694 | if (sck_count >= 0) { 695 | for (i=0; i < sck_count; i++) { 696 | LIBXSVF_HOST_PULSE_SCK(); 697 | } 698 | } 699 | if (min_time >= 0 || tck_count >= 0) { 700 | LIBXSVF_HOST_UDELAY(min_time >= 0 ? min_time : 0, 0, tck_count >= 0 ? tck_count : 0); 701 | } 702 | if (libxsvf_tap_walk(h, state_endrun) < 0) 703 | goto error; 704 | goto eol_check; 705 | } 706 | 707 | if (!strtokencmp(p, "SDR")) { 708 | p += strtokenskip(p); 709 | p = bitdata_parse(h, p, &bd_sdr, LIBXSVF_MEM_SVF_SDR_TDI_DATA); 710 | if (!p) 711 | goto syntax_error; 712 | if (libxsvf_tap_walk(h, LIBXSVF_TAP_DRSHIFT) < 0) 713 | goto error; 714 | if (bitdata_play(h, &bd_hdr, bd_sdr.len+bd_tdr.len > 0 ? LIBXSVF_TAP_DRSHIFT : state_enddr) < 0) 715 | goto error; 716 | if (bitdata_play(h, &bd_sdr, bd_tdr.len > 0 ? LIBXSVF_TAP_DRSHIFT : state_enddr) < 0) 717 | goto error; 718 | if (bitdata_play(h, &bd_tdr, state_enddr) < 0) 719 | goto error; 720 | if (libxsvf_tap_walk(h, state_enddr) < 0) 721 | goto error; 722 | goto eol_check; 723 | } 724 | 725 | if (!strtokencmp(p, "SIR")) { 726 | p += strtokenskip(p); 727 | p = bitdata_parse(h, p, &bd_sir, LIBXSVF_MEM_SVF_SIR_TDI_DATA); 728 | if (!p) 729 | goto syntax_error; 730 | if (libxsvf_tap_walk(h, LIBXSVF_TAP_IRSHIFT) < 0) 731 | goto error; 732 | if (bitdata_play(h, &bd_hir, bd_sir.len+bd_tir.len > 0 ? LIBXSVF_TAP_IRSHIFT : state_endir) < 0) 733 | goto error; 734 | if (bitdata_play(h, &bd_sir, bd_tir.len > 0 ? LIBXSVF_TAP_IRSHIFT : state_endir) < 0) 735 | goto error; 736 | if (bitdata_play(h, &bd_tir, state_endir) < 0) 737 | goto error; 738 | if (libxsvf_tap_walk(h, state_endir) < 0) 739 | goto error; 740 | goto eol_check; 741 | } 742 | 743 | if (!strtokencmp(p, "STATE")) { 744 | p += strtokenskip(p); 745 | while (*p) { 746 | int st = token2tapstate(p); 747 | if (st < 0) 748 | goto syntax_error; 749 | if (libxsvf_tap_walk(h, st) < 0) 750 | goto error; 751 | p += strtokenskip(p); 752 | } 753 | goto eol_check; 754 | } 755 | 756 | if (!strtokencmp(p, "TDR")) { 757 | p += strtokenskip(p); 758 | p = bitdata_parse(h, p, &bd_tdr, LIBXSVF_MEM_SVF_TDR_TDI_DATA); 759 | if (!p) 760 | goto syntax_error; 761 | goto eol_check; 762 | } 763 | 764 | if (!strtokencmp(p, "TIR")) { 765 | p += strtokenskip(p); 766 | p = bitdata_parse(h, p, &bd_tir, LIBXSVF_MEM_SVF_TIR_TDI_DATA); 767 | if (!p) 768 | goto syntax_error; 769 | goto eol_check; 770 | } 771 | 772 | if (!strtokencmp(p, "TRST")) { 773 | p += strtokenskip(p); 774 | if (!strtokencmp(p, "ON")) { 775 | p += strtokenskip(p); 776 | LIBXSVF_HOST_SET_TRST(1); 777 | goto eol_check; 778 | } 779 | if (!strtokencmp(p, "OFF")) { 780 | p += strtokenskip(p); 781 | LIBXSVF_HOST_SET_TRST(0); 782 | goto eol_check; 783 | } 784 | if (!strtokencmp(p, "Z")) { 785 | p += strtokenskip(p); 786 | LIBXSVF_HOST_SET_TRST(-1); 787 | goto eol_check; 788 | } 789 | if (!strtokencmp(p, "ABSENT")) { 790 | p += strtokenskip(p); 791 | LIBXSVF_HOST_SET_TRST(-2); 792 | goto eol_check; 793 | } 794 | goto syntax_error; 795 | } 796 | 797 | eol_check: 798 | while (*p == ' ') 799 | p++; 800 | if (*p == 0) 801 | continue; 802 | 803 | syntax_error: 804 | LIBXSVF_HOST_REPORT_ERROR("Syntax Error"); 805 | if (0) { 806 | unsupported_error: 807 | LIBXSVF_HOST_REPORT_ERROR("Error in SVF input: unsupported command:"); 808 | } 809 | // LIBXSVF_HOST_REPORT_ERROR(command_buffer); 810 | error: 811 | rc = -1; 812 | break; 813 | } 814 | 815 | return rc; 816 | } 817 | 818 | int libxsvf_svf_packet(struct libxsvf_host *h, int index, int final) 819 | { 820 | int rc = 1; 821 | if(index == 0) 822 | { 823 | rc = 1; 824 | /* open tap */ 825 | #if 1 826 | h->tap_state = LIBXSVF_TAP_INIT; 827 | if (LIBXSVF_HOST_SETUP() < 0) { 828 | LIBXSVF_HOST_REPORT_ERROR("Setup of JTAG interface failed."); 829 | return -1; 830 | } 831 | #endif 832 | libxsvf_feed(h, 0); // reset vars, start the stream 833 | LIBXSVF_HOST_REPORT_ERROR("Start"); 834 | } 835 | rc = libxsvf_feed(h, 1); 836 | if(final) 837 | { 838 | if(rc != -1) 839 | LIBXSVF_HOST_REPORT_ERROR("Done"); 840 | /* close tap */ 841 | #if 1 842 | libxsvf_tap_walk(h, LIBXSVF_TAP_RESET); 843 | if (LIBXSVF_HOST_SYNC() != 0 && rc >= 0 ) { 844 | LIBXSVF_HOST_REPORT_ERROR("TDO mismatch in TAP reset. (this is not possible!)"); 845 | rc = -1; 846 | } 847 | #endif 848 | LIBXSVF_HOST_SHUTDOWN(); 849 | libxsvf_feed(h, -1); // last call to finish 850 | } 851 | return rc; 852 | } 853 | 854 | /* streamable replacement for libxsvf_svf, should work the same 855 | ** first examples work, further testing is recommended 856 | */ 857 | int libxsvf_svf_stream(struct libxsvf_host *h) 858 | { 859 | int len = 1; 860 | char buf[256]; 861 | int rc = 1; 862 | libxsvf_feed(h, 0); // reset vars, start the stream 863 | while(rc > 0) 864 | rc = libxsvf_feed(h, 1); 865 | return libxsvf_feed(h, -1); // last call to finish 866 | } 867 | 868 | int libxsvf_svf(struct libxsvf_host *h) 869 | { 870 | char *command_buffer = (void*)0; 871 | int command_buffer_len = 0; 872 | int rc, i; 873 | 874 | struct bitdata_s bd_hdr = { 0, 0, 0, (void*)0, (void*)0, (void*)0, (void*)0, (void*)0 }; 875 | struct bitdata_s bd_hir = { 0, 0, 0, (void*)0, (void*)0, (void*)0, (void*)0, (void*)0 }; 876 | struct bitdata_s bd_tdr = { 0, 0, 0, (void*)0, (void*)0, (void*)0, (void*)0, (void*)0 }; 877 | struct bitdata_s bd_tir = { 0, 0, 0, (void*)0, (void*)0, (void*)0, (void*)0, (void*)0 }; 878 | struct bitdata_s bd_sdr = { 0, 0, 0, (void*)0, (void*)0, (void*)0, (void*)0, (void*)0 }; 879 | struct bitdata_s bd_sir = { 0, 0, 0, (void*)0, (void*)0, (void*)0, (void*)0, (void*)0 }; 880 | 881 | int state_endir = LIBXSVF_TAP_IDLE; 882 | int state_enddr = LIBXSVF_TAP_IDLE; 883 | int state_run = LIBXSVF_TAP_IDLE; 884 | int state_endrun = LIBXSVF_TAP_IDLE; 885 | 886 | int cmd_count = 0; 887 | char cmd_reportstring[256]; 888 | while (1) 889 | { 890 | rc = read_command(h, &command_buffer, &command_buffer_len); 891 | 892 | if (rc <= 0) 893 | break; 894 | 895 | cmd_count++; 896 | #if 0 897 | if((cmd_count % 1000) == 0) 898 | { 899 | // print progress every 1000 commands 900 | // sprintf(cmd_reportstring, "%d commands", cmd_count); 901 | LIBXSVF_HOST_REPORT_ERROR(cmd_reportstring); 902 | } 903 | #endif 904 | const char *p = command_buffer; 905 | 906 | LIBXSVF_HOST_REPORT_STATUS(command_buffer); 907 | 908 | if (!strtokencmp(p, "ENDIR")) { 909 | p += strtokenskip(p); 910 | state_endir = token2tapstate(p); 911 | if (state_endir < 0) 912 | goto syntax_error; 913 | p += strtokenskip(p); 914 | goto eol_check; 915 | } 916 | 917 | if (!strtokencmp(p, "ENDDR")) { 918 | p += strtokenskip(p); 919 | state_enddr = token2tapstate(p); 920 | if (state_endir < 0) 921 | goto syntax_error; 922 | p += strtokenskip(p); 923 | goto eol_check; 924 | } 925 | 926 | if (!strtokencmp(p, "FREQUENCY")) { 927 | unsigned long number = 0; 928 | int got_decimal_point = 0; 929 | int decimal_digits = 0; 930 | int exp = 0; 931 | p += strtokenskip(p); 932 | if (*p < '0' || *p > '9') 933 | goto syntax_error; 934 | while ((*p >= '0' && *p <= '9') || (*p == '.')) { 935 | if (*p == '.') { 936 | got_decimal_point = 1; 937 | } else { 938 | if (got_decimal_point) 939 | decimal_digits++; 940 | number = number*10 + (*p - '0'); 941 | } 942 | p++; 943 | } 944 | if(*p == 'E' || *p == 'e') { 945 | p++; 946 | if (*p == '+') 947 | p++; 948 | while (*p >= '0' && *p <= '9') { 949 | exp = exp*10 + (*p - '0'); 950 | p++; 951 | } 952 | exp -= decimal_digits; 953 | if (exp < 0) 954 | goto syntax_error; 955 | for(i=0; i= 0) { 1009 | p += strtokenskip(p); 1010 | if (got_endstate) 1011 | state_endrun = st; 1012 | else 1013 | state_run = st; 1014 | continue; 1015 | } 1016 | if (*p < '0' || *p > '9') 1017 | goto syntax_error; 1018 | int number = 0; 1019 | int exp = 0, expsign = 1; 1020 | int number_e6, exp_e6; 1021 | while (*p >= '0' && *p <= '9') { 1022 | number = number*10 + (*p - '0'); 1023 | p++; 1024 | } 1025 | if(*p == '.') 1026 | { 1027 | p++; 1028 | while (*p >= '0' && *p <= '9') 1029 | p++; 1030 | // FIXME: accept fractional part 1031 | } 1032 | if(*p == 'E' || *p == 'e') { 1033 | p++; 1034 | if(*p == '-') { 1035 | expsign = -1; 1036 | p++; 1037 | } 1038 | if(*p == '+') { 1039 | expsign = 1; 1040 | p++; 1041 | } 1042 | while (*p >= '0' && *p <= '9') { 1043 | exp = exp*10 + (*p - '0'); 1044 | p++; 1045 | } 1046 | exp = exp * expsign; 1047 | number_e6 = number; 1048 | exp_e6 = exp + 6; 1049 | while (exp < 0) { 1050 | number /= 10; 1051 | exp++; 1052 | } 1053 | while (exp > 0) { 1054 | number *= 10; 1055 | exp--; 1056 | } 1057 | while (exp_e6 < 0) { 1058 | number_e6 /= 10; 1059 | exp_e6++; 1060 | } 1061 | while (exp_e6 > 0) { 1062 | number_e6 *= 10; 1063 | exp_e6--; 1064 | } 1065 | } else { 1066 | number_e6 = number * 1000000; 1067 | } 1068 | while (*p == ' ') { 1069 | p++; 1070 | } 1071 | if (!strtokencmp(p, "SEC")) { 1072 | p += strtokenskip(p); 1073 | if (got_maximum) 1074 | max_time = number_e6; 1075 | else 1076 | min_time = number_e6; 1077 | continue; 1078 | } 1079 | if (!strtokencmp(p, "TCK")) { 1080 | p += strtokenskip(p); 1081 | tck_count = number; 1082 | continue; 1083 | } 1084 | if (!strtokencmp(p, "SCK")) { 1085 | p += strtokenskip(p); 1086 | sck_count = number; 1087 | continue; 1088 | } 1089 | goto syntax_error; 1090 | } 1091 | if (libxsvf_tap_walk(h, state_run) < 0) 1092 | goto error; 1093 | if (max_time >= 0) { 1094 | LIBXSVF_HOST_REPORT_ERROR("WARNING: Maximum time in SVF RUNTEST command is ignored."); 1095 | } 1096 | if (sck_count >= 0) { 1097 | for (i=0; i < sck_count; i++) { 1098 | LIBXSVF_HOST_PULSE_SCK(); 1099 | } 1100 | } 1101 | if (min_time >= 0 || tck_count >= 0) { 1102 | LIBXSVF_HOST_UDELAY(min_time >= 0 ? min_time : 0, 0, tck_count >= 0 ? tck_count : 0); 1103 | } 1104 | if (libxsvf_tap_walk(h, state_endrun) < 0) 1105 | goto error; 1106 | goto eol_check; 1107 | } 1108 | 1109 | if (!strtokencmp(p, "SDR")) { 1110 | p += strtokenskip(p); 1111 | p = bitdata_parse(h, p, &bd_sdr, LIBXSVF_MEM_SVF_SDR_TDI_DATA); 1112 | if (!p) 1113 | goto syntax_error; 1114 | if (libxsvf_tap_walk(h, LIBXSVF_TAP_DRSHIFT) < 0) 1115 | goto error; 1116 | if (bitdata_play(h, &bd_hdr, bd_sdr.len+bd_tdr.len > 0 ? LIBXSVF_TAP_DRSHIFT : state_enddr) < 0) 1117 | goto error; 1118 | if (bitdata_play(h, &bd_sdr, bd_tdr.len > 0 ? LIBXSVF_TAP_DRSHIFT : state_enddr) < 0) 1119 | goto error; 1120 | if (bitdata_play(h, &bd_tdr, state_enddr) < 0) 1121 | goto error; 1122 | if (libxsvf_tap_walk(h, state_enddr) < 0) 1123 | goto error; 1124 | goto eol_check; 1125 | } 1126 | 1127 | if (!strtokencmp(p, "SIR")) { 1128 | p += strtokenskip(p); 1129 | p = bitdata_parse(h, p, &bd_sir, LIBXSVF_MEM_SVF_SIR_TDI_DATA); 1130 | if (!p) 1131 | goto syntax_error; 1132 | if (libxsvf_tap_walk(h, LIBXSVF_TAP_IRSHIFT) < 0) 1133 | goto error; 1134 | if (bitdata_play(h, &bd_hir, bd_sir.len+bd_tir.len > 0 ? LIBXSVF_TAP_IRSHIFT : state_endir) < 0) 1135 | goto error; 1136 | if (bitdata_play(h, &bd_sir, bd_tir.len > 0 ? LIBXSVF_TAP_IRSHIFT : state_endir) < 0) 1137 | goto error; 1138 | if (bitdata_play(h, &bd_tir, state_endir) < 0) 1139 | goto error; 1140 | if (libxsvf_tap_walk(h, state_endir) < 0) 1141 | goto error; 1142 | goto eol_check; 1143 | } 1144 | 1145 | if (!strtokencmp(p, "STATE")) { 1146 | p += strtokenskip(p); 1147 | while (*p) { 1148 | int st = token2tapstate(p); 1149 | if (st < 0) 1150 | goto syntax_error; 1151 | if (libxsvf_tap_walk(h, st) < 0) 1152 | goto error; 1153 | p += strtokenskip(p); 1154 | } 1155 | goto eol_check; 1156 | } 1157 | 1158 | if (!strtokencmp(p, "TDR")) { 1159 | p += strtokenskip(p); 1160 | p = bitdata_parse(h, p, &bd_tdr, LIBXSVF_MEM_SVF_TDR_TDI_DATA); 1161 | if (!p) 1162 | goto syntax_error; 1163 | goto eol_check; 1164 | } 1165 | 1166 | if (!strtokencmp(p, "TIR")) { 1167 | p += strtokenskip(p); 1168 | p = bitdata_parse(h, p, &bd_tir, LIBXSVF_MEM_SVF_TIR_TDI_DATA); 1169 | if (!p) 1170 | goto syntax_error; 1171 | goto eol_check; 1172 | } 1173 | 1174 | if (!strtokencmp(p, "TRST")) { 1175 | p += strtokenskip(p); 1176 | if (!strtokencmp(p, "ON")) { 1177 | p += strtokenskip(p); 1178 | LIBXSVF_HOST_SET_TRST(1); 1179 | goto eol_check; 1180 | } 1181 | if (!strtokencmp(p, "OFF")) { 1182 | p += strtokenskip(p); 1183 | LIBXSVF_HOST_SET_TRST(0); 1184 | goto eol_check; 1185 | } 1186 | if (!strtokencmp(p, "Z")) { 1187 | p += strtokenskip(p); 1188 | LIBXSVF_HOST_SET_TRST(-1); 1189 | goto eol_check; 1190 | } 1191 | if (!strtokencmp(p, "ABSENT")) { 1192 | p += strtokenskip(p); 1193 | LIBXSVF_HOST_SET_TRST(-2); 1194 | goto eol_check; 1195 | } 1196 | goto syntax_error; 1197 | } 1198 | 1199 | eol_check: 1200 | while (*p == ' ') 1201 | p++; 1202 | if (*p == 0) 1203 | continue; 1204 | 1205 | syntax_error: 1206 | sprintf(cmd_reportstring, "Command %d: SVF Syntax Error:", cmd_count); 1207 | LIBXSVF_HOST_REPORT_ERROR(cmd_reportstring); 1208 | if (0) { 1209 | unsupported_error: 1210 | LIBXSVF_HOST_REPORT_ERROR("Error in SVF input: unsupported command:"); 1211 | } 1212 | LIBXSVF_HOST_REPORT_ERROR(command_buffer); 1213 | error: 1214 | rc = -1; 1215 | break; 1216 | } 1217 | 1218 | if (LIBXSVF_HOST_SYNC() != 0 && rc >= 0 ) { 1219 | LIBXSVF_HOST_REPORT_ERROR("TDO mismatch."); 1220 | rc = -1; 1221 | } 1222 | 1223 | bitdata_free(h, &bd_hdr, LIBXSVF_MEM_SVF_HDR_TDI_DATA); 1224 | bitdata_free(h, &bd_hir, LIBXSVF_MEM_SVF_HIR_TDI_DATA); 1225 | bitdata_free(h, &bd_tdr, LIBXSVF_MEM_SVF_TDR_TDI_DATA); 1226 | bitdata_free(h, &bd_tir, LIBXSVF_MEM_SVF_TIR_TDI_DATA); 1227 | bitdata_free(h, &bd_sdr, LIBXSVF_MEM_SVF_SDR_TDI_DATA); 1228 | bitdata_free(h, &bd_sir, LIBXSVF_MEM_SVF_SIR_TDI_DATA); 1229 | 1230 | LIBXSVF_HOST_REALLOC(command_buffer, 0, LIBXSVF_MEM_SVF_COMMANDBUF); 1231 | 1232 | return rc; 1233 | } 1234 | 1235 | --------------------------------------------------------------------------------