aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--riscv/execute.cc21
-rw-r--r--riscv/gdbserver.cc60
-rw-r--r--riscv/gdbserver.h2
-rw-r--r--riscv/insns/dret.h3
-rw-r--r--riscv/processor.cc1
-rw-r--r--riscv/processor.h8
-rwxr-xr-xtests/gdbserver.py3
7 files changed, 76 insertions, 22 deletions
diff --git a/riscv/execute.cc b/riscv/execute.cc
index f67843e..8f7b85f 100644
--- a/riscv/execute.cc
+++ b/riscv/execute.cc
@@ -66,6 +66,10 @@ void processor_t::step(size_t n)
n = std::min(n, (size_t) 11);
}
+ if (debug) {
+ fprintf(stderr, "step(%ld)\n", n);
+ }
+
while (n > 0) {
size_t instret = 0;
reg_t pc = state.pc;
@@ -89,12 +93,25 @@ void processor_t::step(size_t n)
{
take_interrupt();
- if (unlikely(debug))
+ // When we might single step, use the slow loop instead of the fast one.
+ if (unlikely(debug || state.single_step != state.STEP_NONE || state.dcsr.cause))
{
while (instret < n)
{
+ // TODO: implement this for the main loop also. To keep
+ // performance good, probably go into this version when entering
+ // debug mode or something.
+ if (unlikely(state.single_step == state.STEP_STEPPING)) {
+ state.single_step = state.STEP_STEPPED;
+ } else if (unlikely(state.single_step == state.STEP_STEPPED)) {
+ state.single_step = state.STEP_NONE;
+ enter_debug_mode(DCSR_CAUSE_STEP);
+ // enter_debug_mode changed state.pc, so we can't just continue.
+ break;
+ }
+
insn_fetch_t fetch = mmu->load_insn(pc);
- if (!state.serialized)
+ if (debug && !state.serialized)
disasm(fetch.insn);
pc = execute_insn(this, pc, fetch);
advance_pc();
diff --git a/riscv/gdbserver.cc b/riscv/gdbserver.cc
index 0cccf3d..b181e27 100644
--- a/riscv/gdbserver.cc
+++ b/riscv/gdbserver.cc
@@ -66,13 +66,13 @@ static uint32_t jal(unsigned int rd, uint32_t imm) {
MATCH_JAL;
}
-static uint32_t csrsi(unsigned int csr, uint8_t imm) {
+static uint32_t csrsi(unsigned int csr, uint16_t imm) {
return (csr << 20) |
(bits(imm, 4, 0) << 15) |
MATCH_CSRRSI;
}
-static uint32_t csrci(unsigned int csr, uint8_t imm) {
+static uint32_t csrci(unsigned int csr, uint16_t imm) {
return (csr << 20) |
(bits(imm, 4, 0) << 15) |
MATCH_CSRRCI;
@@ -320,7 +320,8 @@ class halt_op_t : public operation_t
class continue_op_t : public operation_t
{
public:
- continue_op_t(gdbserver_t& gdbserver) : operation_t(gdbserver) {};
+ continue_op_t(gdbserver_t& gdbserver, bool single_step) :
+ operation_t(gdbserver), single_step(single_step) {};
bool perform_step(unsigned int step) {
switch (step) {
@@ -352,17 +353,29 @@ class continue_op_t : public operation_t
return false;
case 3:
- gs.write_debug_ram(0, ld(S0, 0, (uint16_t) DEBUG_RAM_START+16));
+ gs.write_debug_ram(0, ld(S0, 0, (uint16_t) DEBUG_RAM_START+24));
gs.write_debug_ram(1, csrw(S0, CSR_MCAUSE));
- gs.write_debug_ram(2, csrci(DCSR_ADDRESS, DCSR_HALT_MASK));
- gs.write_debug_ram(3, jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*3))));
- gs.write_debug_ram(4, gs.saved_mcause);
- gs.write_debug_ram(5, gs.saved_mcause >> 32);
+ gs.write_debug_ram(2, lw(S0, 0, (uint16_t) DEBUG_RAM_START+20));
+ gs.write_debug_ram(3, csrw(S0, CSR_DCSR));
+ gs.write_debug_ram(4, jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*4))));
+
+ reg_t dcsr = gs.dcsr & ~DCSR_HALT_MASK;
+ if (single_step)
+ dcsr |= DCSR_STEP_MASK;
+ else
+ dcsr &= ~DCSR_STEP_MASK;
+ gs.write_debug_ram(5, dcsr);
+
+ gs.write_debug_ram(6, gs.saved_mcause);
+ gs.write_debug_ram(7, gs.saved_mcause >> 32);
gs.set_interrupt(0);
return true;
}
return false;
}
+
+ private:
+ bool single_step;
};
class general_registers_read_op_t : public operation_t
@@ -534,12 +547,15 @@ class memory_read_op_t : public operation_t
for (unsigned int i = 0; i < access_size; i++) {
if (data) {
*(data++) = value & 0xff;
+ fprintf(stderr, "%02x", (unsigned int) (value & 0xff));
} else {
sprintf(buffer, "%02x", (unsigned int) (value & 0xff));
gs.send(buffer);
}
value >>= 8;
}
+ if (data)
+ fprintf(stderr, "\n");
length -= access_size;
paddr += access_size;
@@ -568,7 +584,7 @@ class memory_write_op_t : public operation_t
{
public:
memory_write_op_t(gdbserver_t& gdbserver, reg_t vaddr, unsigned int length,
- unsigned char *data) :
+ const unsigned char *data) :
operation_t(gdbserver), vaddr(vaddr), offset(0), length(length), data(data) {};
~memory_write_op_t() {
@@ -584,6 +600,11 @@ class memory_write_op_t : public operation_t
if (access_size == 0)
access_size = length;
+ fprintf(stderr, "write to 0x%lx -> 0x%lx: ", vaddr, paddr);
+ for (unsigned int i = 0; i < length; i++)
+ fprintf(stderr, "%02x", data[i]);
+ fprintf(stderr, "\n");
+
gs.write_debug_ram(0, ld(S0, 0, (uint16_t) DEBUG_RAM_START + 16));
switch (access_size) {
case 1:
@@ -661,7 +682,7 @@ class memory_write_op_t : public operation_t
unsigned int offset;
unsigned int length;
unsigned int access_size;
- unsigned char *data;
+ const unsigned char *data;
};
class collect_translation_info_op_t : public operation_t
@@ -1267,7 +1288,7 @@ void gdbserver_t::handle_continue(const std::vector<uint8_t> &packet)
return send_packet("E30");
}
- add_operation(new continue_op_t(*this));
+ add_operation(new continue_op_t(*this, false));
}
void gdbserver_t::handle_step(const std::vector<uint8_t> &packet)
@@ -1281,8 +1302,7 @@ void gdbserver_t::handle_step(const std::vector<uint8_t> &packet)
return send_packet("E40");
}
- // TODO: p->set_single_step(true);
- // TODO running = true;
+ add_operation(new continue_op_t(*this, true));
}
void gdbserver_t::handle_kill(const std::vector<uint8_t> &packet)
@@ -1340,16 +1360,20 @@ void gdbserver_t::handle_breakpoint(const std::vector<uint8_t> &packet)
swbp[3] = (EBREAK >> 24) & 0xff;
}
- add_operation(new memory_read_op_t(*this, bp.address, bp.size, bp.instruction));
+ breakpoints[bp.address] = new software_breakpoint_t(bp);
+ add_operation(new memory_read_op_t(*this, bp.address, bp.size,
+ breakpoints[bp.address]->instruction));
add_operation(new memory_write_op_t(*this, bp.address, bp.size, swbp));
- breakpoints[bp.address] = bp;
} else {
- bp = breakpoints[bp.address];
+ software_breakpoint_t *found_bp;
+ found_bp = breakpoints[bp.address];
unsigned char* instruction = new unsigned char[4];
- memcpy(instruction, bp.instruction, 4);
- add_operation(new memory_write_op_t(*this, bp.address, bp.size, instruction));
+ memcpy(instruction, found_bp->instruction, 4);
+ add_operation(new memory_write_op_t(*this, found_bp->address,
+ found_bp->size, instruction));
breakpoints.erase(bp.address);
+ delete found_bp;
}
// TODO mmu->flush_icache();
diff --git a/riscv/gdbserver.h b/riscv/gdbserver.h
index f91498a..2ab2ffe 100644
--- a/riscv/gdbserver.h
+++ b/riscv/gdbserver.h
@@ -166,7 +166,7 @@ private:
// but it isn't, we need to tell gdb about it.
bool running;
- std::map <reg_t, software_breakpoint_t> breakpoints;
+ std::map <reg_t, software_breakpoint_t*> breakpoints;
// Read pending data from the client.
void read();
diff --git a/riscv/insns/dret.h b/riscv/insns/dret.h
index 6cfd1e2..35c19cb 100644
--- a/riscv/insns/dret.h
+++ b/riscv/insns/dret.h
@@ -4,3 +4,6 @@ p->set_privilege(STATE.dcsr.prv);
/* We're not in Debug Mode anymore. */
STATE.dcsr.cause = 0;
+
+if (STATE.dcsr.step)
+ STATE.single_step = STATE.STEP_STEPPING;
diff --git a/riscv/processor.cc b/riscv/processor.cc
index d43defc..4c4e3dd 100644
--- a/riscv/processor.cc
+++ b/riscv/processor.cc
@@ -279,6 +279,7 @@ static bool validate_vm(int max_xlen, reg_t vm)
void processor_t::set_csr(int which, reg_t val)
{
+ fprintf(stderr, "set_csr(0x%x, 0x%lx)\n", which, val);
val = zext_xlen(val);
reg_t delegable_ints = MIP_SSIP | MIP_STIP | MIP_SEIP | (1 << IRQ_COP);
reg_t all_ints = delegable_ints | MIP_MSIP | MIP_MTIP;
diff --git a/riscv/processor.h b/riscv/processor.h
index 9c2f7a6..721da2c 100644
--- a/riscv/processor.h
+++ b/riscv/processor.h
@@ -81,6 +81,14 @@ struct state_t
uint32_t frm;
bool serialized; // whether timer CSRs are in a well-defined state
+ // When true, execute a single instruction and then enter debug mode. This
+ // can only be set by executing dret.
+ enum {
+ STEP_NONE,
+ STEP_STEPPING,
+ STEP_STEPPED
+ } single_step;
+
reg_t load_reservation;
#ifdef RISCV_ENABLE_COMMITLOG
diff --git a/tests/gdbserver.py b/tests/gdbserver.py
index 90ebbe9..c3c2eca 100755
--- a/tests/gdbserver.py
+++ b/tests/gdbserver.py
@@ -36,9 +36,10 @@ class DebugTest(unittest.TestCase):
def test_breakpoint(self):
self.gdb.command("b print_row")
# The breakpoint should be hit exactly 10 times.
- for _ in range(10):
+ for i in range(10):
output = self.gdb.command("c")
self.assertIn("Continuing", output)
+ self.assertIn("length=%d" % i, output)
self.assertIn("Breakpoint 1", output)
output = self.gdb.command("c")
self.assertIn("Continuing", output)