Single step appears to work.
authorTim Newsome <tim@sifive.com>
Thu, 5 May 2016 01:51:26 +0000 (18:51 -0700)
committerTim Newsome <tim@sifive.com>
Mon, 23 May 2016 19:12:12 +0000 (12:12 -0700)
riscv/execute.cc
riscv/gdbserver.cc
riscv/gdbserver.h
riscv/insns/dret.h
riscv/processor.cc
riscv/processor.h
tests/gdbserver.py

index f67843eedd48b52e8ba661ac37e1acb1b108eafa..8f7b85f747946eb0fc698257c8d722190d0ace61 100644 (file)
@@ -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();
index 0cccf3df0467d7d369df477dc2bbc9c5eff6282e..b181e27a31fd47860e10a8d7da707cc099cbf58c 100644 (file)
@@ -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();
index f91498ab9e3fa6f9d4cc131527ef0e7e5eacd5c3..2ab2ffe0f96776750e0b7e8e6c018bf1ae13753e 100644 (file)
@@ -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();
index 6cfd1e2660496c2bf137bb64188ad78b7b84a346..35c19cb8a29090b774ff8c7a1fa091aa36428e21 100644 (file)
@@ -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;
index d43defc81c48d468303085f5ce118ab206880160..4c4e3dd110ee5f352895e7ee34667e5b9c3765c4 100644 (file)
@@ -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;
index 9c2f7a66aa1da730fc72bcabeb54c983bbc1c831..721da2cb54fdb53f0611e6e6b97097bbefdb38f4 100644 (file)
@@ -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
index 90ebbe91115fb5e161e20ab672ce0ba4866782c7..c3c2ecad016241087e6e6bb3bb51e0cacefbcaca 100755 (executable)
@@ -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)