From 2415a52afbf350f33915225b4c87cb89ed6c95ac Mon Sep 17 00:00:00 2001 From: ga Date: Wed, 16 Mar 2022 16:56:41 +0000 Subject: [PATCH] Add support for avr-gdb's "info io_registers" command and also "monitor ior " to select only some registers for output. Selective cherry-pick of 6923a0ac705c773e663358c7231e36a10e453d19 and 05b6803d390ac87c1b4deb9f296f7e39a20a6633. --- simavr/sim/sim_avr.h | 2 + simavr/sim/sim_core.c | 4 +- simavr/sim/sim_gdb.c | 157 ++++++++++++++++++++++++++++++++++++------ 3 files changed, 140 insertions(+), 23 deletions(-) diff --git a/simavr/sim/sim_avr.h b/simavr/sim/sim_avr.h index 710e12b..e9a97cd 100644 --- a/simavr/sim/sim_avr.h +++ b/simavr/sim/sim_avr.h @@ -152,6 +152,8 @@ typedef void (*avr_run_t)( #define AVR_FUSE_HIGH 1 #define AVR_FUSE_EXT 2 +#define REG_NAME_COUNT (256 + 32) // Size of reg_names table. + /* * Main AVR instance. Some of these fields are set by the AVR "Core" definition files * the rest is runtime data (as little as possible) diff --git a/simavr/sim/sim_core.c b/simavr/sim/sim_core.c index 4bb2543..4dae91e 100644 --- a/simavr/sim/sim_core.c +++ b/simavr/sim/sim_core.c @@ -321,7 +321,7 @@ avr_flashaddr_t _avr_pop_addr(avr_t * avr) /* * "Pretty" register names */ -const char * reg_names[255] = { +const char * reg_names[REG_NAME_COUNT] = { [R_XH] = "XH", [R_XL] = "XL", [R_YH] = "YH", [R_YL] = "YL", [R_ZH] = "ZH", [R_ZL] = "ZL", @@ -330,7 +330,7 @@ const char * reg_names[255] = { }; -const char * avr_regname(uint8_t reg) +const char * avr_regname(unsigned int reg) { if (!reg_names[reg]) { char tt[16]; diff --git a/simavr/sim/sim_gdb.c b/simavr/sim/sim_gdb.c index 5ea74a1..144c6ff 100644 --- a/simavr/sim/sim_gdb.c +++ b/simavr/sim/sim_gdb.c @@ -48,11 +48,16 @@ typedef struct { typedef struct avr_gdb_t { avr_t * avr; - int listen; // listen socket - int s; // current gdb connection + int listen; // listen socket + int s; // current gdb connection avr_gdb_watchpoints_t breakpoints; avr_gdb_watchpoints_t watchpoints; + + // These are used by gdb's "info io_registers" command. + + uint16_t ior_base; + uint8_t ior_count, mad; } avr_gdb_t; @@ -218,7 +223,7 @@ gdb_change_breakpoint( uint32_t addr, uint32_t size ) { - DBG(printf("set %d kind %d addr %08x len %d\n", set, kind, addr, len);) + DBG(printf("set %d kind %d addr %08x len %d\n", set, kind, addr, size);) if (set) { return gdb_watch_add_or_update(w, kind, addr, size); @@ -281,6 +286,123 @@ gdb_read_register( return strlen(rep); } + +static uint8_t +handle_monitor(avr_t * avr, avr_gdb_t * g, char * cmd) +{ + char *ip, *op; + unsigned int c1, c2; + char dehex[64]; + + if (*cmd++ != ',') + return 1; // Bad format + for (op = dehex; op < dehex + (sizeof dehex - 1); ++op) { + if (!*cmd) + break; + if (sscanf(cmd, "%1x%1x", &c1, &c2) != 2) + return 2; // Bad format + *op = (c1 << 4) + c2; + cmd += 2; + } + *op = '\0'; + if (*cmd) + return 3; // Too long + ip = dehex; + while (*ip) { + while (*ip == ' ' || *ip == '\t') + ++ip; + + if (strncmp(ip, "reset", 5) == 0) { + avr->state = cpu_StepDone; + avr_reset(avr); + ip += 5; + } else if (strncmp(ip, "halt", 4) == 0) { + avr->state = cpu_Stopped; + ip += 4; + } else if (strncmp(ip, "ior", 3) == 0) { + unsigned int base; + int n, m, count; + + // Format is "ior + // or just "ior" to reset. + + ip += 3; + m = sscanf(ip, "%x %i%n", &base, &count, &n); + if (m <= 0) { + // Reset values. + + g->ior_base = g->ior_count = 0; + n = 0; + } else if (m != 2) { + return 1; + } else { + if (count <= 0 || base + count + 32 > REG_NAME_COUNT || + base + count + 32 > avr->ioend) { + return 4; // bad value + } + g->ior_base = base; + g->ior_count = count; + } + ip += n; + } else { + return 5; + } + } + return 0; +} + +static void +handle_io_registers(avr_t * avr, avr_gdb_t * g, char * cmd) +{ + extern const char *avr_regname(unsigned int); // sim_core.c + char * params; + char * reply; + unsigned int addr, count; + char buff[1024]; + + if (g->mad) { + /* For this command, gdb employs a streaming protocol, + * with the command being repeated until the stub sends + * an empy packet as terminator. That makes no sense, + * as the requests are sized to ensure the reply will + * fit in a single packet. + */ + + reply = ""; + g->mad = 0; + } else { + params = cmd + 11; + if (sscanf(params, ":%x,%x", &addr, &count) == 2) { + int i; + + // Send names and values. + addr += 32; + if (addr + count > avr->ioend) + count = avr->ioend + 1 - addr; + reply = buff; + for (i = 0; i < count; ++i) { + const char *name; + + name = avr_regname(addr + i); + reply += sprintf(reply, "%s,%x;", + name, avr->data[addr + i]); + if (reply > buff + sizeof buff - 20) + break; + } + } else { + // Send register count. + + count = g->ior_count ? g->ior_count : + avr->ioend > REG_NAME_COUNT ? + REG_NAME_COUNT - 32 : avr->ioend - 32; + sprintf(buff, "%x", count); + } + reply = buff; + g->mad = 1; + } + gdb_send_reply(g, reply); +} + static void gdb_handle_command( avr_gdb_t * g, @@ -349,25 +471,18 @@ gdb_handle_command( // all available registers. } } else if (strncmp(cmd, "Rcmd", 4) == 0) { // monitor command - char * args = strchr(cmd, ','); - if (args != NULL) { - args++; - while (args != 0x00) { - printf("%s",args); - if (strncmp(args, "7265736574", 10) == 0) { // reset matched - avr->state = cpu_StepDone; - avr_reset(avr); - args += 10; - } else if (strncmp(args, "68616c74", 8) == 0) { // halt matched - avr->state = cpu_Stopped; - args += 8; - } else if (strncmp(args, "20", 2) == 0) { // space matched - args += 2; - } else // no match - end - break; - } + uint8_t err = handle_monitor(avr, g, cmd + 4); + if (err) { + snprintf(rep, sizeof rep, + "E%02x", err); + gdb_send_reply(g, rep); + } else { + gdb_send_reply(g, "OK"); } - gdb_send_reply(g, "OK"); + break; + } else if (strncmp(cmd, "Ravr.io_reg", 11) == 0) { + handle_io_registers(avr, g, cmd); + break; } gdb_send_reply(g, ""); break; -- 2.39.5