Browse Source

Implement reading of CSRs.

pull/39/head
Tim Newsome 10 years ago
parent
commit
64f7d791b7
  1. 137
      riscv/gdbserver.cc
  2. 18
      tests/gdbserver-smoke.py
  3. 2
      tests/testlib.py

137
riscv/gdbserver.cc

@ -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("");
}

18
tests/gdbserver-smoke.py

@ -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()

2
tests/testlib.py

@ -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."""

Loading…
Cancel
Save