commit 52d836949e0b7440258ea23ae635613bed6bae41
parent de60c86b2ae817590c82b62847e3f23054794eb2
Author: Brian Swetland <swetland@frotz.net>
Date: Fri, 3 Mar 2023 23:44:48 -0800
add register read/write and processor halt/resume/check
Diffstat:
3 files changed, 129 insertions(+), 2 deletions(-)
diff --git a/src/arm-v7-debug.h b/src/arm-v7-debug.h
@@ -53,8 +53,9 @@
// bit 16 controls read vs write
-#define DCRSR_RD 0x00000000
-#define DCRSR_WR 0x00010000
+#define DCRSR_RD 0x00000000
+#define DCRSR_WR 0x00010000
+#define DCRSR_ID_MASK 0x0000FFFF
// to write: write value to DCRDR
// write (regno | DCRSR_WR) to DCRSR
diff --git a/src/transport-arm-debug.c b/src/transport-arm-debug.c
@@ -5,6 +5,7 @@
#include "transport-private.h"
#include "arm-debug.h"
+#include "arm-v7-debug.h"
static void dc_q_map_csw_wr(DC* dc, uint32_t val) {
if (val != dc->map_csw_cache) {
@@ -31,6 +32,16 @@ void dc_q_mem_rd32(DC* dc, uint32_t addr, uint32_t* val) {
}
}
+void dc_q_mem_match32(DC* dc, uint32_t addr, uint32_t val) {
+ if (addr & 3) {
+ dc->qerror = DC_ERR_BAD_PARAMS;
+ } else {
+ dc_q_map_csw_wr(dc, MAP_CSW_SZ_32 | MAP_CSW_INC_OFF | MAP_CSW_DEVICE_EN);
+ dc_q_map_tar_wr(dc, addr);
+ dc_q_ap_match(dc, MAP_DRW, val);
+ }
+}
+
void dc_q_mem_wr32(DC* dc, uint32_t addr, uint32_t val) {
if (addr & 3) {
dc->qerror = DC_ERR_BAD_PARAMS;
@@ -127,3 +138,105 @@ int dc_mem_wr_words(dctx_t* dc, uint32_t addr, uint32_t num, const uint32_t* ptr
return DC_OK;
}
#endif
+
+int dc_core_check_halt(dctx_t* dc) {
+ uint32_t val;
+ int r;
+ if ((r = dc_mem_rd32(dc, DHCSR, &val)) < 0) {
+ return r;
+ }
+ if (val & DHCSR_S_HALT) {
+ return 1;
+ }
+ return 0;
+}
+
+int dc_core_halt(DC* dc) {
+ uint32_t val;
+ int r;
+ if ((r = dc_mem_rd32(dc, DHCSR, &val)) < 0) {
+ return r;
+ }
+ if (val & DHCSR_C_DEBUGEN) {
+ // preserve C_MASKINTS
+ val &= DHCSR_C_MASKINTS;
+ } else {
+ // when setting C_DEBUGEN to 1 (from 0),
+ // must write 0 to C_MASKINTS
+ val = 0;
+ }
+ // set C_HALT and C_DEBUGEN
+ val |= DHCSR_C_HALT | DHCSR_C_DEBUGEN | DHCSR_DBGKEY;
+ if ((r = dc_mem_wr32(dc, DHCSR, val)) < 0) {
+ return r;
+ }
+ for (unsigned n = 0; n < 64; n++) {
+ if (dc_core_check_halt(dc) == 1) {
+ return 0;
+ }
+ }
+ return DC_ERR_TIMEOUT;
+}
+
+int dc_core_resume(DC* dc){
+ uint32_t val;
+ int r;
+ if ((r = dc_mem_rd32(dc, DHCSR, &val)) < 0) {
+ return r;
+ }
+ if (val & DHCSR_C_DEBUGEN) {
+ // preserve C_MASKINTS
+ val &= DHCSR_C_MASKINTS;
+ } else {
+ // when setting C_DEBUGEN to 1 (from 0),
+ // must write 0 to C_MASKINTS
+ val = 0;
+ }
+ // clear C_HALT
+ val |= DHCSR_C_DEBUGEN | DHCSR_DBGKEY;
+ if ((r = dc_mem_wr32(dc, DHCSR, val)) < 0) {
+ return r;
+ }
+ for (unsigned n = 0; n < 64; n++) {
+ if (dc_core_check_halt(dc) == 0) {
+ return 0;
+ }
+ }
+ return DC_ERR_TIMEOUT;
+}
+
+int dc_core_step(DC* dc) {
+ return DC_ERR_FAILED;
+}
+
+static void dc_q_core_reg_rd(DC* dc, unsigned id, uint32_t* val) {
+ dc_q_mem_wr32(dc, DCRSR, DCRSR_RD | (id & DCRSR_ID_MASK));
+ dc_q_set_mask(dc, DHCSR_S_REGRDY);
+ dc_q_mem_match32(dc, DHCSR, DHCSR_S_REGRDY);
+ dc_q_mem_rd32(dc, DCRDR, val);
+}
+static void dc_q_core_reg_wr(DC* dc, unsigned id, uint32_t val) {
+ dc_q_mem_wr32(dc, DCRDR, val);
+ dc_q_mem_wr32(dc, DCRSR, DCRSR_WR | (id & DCRSR_ID_MASK));
+ dc_q_set_mask(dc, DHCSR_S_REGRDY);
+ dc_q_mem_match32(dc, DHCSR, DHCSR_S_REGRDY);
+}
+
+int dc_core_reg_rd(DC* dc, unsigned id, uint32_t* val) {
+ dc_q_init(dc);
+ dc_q_core_reg_rd(dc, id, val);
+ return dc_q_exec(dc);
+}
+int dc_core_reg_wr(DC* dc, unsigned id, uint32_t val) {
+ dc_q_init(dc);
+ dc_q_core_reg_wr(dc, id, val);
+ return dc_q_exec(dc);
+}
+int dc_core_reg_rd_list(DC* dc, uint32_t* id, uint32_t* val, unsigned count) {
+ dc_q_init(dc);
+ while (count > 0) {
+ dc_q_core_reg_rd(dc, *id++, val++);
+ count--;
+ }
+ return dc_q_exec(dc);
+}
diff --git a/src/transport.h b/src/transport.h
@@ -67,6 +67,7 @@ int dc_attach(dctx_t* dc, unsigned flags, uint32_t tgt, uint32_t* idcode);
void dc_q_mem_rd32(dctx_t* dc, uint32_t addr, uint32_t* val);
void dc_q_mem_wr32(dctx_t* dc, uint32_t addr, uint32_t val);
+void dc_q_mem_match32(dctx_t* dc, uint32_t addr, uint32_t val);
int dc_mem_rd32(dctx_t* dc, uint32_t addr, uint32_t* val);
int dc_mem_wr32(dctx_t* dc, uint32_t addr, uint32_t val);
@@ -76,3 +77,15 @@ int dc_mem_wr_words(dctx_t* dc, uint32_t addr, uint32_t num, const uint32_t* ptr
+int dc_core_halt(dctx_t* dc);
+int dc_core_resume(dctx_t* dc);
+int dc_core_step(dctx_t* dc);
+
+int dc_core_reg_rd(dctx_t* dc, unsigned id, uint32_t* val);
+int dc_core_reg_wr(dctx_t* dc, unsigned id, uint32_t val);
+
+int dc_core_reg_rd_list(dctx_t* dc, uint32_t* id, uint32_t* val, unsigned count);
+
+// 0 = no, 1 = yes, < 0 = error
+int dc_core_check_halt(dctx_t* dc);
+