commit bb09bb68bc74034323ef7552cc2ca31855c20aa0
parent d2b56ad246d06155a345a18e5180010340acf983
Author: Brian Swetland <swetland@frotz.net>
Date: Sun, 28 Sep 2014 00:34:27 -0700
dap: improved error handling, reintroduce some caching
- request sticky overruns
- dap_commit() queues DPCSW check for sticky errors
or overruns, jtag_commit()s then checks for badness
- everything uses dap_commit() now
- reintroduce cached_ir, but cache only for the duration
of a txn (avoids redundant ir writes within a txn,
but is more conservative across multiple txns)
- introduce a timing hack to dap_mem_read/write() so they
work correctly on zynq (TODO: make this adaptive)
- remove some dead code
Diffstat:
M | dap.c | | | 127 | +++++++++++++++++++++++++++++++++++++++++++++---------------------------------- |
1 file changed, 72 insertions(+), 55 deletions(-)
diff --git a/dap.c b/dap.c
@@ -19,6 +19,9 @@
#include "jtag.h"
#include "dap.h"
+#define CSW_ERRORS (DPCSW_STICKYERR | DPCSW_STICKYCMP | DPCSW_STICKYORUN)
+#define CSW_ENABLES (DPCSW_CSYSPWRUPREQ | DPCSW_CDBGPWRUPREQ | DPCSW_ORUNDETECT)
+
#include <time.h>
static u64 NOW(void) {
struct timespec ts;
@@ -28,9 +31,20 @@ static u64 NOW(void) {
typedef struct {
JTAG *jtag;
+ u32 cached_ir;
} DAP;
static void q_dap_ir_wr(DAP *dap, u32 ir) {
+ if (dap->cached_ir != ir) {
+ dap->cached_ir = ir;
+ jtag_ir_wr(dap->jtag, 4, &ir);
+ }
+}
+
+// force ir write even if redundant
+// used for a timing hack
+static void _q_dap_ir_wr(DAP *dap, u32 ir) {
+ dap->cached_ir = ir;
jtag_ir_wr(dap->jtag, 4, &ir);
}
@@ -50,6 +64,37 @@ static void q_dap_abort(DAP *dap) {
u = 8;
jtag_ir_wr(dap->jtag, 4, &x);
jtag_dr_wr(dap->jtag, 35, &u);
+ dap->cached_ir = 0xFFFFFFFF;
+}
+
+// queue a DPCSW status query, commit jtag txn
+static int dap_commit(DAP *dap) {
+ u64 a, b;
+ q_dap_ir_wr(dap, DAP_IR_DPACC);
+ q_dap_dr_io(dap, 35, XPACC_RD(DPACC_CSW), &a);
+ q_dap_dr_io(dap, 35, XPACC_RD(DPACC_RDBUFF), &b);
+ dap->cached_ir = 0xFFFFFFFF;
+ if (jtag_commit(dap->jtag)) {
+ return -1;
+ }
+ if (XPACC_STATUS(a) != XPACC_OK) {
+ fprintf(stderr, "dap: invalid txn status\n");
+ return -1;
+ }
+ if (XPACC_STATUS(b) != XPACC_OK) {
+ fprintf(stderr, "dap: cannot read status\n");
+ return -1;
+ }
+ b >>= 3;
+ if (b & DPCSW_STICKYORUN) {
+ fprintf(stderr, "dap: overrun\n");
+ return -1;
+ }
+ if (b & DPCSW_STICKYERR) {
+ fprintf(stderr, "dap: error\n");
+ return -1;
+ }
+ return 0;
}
int dap_dp_rd(DAP *dap, u32 addr, u32 *val) {
@@ -57,10 +102,7 @@ int dap_dp_rd(DAP *dap, u32 addr, u32 *val) {
q_dap_ir_wr(dap, DAP_IR_DPACC);
q_dap_dr_io(dap, 35, XPACC_RD(addr), NULL);
q_dap_dr_io(dap, 35, XPACC_RD(DPACC_RDBUFF), &u);
- if (jtag_commit(dap->jtag)) {
- return -1;
- }
- if (XPACC_STATUS(u) != XPACC_OK) {
+ if (dap_commit(dap)) {
return -1;
}
*val = u >> 3;
@@ -75,77 +117,51 @@ static void q_dap_dp_wr(DAP *dap, u32 addr, u32 val) {
int dap_dp_wr(DAP *dap, u32 addr, u32 val) {
q_dap_dp_wr(dap, addr, val);
- return jtag_commit(dap->jtag);
+ return dap_commit(dap);
}
-/* TODO: cache state, check errors */
int dap_ap_rd(DAP *dap, u32 apnum, u32 addr, u32 *val) {
u64 u;
+ q_dap_ir_wr(dap, DAP_IR_DPACC);
q_dap_dp_wr(dap, DPACC_SELECT, DPSEL_APSEL(apnum) | DPSEL_APBANKSEL(addr));
q_dap_ir_wr(dap, DAP_IR_APACC);
q_dap_dr_io(dap, 35, XPACC_RD(addr), NULL);
q_dap_ir_wr(dap, DAP_IR_DPACC);
q_dap_dr_io(dap, 35, XPACC_RD(DPACC_RDBUFF), &u);
- if (jtag_commit(dap->jtag)) {
- return -1;
- }
- if (XPACC_STATUS(u) != XPACC_OK) {
+ // TODO: redundant ir wr
+ if (dap_commit(dap)) {
return -1;
}
*val = (u >> 3);
return 0;
}
-int q_dap_ap_wr(DAP *dap, u32 apnum, u32 addr, u32 val) {
+void q_dap_ap_wr(DAP *dap, u32 apnum, u32 addr, u32 val) {
+ q_dap_ir_wr(dap, DAP_IR_DPACC);
q_dap_dp_wr(dap, DPACC_SELECT, DPSEL_APSEL(apnum) | DPSEL_APBANKSEL(addr));
q_dap_ir_wr(dap, DAP_IR_APACC);
q_dap_dr_io(dap, 35, XPACC_WR(addr, val), NULL);
- //q_dap_ir_wr(dap, DAP_IR_DPACC);
- //q_dap_dr_io(dap, 35, XPACC_RD(DPACC_RDBUFF), &u);
- return 0;
}
int dap_mem_wr32(DAP *dap, u32 n, u32 addr, u32 val) {
if (addr & 3)
return -1;
- if (q_dap_ap_wr(dap, n, APACC_TAR, addr))
- return -1;
- if (q_dap_ap_wr(dap, n, APACC_DRW, val))
- return -1;
- return jtag_commit(dap->jtag);
+ q_dap_ap_wr(dap, n, APACC_CSW,
+ APCSW_DBGSWEN | APCSW_INCR_NONE | APCSW_SIZE32);
+ q_dap_ap_wr(dap, n, APACC_TAR, addr);
+ q_dap_ap_wr(dap, n, APACC_DRW, val);
+ return dap_commit(dap);
}
int dap_mem_rd32(DAP *dap, u32 n, u32 addr, u32 *val) {
if (addr & 3)
return -1;
- if (q_dap_ap_wr(dap, n, APACC_TAR, addr))
- return -1;
+ q_dap_ap_wr(dap, n, APACC_TAR, addr);
if (dap_ap_rd(dap, n, APACC_DRW, val))
return -1;
return 0;
}
-int dap_mem_wr32x(DAP *dap, u32 n, u32 addr, u32 *val, u32 count) {
-#if 0
- q_dap_ap_wr
- dap_ap_wr(dap, 0, APACC_CSW, APCSW_DBGSWEN | APCSW_INCR_SINGLE | APCSW_SIZE32);
- dap_ap_wr(dap, 0xf0000000, APACC_TAR, n);
- dap_ap_wr_x(dap, 0, APACC_DRW, val);
- u = XPACC_WR(APACC_DRW);
- u |= (((u64) val) << 3);
- for (i = 0; i < 1024; i++) {
- for (n = 0; n < 1024; n++) {
- jtag_dr_wr(dap->jtag, 35, &u);
- }
- jtag_commit(dap->jtag);
- }
- dap_ap_rd(dap, 0, APACC_CSW, &x);
- dap_dp_rd(dap, DPACC_CSW, &y);
- fprintf(stderr, "APCSW=%08x DPCSW=%08x\n", x, y);
-#endif
- return -1;
-}
-
int dap_mem_read(DAP *dap, u32 apnum, u32 addr, void *data, u32 len) {
u64 scratch[1024];
u32 *x = data;
@@ -163,16 +179,19 @@ int dap_mem_read(DAP *dap, u32 apnum, u32 addr, void *data, u32 len) {
if (xfer > len) {
xfer = len;
}
- q_dap_ap_wr(dap, apnum, APACC_CSW, APCSW_DBGSWEN | APCSW_INCR_SINGLE | APCSW_SIZE32);
+ q_dap_ap_wr(dap, apnum, APACC_CSW,
+ APCSW_DBGSWEN | APCSW_INCR_SINGLE | APCSW_SIZE32);
q_dap_dr_io(dap, 35, XPACC_WR(APACC_TAR, addr), NULL);
// read txn will be returned on the next txn
q_dap_dr_io(dap, 35, XPACC_RD(APACC_DRW), NULL);
+ _q_dap_ir_wr(dap, DAP_IR_APACC); // HACK, timing
for (n = 0; n < (xfer-4); n += 4) {
q_dap_dr_io(dap, 35, XPACC_RD(APACC_DRW), &scratch[n/4]);
+ _q_dap_ir_wr(dap, DAP_IR_APACC); // HACK, timing
}
// dummy read of TAR to pick up last read value
q_dap_dr_io(dap, 35, XPACC_RD(APACC_TAR), &scratch[n/4]);
- if (jtag_commit(dap->jtag)) {
+ if (dap_commit(dap)) {
return -1;
}
for (n = 0; n < xfer; n += 4) {
@@ -209,11 +228,12 @@ int dap_mem_write(DAP *dap, u32 apnum, u32 addr, void *data, u32 len) {
q_dap_ap_wr(dap, apnum, APACC_CSW, APCSW_DBGSWEN | APCSW_INCR_SINGLE | APCSW_SIZE32);
q_dap_dr_io(dap, 35, XPACC_WR(APACC_TAR, addr), NULL);
for (n = 0; n < xfer; n += 4) {
+ _q_dap_ir_wr(dap, DAP_IR_APACC); // HACK, timing
q_dap_dr_io(dap, 35, XPACC_WR(APACC_DRW, *x++), NULL);
}
- if (jtag_commit(dap->jtag)) {
+ if (dap_commit(dap)) {
return -1;
- }
+ }
len -= xfer;
addr += xfer;
}
@@ -224,6 +244,7 @@ DAP *dap_init(JTAG *jtag) {
DAP *dap = malloc(sizeof(DAP));
memset(dap, 0, sizeof(DAP));
dap->jtag = jtag;
+ dap->cached_ir = 0xFFFFFFFF;
return dap;
}
@@ -235,14 +256,12 @@ int dap_attach(DAP *dap) {
q_dap_abort(dap);
// attempt to power up and clear errors
- for (n = 0; n < 100; n++) {
- if (dap_dp_wr(dap, DPACC_CSW,
- DPCSW_CSYSPWRUPREQ | DPCSW_CDBGPWRUPREQ |
- DPCSW_STICKYERR | DPCSW_STICKYCMP | DPCSW_STICKYORUN))
+ for (n = 0; n < 10; n++) {
+ if (dap_dp_wr(dap, DPACC_CSW, CSW_ERRORS | CSW_ENABLES))
continue;
if (dap_dp_rd(dap, DPACC_CSW, &x))
continue;
- if (x & (DPCSW_STICKYERR | DPCSW_STICKYCMP | DPCSW_STICKYORUN))
+ if (x & CSW_ERRORS)
continue;
if (!(x & DPCSW_CSYSPWRUPACK))
continue;
@@ -351,20 +370,18 @@ int main(int argc, char **argv) {
#if 1
for (n = 0; n < 8; n++) {
x = 0xefefefef;
- //dap_mem_rd32(dap, 1, 0x80090FE0 + n*4, &x);
dap_mem_rd32(dap, 0, 0x00000000 + n*4, &x);
printf("%08x: %08x\n", n*4, x);
}
#endif
#if 0
- //memset(DATA, 0xEE, sizeof(DATA));
for (n = 0; n < 1024*1024; n++) DATA[n] = n;
- //for (n = 0; n < 10; n++)
+ for (n = 0; n < 10; n++)
dap_mem_write(dap, 0, 0, DATA, 192*1024);
#endif
-#if 0
+#if 0
if (dap_mem_read(dap, 0, 0, DATA, 4096) == 0) {
for (n = 0; n < 16; n++) printf("%08x ",DATA[n]);
printf("\n");