commit b09e4e8c9582bae629676d64a56b7c58e925bf01
parent a68ce9fc2fcc10bd6aeb54afcfd9c814e5a40492
Author: Brian Swetland <swetland@frotz.net>
Date: Mon, 29 Sep 2014 18:04:21 -0700
v7debug: basic halt and restart working
Diffstat:
M | v7debug.c | | | 230 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------- |
1 file changed, 202 insertions(+), 28 deletions(-)
diff --git a/v7debug.c b/v7debug.c
@@ -16,16 +16,55 @@
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
#include "jtag.h"
#include "dap.h"
#include "v7debug.h"
+// CPSR bits
+#define ARM_N (1 << 31)
+#define ARM_Z (1 << 30)
+#define ARM_C (1 << 29)
+#define ARM_V (1 << 28)
+#define ARM_Q (1 << 27)
+#define ARM_J (1 << 24)
+#define ARM_E (1 << 9)
+#define ARM_A (1 << 8)
+#define ARM_I (1 << 7)
+#define ARM_F (1 << 6)
+#define ARM_T (1 << 5)
+#define ARM_M_MASK 0x1F
+#define ARM_M_USR 0x10
+#define ARM_M_FIQ 0x11
+#define ARM_M_IRQ 0x12
+#define ARM_M_SVC 0x13
+#define ARM_M_MON 0x16
+#define ARM_M_ABT 0x17
+#define ARM_M_UND 0x1B
+#define ARM_M_SYS 0x1F
+
typedef struct V7DEBUG V7DEBUG;
+#define STATE_IDLE 0
+#define STATE_HALTED 1
+#define STATE_RUNNING 2
+
struct V7DEBUG {
DAP *dap;
+ unsigned state;
u32 apnum;
u32 base;
+
+ // saved state while halted
+ u32 save_r0;
+ u32 save_r1;
+ u32 save_pc;
+ u32 save_cpsr;
+
+ // cached cpsr
+ u32 cpsr;
};
static inline int dwr(V7DEBUG *debug, u32 off, u32 val) {
@@ -48,10 +87,7 @@ V7DEBUG *debug_init(DAP *dap, u32 apnum, u32 base) {
return debug;
}
-
-#define P(n) do { u32 x; if (!drd(debug, n, &x)) printf("%s: %08x\n", #n, x); } while(0)
-
-int dccrd(V7DEBUG *debug, u32 *val) {
+static int dccrd(V7DEBUG *debug, u32 *val) {
u32 x;
int n;
for (n = 0; n < 10; n++) {
@@ -64,7 +100,20 @@ int dccrd(V7DEBUG *debug, u32 *val) {
return -1;
}
-int dexec(V7DEBUG *debug, u32 instr) {
+static int dccwr(V7DEBUG *debug, u32 val) {
+ u32 x;
+ int n;
+ for (n = 0; n < 10; n++) {
+ if (drd(debug, DBGDSCR, &x)) return -1;
+ if (!(x & DSCR_RXFULL)) {
+ return dwr(debug, DBGDTRRX, val);
+ }
+ }
+ fprintf(stderr, "v7debug: dcc write timed out\n");
+ return -1;
+}
+
+static int dexec(V7DEBUG *debug, u32 instr) {
u32 x;
int n;
dwr(debug, DBGITR, instr);
@@ -76,26 +125,67 @@ int dexec(V7DEBUG *debug, u32 instr) {
return -1;
}
-#define ARM_DSB 0xE57FF040
+#define ARM_DSB 0xEE070F9A
#define ARM_MOV_DCC_Rx(x) (0xEE000E15 | ((x) << 12)) // Rx -> DCC
#define ARM_MOV_Rx_DCC(x) (0xEE100E15 | ((x) << 12)) // DCC -> Rx
#define ARM_MOV_R0_PC 0xE1A0000F
-#define ARM_MOV_CPSR_R0 0xE12FF000 // R0 -> CPSR
+#define ARM_MOV_PC_R0 0xE1A0F000
+//#define ARM_MOV_CPSR_R0 0xE12FF000 // R0 -> CPSR
+#define ARM_MOV_CPSR_R0 0xE129F000 // R0 -> CPSR
#define ARM_MOV_R0_CPSR 0xE10F0000 // CPSR -> R0
+int debug_reg_rd(V7DEBUG *debug, unsigned n, u32 *val) {
+ if (debug->state != STATE_HALTED) {
+ return -1;
+ }
+ switch (n) {
+ case 0: { *val = debug->save_r0; return 0; }
+ case 1: { *val = debug->save_r1; return 0; }
+ case 15: { *val = debug->save_pc; return 0; }
+ case 16: { *val = debug->save_cpsr; return 0; }
+ }
+ if (n > 15) {
+ return -1;
+ }
+ if (dexec(debug, ARM_MOV_DCC_Rx(n))) return -1;
+ return dccrd(debug, val);
+}
+
+int debug_reg_wr(V7DEBUG *debug, unsigned n, u32 val) {
+ if (debug->state != STATE_HALTED) {
+ return -1;
+ }
+ switch (n) {
+ case 0: { debug->save_r0 = val; return 0; }
+ case 1: { debug->save_r1 = val; return 0; }
+ case 15: { debug->save_pc = val; return 0; }
+ case 16: { debug->save_cpsr = val; return 0; }
+ }
+ if (n > 15) {
+ return -1;
+ }
+ if (dccwr(debug, val)) return -1;
+ return dexec(debug, ARM_MOV_Rx_DCC(n));
+}
+
int debug_attach(V7DEBUG *debug) {
u32 x;
- u32 r[16];
- u32 cpsr;
int n;
- if (dap_attach(debug->dap)) return -1;
- P(DBGDIDR);
- P(DBGDEVID);
- P(DBGDEVTYPE);
- P(DBGLSR);
- P(DBGDSCCR);
- P(DBGDSCR);
+ if (debug->state == STATE_HALTED) {
+ return -1;
+ }
+
+ if (dap_attach(debug->dap)) {
+ return -1;
+ }
+
+ drd(debug, DBGDSCR, &x);
+ if (x & DSCR_HALTED) {
+ fprintf(stderr, "debug: warning, processor already halted\n");
+ }
+
+ dwr(debug, DBGDSCR, DSCR_H_DBG_EN | DSCR_RESTARTED | DSCR_HALTED);
dwr(debug, DBGDRCR, DRCR_HALT_REQ);
for (n = 0; n < 100; n++) {
@@ -103,25 +193,79 @@ int debug_attach(V7DEBUG *debug) {
if (x & DSCR_HALTED) goto halted;
}
fprintf(stderr, "v7debug: halt timed out\n");
+ return -1;
halted:
- dwr(debug, DBGDSCR, DSCR_ITR_EN);
+ dwr(debug, DBGDSCR, DSCR_H_DBG_EN | DSCR_ITR_EN | DSCR_RESTARTED | DSCR_HALTED);
- dexec(debug, ARM_DSB); // dsb
- for (n = 0; n < 15; n++) {
- dexec(debug, ARM_MOV_DCC_Rx(n));
- dccrd(debug, r + n);
- }
+ // save essential state
+ // we need r0/r1 to shuffle data in/out of memory and dcc
+ // pc will be corrupted on cpsr writes
+ // cpsr needs to be written to access other modes
+ dexec(debug, ARM_DSB);
+ dexec(debug, ARM_MOV_DCC_Rx(0));
+ dccrd(debug, &debug->save_r0);
+ dexec(debug, ARM_MOV_DCC_Rx(1));
+ dccrd(debug, &debug->save_r1);
dexec(debug, ARM_MOV_R0_PC);
dexec(debug, ARM_MOV_DCC_Rx(0));
- dccrd(debug, r + 15);
+ dccrd(debug, &debug->save_pc);
dexec(debug, ARM_MOV_R0_CPSR);
dexec(debug, ARM_MOV_DCC_Rx(0));
- dccrd(debug, &cpsr);
- for (n = 0; n < 16; n++) {
- fprintf(stderr,"R%d %08x ", n, r[n]);
+ dccrd(debug, &debug->save_cpsr);
+ if (debug->save_cpsr & ARM_T) {
+ debug->save_pc -= 4;
+ } else {
+ debug->save_pc -= 8;
}
- fprintf(stderr, "CPSR %08x\n", cpsr);
+ debug->cpsr = debug->save_cpsr;
+ debug->state = STATE_HALTED;
+ return 0;
+}
+
+int debug_detach(V7DEBUG *debug) {
+ if (debug->state != STATE_HALTED) {
+ return -1;
+ }
+
+ dccwr(debug, debug->save_cpsr);
+ dexec(debug, ARM_MOV_Rx_DCC(0));
+ dexec(debug, ARM_MOV_CPSR_R0);
+
+ dccwr(debug, debug->save_pc);
+ dexec(debug, ARM_MOV_Rx_DCC(0));
+ dexec(debug, ARM_MOV_PC_R0);
+
+ dccwr(debug, debug->save_r0);
+ dexec(debug, ARM_MOV_Rx_DCC(0));
+
+ dccwr(debug, debug->save_r1);
+ dexec(debug, ARM_MOV_Rx_DCC(1));
+
+ dwr(debug, DBGDSCR, 0);
+ dwr(debug, DBGDRCR, DRCR_CLR_EXC);
+ dwr(debug, DBGDRCR, DRCR_START_REQ);
+
+ debug->state = STATE_RUNNING;
+ return 0;
+}
+
+int debug_reg_dump(V7DEBUG *debug) {
+ int n;
+ u32 r[17];
+ for (n = 0; n < 17; n++) {
+ if (debug_reg_rd(debug, n, r + n)) return -1;
+ }
+
+ printf(" r0: %08x r1: %08x r2: %08x r3: %08x\n",
+ r[0], r[1], r[2], r[3]);
+ printf(" r4: %08x r5: %08x r6: %08x r7: %08x\n",
+ r[4], r[5], r[6], r[7]);
+ printf(" r8: %08x r9: %08x r10: %08x r11: %08x\n",
+ r[8], r[9], r[10], r[11]);
+ printf(" r12: %08x sp: %08x lr: %08x pc: %08x\n",
+ r[12], r[13], r[14], r[15]);
+ printf("cpsr: %08x\n", r[16]);
return 0;
}
@@ -130,17 +274,47 @@ halted:
#define ZYNQ_DEBUG1_APN 1
#define ZYNQ_DEBUG1_BASE 0x80092000
+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;
+}
+
int main(int argc, char **argv) {
JTAG *jtag;
DAP *dap;
V7DEBUG *debug;
+ void *data;
+ u32 sz;
if (jtag_mpsse_open(&jtag)) return -1;
if ((dap = dap_init(jtag, 0x4ba00477)) == NULL) return -1;
if ((debug = debug_init(dap, ZYNQ_DEBUG0_APN, ZYNQ_DEBUG0_BASE)) == NULL) return -1;
if (debug_attach(debug)) return -1;
- fprintf(stderr, "whee!\n");
+ debug_reg_dump(debug);
+
+ if (argc == 2) {
+ if ((data = loadfile(argv[1], &sz))) {
+ dap_mem_write(dap, 0, 0, data, sz);
+ debug_reg_wr(debug, 15, 0);
+ }
+ }
+
+ debug_detach(debug);
return 0;
}