From: Joshua Wise Date: Thu, 19 Jun 2008 03:01:59 +0000 (-0400) Subject: initial commit of s3load X-Git-Url: http://git.joshuawise.com/s3load.git/commitdiff_plain/refs/remotes/origin/master initial commit of s3load --- 5ee943f9cb03c6e18160be40b69437a9c9b897c6 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c0bdb7d --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +s3load: s3load.c libnexys.c libnexys.h + gcc -o s3load s3load.c libnexys.c -lusb + +s3load-pp: s3load.c libnexys.parport.c libnexys.h + gcc -o s3load-pp -DPARPORT s3load.c libnexys.parport.c + +s3load-win32.exe: s3load.c libnexys.win32.c libnexys.h + gcc -o s3load-win32.exe s3load.c libnexys.win32.c dpcutil.lib diff --git a/libnexys.c b/libnexys.c new file mode 100644 index 0000000..9fbf833 --- /dev/null +++ b/libnexys.c @@ -0,0 +1,405 @@ +#ifdef WIN32_NATIVE +#include "libnexys.win32.c" +#else +#define LIBNEXYS_INTERNAL +#include "libnexys.h" +#include +#include + +#define NEXYS2_VENDOR 0x1443 +#define NEXYS2_DEVICE 0x0005 + +nexys2_t nexys2_init(void) { + struct usb_bus *bus; + struct usb_device *dev; + usb_dev_handle *udev; + int dev_found, ret; + unsigned char buf[15]; + + usb_init(); + + usb_find_busses(); + usb_find_devices(); + + udev = NULL; + for (bus = usb_get_busses(); bus && !udev; bus = bus->next) + for (dev = bus->devices; dev && !udev; dev = dev->next) + if ((dev->descriptor.idVendor == NEXYS2_VENDOR) && (dev->descriptor.idProduct == NEXYS2_DEVICE)) + udev = usb_open(dev); + + if (!udev) + { + fprintf(stderr, "nexys2_init: no device found or device open failed\n"); + return NULL; + } + + if (usb_set_configuration(udev, 1) < 0) + { + fprintf(stderr, "nexys2_init: failed to set configuration 1 -- check your permissions\n"); + return NULL; + } + + if (usb_claim_interface(udev, 0) < 0) /* Needed for libusb on win32. This code somehow crashes win32 libusb/kernel anyway, but... */ + { + fprintf(stderr, "nexys2_init: failed to claim interface 0 -- check your permissions\n"); + return NULL; + } + + if (usb_clear_halt(udev, 0x01) < 0) /* Sometimes the board locks up when you close it, so send this. */ + { + fprintf(stderr, "nexys2_init: failed to clear halt on interface 0x01\n"); + return NULL; + } + + ret = usb_control_msg(udev, 0x00, 0x09, 1, 0, NULL, 0, 1000); + if (ret < 0) + { + fprintf(stderr, "nexys2_init: failed to send setup control message\n"); + return NULL; + } + + ret = usb_control_msg(udev, 0xC0, 0xE4, 0, 0, buf, 14, 1000); + if (ret < 0) + { + fprintf(stderr, "nexys2_init: failed to send serial number control message\n"); + return NULL; + } + + buf[ret] = 0; + fprintf(stderr, "nexys2_init: got serial number \"%s\" (%d bytes)\n", buf, ret); + + ret = usb_control_msg(udev, 0xC0, 0xE6, 0, 0, buf, 4, 1000); + if (ret < 0) + { + fprintf(stderr, "nexys2_init: failed to send magic goo message\n"); + return NULL; + } + if (memcmp(buf, "\x01\x00\x02\x00", 4)) + { + fprintf(stderr, "nexys2_init: magic goo did not return what we expected (%d, %02x %02x %02x %02x)\n", ret, buf[0], buf[1], buf[2], buf[3]); + return NULL; + } + + return udev; +} + +static unsigned char common_response[64] = + { 0x00, 0x03, 0xf3, 0x77, 0x9f, 0xf5, 0xdf, 0xdd, + 0xdf, 0xfe, 0x5f, 0xac, 0xff, 0xad, 0xf3, 0x34, + 0xaf, 0xf5, 0xac, 0xf7, 0xca, 0xb7, 0xf7, 0x6f, + 0xff, 0x5e, 0x5e, 0xf7, 0xfb, 0xfd, 0xfb, 0x37, + 0x81, 0x53, 0xbf, 0x64, 0x59, 0x47, 0x59, 0x2d, + 0xe8, 0x30, 0x77, 0xda, 0x4f, 0xaf, 0x7f, 0xd7, + 0x5f, 0xee, 0xc7, 0x3b, 0xdf, 0x3e, 0xbf, 0x35, + 0xd1, 0xdf, 0xef, 0x3f, 0x9f, 0xde, 0xfa, 0xe2 + }; + +int nexys2_jtag_enable(usb_dev_handle *udev) +{ + int ret; + unsigned char message[64] = + { 0x07, 0x01, 0x00, 0x00, 0xdc, 0xff, 0xd3, 0x00, + 0xf3, 0x99, 0x83, 0x7c, 0x08, 0x26, 0x80, 0x7c, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x26, 0x80, 0x7c, + 0xf1, 0xe2, 0x90, 0x7c, 0xb7, 0x24, 0x80, 0x7c, + 0x14, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2a, 0x95, 0x80, 0x7c, 0x5b, 0x3d, 0x00, 0x11, + 0x14, 0x07, 0x00, 0x00, 0xe8, 0x22, 0xa0, 0x00, + 0x02, 0x00, 0x00, 0x00, 0xb3, 0x9e, 0x01, 0x11 /* XXX does this need to be sequenced? */ + }; + unsigned char resp[64]; + + if ((ret = usb_bulk_write(udev, 0x01, message, 64, 1000)) < 64) + { + fprintf(stderr, "nexys2_jtag_enable: write failed: %d (%s)\n", ret, usb_strerror()); + return -1; + } + + if ((ret = usb_bulk_read(udev, 0x81, resp, 64, 1000)) < 64) + { + fprintf(stderr, "nexys2_jtag_enable: short read on response: %d\n", ret); + return -1; + } + + if (memcmp(resp, common_response, 64)) + { + fprintf(stderr, "nexys2_jtag_enable: incorrect response?\n"); +// return -1; + } + + return 0; +} + +int nexys2_jtag_disable(usb_dev_handle *udev) +{ + int ret; + unsigned char message[64] = + { 0x07, 0x00, 0xf3, 0x76, 0xdc, 0xff, 0xd3, 0x00, + 0xf3, 0x99, 0x83, 0x7c, 0x08, 0x26, 0x80, 0x7c, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x26, 0x80, 0x7c, + 0xf1, 0xe2, 0x90, 0x7c, 0xb7, 0x24, 0x80, 0x7c, + 0x14, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2a, 0x95, 0x80, 0x7c, 0x5b, 0x3d, 0x00, 0x11, + 0x14, 0x07, 0x00, 0x00, 0xe8, 0x22, 0xa0, 0x00, + 0x05, 0x00, 0x00, 0x00, 0xb3, 0x9e, 0x01, 0x11 /* XXX does this need to be sequenced? */ + }; + unsigned char resp[64]; + + if ((ret = usb_bulk_write(udev, 0x01, message, 64, 1000)) < 64) + { + fprintf(stderr, "nexys2_jtag_disable: write failed: %d (%s)\n", ret, usb_strerror()); + return -1; + } + + if ((ret = usb_bulk_read(udev, 0x81, resp, 64, 1000)) < 64) + { + fprintf(stderr, "nexys2_jtag_disable: short read on response: %d\n", ret); + return -1; + } + + if (memcmp(resp, common_response, 64)) + { + fprintf(stderr, "nexys2_jtag_disable: incorrect response?\n"); +// return -1; + } + + return 0; +} + +int nexys2_jtag_setbits(usb_dev_handle *udev, int tms, int tdi, int tck) +{ + int ret; + unsigned char message[64] = + { 0x08, !!tms, !!tdi, !!tck, 0xdc, 0xff, 0xd3, 0x00, + 0xf3, 0x99, 0x83, 0x7c, 0x08, 0x26, 0x80, 0x7c, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x26, 0x80, 0x7c, + 0xf1, 0xe2, 0x90, 0x7c, 0xb7, 0x24, 0x80, 0x7c, + 0x14, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2a, 0x95, 0x80, 0x7c, 0x5b, 0x3d, 0x00, 0x11, + 0x14, 0x07, 0x00, 0x00, 0xe8, 0x22, 0xa0, 0x00, + 0x03, 0x00, 0x00, 0x00, 0xb3, 0x9e, 0x01, 0x11 /* XXX does this need to be sequenced? */ + }; + unsigned char resp[64]; + + if ((ret = usb_bulk_write(udev, 0x01, message, 64, 1000)) < 64) + { + fprintf(stderr, "nexys2_jtag_setbits: write failed: %d (%s)\n", ret, usb_strerror()); + return -1; + } + +/* if ((ret = usb_bulk_read(udev, 0x81, resp, 64, 1000)) < 64) + { + fprintf(stderr, "nexys2_jtag_setbits: short read on response: %d\n", ret); + return -1; + } + + if (memcmp(resp, common_response, 64)) + { + fprintf(stderr, "nexys2_jtag_setbits: incorrect response?\n"); + return -1; + }*/ + + return 0; +} + +int nexys2_jtag_puttdi(usb_dev_handle *udev, int tms, int nbits, unsigned char *bits, unsigned char *obits) +{ + int wanttdo = obits ? 1 : 0; + int bytesrem; + int ret; + + unsigned char message[64] = + { 0x09, wanttdo, !!tms, 0x00, 0x00, (nbits >> 8) & 0xFF, nbits & 0xFF, 0x7C, + 0xeb, 0x06, 0x91, 0x7c, 0x28, 0xfa, 0xd3, 0x00, + 0xec, 0xfc, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + if (nbits > 0xFFFF) + { + fprintf(stderr, "nexys2_jtag_puttdi: too many bits!\n"); + return -1; + } + + if ((ret = usb_bulk_write(udev, 0x01, message, 64, 1000)) < 64) + { + fprintf(stderr, "nexys2_jtag_puttdi: write failed: %d (%s)\n", ret, usb_strerror()); + return -1; + } + + bytesrem = nbits / 8 + ((nbits % 8) != 0); + while (bytesrem) + { + int nbytes = (bytesrem > 512) ? 512 : bytesrem; + if ((ret = usb_bulk_write(udev, 0x02, bits, nbytes, 1000)) < nbytes) + { + fprintf(stderr, "nexys2_jtag_puttdi: data write failed: %d (%s)\n", ret, usb_strerror()); + return -1; + } + bits += nbytes; + bytesrem -= nbytes; + } + + if (obits) + { + bytesrem = nbits / 8 + ((nbits % 8) != 0); + while (bytesrem) + { + int nbytes = (bytesrem > 512) ? 512 : bytesrem; + if ((ret = usb_bulk_read(udev, 0x86, obits, nbytes, 1000)) < nbytes) + { + fprintf(stderr, "nexys2_jtag_puttdi: data read failed: %d (%s)\n", ret, usb_strerror()); + return -1; + } + obits += nbytes; + bytesrem -= nbytes; + } + } + + return 0; +} + +int nexys2_jtag_puttmstdi(usb_dev_handle *udev, int nbits, unsigned char *bits, unsigned char *obits) +{ + int wanttdo = obits ? 1 : 0; + int bytesrem; + int ret; + + unsigned char message[64] = + { 0x0a, wanttdo, 0x00, 0x00, (nbits >> 8) & 0xFF, nbits & 0xFF, 0x91, 0x7C, + 0xeb, 0x06, 0x91, 0x7c, 0x28, 0xfa, 0xd3, 0x00, + 0xec, 0xfc, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + if (nbits > 0xFFFF) + { + fprintf(stderr, "nexys2_jtag_puttmstdi: too many bits!\n"); + return -1; + } + + if ((ret = usb_bulk_write(udev, 0x01, message, 64, 1000)) < 64) + { + fprintf(stderr, "nexys2_jtag_puttmstdi: write failed: %d (%s)\n", ret, usb_strerror()); + return -1; + } + + bytesrem = nbits / 4 + ((nbits % 4) != 0); + while (bytesrem) + { + int nbytes = (bytesrem > 512) ? 512 : bytesrem; + if ((ret = usb_bulk_write(udev, 0x02, bits, nbytes, 1000)) < nbytes) + { + fprintf(stderr, "nexys2_jtag_puttmstdi: data write failed: %d (%s)\n", ret, usb_strerror()); + return -1; + } + if (obits) + { + int nrbytes = nbytes/2 + (nbytes % 2); + if ((ret = usb_bulk_read(udev, 0x86, obits, nrbytes, 1000)) < nrbytes) + { + fprintf(stderr, "nexys2_jtag_puttmstdi: data read failed: %d (%s)\n", ret, usb_strerror()); + return -1; + } + obits += nrbytes; + } + bits += nbytes; + bytesrem -= nbytes; + } + + return 0; +} + +int nexys2_jtag_gettdo(usb_dev_handle *udev, int tdi, int tms, int nbits, unsigned char *obits) +{ + int wanttdo = obits ? 1 : 0; + int bytesrem; + int ret; + + unsigned char message[64] = + { 0x0B, !!tdi, !!tms, 0x00, 0x00, (nbits >> 8) & 0xFF, nbits & 0xFF, 0x7C, + 0xeb, 0x06, 0x91, 0x7c, 0x28, 0xfa, 0xd3, 0x00, + 0xec, 0xfc, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + if (nbits > 0xFFFF) + { + fprintf(stderr, "nexys2_jtag_puttdo: too many bits!\n"); + return -1; + } + + if ((ret = usb_bulk_write(udev, 0x01, message, 64, 1000)) < 64) + { + fprintf(stderr, "nexys2_jtag_gettdo: write failed: %d (%s)\n", ret, usb_strerror()); + return -1; + } + + bytesrem = nbits / 8 + ((nbits % 8) != 0); + while (bytesrem) + { + int nbytes = (bytesrem > 512) ? 512 : bytesrem; + if ((ret = usb_bulk_read(udev, 0x86, obits, nbytes, 1000)) < nbytes) + { + fprintf(stderr, "nexys2_jtag_gettdo: data read failed: %d (%s)\n", ret, usb_strerror()); + return -1; + } + obits += nbytes; + bytesrem -= nbytes; + } + + return 0; +} + +#endif + +#ifdef TEST_DRIVER + +void poke_idcode(nexys2_t nexys) +{ + unsigned char seq1[] = { 0xaa, 0x22}; + unsigned char seq2[] = { 0xaa, 0x02}; + unsigned int idcode = 0; + +// while(1) + { + while (nexys2_jtag_enable(nexys) < 0) + ; + if (nexys2_jtag_puttmstdi(nexys, 8, seq1, NULL) < 0) + return; + do + { + if (nexys2_jtag_gettdo(nexys, 0, 0, 32, &idcode) < 0) + return; + printf("IDCODE: %08x\n", idcode); + } while(idcode && (idcode != 0xFFFFFFFF)); + if (nexys2_jtag_puttmstdi(nexys, 8, seq2, NULL) < 0) + return; + if (nexys2_jtag_disable(nexys) < 0) + return; + } +} + +void main() +{ + nexys2_t nexys; + nexys = nexys2_init(); + if (!nexys) + return; + poke_idcode(nexys); +} + +#endif + diff --git a/libnexys.h b/libnexys.h new file mode 100644 index 0000000..581aa10 --- /dev/null +++ b/libnexys.h @@ -0,0 +1,31 @@ +#ifndef _LIBNEXYS_H +#define _LIBNEXYS_H + +#ifdef LIBNEXYS_INTERNAL +#ifdef WIN32_NATIVE +# include +# include "gendefs.h" +# include "dpcdefs.h" +# include "dpcutil.h" + typedef HANDLE nexys2_t; +#else +#ifdef PARPORT + typedef int nexys2_t; +#else +# include + typedef usb_dev_handle *nexys2_t; +#endif +#endif +#else + typedef void *nexys2_t; +#endif + +extern nexys2_t nexys2_init(void); +extern int nexys2_jtag_enable(nexys2_t dev); +extern int nexys2_jtag_disable(nexys2_t dev); +extern int nexys2_jtag_setbits(nexys2_t dev, int tms, int tdi, int tck); +extern int nexys2_jtag_puttdi(nexys2_t dev, int tms, int nbits, unsigned char *bits, unsigned char *obits); +extern int nexys2_jtag_puttmstdi(nexys2_t dev, int nbits, unsigned char *bits, unsigned char *obits); +extern int nexys2_jtag_gettdo(nexys2_t dev, int tdi, int tms, int nbits, unsigned char *obits); + +#endif diff --git a/libnexys.parport.c b/libnexys.parport.c new file mode 100644 index 0000000..be739a4 --- /dev/null +++ b/libnexys.parport.c @@ -0,0 +1,181 @@ +#ifdef WIN32 +#include "libnexys.win32.c" +#else +#define LIBNEXYS_INTERNAL +#ifndef PARPORT +# define PARPORT +#endif +#include "libnexys.h" +#include +#include +#include +#include +#include + +#define TDI 0 +#define TCK 1 +#define TMS 2 +#define TDO 4 + + +nexys2_t nexys2_init(void) { + int pfd = open("/dev/parport0", O_RDWR); + if (pfd < 0) + { + perror("open /dev/parport0"); + return -1; + } + + if ((ioctl(pfd, PPEXCL) < 0) || (ioctl(pfd, PPCLAIM) < 0)) + { + perror("lock /dev/parport0"); + return -1; + } + + return pfd; +} + +int nexys2_jtag_enable(int pfd) +{ + return 0; +} + +int nexys2_jtag_disable(int pfd) +{ + return 0; +} + +int nexys2_jtag_setbits(int pfd, int tms, int tdi, int tck) +{ + unsigned char data; + int i; + + data = ((!!tms) << TMS) | ((!!tdi) << TDI) | ((!!tck) << TCK); + + if (ioctl(pfd, PPWDATA, &data) < 0) + { + perror("nexys2_jtag_setbits: ioctl"); + return -1; + } + + return 0; +} + +int _gettdo(int pfd) +{ + unsigned char data; + + if (ioctl(pfd, PPRSTATUS, &data) < 0) + { + perror("_gettdi: PPRSTATUS"); + return -1; + } + + data ^= 0x80; + data >>= TDO; + data &= 1; + + return data; +} + +int nexys2_jtag_puttdi(int pfd, int tms, int nbits, unsigned char *bits, unsigned char *obits) +{ + int i; + + if (obits) + memset(obits, 0, (nbits / 8) + ((nbits % 8) != 0)); + + for (i = 0; i < nbits; i++) + { + int bit; + + bit = bits[i / 8] & (1 << (i % 8)); + nexys2_jtag_setbits(pfd, tms, bit, 1); + nexys2_jtag_setbits(pfd, tms, bit, 0); + if (obits) + obits[i/8] |= _gettdo(pfd) << (i % 8); + } + return 0; +} + +int nexys2_jtag_puttmstdi(int pfd, int nbits, unsigned char *bits, unsigned char *obits) +{ + int i; + + if (obits) + memset(obits, 0, (nbits / 8) + ((nbits % 8) != 0)); + + for (i = 0; i < nbits; i++) + { + int tdi, tms; + + tdi = bits[i / 4] & (1 << ((i % 4) * 2)); + tms = bits[i / 4] & (2 << ((i % 4) * 2)); + nexys2_jtag_setbits(pfd, tms, tdi, 0); + nexys2_jtag_setbits(pfd, tms, tdi, 1); + nexys2_jtag_setbits(pfd, tms, tdi, 0); + if (obits) + obits[i/8] |= _gettdo(pfd) << (i % 8); + } + return 0; +} + +int nexys2_jtag_gettdo(int pfd, int tdi, int tms, int nbits, unsigned char *obits) +{ + int i; + + if (obits) + memset(obits, 0, (nbits / 8) + ((nbits % 8) != 0)); + + for (i = 0; i < nbits; i++) + { + nexys2_jtag_setbits(pfd, tms, tdi, 0); + nexys2_jtag_setbits(pfd, tms, tdi, 1); + nexys2_jtag_setbits(pfd, tms, tdi, 0); + if (obits) + obits[i/8] |= _gettdo(pfd) << (i % 8); + } + return 0; +} + +#endif + +#ifdef TEST_DRIVER + +void poke_idcode(nexys2_t nexys) +{ + unsigned char seq1[] = { 0xaa, 0x22}; + unsigned char seq2[] = { 0xaa, 0x02}; + unsigned int idcode = 0; + unsigned int woop = 0x12345678; + +// while(1) + { + while (nexys2_jtag_enable(nexys) < 0) + ; + if (nexys2_jtag_puttmstdi(nexys, 8, seq1, NULL) < 0) + return; + do + { + if (nexys2_jtag_gettdo(nexys, 0, 0, 32, &idcode) < 0) + return; + printf("IDCODE: %08x\n", idcode); + } while(idcode && (idcode != 0xFFFFFFFF)); + if (nexys2_jtag_puttmstdi(nexys, 8, seq2, NULL) < 0) + return; + if (nexys2_jtag_disable(nexys) < 0) + return; + } +} + +void main() +{ + nexys2_t nexys; + nexys = nexys2_init(); + if (!nexys) + return; + poke_idcode(nexys); +} + +#endif + diff --git a/libnexys.win32.c b/libnexys.win32.c new file mode 100644 index 0000000..083e105 --- /dev/null +++ b/libnexys.win32.c @@ -0,0 +1,68 @@ +#define LIBNEXYS_INTERNAL +#include "libnexys.h" +#include + +nexys2_t nexys2_init(void) { + int device; + char devname[32]; + HANDLE hand; + ERC erc; + + if (!DpcInit(&erc)) + { + printf("DpcInit failed\n"); + return NULL; + } + + if ((device = DvmgGetDefaultDev(&erc)) == -1) + { + printf("We appear to lack a default device. Sadface :(\n"); + return NULL; + } + + DvmgGetDevName(device, devname, &erc); + printf("Interacting with device %d (%s)\n", device, devname); + + if (!DpcOpenJtag(&hand, devname, &erc, NULL)) + { + printf("JTAG open failed\n"); + return NULL; + } + return hand; +} + +int nexys2_jtag_enable(HANDLE hand) +{ + ERC erc; + return DpcEnableJtag(hand, &erc, NULL) ? 0 : -1; +} + +int nexys2_jtag_disable(HANDLE hand) +{ + ERC erc; + return DpcDisableJtag(hand, &erc, NULL) ? 0 : -1; +} + +int nexys2_jtag_setbits(HANDLE hand, int tms, int tdi, int tck) +{ + ERC erc; + return DpcSetTmsTdiTck(hand, tms, tdi, tck, &erc, NULL) ? 0 : -1; +} + +int nexys2_jtag_puttdi(HANDLE hand, int tms, int nbits, unsigned char *bits, unsigned char *obits) +{ + ERC erc; + return DpcPutTdiBits(hand, nbits, bits, tms, obits ? 1 : 0, obits, &erc, NULL) ? 0 : -1; +} + +int nexys2_jtag_puttmstdi(HANDLE hand, int nbits, unsigned char *bits, unsigned char *obits) +{ + ERC erc; + return DpcPutTmsTdiBits(hand, nbits, bits, obits ? 1 : 0, obits, &erc, NULL) ? 0 : -1; +} + +int nexys2_jtag_gettdo(HANDLE hand, int tdi, int tms, int nbits, unsigned char *obits) +{ + ERC erc; + return DpcGetTdoBits(hand, nbits, tdi, tms, obits, &erc, NULL) ? 0 : -1; +} diff --git a/s3load.c b/s3load.c new file mode 100644 index 0000000..5b047fb --- /dev/null +++ b/s3load.c @@ -0,0 +1,545 @@ +#include "libnexys.h" +#include +#include +#include +#include +#include + +enum TAPSTATE { + TAP_UNKNOWN, + TAP_RESET, + TAP_IDLE, + TAP_DRSEL, + TAP_DRCAP, + TAP_DRSHIFT, + TAP_DREXIT1, + TAP_DRPAUSE, + TAP_DREXIT2, + TAP_DRUPDATE, + TAP_IRSEL, + TAP_IRCAP, + TAP_IRSHIFT, + TAP_IREXIT1, + TAP_IRPAUSE, + TAP_IREXIT2, + TAP_IRUPDATE, +}; + +typedef struct tap { + nexys2_t nexys; + int tapstate; +} tap_t; + +int s3l_tap_reset(tap_t *tap) +{ + unsigned char reset[] = {0xAA, 0x02}; + tap->tapstate = TAP_RESET; + return nexys2_jtag_puttmstdi(tap->nexys, 5, reset, NULL); +} + +int s3l_tap_idle(tap_t *tap) +{ + switch (tap->tapstate) + { + case TAP_UNKNOWN: + printf("Resetting TAP from unknown state...\n"); + s3l_tap_reset(tap); + case TAP_RESET: + { + unsigned char idle[] = {0x00}; + printf("Placing TAP in idle state...\n"); + tap->tapstate = TAP_IDLE; + return nexys2_jtag_puttmstdi(tap->nexys, 1, idle, NULL); + } + case TAP_IDLE: + return 0; + default: + printf("cannot transition to idle from %d\n", tap->tapstate); + abort(); + } +} + +enum TOKENTYPE { + TOK_TRST = 0, + TOK_OFF = 1, + TOK_ENDIR = 2, + TOK_IDLE = 3, + TOK_ENDDR = 4, + TOK_STATE = 5, + TOK_RESET = 6, + TOK_FREQUENCY = 7, + TOK_1E6 = 8, + TOK_HZ = 9, + TOK_SEMICOLON = 10, + TOK_TIR = 11, + TOK_HIR = 12, + TOK_TDR = 13, + TOK_HDR = 14, + TOK_SIR = 15, + TOK_SDR = 16, + TOK_TDI = 17, + TOK_TDO = 18, + TOK_MASK = 19, + TOK_SMASK = 20, + TOK_NUMBER = 21, + TOK_BITSTRING = 22, + TOK_RUNTEST = 23, + TOK_TCK = 24, +}; + +typedef struct token { + int token; + union { + int i; + char *s; + } data; + struct token *next; +} token_t; + +int hex2nyb(char c) +{ + if (c >= '0' && c <= '9') + return c-'0'; + if (c >= 'a' && c <= 'f') + return c-'a'+10; + if (c >= 'A' && c <= 'F') + return c-'A'+10; + printf("Bad hex nybble %c\n", c); + abort(); +} + +token_t *tokenize(int fd) +{ + /* First off, suck in ALL of the file */ + char *f = NULL, *fst; + int sz = 0; + token_t *start = NULL, *cur = NULL; + + while (1) + { + int rsz; + f = realloc(f, sz + 16385); + if ((rsz = read(fd, &(f[sz]), 16384)) < 16384) + { + sz += rsz; + break; + } + sz += rsz; + } + f[sz] = 0; + fst = f; + + while (f && *f) + { + if (!strncmp(f, "//", 2)) + { + // Comment, eat the rest of the line + f = strchr(f, '\n'); + if (f && f[1] == '\r') + f += 2; + else if (f) + f++; + } else if (*f == '\n' || *f == '\r' || *f == '\t' || *f == ' ') + f++; +#define NEWTOKEN \ + if (!cur) \ + { \ + start = cur = malloc(sizeof(*cur)); \ + start->next = NULL; \ + } else { \ + cur->next = malloc(sizeof(*cur)); \ + cur = cur->next; \ + cur->next = NULL; \ + } +#define MATCHSTRING(str, tok) \ + if (!strncmp(f, str, strlen(str))) { \ + NEWTOKEN \ + cur->token = tok; \ + f += strlen(str); \ + } + else MATCHSTRING("TRST", TOK_TRST) + else MATCHSTRING("OFF", TOK_OFF) + else MATCHSTRING("ENDIR", TOK_ENDIR) + else MATCHSTRING("IDLE", TOK_IDLE) + else MATCHSTRING("ENDDR", TOK_ENDDR) + else MATCHSTRING("STATE", TOK_STATE) + else MATCHSTRING("RESET", TOK_RESET) + else MATCHSTRING("FREQUENCY", TOK_FREQUENCY) + else MATCHSTRING("1E6", TOK_1E6) + else MATCHSTRING("HZ", TOK_HZ) + else MATCHSTRING(";", TOK_SEMICOLON) + else MATCHSTRING("TIR", TOK_TIR) + else MATCHSTRING("HIR", TOK_HIR) + else MATCHSTRING("TDR", TOK_TDR) + else MATCHSTRING("HDR", TOK_HDR) + else MATCHSTRING("TDI", TOK_TDI) + else MATCHSTRING("SMASK", TOK_SMASK) + else MATCHSTRING("SIR", TOK_SIR) + else MATCHSTRING("MASK", TOK_MASK) + else MATCHSTRING("TDO", TOK_TDO) + else MATCHSTRING("SDR", TOK_SDR) + else MATCHSTRING("RUNTEST", TOK_RUNTEST) + else MATCHSTRING("TCK", TOK_TCK) + else if (isdigit(*f)) { + NEWTOKEN + cur->token = TOK_NUMBER; + cur->data.i = *f - '0'; + f++; + while (isdigit(*f)) + { + cur->data.i *= 10; + cur->data.i += *f - '0'; + f++; + } + } else if (*f == '(') { + int asz = 0; + int l = 0; + NEWTOKEN + cur->token = TOK_BITSTRING; + cur->data.s = NULL; + f++; + while (*f && *f != ')') + { + char c1, c2; + while (isspace(*f) && *f && *f != ')') + f++; + if (!*f || *f == ')') + break; + c1 = *(f++); + + while (isspace(*f) && *f && *f != ')') + f++; + if (!*f || *f == ')') + { + printf("Unpaired hex digit in bitstring\n"); + abort(); + } + c2 = *(f++); + + if (l == asz) + { + asz += 128; + cur->data.s = realloc(cur->data.s, asz); + } + cur->data.s[l++] = hex2nyb(c1) << 4 | hex2nyb(c2); + } + f++; + } else { + printf("Tokenizing error, unhandled: %s\n", f); + abort(); + } + } + + free(fst); + + return start; +} + +typedef struct blitval { + int len; + char *tdi, *tdo, *mask, *smask; +} blitval_t; + +/* Copies bits from an input in format: + * (msb first) 0 1 2 3 4 5 6 7 | 8 9 10 11 12 13 14 15 | ... + * To an output in format: + * 7 6 5 4 3 2 1 0 | 15 14 13 12 11 10 9 8 | ... + */ +void bitcopy(int len, unsigned char *inbits, int inpos, int indir, unsigned char *outbits, int outpos, int outdir) +{ + int i; + if (!inbits || !outbits) + return; + for (i = 0; i < len; i++) + { + int inbit; + inbit = inbits[(inpos + i * indir) / 8] & (1 << (7 - ((inpos + i * indir) % 8))); + outbits[(outpos + i * outdir) / 8] |= inbit ? (1 << ((outpos + i * outdir) % 8)) : 0; + } +} + +void printprog(int done, int total) +{ + int i; + int progresscounter = done * 32 / total; + static int spinnerstate; + char *spinner = "_.oOo."; + + printf("["); + for (i=0; i < progresscounter; i++) + printf("="); + if (progresscounter != 32) + printf(">"); + for (i=0; i < (31 - progresscounter); i++) + printf(" "); + printf("] %c %d/%d", spinner[(spinnerstate++) % 6], done, total); +} + +void pokethrough(tap_t *tap, blitval_t *tbv, blitval_t *sbv, blitval_t *hbv) +{ + int totlen = tbv->len + sbv->len + hbv->len; + int lenb = (totlen / 4) + ((totlen % 4) != 0) + 1; // Number of nexys2_* bytes + unsigned char *inb = calloc(lenb, 1); // Bitstream to be fed to nexys2_* + unsigned char *outb = calloc(lenb, 1); + unsigned char *expoutb = calloc(lenb, 1); + int bitp = 0; // Position in the "inb" bitstream + int txp = 0; + int needout = 0; + + if (!totlen) + return; + + printf("t:%d, s:%d, h:%d\n", tbv->len, sbv->len, hbv->len); + + bitp = 0; +#define ROUNDUP(x) (((x / 8) + ((x % 8) != 0)) * 8 - 1) + bitcopy(hbv->len, hbv->tdi, ROUNDUP(hbv->len), -1, inb, bitp*2, 2); bitp += hbv->len; + bitcopy(sbv->len, sbv->tdi, ROUNDUP(sbv->len), -1, inb, bitp*2, 2); bitp += sbv->len; + bitcopy(tbv->len, tbv->tdi, ROUNDUP(tbv->len), -1, inb, bitp*2, 2); bitp += tbv->len; + inb[(bitp*2-2)/8] |= 2 << ((bitp*2-2) % 8); + assert(bitp == totlen); + + if (sbv->tdo) + needout = 1; + bitp = 0; /* Have to throw away one bit :( */ + bitcopy(tbv->len, tbv->tdo, ROUNDUP(tbv->len), -1, expoutb, bitp, 1); bitp += tbv->len; + bitcopy(sbv->len, sbv->tdo, ROUNDUP(sbv->len), -1, expoutb, bitp, 1); bitp += sbv->len; + bitcopy(hbv->len, hbv->tdo, ROUNDUP(hbv->len), -1, expoutb, bitp, 1); bitp += hbv->len; + + + for (txp = 0; txp < totlen; txp += 0x8000) + { + int len = (((txp + 0x8000) > totlen) ? totlen : (txp + 0x8000)) - txp; + printf("Shifting: "); printprog(txp + len, totlen); printf("\r"); + fflush(stdout); + nexys2_jtag_puttmstdi(tap->nexys, len, inb + ((txp * 2) / 8), needout ? (outb + (txp / 8)) : NULL); + } + printf("\n"); + + printf("I: %02x, %02x, %02x, %02x\n", (int)inb[0], (int)inb[1], (int) inb[2], (int)inb[3]); + printf("O: %02x, %02x, %02x, %02x\n", (int)outb[0], (int)outb[1], (int)outb[2], (int)outb[3]); + printf("X: %02x, %02x, %02x, %02x\n", (int)expoutb[0], (int)expoutb[1], (int)expoutb[2], (int)expoutb[3]); + + free(inb); + free(outb); + free(expoutb); +} + +void runsvf(tap_t *tap, token_t *tlist) +{ + int trst = 0; + int endir = TOK_IDLE, enddr = TOK_IDLE; + blitval_t tir, tdr, hir, hdr; + + tir.len = 0; + tdr.len = 0; + hir.len = 0; + hdr.len = 0; + +#define NEXT tlist = tlist->next +#define REQUIRENEXT do { NEXT; if (!tlist) { printf("Unexpected end of stream\n"); abort(); } } while(0) +#define EXPECT(tok) \ + if (tlist->token != tok) \ + { \ + printf("Expected " #tok ", got %d\n", tok); \ + abort(); \ + } + + while (tlist) + { + switch (tlist->token) + { + case TOK_TRST: + REQUIRENEXT; EXPECT(TOK_OFF); + trst = 0; + REQUIRENEXT; EXPECT(TOK_SEMICOLON); + NEXT; + break; + case TOK_ENDIR: + REQUIRENEXT; EXPECT(TOK_IDLE); + endir = TOK_IDLE; + REQUIRENEXT; EXPECT(TOK_SEMICOLON); + NEXT; + break; + case TOK_ENDDR: + REQUIRENEXT; EXPECT(TOK_IDLE); + enddr = TOK_IDLE; + REQUIRENEXT; EXPECT(TOK_SEMICOLON); + NEXT; + break; + case TOK_STATE: + REQUIRENEXT; + printf("Changing state...\n"); + if (tlist->token == TOK_RESET) + s3l_tap_reset(tap); + else if (tlist->token == TOK_IDLE) + s3l_tap_idle(tap); + else { + printf("Unknown token after TOK_STATE\n"); + abort(); + } + REQUIRENEXT; EXPECT(TOK_SEMICOLON); + NEXT; + break; + case TOK_FREQUENCY: + REQUIRENEXT; EXPECT(TOK_1E6); + REQUIRENEXT; EXPECT(TOK_HZ); + REQUIRENEXT; EXPECT(TOK_SEMICOLON); + NEXT; + break; + case TOK_TIR: + case TOK_TDR: + case TOK_HIR: + case TOK_HDR: + case TOK_SIR: + case TOK_SDR: + { + int oldtok = tlist->token; + blitval_t *bv; + blitval_t s; + + if (oldtok == TOK_TIR) + bv = &tir; + else if (oldtok == TOK_HIR) + bv = &hir; + else if (oldtok == TOK_TDR) + bv = &tdr; + else if (oldtok == TOK_HDR) + bv = &hdr; + else + bv = &s; + + REQUIRENEXT; EXPECT(TOK_NUMBER); + bv->len = tlist->data.i; + bv->tdi = NULL; + bv->tdo = NULL; + bv->mask = NULL; + bv->smask = NULL; + REQUIRENEXT; + + while (tlist->token != TOK_SEMICOLON) + { + switch (tlist->token) + { + case TOK_TDI: + REQUIRENEXT; EXPECT(TOK_BITSTRING); + bv->tdi = tlist->data.s; + REQUIRENEXT; + break; + case TOK_TDO: + REQUIRENEXT; EXPECT(TOK_BITSTRING); + bv->tdo = tlist->data.s; + REQUIRENEXT; + break; + case TOK_MASK: + REQUIRENEXT; EXPECT(TOK_BITSTRING); + bv->mask = tlist->data.s; + REQUIRENEXT; + break; + case TOK_SMASK: + REQUIRENEXT; EXPECT(TOK_BITSTRING); + bv->smask = tlist->data.s; + REQUIRENEXT; + break; + default: + abort(); + } + } + EXPECT(TOK_SEMICOLON); + NEXT; + + if (oldtok == TOK_SIR || oldtok == TOK_SDR) + { + char *capturedr = "\x02"; + char *captureir = "\x0A"; + char *returnidle = "\x02"; + s3l_tap_idle(tap); + /* Enter capture DR is TMS 1 0 */ + /* Enter capture IR is TMS 1 1 0 */ + /* Return to RTI is TMS 1 0 */ + + if (oldtok == TOK_SIR) + { + printf("Shifting IR (%d bits)...\n", tir.len + s.len + hdr.len); + nexys2_jtag_puttmstdi(tap->nexys, 4, captureir, NULL); + pokethrough(tap, &tir, &s, &hir); + } else { + printf("Shifting DR (%d bits)...\n", tdr.len + s.len + hdr.len); + nexys2_jtag_puttmstdi(tap->nexys, 3, capturedr, NULL); + pokethrough(tap, &tdr, &s, &hdr); + } + nexys2_jtag_puttmstdi(tap->nexys, 2, returnidle, NULL); + } + break; + } + case TOK_RUNTEST: + { + int n; + char *loss; + + REQUIRENEXT; EXPECT(TOK_NUMBER); + n = tlist->data.i; + REQUIRENEXT; EXPECT(TOK_TCK); + REQUIRENEXT; EXPECT(TOK_SEMICOLON); + NEXT; + + loss = malloc(64); + memset(loss, 0, 64); + s3l_tap_idle(tap); + + printf("Going RTI for %d clocks...\n", n); + + while (n) + { + int b = (n < 512) ? n : 512; + nexys2_jtag_puttdi(tap->nexys, 0, n, loss, NULL); + n -= b; + } + free(loss); + + break; + } + default: + printf("Unknown top level token %d\n", tlist->token); + abort(); + } + } +} + +int main(int argc, char **argv) +{ + tap_t tap; + token_t *tlist; + int fd; + + if (argc < 2) + { + printf("usage: s3load \n"); + return 1; + } + if ((fd = open(argv[1], O_RDONLY)) < 0) + { + perror("open"); + return 1; + } + tlist = tokenize(fd); + close(fd); + + + tap.tapstate = TAP_UNKNOWN; + tap.nexys = nexys2_init(); + if (!tap.nexys) + { + fprintf(stderr, "Board init failed :(\n"); + return 1; + } + + if (nexys2_jtag_enable(tap.nexys) < 0) + return 1; + + runsvf(&tap, tlist); + + nexys2_jtag_disable(tap.nexys); + + return 0; +}