Commit 2415a52afbf350f33915225b4c87cb89ed6c95ac
authorga <ga@oldell.fish>
Wed, 16 Mar 2022 16:56:41 +0000 (16:56 +0000)
committerga <ga@oldell.fish>
Wed, 16 Mar 2022 17:55:04 +0000 (17:55 +0000)
"monitor ior <base> <count>" to select only some registers for output.
Selective cherry-pick of 6923a0ac705c773e663358c7231e36a10e453d19
and 05b6803d390ac87c1b4deb9f296f7e39a20a6633.

3 files changed:
simavr/sim/sim_avr.h
simavr/sim/sim_core.c
simavr/sim/sim_gdb.c

index 710e12b1b0a08a15f24e438f4d70f11a277ea932..e9a97cde20e03f5f234e392d294e2b2e3d736057 100644 (file)
@@ -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)
index 4bb254334a80e1284f9a8465878d5b51940f8377..4dae91ed5ce6d24640e5aeadf84e06fc270c08e1 100644 (file)
@@ -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];
index 5ea74a126902a177842d96aa24926e6019228612..144c6ffa6af8bdf3e89549fba73cf1b3a3608bcf 100644 (file)
@@ -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 <base> <count>
+                       // 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;