Implement reading of CSRs.
authorTim Newsome <tim@sifive.com>
Sun, 13 Mar 2016 22:39:08 +0000 (15:39 -0700)
committerTim Newsome <tim@sifive.com>
Mon, 23 May 2016 19:12:10 +0000 (12:12 -0700)
riscv/gdbserver.cc
tests/gdbserver-smoke.py
tests/testlib.py

index 39bfdf85b3be5e61d32492f8187fa7a6c64eebd0..bc863130627ea6ced5784c13ac69d68eafd230d9 100644 (file)
@@ -189,11 +189,11 @@ void gdbserver_t::write()
       // Client can't take any more data right now.
       break;
     } else {
-      printf("wrote %ld bytes: ", bytes);
+      fprintf(stderr, "wrote %ld bytes: ", bytes);
       for (unsigned int i = 0; i < bytes; i++) {
-        printf("%c", send_buf[i]);
+        fprintf(stderr, "%c", send_buf[i]);
       }
-      printf("\n");
+      fprintf(stderr, "\n");
       send_buf.consume(bytes);
     }
   }
@@ -347,36 +347,126 @@ void consume_string(std::string &str, std::vector<uint8_t>::const_iterator &iter
   }
 }
 
+typedef enum {
+  RC_XPR,
+  RC_PC,
+  RC_FPR,
+  RC_CSR
+} register_class_t;
+
+typedef struct {
+  register_class_t clss;
+  int index;
+} register_access_t;
+    
+// gdb's register list is defined in riscv_gdb_reg_names gdb/riscv-tdep.c in
+// its source tree. The definition here must match that one.
+const register_access_t register_access[] = {
+  { RC_XPR, 0 },
+  { RC_XPR, 1 },
+  { RC_XPR, 2 },
+  { RC_XPR, 3 },
+  { RC_XPR, 4 },
+  { RC_XPR, 5 },
+  { RC_XPR, 6 },
+  { RC_XPR, 7 },
+  { RC_XPR, 8 },
+  { RC_XPR, 9 },
+  { RC_XPR, 10 },
+  { RC_XPR, 11 },
+  { RC_XPR, 12 },
+  { RC_XPR, 13 },
+  { RC_XPR, 14 },
+  { RC_XPR, 15 },
+  { RC_XPR, 16 },
+  { RC_XPR, 17 },
+  { RC_XPR, 18 },
+  { RC_XPR, 19 },
+  { RC_XPR, 20 },
+  { RC_XPR, 21 },
+  { RC_XPR, 22 },
+  { RC_XPR, 23 },
+  { RC_XPR, 24 },
+  { RC_XPR, 25 },
+  { RC_XPR, 26 },
+  { RC_XPR, 27 },
+  { RC_XPR, 28 },
+  { RC_XPR, 29 },
+  { RC_XPR, 30 },
+  { RC_XPR, 31 },
+  { RC_PC, 0 },
+  { RC_FPR, 0 },
+  { RC_FPR, 1 },
+  { RC_FPR, 2 },
+  { RC_FPR, 3 },
+  { RC_FPR, 4 },
+  { RC_FPR, 5 },
+  { RC_FPR, 6 },
+  { RC_FPR, 7 },
+  { RC_FPR, 8 },
+  { RC_FPR, 9 },
+  { RC_FPR, 10 },
+  { RC_FPR, 11 },
+  { RC_FPR, 12 },
+  { RC_FPR, 13 },
+  { RC_FPR, 14 },
+  { RC_FPR, 15 },
+  { RC_FPR, 16 },
+  { RC_FPR, 17 },
+  { RC_FPR, 18 },
+  { RC_FPR, 19 },
+  { RC_FPR, 20 },
+  { RC_FPR, 21 },
+  { RC_FPR, 22 },
+  { RC_FPR, 23 },
+  { RC_FPR, 24 },
+  { RC_FPR, 25 },
+  { RC_FPR, 26 },
+  { RC_FPR, 27 },
+  { RC_FPR, 28 },
+  { RC_FPR, 29 },
+  { RC_FPR, 30 },
+  { RC_FPR, 31 },
+
+#define DECLARE_CSR(name, num) { RC_CSR, num },
+#include "encoding.h"
+#undef DECLARE_CSR
+};
 
 void gdbserver_t::handle_register_read(const std::vector<uint8_t> &packet)
 {
   // p n
 
-  // Register order that gdb expects is:
-  //   "x0",  "x1",  "x2",  "x3",  "x4",  "x5",  "x6",  "x7",
-  //   "x8",  "x9",  "x10", "x11", "x12", "x13", "x14", "x15",
-  //   "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
-  //   "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31",
-  //   "pc",
-  //   "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
-  //   "f8",  "f9",  "f10", "f11", "f12", "f13", "f14", "f15",
-  //   "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
-  //   "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
-
   std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
   unsigned int n = consume_hex_number(iter, packet.end());
   if (*iter != '#')
     return send_packet("E01");
 
+  if (n >= sizeof(register_access) / sizeof(*register_access))
+    return send_packet("E02");
+
   processor_t *p = sim->get_core(0);
   send("$");
   running_checksum = 0;
-  if (n < 32) {
-    send(p->state.XPR[n]);
-  } else if (n == 0x20) {
-    send(p->state.pc);
-  } else {
-    send("E02");
+
+  register_access_t access = register_access[n];
+  switch (access.clss) {
+    case RC_XPR:
+      send(p->state.XPR[access.index]);
+      break;
+    case RC_PC:
+      send(p->state.pc);
+      break;
+    case RC_FPR:
+      send(p->state.FPR[access.index]);
+      break;
+    case RC_CSR:
+      try {
+        send(p->get_csr(access.index));
+      } catch(trap_t& t) {
+        send((reg_t) 0);
+      }
+      break;
   }
 
   send_running_checksum();
@@ -491,12 +581,12 @@ void software_breakpoint_t::insert(mmu_t* mmu)
     instruction = mmu->load_uint32(address);
     mmu->store_uint32(address, EBREAK);
   }
-  printf(">>> Read %x from %lx\n", instruction, address);
+  fprintf(stderr, ">>> Read %x from %lx\n", instruction, address);
 }
 
 void software_breakpoint_t::remove(mmu_t* mmu)
 {
-  printf(">>> write %x to %lx\n", instruction, address);
+  fprintf(stderr, ">>> write %x to %lx\n", instruction, address);
   if (size == 2) {
     mmu->store_uint16(address, instruction);
   } else {
@@ -561,7 +651,6 @@ void gdbserver_t::handle_query(const std::vector<uint8_t> &packet)
       consume_string(feature, iter, packet.end(), ';');
       if (iter != packet.end())
         iter++;
-      printf("is %s supported?\n", feature.c_str());
       if (feature == "swbreak+") {
         send("swbreak+;");
       }
@@ -569,7 +658,7 @@ void gdbserver_t::handle_query(const std::vector<uint8_t> &packet)
     return send_running_checksum();
   }
 
-  printf("Unsupported query %s\n", name.c_str());
+  fprintf(stderr, "Unsupported query %s\n", name.c_str());
   return send_packet("");
 }
 
index d9eae927efcd435d34b4de8538e68e84cde501b6..9cdac06289d1b14702f8dc6f2a5aae80356a065c 100755 (executable)
@@ -14,7 +14,6 @@ class SmokeTest(unittest.TestCase):
         self.gdb = testlib.Gdb()
         self.gdb.command("file %s" % self.tmpf.name)
         self.gdb.command("target extended-remote localhost:9824")
-        self.gdb.command("p i");
         self.gdb.command("p i=0");
 
     def cleanUp(self):
@@ -45,5 +44,22 @@ class SmokeTest(unittest.TestCase):
         self.assertIn("Continuing", output)
         self.assertIn("Remote connection closed", output)
 
+    def test_registers(self):
+        output = self.gdb.command("info all-registers")
+        self.assertNotIn("Could not", output)
+        for reg in ('zero', 'ra', 'sp', 'gp', 'tp'):
+            self.assertIn(reg, output)
+        # mcpuid is one of the few registers that should have the high bit set
+        # (for rv64).
+        self.assertRegexpMatches(output, ".*mcpuid *0x80")
+
+        # The time register should always be changing.
+        last_time = None
+        for _ in range(5):
+            time = self.gdb.command("p $time").split('=')[-1]
+            self.assertNotEqual(time, last_time)
+            last_time = time
+            self.gdb.command("stepi")
+
 if __name__ == '__main__':
     unittest.main()
index 274ba6ce576764654cd82f0a88cd5f2a24eec374..1f60ce6b188e10c6fdc55f5af3379eaf54655273 100644 (file)
@@ -34,6 +34,8 @@ class Gdb(object):
         self.child = pexpect.spawn(path)
         self.child.logfile = file("gdb.log", "w")
         self.wait()
+        self.command("set width 0")
+        self.command("set height 0")
 
     def wait(self):
         """Wait for prompt."""