From: Paul Fertser Date: Mon, 27 Jan 2014 18:07:16 +0000 (+0400) Subject: Move xsvf_tools and remote_bitbang to contrib/ X-Git-Tag: v0.8.0-rc1~17 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=6405941c9716e5f7b33417508ee9d8f62210429d;p=openocd Move xsvf_tools and remote_bitbang to contrib/ It looks like tools/ should be used only for build tools, and contrib/ is a suitable place for everything else. Change-Id: Iddaebba0acb6d66404912ec96749b46e4be643d8 Signed-off-by: Paul Fertser Reviewed-on: http://openocd.zylin.com/1906 Reviewed-by: Spencer Oliver Tested-by: Spencer Oliver --- diff --git a/contrib/remote_bitbang/remote_bitbang_sysfsgpio.c b/contrib/remote_bitbang/remote_bitbang_sysfsgpio.c new file mode 100644 index 00000000..e59a1bde --- /dev/null +++ b/contrib/remote_bitbang/remote_bitbang_sysfsgpio.c @@ -0,0 +1,408 @@ +/*************************************************************************** + * Copyright (C) 2013 Paul Fertser * + * Copyright (C) 2012 by Creative Product Design, marc @ cpdesign.com.au * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +/* + This is a test application to be used as a remote bitbang server for + the OpenOCD remote_bitbang interface driver. + + To compile run: + gcc -Wall -ansi -pedantic -std=c99 -o remote_bitbang_sysfsgpio remote_bitbang_sysfsgpio.c + + + Usage example: + + On Raspberry Pi run: + socat TCP6-LISTEN:7777,fork EXEC:"sudo ./remote_bitbang_sysfsgpio tck 11 tms 25 tdo 9 tdi 10" + + On host run: + openocd -c "interface remote_bitbang; remote_bitbang_host raspberrypi; remote_bitbang_port 7777" \ + -f target/stm32f1x.cfg + + Or if you want to test UNIX sockets, run both on Raspberry Pi: + socat UNIX-LISTEN:/tmp/remotebitbang-socket,fork EXEC:"sudo ./remote_bitbang_sysfsgpio tck 11 tms 25 tdo 9 tdi 10" + openocd -c "interface remote_bitbang; remote_bitbang_host /tmp/remotebitbang-socket" -f target/stm32f1x.cfg +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOG_ERROR(...) do { \ + fprintf(stderr, __VA_ARGS__); \ + fputc('\n', stderr); \ + } while (0) +#define LOG_WARNING(...) LOG_ERROR(__VA_ARGS__) + +#define ERROR_OK (-1) +#define ERROR_FAIL (-2) +#define ERROR_JTAG_INIT_FAILED ERROR_FAIL + +/* + * Helper func to determine if gpio number valid + * + * Assume here that there will be less than 1000 gpios on a system + */ +static int is_gpio_valid(int gpio) +{ + return gpio >= 0 && gpio < 1000; +} + +/* + * Helper func to open, write to and close a file + * name and valstr must be null terminated. + * + * Returns negative on failure. + */ +static int open_write_close(const char *name, const char *valstr) +{ + int ret; + int fd = open(name, O_WRONLY); + if (fd < 0) + return fd; + + ret = write(fd, valstr, strlen(valstr)); + close(fd); + + return ret; +} + +/* + * Helper func to unexport gpio from sysfs + */ +static void unexport_sysfs_gpio(int gpio) +{ + char gpiostr[4]; + + if (!is_gpio_valid(gpio)) + return; + + snprintf(gpiostr, sizeof(gpiostr), "%d", gpio); + if (open_write_close("/sys/class/gpio/unexport", gpiostr) < 0) + LOG_ERROR("Couldn't unexport gpio %d", gpio); + + return; +} + +/* + * Exports and sets up direction for gpio. + * If the gpio is an output, it is initialized according to init_high, + * otherwise it is ignored. + * + * If the gpio is already exported we just show a warning and continue; if + * openocd happened to crash (or was killed by user) then the gpios will not + * have been cleaned up. + */ +static int setup_sysfs_gpio(int gpio, int is_output, int init_high) +{ + char buf[40]; + char gpiostr[4]; + int ret; + + if (!is_gpio_valid(gpio)) + return ERROR_OK; + + snprintf(gpiostr, sizeof(gpiostr), "%d", gpio); + ret = open_write_close("/sys/class/gpio/export", gpiostr); + if (ret < 0) { + if (errno == EBUSY) { + LOG_WARNING("gpio %d is already exported", gpio); + } else { + LOG_ERROR("Couldn't export gpio %d", gpio); + perror("sysfsgpio: "); + return ERROR_FAIL; + } + } + + snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/direction", gpio); + ret = open_write_close(buf, is_output ? (init_high ? "high" : "low") : "in"); + if (ret < 0) { + LOG_ERROR("Couldn't set direction for gpio %d", gpio); + perror("sysfsgpio: "); + unexport_sysfs_gpio(gpio); + return ERROR_FAIL; + } + + snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", gpio); + if (is_output) + ret = open(buf, O_WRONLY | O_NONBLOCK | O_SYNC); + else + ret = open(buf, O_RDONLY | O_NONBLOCK | O_SYNC); + + if (ret < 0) + unexport_sysfs_gpio(gpio); + + return ret; +} + +/* + * file descriptors for /sys/class/gpio/gpioXX/value + * Set up during init. + */ +static int tck_fd = -1; +static int tms_fd = -1; +static int tdi_fd = -1; +static int tdo_fd = -1; +static int trst_fd = -1; +static int srst_fd = -1; + +/* + * Bitbang interface read of TDO + * + * The sysfs value will read back either '0' or '1'. The trick here is to call + * lseek to bypass buffering in the sysfs kernel driver. + */ +static int sysfsgpio_read(void) +{ + char buf[1]; + + /* important to seek to signal sysfs of new read */ + lseek(tdo_fd, 0, SEEK_SET); + int ret = read(tdo_fd, &buf, sizeof(buf)); + + if (ret < 0) { + LOG_WARNING("reading tdo failed"); + return 0; + } + + return buf[0]; +} + +/* + * Bitbang interface write of TCK, TMS, TDI + * + * Seeing as this is the only function where the outputs are changed, + * we can cache the old value to avoid needlessly writing it. + */ +static void sysfsgpio_write(int tck, int tms, int tdi) +{ + const char one[] = "1"; + const char zero[] = "0"; + + static int last_tck; + static int last_tms; + static int last_tdi; + + static int first_time; + size_t bytes_written; + + if (!first_time) { + last_tck = !tck; + last_tms = !tms; + last_tdi = !tdi; + first_time = 1; + } + + if (tdi != last_tdi) { + bytes_written = write(tdi_fd, tdi ? &one : &zero, 1); + if (bytes_written != 1) + LOG_WARNING("writing tdi failed"); + } + + if (tms != last_tms) { + bytes_written = write(tms_fd, tms ? &one : &zero, 1); + if (bytes_written != 1) + LOG_WARNING("writing tms failed"); + } + + /* write clk last */ + if (tck != last_tck) { + bytes_written = write(tck_fd, tck ? &one : &zero, 1); + if (bytes_written != 1) + LOG_WARNING("writing tck failed"); + } + + last_tdi = tdi; + last_tms = tms; + last_tck = tck; +} + +/* + * Bitbang interface to manipulate reset lines SRST and TRST + * + * (1) assert or (0) deassert reset lines + */ +static void sysfsgpio_reset(int trst, int srst) +{ + const char one[] = "1"; + const char zero[] = "0"; + size_t bytes_written; + + /* assume active low */ + if (srst_fd >= 0) { + bytes_written = write(srst_fd, srst ? &zero : &one, 1); + if (bytes_written != 1) + LOG_WARNING("writing srst failed"); + } + + /* assume active low */ + if (trst_fd >= 0) { + bytes_written = write(trst_fd, trst ? &zero : &one, 1); + if (bytes_written != 1) + LOG_WARNING("writing trst failed"); + } +} + +/* gpio numbers for each gpio. Negative values are invalid */ +static int tck_gpio = -1; +static int tms_gpio = -1; +static int tdi_gpio = -1; +static int tdo_gpio = -1; +static int trst_gpio = -1; +static int srst_gpio = -1; + +/* helper func to close and cleanup files only if they were valid/ used */ +static void cleanup_fd(int fd, int gpio) +{ + if (gpio >= 0) { + if (fd >= 0) + close(fd); + + unexport_sysfs_gpio(gpio); + } +} + +static void cleanup_all_fds(void) +{ + cleanup_fd(tck_fd, tck_gpio); + cleanup_fd(tms_fd, tms_gpio); + cleanup_fd(tdi_fd, tdi_gpio); + cleanup_fd(tdo_fd, tdo_gpio); + cleanup_fd(trst_fd, trst_gpio); + cleanup_fd(srst_fd, srst_gpio); +} + +static void process_remote_protocol(void) +{ + int c; + while (1) { + c = getchar(); + if (c == EOF || c == 'Q') /* Quit */ + break; + else if (c == 'b' || c == 'B') /* Blink */ + continue; + else if (c >= 'r' && c <= 'r' + 2) { /* Reset */ + char d = c - 'r'; + sysfsgpio_reset(!!(d & 2), + (d & 1)); + } else if (c >= '0' && c <= '0' + 7) {/* Write */ + char d = c - '0'; + sysfsgpio_write(!!(d & 4), + !!(d & 2), + (d & 1)); + } else if (c == 'R') + putchar(sysfsgpio_read()); + else + LOG_ERROR("Unknown command '%c' received", c); + } +} + +int main(int argc, char *argv[]) +{ + LOG_WARNING("SysfsGPIO remote_bitbang JTAG driver\n"); + + for (int i = 1; i < argc; i++) { + if (!strcmp(argv[i], "tck")) + tck_gpio = atoi(argv[++i]); + else if (!strcmp(argv[i], "tms")) + tms_gpio = atoi(argv[++i]); + else if (!strcmp(argv[i], "tdo")) + tdo_gpio = atoi(argv[++i]); + else if (!strcmp(argv[i], "tdi")) + tdi_gpio = atoi(argv[++i]); + else if (!strcmp(argv[i], "trst")) + trst_gpio = atoi(argv[++i]); + else if (!strcmp(argv[i], "srst")) + srst_gpio = atoi(argv[++i]); + else { + LOG_ERROR("Usage:\n%s ((tck|tms|tdo|tdi|trst|srst) num)*", argv[0]); + return -1; + } + } + + if (!(is_gpio_valid(tck_gpio) + && is_gpio_valid(tms_gpio) + && is_gpio_valid(tdi_gpio) + && is_gpio_valid(tdo_gpio))) { + if (!is_gpio_valid(tck_gpio)) + LOG_ERROR("gpio num for tck is invalid"); + if (!is_gpio_valid(tms_gpio)) + LOG_ERROR("gpio num for tms is invalid"); + if (!is_gpio_valid(tdo_gpio)) + LOG_ERROR("gpio num for tdo is invalid"); + if (!is_gpio_valid(tdi_gpio)) + LOG_ERROR("gpio num for tdi is invalid"); + + LOG_ERROR("Require tck, tms, tdi and tdo gpios to all be specified"); + return ERROR_JTAG_INIT_FAILED; + } + + /* + * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST + * as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high. + */ + tck_fd = setup_sysfs_gpio(tck_gpio, 1, 0); + if (tck_fd < 0) + goto out_error; + + tms_fd = setup_sysfs_gpio(tms_gpio, 1, 1); + if (tms_fd < 0) + goto out_error; + + tdi_fd = setup_sysfs_gpio(tdi_gpio, 1, 0); + if (tdi_fd < 0) + goto out_error; + + tdo_fd = setup_sysfs_gpio(tdo_gpio, 0, 0); + if (tdo_fd < 0) + goto out_error; + + /* assume active low */ + if (trst_gpio > 0) { + trst_fd = setup_sysfs_gpio(trst_gpio, 1, 1); + if (trst_fd < 0) + goto out_error; + } + + /* assume active low */ + if (srst_gpio > 0) { + srst_fd = setup_sysfs_gpio(srst_gpio, 1, 1); + if (srst_fd < 0) + goto out_error; + } + + LOG_WARNING("SysfsGPIO nums: tck = %d, tms = %d, tdi = %d, tdo = %d", + tck_gpio, tms_gpio, tdi_gpio, tdo_gpio); + LOG_WARNING("SysfsGPIO num: srst = %d", srst_gpio); + LOG_WARNING("SysfsGPIO num: trst = %d", trst_gpio); + + setvbuf(stdout, NULL, _IONBF, 0); + process_remote_protocol(); + + cleanup_all_fds(); + return 0; +out_error: + cleanup_all_fds(); + return ERROR_JTAG_INIT_FAILED; +} diff --git a/contrib/xsvf_tools/svf2xsvf.py b/contrib/xsvf_tools/svf2xsvf.py new file mode 100644 index 00000000..113e0a61 --- /dev/null +++ b/contrib/xsvf_tools/svf2xsvf.py @@ -0,0 +1,729 @@ +#!/usr/bin/python3.0 + +# Copyright 2008, SoftPLC Corporation http://softplc.com +# Dick Hollenbeck dick@softplc.com + + +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, you may find one here: +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html +# or you may search the http://www.gnu.org website for the version 2 license, +# or you may write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + + +# A python program to convert an SVF file to an XSVF file. There is an +# option to include comments containing the source file line number from the origin +# SVF file before each outputted XSVF statement. +# +# We deviate from the XSVF spec in that we introduce a new command called +# XWAITSTATE which directly flows from the SVF RUNTEST command. Unfortunately +# XRUNSTATE was ill conceived and is not used here. We also add support for the +# three Lattice extensions to SVF: LCOUNT, LDELAY, and LSDR. The xsvf file +# generated from this program is suitable for use with the xsvf player in +# OpenOCD with my modifications to xsvf.c. +# +# This program is written for python 3.0, and it is not easy to change this +# back to 2.x. You may find it easier to use python 3.x even if that means +# building it. + + +import re +import sys +import struct + + +# There are both ------ and ------ sections to this program + + +if len( sys.argv ) < 3: + print("usage %s " % sys.argv[0]) + exit(1) + + +inputFilename = sys.argv[1] +outputFilename = sys.argv[2] + +doCOMMENTs = True # Save XCOMMENTs in the output xsvf file +#doCOMMENTs = False # Save XCOMMENTs in the output xsvf file + +# pick your file encoding +file_encoding = 'ISO-8859-1' +#file_encoding = 'utf-8' + + +xrepeat = 0 # argument to XREPEAT, gives retry count for masked compares + + +#-----< Lexer >--------------------------------------------------------------- + +StateBin = (RESET,IDLE, + DRSELECT,DRCAPTURE,DRSHIFT,DREXIT1,DRPAUSE,DREXIT2,DRUPDATE, + IRSELECT,IRCAPTURE,IRSHIFT,IREXIT1,IRPAUSE,IREXIT2,IRUPDATE) = range(16) + +# Any integer index into this tuple will be equal to its corresponding StateBin value +StateTxt = ("RESET","IDLE", + "DRSELECT","DRCAPTURE","DRSHIFT","DREXIT1","DRPAUSE","DREXIT2","DRUPDATE", + "IRSELECT","IRCAPTURE","IRSHIFT","IREXIT1","IRPAUSE","IREXIT2","IRUPDATE") + + +(XCOMPLETE,XTDOMASK,XSIR,XSDR,XRUNTEST,hole0,hole1,XREPEAT,XSDRSIZE,XSDRTDO, + XSETSDRMASKS,XSDRINC,XSDRB,XSDRC,XSDRE,XSDRTDOB,XSDRTDOC, + XSDRTDOE,XSTATE,XENDIR,XENDDR,XSIR2,XCOMMENT,XWAIT,XWAITSTATE, + LCOUNT,LDELAY,LSDR,XTRST) = range(29) + +#Note: LCOUNT, LDELAY, and LSDR are Lattice extensions to SVF and provide a way to loop back +# and check a completion status, essentially waiting on a part until it signals that it is done. +# For example below: loop 25 times, each time through the loop do a LDELAY (same as a true RUNTEST) +# and exit loop when LSDR compares match. +""" +LCOUNT 25; +! Step to DRPAUSE give 5 clocks and wait for 1.00e+000 SEC. +LDELAY DRPAUSE 5 TCK 1.00E-003 SEC; +! Test for the completed status. Match means pass. +! Loop back to LDELAY line if not match and loop count less than 25. +LSDR 1 TDI (0) + TDO (1); +""" + +#XTRST is an opcode Xilinx seemed to have missed and it comes from the SVF TRST statement. + +LineNumber = 1 + +def s_ident(scanner, token): return ("ident", token.upper(), LineNumber) + +def s_hex(scanner, token): + global LineNumber + LineNumber = LineNumber + token.count('\n') + token = ''.join(token.split()) + return ("hex", token[1:-1], LineNumber) + +def s_int(scanner, token): return ("int", int(token), LineNumber) +def s_float(scanner, token): return ("float", float(token), LineNumber) +#def s_comment(scanner, token): return ("comment", token, LineNumber) +def s_semicolon(scanner, token): return ("semi", token, LineNumber) + +def s_nl(scanner,token): + global LineNumber + LineNumber = LineNumber + 1 + #print( 'LineNumber=', LineNumber, file=sys.stderr ) + return None + +#2.00E-002 + +scanner = re.Scanner([ + (r"[a-zA-Z]\w*", s_ident), +# (r"[-+]?[0-9]+[.]?[0-9]*([eE][-+]?[0-9]+)?", s_float), + (r"[-+]?[0-9]+(([.][0-9eE+-]*)|([eE]+[-+]?[0-9]+))", s_float), + (r"\d+", s_int), + (r"\(([0-9a-fA-F]|\s)*\)", s_hex), + (r"(!|//).*$", None), + (r";", s_semicolon), + (r"\n",s_nl), + (r"\s*", None), + ], + re.MULTILINE + ) + +# open the file using the given encoding +file = open( sys.argv[1], encoding=file_encoding ) + +# read all svf file input into string "input" +input = file.read() + +file.close() + +# Lexer: +# create a list of tuples containing (tokenType, tokenValue, LineNumber) +tokens = scanner.scan( input )[0] + +input = None # allow gc to reclaim memory holding file + +#for tokenType, tokenValue, ln in tokens: print( "line %d: %s" % (ln, tokenType), tokenValue ) + + +#---------------------------------------------------------------------- + +tokVal = tokType = tokLn = None + +tup = iter( tokens ) + +def nextTok(): + """ + Function to read the next token from tup into tokType, tokVal, tokLn (linenumber) + which are globals. + """ + global tokType, tokVal, tokLn, tup + tokType, tokVal, tokLn = tup.__next__() + + +class ParseError(Exception): + """A class to hold a parsing error message""" + def __init__(self, linenumber, token, message): + self.linenumber = linenumber + self.token = token + self.message = message + def __str__(self): + global inputFilename + return "Error in file \'%s\' at line %d near token %s\n %s" % ( + inputFilename, self.linenumber, repr(self.token), self.message) + + +class MASKSET(object): + """ + Class MASKSET holds a set of bit vectors, all of which are related, will all + have the same length, and are associated with one of the seven shiftOps: + HIR, HDR, TIR, TDR, SIR, SDR, LSDR. One of these holds a mask, smask, tdi, tdo, and a + size. + """ + def __init__(self, name): + self.empty() + self.name = name + + def empty(self): + self.mask = bytearray() + self.smask = bytearray() + self.tdi = bytearray() + self.tdo = bytearray() + self.size = 0 + + def syncLengths( self, sawTDI, sawTDO, sawMASK, sawSMASK, newSize ): + """ + Set all the lengths equal in the event some of the masks were + not seen as part of the last change set. + """ + if self.size == newSize: + return + + if newSize == 0: + self.empty() + return + + # If an SIR was given without a MASK(), then use a mask of all zeros. + # this is not consistent with the SVF spec, but it makes sense because + # it would be odd to be testing an instruction register read out of a + # tap without giving a mask for it. Also, lattice seems to agree and is + # generating SVF files that comply with this philosophy. + if self.name == 'SIR' and not sawMASK: + self.mask = bytearray( newSize ) + + if newSize != len(self.mask): + self.mask = bytearray( newSize ) + if self.name == 'SDR': # leave mask for HIR,HDR,TIR,TDR,SIR zeros + for i in range( newSize ): + self.mask[i] = 1 + + if newSize != len(self.tdo): + self.tdo = bytearray( newSize ) + + if newSize != len(self.tdi): + self.tdi = bytearray( newSize ) + + if newSize != len(self.smask): + self.smask = bytearray( newSize ) + + self.size = newSize +#---------- + + +def makeBitArray( hexString, bitCount ): + """ + Converts a packed sequence of hex ascii characters into a bytearray where + each element in the array holds exactly one bit. Only "bitCount" bits are + scanned and these must be the least significant bits in the hex number. That + is, it is legal to have some unused bits in the must significant hex nibble + of the input "hexString". The string is scanned starting from the backend, + then just before returning we reverse the array. This way the append() + method can be used, which I assume is faster than an insert. + """ + global tokLn + a = bytearray() + length = bitCount + hexString = list(hexString) + hexString.reverse() + #print(hexString) + for c in hexString: + if length <= 0: + break; + c = int(c, 16) + for mask in [1,2,4,8]: + if length <= 0: + break; + length = length - 1 + a.append( (c & mask) != 0 ) + if length > 0: + raise ParseError( tokLn, hexString, "Insufficient hex characters for given length of %d" % bitCount ) + a.reverse() + #print(a) + return a + + +def makeXSVFbytes( bitarray ): + """ + Make a bytearray which is contains the XSVF bits which will be written + directly to disk. The number of bytes needed is calculated from the size + of the argument bitarray. + """ + bitCount = len(bitarray) + byteCount = (bitCount+7)//8 + ba = bytearray( byteCount ) + firstBit = (bitCount % 8) - 1 + if firstBit == -1: + firstBit = 7 + bitNdx = 0 + for byteNdx in range(byteCount): + mask = 1<> 1 + bitNdx = bitNdx + 1 + ba[byteNdx] = byte + firstBit = 7 + return ba + + +def writeComment( outputFile, shiftOp_linenum, shiftOp ): + """ + Write an XCOMMENT record to outputFile + """ + comment = "%s @%d\0" % (shiftOp, shiftOp_linenum) # \0 is terminating nul + ba = bytearray(1) + ba[0] = XCOMMENT + ba += comment.encode() + outputFile.write( ba ) + + +def combineBitVectors( trailer, meat, header ): + """ + Combine the 3 bit vectors comprizing a transmission. Since the least + significant bits are sent first, the header is put onto the list last so + they are sent first from that least significant position. + """ + ret = bytearray() + ret.extend( trailer ) + ret.extend( meat ) + ret.extend( header ) + return ret + + +def writeRUNTEST( outputFile, run_state, end_state, run_count, min_time, tokenTxt ): + """ + Write the output for the SVF RUNTEST command. + run_count - the number of clocks + min_time - the number of seconds + tokenTxt - either RUNTEST or LDELAY + """ + # convert from secs to usecs + min_time = int( min_time * 1000000) + + # the SVF RUNTEST command does NOT map to the XSVF XRUNTEST command. Check the SVF spec, then + # read the XSVF command. They are not the same. Use an XSVF XWAITSTATE to + # implement the required behavior of the SVF RUNTEST command. + if doCOMMENTs: + writeComment( output, tokLn, tokenTxt ) + + if tokenTxt == 'RUNTEST': + obuf = bytearray(11) + obuf[0] = XWAITSTATE + obuf[1] = run_state + obuf[2] = end_state + struct.pack_into(">i", obuf, 3, run_count ) # big endian 4 byte int to obuf + struct.pack_into(">i", obuf, 7, min_time ) # big endian 4 byte int to obuf + outputFile.write( obuf ) + else: # == 'LDELAY' + obuf = bytearray(10) + obuf[0] = LDELAY + obuf[1] = run_state + # LDELAY has no end_state + struct.pack_into(">i", obuf, 2, run_count ) # big endian 4 byte int to obuf + struct.pack_into(">i", obuf, 6, min_time ) # big endian 4 byte int to obuf + outputFile.write( obuf ) + + +output = open( outputFilename, mode='wb' ) + +hir = MASKSET('HIR') +hdr = MASKSET('HDR') +tir = MASKSET('TIR') +tdr = MASKSET('TDR') +sir = MASKSET('SIR') +sdr = MASKSET('SDR') + + +expecting_eof = True + + +# one of the commands that take the shiftParts after the length, the parse +# template for all of these commands is identical +shiftOps = ('SDR', 'SIR', 'LSDR', 'HDR', 'HIR', 'TDR', 'TIR') + +# the order must correspond to shiftOps, this holds the MASKSETS. 'LSDR' shares sdr with 'SDR' +shiftSets = (sdr, sir, sdr, hdr, hir, tdr, tir ) + +# what to expect as parameters to a shiftOp, i.e. after a SDR length or SIR length +shiftParts = ('TDI', 'TDO', 'MASK', 'SMASK') + +# the set of legal states which can trail the RUNTEST command +run_state_allowed = ('IRPAUSE', 'DRPAUSE', 'RESET', 'IDLE') + +enddr_state_allowed = ('DRPAUSE', 'IDLE') +endir_state_allowed = ('IRPAUSE', 'IDLE') + +trst_mode_allowed = ('ON', 'OFF', 'Z', 'ABSENT') + +enddr_state = IDLE +endir_state = IDLE + +frequency = 1.00e+006 # HZ; + +# change detection for xsdrsize and xtdomask +xsdrsize = -1 # the last one sent, send only on change +xtdomask = bytearray() # the last one sent, send only on change + + +# we use a number of single byte writes for the XSVF command below +cmdbuf = bytearray(1) + + +# Save the XREPEAT setting into the file as first thing. +obuf = bytearray(2) +obuf[0] = XREPEAT +obuf[1] = xrepeat +output.write( obuf ) + + +try: + while 1: + expecting_eof = True + nextTok() + expecting_eof = False + # print( tokType, tokVal, tokLn ) + + if tokVal in shiftOps: + shiftOp_linenum = tokLn + shiftOp = tokVal + + set = shiftSets[shiftOps.index(shiftOp)] + + # set flags false, if we see one later, set that one true later + sawTDI = sawTDO = sawMASK = sawSMASK = False + + nextTok() + if tokType != 'int': + raise ParseError( tokLn, tokVal, "Expecting 'int' giving %s length, got '%s'" % (shiftOp, tokType) ) + length = tokVal + + nextTok() + + while tokVal != ';': + if tokVal not in shiftParts: + raise ParseError( tokLn, tokVal, "Expecting TDI, TDO, MASK, SMASK, or ';'") + shiftPart = tokVal + + nextTok() + + if tokType != 'hex': + raise ParseError( tokLn, tokVal, "Expecting hex bits" ) + bits = makeBitArray( tokVal, length ) + + if shiftPart == 'TDI': + sawTDI = True + set.tdi = bits + + elif shiftPart == 'TDO': + sawTDO = True + set.tdo = bits + + elif shiftPart == 'MASK': + sawMASK = True + set.mask = bits + + elif shiftPart == 'SMASK': + sawSMASK = True + set.smask = bits + + nextTok() + + set.syncLengths( sawTDI, sawTDO, sawMASK, sawSMASK, length ) + + # process all the gathered parameters and generate outputs here + if shiftOp == 'SIR': + if doCOMMENTs: + writeComment( output, shiftOp_linenum, 'SIR' ) + + tdi = combineBitVectors( tir.tdi, sir.tdi, hir.tdi ) + if len(tdi) > 255: + obuf = bytearray(3) + obuf[0] = XSIR2 + struct.pack_into( ">h", obuf, 1, len(tdi) ) + else: + obuf = bytearray(2) + obuf[0] = XSIR + obuf[1] = len(tdi) + output.write( obuf ) + obuf = makeXSVFbytes( tdi ) + output.write( obuf ) + + elif shiftOp == 'SDR': + if doCOMMENTs: + writeComment( output, shiftOp_linenum, shiftOp ) + + if not sawTDO: + # pass a zero filled bit vector for the sdr.mask + mask = combineBitVectors( tdr.mask, bytearray(sdr.size), hdr.mask ) + tdi = combineBitVectors( tdr.tdi, sdr.tdi, hdr.tdi ) + + if xsdrsize != len(tdi): + xsdrsize = len(tdi) + cmdbuf[0] = XSDRSIZE + output.write( cmdbuf ) + obuf = bytearray(4) + struct.pack_into( ">i", obuf, 0, xsdrsize ) # big endian 4 byte int to obuf + output.write( obuf ) + + if xtdomask != mask: + xtdomask = mask + cmdbuf[0] = XTDOMASK + output.write( cmdbuf ) + obuf = makeXSVFbytes( mask ) + output.write( obuf ) + + cmdbuf[0] = XSDR + output.write( cmdbuf ) + obuf = makeXSVFbytes( tdi ) + output.write( obuf ) + + else: + mask = combineBitVectors( tdr.mask, sdr.mask, hdr.mask ) + tdi = combineBitVectors( tdr.tdi, sdr.tdi, hdr.tdi ) + tdo = combineBitVectors( tdr.tdo, sdr.tdo, hdr.tdo ) + + if xsdrsize != len(tdi): + xsdrsize = len(tdi) + cmdbuf[0] = XSDRSIZE + output.write( cmdbuf ) + obuf = bytearray(4) + struct.pack_into(">i", obuf, 0, xsdrsize ) # big endian 4 byte int to obuf + output.write( obuf ) + + if xtdomask != mask: + xtdomask = mask + cmdbuf[0] = XTDOMASK + output.write( cmdbuf ) + obuf = makeXSVFbytes( mask ) + output.write( obuf ) + + cmdbuf[0] = XSDRTDO + output.write( cmdbuf ) + obuf = makeXSVFbytes( tdi ) + output.write( obuf ) + obuf = makeXSVFbytes( tdo ) + output.write( obuf ) + #print( "len(tdo)=", len(tdo), "len(tdr.tdo)=", len(tdr.tdo), "len(sdr.tdo)=", len(sdr.tdo), "len(hdr.tdo)=", len(hdr.tdo) ) + + elif shiftOp == 'LSDR': + if doCOMMENTs: + writeComment( output, shiftOp_linenum, shiftOp ) + + mask = combineBitVectors( tdr.mask, sdr.mask, hdr.mask ) + tdi = combineBitVectors( tdr.tdi, sdr.tdi, hdr.tdi ) + tdo = combineBitVectors( tdr.tdo, sdr.tdo, hdr.tdo ) + + if xsdrsize != len(tdi): + xsdrsize = len(tdi) + cmdbuf[0] = XSDRSIZE + output.write( cmdbuf ) + obuf = bytearray(4) + struct.pack_into(">i", obuf, 0, xsdrsize ) # big endian 4 byte int to obuf + output.write( obuf ) + + if xtdomask != mask: + xtdomask = mask + cmdbuf[0] = XTDOMASK + output.write( cmdbuf ) + obuf = makeXSVFbytes( mask ) + output.write( obuf ) + + cmdbuf[0] = LSDR + output.write( cmdbuf ) + obuf = makeXSVFbytes( tdi ) + output.write( obuf ) + obuf = makeXSVFbytes( tdo ) + output.write( obuf ) + #print( "len(tdo)=", len(tdo), "len(tdr.tdo)=", len(tdr.tdo), "len(sdr.tdo)=", len(sdr.tdo), "len(hdr.tdo)=", len(hdr.tdo) ) + + elif tokVal == 'RUNTEST' or tokVal == 'LDELAY': + # e.g. from lattice tools: + # "RUNTEST IDLE 5 TCK 1.00E-003 SEC;" + saveTok = tokVal + nextTok() + min_time = 0 + run_count = 0 + max_time = 600 # ten minutes + if tokVal in run_state_allowed: + run_state = StateTxt.index(tokVal) + end_state = run_state # bottom of page 17 of SVF spec + nextTok() + if tokType != 'int' and tokType != 'float': + raise ParseError( tokLn, tokVal, "Expecting 'int' or 'float' after RUNTEST [run_state]") + timeval = tokVal; + nextTok() + if tokVal != 'TCK' and tokVal != 'SEC' and tokVal != 'SCK': + raise ParseError( tokLn, tokVal, "Expecting 'TCK' or 'SEC' or 'SCK' after RUNTEST [run_state] (run_count|min_time)") + if tokVal == 'TCK' or tokVal == 'SCK': + run_count = int( timeval ) + else: + min_time = timeval + nextTok() + if tokType == 'int' or tokType == 'float': + min_time = tokVal + nextTok() + if tokVal != 'SEC': + raise ParseError( tokLn, tokVal, "Expecting 'SEC' after RUNTEST [run_state] run_count min_time") + nextTok() + if tokVal == 'MAXIMUM': + nextTok() + if tokType != 'int' and tokType != 'float': + raise ParseError( tokLn, tokVal, "Expecting 'max_time' after RUNTEST [run_state] min_time SEC MAXIMUM") + max_time = tokVal + nextTok() + if tokVal != 'SEC': + raise ParseError( tokLn, tokVal, "Expecting 'max_time' after RUNTEST [run_state] min_time SEC MAXIMUM max_time") + nextTok() + if tokVal == 'ENDSTATE': + nextTok() + if tokVal not in run_state_allowed: + raise ParseError( tokLn, tokVal, "Expecting 'run_state' after RUNTEST .... ENDSTATE") + end_state = StateTxt.index(tokVal) + nextTok() + if tokVal != ';': + raise ParseError( tokLn, tokVal, "Expecting ';' after RUNTEST ....") + # print( "run_count=", run_count, "min_time=", min_time, + # "max_time=", max_time, "run_state=", State[run_state], "end_state=", State[end_state] ) + writeRUNTEST( output, run_state, end_state, run_count, min_time, saveTok ) + + elif tokVal == 'LCOUNT': + nextTok() + if tokType != 'int': + raise ParseError( tokLn, tokVal, "Expecting integer 'count' after LCOUNT") + loopCount = tokVal + nextTok() + if tokVal != ';': + raise ParseError( tokLn, tokVal, "Expecting ';' after LCOUNT count") + if doCOMMENTs: + writeComment( output, tokLn, 'LCOUNT' ) + obuf = bytearray(5) + obuf[0] = LCOUNT + struct.pack_into(">i", obuf, 1, loopCount ) # big endian 4 byte int to obuf + output.write( obuf ) + + elif tokVal == 'ENDDR': + nextTok() + if tokVal not in enddr_state_allowed: + raise ParseError( tokLn, tokVal, "Expecting 'stable_state' after ENDDR. (one of: DRPAUSE, IDLE)") + enddr_state = StateTxt.index(tokVal) + nextTok() + if tokVal != ';': + raise ParseError( tokLn, tokVal, "Expecting ';' after ENDDR stable_state") + if doCOMMENTs: + writeComment( output, tokLn, 'ENDDR' ) + obuf = bytearray(2) + obuf[0] = XENDDR + # Page 10 of the March 1999 SVF spec shows that RESET is also allowed here. + # Yet the XSVF spec has no provision for that, and uses a non-standard, i.e. + # boolean argument to XENDDR which only handles two of the 3 intended states. + obuf[1] = 1 if enddr_state == DRPAUSE else 0 + output.write( obuf ) + + elif tokVal == 'ENDIR': + nextTok() + if tokVal not in endir_state_allowed: + raise ParseError( tokLn, tokVal, "Expecting 'stable_state' after ENDIR. (one of: IRPAUSE, IDLE)") + endir_state = StateTxt.index(tokVal) + nextTok() + if tokVal != ';': + raise ParseError( tokLn, tokVal, "Expecting ';' after ENDIR stable_state") + if doCOMMENTs: + writeComment( output, tokLn, 'ENDIR' ) + obuf = bytearray(2) + obuf[0] = XENDIR + # Page 10 of the March 1999 SVF spec shows that RESET is also allowed here. + # Yet the XSVF spec has no provision for that, and uses a non-standard, i.e. + # boolean argument to XENDDR which only handles two of the 3 intended states. + obuf[1] = 1 if endir_state == IRPAUSE else 0 + output.write( obuf ) + + elif tokVal == 'STATE': + nextTok() + ln = tokLn + while tokVal != ';': + if tokVal not in StateTxt: + raise ParseError( tokLn, tokVal, "Expecting 'stable_state' after STATE") + stable_state = StateTxt.index( tokVal ) + + if doCOMMENTs and ln != -1: + writeComment( output, ln, 'STATE' ) + ln = -1 # save comment only once + + obuf = bytearray(2) + obuf[0] = XSTATE + obuf[1] = stable_state + output.write( obuf ) + nextTok() + + elif tokVal == 'FREQUENCY': + nextTok() + if tokVal != ';': + if tokType != 'int' and tokType != 'float': + raise ParseError( tokLn, tokVal, "Expecting 'cycles HZ' after FREQUENCY") + frequency = tokVal + nextTok() + if tokVal != 'HZ': + raise ParseError( tokLn, tokVal, "Expecting 'HZ' after FREQUENCY cycles") + nextTok() + if tokVal != ';': + raise ParseError( tokLn, tokVal, "Expecting ';' after FREQUENCY cycles HZ") + + elif tokVal == 'TRST': + nextTok() + if tokVal not in trst_mode_allowed: + raise ParseError( tokLn, tokVal, "Expecting 'ON|OFF|Z|ABSENT' after TRST") + trst_mode = tokVal + nextTok() + if tokVal != ';': + raise ParseError( tokLn, tokVal, "Expecting ';' after TRST trst_mode") + if doCOMMENTs: + writeComment( output, tokLn, 'TRST %s' % trst_mode ) + obuf = bytearray( 2 ) + obuf[0] = XTRST + obuf[1] = trst_mode_allowed.index( trst_mode ) # use the index as the binary argument to XTRST opcode + output.write( obuf ) + + else: + raise ParseError( tokLn, tokVal, "Unknown token '%s'" % tokVal) + +except StopIteration: + if not expecting_eof: + print( "Unexpected End of File at line ", tokLn ) + +except ParseError as pe: + print( "\n", pe ) + +finally: + # print( "closing file" ) + cmdbuf[0] = XCOMPLETE + output.write( cmdbuf ) + output.close() + diff --git a/contrib/xsvf_tools/xsvfdump.py b/contrib/xsvf_tools/xsvfdump.py new file mode 100644 index 00000000..e65f8d5b --- /dev/null +++ b/contrib/xsvf_tools/xsvfdump.py @@ -0,0 +1,268 @@ +#!/usr/bin/python3.0 + +# Copyright 2008, SoftPLC Corporation http://softplc.com +# Dick Hollenbeck dick@softplc.com + +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, you may find one here: +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html +# or you may search the http://www.gnu.org website for the version 2 license, +# or you may write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +# Dump an Xilinx XSVF file to stdout + +# This program is written for python 3.0, and it is not easy to change this +# back to 2.x. You may find it easier to use python 3.x even if that means +# building it. + + +import sys +import struct + + +LABEL = "A script to dump an XSVF file to stdout" + + +Xsdrsize = 0 + + +(XCOMPLETE,XTDOMASK,XSIR,XSDR,XRUNTEST,hole0,hole1,XREPEAT,XSDRSIZE,XSDRTDO, + XSETSDRMASKS,XSDRINC,XSDRB,XSDRC,XSDRE,XSDRTDOB,XSDRTDOC, + XSDRTDOE,XSTATE,XENDIR,XENDDR,XSIR2,XCOMMENT,XWAIT,XWAITSTATE, + LCOUNT,LDELAY,LSDR,XTRST) = range(29) + + +(RESET,IDLE, + DRSELECT,DRCAPTURE,DRSHIFT,DREXIT1,DRPAUSE,DREXIT2,DRUPDATE, + IRSELECT,IRCAPTURE,IRSHIFT,IREXIT1,IRPAUSE,IREXIT2,IRUPDATE) = range(16) + + +State = ("RESET","IDLE", + "DRSELECT","DRCAPTURE","DRSHIFT","DREXIT1","DRPAUSE","DREXIT2","DRUPDATE", + "IRSELECT","IRCAPTURE","IRSHIFT","IREXIT1","IRPAUSE","IREXIT2","IRUPDATE") + + +trst_mode_allowed = ('ON', 'OFF', 'Z', 'ABSENT') + + +Setsdrmasks = 0 +SetsdrmasksOnesCount = 0 + +def ReadSDRMASKS( f, len ): + global Setsdrmasks, SetsdrmasksOnesCount + byteCount = (len+7)//8 + Setsdrmasks = f.read( byteCount ) + ls = [] + SetsdrmasksOnesCount = 0 + for b in Setsdrmasks: + ls.append( "%x" % ((b & 0xf0) >> 4) ) + ls.append( "%x" % ( b & 0x0f ) ) + for i in range(8): + if b & (1<> 4) ) + ls.append( "%x" % ( b & 0x0f ) ) + return ''.join(ls) + + +def ReadByte( f ): + """Read a byte from a file and return it as an int in least significant 8 bits""" + b = f.read(1) + if b: + return 0xff & b[0]; + else: + return -1 + + +def ShowState( state ): + """return the given state int as a state string""" + #return "0x%02x" % state # comment this out to get textual state form + global State + if 0 <= state <= IRUPDATE: + return State[state] + else: + return "Unknown state 0x%02x" % state + + +def ShowOpcode( op, f ): + """return the given byte as an opcode string""" + global Xsdrsize + if op == XCOMPLETE: + print("XCOMPLETE") + + elif op == XTDOMASK: + buf = bytes2hexString( f, Xsdrsize ) + print("XTDOMASK 0x%s" % buf) + + elif op == XSIR: + len = ReadByte( f ) + buf = bytes2hexString( f, len ) + print("XSIR 0x%02X 0x%s" % (len, buf)) + + elif op == XSDR: + tdi = bytes2hexString( f, Xsdrsize ) + print("XSDR 0x%s" % tdi) + + elif op == XRUNTEST: + len = struct.unpack( '>i', f.read(4) )[0] + print("XRUNTEST 0x%08X" % len) + + elif op == XREPEAT: + len = ReadByte( f ) + print("XREPEAT 0x%02X" % len) + + elif op == XSDRSIZE: + Xsdrsize = struct.unpack( '>i', f.read(4) )[0] + #print("XSDRSIZE 0x%08X" % Xsdrsize, file=sys.stderr ) + print("XSDRSIZE 0x%08X %d" % (Xsdrsize, Xsdrsize) ) + + elif op == XSDRTDO: + tdi = bytes2hexString( f, Xsdrsize ) + tdo = bytes2hexString( f, Xsdrsize ) + print("XSDRTDO 0x%s 0x%s" % (tdi, tdo) ) + + elif op == XSETSDRMASKS: + addrmask = bytes2hexString( f, Xsdrsize ) + datamask = ReadSDRMASKS( f, Xsdrsize ) + print("XSETSDRMASKS 0x%s 0x%s" % (addrmask, datamask) ) + + elif op == XSDRINC: + startaddr = bytes2hexString( f, Xsdrsize ) + len = ReadByte(f) + print("XSDRINC 0x%s 0x%02X" % (startaddr, len), end='' ) + for numTimes in range(len): + data = bytes2hexString( f, SetsdrmasksOnesCount) + print(" 0x%s" % data ) + print() # newline + + elif op == XSDRB: + tdi = bytes2hexString( f, Xsdrsize ) + print("XSDRB 0x%s" % tdi ) + + elif op == XSDRC: + tdi = bytes2hexString( f, Xsdrsize ) + print("XSDRC 0x%s" % tdi ) + + elif op == XSDRE: + tdi = bytes2hexString( f, Xsdrsize ) + print("XSDRE 0x%s" % tdi ) + + elif op == XSDRTDOB: + tdo = bytes2hexString( f, Xsdrsize ) + print("XSDRTDOB 0x%s" % tdo ) + + elif op == XSDRTDOC: + tdi = bytes2hexString( f, Xsdrsize ) + tdo = bytes2hexString( f, Xsdrsize ) + print("XSDRTDOC 0x%s 0x%s" % (tdi, tdo) ) + + elif op == XSDRTDOE: + tdi = bytes2hexString( f, Xsdrsize ) + tdo = bytes2hexString( f, Xsdrsize ) + print("XSDRTDOE 0x%s 0x%s" % (tdi, tdo) ) + + elif op == XSTATE: + b = ReadByte(f) + print("XSTATE %s" % ShowState(b)) + + elif op == XENDIR: + b = ReadByte( f ) + print("XENDIR %s" % 'IRPAUSE' if b==1 else 'IDLE') + + elif op == XENDDR: + b = ReadByte( f ) + print("XENDDR %s" % 'DRPAUSE' if b==1 else 'IDLE') + + elif op == XSIR2: + len = struct.unpack( '>H', f.read(2) )[0] + buf = bytes2hexString( f, len ) + print("XSIR2 0x%04X 0x%s" % (len, buf)) + + elif op == XCOMMENT: + cmt = [] + while 1: + b = ReadByte(f) + if b == 0: # terminating nul + break; + cmt.append( chr(b) ) + print("XCOMMENT \"%s\"" % ''.join(cmt) ) + + elif op == XWAIT: + run_state = ReadByte(f) + end_state = ReadByte(f) + useconds = struct.unpack( '>i', f.read(4) )[0] + print("XWAIT %s %s" % (ShowState(run_state), ShowState(end_state)), useconds) + + elif op == XWAITSTATE: + run_state = ReadByte(f) + end_state = ReadByte(f) + clocks = struct.unpack( '>i', f.read(4) )[0] + useconds = struct.unpack( '>i', f.read(4) )[0] + print("XWAITSTATE %s %s CLOCKS=%d USECS=%d" % (ShowState(run_state), ShowState(end_state), clocks, useconds) ) + + elif op == LCOUNT: + loop_count = struct.unpack( '>i', f.read(4) )[0] + print("LCOUNT", loop_count ) + + elif op == LDELAY: + run_state = ReadByte(f) + clocks = struct.unpack( '>i', f.read(4) )[0] + useconds = struct.unpack( '>i', f.read(4) )[0] + print("LDELAY %s CLOCKS=%d USECS=%d" % (ShowState(run_state), clocks, useconds) ) + + elif op == LSDR: + tdi = bytes2hexString( f, Xsdrsize ) + tdo = bytes2hexString( f, Xsdrsize ) + print("LSDR 0x%s 0x%s" % (tdi, tdo) ) + + elif op == XTRST: + # the argument is a single byte and it is the index into "trst_mode_allowed" + trst_mode = ReadByte(f) + if trst_mode <= 3: + print("TRST %s" % trst_mode_allowed[trst_mode] ) + else: + print("TRST 0x%02X" % trst_mode ); + + else: + print("UNKNOWN op 0x%02X %d" % (op, op)) + exit(1) + + +def main(): + + if len( sys.argv ) < 2: + print("usage %s " % sys.argv[0]) + exit(1) + + f = open( sys.argv[1], 'rb' ) + + opcode = ReadByte( f ) + while opcode != -1: + # print the position within the file, then the command + print( "%d: " % f.tell(), end='' ) + ShowOpcode( opcode, f ) + opcode = ReadByte(f) + + +if __name__ == "__main__": + main() + diff --git a/tools/remote_bitbang/remote_bitbang_sysfsgpio.c b/tools/remote_bitbang/remote_bitbang_sysfsgpio.c deleted file mode 100644 index e59a1bde..00000000 --- a/tools/remote_bitbang/remote_bitbang_sysfsgpio.c +++ /dev/null @@ -1,408 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2013 Paul Fertser * - * Copyright (C) 2012 by Creative Product Design, marc @ cpdesign.com.au * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - ***************************************************************************/ - -/* - This is a test application to be used as a remote bitbang server for - the OpenOCD remote_bitbang interface driver. - - To compile run: - gcc -Wall -ansi -pedantic -std=c99 -o remote_bitbang_sysfsgpio remote_bitbang_sysfsgpio.c - - - Usage example: - - On Raspberry Pi run: - socat TCP6-LISTEN:7777,fork EXEC:"sudo ./remote_bitbang_sysfsgpio tck 11 tms 25 tdo 9 tdi 10" - - On host run: - openocd -c "interface remote_bitbang; remote_bitbang_host raspberrypi; remote_bitbang_port 7777" \ - -f target/stm32f1x.cfg - - Or if you want to test UNIX sockets, run both on Raspberry Pi: - socat UNIX-LISTEN:/tmp/remotebitbang-socket,fork EXEC:"sudo ./remote_bitbang_sysfsgpio tck 11 tms 25 tdo 9 tdi 10" - openocd -c "interface remote_bitbang; remote_bitbang_host /tmp/remotebitbang-socket" -f target/stm32f1x.cfg -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define LOG_ERROR(...) do { \ - fprintf(stderr, __VA_ARGS__); \ - fputc('\n', stderr); \ - } while (0) -#define LOG_WARNING(...) LOG_ERROR(__VA_ARGS__) - -#define ERROR_OK (-1) -#define ERROR_FAIL (-2) -#define ERROR_JTAG_INIT_FAILED ERROR_FAIL - -/* - * Helper func to determine if gpio number valid - * - * Assume here that there will be less than 1000 gpios on a system - */ -static int is_gpio_valid(int gpio) -{ - return gpio >= 0 && gpio < 1000; -} - -/* - * Helper func to open, write to and close a file - * name and valstr must be null terminated. - * - * Returns negative on failure. - */ -static int open_write_close(const char *name, const char *valstr) -{ - int ret; - int fd = open(name, O_WRONLY); - if (fd < 0) - return fd; - - ret = write(fd, valstr, strlen(valstr)); - close(fd); - - return ret; -} - -/* - * Helper func to unexport gpio from sysfs - */ -static void unexport_sysfs_gpio(int gpio) -{ - char gpiostr[4]; - - if (!is_gpio_valid(gpio)) - return; - - snprintf(gpiostr, sizeof(gpiostr), "%d", gpio); - if (open_write_close("/sys/class/gpio/unexport", gpiostr) < 0) - LOG_ERROR("Couldn't unexport gpio %d", gpio); - - return; -} - -/* - * Exports and sets up direction for gpio. - * If the gpio is an output, it is initialized according to init_high, - * otherwise it is ignored. - * - * If the gpio is already exported we just show a warning and continue; if - * openocd happened to crash (or was killed by user) then the gpios will not - * have been cleaned up. - */ -static int setup_sysfs_gpio(int gpio, int is_output, int init_high) -{ - char buf[40]; - char gpiostr[4]; - int ret; - - if (!is_gpio_valid(gpio)) - return ERROR_OK; - - snprintf(gpiostr, sizeof(gpiostr), "%d", gpio); - ret = open_write_close("/sys/class/gpio/export", gpiostr); - if (ret < 0) { - if (errno == EBUSY) { - LOG_WARNING("gpio %d is already exported", gpio); - } else { - LOG_ERROR("Couldn't export gpio %d", gpio); - perror("sysfsgpio: "); - return ERROR_FAIL; - } - } - - snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/direction", gpio); - ret = open_write_close(buf, is_output ? (init_high ? "high" : "low") : "in"); - if (ret < 0) { - LOG_ERROR("Couldn't set direction for gpio %d", gpio); - perror("sysfsgpio: "); - unexport_sysfs_gpio(gpio); - return ERROR_FAIL; - } - - snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", gpio); - if (is_output) - ret = open(buf, O_WRONLY | O_NONBLOCK | O_SYNC); - else - ret = open(buf, O_RDONLY | O_NONBLOCK | O_SYNC); - - if (ret < 0) - unexport_sysfs_gpio(gpio); - - return ret; -} - -/* - * file descriptors for /sys/class/gpio/gpioXX/value - * Set up during init. - */ -static int tck_fd = -1; -static int tms_fd = -1; -static int tdi_fd = -1; -static int tdo_fd = -1; -static int trst_fd = -1; -static int srst_fd = -1; - -/* - * Bitbang interface read of TDO - * - * The sysfs value will read back either '0' or '1'. The trick here is to call - * lseek to bypass buffering in the sysfs kernel driver. - */ -static int sysfsgpio_read(void) -{ - char buf[1]; - - /* important to seek to signal sysfs of new read */ - lseek(tdo_fd, 0, SEEK_SET); - int ret = read(tdo_fd, &buf, sizeof(buf)); - - if (ret < 0) { - LOG_WARNING("reading tdo failed"); - return 0; - } - - return buf[0]; -} - -/* - * Bitbang interface write of TCK, TMS, TDI - * - * Seeing as this is the only function where the outputs are changed, - * we can cache the old value to avoid needlessly writing it. - */ -static void sysfsgpio_write(int tck, int tms, int tdi) -{ - const char one[] = "1"; - const char zero[] = "0"; - - static int last_tck; - static int last_tms; - static int last_tdi; - - static int first_time; - size_t bytes_written; - - if (!first_time) { - last_tck = !tck; - last_tms = !tms; - last_tdi = !tdi; - first_time = 1; - } - - if (tdi != last_tdi) { - bytes_written = write(tdi_fd, tdi ? &one : &zero, 1); - if (bytes_written != 1) - LOG_WARNING("writing tdi failed"); - } - - if (tms != last_tms) { - bytes_written = write(tms_fd, tms ? &one : &zero, 1); - if (bytes_written != 1) - LOG_WARNING("writing tms failed"); - } - - /* write clk last */ - if (tck != last_tck) { - bytes_written = write(tck_fd, tck ? &one : &zero, 1); - if (bytes_written != 1) - LOG_WARNING("writing tck failed"); - } - - last_tdi = tdi; - last_tms = tms; - last_tck = tck; -} - -/* - * Bitbang interface to manipulate reset lines SRST and TRST - * - * (1) assert or (0) deassert reset lines - */ -static void sysfsgpio_reset(int trst, int srst) -{ - const char one[] = "1"; - const char zero[] = "0"; - size_t bytes_written; - - /* assume active low */ - if (srst_fd >= 0) { - bytes_written = write(srst_fd, srst ? &zero : &one, 1); - if (bytes_written != 1) - LOG_WARNING("writing srst failed"); - } - - /* assume active low */ - if (trst_fd >= 0) { - bytes_written = write(trst_fd, trst ? &zero : &one, 1); - if (bytes_written != 1) - LOG_WARNING("writing trst failed"); - } -} - -/* gpio numbers for each gpio. Negative values are invalid */ -static int tck_gpio = -1; -static int tms_gpio = -1; -static int tdi_gpio = -1; -static int tdo_gpio = -1; -static int trst_gpio = -1; -static int srst_gpio = -1; - -/* helper func to close and cleanup files only if they were valid/ used */ -static void cleanup_fd(int fd, int gpio) -{ - if (gpio >= 0) { - if (fd >= 0) - close(fd); - - unexport_sysfs_gpio(gpio); - } -} - -static void cleanup_all_fds(void) -{ - cleanup_fd(tck_fd, tck_gpio); - cleanup_fd(tms_fd, tms_gpio); - cleanup_fd(tdi_fd, tdi_gpio); - cleanup_fd(tdo_fd, tdo_gpio); - cleanup_fd(trst_fd, trst_gpio); - cleanup_fd(srst_fd, srst_gpio); -} - -static void process_remote_protocol(void) -{ - int c; - while (1) { - c = getchar(); - if (c == EOF || c == 'Q') /* Quit */ - break; - else if (c == 'b' || c == 'B') /* Blink */ - continue; - else if (c >= 'r' && c <= 'r' + 2) { /* Reset */ - char d = c - 'r'; - sysfsgpio_reset(!!(d & 2), - (d & 1)); - } else if (c >= '0' && c <= '0' + 7) {/* Write */ - char d = c - '0'; - sysfsgpio_write(!!(d & 4), - !!(d & 2), - (d & 1)); - } else if (c == 'R') - putchar(sysfsgpio_read()); - else - LOG_ERROR("Unknown command '%c' received", c); - } -} - -int main(int argc, char *argv[]) -{ - LOG_WARNING("SysfsGPIO remote_bitbang JTAG driver\n"); - - for (int i = 1; i < argc; i++) { - if (!strcmp(argv[i], "tck")) - tck_gpio = atoi(argv[++i]); - else if (!strcmp(argv[i], "tms")) - tms_gpio = atoi(argv[++i]); - else if (!strcmp(argv[i], "tdo")) - tdo_gpio = atoi(argv[++i]); - else if (!strcmp(argv[i], "tdi")) - tdi_gpio = atoi(argv[++i]); - else if (!strcmp(argv[i], "trst")) - trst_gpio = atoi(argv[++i]); - else if (!strcmp(argv[i], "srst")) - srst_gpio = atoi(argv[++i]); - else { - LOG_ERROR("Usage:\n%s ((tck|tms|tdo|tdi|trst|srst) num)*", argv[0]); - return -1; - } - } - - if (!(is_gpio_valid(tck_gpio) - && is_gpio_valid(tms_gpio) - && is_gpio_valid(tdi_gpio) - && is_gpio_valid(tdo_gpio))) { - if (!is_gpio_valid(tck_gpio)) - LOG_ERROR("gpio num for tck is invalid"); - if (!is_gpio_valid(tms_gpio)) - LOG_ERROR("gpio num for tms is invalid"); - if (!is_gpio_valid(tdo_gpio)) - LOG_ERROR("gpio num for tdo is invalid"); - if (!is_gpio_valid(tdi_gpio)) - LOG_ERROR("gpio num for tdi is invalid"); - - LOG_ERROR("Require tck, tms, tdi and tdo gpios to all be specified"); - return ERROR_JTAG_INIT_FAILED; - } - - /* - * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST - * as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high. - */ - tck_fd = setup_sysfs_gpio(tck_gpio, 1, 0); - if (tck_fd < 0) - goto out_error; - - tms_fd = setup_sysfs_gpio(tms_gpio, 1, 1); - if (tms_fd < 0) - goto out_error; - - tdi_fd = setup_sysfs_gpio(tdi_gpio, 1, 0); - if (tdi_fd < 0) - goto out_error; - - tdo_fd = setup_sysfs_gpio(tdo_gpio, 0, 0); - if (tdo_fd < 0) - goto out_error; - - /* assume active low */ - if (trst_gpio > 0) { - trst_fd = setup_sysfs_gpio(trst_gpio, 1, 1); - if (trst_fd < 0) - goto out_error; - } - - /* assume active low */ - if (srst_gpio > 0) { - srst_fd = setup_sysfs_gpio(srst_gpio, 1, 1); - if (srst_fd < 0) - goto out_error; - } - - LOG_WARNING("SysfsGPIO nums: tck = %d, tms = %d, tdi = %d, tdo = %d", - tck_gpio, tms_gpio, tdi_gpio, tdo_gpio); - LOG_WARNING("SysfsGPIO num: srst = %d", srst_gpio); - LOG_WARNING("SysfsGPIO num: trst = %d", trst_gpio); - - setvbuf(stdout, NULL, _IONBF, 0); - process_remote_protocol(); - - cleanup_all_fds(); - return 0; -out_error: - cleanup_all_fds(); - return ERROR_JTAG_INIT_FAILED; -} diff --git a/tools/xsvf_tools/svf2xsvf.py b/tools/xsvf_tools/svf2xsvf.py deleted file mode 100644 index 113e0a61..00000000 --- a/tools/xsvf_tools/svf2xsvf.py +++ /dev/null @@ -1,729 +0,0 @@ -#!/usr/bin/python3.0 - -# Copyright 2008, SoftPLC Corporation http://softplc.com -# Dick Hollenbeck dick@softplc.com - - -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, you may find one here: -# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html -# or you may search the http://www.gnu.org website for the version 2 license, -# or you may write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - - -# A python program to convert an SVF file to an XSVF file. There is an -# option to include comments containing the source file line number from the origin -# SVF file before each outputted XSVF statement. -# -# We deviate from the XSVF spec in that we introduce a new command called -# XWAITSTATE which directly flows from the SVF RUNTEST command. Unfortunately -# XRUNSTATE was ill conceived and is not used here. We also add support for the -# three Lattice extensions to SVF: LCOUNT, LDELAY, and LSDR. The xsvf file -# generated from this program is suitable for use with the xsvf player in -# OpenOCD with my modifications to xsvf.c. -# -# This program is written for python 3.0, and it is not easy to change this -# back to 2.x. You may find it easier to use python 3.x even if that means -# building it. - - -import re -import sys -import struct - - -# There are both ------ and ------ sections to this program - - -if len( sys.argv ) < 3: - print("usage %s " % sys.argv[0]) - exit(1) - - -inputFilename = sys.argv[1] -outputFilename = sys.argv[2] - -doCOMMENTs = True # Save XCOMMENTs in the output xsvf file -#doCOMMENTs = False # Save XCOMMENTs in the output xsvf file - -# pick your file encoding -file_encoding = 'ISO-8859-1' -#file_encoding = 'utf-8' - - -xrepeat = 0 # argument to XREPEAT, gives retry count for masked compares - - -#-----< Lexer >--------------------------------------------------------------- - -StateBin = (RESET,IDLE, - DRSELECT,DRCAPTURE,DRSHIFT,DREXIT1,DRPAUSE,DREXIT2,DRUPDATE, - IRSELECT,IRCAPTURE,IRSHIFT,IREXIT1,IRPAUSE,IREXIT2,IRUPDATE) = range(16) - -# Any integer index into this tuple will be equal to its corresponding StateBin value -StateTxt = ("RESET","IDLE", - "DRSELECT","DRCAPTURE","DRSHIFT","DREXIT1","DRPAUSE","DREXIT2","DRUPDATE", - "IRSELECT","IRCAPTURE","IRSHIFT","IREXIT1","IRPAUSE","IREXIT2","IRUPDATE") - - -(XCOMPLETE,XTDOMASK,XSIR,XSDR,XRUNTEST,hole0,hole1,XREPEAT,XSDRSIZE,XSDRTDO, - XSETSDRMASKS,XSDRINC,XSDRB,XSDRC,XSDRE,XSDRTDOB,XSDRTDOC, - XSDRTDOE,XSTATE,XENDIR,XENDDR,XSIR2,XCOMMENT,XWAIT,XWAITSTATE, - LCOUNT,LDELAY,LSDR,XTRST) = range(29) - -#Note: LCOUNT, LDELAY, and LSDR are Lattice extensions to SVF and provide a way to loop back -# and check a completion status, essentially waiting on a part until it signals that it is done. -# For example below: loop 25 times, each time through the loop do a LDELAY (same as a true RUNTEST) -# and exit loop when LSDR compares match. -""" -LCOUNT 25; -! Step to DRPAUSE give 5 clocks and wait for 1.00e+000 SEC. -LDELAY DRPAUSE 5 TCK 1.00E-003 SEC; -! Test for the completed status. Match means pass. -! Loop back to LDELAY line if not match and loop count less than 25. -LSDR 1 TDI (0) - TDO (1); -""" - -#XTRST is an opcode Xilinx seemed to have missed and it comes from the SVF TRST statement. - -LineNumber = 1 - -def s_ident(scanner, token): return ("ident", token.upper(), LineNumber) - -def s_hex(scanner, token): - global LineNumber - LineNumber = LineNumber + token.count('\n') - token = ''.join(token.split()) - return ("hex", token[1:-1], LineNumber) - -def s_int(scanner, token): return ("int", int(token), LineNumber) -def s_float(scanner, token): return ("float", float(token), LineNumber) -#def s_comment(scanner, token): return ("comment", token, LineNumber) -def s_semicolon(scanner, token): return ("semi", token, LineNumber) - -def s_nl(scanner,token): - global LineNumber - LineNumber = LineNumber + 1 - #print( 'LineNumber=', LineNumber, file=sys.stderr ) - return None - -#2.00E-002 - -scanner = re.Scanner([ - (r"[a-zA-Z]\w*", s_ident), -# (r"[-+]?[0-9]+[.]?[0-9]*([eE][-+]?[0-9]+)?", s_float), - (r"[-+]?[0-9]+(([.][0-9eE+-]*)|([eE]+[-+]?[0-9]+))", s_float), - (r"\d+", s_int), - (r"\(([0-9a-fA-F]|\s)*\)", s_hex), - (r"(!|//).*$", None), - (r";", s_semicolon), - (r"\n",s_nl), - (r"\s*", None), - ], - re.MULTILINE - ) - -# open the file using the given encoding -file = open( sys.argv[1], encoding=file_encoding ) - -# read all svf file input into string "input" -input = file.read() - -file.close() - -# Lexer: -# create a list of tuples containing (tokenType, tokenValue, LineNumber) -tokens = scanner.scan( input )[0] - -input = None # allow gc to reclaim memory holding file - -#for tokenType, tokenValue, ln in tokens: print( "line %d: %s" % (ln, tokenType), tokenValue ) - - -#---------------------------------------------------------------------- - -tokVal = tokType = tokLn = None - -tup = iter( tokens ) - -def nextTok(): - """ - Function to read the next token from tup into tokType, tokVal, tokLn (linenumber) - which are globals. - """ - global tokType, tokVal, tokLn, tup - tokType, tokVal, tokLn = tup.__next__() - - -class ParseError(Exception): - """A class to hold a parsing error message""" - def __init__(self, linenumber, token, message): - self.linenumber = linenumber - self.token = token - self.message = message - def __str__(self): - global inputFilename - return "Error in file \'%s\' at line %d near token %s\n %s" % ( - inputFilename, self.linenumber, repr(self.token), self.message) - - -class MASKSET(object): - """ - Class MASKSET holds a set of bit vectors, all of which are related, will all - have the same length, and are associated with one of the seven shiftOps: - HIR, HDR, TIR, TDR, SIR, SDR, LSDR. One of these holds a mask, smask, tdi, tdo, and a - size. - """ - def __init__(self, name): - self.empty() - self.name = name - - def empty(self): - self.mask = bytearray() - self.smask = bytearray() - self.tdi = bytearray() - self.tdo = bytearray() - self.size = 0 - - def syncLengths( self, sawTDI, sawTDO, sawMASK, sawSMASK, newSize ): - """ - Set all the lengths equal in the event some of the masks were - not seen as part of the last change set. - """ - if self.size == newSize: - return - - if newSize == 0: - self.empty() - return - - # If an SIR was given without a MASK(), then use a mask of all zeros. - # this is not consistent with the SVF spec, but it makes sense because - # it would be odd to be testing an instruction register read out of a - # tap without giving a mask for it. Also, lattice seems to agree and is - # generating SVF files that comply with this philosophy. - if self.name == 'SIR' and not sawMASK: - self.mask = bytearray( newSize ) - - if newSize != len(self.mask): - self.mask = bytearray( newSize ) - if self.name == 'SDR': # leave mask for HIR,HDR,TIR,TDR,SIR zeros - for i in range( newSize ): - self.mask[i] = 1 - - if newSize != len(self.tdo): - self.tdo = bytearray( newSize ) - - if newSize != len(self.tdi): - self.tdi = bytearray( newSize ) - - if newSize != len(self.smask): - self.smask = bytearray( newSize ) - - self.size = newSize -#---------- - - -def makeBitArray( hexString, bitCount ): - """ - Converts a packed sequence of hex ascii characters into a bytearray where - each element in the array holds exactly one bit. Only "bitCount" bits are - scanned and these must be the least significant bits in the hex number. That - is, it is legal to have some unused bits in the must significant hex nibble - of the input "hexString". The string is scanned starting from the backend, - then just before returning we reverse the array. This way the append() - method can be used, which I assume is faster than an insert. - """ - global tokLn - a = bytearray() - length = bitCount - hexString = list(hexString) - hexString.reverse() - #print(hexString) - for c in hexString: - if length <= 0: - break; - c = int(c, 16) - for mask in [1,2,4,8]: - if length <= 0: - break; - length = length - 1 - a.append( (c & mask) != 0 ) - if length > 0: - raise ParseError( tokLn, hexString, "Insufficient hex characters for given length of %d" % bitCount ) - a.reverse() - #print(a) - return a - - -def makeXSVFbytes( bitarray ): - """ - Make a bytearray which is contains the XSVF bits which will be written - directly to disk. The number of bytes needed is calculated from the size - of the argument bitarray. - """ - bitCount = len(bitarray) - byteCount = (bitCount+7)//8 - ba = bytearray( byteCount ) - firstBit = (bitCount % 8) - 1 - if firstBit == -1: - firstBit = 7 - bitNdx = 0 - for byteNdx in range(byteCount): - mask = 1<> 1 - bitNdx = bitNdx + 1 - ba[byteNdx] = byte - firstBit = 7 - return ba - - -def writeComment( outputFile, shiftOp_linenum, shiftOp ): - """ - Write an XCOMMENT record to outputFile - """ - comment = "%s @%d\0" % (shiftOp, shiftOp_linenum) # \0 is terminating nul - ba = bytearray(1) - ba[0] = XCOMMENT - ba += comment.encode() - outputFile.write( ba ) - - -def combineBitVectors( trailer, meat, header ): - """ - Combine the 3 bit vectors comprizing a transmission. Since the least - significant bits are sent first, the header is put onto the list last so - they are sent first from that least significant position. - """ - ret = bytearray() - ret.extend( trailer ) - ret.extend( meat ) - ret.extend( header ) - return ret - - -def writeRUNTEST( outputFile, run_state, end_state, run_count, min_time, tokenTxt ): - """ - Write the output for the SVF RUNTEST command. - run_count - the number of clocks - min_time - the number of seconds - tokenTxt - either RUNTEST or LDELAY - """ - # convert from secs to usecs - min_time = int( min_time * 1000000) - - # the SVF RUNTEST command does NOT map to the XSVF XRUNTEST command. Check the SVF spec, then - # read the XSVF command. They are not the same. Use an XSVF XWAITSTATE to - # implement the required behavior of the SVF RUNTEST command. - if doCOMMENTs: - writeComment( output, tokLn, tokenTxt ) - - if tokenTxt == 'RUNTEST': - obuf = bytearray(11) - obuf[0] = XWAITSTATE - obuf[1] = run_state - obuf[2] = end_state - struct.pack_into(">i", obuf, 3, run_count ) # big endian 4 byte int to obuf - struct.pack_into(">i", obuf, 7, min_time ) # big endian 4 byte int to obuf - outputFile.write( obuf ) - else: # == 'LDELAY' - obuf = bytearray(10) - obuf[0] = LDELAY - obuf[1] = run_state - # LDELAY has no end_state - struct.pack_into(">i", obuf, 2, run_count ) # big endian 4 byte int to obuf - struct.pack_into(">i", obuf, 6, min_time ) # big endian 4 byte int to obuf - outputFile.write( obuf ) - - -output = open( outputFilename, mode='wb' ) - -hir = MASKSET('HIR') -hdr = MASKSET('HDR') -tir = MASKSET('TIR') -tdr = MASKSET('TDR') -sir = MASKSET('SIR') -sdr = MASKSET('SDR') - - -expecting_eof = True - - -# one of the commands that take the shiftParts after the length, the parse -# template for all of these commands is identical -shiftOps = ('SDR', 'SIR', 'LSDR', 'HDR', 'HIR', 'TDR', 'TIR') - -# the order must correspond to shiftOps, this holds the MASKSETS. 'LSDR' shares sdr with 'SDR' -shiftSets = (sdr, sir, sdr, hdr, hir, tdr, tir ) - -# what to expect as parameters to a shiftOp, i.e. after a SDR length or SIR length -shiftParts = ('TDI', 'TDO', 'MASK', 'SMASK') - -# the set of legal states which can trail the RUNTEST command -run_state_allowed = ('IRPAUSE', 'DRPAUSE', 'RESET', 'IDLE') - -enddr_state_allowed = ('DRPAUSE', 'IDLE') -endir_state_allowed = ('IRPAUSE', 'IDLE') - -trst_mode_allowed = ('ON', 'OFF', 'Z', 'ABSENT') - -enddr_state = IDLE -endir_state = IDLE - -frequency = 1.00e+006 # HZ; - -# change detection for xsdrsize and xtdomask -xsdrsize = -1 # the last one sent, send only on change -xtdomask = bytearray() # the last one sent, send only on change - - -# we use a number of single byte writes for the XSVF command below -cmdbuf = bytearray(1) - - -# Save the XREPEAT setting into the file as first thing. -obuf = bytearray(2) -obuf[0] = XREPEAT -obuf[1] = xrepeat -output.write( obuf ) - - -try: - while 1: - expecting_eof = True - nextTok() - expecting_eof = False - # print( tokType, tokVal, tokLn ) - - if tokVal in shiftOps: - shiftOp_linenum = tokLn - shiftOp = tokVal - - set = shiftSets[shiftOps.index(shiftOp)] - - # set flags false, if we see one later, set that one true later - sawTDI = sawTDO = sawMASK = sawSMASK = False - - nextTok() - if tokType != 'int': - raise ParseError( tokLn, tokVal, "Expecting 'int' giving %s length, got '%s'" % (shiftOp, tokType) ) - length = tokVal - - nextTok() - - while tokVal != ';': - if tokVal not in shiftParts: - raise ParseError( tokLn, tokVal, "Expecting TDI, TDO, MASK, SMASK, or ';'") - shiftPart = tokVal - - nextTok() - - if tokType != 'hex': - raise ParseError( tokLn, tokVal, "Expecting hex bits" ) - bits = makeBitArray( tokVal, length ) - - if shiftPart == 'TDI': - sawTDI = True - set.tdi = bits - - elif shiftPart == 'TDO': - sawTDO = True - set.tdo = bits - - elif shiftPart == 'MASK': - sawMASK = True - set.mask = bits - - elif shiftPart == 'SMASK': - sawSMASK = True - set.smask = bits - - nextTok() - - set.syncLengths( sawTDI, sawTDO, sawMASK, sawSMASK, length ) - - # process all the gathered parameters and generate outputs here - if shiftOp == 'SIR': - if doCOMMENTs: - writeComment( output, shiftOp_linenum, 'SIR' ) - - tdi = combineBitVectors( tir.tdi, sir.tdi, hir.tdi ) - if len(tdi) > 255: - obuf = bytearray(3) - obuf[0] = XSIR2 - struct.pack_into( ">h", obuf, 1, len(tdi) ) - else: - obuf = bytearray(2) - obuf[0] = XSIR - obuf[1] = len(tdi) - output.write( obuf ) - obuf = makeXSVFbytes( tdi ) - output.write( obuf ) - - elif shiftOp == 'SDR': - if doCOMMENTs: - writeComment( output, shiftOp_linenum, shiftOp ) - - if not sawTDO: - # pass a zero filled bit vector for the sdr.mask - mask = combineBitVectors( tdr.mask, bytearray(sdr.size), hdr.mask ) - tdi = combineBitVectors( tdr.tdi, sdr.tdi, hdr.tdi ) - - if xsdrsize != len(tdi): - xsdrsize = len(tdi) - cmdbuf[0] = XSDRSIZE - output.write( cmdbuf ) - obuf = bytearray(4) - struct.pack_into( ">i", obuf, 0, xsdrsize ) # big endian 4 byte int to obuf - output.write( obuf ) - - if xtdomask != mask: - xtdomask = mask - cmdbuf[0] = XTDOMASK - output.write( cmdbuf ) - obuf = makeXSVFbytes( mask ) - output.write( obuf ) - - cmdbuf[0] = XSDR - output.write( cmdbuf ) - obuf = makeXSVFbytes( tdi ) - output.write( obuf ) - - else: - mask = combineBitVectors( tdr.mask, sdr.mask, hdr.mask ) - tdi = combineBitVectors( tdr.tdi, sdr.tdi, hdr.tdi ) - tdo = combineBitVectors( tdr.tdo, sdr.tdo, hdr.tdo ) - - if xsdrsize != len(tdi): - xsdrsize = len(tdi) - cmdbuf[0] = XSDRSIZE - output.write( cmdbuf ) - obuf = bytearray(4) - struct.pack_into(">i", obuf, 0, xsdrsize ) # big endian 4 byte int to obuf - output.write( obuf ) - - if xtdomask != mask: - xtdomask = mask - cmdbuf[0] = XTDOMASK - output.write( cmdbuf ) - obuf = makeXSVFbytes( mask ) - output.write( obuf ) - - cmdbuf[0] = XSDRTDO - output.write( cmdbuf ) - obuf = makeXSVFbytes( tdi ) - output.write( obuf ) - obuf = makeXSVFbytes( tdo ) - output.write( obuf ) - #print( "len(tdo)=", len(tdo), "len(tdr.tdo)=", len(tdr.tdo), "len(sdr.tdo)=", len(sdr.tdo), "len(hdr.tdo)=", len(hdr.tdo) ) - - elif shiftOp == 'LSDR': - if doCOMMENTs: - writeComment( output, shiftOp_linenum, shiftOp ) - - mask = combineBitVectors( tdr.mask, sdr.mask, hdr.mask ) - tdi = combineBitVectors( tdr.tdi, sdr.tdi, hdr.tdi ) - tdo = combineBitVectors( tdr.tdo, sdr.tdo, hdr.tdo ) - - if xsdrsize != len(tdi): - xsdrsize = len(tdi) - cmdbuf[0] = XSDRSIZE - output.write( cmdbuf ) - obuf = bytearray(4) - struct.pack_into(">i", obuf, 0, xsdrsize ) # big endian 4 byte int to obuf - output.write( obuf ) - - if xtdomask != mask: - xtdomask = mask - cmdbuf[0] = XTDOMASK - output.write( cmdbuf ) - obuf = makeXSVFbytes( mask ) - output.write( obuf ) - - cmdbuf[0] = LSDR - output.write( cmdbuf ) - obuf = makeXSVFbytes( tdi ) - output.write( obuf ) - obuf = makeXSVFbytes( tdo ) - output.write( obuf ) - #print( "len(tdo)=", len(tdo), "len(tdr.tdo)=", len(tdr.tdo), "len(sdr.tdo)=", len(sdr.tdo), "len(hdr.tdo)=", len(hdr.tdo) ) - - elif tokVal == 'RUNTEST' or tokVal == 'LDELAY': - # e.g. from lattice tools: - # "RUNTEST IDLE 5 TCK 1.00E-003 SEC;" - saveTok = tokVal - nextTok() - min_time = 0 - run_count = 0 - max_time = 600 # ten minutes - if tokVal in run_state_allowed: - run_state = StateTxt.index(tokVal) - end_state = run_state # bottom of page 17 of SVF spec - nextTok() - if tokType != 'int' and tokType != 'float': - raise ParseError( tokLn, tokVal, "Expecting 'int' or 'float' after RUNTEST [run_state]") - timeval = tokVal; - nextTok() - if tokVal != 'TCK' and tokVal != 'SEC' and tokVal != 'SCK': - raise ParseError( tokLn, tokVal, "Expecting 'TCK' or 'SEC' or 'SCK' after RUNTEST [run_state] (run_count|min_time)") - if tokVal == 'TCK' or tokVal == 'SCK': - run_count = int( timeval ) - else: - min_time = timeval - nextTok() - if tokType == 'int' or tokType == 'float': - min_time = tokVal - nextTok() - if tokVal != 'SEC': - raise ParseError( tokLn, tokVal, "Expecting 'SEC' after RUNTEST [run_state] run_count min_time") - nextTok() - if tokVal == 'MAXIMUM': - nextTok() - if tokType != 'int' and tokType != 'float': - raise ParseError( tokLn, tokVal, "Expecting 'max_time' after RUNTEST [run_state] min_time SEC MAXIMUM") - max_time = tokVal - nextTok() - if tokVal != 'SEC': - raise ParseError( tokLn, tokVal, "Expecting 'max_time' after RUNTEST [run_state] min_time SEC MAXIMUM max_time") - nextTok() - if tokVal == 'ENDSTATE': - nextTok() - if tokVal not in run_state_allowed: - raise ParseError( tokLn, tokVal, "Expecting 'run_state' after RUNTEST .... ENDSTATE") - end_state = StateTxt.index(tokVal) - nextTok() - if tokVal != ';': - raise ParseError( tokLn, tokVal, "Expecting ';' after RUNTEST ....") - # print( "run_count=", run_count, "min_time=", min_time, - # "max_time=", max_time, "run_state=", State[run_state], "end_state=", State[end_state] ) - writeRUNTEST( output, run_state, end_state, run_count, min_time, saveTok ) - - elif tokVal == 'LCOUNT': - nextTok() - if tokType != 'int': - raise ParseError( tokLn, tokVal, "Expecting integer 'count' after LCOUNT") - loopCount = tokVal - nextTok() - if tokVal != ';': - raise ParseError( tokLn, tokVal, "Expecting ';' after LCOUNT count") - if doCOMMENTs: - writeComment( output, tokLn, 'LCOUNT' ) - obuf = bytearray(5) - obuf[0] = LCOUNT - struct.pack_into(">i", obuf, 1, loopCount ) # big endian 4 byte int to obuf - output.write( obuf ) - - elif tokVal == 'ENDDR': - nextTok() - if tokVal not in enddr_state_allowed: - raise ParseError( tokLn, tokVal, "Expecting 'stable_state' after ENDDR. (one of: DRPAUSE, IDLE)") - enddr_state = StateTxt.index(tokVal) - nextTok() - if tokVal != ';': - raise ParseError( tokLn, tokVal, "Expecting ';' after ENDDR stable_state") - if doCOMMENTs: - writeComment( output, tokLn, 'ENDDR' ) - obuf = bytearray(2) - obuf[0] = XENDDR - # Page 10 of the March 1999 SVF spec shows that RESET is also allowed here. - # Yet the XSVF spec has no provision for that, and uses a non-standard, i.e. - # boolean argument to XENDDR which only handles two of the 3 intended states. - obuf[1] = 1 if enddr_state == DRPAUSE else 0 - output.write( obuf ) - - elif tokVal == 'ENDIR': - nextTok() - if tokVal not in endir_state_allowed: - raise ParseError( tokLn, tokVal, "Expecting 'stable_state' after ENDIR. (one of: IRPAUSE, IDLE)") - endir_state = StateTxt.index(tokVal) - nextTok() - if tokVal != ';': - raise ParseError( tokLn, tokVal, "Expecting ';' after ENDIR stable_state") - if doCOMMENTs: - writeComment( output, tokLn, 'ENDIR' ) - obuf = bytearray(2) - obuf[0] = XENDIR - # Page 10 of the March 1999 SVF spec shows that RESET is also allowed here. - # Yet the XSVF spec has no provision for that, and uses a non-standard, i.e. - # boolean argument to XENDDR which only handles two of the 3 intended states. - obuf[1] = 1 if endir_state == IRPAUSE else 0 - output.write( obuf ) - - elif tokVal == 'STATE': - nextTok() - ln = tokLn - while tokVal != ';': - if tokVal not in StateTxt: - raise ParseError( tokLn, tokVal, "Expecting 'stable_state' after STATE") - stable_state = StateTxt.index( tokVal ) - - if doCOMMENTs and ln != -1: - writeComment( output, ln, 'STATE' ) - ln = -1 # save comment only once - - obuf = bytearray(2) - obuf[0] = XSTATE - obuf[1] = stable_state - output.write( obuf ) - nextTok() - - elif tokVal == 'FREQUENCY': - nextTok() - if tokVal != ';': - if tokType != 'int' and tokType != 'float': - raise ParseError( tokLn, tokVal, "Expecting 'cycles HZ' after FREQUENCY") - frequency = tokVal - nextTok() - if tokVal != 'HZ': - raise ParseError( tokLn, tokVal, "Expecting 'HZ' after FREQUENCY cycles") - nextTok() - if tokVal != ';': - raise ParseError( tokLn, tokVal, "Expecting ';' after FREQUENCY cycles HZ") - - elif tokVal == 'TRST': - nextTok() - if tokVal not in trst_mode_allowed: - raise ParseError( tokLn, tokVal, "Expecting 'ON|OFF|Z|ABSENT' after TRST") - trst_mode = tokVal - nextTok() - if tokVal != ';': - raise ParseError( tokLn, tokVal, "Expecting ';' after TRST trst_mode") - if doCOMMENTs: - writeComment( output, tokLn, 'TRST %s' % trst_mode ) - obuf = bytearray( 2 ) - obuf[0] = XTRST - obuf[1] = trst_mode_allowed.index( trst_mode ) # use the index as the binary argument to XTRST opcode - output.write( obuf ) - - else: - raise ParseError( tokLn, tokVal, "Unknown token '%s'" % tokVal) - -except StopIteration: - if not expecting_eof: - print( "Unexpected End of File at line ", tokLn ) - -except ParseError as pe: - print( "\n", pe ) - -finally: - # print( "closing file" ) - cmdbuf[0] = XCOMPLETE - output.write( cmdbuf ) - output.close() - diff --git a/tools/xsvf_tools/xsvfdump.py b/tools/xsvf_tools/xsvfdump.py deleted file mode 100644 index e65f8d5b..00000000 --- a/tools/xsvf_tools/xsvfdump.py +++ /dev/null @@ -1,268 +0,0 @@ -#!/usr/bin/python3.0 - -# Copyright 2008, SoftPLC Corporation http://softplc.com -# Dick Hollenbeck dick@softplc.com - -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, you may find one here: -# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html -# or you may search the http://www.gnu.org website for the version 2 license, -# or you may write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - -# Dump an Xilinx XSVF file to stdout - -# This program is written for python 3.0, and it is not easy to change this -# back to 2.x. You may find it easier to use python 3.x even if that means -# building it. - - -import sys -import struct - - -LABEL = "A script to dump an XSVF file to stdout" - - -Xsdrsize = 0 - - -(XCOMPLETE,XTDOMASK,XSIR,XSDR,XRUNTEST,hole0,hole1,XREPEAT,XSDRSIZE,XSDRTDO, - XSETSDRMASKS,XSDRINC,XSDRB,XSDRC,XSDRE,XSDRTDOB,XSDRTDOC, - XSDRTDOE,XSTATE,XENDIR,XENDDR,XSIR2,XCOMMENT,XWAIT,XWAITSTATE, - LCOUNT,LDELAY,LSDR,XTRST) = range(29) - - -(RESET,IDLE, - DRSELECT,DRCAPTURE,DRSHIFT,DREXIT1,DRPAUSE,DREXIT2,DRUPDATE, - IRSELECT,IRCAPTURE,IRSHIFT,IREXIT1,IRPAUSE,IREXIT2,IRUPDATE) = range(16) - - -State = ("RESET","IDLE", - "DRSELECT","DRCAPTURE","DRSHIFT","DREXIT1","DRPAUSE","DREXIT2","DRUPDATE", - "IRSELECT","IRCAPTURE","IRSHIFT","IREXIT1","IRPAUSE","IREXIT2","IRUPDATE") - - -trst_mode_allowed = ('ON', 'OFF', 'Z', 'ABSENT') - - -Setsdrmasks = 0 -SetsdrmasksOnesCount = 0 - -def ReadSDRMASKS( f, len ): - global Setsdrmasks, SetsdrmasksOnesCount - byteCount = (len+7)//8 - Setsdrmasks = f.read( byteCount ) - ls = [] - SetsdrmasksOnesCount = 0 - for b in Setsdrmasks: - ls.append( "%x" % ((b & 0xf0) >> 4) ) - ls.append( "%x" % ( b & 0x0f ) ) - for i in range(8): - if b & (1<> 4) ) - ls.append( "%x" % ( b & 0x0f ) ) - return ''.join(ls) - - -def ReadByte( f ): - """Read a byte from a file and return it as an int in least significant 8 bits""" - b = f.read(1) - if b: - return 0xff & b[0]; - else: - return -1 - - -def ShowState( state ): - """return the given state int as a state string""" - #return "0x%02x" % state # comment this out to get textual state form - global State - if 0 <= state <= IRUPDATE: - return State[state] - else: - return "Unknown state 0x%02x" % state - - -def ShowOpcode( op, f ): - """return the given byte as an opcode string""" - global Xsdrsize - if op == XCOMPLETE: - print("XCOMPLETE") - - elif op == XTDOMASK: - buf = bytes2hexString( f, Xsdrsize ) - print("XTDOMASK 0x%s" % buf) - - elif op == XSIR: - len = ReadByte( f ) - buf = bytes2hexString( f, len ) - print("XSIR 0x%02X 0x%s" % (len, buf)) - - elif op == XSDR: - tdi = bytes2hexString( f, Xsdrsize ) - print("XSDR 0x%s" % tdi) - - elif op == XRUNTEST: - len = struct.unpack( '>i', f.read(4) )[0] - print("XRUNTEST 0x%08X" % len) - - elif op == XREPEAT: - len = ReadByte( f ) - print("XREPEAT 0x%02X" % len) - - elif op == XSDRSIZE: - Xsdrsize = struct.unpack( '>i', f.read(4) )[0] - #print("XSDRSIZE 0x%08X" % Xsdrsize, file=sys.stderr ) - print("XSDRSIZE 0x%08X %d" % (Xsdrsize, Xsdrsize) ) - - elif op == XSDRTDO: - tdi = bytes2hexString( f, Xsdrsize ) - tdo = bytes2hexString( f, Xsdrsize ) - print("XSDRTDO 0x%s 0x%s" % (tdi, tdo) ) - - elif op == XSETSDRMASKS: - addrmask = bytes2hexString( f, Xsdrsize ) - datamask = ReadSDRMASKS( f, Xsdrsize ) - print("XSETSDRMASKS 0x%s 0x%s" % (addrmask, datamask) ) - - elif op == XSDRINC: - startaddr = bytes2hexString( f, Xsdrsize ) - len = ReadByte(f) - print("XSDRINC 0x%s 0x%02X" % (startaddr, len), end='' ) - for numTimes in range(len): - data = bytes2hexString( f, SetsdrmasksOnesCount) - print(" 0x%s" % data ) - print() # newline - - elif op == XSDRB: - tdi = bytes2hexString( f, Xsdrsize ) - print("XSDRB 0x%s" % tdi ) - - elif op == XSDRC: - tdi = bytes2hexString( f, Xsdrsize ) - print("XSDRC 0x%s" % tdi ) - - elif op == XSDRE: - tdi = bytes2hexString( f, Xsdrsize ) - print("XSDRE 0x%s" % tdi ) - - elif op == XSDRTDOB: - tdo = bytes2hexString( f, Xsdrsize ) - print("XSDRTDOB 0x%s" % tdo ) - - elif op == XSDRTDOC: - tdi = bytes2hexString( f, Xsdrsize ) - tdo = bytes2hexString( f, Xsdrsize ) - print("XSDRTDOC 0x%s 0x%s" % (tdi, tdo) ) - - elif op == XSDRTDOE: - tdi = bytes2hexString( f, Xsdrsize ) - tdo = bytes2hexString( f, Xsdrsize ) - print("XSDRTDOE 0x%s 0x%s" % (tdi, tdo) ) - - elif op == XSTATE: - b = ReadByte(f) - print("XSTATE %s" % ShowState(b)) - - elif op == XENDIR: - b = ReadByte( f ) - print("XENDIR %s" % 'IRPAUSE' if b==1 else 'IDLE') - - elif op == XENDDR: - b = ReadByte( f ) - print("XENDDR %s" % 'DRPAUSE' if b==1 else 'IDLE') - - elif op == XSIR2: - len = struct.unpack( '>H', f.read(2) )[0] - buf = bytes2hexString( f, len ) - print("XSIR2 0x%04X 0x%s" % (len, buf)) - - elif op == XCOMMENT: - cmt = [] - while 1: - b = ReadByte(f) - if b == 0: # terminating nul - break; - cmt.append( chr(b) ) - print("XCOMMENT \"%s\"" % ''.join(cmt) ) - - elif op == XWAIT: - run_state = ReadByte(f) - end_state = ReadByte(f) - useconds = struct.unpack( '>i', f.read(4) )[0] - print("XWAIT %s %s" % (ShowState(run_state), ShowState(end_state)), useconds) - - elif op == XWAITSTATE: - run_state = ReadByte(f) - end_state = ReadByte(f) - clocks = struct.unpack( '>i', f.read(4) )[0] - useconds = struct.unpack( '>i', f.read(4) )[0] - print("XWAITSTATE %s %s CLOCKS=%d USECS=%d" % (ShowState(run_state), ShowState(end_state), clocks, useconds) ) - - elif op == LCOUNT: - loop_count = struct.unpack( '>i', f.read(4) )[0] - print("LCOUNT", loop_count ) - - elif op == LDELAY: - run_state = ReadByte(f) - clocks = struct.unpack( '>i', f.read(4) )[0] - useconds = struct.unpack( '>i', f.read(4) )[0] - print("LDELAY %s CLOCKS=%d USECS=%d" % (ShowState(run_state), clocks, useconds) ) - - elif op == LSDR: - tdi = bytes2hexString( f, Xsdrsize ) - tdo = bytes2hexString( f, Xsdrsize ) - print("LSDR 0x%s 0x%s" % (tdi, tdo) ) - - elif op == XTRST: - # the argument is a single byte and it is the index into "trst_mode_allowed" - trst_mode = ReadByte(f) - if trst_mode <= 3: - print("TRST %s" % trst_mode_allowed[trst_mode] ) - else: - print("TRST 0x%02X" % trst_mode ); - - else: - print("UNKNOWN op 0x%02X %d" % (op, op)) - exit(1) - - -def main(): - - if len( sys.argv ) < 2: - print("usage %s " % sys.argv[0]) - exit(1) - - f = open( sys.argv[1], 'rb' ) - - opcode = ReadByte( f ) - while opcode != -1: - # print the position within the file, then the command - print( "%d: " % f.tell(), end='' ) - ShowOpcode( opcode, f ) - opcode = ReadByte(f) - - -if __name__ == "__main__": - main() -