commit a7d29a11b2b18d515f0303071251338960cae5ce
parent 7b0db42e5617040a6873d7af5736bfd6c9fcd570
Author: Brian Swetland <swetland@frotz.net>
Date:   Sun, 20 Apr 2014 23:58:36 -0700
big pile of work in progress
- added bit level shift transaction tracing (#ifdef TRACE_JTAG)
- fixed bogus bitcount for TMS moves at end of a shift
- fixed bogus bitread paths
- started sketching out AP and DP access
Diffstat:
| M | jtag-mpsse.c |  |  | 54 | ++++++++++++++++++++++++++++++++++++++++++++++++------ | 
| M | jtag.c |  |  | 117 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- | 
| M | zynq.h |  |  | 57 | ++++++++++++++++++++++++++++++++++++++++++++++++++++----- | 
3 files changed, 215 insertions(+), 13 deletions(-)
diff --git a/jtag-mpsse.c b/jtag-mpsse.c
@@ -219,6 +219,22 @@ static int jtag_move(JTAG *jtag, int count, unsigned bits){
 	if (count > 32)
 		return -1;
 
+#if TRACE_JTAG
+	{
+		u64 tmp = bits;
+		int n;
+		fprintf(stderr,"TDI <- ");
+		for (n = 0; n < count; n++) {
+			fprintf(stderr, "X");
+		}
+		fprintf(stderr,"\nTMS <- ");
+		for (n = 0; n < count; n++) {
+			fprintf(stderr,"%c", (tmp & 1) ? '1' : '0');
+			tmp >>= 1;
+		}
+		fprintf(stderr,"\n");
+	}
+#endif
 	while (count > 0) {
 		xfer = (count > 6) ? 6 : count;
 		*p++ = 0x4b;
@@ -251,6 +267,29 @@ int _jtag_shift(JTAG *jtag, int count, u64 bits, u64 *out,
 	if (count <= 0)
 		return -1;
 
+#if TRACE_JTAG
+	{
+		u64 tmp = bits;
+		int n;
+		fprintf(stderr,"TDI <- ");
+		for (n = 0; n < count; n++) {
+			fprintf(stderr,"%c", (tmp & 1) ? '1' : '0');
+			tmp >>= 1;
+		}
+		for (n = 0; n < movebits; n++)
+			fprintf(stderr,"%c", (tmp & 1) ? '1' : '0');
+		fprintf(stderr,"\nTMS <- ");
+		for (n = 0; n < count; n++)
+			fprintf(stderr,"0");
+		tmp = movebits;
+		for (n = 0; n < movebits; n++) {
+			fprintf(stderr,"%c", (tmp & 1) ? '1' : '0');
+			tmp >>= 1;
+		}
+		fprintf(stderr,"\n");
+	}
+#endif
+
 	bytes = count / 8;
 	readbytes = bytes;
 	iobytes = bytes;
@@ -281,7 +320,7 @@ int _jtag_shift(JTAG *jtag, int count, u64 bits, u64 *out,
 		if (movebits > 6)
 			return -1; /* TODO */
 		*p++ = out ? 0x6b : 0x4b;
-		*p++ = movebits;
+		*p++ = movecount - 1;
 		*p++ = ((bits & 1) << 7) | (movebits & 0x3F);
 		iobytes++;
 	}
@@ -294,7 +333,7 @@ int _jtag_shift(JTAG *jtag, int count, u64 bits, u64 *out,
 		return -1;
 
 	if (out) {
-		u64 n = 0;
+		u64 n = 0, bit;
 		unsigned shift = 0;
 		if (ftdi_read(jtag, buf, iobytes, 1000))
 			return -1;
@@ -305,12 +344,15 @@ int _jtag_shift(JTAG *jtag, int count, u64 bits, u64 *out,
 		}
 		while (readbits > 0) {
 			xfer = (readbits > 6) ? 6 : readbits;
-			n |= ((*p++ & bitxfermask[xfer]) << shift);
-			shift <<= xfer;
+			bit = ((*p++) >> (8 - xfer)) & bitxfermask[xfer];
+			n |= (bit << shift);
+			shift += xfer;
 			readbits -= xfer;
 		}
 		if (movecount) {
-			n |= ((*p++ & bitxfermask[movecount]) << shift);
+			/* we only ever care about the first bit */
+			bit = ((*p++) >> (8 - movecount)) & 1;
+			n |= (bit << shift);
 		}
 		*out = n;
 	}
@@ -364,7 +406,7 @@ static int jtag_shift_ir(JTAG *jtag, int count, u64 bits,
 #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
+#define MOVE_SHIFTxR_TO_IDLE	3,0b011
 
 
 void jtag_close(JTAG *jtag) {
diff --git a/jtag.c b/jtag.c
@@ -18,10 +18,84 @@
 #include "jtag.h"
 #include "zynq.h"
 
+void pause(const char *msg) {
+	char crap[1024];
+	fprintf(stderr,">>> %s <<<\n", msg);
+	fgets(crap, sizeof(crap), stdin);
+}
+
+int jtag_dp_rd(JTAG *jtag, u32 addr, u32 *val) {
+	int retry = 30;
+	u64 u;
+	jtag_ir_wr(jtag, DAP_IR_DPACC);
+	jtag_dr_io(jtag, 35, XPACC_RD(addr), NULL);
+	while (retry-- > 0) {
+		jtag_dr_io(jtag, 35, XPACC_RD(DPACC_RDBUFF), &u);
+		switch (XPACC_STATUS(u)) {
+		case XPACC_OK:
+			*val = u >> 3;
+			return 0;
+		case XPACC_WAIT:
+			fprintf(stderr,"!");
+			continue;
+		default:
+			return -1;
+		}
+	}
+	return -1;
+}
+
+int jtag_dp_wr(JTAG *jtag, u32 addr, u32 val) {
+	int retry = 30;
+	u64 u;
+	u = XPACC_WR(addr);
+	u |= (((u64) val) << 3);
+	jtag_ir_wr(jtag, DAP_IR_DPACC);
+	jtag_dr_io(jtag, 35, u, NULL);
+	while (retry-- > 0) {
+		jtag_dr_io(jtag, 35, XPACC_RD(DPACC_RDBUFF), &u);
+		switch (XPACC_STATUS(u)) {
+		case XPACC_OK:
+			return 0;
+		case XPACC_WAIT:
+			fprintf(stderr,"!");
+			continue;
+		default:
+			return -1;
+		}
+	}
+	return -1;
+}
+
+/* TODO: cache state, check errors */
+int jtag_ap_rd(JTAG *jtag, u32 addr, u32 *val) {
+	u64 u;
+	jtag_dp_wr(jtag, DPACC_SELECT, DPSEL_APSEL(0) | DPSEL_APBANKSEL(addr));
+	jtag_ir_wr(jtag, DAP_IR_APACC);
+	jtag_dr_io(jtag, 35, XPACC_RD(addr), NULL);
+	jtag_ir_wr(jtag, DAP_IR_DPACC);
+	jtag_dr_io(jtag, 35, XPACC_RD(DPACC_RDBUFF), &u);
+	*val = (u >> 3);
+	return 0;
+}
+
+int jtag_ap_wr(JTAG *jtag, u32 addr, u32 val) {
+	u64 u;
+	jtag_dp_wr(jtag, DPACC_SELECT, DPSEL_APSEL(0) | DPSEL_APBANKSEL(addr));
+	jtag_ir_wr(jtag, DAP_IR_APACC);
+	u = XPACC_WR(addr);
+	u |= (((u64) val) << 3);
+	jtag_dr_io(jtag, 35, u, NULL);
+	jtag_ir_wr(jtag, DAP_IR_DPACC);
+	jtag_dr_io(jtag, 35, XPACC_RD(DPACC_RDBUFF), &u);
+	return 0;
+}
+
 int main(int argc, char **argv) {
 	JTAG *jtag;
 	unsigned n;
 	u64 u;
+	u32 x;
 
 	if (!(jtag = jtag_open()))
 		return -1;
@@ -31,11 +105,50 @@ int main(int argc, char **argv) {
 	if (jtag_select(jtag, 0x4ba00477))
 		return -1;
 
-	if (jtag_ir_wr(jtag, DAP_IDCODE))
+	if (jtag_ir_wr(jtag, DAP_IR_IDCODE))
 		return -1;
 	if (jtag_dr_io(jtag, 32, 0, &u))
 		return -1;
-
 	fprintf(stderr,"idcode? %08lx\n", u);
+
+	jtag_dp_rd(jtag, DPACC_CSW, &x);
+	fprintf(stderr,"CSW %08x\n", x);
+
+	jtag_dp_wr(jtag, DPACC_CSW, DPCSW_CSYSPWRUPREQ | DPCSW_CDBGPWRUPREQ);
+	do {
+		jtag_dp_rd(jtag, DPACC_CSW, &x);
+		fprintf(stderr,"CSW %08x\n", x);
+	} while ((x & (DPCSW_CSYSPWRUPACK | DPCSW_CDBGPWRUPACK)) != (DPCSW_CSYSPWRUPACK | DPCSW_CDBGPWRUPACK));
+
+	jtag_ap_rd(jtag, APACC_BASE, &x);
+	fprintf(stderr,"base %08x\n", x);
+
+	jtag_ap_rd(jtag, APACC_IDR, &x);
+	fprintf(stderr,"idr %08x\n", x);
+
+#if STRESSTEST
+	for (n = 0; n < 0xFFFFFFFF; n++) { 
+		u32 z = (n >> 16) | (n << 16);
+		x = 0xeeeeeeee;
+		jtag_ap_wr(jtag, APACC_TAR, z);
+		jtag_ap_rd(jtag, APACC_TAR, &x);
+		if (z != x) {
+			fprintf(stderr,"%08x != %08x\n", z, x);
+		}
+		//if ((n & 0xFFF) == 0)
+			fprintf(stderr,"%08x\r", z);
+	}
+
+	jtag_ap_wr(jtag, APACC_TAR, 0x12345678);
+#endif
+
+	jtag_ap_rd(jtag, APACC_TAR, &x);
+	fprintf(stderr,"tar %08x\n", x);
+
+#if 0
+	fprintf(stderr,"done\n");
+	jtag_dp_wr(jtag, DPACC_CSW, 0);
+#endif
+
 	return 0;
 }
diff --git a/zynq.h b/zynq.h
@@ -2,11 +2,58 @@
 /* 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
+#define DAP_IR_ABORT		0x08
+#define DAP_IR_DPACC		0x0A
+#define DAP_IR_APACC		0x0B
+#define DAP_IR_IDCODE		0x0E
+#define DAP_IR_BYPASS		0x0F
+
+#define XPACC_STATUS(n)		((n) & 0x3)
+#define XPACC_WAIT		0x1
+#define XPACC_OK		0x2
+#define XPACC_RD(n)		(0x1 | (((n) >> 1) & 6))
+#define XPACC_WR(n)		(0x0 | (((n) >> 1) & 6))
+
+#define DPACC_RESERVED		0x0
+#define DPACC_CSW		0x4
+#define DPACC_SELECT		0x8
+#define DPACC_RDBUFF		0xC
+
+#define DPCSW_CSYSPWRUPACK	(1 << 31)
+#define DPCSW_CSYSPWRUPREQ	(1 << 30)
+#define DPCSW_CDBGPWRUPACK	(1 << 29)
+#define DPCSW_CDBGPWRUPREQ	(1 << 28)
+#define DPCSW_CDBGRSTACK	(1 << 27)
+#define DPCSW_CDBGRSTREQ	(1 << 26)
+#define DPCSW_TRNCNT(n)		(((n) & 0x3FF) << 12)
+#define DPCSW_MASKLANE(n)	(((n) & 0xF) << 8) // pushed verify or compare
+#define DPCSW_WDATAERR		(1 << 7) // reserved on jtag
+#define DPCSW_READOK		(1 << 6) // reserved on jtag
+#define DPCSW_STICKYERR		(1 << 5)
+#define DPCSW_STICKYCMP		(1 << 4)
+#define DPCSW_TRNMODE_NORMAL	(0 << 2)
+#define DPCSW_TRNMODE_PUSH_VRFY	(1 << 2)
+#define DPCSW_TRNMODE_PUSH_CMP	(2 << 2)
+#define DPCSW_STICKYORUN	(1 << 1)
+#define DPCSW_ORUNDETECT	(1 << 0)
+
+#define DPSEL_APSEL(n)		(((n) & 0xFF) << 24)
+#define DPSEL_APBANKSEL(a)	((a) & 0xF0)
+#define DPSEL_CTRLSEL		(1 << 0) // reserved on jtag
+
+/* Reading RDBUFF returns 0, has no side effects */
+/* Can be used to obtain final read result and ack values at end of seq */
+
+#define APACC_CSW		0x00
+#define APACC_TAR		0x04
+#define APACC_DRW		0x0C
+#define APACC_BD0		0x10
+#define APACC_BD1		0x14
+#define APACC_BD2		0x18
+#define APACC_BD3		0x1C
+#define APACC_CFG		0xF4
+#define APACC_BASE		0xF8
+#define APACC_IDR		0xFC
 
 
 /* Xilinx TAP Controller (6bit IR) */