From daa39a220492433a138ce359f2afcf91f2ff48b6 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 14 Mar 2016 11:54:29 -0700 Subject: [PATCH] Implement register writes. --- riscv/gdbserver.cc | 74 +++++++++++++++++++++++++++++++++++++--- riscv/gdbserver.h | 1 + tests/gdbserver-smoke.py | 41 +++++++++++++++++++--- tests/testlib.py | 14 ++++++-- 4 files changed, 118 insertions(+), 12 deletions(-) diff --git a/riscv/gdbserver.cc b/riscv/gdbserver.cc index bc86313..883ac05 100644 --- a/riscv/gdbserver.cc +++ b/riscv/gdbserver.cc @@ -299,11 +299,6 @@ void gdbserver_t::handle_general_registers_read(const std::vector &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 &pack expect_ack = true; } +// First byte is the most-significant one. +// Eg. "08675309" becomes 0x08675309. uint64_t consume_hex_number(std::vector::const_iterator &iter, std::vector::const_iterator end) { @@ -338,6 +335,29 @@ uint64_t consume_hex_number(std::vector::const_iterator &iter, return value; } +// First byte is the least-significant one. +// Eg. "08675309" becomes 0x09536708 +uint64_t consume_hex_number_le(std::vector::const_iterator &iter, + std::vector::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::const_iterator &iter, std::vector::const_iterator end, uint8_t separator) { @@ -473,6 +493,48 @@ void gdbserver_t::handle_register_read(const std::vector &packet) expect_ack = true; } +void gdbserver_t::handle_register_write(const std::vector &packet) +{ + // P n...=r... + + std::vector::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 &packet) { // m addr,length @@ -693,6 +755,8 @@ void gdbserver_t::handle_packet(const std::vector &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': diff --git a/riscv/gdbserver.h b/riscv/gdbserver.h index 8f52a92..8a7111f 100644 --- a/riscv/gdbserver.h +++ b/riscv/gdbserver.h @@ -77,6 +77,7 @@ public: void handle_memory_read(const std::vector &packet); void handle_query(const std::vector &packet); void handle_register_read(const std::vector &packet); + void handle_register_write(const std::vector &packet); void handle_step(const std::vector &packet); private: diff --git a/tests/gdbserver-smoke.py b/tests/gdbserver-smoke.py index 770e77a..9d04915 100755 --- a/tests/gdbserver-smoke.py +++ b/tests/gdbserver-smoke.py @@ -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() diff --git a/tests/testlib.py b/tests/testlib.py index 04acbfc..0c1713c 100644 --- a/tests/testlib.py +++ b/tests/testlib.py @@ -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 -- 2.30.2