Implement register writes.
authorTim Newsome <tim@sifive.com>
Mon, 14 Mar 2016 18:54:29 +0000 (11:54 -0700)
committerTim Newsome <tim@sifive.com>
Mon, 23 May 2016 19:12:10 +0000 (12:12 -0700)
riscv/gdbserver.cc
riscv/gdbserver.h
tests/gdbserver-smoke.py
tests/testlib.py

index bc863130627ea6ced5784c13ac69d68eafd230d9..883ac055392a3ec4c1e3c60fa05d9878a8dda680 100644 (file)
@@ -299,11 +299,6 @@ void gdbserver_t::handle_general_registers_read(const std::vector<uint8_t> &pack
   //   "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",
 
   // Each byte of register data is described by two hex digits. The bytes with
   // the register are transmitted in target byte order. The size of each
@@ -321,6 +316,8 @@ void gdbserver_t::handle_general_registers_read(const std::vector<uint8_t> &pack
   expect_ack = true;
 }
 
+// First byte is the most-significant one.
+// Eg. "08675309" becomes 0x08675309.
 uint64_t consume_hex_number(std::vector<uint8_t>::const_iterator &iter,
     std::vector<uint8_t>::const_iterator end)
 {
@@ -338,6 +335,29 @@ uint64_t consume_hex_number(std::vector<uint8_t>::const_iterator &iter,
   return value;
 }
 
+// First byte is the least-significant one.
+// Eg. "08675309" becomes 0x09536708
+uint64_t consume_hex_number_le(std::vector<uint8_t>::const_iterator &iter,
+    std::vector<uint8_t>::const_iterator end)
+{
+  uint64_t value = 0;
+  unsigned int shift = 4;
+
+  while (iter != end) {
+    uint8_t c = *iter;
+    uint64_t c_value = character_hex_value(c);
+    if (c_value > 15)
+      break;
+    iter++;
+    value |= c_value << shift;
+    if ((shift % 8) == 0)
+      shift += 12;
+    else
+      shift -= 4;
+  }
+  return value;
+}
+
 void consume_string(std::string &str, std::vector<uint8_t>::const_iterator &iter,
     std::vector<uint8_t>::const_iterator end, uint8_t separator)
 {
@@ -473,6 +493,48 @@ void gdbserver_t::handle_register_read(const std::vector<uint8_t> &packet)
   expect_ack = true;
 }
 
+void gdbserver_t::handle_register_write(const std::vector<uint8_t> &packet)
+{
+  // P n...=r...
+
+  std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
+  unsigned int n = consume_hex_number(iter, packet.end());
+  if (*iter != '=')
+    return send_packet("E05");
+  iter++;
+
+  if (n >= sizeof(register_access) / sizeof(*register_access))
+    return send_packet("E07");
+
+  reg_t value = consume_hex_number_le(iter, packet.end());
+  if (*iter != '#')
+    return send_packet("E06");
+
+  processor_t *p = sim->get_core(0);
+
+  register_access_t access = register_access[n];
+  switch (access.clss) {
+    case RC_XPR:
+      p->state.XPR.write(access.index, value);
+      break;
+    case RC_PC:
+      p->state.pc = value;
+      break;
+    case RC_FPR:
+      p->state.FPR.write(access.index, value);
+      break;
+    case RC_CSR:
+      try {
+        p->set_csr(access.index, value);
+      } catch(trap_t& t) {
+        return send_packet("EFF");
+      }
+      break;
+  }
+
+  return send_packet("OK");
+}
+
 void gdbserver_t::handle_memory_read(const std::vector<uint8_t> &packet)
 {
   // m addr,length
@@ -693,6 +755,8 @@ void gdbserver_t::handle_packet(const std::vector<uint8_t> &packet)
       return handle_memory_binary_write(packet);
     case 'p':
       return handle_register_read(packet);
+    case 'P':
+      return handle_register_write(packet);
     case 'c':
       return handle_continue(packet);
     case 's':
index 8f52a92e9566a4ba9d151077ccc433753ebea82b..8a7111fbe6a6f7c9028f4b297886d01db67ce755 100644 (file)
@@ -77,6 +77,7 @@ public:
   void handle_memory_read(const std::vector<uint8_t> &packet);
   void handle_query(const std::vector<uint8_t> &packet);
   void handle_register_read(const std::vector<uint8_t> &packet);
+  void handle_register_write(const std::vector<uint8_t> &packet);
   void handle_step(const std::vector<uint8_t> &packet);
 
 private:
index 770e77ad1e9c6621642e00811efdb1092d4a996c..9d04915dcefea5f05e404057699e6bbd99c0a8f1 100755 (executable)
@@ -6,13 +6,12 @@ import unittest
 import tempfile
 import time
 
-class SmokeTest(unittest.TestCase):
+class DebugTest(unittest.TestCase):
     def setUp(self):
-        self.tmpf = tempfile.NamedTemporaryFile()
-        testlib.compile("debug.c", self.tmpf.name)
-        self.spike = testlib.spike(self.tmpf.name, halted=False)
+        self.binary = testlib.compile("debug.c")
+        self.spike = testlib.spike(self.binary, halted=False)
         self.gdb = testlib.Gdb()
-        self.gdb.command("file %s" % self.tmpf.name)
+        self.gdb.command("file %s" % self.binary)
         self.gdb.command("target extended-remote localhost:9824")
         self.gdb.command("p i=0");
 
@@ -62,5 +61,37 @@ class SmokeTest(unittest.TestCase):
             last_time = time
             self.gdb.command("stepi")
 
+class RegsTest(unittest.TestCase):
+    def setUp(self):
+        self.binary = testlib.compile("regs.s")
+        self.spike = testlib.spike(self.binary, halted=False)
+        self.gdb = testlib.Gdb()
+        self.gdb.command("file %s" % self.binary)
+        self.gdb.command("target extended-remote localhost:9824")
+
+    def tearDown(self):
+        self.spike.kill()
+        self.spike.wait()
+
+    def test_write_gprs(self):
+        # Note a0 is missing from this list since it's used to hold the
+        # address.
+        regs = ("ra", "sp", "gp", "tp", "t0", "t1", "t2", "fp", "s1",
+                "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4",
+                "s5", "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5",
+                "t6")
+
+        self.gdb.command("p $pc=write_regs")
+        for i, r in enumerate(regs):
+            self.gdb.command("p $%s=%d" % (r, i*0xdeadbeef+17))
+        self.gdb.command("p $a0=data")
+        self.gdb.command("b all_done")
+        output = self.gdb.command("c")
+        self.assertIn("Breakpoint 1", output)
+
+        for n in range(len(regs)):
+            self.assertEqual(self.gdb.x("data+%d" % (8*n), 'g'),
+                    n*0xdeadbeef+17)
+
 if __name__ == '__main__':
     unittest.main()
index 04acbfc32993fe703a7b48f9c2f8bcbbe2449a62..0c1713c846d39bea31f7a06d4bb4ae42403f3c13 100644 (file)
@@ -15,10 +15,15 @@ def find_file(path):
             return fullpath
     raise ValueError("Couldn't find %r." % path)
 
-def compile(src, dst):
+def compile(src):
     """Compile a single .c file into a binary."""
+    src = find_file(src)
+    dst = os.path.splitext(src)[0]
     cc = os.path.expandvars("$RISCV/bin/riscv64-unknown-elf-gcc")
-    return os.system("%s -g -o %s %s" % (cc, dst, find_file(src)))
+    cmd = "%s -g -o %s %s" % (cc, dst, src)
+    result = os.system(cmd)
+    assert result == 0, "%r failed" % cmd
+    return dst
 
 def spike(binary, halted=False):
     cmd = [find_file("spike")]
@@ -46,3 +51,8 @@ class Gdb(object):
         self.child.expect("\n")
         self.child.expect("\(gdb\)")
         return self.child.before.strip()
+
+    def x(self, address, size='w'):
+        output = self.command("x/%s %s" % (size, address))
+        value = int(output.split(':')[1].strip())
+        return value