commit 4280d3f76877bc695706f913bd1241f56838afa2
parent 81203d554763a279dfc53ff7daf9b13ac426fcc9
Author: Brian Swetland <swetland@frotz.net>
Date: Sat, 4 Mar 2023 15:22:26 -0800
start bolting the text UI on
- xtest exercises the transport by itself
- xdebug is the debugger
- start unifying logging
- minimal command parser
Diffstat:
7 files changed, 429 insertions(+), 73 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,16 +1,28 @@
-all: out/xdebug
+all: out/xdebug out/xtest
CFLAGS := -Wall -g -O1
-
-SRCS := src/xdebug.c src/transport-arm-debug.c src/transport-dap.c src/usb.c
+CFLAGS += -Itui -Itermbox -D_XOPEN_SOURCE
LIBS := -lusb-1.0
-OBJS := $(addprefix out/,$(patsubst %.c,%.o,$(filter %.c,$(SRCS))))
+COMMON := src/transport-arm-debug.c src/transport-dap.c src/usb.c
+XTESTSRCS := src/xtest.c $(COMMON)
+XTESTOBJS := $(addprefix out/,$(patsubst %.c,%.o,$(filter %.c,$(XTESTSRCS))))
+
+XDEBUGSRCS := src/xdebug.c src/commands.c $(COMMON)
+XDEBUGSRCS += tui/tui.c termbox/termbox.c termbox/utf8.c
+XDEBUGOBJS := $(addprefix out/,$(patsubst %.c,%.o,$(filter %.c,$(XDEBUGSRCS))))
-out/xdebug: $(OBJS)
+out/xtest: $(XTESTOBJS)
@mkdir -p $(dir $@)
- gcc -o $@ -Wall -g -O1 $(OBJS) $(LIBS)
+ gcc -o $@ -Wall -g -O1 $(XTESTOBJS) $(LIBS)
+
+out/xdebug: $(XDEBUGOBJS)
+ @mkdir -p $(dir $@)
+ gcc -o $@ -Wall -g -O1 $(XDEBUGOBJS) $(LIBS)
+
+# remove dups
+OBJS := $(sort $(XTESTOBJS) $(XDEBUGOBJS))
$(OBJS): out/%.o: %.c $(XDEPS)
@mkdir -p $(dir $@)
diff --git a/src/commands.c b/src/commands.c
@@ -0,0 +1,54 @@
+// Copyright 2023, Brian Swetland <swetland@frotz.net>
+// Licensed under the Apache License, Version 2.0.
+
+#include <string.h>
+
+#include "xdebug.h"
+#include "transport.h"
+#include "arm-v7-debug.h"
+#include "arm-v7-system-control.h"
+
+
+int do_exit(DC* dc, CC* cc) {
+ debugger_exit();
+ return 0;
+}
+
+int do_help(DC* dc, CC* cc);
+
+struct {
+ const char* name;
+ int (*func)(DC* dc, CC* cc);
+ const char* help;
+} CMDS[] = {
+ { "exit", do_exit, "exit debugger" },
+ { "quit", do_exit, NULL },
+ { "help", do_help, "list debugger commands" },
+};
+
+int do_help(DC* dc, CC* cc) {
+ int w = 0;
+ for (int n = 0; n < sizeof(CMDS)/sizeof(CMDS[0]); n++) {
+ int len = strlen(CMDS[0].name);
+ if (len > w) w = len;
+ }
+ for (int n = 0; n < sizeof(CMDS)/sizeof(CMDS[0]); n++) {
+ if (CMDS[n].help == NULL) {
+ continue;
+ }
+ INFO("%-*s %s", w, CMDS[n].name, CMDS[n].help);
+ }
+ return 0;
+}
+
+void debugger_command(DC* dc, CC* cc) {
+ const char* cmd = cmd_name(cc);
+ for (int n = 0; n < sizeof(CMDS)/sizeof(CMDS[0]); n++) {
+ if (!strcmp(cmd, CMDS[n].name)) {
+ CMDS[n].func(dc, cc);
+ return;
+ }
+ }
+ ERROR("unknown command '%s'\n", cmd);
+}
+
diff --git a/src/transport-dap.c b/src/transport-dap.c
@@ -426,7 +426,7 @@ int dc_attach(DC* dc, unsigned flags, unsigned tgt, uint32_t* idcode) {
uint32_t n;
_dc_attach(dc, 0, 0, &n);
- printf("IDCODE %08x\n", n);
+ INFO("IDCODE %08x\n", n);
// If this is a RP2040, we need to connect in multidrop
// mode before doing anything else.
@@ -438,7 +438,7 @@ int dc_attach(DC* dc, unsigned flags, unsigned tgt, uint32_t* idcode) {
}
dc_dp_rd(dc, DP_CS, &n);
- printf("CTRL/STAT %08x\n", n);
+ INFO("CTRL/STAT %08x\n", n);
// clear all sticky errors
dc_dp_wr(dc, DP_ABORT, DP_ABORT_ALLCLR);
@@ -451,8 +451,8 @@ int dc_attach(DC* dc, unsigned flags, unsigned tgt, uint32_t* idcode) {
dc_q_dp_rd(dc, DP_CS, &n);
dc_q_ap_rd(dc, MAP_CSW, &dc->map_csw_keep);
dc_q_exec(dc);
- printf("CTRL/STAT %08x\n", n);
- printf("MAP.CSW %08x\n", dc->map_csw_keep);
+ INFO("CTRL/STAT %08x\n", n);
+ INFO("MAP.CSW %08x\n", dc->map_csw_keep);
dc->map_csw_keep &= MAP_CSW_KEEP;
@@ -503,40 +503,40 @@ static int dap_configure(DC* dc) {
int sz = dap_get_info(dc, n, buf, 0, 255);
if (sz > 0) {
buf[sz] = 0;
- printf("0x%02x: '%s'\n", n, (char*) buf);
+ INFO("0x%02x: '%s'\n", n, (char*) buf);
}
}
buf[0] = 0; buf[1] = 0;
if (dap_get_info(dc, DI_Capabilities, buf, 1, 2) > 0) {
- printf("Capabilities: 0x%02x 0x%02x\n", buf[0], buf[1]);
- printf("Capabilities:");
- if (buf[0] & I0_SWD) printf(" SWD");
- if (buf[0] & I0_JTAG) printf(" JTAG");
- if (buf[0] & I0_SWO_UART) printf(" SWO(UART)");
- if (buf[0] & I0_SWO_Manchester) printf(" SWO(Manchester)");
- if (buf[0] & I0_Atomic_Commands) printf(" ATOMIC");
- if (buf[0] & I0_Test_Domain_Timer) printf(" TIMER");
- if (buf[0] & I0_SWO_Streaming_Trace) printf(" SWO(Streaming)");
- if (buf[0] & I0_UART_Comm_Port) printf(" UART");
- if (buf[1] & I1_USB_COM_Port) printf(" USBCOM");
- printf("\n");
+ INFO("Capabilities: 0x%02x 0x%02x\n", buf[0], buf[1]);
+ INFO("Capabilities:");
+ if (buf[0] & I0_SWD) INFO(" SWD");
+ if (buf[0] & I0_JTAG) INFO(" JTAG");
+ if (buf[0] & I0_SWO_UART) INFO(" SWO(UART)");
+ if (buf[0] & I0_SWO_Manchester) INFO(" SWO(Manchester)");
+ if (buf[0] & I0_Atomic_Commands) INFO(" ATOMIC");
+ if (buf[0] & I0_Test_Domain_Timer) INFO(" TIMER");
+ if (buf[0] & I0_SWO_Streaming_Trace) INFO(" SWO(Streaming)");
+ if (buf[0] & I0_UART_Comm_Port) INFO(" UART");
+ if (buf[1] & I1_USB_COM_Port) INFO(" USBCOM");
+ INFO("\n");
}
if (dap_get_info(dc, DI_UART_RX_Buffer_Size, &n32, 4, 4) == 4) {
- printf("UART RX Buffer Size: %u\n", n32);
+ INFO("UART RX Buffer Size: %u\n", n32);
}
if (dap_get_info(dc, DI_UART_TX_Buffer_Size, &n32, 4, 4) == 4) {
- printf("UART TX Buffer Size: %u\n", n32);
+ INFO("UART TX Buffer Size: %u\n", n32);
}
if (dap_get_info(dc, DI_SWO_Trace_Buffer_Size, &n32, 4, 4) == 4) {
- printf("SWO Trace Buffer Size: %u\n", n32);
+ INFO("SWO Trace Buffer Size: %u\n", n32);
}
if (dap_get_info(dc, DI_Max_Packet_Count, &n8, 1, 1) == 1) {
- printf("Max Packet Count: %u\n", n8);
+ INFO("Max Packet Count: %u\n", n8);
dc->max_packet_count = n8;
}
if (dap_get_info(dc, DI_Max_Packet_Size, &n16, 2, 2) == 2) {
- printf("Max Packet Size: %u\n", n16);
+ INFO("Max Packet Size: %u\n", n16);
dc->max_packet_size = n16;
}
if ((dc->max_packet_count < 1) || (dc->max_packet_size < 64)) {
diff --git a/src/transport-private.h b/src/transport-private.h
@@ -3,6 +3,8 @@
#pragma once
+#include "xdebug.h"
+
#include <stdint.h>
#include "usb.h"
@@ -51,17 +53,7 @@ typedef struct debug_context DC;
#define INVALID 0xFFFFFFFFU
-#define WITH_TRACE 0
-
-#if WITH_TRACE
-#define TRACE(fmt...) fprintf(stderr, fmt)
-#else
-#define TRACE(fmt...) do {} while (0)
-#endif
-
-#define ERROR(fmt...) fprintf(stderr, fmt)
-
-#if WITH_TRACE
+#if 0
static void dump(const char* str, const void* ptr, unsigned len) {
const uint8_t* x = ptr;
TRACE("%s", str);
diff --git a/src/xdebug.c b/src/xdebug.c
@@ -5,52 +5,197 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
+#include <stdarg.h>
+
+#include "xdebug.h"
+#include "tui.h"
-#include "arm-debug.h"
-#include "cmsis-dap-protocol.h"
#include "transport.h"
-int main(int argc, char **argv) {
- uint32_t n = 0;
+#define MAX_ARGS 16
+
+static const char* NTH(unsigned n) {
+ switch (n) {
+ case 1: return "1st ";
+ case 2: return "2nd ";
+ case 3: return "3rd ";
+ case 4: return "4th ";
+ case 5: return "5th ";
+ default: return "";
+ }
+}
+
+#define tSTRING 0x01
+#define tNUMBER 0x02
+
+typedef struct token {
+ const char* s;
+ uint32_t n;
+ uint32_t info;
+} TOKEN;
+
+struct command_context {
+ TOKEN tok[MAX_ARGS];
+ unsigned count;
+};
+
+const char* cmd_name(CC* cc) {
+ return cc->tok[0].s;
+}
+
+int cmd_arg_u32(CC* cc, unsigned nth, uint32_t* out) {
+ if (nth >= cc->count) {
+ ERROR("%s: missing %sargument\n", cc->tok[0].s, NTH(nth));
+ return DBG_ERR;
+ }
+ if (!(cc->tok[nth].info & tNUMBER)) {
+ ERROR("%s: %sargument not a number\n", cc->tok[0].s, NTH(nth));
+ return DBG_ERR;
+ }
+ *out = cc->tok[nth].n;
+ return 0;
+}
+
+int cmd_arg_u32_opt(CC* cc, unsigned nth, uint32_t* out, uint32_t val) {
+ if (nth >= cc->count) {
+ *out = val;
+ return 0;
+ }
+ if (!(cc->tok[nth].info & tNUMBER)) {
+ ERROR("%s: %sargument not a number\n", cc->tok[0].s, NTH(nth));
+ return DBG_ERR;
+ }
+ *out = cc->tok[nth].n;
+ return 0;
+}
+
+int cmd_arg_str(CC* cc, unsigned nth, const char** out) {
+ if (nth >= cc->count) {
+ ERROR("%s: missing %sargument\n", cc->tok[0].s, NTH(nth));
+ return DBG_ERR;
+ }
+ *out = cc->tok[nth].s;
+ return 0;
+}
+
+int cmd_arg_str_opt(CC* cc, unsigned nth, const char** out, const char* str) {
+ if (nth >= cc->count) {
+ *out = str;
+ } else {
+ *out = cc->tok[nth].s;
+ }
+ return 0;
+}
+
+static DC* dc;
- dctx_t* dc;
- if (dc_create(&dc) < 0) {
- return -1;
+int parse(TOKEN* tok) {
+ char *end;
+ if ((tok->s[0] == '.') && tok->s[1]) {
+ // decimal
+ tok->n = strtoul(tok->s + 1, &end, 10);
+ if (*end == 0) {
+ tok->info = tNUMBER;
+ return 0;
+ }
}
+ tok->n = strtoul(tok->s, &end, 16);
+ if (*end == 0) {
+ tok->info = tNUMBER;
+ return 0;
+ }
+ tok->n = 0;
+ tok->info = tSTRING;
+ return 0;
+}
- dc_set_clock(dc, 1000000);
+void handle_line(char *line, unsigned len) {
+ CC cc;
- dc_attach(dc, 0, 0, &n);
+ while (*line && (*line <= ' ')) line++;
+ if (*line == '/') {
+ cc.count = 2;
+ cc.tok[0].s = "wconsole";
+ cc.tok[0].info = tSTRING;
+ cc.tok[1].s = line + 1;
+ cc.tok[1].info = tSTRING;
+ cc.count = 2;
+ debugger_command(dc, &cc);
+ return;
+ }
-#if 1
- // dump some info
- dc_dp_rd(dc, DP_DPIDR, &n);
- printf("DP.DPIDR %08x\n", n);
- dc_dp_rd(dc, DP_TARGETID, &n);
- printf("DP.TARGETID %08x\n", n);
- dc_dp_rd(dc, DP_DLPIDR, &n);
- printf("DP.DLPIDR %08x\n", n);
- dc_ap_rd(dc, MAP_IDR, &n);
- printf("MAP.IDR %08x\n", n);
- dc_ap_rd(dc, MAP_CSW, &n);
- printf("MAP.CSW %08x\n", n);
- dc_ap_rd(dc, MAP_CFG, &n);
- printf("MAP.CFG %08x\n", n);
- dc_ap_rd(dc, MAP_CFG1, &n);
- printf("MAP.CFG1 %08x\n", n);
- dc_ap_rd(dc, MAP_BASE, &n);
- printf("MAP.BASE %08x\n", n);
-#endif
+ unsigned c, n = 0;
+ while ((c = *line)) {
+ if (c <= ' ') {
+ line++;
+ continue;
+ }
+ if (n == MAX_ARGS) {
+ ERROR("too many arguments\n");
+ return;
+ }
+ cc.tok[n].s = line;
+ for (;;) {
+ if (c == 0) {
+ n++;
+ break;
+ } else if (c == '#') {
+ *line = 0;
+ break;
+ } else if (c <= ' ') {
+ *line++ = 0;
+ n++;
+ break;
+ }
+ c = *++line;
+ }
+ }
- dc_mem_rd32(dc, 0, &n);
- printf("%08x: %08x\n", 0, n);
+ if (n == 0) {
+ return;
+ }
- unsigned addr = 0x00000000;
- for (unsigned a = addr; a < addr + 32; a += 4) {
- dc_mem_rd32(dc, a, &n);
- printf("%08x: %08x\n", a, n);
+ cc.tok[0].info = tSTRING;
+ for (c = 1; c < n; n++) {
+ if (parse(cc.tok + n) < 0) {
+ return;
+ }
}
+ debugger_command(dc, &cc);
+}
+static tui_ch_t* ch;
+
+int main(int argc, char** argv) {
+ tui_init();
+ tui_ch_create(&ch, 0);
+ dc_create(&dc);
+ while (tui_handle_event(handle_line) == 0) ;
+ tui_exit();
return 0;
}
+void debugger_exit(void) {
+ tui_exit();
+ exit(0);
+}
+
+void MSG(uint32_t flags, const char* fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ switch (flags) {
+ case mDEBUG:
+ tui_ch_printf(ch, "debug: ");
+ break;
+ case mTRACE:
+ tui_ch_printf(ch, "trace: ");
+ break;
+ case mPANIC:
+ tui_exit();
+ fprintf(stderr,"panic: ");
+ vfprintf(stderr, fmt, ap);
+ exit(-1);
+ }
+ tui_ch_vprintf(ch, fmt, ap);
+ va_end(ap);
+}
diff --git a/src/xdebug.h b/src/xdebug.h
@@ -0,0 +1,36 @@
+// Copyright 2023, Brian Swetland <swetland@frotz.net>
+// Licensed under the Apache License, Version 2.0.
+
+#pragma once
+
+#include <stdint.h>
+#include <stdarg.h>
+
+void MSG(uint32_t flags, const char* fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+
+#define mINFO 1
+#define mDEBUG 2
+#define mTRACE 3
+#define mERROR 4
+#define mPANIC 5
+
+#define DEBUG(fmt...) MSG(mDEBUG, fmt)
+#define INFO(fmt...) MSG(mINFO, fmt)
+#define TRACE(fmt...) MSG(mTRACE, fmt)
+#define ERROR(fmt...) MSG(mERROR, fmt)
+#define PANIC(fmt...) MSG(mPANIC, fmt)
+
+#define DBG_OK 0
+#define DBG_ERR -1
+
+typedef struct command_context CC;
+const char* cmd_name(CC* cc);
+int cmd_arg_u32(CC* cc, unsigned nth, uint32_t* out);
+int cmd_arg_u32_opt(CC* cc, unsigned nth, uint32_t* out, uint32_t val);
+int cmd_arg_str(CC* cc, unsigned nth, const char** out);
+int cmd_arg_str_opt(CC* cc, unsigned nth, const char** out, const char* str);
+
+typedef struct debug_context DC;
+void debugger_command(DC* dc, CC* cc);
+void debugger_exit(void);
diff --git a/src/xtest.c b/src/xtest.c
@@ -0,0 +1,117 @@
+// Copyright 2023, Brian Swetland <swetland@frotz.net>
+// Licensed under the Apache License, Version 2.0.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "xdebug.h"
+#include "transport.h"
+#include "arm-debug.h"
+#include "cmsis-dap-protocol.h"
+
+void MSG(uint32_t flags, const char* fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
+void dump(uint32_t* w, int count) {
+ int n = 0;
+ while (count > 0) {
+ INFO(" %08x", *w++);
+ count--;
+ n++;
+ if (n == 4) {
+ INFO("\n");
+ n = 0;
+ }
+ }
+ if (n) INFO("\n");
+}
+
+int main(int argc, char **argv) {
+ uint32_t n = 0;
+
+ dctx_t* dc;
+ if (dc_create(&dc) < 0) {
+ return -1;
+ }
+
+ dc_set_clock(dc, 4000000);
+
+ dc_attach(dc, 0, 0, &n);
+
+#if 1
+ // dump some info
+ dc_dp_rd(dc, DP_DPIDR, &n);
+ INFO("DP.DPIDR %08x\n", n);
+ dc_dp_rd(dc, DP_TARGETID, &n);
+ INFO("DP.TARGETID %08x\n", n);
+ dc_dp_rd(dc, DP_DLPIDR, &n);
+ INFO("DP.DLPIDR %08x\n", n);
+ dc_ap_rd(dc, MAP_IDR, &n);
+ INFO("MAP.IDR %08x\n", n);
+ dc_ap_rd(dc, MAP_CSW, &n);
+ INFO("MAP.CSW %08x\n", n);
+ dc_ap_rd(dc, MAP_CFG, &n);
+ INFO("MAP.CFG %08x\n", n);
+ dc_ap_rd(dc, MAP_CFG1, &n);
+ INFO("MAP.CFG1 %08x\n", n);
+ dc_ap_rd(dc, MAP_BASE, &n);
+ INFO("MAP.BASE %08x\n", n);
+#endif
+
+#if 0
+ dc_mem_rd32(dc, 0, &n);
+ INFO("%08x: %08x\n", 0, n);
+
+ dc_mem_rd32(dc, 0xc0000000, &n);
+ INFO("%08x: %08x\n", 0, n);
+
+ dc_mem_rd32(dc, 0, &n);
+ INFO("%08x: %08x\n", 0, n);
+
+ unsigned addr = 0x00000000;
+ for (unsigned a = addr; a < addr + 32; a += 4) {
+ dc_mem_rd32(dc, a, &n);
+ INFO("%08x: %08x\n", a, n);
+ }
+#endif
+
+#if 0
+ int r = dc_core_halt(dc);
+ INFO("halt ? %d\n", r);
+ r = dc_core_reg_rd(dc, 0, &n);
+ INFO("r0 %x ? %d\n", n, r);
+ r = dc_core_reg_wr(dc, 0, 0xe0a0b0c0);
+ INFO("wr ? %d\n", r);
+ r = dc_core_reg_rd(dc, 15, &n);
+ INFO("r15 %x ? %d\n", n, r);
+ r = dc_core_reg_rd(dc, 0, &n);
+ INFO("r0 %x ? %d\n", n, r);
+ r = dc_core_resume(dc);
+ INFO("resume ? %d\n", r);
+ r = dc_core_reg_rd(dc, 0, &n);
+ INFO("r0 %x ? %d\n", n, r);
+ r = dc_core_reg_rd(dc, 15, &n);
+ INFO("r15 %x ? %d\n", n, r);
+#endif
+
+#if 0
+ uint32_t w[1024];
+ int r = dc_mem_rd_words(dc, 0x00000000, 1024, w);
+ if (r == 0) {
+ dump(w, 1024);
+ }
+ for (unsigned n = 0; n < 250; n++) {
+ uint32_t w[1024];
+ dc_mem_rd_words(dc, 0x00000000, 1024, w);
+ }
+#endif
+ return 0;
+}
+