commit 7b0db42e5617040a6873d7af5736bfd6c9fcd570
Author: Brian Swetland <swetland@frotz.net>
Date: Sun, 20 Apr 2014 19:31:49 -0700
initial commit
Doesn't do a whole lot yet, but basic IR/DR interactions are working
along with a bus enumeration whatsit.
Diffstat:
A | .gitignore | | | 2 | ++ |
A | Makefile | | | 15 | +++++++++++++++ |
A | jtag-mpsse.c | | | 535 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | jtag.c | | | 41 | +++++++++++++++++++++++++++++++++++++++++ |
A | jtag.h | | | 37 | +++++++++++++++++++++++++++++++++++++ |
A | zynq.h | | | 32 | ++++++++++++++++++++++++++++++++ |
6 files changed, 662 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,2 @@
+.*.swp
+*.o
diff --git a/Makefile b/Makefile
@@ -0,0 +1,15 @@
+
+CFLAGS := -g -Wall -O2
+LIBS := -lusb-1.0
+
+all: jtag
+
+jtag.c: jtag.h
+jtag-mpsse.c: jtag.h
+
+JTAG2232_OBJS := jtag.o jtag-mpsse.o
+jtag: $(JTAG2232_OBJS)
+ $(CC) -o jtag $(JTAG2232_OBJS) $(LIBS)
+
+clean::
+ rm -f jtag *.o
diff --git a/jtag-mpsse.c b/jtag-mpsse.c
@@ -0,0 +1,535 @@
+/* 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 <unistd.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "jtag.h"
+
+#include <libusb-1.0/libusb.h>
+
+struct device_info {
+ u32 idcode;
+ u32 idmask;
+ u32 irsize;
+ const char *name;
+};
+
+#define ZYNQID(code) ((0x1B<<21)|(0x9<<17)|((code)<<12)|(0x49<<1)|1)
+#define ZYNQMASK 0x0FFFFFFF
+
+struct device_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" },
+};
+
+struct device_info *identify_device(u32 idcode) {
+ unsigned n;
+ for (n = 0; n < sizeof(LIBRARY) / sizeof(LIBRARY[0]); n++) {
+ if ((idcode & LIBRARY[n].idmask) == LIBRARY[n].idcode) {
+ return LIBRARY + n;
+ }
+ }
+ return NULL;
+}
+
+#define TRACE_USB 0
+#define TRACE_JTAG 0
+
+#define DEVICE_MAX 16
+
+struct jtag_handle {
+ struct libusb_device_handle *udev;
+ u8 ep_in;
+ u8 ep_out;
+
+ u8 read_buffer[512];
+ u8 *read_ptr;
+ u32 read_count;
+ u32 read_size;
+
+ u32 dr_pre;
+ u32 dr_post;
+ u32 ir_pre;
+ u32 ir_post;
+
+ u32 dev_count;
+ u32 dev_idcode[DEVICE_MAX];
+ u32 dev_irsize[DEVICE_MAX];
+ struct device_info *dev_info[DEVICE_MAX];
+
+ u32 active_irsize;
+ u32 active_idcode;
+};
+
+static int usb_open(JTAG *jtag, unsigned vid, unsigned pid) {
+ struct libusb_device_handle *udev;
+
+ if (libusb_init(NULL) < 0)
+ return -1;
+
+ if (!(udev = libusb_open_device_with_vid_pid(NULL, vid, pid))) {
+ fprintf(stderr,"cannot find device\n");
+ return -1;
+ }
+
+ libusb_detach_kernel_driver(udev, 0);
+
+ if (libusb_claim_interface(udev, 0) < 0) {
+ fprintf(stderr,"cannot claim interface\n");
+ return -1;
+ }
+ jtag->udev = udev;
+ jtag->ep_in = 0x81;
+ jtag->ep_out = 0x02;
+ return 0;
+}
+
+
+#if TRACE_USB
+static void dump(char *prefix, void *data, int len) {
+ unsigned char *x = data;
+ fprintf(stderr,"%s: (%d)", prefix, len);
+ while (len > 0) {
+ fprintf(stderr," %02x", *x++);
+ len--;
+ }
+ fprintf(stderr,"\n");
+}
+#endif
+
+static int usb_bulk(struct libusb_device_handle *udev,
+ unsigned char ep, void *data, int len, unsigned timeout) {
+ int r, xfer;
+#if TRACE_USB
+ if (!(ep & 0x80))
+ dump("xmit", data, len);
+#endif
+ r = libusb_bulk_transfer(udev, ep, data, len, &xfer, timeout);
+ if (r < 0) {
+ fprintf(stderr,"bulk: error: %d\n", r);
+ return r;
+ }
+#if TRACE_USB
+ if (ep & 0x80)
+ dump("recv", data, xfer);
+#endif
+ return xfer;
+}
+
+#define FTDI_REQTYPE_OUT (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT)
+#define FTDI_CTL_RESET 0x00
+#define FTDI_CTL_SET_BITMODE 0x0B
+#define FTDI_CTL_SET_EVENT_CH 0x06
+#define FTDI_CTL_SET_ERROR_CH 0x07
+
+#define FTDI_IFC_A 1
+#define FTDI_IFC_B 2
+
+int ftdi_reset(struct libusb_device_handle *udev) {
+ if (libusb_control_transfer(udev,
+ FTDI_REQTYPE_OUT, FTDI_CTL_RESET, 0, FTDI_IFC_A, NULL, 0, 10000) < 0) {
+ fprintf(stderr,"ftdi: reset failed\n");
+ return -1;
+ }
+ return 0;
+}
+
+int ftdi_mpsse_enable(struct libusb_device_handle *udev) {
+ if (libusb_control_transfer(udev,
+ FTDI_REQTYPE_OUT, FTDI_CTL_SET_BITMODE, 0x0000, FTDI_IFC_A, NULL, 0, 10000) < 0) {
+ fprintf(stderr,"ftdi: set bitmode failed\n");
+ return -1;
+ }
+ if (libusb_control_transfer(udev,
+ FTDI_REQTYPE_OUT, FTDI_CTL_SET_BITMODE, 0x020b, FTDI_IFC_A, NULL, 0, 10000) < 0) {
+ fprintf(stderr,"ftdi: set bitmode failed\n");
+ return -1;
+ }
+ if (libusb_control_transfer(udev,
+ FTDI_REQTYPE_OUT, FTDI_CTL_SET_EVENT_CH, 0, FTDI_IFC_A, NULL, 0, 10000) < 0) {
+ fprintf(stderr,"ftdi: disable event character failed\n");
+ return -1;
+ }
+ return 0;
+ if (libusb_control_transfer(udev,
+ FTDI_REQTYPE_OUT, FTDI_CTL_SET_ERROR_CH, 0, FTDI_IFC_A, NULL, 0, 10000) < 0) {
+ fprintf(stderr,"ftdi: disable error character failed\n");
+ return -1;
+ }
+ return 0;
+}
+
+/* TODO: handle smaller packet size for lowspeed version of the part */
+/* TODO: multi-packet reads */
+/* TODO: asynch/background reads */
+static int ftdi_read(JTAG *jtag, unsigned char *buffer, int count, int timeout) {
+ int xfer;
+ while (count > 0) {
+ if (jtag->read_count >= count) {
+ memcpy(buffer, jtag->read_ptr, count);
+ jtag->read_count -= count;
+ jtag->read_ptr += count;
+ return 0;
+ }
+ if (jtag->read_count > 0) {
+ memcpy(buffer, jtag->read_ptr, jtag->read_count);
+ count -= jtag->read_count;
+ jtag->read_count = 0;
+ }
+ xfer = usb_bulk(jtag->udev, jtag->ep_in,
+ jtag->read_buffer, jtag->read_size, 1000);
+ if (xfer < 0)
+ return -1;
+ if (xfer < 2)
+ return -1;
+ /* discard header */
+ jtag->read_ptr = jtag->read_buffer + 2;
+ jtag->read_count = xfer - 2;
+ }
+ return 0;
+}
+
+static unsigned char bitxfermask[8] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F };
+
+static int jtag_move(JTAG *jtag, int count, unsigned bits){
+ unsigned char buf[1024];
+ unsigned char *p = buf;
+ unsigned xfer;
+
+ if (count > 32)
+ return -1;
+
+ while (count > 0) {
+ xfer = (count > 6) ? 6 : count;
+ *p++ = 0x4b;
+ *p++ = xfer - 1;
+ *p++ = bits & bitxfermask[xfer];
+ bits >>= xfer;
+ count -= xfer;
+ }
+ if (usb_bulk(jtag->udev, jtag->ep_out, buf, p - buf, 1000) != (p - buf))
+ return -1;
+ return 0;
+}
+
+int _jtag_shift(JTAG *jtag, int count, u64 bits, u64 *out,
+ int movecount, unsigned movebits) {
+ unsigned char buf[1024];
+ unsigned char *p = buf;
+ unsigned xfer, bytes, readbytes, iobytes, readbits;
+
+ if (count > 64)
+ return -1;
+
+ if (movecount) {
+ /* if we're doing a joint shift-move, the last bit is
+ * shifted during the first bit of the move
+ */
+ count--;
+ }
+
+ if (count <= 0)
+ return -1;
+
+ bytes = count / 8;
+ readbytes = bytes;
+ iobytes = bytes;
+
+ if (bytes) {
+ count -= (bytes * 8);
+ *p++ = out ? 0x39 : 0x19;
+ *p++ = bytes - 1;
+ *p++ = 0;
+ while (bytes > 0) {
+ *p++ = bits & 0xff;
+ bits >>= 8;
+ bytes--;
+ }
+ }
+ readbits = count;
+ while (count > 0) {
+ xfer = (count > 6) ? 6 : count;
+ *p++ = out ? 0x3b : 0x1b;
+ *p++ = xfer - 1;
+ *p++ = bits & bitxfermask[xfer];
+ bits >>= xfer;
+ count -= xfer;
+ iobytes++;
+ }
+
+ if (movecount) {
+ if (movebits > 6)
+ return -1; /* TODO */
+ *p++ = out ? 0x6b : 0x4b;
+ *p++ = movebits;
+ *p++ = ((bits & 1) << 7) | (movebits & 0x3F);
+ iobytes++;
+ }
+
+ /* if we're doing readback demand an ioflush */
+ if (out)
+ *p++ = 0x87;
+
+ if (usb_bulk(jtag->udev, jtag->ep_out, buf, p - buf, 1000) != (p - buf))
+ return -1;
+
+ if (out) {
+ u64 n = 0;
+ unsigned shift = 0;
+ if (ftdi_read(jtag, buf, iobytes, 1000))
+ return -1;
+ p = buf;
+ while (readbytes-- > 0) {
+ n |= (((u64) *p++) << shift);
+ shift += 8;
+ }
+ while (readbits > 0) {
+ xfer = (readbits > 6) ? 6 : readbits;
+ n |= ((*p++ & bitxfermask[xfer]) << shift);
+ shift <<= xfer;
+ readbits -= xfer;
+ }
+ if (movecount) {
+ n |= ((*p++ & bitxfermask[movecount]) << shift);
+ }
+ *out = n;
+ }
+ return 0;
+}
+
+#define ONES(n) (0xFFFFFFFFFFFFFFFFULL >> ((64 - (n))))
+
+static int jtag_shift_dr(JTAG *jtag, int count, u64 bits,
+ u64 *out, int movecount, unsigned movebits) {
+ int r;
+ bits <<= jtag->dr_pre;
+ r = _jtag_shift(jtag, count + jtag->dr_pre + jtag->dr_post,
+ bits, out, movecount, movebits);
+ if (out) {
+ *out = (*out >> jtag->dr_pre) & ONES(count);
+ }
+ return r;
+}
+
+static int jtag_shift_ir(JTAG *jtag, int count, u64 bits,
+ int movecount, unsigned movebits) {
+ bits |= (ONES(jtag->ir_post) << count);
+ bits <<= jtag->ir_pre;
+ bits |= ONES(jtag->ir_pre);
+ return _jtag_shift(jtag, count + jtag->ir_pre + jtag->ir_post,
+ bits, NULL , movecount, movebits);
+}
+
+/* JTAG notes
+ *
+ * TMS is sampled on +TCK
+ * Capture-XR state loads shift register on +TCK as state is exited
+ * Shift-XR state TDO goes active (containing shiftr[0]) on the first -TCK
+ * after entry, shifts occur on each +TCK, *including* the +TCK
+ * that will exist Shift-XR when TMS=1 again
+ * Update-XR update occurs on the -TCK after entry to state
+ *
+ * Any -> Reset: 11111
+ * Any -> Reset -> RTI: 111110
+ * RTI -> ShiftDR: 100
+ * ShiftDR shifting: 0 x N
+ * ShiftDR -> UpdateDR -> RTI: 110
+ * ShiftDR -> UpdateDR -> ShiftDR: 11100
+ * RTI -> ShiftIR: 1100
+ * ShiftIR shifting: 0 x N
+ * ShiftIR -> UpdateIR -> RTI: 110
+ */
+
+#define MOVE_NONE 0,0
+#define MOVE_ANY_TO_RESET_IDLE 8,0b01111111
+#define MOVE_IDLE_TO_SHIFTDR 3,0b001
+#define MOVE_IDLE_TO_SHIFTIR 4,0b0011
+#define MOVE_SHIFTxR_TO_IDLE 2,0b011
+
+
+void jtag_close(JTAG *jtag) {
+}
+
+static unsigned char mpsse_init[] = {
+ 0x85, // loopback off
+ 0x8a, // disable clock/5
+ 0x86, 0x01, 0x00, // set divisor
+ 0x80, 0xe8, 0xeb, // set low state and dir
+ 0x82, 0x20, 0x30, // set high state and dir
+};
+
+JTAG *jtag_open(void) {
+ int r;
+ JTAG *jtag = malloc(sizeof(JTAG));
+ if (!jtag)
+ return NULL;
+ memset(jtag, 0, sizeof(JTAG));
+ jtag->read_size = sizeof(jtag->read_buffer);
+
+ r = usb_open(jtag, 0x0403, 0x6010);
+ if (r < 0)
+ goto fail;
+ if (ftdi_reset(jtag->udev))
+ goto fail;
+ if (ftdi_mpsse_enable(jtag->udev))
+ goto fail;
+ if (usb_bulk(jtag->udev, jtag->ep_out,
+ mpsse_init, sizeof(mpsse_init), 1000) != sizeof(mpsse_init))
+ goto fail;
+ return jtag;
+
+fail:
+ jtag_close(jtag);
+ free(jtag);
+ return NULL;
+}
+
+#define ENUM_MAGIC (0x00005038aaaaaaFFULL)
+
+/* TODO: attempt to probe for IR size if devices are not in library.
+ * On RESET the IR must have 1 in bit0 and 0 in bit1.
+ * The other bits are undefined.
+ */
+int jtag_enumerate(JTAG *jtag) {
+ u64 u;
+ unsigned n;
+
+ jtag_move(jtag, MOVE_ANY_TO_RESET_IDLE);
+ jtag_move(jtag, MOVE_IDLE_TO_SHIFTIR);
+ /* BYPASS is always all 1s -- shift a pile of BYPASS opcodes into the chain */
+ _jtag_shift(jtag, 64, 0xFFFFFFFFFFFFFFFFULL, NULL, MOVE_NONE);
+ _jtag_shift(jtag, 64, 0xFFFFFFFFFFFFFFFFULL, NULL, MOVE_NONE);
+ _jtag_shift(jtag, 64, 0xFFFFFFFFFFFFFFFFULL, NULL, MOVE_NONE);
+ _jtag_shift(jtag, 64, 0xFFFFFFFFFFFFFFFFULL, NULL, MOVE_NONE);
+ _jtag_shift(jtag, 64, 0xFFFFFFFFFFFFFFFFULL, NULL, MOVE_NONE);
+ _jtag_shift(jtag, 64, 0xFFFFFFFFFFFFFFFFULL, NULL, MOVE_NONE);
+ _jtag_shift(jtag, 64, 0xFFFFFFFFFFFFFFFFULL, NULL, MOVE_NONE);
+ _jtag_shift(jtag, 64, 0xFFFFFFFFFFFFFFFFULL, NULL, MOVE_SHIFTxR_TO_IDLE);
+ jtag_move(jtag, MOVE_IDLE_TO_SHIFTDR);
+ /* BYPASS registers should be one 0 bit each.
+ * Shift a pattern in and try to find it after all the 0s.
+ * If we can't find it, there must be >16 devices on the chain
+ * and/or they have enormous instruction registers.
+ */
+ _jtag_shift(jtag, 64, ENUM_MAGIC, &u, MOVE_SHIFTxR_TO_IDLE);
+ for (n = 0; n < DEVICE_MAX; n++) {
+ if (!(u & 1)) {
+ u >>= 1;
+ continue;
+ }
+ if (u == ENUM_MAGIC) {
+ jtag->dev_count = n;
+ fprintf(stderr, "jtag: found %d devices\n", jtag->dev_count);
+ goto okay;
+ }
+ }
+ fprintf(stderr,"jtag: more than %d devices?!\n", DEVICE_MAX);
+ return -1;
+
+okay:
+ jtag_move(jtag, MOVE_ANY_TO_RESET_IDLE);
+ /* should put IDCODE in IR of everyone */
+ jtag_move(jtag, MOVE_IDLE_TO_SHIFTDR);
+ for (n = 0; n < jtag->dev_count; n++) {
+ _jtag_shift(jtag, 32, 0xFFFFFFFF, &u, MOVE_NONE);
+ if ((u & 1) == 0) {
+ fprintf(stderr, "jtag: device %2d has no idcode\n", n);
+ return -1;
+ }
+ jtag->dev_idcode[n] = (u32) u;
+ jtag->dev_info[n] = identify_device((u32) u);
+ if (jtag->dev_info[n] == NULL) {
+ fprintf(stderr, "jtag: device %2d idcode %08x unknown IR size\n",
+ n, (u32) u);
+ return -1;
+ }
+ jtag->dev_irsize[n] = jtag->dev_info[n]->irsize;
+ fprintf(stderr, "jtag: device %2d idcode %08x irsize %2d '%s'\n",
+ n, jtag->dev_idcode[n], jtag->dev_irsize[n],
+ jtag->dev_info[n]->name);
+ }
+ return jtag->dev_count;
+}
+
+int jtag_select(JTAG *jtag, u32 idcode) {
+ u32 irsize = 0;
+ u32 ir_pre = 0;
+ u32 ir_post = 0;
+ u32 dr_pre = 0;
+ u32 dr_post = 0;
+ int found = 0;
+ unsigned n;
+
+ for (n = 0; n < jtag->dev_count; n++) {
+ u32 sz;
+ if (idcode == jtag->dev_idcode[n]) {
+ irsize = jtag->dev_irsize[n];
+ found = 1;
+ continue;
+ }
+ sz = jtag->dev_irsize[n];
+ if (sz > 32)
+ return -1;
+ if (found) {
+ ir_post += sz;
+ dr_post += 1;
+ } else {
+ ir_pre += sz;
+ dr_pre += 1;
+ }
+ }
+ if (!found) {
+ fprintf(stderr,"device id %08x not found in chain\n", idcode);
+ return -1;
+ }
+
+ jtag->active_idcode = idcode;
+ jtag->active_irsize = irsize;
+ fprintf(stderr,"jtag: select idcode %08x\n", idcode);
+ fprintf(stderr,"jtag: TDI -> irpost(%d) -> iract(%d) -> irpre(%d) -> TDO\n",
+ ir_post, irsize, ir_pre);
+
+ jtag->dr_pre = dr_pre;
+ jtag->dr_post = dr_post;
+ jtag->ir_pre = ir_pre;
+ jtag->ir_post = ir_post;
+
+ return jtag_move(jtag, MOVE_ANY_TO_RESET_IDLE);
+}
+
+int jtag_ir_wr(JTAG *jtag, u32 ir) {
+ if (jtag_move(jtag, MOVE_IDLE_TO_SHIFTIR))
+ return -1;
+ if (jtag_shift_ir(jtag, jtag->active_irsize, ir, MOVE_SHIFTxR_TO_IDLE))
+ return -1;
+ return 0;
+}
+
+int jtag_dr_io(JTAG *jtag, u32 bitcount, u64 wdata, u64 *rdata) {
+ if (jtag_move(jtag, MOVE_IDLE_TO_SHIFTDR))
+ return -1;
+ if (jtag_shift_dr(jtag, bitcount, wdata, rdata, MOVE_SHIFTxR_TO_IDLE))
+ return -1;
+ return 0;
+}
+
diff --git a/jtag.c b/jtag.c
@@ -0,0 +1,41 @@
+/* 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 "jtag.h"
+#include "zynq.h"
+
+int main(int argc, char **argv) {
+ JTAG *jtag;
+ unsigned n;
+ u64 u;
+
+ if (!(jtag = jtag_open()))
+ return -1;
+ if ((n = jtag_enumerate(jtag)) <= 0)
+ return -1;
+
+ if (jtag_select(jtag, 0x4ba00477))
+ return -1;
+
+ if (jtag_ir_wr(jtag, DAP_IDCODE))
+ return -1;
+ if (jtag_dr_io(jtag, 32, 0, &u))
+ return -1;
+
+ fprintf(stderr,"idcode? %08lx\n", u);
+ return 0;
+}
diff --git a/jtag.h b/jtag.h
@@ -0,0 +1,37 @@
+/* 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.
+ */
+
+#ifndef _JTAG_H_
+#define _JTAG_H_
+
+#include <stdint.h>
+
+typedef uint64_t u64;
+typedef uint32_t u32;
+typedef uint8_t u8;
+
+typedef struct jtag_handle JTAG;
+
+JTAG *jtag_open(void);
+void jtag_close(JTAG *jtag);
+
+int jtag_enumerate(JTAG *jtag);
+u32 jtag_get_nth_idcode(JTAG *jtag, u32 n);
+int jtag_select(JTAG *jtag, u32 idcode);
+
+int jtag_ir_wr(JTAG *jtag, u32 ir);
+int jtag_dr_io(JTAG *jtag, u32 bitcount, u64 wdata, u64 *rdata);
+
+#endif
diff --git a/zynq.h b/zynq.h
@@ -0,0 +1,32 @@
+
+/* ARM DAP Controller (4bit IR) */
+#define DAP_IR_SIZE 4
+
+#define DAP_ABORT 0x08
+#define DAP_DPACC 0x0A
+#define DAP_APACC 0x0B
+#define DAP_IDCODE 0x0E
+#define DAP_BYPASS 0x0F
+
+
+/* Xilinx TAP Controller (6bit IR) */
+#define XIL_IR_SIZE 6
+
+#define XIL_EXTEST 0x00
+#define XIL_SAMPLE 0x01
+#define XIL_USER1 0x02
+#define XIL_USER2 0x03
+#define XIL_USER3 0x22
+#define XIL_USER4 0x23
+#define XIL_CFG_OUT 0x04
+#define XIL_CFG_IN 0x05
+#define XIL_USERCODE 0x08
+#define XIL_IDCODE 0x09
+#define XIL_ISC_ENABLE 0x10
+#define XIL_ISC_PROGRAM 0x11
+#define XIL_ISC_PROGRAM_SECURITY 0x12
+#define XIL_ISC_NOOP 0x14
+#define XIL_ISC_READ 0x1B
+#define XIL_ISC_DISABLE 0x17
+#define XIL_BYPASS 0x3F
+