commit 486f882823b5c64053903d9834439ef40c0601b2
parent 940b6d1fa9e0f9483d2f05447a699e98d5903282
Author: Brian Swetland <swetland@frotz.net>
Date: Sat, 4 Oct 2014 22:52:09 -0700
fpga: tool to download bitfile to xilinx 7-series fpga
- Currently only works if the FPGA is unprogrammed, out of reset.
- Does not have the entire 7-series idcodes in its table, so will
not recognize all parts.
- Does not do any bitfile metadata vs device validation yet, so will
happily send the wrong bitfile to a device (but that should always
fail).
Diffstat:
M | Makefile | | | 9 | +++++++-- |
A | fpga.c | | | 80 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | jtag-core.c | | | 38 | +++++++++++++++++++++++++++++--------- |
M | jtag.h | | | 3 | +++ |
4 files changed, 119 insertions(+), 11 deletions(-)
diff --git a/Makefile b/Makefile
@@ -4,7 +4,7 @@ CFLAGS := -Wall -O0 -g
LIBS := -lusb-1.0 -lrt
-all: jtag dap-test zynq
+all: zynq fpga
JTAG_OBJS := jtag-mpsse-driver.o jtag-core.o jtag.o
$(JTAG_OBJS): jtag.h jtag-driver.h
@@ -21,5 +21,10 @@ $(ZYNQ_OBJS): jtag.h jtag-driver.h dap.h dap-registers.h v7debug.h v7debug-regis
zynq: $(ZYNQ_OBJS)
$(CC) -o zynq $(ZYNQ_OBJS) $(LIBS)
+FPGA_OBJS := fpga.o jtag-core.o jtag-mpsse-driver.o
+$(FPGA_OBJS): jtag.h jtag-driver.h
+fpga: $(FPGA_OBJS)
+ $(CC) -o fpga $(FPGA_OBJS) $(LIBS)
+
clean:
- rm -f *.o jtag dap-test zynq
+ rm -f *.o jtag dap-test zynq fpga
diff --git a/fpga.c b/fpga.c
@@ -0,0 +1,80 @@
+// Copyright 2014 Brian Swetland <swetland@frotz.net>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "jtag.h"
+
+static void *loadfile(const char *fn, u32 *sz) {
+ int fd;
+ off_t end;
+ void *data = NULL;
+ if ((fd = open(fn, O_RDONLY)) < 0) return NULL;
+ if ((end = lseek(fd, 0, SEEK_END)) < 0) goto oops;
+ if (lseek(fd, 0, SEEK_SET) < 0) goto oops;
+ if ((data = malloc(end + 4)) == NULL) goto oops;
+ if (read(fd, data, end) != end) goto oops;
+ close(fd);
+ *sz = end;
+ return data;
+
+oops:
+ free(data);
+ close(fd);
+ return NULL;
+}
+
+static u8 bitrev(u8 x) {
+ x = (x << 4) | (x >> 4);
+ x = ((x << 2) & 0xcc) | ((x >> 2) & 0x33);
+ x = ((x << 1) & 0xaa) | ((x >> 1) & 0x55);
+ return x;
+}
+
+int main(int argc, char **argv) {
+ JTAG *jtag;
+ u8 *data;
+ u32 sz, n;
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: fpga <bitfile>\n");
+ return -1;
+ }
+
+ if ((data = loadfile(argv[1], &sz)) == NULL) return -1;
+
+ for (n = 0; n < sz; n++) {
+ data[n] = bitrev(data[n]);
+ }
+
+ if (jtag_mpsse_open(&jtag)) return -1;
+ if (jtag_enumerate(jtag) < 0) return -1;
+ if (jtag_select_by_family(jtag, "Xilinx 7")) return -1;
+
+ fprintf(stderr, "begin.\n");
+ n = 5;
+ jtag_ir_wr(jtag, 6, &n);
+ jtag_dr_wr(jtag, sz * 8, data);
+
+ if (jtag_commit(jtag)) return -1;
+
+ fprintf(stderr, "done.\n");
+ return 0;
+}
+
diff --git a/jtag-core.c b/jtag-core.c
@@ -23,13 +23,13 @@
#define ZYNQMASK 0x0FFFFFFF
static JTAG_INFO LIBRARY[] = {
- { 0x4ba00477, 0xFFFFFFFF, 4, "Cortex A9" },
- { ZYNQID(0x02), ZYNQMASK, 6, "xc7x010" },
- { ZYNQID(0x1b), ZYNQMASK, 6, "xc7x015" },
- { ZYNQID(0x07), ZYNQMASK, 6, "xc7x020" },
- { ZYNQID(0x0c), ZYNQMASK, 6, "xc7x030" },
- { ZYNQID(0x11), ZYNQMASK, 6, "xc7x045" },
- { 0x13631093, 0xFFFFFFFF, 6, "xc7a100t" },
+ { 0x4ba00477, 0xFFFFFFFF, 4, "Cortex A9", "ARM A9" },
+ { ZYNQID(0x02), ZYNQMASK, 6, "xc7x010", "Xilinx 7" },
+ { ZYNQID(0x1b), ZYNQMASK, 6, "xc7x015", "Xilinx 7" },
+ { ZYNQID(0x07), ZYNQMASK, 6, "xc7x020", "Xilinx 7" },
+ { ZYNQID(0x0c), ZYNQMASK, 6, "xc7x030", "Xilinx 7" },
+ { ZYNQID(0x11), ZYNQMASK, 6, "xc7x045", "Xilinx 7" },
+ { 0x13631093, 0xFFFFFFFF, 6, "xc7a100t", "Xilinx 7" },
};
JTAG_INFO *jtag_lookup_device(unsigned idcode) {
@@ -327,8 +327,8 @@ int jtag_enumerate(JTAG *jtag) {
return -1;
}
memcpy(jtag->devinfo + n, info, sizeof(JTAG_INFO));
- fprintf(stderr, "device %02d idcode %08x '%s'\n",
- n, info->idcode, info->name);
+ fprintf(stderr, "device %02d idcode: %08x name: %-16s family: %s\n",
+ n, info->idcode, info->name, info->family);
}
fprintf(stderr, "too many devices\n");
return -1;
@@ -376,3 +376,23 @@ int jtag_select_device(JTAG *jtag, unsigned idcode) {
return -1;
}
+int jtag_select_by_family(JTAG *jtag, const char *family) {
+ int i, n;
+ int count = 0;
+ for (i = 0; i < jtag->devcount; i++) {
+ if (!strcmp(jtag->devinfo[i].family, family)) {
+ count++;
+ n = i;
+ }
+ }
+ if (count == 0) {
+ fprintf(stderr, "jtag: no devices of family '%s' found.\n", family);
+ return -1;
+ }
+ if (count > 1) {
+ fprintf(stderr, "jtag: multiple devices of family '%s' found.\n", family);
+ return -1;
+ }
+ return jtag_select_device_nth(jtag, n);
+}
+
diff --git a/jtag.h b/jtag.h
@@ -83,6 +83,7 @@ typedef struct {
unsigned idmask;
unsigned irsize;
const char *name;
+ const char *family;
} JTAG_INFO;
// reset the bus and probe it
@@ -99,4 +100,6 @@ int jtag_select_device(JTAG *jtag, unsigned idcode);
// select by position in scan chain
int jtag_select_device_nth(JTAG *jtag, int n);
+int jtag_select_by_family(JTAG *jtag, const char *family);
+
#endif