Merge remote-tracking branch 'origin/priv-1.10' into HEAD
authorMegan Wachs <megan@sifive.com>
Mon, 17 Apr 2017 17:59:38 +0000 (10:59 -0700)
committerMegan Wachs <megan@sifive.com>
Mon, 17 Apr 2017 17:59:38 +0000 (10:59 -0700)
20 files changed:
remote_bitbang.cc [new file with mode: 0644]
remote_bitbang.h [new file with mode: 0644]
riscv/debug_defines.h [new file with mode: 0644]
riscv/debug_module.cc
riscv/debug_module.h
riscv/decode.h
riscv/execute.cc
riscv/gdbserver.cc [deleted file]
riscv/gdbserver.h [deleted file]
riscv/jtag_dtm.cc [new file with mode: 0644]
riscv/jtag_dtm.h [new file with mode: 0644]
riscv/opcodes.h [new file with mode: 0644]
riscv/processor.cc
riscv/processor.h
riscv/remote_bitbang.cc [new file with mode: 0644]
riscv/remote_bitbang.h [new file with mode: 0644]
riscv/riscv.mk.in
riscv/sim.cc
riscv/sim.h
spike_main/spike.cc

diff --git a/remote_bitbang.cc b/remote_bitbang.cc
new file mode 100644 (file)
index 0000000..9d0ca90
--- /dev/null
@@ -0,0 +1,174 @@
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <cassert>
+#include <cstdio>
+
+#include "remote_bitbang.h"
+
+#if 1
+#  define D(x) x
+#else
+#  define D(x)
+#endif
+
+/////////// remote_bitbang_t
+
+remote_bitbang_t::remote_bitbang_t(uint16_t port, jtag_dtm_t *tap) :
+  tap(tap),
+  socket_fd(0),
+  client_fd(0),
+  recv_start(0),
+  recv_end(0)
+{
+  socket_fd = socket(AF_INET, SOCK_STREAM, 0);
+  if (socket_fd == -1) {
+    fprintf(stderr, "remote_bitbang failed to make socket: %s (%d)\n",
+        strerror(errno), errno);
+    abort();
+  }
+
+  fcntl(socket_fd, F_SETFL, O_NONBLOCK);
+  int reuseaddr = 1;
+  if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
+        sizeof(int)) == -1) {
+    fprintf(stderr, "remote_bitbang failed setsockopt: %s (%d)\n",
+        strerror(errno), errno);
+    abort();
+  }
+
+  struct sockaddr_in addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = INADDR_ANY;
+  addr.sin_port = htons(port);
+
+  if (bind(socket_fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
+    fprintf(stderr, "remote_bitbang failed to bind socket: %s (%d)\n",
+        strerror(errno), errno);
+    abort();
+  }
+
+  if (listen(socket_fd, 1) == -1) {
+    fprintf(stderr, "remote_bitbang failed to listen on socket: %s (%d)\n",
+        strerror(errno), errno);
+    abort();
+  }
+
+  socklen_t addrlen = sizeof(addr);
+  if (getsockname(socket_fd, (struct sockaddr *) &addr, &addrlen) == -1) {
+    fprintf(stderr, "remote_bitbang getsockname failed: %s (%d)\n",
+        strerror(errno), errno);
+    abort();
+  }
+
+  printf("Listening for remote bitbang connection on port %d.\n",
+      ntohs(addr.sin_port));
+  fflush(stdout);
+}
+
+void remote_bitbang_t::accept()
+{
+  client_fd = ::accept(socket_fd, NULL, NULL);
+  if (client_fd == -1) {
+    if (errno == EAGAIN) {
+      // No client waiting to connect right now.
+    } else {
+      fprintf(stderr, "failed to accept on socket: %s (%d)\n", strerror(errno),
+          errno);
+      abort();
+    }
+  } else {
+    fcntl(client_fd, F_SETFL, O_NONBLOCK);
+  }
+}
+
+void remote_bitbang_t::tick()
+{
+  if (client_fd > 0) {
+    execute_commands();
+  } else {
+    this->accept();
+  }
+}
+
+void remote_bitbang_t::execute_commands()
+{
+  static char send_buf[buf_size];
+  unsigned total_processed = 0;
+  bool quit = false;
+  bool in_rti = tap->state() == RUN_TEST_IDLE;
+  bool entered_rti = false;
+  while (1) {
+    if (recv_start < recv_end) {
+      unsigned send_offset = 0;
+      while (recv_start < recv_end) {
+        uint8_t command = recv_buf[recv_start];
+
+        switch (command) {
+          case 'B': /* fprintf(stderr, "*BLINK*\n"); */ break;
+          case 'b': /* fprintf(stderr, "_______\n"); */ break;
+          case 'r': tap->reset(); break;
+          case '0': tap->set_pins(0, 0, 0); break;
+          case '1': tap->set_pins(0, 0, 1); break;
+          case '2': tap->set_pins(0, 1, 0); break;
+          case '3': tap->set_pins(0, 1, 1); break;
+          case '4': tap->set_pins(1, 0, 0); break;
+          case '5': tap->set_pins(1, 0, 1); break;
+          case '6': tap->set_pins(1, 1, 0); break;
+          case '7': tap->set_pins(1, 1, 1); break;
+          case 'R': send_buf[send_offset++] = tap->tdo() ? '1' : '0'; break;
+          case 'Q': quit = true; break;
+          default:
+                    fprintf(stderr, "remote_bitbang got unsupported command '%c'\n",
+                        command);
+        }
+        recv_start++;
+        total_processed++;
+        if (!in_rti && tap->state() == RUN_TEST_IDLE) {
+          entered_rti = true;
+          break;
+        }
+        in_rti = false;
+      }
+      unsigned sent = 0;
+      while (sent < send_offset) {
+        ssize_t bytes = write(client_fd, send_buf + sent, send_offset);
+        if (bytes == -1) {
+          fprintf(stderr, "failed to write to socket: %s (%d)\n", strerror(errno), errno);
+          abort();
+        }
+        sent += bytes;
+      }
+    }
+
+    if (total_processed > buf_size || quit || entered_rti) {
+      // Don't go forever, because that could starve the main simulation.
+      break;
+    }
+
+    recv_start = 0;
+    recv_end = read(client_fd, recv_buf, buf_size);
+
+    if (recv_end == -1) {
+      if (errno == EAGAIN) {
+        // We'll try again the next call.
+      } else {
+        fprintf(stderr, "remote_bitbang failed to read on socket: %s (%d)\n",
+            strerror(errno), errno);
+        abort();
+      }
+    }
+    if (recv_end == 0 || quit) {
+      // The remote disconnected.
+      close(client_fd);
+      client_fd = 0;
+      break;
+    }
+  }
+}
diff --git a/remote_bitbang.h b/remote_bitbang.h
new file mode 100644 (file)
index 0000000..1db4d55
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef REMOTE_BITBANG_H
+#define REMOTE_BITBANG_H
+
+#include <stdint.h>
+
+#include "jtag_dtm.h"
+
+class remote_bitbang_t
+{
+public:
+  // Create a new server, listening for connections from localhost on the given
+  // port.
+  remote_bitbang_t(uint16_t port, jtag_dtm_t *tap);
+
+  // Do a bit of work.
+  void tick();
+
+private:
+  jtag_dtm_t *tap;
+
+  int socket_fd;
+  int client_fd;
+
+  static const ssize_t buf_size = 64 * 1024;
+  char recv_buf[buf_size];
+  ssize_t recv_start, recv_end;
+
+  // Check for a client connecting, and accept if there is one.
+  void accept();
+  // Execute any commands the client has for us.
+  void execute_commands();
+};
+
+#endif
diff --git a/riscv/debug_defines.h b/riscv/debug_defines.h
new file mode 100644 (file)
index 0000000..ec535db
--- /dev/null
@@ -0,0 +1,1501 @@
+#define DTM_IDCODE                          0x01
+/*
+* Identifies the release version of this part.
+ */
+#define DTM_IDCODE_VERSION_OFFSET           28
+#define DTM_IDCODE_VERSION_LENGTH           4
+#define DTM_IDCODE_VERSION                  (0xf << DTM_IDCODE_VERSION_OFFSET)
+/*
+* Identifies the designer's part number of this part.
+ */
+#define DTM_IDCODE_PARTNUMBER_OFFSET        12
+#define DTM_IDCODE_PARTNUMBER_LENGTH        16
+#define DTM_IDCODE_PARTNUMBER               (0xffff << DTM_IDCODE_PARTNUMBER_OFFSET)
+/*
+* Identifies the designer/manufacturer of this part. Bits 6:0 must be
+* bits 6:0 of the designer/manufacturer's Identification Code as
+* assigned by JEDEC Standard JEP106. Bits 10:7 contain the modulo-16
+* count of the number of continuation characters (0x7f) in that same
+* Identification Code.
+ */
+#define DTM_IDCODE_MANUFID_OFFSET           1
+#define DTM_IDCODE_MANUFID_LENGTH           11
+#define DTM_IDCODE_MANUFID                  (0x7ff << DTM_IDCODE_MANUFID_OFFSET)
+#define DTM_IDCODE_1_OFFSET                 0
+#define DTM_IDCODE_1_LENGTH                 1
+#define DTM_IDCODE_1                        (0x1 << DTM_IDCODE_1_OFFSET)
+#define DTM_DTMCS                           0x10
+/*
+* Writing 1 to this bit resets the DMI controller, clearing any
+* sticky error state.
+ */
+#define DTM_DTMCS_DMIRESET_OFFSET           16
+#define DTM_DTMCS_DMIRESET_LENGTH           1
+#define DTM_DTMCS_DMIRESET                  (0x1 << DTM_DTMCS_DMIRESET_OFFSET)
+/*
+* This is the minimum number of cycles a debugger should spend in
+* Run-Test/Idle after every DMI scan to avoid a 'busy'
+* return code (\Fdmistat of 3). A debugger must still
+* check \Fdmistat when necessary.
+*
+* 0: It is not necessary to enter Run-Test/Idle at all.
+*
+* 1: Enter Run-Test/Idle and leave it immediately.
+*
+* 2: Enter Run-Test/Idle and stay there for 1 cycle before leaving.
+*
+* And so on.
+ */
+#define DTM_DTMCS_IDLE_OFFSET               12
+#define DTM_DTMCS_IDLE_LENGTH               3
+#define DTM_DTMCS_IDLE                      (0x7 << DTM_DTMCS_IDLE_OFFSET)
+/*
+* 0: No error.
+*
+* 1: Reserved. Interpret the same as 2.
+*
+* 2: An operation failed (resulted in \Fop of 2).
+*
+* 3: An operation was attempted while a DMI access was still in
+* progress (resulted in \Fop of 3).
+ */
+#define DTM_DTMCS_DMISTAT_OFFSET            10
+#define DTM_DTMCS_DMISTAT_LENGTH            2
+#define DTM_DTMCS_DMISTAT                   (0x3 << DTM_DTMCS_DMISTAT_OFFSET)
+/*
+* The size of \Faddress in \Rdmi.
+ */
+#define DTM_DTMCS_ABITS_OFFSET              4
+#define DTM_DTMCS_ABITS_LENGTH              6
+#define DTM_DTMCS_ABITS                     (0x3f << DTM_DTMCS_ABITS_OFFSET)
+/*
+* 0: Version described in spec version 0.11.
+*
+* 1: Version described in spec version 0.12 (and later?), which
+* reduces the DMI data width to 32 bits.
+*
+* Other values are reserved for future use.
+ */
+#define DTM_DTMCS_VERSION_OFFSET            0
+#define DTM_DTMCS_VERSION_LENGTH            4
+#define DTM_DTMCS_VERSION                   (0xf << DTM_DTMCS_VERSION_OFFSET)
+#define DTM_DMI                             0x11
+/*
+* Address used for DMI access. In Update-DR this value is used
+* to access the DM over the DMI.
+ */
+#define DTM_DMI_ADDRESS_OFFSET              34
+#define DTM_DMI_ADDRESS_LENGTH              abits
+#define DTM_DMI_ADDRESS                     (((1L<<abits)-1) << DTM_DMI_ADDRESS_OFFSET)
+/*
+* The data to send to the DM over the DMI during Update-DR, and
+* the data returned from the DM as a result of the previous operation.
+ */
+#define DTM_DMI_DATA_OFFSET                 2
+#define DTM_DMI_DATA_LENGTH                 32
+#define DTM_DMI_DATA                        (0xffffffffL << DTM_DMI_DATA_OFFSET)
+/*
+* When the debugger writes this field, it has the following meaning:
+*
+* 0: Ignore \Fdata. (nop)
+*
+* 1: Read from \Faddress. (read)
+*
+* 2: Write \Fdata to \Faddress. (write)
+*
+* 3: Reserved.
+*
+* When the debugger reads this field, it means the following:
+*
+* 0: The previous operation completed successfully.
+*
+* 1: Reserved.
+*
+* 2: A previous operation failed.  The data scanned into \Rdmi in
+* this access will be ignored.  This status is sticky and can be
+* cleared by writing \Fdmireset in \Rdtmcs.
+*
+* This indicates that the DM itself responded with an error, e.g.
+* in the System Bus and Serial Port overflow/underflow cases.
+*
+* 3: An operation was attempted while a DMI request is still in
+* progress. The data scanned into \Rdmi in this access will be
+* ignored. This status is sticky and can be cleared by writing
+* \Fdmireset in \Rdtmcs. If a debugger sees this status, it
+* needs to give the target more TCK edges between Update-DR and
+* Capture-DR. The simplest way to do that is to add extra transitions
+* in Run-Test/Idle.
+*
+* (The DTM, DM, and/or component may be in different clock domains,
+* so synchronization may be required. Some relatively fixed number of
+* TCK ticks may be needed for the request to reach the DM, complete,
+* and for the response to be synchronized back into the TCK domain.)
+ */
+#define DTM_DMI_OP_OFFSET                   0
+#define DTM_DMI_OP_LENGTH                   2
+#define DTM_DMI_OP                          (0x3L << DTM_DMI_OP_OFFSET)
+#define CSR_DCSR                            0x7b0
+/*
+* 0: There is no external debug support.
+*
+* 1: External debug support exists as it is described in this document.
+*
+* Other values are reserved for future standards.
+ */
+#define CSR_DCSR_XDEBUGVER_OFFSET           30
+#define CSR_DCSR_XDEBUGVER_LENGTH           2
+#define CSR_DCSR_XDEBUGVER                  (0x3 << CSR_DCSR_XDEBUGVER_OFFSET)
+/*
+* When 1, {\tt ebreak} instructions in Machine Mode enter Halt Mode.
+ */
+#define CSR_DCSR_EBREAKM_OFFSET             15
+#define CSR_DCSR_EBREAKM_LENGTH             1
+#define CSR_DCSR_EBREAKM                    (0x1 << CSR_DCSR_EBREAKM_OFFSET)
+/*
+* When 1, {\tt ebreak} instructions in Hypervisor Mode enter Halt Mode.
+ */
+#define CSR_DCSR_EBREAKH_OFFSET             14
+#define CSR_DCSR_EBREAKH_LENGTH             1
+#define CSR_DCSR_EBREAKH                    (0x1 << CSR_DCSR_EBREAKH_OFFSET)
+/*
+* When 1, {\tt ebreak} instructions in Supervisor Mode enter Halt Mode.
+ */
+#define CSR_DCSR_EBREAKS_OFFSET             13
+#define CSR_DCSR_EBREAKS_LENGTH             1
+#define CSR_DCSR_EBREAKS                    (0x1 << CSR_DCSR_EBREAKS_OFFSET)
+/*
+* When 1, {\tt ebreak} instructions in User/Application Mode enter
+* Halt Mode.
+ */
+#define CSR_DCSR_EBREAKU_OFFSET             12
+#define CSR_DCSR_EBREAKU_LENGTH             1
+#define CSR_DCSR_EBREAKU                    (0x1 << CSR_DCSR_EBREAKU_OFFSET)
+/*
+* 0: Increment counters as usual.
+*
+* 1: Don't increment any counters while in Halt Mode.  This includes
+* the {\tt cycle} and {\tt instret} CSRs. This is preferred for most
+* debugging scenarios.
+*
+* An implementation may choose not to support writing to this bit.
+* The debugger must read back the value it writes to check whether
+* the feature is supported.
+ */
+#define CSR_DCSR_STOPCOUNT_OFFSET           10
+#define CSR_DCSR_STOPCOUNT_LENGTH           1
+#define CSR_DCSR_STOPCOUNT                  (0x1 << CSR_DCSR_STOPCOUNT_OFFSET)
+/*
+* 0: Increment timers as usual.
+*
+* 1: Don't increment any hart-local timers while in Halt Mode.
+*
+* An implementation may choose not to support writing to this bit.
+* The debugger must read back the value it writes to check whether
+* the feature is supported.
+ */
+#define CSR_DCSR_STOPTIME_OFFSET            9
+#define CSR_DCSR_STOPTIME_LENGTH            1
+#define CSR_DCSR_STOPTIME                   (0x1 << CSR_DCSR_STOPTIME_OFFSET)
+/*
+* Explains why Halt Mode was entered.
+*
+* When there are multiple reasons to enter Halt Mode in a single
+* cycle, the cause with the highest priority is the one written.
+*
+* 1: A software breakpoint was hit. (priority 3)
+*
+* 2: The Trigger Module caused a halt. (priority 4)
+*
+* 3: The debug interrupt was asserted by the Debug Module. (priority 2)
+*
+* 4: The hart single stepped because \Fstep was set. (priority 1)
+*
+* 5: \Fhaltreq was set. (priority 0)
+*
+* Other values are reserved for future use.
+ */
+#define CSR_DCSR_CAUSE_OFFSET               6
+#define CSR_DCSR_CAUSE_LENGTH               3
+#define CSR_DCSR_CAUSE                      (0x7 << CSR_DCSR_CAUSE_OFFSET)
+/*
+* When set and not in Halt Mode, the hart will only execute a single
+* instruction, and then enter Halt Mode. Interrupts are disabled
+* when this bit is set.
+ */
+#define CSR_DCSR_STEP_OFFSET                2
+#define CSR_DCSR_STEP_LENGTH                1
+#define CSR_DCSR_STEP                       (0x1 << CSR_DCSR_STEP_OFFSET)
+/*
+* Contains the privilege level the hart was operating in when Debug
+* Mode was entered. The encoding is describe in Table
+* \ref{tab:privlevel}.  A debugger can change this value to change
+* the hart's privilege level when exiting Halt Mode.
+*
+* Not all privilege levels are supported on all harts. If the
+* encoding written is not supported or the debugger is not allowed to
+* change to it, the hart may change to any supported privilege level.
+ */
+#define CSR_DCSR_PRV_OFFSET                 0
+#define CSR_DCSR_PRV_LENGTH                 2
+#define CSR_DCSR_PRV                        (0x3 << CSR_DCSR_PRV_OFFSET)
+#define CSR_DPC                             0x7b1
+#define CSR_DPC_DPC_OFFSET                  0
+#define CSR_DPC_DPC_LENGTH                  XLEN
+#define CSR_DPC_DPC                         (((1L<<XLEN)-1) << CSR_DPC_DPC_OFFSET)
+#define CSR_DSCRATCH0                       0x7b2
+#define CSR_DSCRATCH1                       0x7b3
+#define CSR_PRIV                            virtual
+/*
+* Contains the privilege level the hart was operating in when Debug
+* Mode was entered. The encoding is describe in Table
+* \ref{tab:privlevel}. A user can write this value to change the
+* hart's privilege level when exiting Halt Mode.
+ */
+#define CSR_PRIV_PRV_OFFSET                 0
+#define CSR_PRIV_PRV_LENGTH                 2
+#define CSR_PRIV_PRV                        (0x3 << CSR_PRIV_PRV_OFFSET)
+#define CSR_TSELECT                         0x7a0
+#define CSR_TSELECT_INDEX_OFFSET            0
+#define CSR_TSELECT_INDEX_LENGTH            XLEN
+#define CSR_TSELECT_INDEX                   (((1L<<XLEN)-1) << CSR_TSELECT_INDEX_OFFSET)
+#define CSR_TDATA1                          0x7a1
+/*
+* 0: There is no trigger at this \Rtselect.
+*
+* 1: The trigger is a legacy SiFive address match trigger. These
+* should not be implemented and aren't further documented here.
+*
+* 2: The trigger is an address/data match trigger. The remaining bits
+* in this register act as described in \Rmcontrol.
+*
+* 3: The trigger is an instruction count trigger. The remaining bits
+* in this register act as described in \Ricount.
+*
+* 15: This trigger exists (so enumeration shouldn't terminate), but
+* is not currently available.
+*
+* Other values are reserved for future use.
+ */
+#define CSR_TDATA1_TYPE_OFFSET              XLEN-4
+#define CSR_TDATA1_TYPE_LENGTH              4
+#define CSR_TDATA1_TYPE                     (0xfL << CSR_TDATA1_TYPE_OFFSET)
+/*
+* 0: Both Debug and M Mode can write the {\tt tdata} registers at the
+* selected \Rtselect.
+*
+* 1: Only Halt Mode can write the {\tt tdata} registers at the
+* selected \Rtselect.  Writes from other modes are ignored.
+*
+* This bit is only writable from Halt Mode.
+ */
+#define CSR_TDATA1_HMODE_OFFSET             XLEN-5
+#define CSR_TDATA1_HMODE_LENGTH             1
+#define CSR_TDATA1_HMODE                    (0x1L << CSR_TDATA1_HMODE_OFFSET)
+/*
+* Trigger-specific data.
+ */
+#define CSR_TDATA1_DATA_OFFSET              0
+#define CSR_TDATA1_DATA_LENGTH              XLEN - 5
+#define CSR_TDATA1_DATA                     (((1L<<XLEN - 5)-1) << CSR_TDATA1_DATA_OFFSET)
+#define CSR_TDATA2                          0x7a2
+#define CSR_TDATA2_DATA_OFFSET              0
+#define CSR_TDATA2_DATA_LENGTH              XLEN
+#define CSR_TDATA2_DATA                     (((1L<<XLEN)-1) << CSR_TDATA2_DATA_OFFSET)
+#define CSR_TDATA3                          0x7a3
+#define CSR_TDATA3_DATA_OFFSET              0
+#define CSR_TDATA3_DATA_LENGTH              XLEN
+#define CSR_TDATA3_DATA                     (((1L<<XLEN)-1) << CSR_TDATA3_DATA_OFFSET)
+#define CSR_MCONTROL                        0x7a1
+#define CSR_MCONTROL_TYPE_OFFSET            XLEN-4
+#define CSR_MCONTROL_TYPE_LENGTH            4
+#define CSR_MCONTROL_TYPE                   (0xfL << CSR_MCONTROL_TYPE_OFFSET)
+#define CSR_MCONTROL_DMODE_OFFSET           XLEN-5
+#define CSR_MCONTROL_DMODE_LENGTH           1
+#define CSR_MCONTROL_DMODE                  (0x1L << CSR_MCONTROL_DMODE_OFFSET)
+/*
+* Specifies the largest naturally aligned powers-of-two (NAPOT) range
+* supported by the hardware. The value is the logarithm base 2 of the
+* number of bytes in that range.  A value of 0 indicates that only
+* exact value matches are supported (one byte range). A value of 63
+* corresponds to the maximum NAPOT range, which is $2^{63}$ bytes in
+* size.
+ */
+#define CSR_MCONTROL_MASKMAX_OFFSET         XLEN-11
+#define CSR_MCONTROL_MASKMAX_LENGTH         6
+#define CSR_MCONTROL_MASKMAX                (0x3fL << CSR_MCONTROL_MASKMAX_OFFSET)
+/*
+* 0: Perform a match on the virtual address.
+*
+* 1: Perform a match on the data value loaded/stored, or the
+* instruction executed.
+ */
+#define CSR_MCONTROL_SELECT_OFFSET          19
+#define CSR_MCONTROL_SELECT_LENGTH          1
+#define CSR_MCONTROL_SELECT                 (0x1L << CSR_MCONTROL_SELECT_OFFSET)
+/*
+* 0: The action for this trigger will be taken just before the
+* instruction that triggered it is executed, but after all preceding
+* instructions are are committed.
+*
+* 1: The action for this trigger will be taken after the instruction
+* that triggered it is executed. It should be taken before the next
+* instruction is executed, but it is better to implement triggers and
+* not implement that suggestion than to not implement them at all.
+*
+* Most hardware will only implement one timing or the other, possibly
+* dependent on \Fselect, \Fexecute, \Fload, and \Fstore. This bit
+* primarily exists for the hardware to communicate to the debugger
+* what will happen. Hardware may implement the bit fully writable, in
+* which case the debugger has a little more control.
+*
+* Data load triggers with \Ftiming of 0 will result in the same load
+* happening again when the debugger lets the core run. For data load
+* triggers, debuggers must first attempt to set the breakpoint with
+* \Ftiming of 1.
+*
+* A chain of triggers that don't all have the same \Ftiming value
+* will never fire (unless consecutive instructions match the
+* appropriate triggers).
+ */
+#define CSR_MCONTROL_TIMING_OFFSET          18
+#define CSR_MCONTROL_TIMING_LENGTH          1
+#define CSR_MCONTROL_TIMING                 (0x1L << CSR_MCONTROL_TIMING_OFFSET)
+/*
+* Determines what happens when this trigger matches.
+*
+* 0: Raise a breakpoint exception. (Used when software wants to use
+* the trigger module without an external debugger attached.)
+*
+* 1: Enter Halt Mode. (Only supported when \Fhmode is 1.)
+*
+* 2: Start tracing.
+*
+* 3: Stop tracing.
+*
+* 4: Emit trace data for this match. If it is a data access match,
+* emit appropriate Load/Store Address/Data. If it is an instruction
+* execution, emit its PC.
+*
+* Other values are reserved for future use.
+ */
+#define CSR_MCONTROL_ACTION_OFFSET          12
+#define CSR_MCONTROL_ACTION_LENGTH          6
+#define CSR_MCONTROL_ACTION                 (0x3fL << CSR_MCONTROL_ACTION_OFFSET)
+/*
+* 0: When this trigger matches, the configured action is taken.
+*
+* 1: While this trigger does not match, it prevents the trigger with
+* the next index from matching.
+ */
+#define CSR_MCONTROL_CHAIN_OFFSET           11
+#define CSR_MCONTROL_CHAIN_LENGTH           1
+#define CSR_MCONTROL_CHAIN                  (0x1L << CSR_MCONTROL_CHAIN_OFFSET)
+/*
+* 0: Matches when the value equals \Rtdatatwo.
+*
+* 1: Matches when the top M bits of the value match the top M bits of
+* \Rtdatatwo. M is XLEN-1 minus the index of the least-significant
+* bit containing 0 in \Rtdatatwo.
+*
+* 2: Matches when the value is greater than or equal to \Rtdatatwo.
+*
+* 3: Matches when the value is less than \Rtdatatwo.
+*
+* 4: Matches when the lower half of the value equals the lower half
+* of \Rtdatatwo after the lower half of the value is ANDed with the
+* upper half of \Rtdatatwo.
+*
+* 5: Matches when the upper half of the value equals the lower half
+* of \Rtdatatwo after the upper half of the value is ANDed with the
+* upper half of \Rtdatatwo.
+*
+* Other values are reserved for future use.
+ */
+#define CSR_MCONTROL_MATCH_OFFSET           7
+#define CSR_MCONTROL_MATCH_LENGTH           4
+#define CSR_MCONTROL_MATCH                  (0xfL << CSR_MCONTROL_MATCH_OFFSET)
+/*
+* When set, enable this trigger in M mode.
+ */
+#define CSR_MCONTROL_M_OFFSET               6
+#define CSR_MCONTROL_M_LENGTH               1
+#define CSR_MCONTROL_M                      (0x1L << CSR_MCONTROL_M_OFFSET)
+/*
+* When set, enable this trigger in H mode.
+ */
+#define CSR_MCONTROL_H_OFFSET               5
+#define CSR_MCONTROL_H_LENGTH               1
+#define CSR_MCONTROL_H                      (0x1L << CSR_MCONTROL_H_OFFSET)
+/*
+* When set, enable this trigger in S mode.
+ */
+#define CSR_MCONTROL_S_OFFSET               4
+#define CSR_MCONTROL_S_LENGTH               1
+#define CSR_MCONTROL_S                      (0x1L << CSR_MCONTROL_S_OFFSET)
+/*
+* When set, enable this trigger in U mode.
+ */
+#define CSR_MCONTROL_U_OFFSET               3
+#define CSR_MCONTROL_U_LENGTH               1
+#define CSR_MCONTROL_U                      (0x1L << CSR_MCONTROL_U_OFFSET)
+/*
+* When set, the trigger fires on the virtual address or opcode of an
+* instruction that is executed.
+ */
+#define CSR_MCONTROL_EXECUTE_OFFSET         2
+#define CSR_MCONTROL_EXECUTE_LENGTH         1
+#define CSR_MCONTROL_EXECUTE                (0x1L << CSR_MCONTROL_EXECUTE_OFFSET)
+/*
+* When set, the trigger fires on the virtual address or data of a store.
+ */
+#define CSR_MCONTROL_STORE_OFFSET           1
+#define CSR_MCONTROL_STORE_LENGTH           1
+#define CSR_MCONTROL_STORE                  (0x1L << CSR_MCONTROL_STORE_OFFSET)
+/*
+* When set, the trigger fires on the virtual address or data of a load.
+ */
+#define CSR_MCONTROL_LOAD_OFFSET            0
+#define CSR_MCONTROL_LOAD_LENGTH            1
+#define CSR_MCONTROL_LOAD                   (0x1L << CSR_MCONTROL_LOAD_OFFSET)
+#define CSR_ICOUNT                          0x7a1
+#define CSR_ICOUNT_TYPE_OFFSET              XLEN-4
+#define CSR_ICOUNT_TYPE_LENGTH              4
+#define CSR_ICOUNT_TYPE                     (0xfL << CSR_ICOUNT_TYPE_OFFSET)
+#define CSR_ICOUNT_DMODE_OFFSET             XLEN-5
+#define CSR_ICOUNT_DMODE_LENGTH             1
+#define CSR_ICOUNT_DMODE                    (0x1L << CSR_ICOUNT_DMODE_OFFSET)
+/*
+* When count is decremented to 0, the trigger fires. Instead of
+* changing \Fcount from 1 to 0, it is also acceptable for hardware to
+* clear \Fm, \Fh, \Fs, and \Fu. This allows \Fcount to be hard-wired
+* to 1 if this register just exists for single step.
+ */
+#define CSR_ICOUNT_COUNT_OFFSET             10
+#define CSR_ICOUNT_COUNT_LENGTH             14
+#define CSR_ICOUNT_COUNT                    (0x3fffL << CSR_ICOUNT_COUNT_OFFSET)
+/*
+* When set, every instruction completed in M mode decrements \Fcount
+* by 1.
+ */
+#define CSR_ICOUNT_M_OFFSET                 9
+#define CSR_ICOUNT_M_LENGTH                 1
+#define CSR_ICOUNT_M                        (0x1L << CSR_ICOUNT_M_OFFSET)
+/*
+* When set, every instruction completed in H mode decrements \Fcount
+* by 1.
+ */
+#define CSR_ICOUNT_H_OFFSET                 8
+#define CSR_ICOUNT_H_LENGTH                 1
+#define CSR_ICOUNT_H                        (0x1L << CSR_ICOUNT_H_OFFSET)
+/*
+* When set, every instruction completed in S mode decrements \Fcount
+* by 1.
+ */
+#define CSR_ICOUNT_S_OFFSET                 7
+#define CSR_ICOUNT_S_LENGTH                 1
+#define CSR_ICOUNT_S                        (0x1L << CSR_ICOUNT_S_OFFSET)
+/*
+* When set, every instruction completed in U mode decrements \Fcount
+* by 1.
+ */
+#define CSR_ICOUNT_U_OFFSET                 6
+#define CSR_ICOUNT_U_LENGTH                 1
+#define CSR_ICOUNT_U                        (0x1L << CSR_ICOUNT_U_OFFSET)
+/*
+* Determines what happens when this trigger matches.
+*
+* 0: Raise a debug exception. (Used when software wants to use the
+* trigger module without an external debugger attached.)
+*
+* 1: Enter Halt Mode. (Only supported when \Fhmode is 1.)
+*
+* 2: Start tracing.
+*
+* 3: Stop tracing.
+*
+* 4: Emit trace data for this match. If it is a data access match,
+* emit appropriate Load/Store Address/Data. If it is an instruction
+* execution, emit its PC.
+*
+* Other values are reserved for future use.
+ */
+#define CSR_ICOUNT_ACTION_OFFSET            0
+#define CSR_ICOUNT_ACTION_LENGTH            6
+#define CSR_ICOUNT_ACTION                   (0x3fL << CSR_ICOUNT_ACTION_OFFSET)
+#define DMI_DMSTATUS                        0x11
+/*
+* This field is 1 when all currently selected harts do not exist in this system.
+ */
+#define DMI_DMSTATUS_ALLNONEXISTENT_OFFSET  15
+#define DMI_DMSTATUS_ALLNONEXISTENT_LENGTH  1
+#define DMI_DMSTATUS_ALLNONEXISTENT         (0x1 << DMI_DMSTATUS_ALLNONEXISTENT_OFFSET)
+/*
+* This field is 1 when any currently selected hart does not exist in this system.
+ */
+#define DMI_DMSTATUS_ANYNONEXISTENT_OFFSET  14
+#define DMI_DMSTATUS_ANYNONEXISTENT_LENGTH  1
+#define DMI_DMSTATUS_ANYNONEXISTENT         (0x1 << DMI_DMSTATUS_ANYNONEXISTENT_OFFSET)
+/*
+* This field is 1 when all currently selected harts are unavailable.
+ */
+#define DMI_DMSTATUS_ALLUNAVAIL_OFFSET      13
+#define DMI_DMSTATUS_ALLUNAVAIL_LENGTH      1
+#define DMI_DMSTATUS_ALLUNAVAIL             (0x1 << DMI_DMSTATUS_ALLUNAVAIL_OFFSET)
+/*
+* This field is 1 when any currently selected hart is unavailable.
+ */
+#define DMI_DMSTATUS_ANYUNAVAIL_OFFSET      12
+#define DMI_DMSTATUS_ANYUNAVAIL_LENGTH      1
+#define DMI_DMSTATUS_ANYUNAVAIL             (0x1 << DMI_DMSTATUS_ANYUNAVAIL_OFFSET)
+/*
+* This field is 1 when all currently selected harts are running.
+ */
+#define DMI_DMSTATUS_ALLRUNNING_OFFSET      11
+#define DMI_DMSTATUS_ALLRUNNING_LENGTH      1
+#define DMI_DMSTATUS_ALLRUNNING             (0x1 << DMI_DMSTATUS_ALLRUNNING_OFFSET)
+/*
+* This field is 1 when any currently selected hart is running.
+ */
+#define DMI_DMSTATUS_ANYRUNNING_OFFSET      10
+#define DMI_DMSTATUS_ANYRUNNING_LENGTH      1
+#define DMI_DMSTATUS_ANYRUNNING             (0x1 << DMI_DMSTATUS_ANYRUNNING_OFFSET)
+/*
+* This field is 1 when all currently selected harts are halted.
+ */
+#define DMI_DMSTATUS_ALLHALTED_OFFSET       9
+#define DMI_DMSTATUS_ALLHALTED_LENGTH       1
+#define DMI_DMSTATUS_ALLHALTED              (0x1 << DMI_DMSTATUS_ALLHALTED_OFFSET)
+/*
+* This field is 1 when any currently selected hart is halted.
+ */
+#define DMI_DMSTATUS_ANYHALTED_OFFSET       8
+#define DMI_DMSTATUS_ANYHALTED_LENGTH       1
+#define DMI_DMSTATUS_ANYHALTED              (0x1 << DMI_DMSTATUS_ANYHALTED_OFFSET)
+/*
+* 0 when authentication is required before using the DM.  1 when the
+* authentication check has passed. On components that don't implement
+* authentication, this bit must be preset as 1.
+ */
+#define DMI_DMSTATUS_AUTHENTICATED_OFFSET   7
+#define DMI_DMSTATUS_AUTHENTICATED_LENGTH   1
+#define DMI_DMSTATUS_AUTHENTICATED          (0x1 << DMI_DMSTATUS_AUTHENTICATED_OFFSET)
+/*
+* 0: The authentication module is ready to process the next
+* read/write to \Rauthdata.
+*
+* 1: The authentication module is busy. Accessing \Rauthdata results
+* in unspecified behavior.
+*
+* \Fauthbusy only becomes set in immediate response to an access to
+* \Rauthdata.
+ */
+#define DMI_DMSTATUS_AUTHBUSY_OFFSET        6
+#define DMI_DMSTATUS_AUTHBUSY_LENGTH        1
+#define DMI_DMSTATUS_AUTHBUSY               (0x1 << DMI_DMSTATUS_AUTHBUSY_OFFSET)
+#define DMI_DMSTATUS_CFGSTRVALID_OFFSET     4
+#define DMI_DMSTATUS_CFGSTRVALID_LENGTH     1
+#define DMI_DMSTATUS_CFGSTRVALID            (0x1 << DMI_DMSTATUS_CFGSTRVALID_OFFSET)
+/*
+* Reserved for future use. Reads as 0.
+ */
+#define DMI_DMSTATUS_VERSIONHI_OFFSET       2
+#define DMI_DMSTATUS_VERSIONHI_LENGTH       2
+#define DMI_DMSTATUS_VERSIONHI              (0x3 << DMI_DMSTATUS_VERSIONHI_OFFSET)
+/*
+* 00: There is no Debug Module present.
+*
+* 01: There is a Debug Module and it conforms to version 0.11 of this
+* specification.
+*
+* 10: There is a Debug Module and it conforms to version 0.13 of this
+* specification.
+*
+* 11: Reserved for future use.
+ */
+#define DMI_DMSTATUS_VERSIONLO_OFFSET       0
+#define DMI_DMSTATUS_VERSIONLO_LENGTH       2
+#define DMI_DMSTATUS_VERSIONLO              (0x3 << DMI_DMSTATUS_VERSIONLO_OFFSET)
+#define DMI_DMCONTROL                       0x10
+/*
+* Halt request signal for all currently selected harts. When 1, the
+* hart will halt if it is not currently halted.
+* Setting both \Fhaltreq and \Fresumereq leads to undefined behavior.
+*
+* Writes apply to the new value of \Fhartsel and \Fhasel.
+ */
+#define DMI_DMCONTROL_HALTREQ_OFFSET        31
+#define DMI_DMCONTROL_HALTREQ_LENGTH        1
+#define DMI_DMCONTROL_HALTREQ               (0x1 << DMI_DMCONTROL_HALTREQ_OFFSET)
+/*
+* Resume request signal for all currently selected harts. When 1,
+* the hart will resume if it is currently halted.
+* Setting both \Fhaltreq and \Fresumereq leads to undefined behavior.
+*
+* Writes apply to the new value of \Fhartsel and \Fhasel.
+ */
+#define DMI_DMCONTROL_RESUMEREQ_OFFSET      30
+#define DMI_DMCONTROL_RESUMEREQ_LENGTH      1
+#define DMI_DMCONTROL_RESUMEREQ             (0x1 << DMI_DMCONTROL_RESUMEREQ_OFFSET)
+/*
+* This optional bit controls reset to all the currently selected harts.
+* To perform a reset the debugger writes 1, and then writes 0 to
+* deassert the reset signal.
+*
+* If this feature is not implemented, the bit always stays 0, so
+* after writing 1 the debugger can read the register back to see if
+* the feature is supported.
+*
+* Writes apply to the new value of \Fhartsel and \Fhasel.
+ */
+#define DMI_DMCONTROL_HARTRESET_OFFSET      29
+#define DMI_DMCONTROL_HARTRESET_LENGTH      1
+#define DMI_DMCONTROL_HARTRESET             (0x1 << DMI_DMCONTROL_HARTRESET_OFFSET)
+/*
+* Selects the  definition of currently selected harts.
+*
+* 0: There is a single currently selected hart, that selected by \Fhartsel.
+*
+* 1: There may be multiple currently selected harts -- that selected by \Fhartsel,
+* plus those selected by the hart array mask register.
+*
+* An implementation which does not implement the hart array mask register
+* should tie this field to 0. A debugger which wishes to use the hart array
+* mask register feature should set this bit and read back to see if the functionality
+* is supported.
+ */
+#define DMI_DMCONTROL_HASEL_OFFSET          26
+#define DMI_DMCONTROL_HASEL_LENGTH          1
+#define DMI_DMCONTROL_HASEL                 (0x1 << DMI_DMCONTROL_HASEL_OFFSET)
+/*
+* The DM-specific index of the hart to select. This hart is always part of the
+* currently selected harts.
+ */
+#define DMI_DMCONTROL_HARTSEL_OFFSET        16
+#define DMI_DMCONTROL_HARTSEL_LENGTH        10
+#define DMI_DMCONTROL_HARTSEL               (0x3ff << DMI_DMCONTROL_HARTSEL_OFFSET)
+/*
+* This bit controls the reset signal from the DM to the rest of the
+* system. To perform a reset the debugger writes 1, and then writes 0
+* to deassert the reset.
+ */
+#define DMI_DMCONTROL_NDMRESET_OFFSET       1
+#define DMI_DMCONTROL_NDMRESET_LENGTH       1
+#define DMI_DMCONTROL_NDMRESET              (0x1 << DMI_DMCONTROL_NDMRESET_OFFSET)
+/*
+* This bit serves as a reset signal for the Debug Module itself.
+*
+* 0: The module's state, including authentication mechanism,
+* takes its reset values (the \Fdmactive bit is the only bit which can
+* be written to something other than its reset value).
+*
+* 1: The module functions normally.
+*
+* No other mechanism should exist that may result in resetting the
+* Debug Module after power up, including the platform's system reset
+* or Debug Transport reset signals.
+*
+* A debugger should pulse this bit low to ensure that the Debug
+* Module is fully reset and ready to use.
+*
+* Implementations may use this bit to aid debugging, for example by
+* preventing the Debug Module from being power gated while debugging
+* is active.
+ */
+#define DMI_DMCONTROL_DMACTIVE_OFFSET       0
+#define DMI_DMCONTROL_DMACTIVE_LENGTH       1
+#define DMI_DMCONTROL_DMACTIVE              (0x1 << DMI_DMCONTROL_DMACTIVE_OFFSET)
+#define DMI_HARTINFO                        0x12
+/*
+* Number of {\tt dscratch} registers available for the debugger
+* to use during program buffer execution, starting from \Rdscratchzero.
+* The debugger can make no assumptions about the contents of these
+* registers between commands.
+ */
+#define DMI_HARTINFO_NSCRATCH_OFFSET        20
+#define DMI_HARTINFO_NSCRATCH_LENGTH        4
+#define DMI_HARTINFO_NSCRATCH               (0xf << DMI_HARTINFO_NSCRATCH_OFFSET)
+/*
+* 0: The {\tt data} registers are shadowed in the hart by CSR
+* registers. Each CSR register is XLEN bits in size, and corresponds
+* to a single argument, per Table~\ref{tab:datareg}.
+*
+* 1: The {\tt data} registers are shadowed in the hart's memory map.
+* Each register takes up 4 bytes in the memory map.
+ */
+#define DMI_HARTINFO_DATAACCESS_OFFSET      16
+#define DMI_HARTINFO_DATAACCESS_LENGTH      1
+#define DMI_HARTINFO_DATAACCESS             (0x1 << DMI_HARTINFO_DATAACCESS_OFFSET)
+/*
+* If \Fdataaccess is 0: Number of CSR registers dedicated to
+* shadowing the {\tt data} registers.
+*
+* If \Fdataaccess is 1: Number of 32-bit words in the memory map
+* dedicated to shadowing the {\tt data} registers.
+ */
+#define DMI_HARTINFO_DATASIZE_OFFSET        12
+#define DMI_HARTINFO_DATASIZE_LENGTH        4
+#define DMI_HARTINFO_DATASIZE               (0xf << DMI_HARTINFO_DATASIZE_OFFSET)
+/*
+* If \Fdataaccess is 0: The number of the first CSR dedicated to
+* shadowing the {\tt data} registers.
+*
+* If \Fdataaccess is 1: Signed address of RAM where the {\tt data}
+* registers are shadowed.
+ */
+#define DMI_HARTINFO_DATAADDR_OFFSET        0
+#define DMI_HARTINFO_DATAADDR_LENGTH        12
+#define DMI_HARTINFO_DATAADDR               (0xfff << DMI_HARTINFO_DATAADDR_OFFSET)
+#define DMI_HALTSUM                         0x13
+#define DMI_HALTSUM_HALT1023_992_OFFSET     31
+#define DMI_HALTSUM_HALT1023_992_LENGTH     1
+#define DMI_HALTSUM_HALT1023_992            (0x1 << DMI_HALTSUM_HALT1023_992_OFFSET)
+#define DMI_HALTSUM_HALT991_960_OFFSET      30
+#define DMI_HALTSUM_HALT991_960_LENGTH      1
+#define DMI_HALTSUM_HALT991_960             (0x1 << DMI_HALTSUM_HALT991_960_OFFSET)
+#define DMI_HALTSUM_HALT959_928_OFFSET      29
+#define DMI_HALTSUM_HALT959_928_LENGTH      1
+#define DMI_HALTSUM_HALT959_928             (0x1 << DMI_HALTSUM_HALT959_928_OFFSET)
+#define DMI_HALTSUM_HALT927_896_OFFSET      28
+#define DMI_HALTSUM_HALT927_896_LENGTH      1
+#define DMI_HALTSUM_HALT927_896             (0x1 << DMI_HALTSUM_HALT927_896_OFFSET)
+#define DMI_HALTSUM_HALT895_864_OFFSET      27
+#define DMI_HALTSUM_HALT895_864_LENGTH      1
+#define DMI_HALTSUM_HALT895_864             (0x1 << DMI_HALTSUM_HALT895_864_OFFSET)
+#define DMI_HALTSUM_HALT863_832_OFFSET      26
+#define DMI_HALTSUM_HALT863_832_LENGTH      1
+#define DMI_HALTSUM_HALT863_832             (0x1 << DMI_HALTSUM_HALT863_832_OFFSET)
+#define DMI_HALTSUM_HALT831_800_OFFSET      25
+#define DMI_HALTSUM_HALT831_800_LENGTH      1
+#define DMI_HALTSUM_HALT831_800             (0x1 << DMI_HALTSUM_HALT831_800_OFFSET)
+#define DMI_HALTSUM_HALT799_768_OFFSET      24
+#define DMI_HALTSUM_HALT799_768_LENGTH      1
+#define DMI_HALTSUM_HALT799_768             (0x1 << DMI_HALTSUM_HALT799_768_OFFSET)
+#define DMI_HALTSUM_HALT767_736_OFFSET      23
+#define DMI_HALTSUM_HALT767_736_LENGTH      1
+#define DMI_HALTSUM_HALT767_736             (0x1 << DMI_HALTSUM_HALT767_736_OFFSET)
+#define DMI_HALTSUM_HALT735_704_OFFSET      22
+#define DMI_HALTSUM_HALT735_704_LENGTH      1
+#define DMI_HALTSUM_HALT735_704             (0x1 << DMI_HALTSUM_HALT735_704_OFFSET)
+#define DMI_HALTSUM_HALT703_672_OFFSET      21
+#define DMI_HALTSUM_HALT703_672_LENGTH      1
+#define DMI_HALTSUM_HALT703_672             (0x1 << DMI_HALTSUM_HALT703_672_OFFSET)
+#define DMI_HALTSUM_HALT671_640_OFFSET      20
+#define DMI_HALTSUM_HALT671_640_LENGTH      1
+#define DMI_HALTSUM_HALT671_640             (0x1 << DMI_HALTSUM_HALT671_640_OFFSET)
+#define DMI_HALTSUM_HALT639_608_OFFSET      19
+#define DMI_HALTSUM_HALT639_608_LENGTH      1
+#define DMI_HALTSUM_HALT639_608             (0x1 << DMI_HALTSUM_HALT639_608_OFFSET)
+#define DMI_HALTSUM_HALT607_576_OFFSET      18
+#define DMI_HALTSUM_HALT607_576_LENGTH      1
+#define DMI_HALTSUM_HALT607_576             (0x1 << DMI_HALTSUM_HALT607_576_OFFSET)
+#define DMI_HALTSUM_HALT575_544_OFFSET      17
+#define DMI_HALTSUM_HALT575_544_LENGTH      1
+#define DMI_HALTSUM_HALT575_544             (0x1 << DMI_HALTSUM_HALT575_544_OFFSET)
+#define DMI_HALTSUM_HALT543_512_OFFSET      16
+#define DMI_HALTSUM_HALT543_512_LENGTH      1
+#define DMI_HALTSUM_HALT543_512             (0x1 << DMI_HALTSUM_HALT543_512_OFFSET)
+#define DMI_HALTSUM_HALT511_480_OFFSET      15
+#define DMI_HALTSUM_HALT511_480_LENGTH      1
+#define DMI_HALTSUM_HALT511_480             (0x1 << DMI_HALTSUM_HALT511_480_OFFSET)
+#define DMI_HALTSUM_HALT479_448_OFFSET      14
+#define DMI_HALTSUM_HALT479_448_LENGTH      1
+#define DMI_HALTSUM_HALT479_448             (0x1 << DMI_HALTSUM_HALT479_448_OFFSET)
+#define DMI_HALTSUM_HALT447_416_OFFSET      13
+#define DMI_HALTSUM_HALT447_416_LENGTH      1
+#define DMI_HALTSUM_HALT447_416             (0x1 << DMI_HALTSUM_HALT447_416_OFFSET)
+#define DMI_HALTSUM_HALT415_384_OFFSET      12
+#define DMI_HALTSUM_HALT415_384_LENGTH      1
+#define DMI_HALTSUM_HALT415_384             (0x1 << DMI_HALTSUM_HALT415_384_OFFSET)
+#define DMI_HALTSUM_HALT383_352_OFFSET      11
+#define DMI_HALTSUM_HALT383_352_LENGTH      1
+#define DMI_HALTSUM_HALT383_352             (0x1 << DMI_HALTSUM_HALT383_352_OFFSET)
+#define DMI_HALTSUM_HALT351_320_OFFSET      10
+#define DMI_HALTSUM_HALT351_320_LENGTH      1
+#define DMI_HALTSUM_HALT351_320             (0x1 << DMI_HALTSUM_HALT351_320_OFFSET)
+#define DMI_HALTSUM_HALT319_288_OFFSET      9
+#define DMI_HALTSUM_HALT319_288_LENGTH      1
+#define DMI_HALTSUM_HALT319_288             (0x1 << DMI_HALTSUM_HALT319_288_OFFSET)
+#define DMI_HALTSUM_HALT287_256_OFFSET      8
+#define DMI_HALTSUM_HALT287_256_LENGTH      1
+#define DMI_HALTSUM_HALT287_256             (0x1 << DMI_HALTSUM_HALT287_256_OFFSET)
+#define DMI_HALTSUM_HALT255_224_OFFSET      7
+#define DMI_HALTSUM_HALT255_224_LENGTH      1
+#define DMI_HALTSUM_HALT255_224             (0x1 << DMI_HALTSUM_HALT255_224_OFFSET)
+#define DMI_HALTSUM_HALT223_192_OFFSET      6
+#define DMI_HALTSUM_HALT223_192_LENGTH      1
+#define DMI_HALTSUM_HALT223_192             (0x1 << DMI_HALTSUM_HALT223_192_OFFSET)
+#define DMI_HALTSUM_HALT191_160_OFFSET      5
+#define DMI_HALTSUM_HALT191_160_LENGTH      1
+#define DMI_HALTSUM_HALT191_160             (0x1 << DMI_HALTSUM_HALT191_160_OFFSET)
+#define DMI_HALTSUM_HALT159_128_OFFSET      4
+#define DMI_HALTSUM_HALT159_128_LENGTH      1
+#define DMI_HALTSUM_HALT159_128             (0x1 << DMI_HALTSUM_HALT159_128_OFFSET)
+#define DMI_HALTSUM_HALT127_96_OFFSET       3
+#define DMI_HALTSUM_HALT127_96_LENGTH       1
+#define DMI_HALTSUM_HALT127_96              (0x1 << DMI_HALTSUM_HALT127_96_OFFSET)
+#define DMI_HALTSUM_HALT95_64_OFFSET        2
+#define DMI_HALTSUM_HALT95_64_LENGTH        1
+#define DMI_HALTSUM_HALT95_64               (0x1 << DMI_HALTSUM_HALT95_64_OFFSET)
+#define DMI_HALTSUM_HALT63_32_OFFSET        1
+#define DMI_HALTSUM_HALT63_32_LENGTH        1
+#define DMI_HALTSUM_HALT63_32               (0x1 << DMI_HALTSUM_HALT63_32_OFFSET)
+#define DMI_HALTSUM_HALT31_0_OFFSET         0
+#define DMI_HALTSUM_HALT31_0_LENGTH         1
+#define DMI_HALTSUM_HALT31_0                (0x1 << DMI_HALTSUM_HALT31_0_OFFSET)
+#define DMI_HAWINDOWSEL                     0x14
+#define DMI_HAWINDOWSEL_HAWINDOWSEL_OFFSET  0
+#define DMI_HAWINDOWSEL_HAWINDOWSEL_LENGTH  5
+#define DMI_HAWINDOWSEL_HAWINDOWSEL         (0x1f << DMI_HAWINDOWSEL_HAWINDOWSEL_OFFSET)
+#define DMI_HAWINDOW                        0x15
+#define DMI_HAWINDOW_MASKDATA_OFFSET        0
+#define DMI_HAWINDOW_MASKDATA_LENGTH        32
+#define DMI_HAWINDOW_MASKDATA               (0xffffffff << DMI_HAWINDOW_MASKDATA_OFFSET)
+#define DMI_ABSTRACTCS                      0x16
+/*
+* Size of the Program Buffer, in 32-bit words. Valid sizes are 0 - 16.
+*
+* TODO: Explain what can be done with each size of the buffer, to suggest
+* why you would want more or less words.
+ */
+#define DMI_ABSTRACTCS_PROGSIZE_OFFSET      24
+#define DMI_ABSTRACTCS_PROGSIZE_LENGTH      5
+#define DMI_ABSTRACTCS_PROGSIZE             (0x1f << DMI_ABSTRACTCS_PROGSIZE_OFFSET)
+/*
+* 1: An abstract command is currently being executed.
+*
+* This bit is set as soon as \Rcommand is written, and is
+* not cleared until that command has completed.
+ */
+#define DMI_ABSTRACTCS_BUSY_OFFSET          12
+#define DMI_ABSTRACTCS_BUSY_LENGTH          1
+#define DMI_ABSTRACTCS_BUSY                 (0x1 << DMI_ABSTRACTCS_BUSY_OFFSET)
+/*
+* Gets set if an abstract command fails. The bits in this field remain set until
+* they are cleared by writing 1 to them. No abstract command is
+* started until the value is reset to 0.
+*
+* 0 (none): No error.
+*
+* 1 (busy): An abstract command was executing while \Rcommand or one
+* of the {\tt data} registers was accessed.
+*
+* 2 (not supported): The requested command is not supported. A
+* command that is not supported while the hart is running may be
+* supported when it is halted.
+*
+* 3 (exception): An exception occurred while executing the command
+* (eg. while executing the Program Buffer).
+*
+* 4 (halt/resume): An abstract command couldn't execute because the
+* hart wasn't in the expected state (running/halted).
+*
+* 7 (other): The command failed for another reason.
+ */
+#define DMI_ABSTRACTCS_CMDERR_OFFSET        8
+#define DMI_ABSTRACTCS_CMDERR_LENGTH        3
+#define DMI_ABSTRACTCS_CMDERR               (0x7 << DMI_ABSTRACTCS_CMDERR_OFFSET)
+/*
+* Number of {\tt data} registers that are implemented as part of the
+* abstract command interface. Valid sizes are 0 - 8.
+ */
+#define DMI_ABSTRACTCS_DATACOUNT_OFFSET     0
+#define DMI_ABSTRACTCS_DATACOUNT_LENGTH     5
+#define DMI_ABSTRACTCS_DATACOUNT            (0x1f << DMI_ABSTRACTCS_DATACOUNT_OFFSET)
+#define DMI_COMMAND                         0x17
+/*
+* The type determines the overall functionality of this
+* abstract command.
+ */
+#define DMI_COMMAND_CMDTYPE_OFFSET          24
+#define DMI_COMMAND_CMDTYPE_LENGTH          8
+#define DMI_COMMAND_CMDTYPE                 (0xff << DMI_COMMAND_CMDTYPE_OFFSET)
+/*
+* This field is interpreted in a command-specific manner,
+* described for each abstract command.
+ */
+#define DMI_COMMAND_CONTROL_OFFSET          0
+#define DMI_COMMAND_CONTROL_LENGTH          24
+#define DMI_COMMAND_CONTROL                 (0xffffff << DMI_COMMAND_CONTROL_OFFSET)
+#define DMI_ABSTRACTAUTO                    0x18
+/*
+* When a bit in this field is 1, read or write accesses the corresponding {\tt progbuf} word
+* cause the command in \Rcommand to be executed again.
+ */
+#define DMI_ABSTRACTAUTO_AUTOEXECPROGBUF_OFFSET 16
+#define DMI_ABSTRACTAUTO_AUTOEXECPROGBUF_LENGTH 16
+#define DMI_ABSTRACTAUTO_AUTOEXECPROGBUF    (0xffff << DMI_ABSTRACTAUTO_AUTOEXECPROGBUF_OFFSET)
+/*
+* When a bit in this field is 1, read or write accesses the corresponding {\tt data} word
+* cause the command in \Rcommand to be executed again.
+ */
+#define DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET 0
+#define DMI_ABSTRACTAUTO_AUTOEXECDATA_LENGTH 12
+#define DMI_ABSTRACTAUTO_AUTOEXECDATA       (0xfff << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET)
+#define DMI_CFGSTRADDR0                     0x19
+#define DMI_CFGSTRADDR0_ADDR_OFFSET         0
+#define DMI_CFGSTRADDR0_ADDR_LENGTH         32
+#define DMI_CFGSTRADDR0_ADDR                (0xffffffff << DMI_CFGSTRADDR0_ADDR_OFFSET)
+#define DMI_CFGSTRADDR1                     0x1a
+#define DMI_CFGSTRADDR2                     0x1b
+#define DMI_CFGSTRADDR3                     0x1c
+#define DMI_DATA0                           0x04
+#define DMI_DATA0_DATA_OFFSET               0
+#define DMI_DATA0_DATA_LENGTH               32
+#define DMI_DATA0_DATA                      (0xffffffff << DMI_DATA0_DATA_OFFSET)
+#define DMI_DATA1                           0x05
+#define DMI_DATA2                           0x06
+#define DMI_DATA3                           0x07
+#define DMI_DATA4                           0x08
+#define DMI_DATA5                           0x09
+#define DMI_DATA6                           0x0a
+#define DMI_DATA7                           0x0b
+#define DMI_DATA8                           0x0c
+#define DMI_DATA9                           0x0d
+#define DMI_DATA10                          0x0e
+#define DMI_DATA11                          0x0f
+#define DMI_PROGBUF0                        0x20
+#define DMI_PROGBUF0_DATA_OFFSET            0
+#define DMI_PROGBUF0_DATA_LENGTH            32
+#define DMI_PROGBUF0_DATA                   (0xffffffff << DMI_PROGBUF0_DATA_OFFSET)
+#define DMI_PROGBUF1                        0x21
+#define DMI_PROGBUF2                        0x22
+#define DMI_PROGBUF3                        0x23
+#define DMI_PROGBUF4                        0x24
+#define DMI_PROGBUF5                        0x25
+#define DMI_PROGBUF6                        0x26
+#define DMI_PROGBUF7                        0x27
+#define DMI_PROGBUF8                        0x28
+#define DMI_PROGBUF9                        0x29
+#define DMI_PROGBUF10                       0x2a
+#define DMI_AUTHDATA                        0x30
+#define DMI_AUTHDATA_DATA_OFFSET            0
+#define DMI_AUTHDATA_DATA_LENGTH            32
+#define DMI_AUTHDATA_DATA                   (0xffffffff << DMI_AUTHDATA_DATA_OFFSET)
+#define DMI_SERCS                           0x34
+/*
+* Number of supported serial ports.
+ */
+#define DMI_SERCS_SERIALCOUNT_OFFSET        28
+#define DMI_SERCS_SERIALCOUNT_LENGTH        4
+#define DMI_SERCS_SERIALCOUNT               (0xf << DMI_SERCS_SERIALCOUNT_OFFSET)
+/*
+* Select which serial port is accessed by \Rserrx and \Rsertx.
+ */
+#define DMI_SERCS_SERIAL_OFFSET             24
+#define DMI_SERCS_SERIAL_LENGTH             3
+#define DMI_SERCS_SERIAL                    (0x7 << DMI_SERCS_SERIAL_OFFSET)
+#define DMI_SERCS_ERROR7_OFFSET             23
+#define DMI_SERCS_ERROR7_LENGTH             1
+#define DMI_SERCS_ERROR7                    (0x1 << DMI_SERCS_ERROR7_OFFSET)
+#define DMI_SERCS_VALID7_OFFSET             22
+#define DMI_SERCS_VALID7_LENGTH             1
+#define DMI_SERCS_VALID7                    (0x1 << DMI_SERCS_VALID7_OFFSET)
+#define DMI_SERCS_FULL7_OFFSET              21
+#define DMI_SERCS_FULL7_LENGTH              1
+#define DMI_SERCS_FULL7                     (0x1 << DMI_SERCS_FULL7_OFFSET)
+#define DMI_SERCS_ERROR6_OFFSET             20
+#define DMI_SERCS_ERROR6_LENGTH             1
+#define DMI_SERCS_ERROR6                    (0x1 << DMI_SERCS_ERROR6_OFFSET)
+#define DMI_SERCS_VALID6_OFFSET             19
+#define DMI_SERCS_VALID6_LENGTH             1
+#define DMI_SERCS_VALID6                    (0x1 << DMI_SERCS_VALID6_OFFSET)
+#define DMI_SERCS_FULL6_OFFSET              18
+#define DMI_SERCS_FULL6_LENGTH              1
+#define DMI_SERCS_FULL6                     (0x1 << DMI_SERCS_FULL6_OFFSET)
+#define DMI_SERCS_ERROR5_OFFSET             17
+#define DMI_SERCS_ERROR5_LENGTH             1
+#define DMI_SERCS_ERROR5                    (0x1 << DMI_SERCS_ERROR5_OFFSET)
+#define DMI_SERCS_VALID5_OFFSET             16
+#define DMI_SERCS_VALID5_LENGTH             1
+#define DMI_SERCS_VALID5                    (0x1 << DMI_SERCS_VALID5_OFFSET)
+#define DMI_SERCS_FULL5_OFFSET              15
+#define DMI_SERCS_FULL5_LENGTH              1
+#define DMI_SERCS_FULL5                     (0x1 << DMI_SERCS_FULL5_OFFSET)
+#define DMI_SERCS_ERROR4_OFFSET             14
+#define DMI_SERCS_ERROR4_LENGTH             1
+#define DMI_SERCS_ERROR4                    (0x1 << DMI_SERCS_ERROR4_OFFSET)
+#define DMI_SERCS_VALID4_OFFSET             13
+#define DMI_SERCS_VALID4_LENGTH             1
+#define DMI_SERCS_VALID4                    (0x1 << DMI_SERCS_VALID4_OFFSET)
+#define DMI_SERCS_FULL4_OFFSET              12
+#define DMI_SERCS_FULL4_LENGTH              1
+#define DMI_SERCS_FULL4                     (0x1 << DMI_SERCS_FULL4_OFFSET)
+#define DMI_SERCS_ERROR3_OFFSET             11
+#define DMI_SERCS_ERROR3_LENGTH             1
+#define DMI_SERCS_ERROR3                    (0x1 << DMI_SERCS_ERROR3_OFFSET)
+#define DMI_SERCS_VALID3_OFFSET             10
+#define DMI_SERCS_VALID3_LENGTH             1
+#define DMI_SERCS_VALID3                    (0x1 << DMI_SERCS_VALID3_OFFSET)
+#define DMI_SERCS_FULL3_OFFSET              9
+#define DMI_SERCS_FULL3_LENGTH              1
+#define DMI_SERCS_FULL3                     (0x1 << DMI_SERCS_FULL3_OFFSET)
+#define DMI_SERCS_ERROR2_OFFSET             8
+#define DMI_SERCS_ERROR2_LENGTH             1
+#define DMI_SERCS_ERROR2                    (0x1 << DMI_SERCS_ERROR2_OFFSET)
+#define DMI_SERCS_VALID2_OFFSET             7
+#define DMI_SERCS_VALID2_LENGTH             1
+#define DMI_SERCS_VALID2                    (0x1 << DMI_SERCS_VALID2_OFFSET)
+#define DMI_SERCS_FULL2_OFFSET              6
+#define DMI_SERCS_FULL2_LENGTH              1
+#define DMI_SERCS_FULL2                     (0x1 << DMI_SERCS_FULL2_OFFSET)
+#define DMI_SERCS_ERROR1_OFFSET             5
+#define DMI_SERCS_ERROR1_LENGTH             1
+#define DMI_SERCS_ERROR1                    (0x1 << DMI_SERCS_ERROR1_OFFSET)
+#define DMI_SERCS_VALID1_OFFSET             4
+#define DMI_SERCS_VALID1_LENGTH             1
+#define DMI_SERCS_VALID1                    (0x1 << DMI_SERCS_VALID1_OFFSET)
+#define DMI_SERCS_FULL1_OFFSET              3
+#define DMI_SERCS_FULL1_LENGTH              1
+#define DMI_SERCS_FULL1                     (0x1 << DMI_SERCS_FULL1_OFFSET)
+/*
+* 1 when the debugger-to-core queue for serial port 0 has
+* over or underflowed. This bit will remain set until it is reset by
+* writing 1 to this bit.
+ */
+#define DMI_SERCS_ERROR0_OFFSET             2
+#define DMI_SERCS_ERROR0_LENGTH             1
+#define DMI_SERCS_ERROR0                    (0x1 << DMI_SERCS_ERROR0_OFFSET)
+/*
+* 1 when the core-to-debugger queue for serial port 0 is not empty.
+ */
+#define DMI_SERCS_VALID0_OFFSET             1
+#define DMI_SERCS_VALID0_LENGTH             1
+#define DMI_SERCS_VALID0                    (0x1 << DMI_SERCS_VALID0_OFFSET)
+/*
+* 1 when the debugger-to-core queue for serial port 0 is full.
+ */
+#define DMI_SERCS_FULL0_OFFSET              0
+#define DMI_SERCS_FULL0_LENGTH              1
+#define DMI_SERCS_FULL0                     (0x1 << DMI_SERCS_FULL0_OFFSET)
+#define DMI_SERTX                           0x35
+#define DMI_SERTX_DATA_OFFSET               0
+#define DMI_SERTX_DATA_LENGTH               32
+#define DMI_SERTX_DATA                      (0xffffffff << DMI_SERTX_DATA_OFFSET)
+#define DMI_SERRX                           0x36
+#define DMI_SERRX_DATA_OFFSET               0
+#define DMI_SERRX_DATA_LENGTH               32
+#define DMI_SERRX_DATA                      (0xffffffff << DMI_SERRX_DATA_OFFSET)
+#define DMI_SBCS                            0x38
+/*
+* When a 1 is written here, triggers a read at the address in {\tt
+* sbaddress} using the access size set by \Fsbaccess.
+ */
+#define DMI_SBCS_SBSINGLEREAD_OFFSET        20
+#define DMI_SBCS_SBSINGLEREAD_LENGTH        1
+#define DMI_SBCS_SBSINGLEREAD               (0x1 << DMI_SBCS_SBSINGLEREAD_OFFSET)
+/*
+* Select the access size to use for system bus accesses triggered by
+* writes to the {\tt sbaddress} registers or \Rsbdatazero.
+*
+* 0: 8-bit
+*
+* 1: 16-bit
+*
+* 2: 32-bit
+*
+* 3: 64-bit
+*
+* 4: 128-bit
+*
+* If an unsupported system bus access size is written here,
+* the DM may not perform the access, or may perform the access
+* with any access size.
+ */
+#define DMI_SBCS_SBACCESS_OFFSET            17
+#define DMI_SBCS_SBACCESS_LENGTH            3
+#define DMI_SBCS_SBACCESS                   (0x7 << DMI_SBCS_SBACCESS_OFFSET)
+/*
+* When 1, the internal address value (used by the system bus master)
+* is incremented by the access size (in bytes) selected in \Fsbaccess
+* after every system bus access.
+ */
+#define DMI_SBCS_SBAUTOINCREMENT_OFFSET     16
+#define DMI_SBCS_SBAUTOINCREMENT_LENGTH     1
+#define DMI_SBCS_SBAUTOINCREMENT            (0x1 << DMI_SBCS_SBAUTOINCREMENT_OFFSET)
+/*
+* When 1, every read from \Rsbdatazero automatically triggers a system
+* bus read at the new address.
+ */
+#define DMI_SBCS_SBAUTOREAD_OFFSET          15
+#define DMI_SBCS_SBAUTOREAD_LENGTH          1
+#define DMI_SBCS_SBAUTOREAD                 (0x1 << DMI_SBCS_SBAUTOREAD_OFFSET)
+/*
+* When the debug module's system bus
+* master causes a bus error, this field gets set. The bits in this
+* field remain set until they are cleared by writing 1 to them.
+* While this field is non-zero, no more system bus accesses can be
+* initiated by the debug module.
+*
+* 0: There was no bus error.
+*
+* 1: There was a timeout.
+*
+* 2: A bad address was accessed.
+*
+* 3: There was some other error (eg. alignment).
+*
+* 4: The system bus master was busy when a one of the
+* {\tt sbaddress} or {\tt sbdata} registers was written,
+* or the {\tt sbdata} register was read when it had
+* stale data.
+ */
+#define DMI_SBCS_SBERROR_OFFSET             12
+#define DMI_SBCS_SBERROR_LENGTH             3
+#define DMI_SBCS_SBERROR                    (0x7 << DMI_SBCS_SBERROR_OFFSET)
+/*
+* Width of system bus addresses in bits. (0 indicates there is no bus
+* access support.)
+ */
+#define DMI_SBCS_SBASIZE_OFFSET             5
+#define DMI_SBCS_SBASIZE_LENGTH             7
+#define DMI_SBCS_SBASIZE                    (0x7f << DMI_SBCS_SBASIZE_OFFSET)
+/*
+* 1 when 128-bit system bus accesses are supported.
+ */
+#define DMI_SBCS_SBACCESS128_OFFSET         4
+#define DMI_SBCS_SBACCESS128_LENGTH         1
+#define DMI_SBCS_SBACCESS128                (0x1 << DMI_SBCS_SBACCESS128_OFFSET)
+/*
+* 1 when 64-bit system bus accesses are supported.
+ */
+#define DMI_SBCS_SBACCESS64_OFFSET          3
+#define DMI_SBCS_SBACCESS64_LENGTH          1
+#define DMI_SBCS_SBACCESS64                 (0x1 << DMI_SBCS_SBACCESS64_OFFSET)
+/*
+* 1 when 32-bit system bus accesses are supported.
+ */
+#define DMI_SBCS_SBACCESS32_OFFSET          2
+#define DMI_SBCS_SBACCESS32_LENGTH          1
+#define DMI_SBCS_SBACCESS32                 (0x1 << DMI_SBCS_SBACCESS32_OFFSET)
+/*
+* 1 when 16-bit system bus accesses are supported.
+ */
+#define DMI_SBCS_SBACCESS16_OFFSET          1
+#define DMI_SBCS_SBACCESS16_LENGTH          1
+#define DMI_SBCS_SBACCESS16                 (0x1 << DMI_SBCS_SBACCESS16_OFFSET)
+/*
+* 1 when 8-bit system bus accesses are supported.
+ */
+#define DMI_SBCS_SBACCESS8_OFFSET           0
+#define DMI_SBCS_SBACCESS8_LENGTH           1
+#define DMI_SBCS_SBACCESS8                  (0x1 << DMI_SBCS_SBACCESS8_OFFSET)
+#define DMI_SBADDRESS0                      0x39
+/*
+* Accesses bits 31:0 of the internal address.
+ */
+#define DMI_SBADDRESS0_ADDRESS_OFFSET       0
+#define DMI_SBADDRESS0_ADDRESS_LENGTH       32
+#define DMI_SBADDRESS0_ADDRESS              (0xffffffff << DMI_SBADDRESS0_ADDRESS_OFFSET)
+#define DMI_SBADDRESS1                      0x3a
+/*
+* Accesses bits 63:32 of the internal address (if the system address
+* bus is that wide).
+ */
+#define DMI_SBADDRESS1_ADDRESS_OFFSET       0
+#define DMI_SBADDRESS1_ADDRESS_LENGTH       32
+#define DMI_SBADDRESS1_ADDRESS              (0xffffffff << DMI_SBADDRESS1_ADDRESS_OFFSET)
+#define DMI_SBADDRESS2                      0x3b
+/*
+* Accesses bits 95:64 of the internal address (if the system address
+* bus is that wide).
+ */
+#define DMI_SBADDRESS2_ADDRESS_OFFSET       0
+#define DMI_SBADDRESS2_ADDRESS_LENGTH       32
+#define DMI_SBADDRESS2_ADDRESS              (0xffffffff << DMI_SBADDRESS2_ADDRESS_OFFSET)
+#define DMI_SBDATA0                         0x3c
+/*
+* Accesses bits 31:0 of the internal data.
+ */
+#define DMI_SBDATA0_DATA_OFFSET             0
+#define DMI_SBDATA0_DATA_LENGTH             32
+#define DMI_SBDATA0_DATA                    (0xffffffff << DMI_SBDATA0_DATA_OFFSET)
+#define DMI_SBDATA1                         0x3d
+/*
+* Accesses bits 63:32 of the internal data (if the system bus is
+* that wide).
+ */
+#define DMI_SBDATA1_DATA_OFFSET             0
+#define DMI_SBDATA1_DATA_LENGTH             32
+#define DMI_SBDATA1_DATA                    (0xffffffff << DMI_SBDATA1_DATA_OFFSET)
+#define DMI_SBDATA2                         0x3e
+/*
+* Accesses bits 95:64 of the internal data (if the system bus is
+* that wide).
+ */
+#define DMI_SBDATA2_DATA_OFFSET             0
+#define DMI_SBDATA2_DATA_LENGTH             32
+#define DMI_SBDATA2_DATA                    (0xffffffff << DMI_SBDATA2_DATA_OFFSET)
+#define DMI_SBDATA3                         0x3f
+/*
+* Accesses bits 127:96 of the internal data (if the system bus is
+* that wide).
+ */
+#define DMI_SBDATA3_DATA_OFFSET             0
+#define DMI_SBDATA3_DATA_LENGTH             32
+#define DMI_SBDATA3_DATA                    (0xffffffff << DMI_SBDATA3_DATA_OFFSET)
+#define SERINFO                             0x280
+/*
+* Like \Fserialzero.
+ */
+#define SERINFO_SERIAL7_OFFSET              7
+#define SERINFO_SERIAL7_LENGTH              1
+#define SERINFO_SERIAL7                     (0x1 << SERINFO_SERIAL7_OFFSET)
+/*
+* Like \Fserialzero.
+ */
+#define SERINFO_SERIAL6_OFFSET              6
+#define SERINFO_SERIAL6_LENGTH              1
+#define SERINFO_SERIAL6                     (0x1 << SERINFO_SERIAL6_OFFSET)
+/*
+* Like \Fserialzero.
+ */
+#define SERINFO_SERIAL5_OFFSET              5
+#define SERINFO_SERIAL5_LENGTH              1
+#define SERINFO_SERIAL5                     (0x1 << SERINFO_SERIAL5_OFFSET)
+/*
+* Like \Fserialzero.
+ */
+#define SERINFO_SERIAL4_OFFSET              4
+#define SERINFO_SERIAL4_LENGTH              1
+#define SERINFO_SERIAL4                     (0x1 << SERINFO_SERIAL4_OFFSET)
+/*
+* Like \Fserialzero.
+ */
+#define SERINFO_SERIAL3_OFFSET              3
+#define SERINFO_SERIAL3_LENGTH              1
+#define SERINFO_SERIAL3                     (0x1 << SERINFO_SERIAL3_OFFSET)
+/*
+* Like \Fserialzero.
+ */
+#define SERINFO_SERIAL2_OFFSET              2
+#define SERINFO_SERIAL2_LENGTH              1
+#define SERINFO_SERIAL2                     (0x1 << SERINFO_SERIAL2_OFFSET)
+/*
+* Like \Fserialzero.
+ */
+#define SERINFO_SERIAL1_OFFSET              1
+#define SERINFO_SERIAL1_LENGTH              1
+#define SERINFO_SERIAL1                     (0x1 << SERINFO_SERIAL1_OFFSET)
+/*
+* 1 means serial interface 0 is supported.
+ */
+#define SERINFO_SERIAL0_OFFSET              0
+#define SERINFO_SERIAL0_LENGTH              1
+#define SERINFO_SERIAL0                     (0x1 << SERINFO_SERIAL0_OFFSET)
+#define SERSEND0                            0x200
+#define SERRECV0                            0x204
+#define SERSTAT0                            0x208
+/*
+* Send ready. 1 when the core-to-debugger queue is not full. 0
+* otherwise.
+ */
+#define SERSTAT0_SENDR_OFFSET               1
+#define SERSTAT0_SENDR_LENGTH               1
+#define SERSTAT0_SENDR                      (0x1 << SERSTAT0_SENDR_OFFSET)
+/*
+* Receive ready. 1 when the debugger-to-core queue is not empty. 0
+* otherwise.
+ */
+#define SERSTAT0_RECVR_OFFSET               0
+#define SERSTAT0_RECVR_LENGTH               1
+#define SERSTAT0_RECVR                      (0x1 << SERSTAT0_RECVR_OFFSET)
+#define SERSEND1                            0x210
+#define SERRECV1                            0x214
+#define SERSTAT1                            0x218
+#define SERSEND2                            0x220
+#define SERRECV2                            0x224
+#define SERSTAT2                            0x228
+#define SERSEND3                            0x230
+#define SERRECV3                            0x234
+#define SERSTAT3                            0x238
+#define SERSEND4                            0x240
+#define SERRECV4                            0x244
+#define SERSTAT4                            0x248
+#define SERSEND5                            0x250
+#define SERRECV5                            0x254
+#define SERSTAT5                            0x258
+#define SERSEND6                            0x260
+#define SERRECV6                            0x264
+#define SERSTAT6                            0x268
+#define SERSEND7                            0x274
+#define SERRECV7                            0x278
+#define SERSTAT7                            0x27c
+#define TRACE                               0x728
+/*
+* 1 if the trace buffer has wrapped since the last time \Fdiscard was
+* written. 0 otherwise.
+ */
+#define TRACE_WRAPPED_OFFSET                24
+#define TRACE_WRAPPED_LENGTH                1
+#define TRACE_WRAPPED                       (0x1 << TRACE_WRAPPED_OFFSET)
+/*
+* Emit Timestamp trace sequences.
+ */
+#define TRACE_EMITTIMESTAMP_OFFSET          23
+#define TRACE_EMITTIMESTAMP_LENGTH          1
+#define TRACE_EMITTIMESTAMP                 (0x1 << TRACE_EMITTIMESTAMP_OFFSET)
+/*
+* Emit Store Data trace sequences.
+ */
+#define TRACE_EMITSTOREDATA_OFFSET          22
+#define TRACE_EMITSTOREDATA_LENGTH          1
+#define TRACE_EMITSTOREDATA                 (0x1 << TRACE_EMITSTOREDATA_OFFSET)
+/*
+* Emit Load Data trace sequences.
+ */
+#define TRACE_EMITLOADDATA_OFFSET           21
+#define TRACE_EMITLOADDATA_LENGTH           1
+#define TRACE_EMITLOADDATA                  (0x1 << TRACE_EMITLOADDATA_OFFSET)
+/*
+* Emit Store Address trace sequences.
+ */
+#define TRACE_EMITSTOREADDR_OFFSET          20
+#define TRACE_EMITSTOREADDR_LENGTH          1
+#define TRACE_EMITSTOREADDR                 (0x1 << TRACE_EMITSTOREADDR_OFFSET)
+/*
+* Emit Load Address trace sequences.
+ */
+#define TRACE_EMITLOADADDR_OFFSET           19
+#define TRACE_EMITLOADADDR_LENGTH           1
+#define TRACE_EMITLOADADDR                  (0x1 << TRACE_EMITLOADADDR_OFFSET)
+/*
+* Emit Privilege Level trace sequences.
+ */
+#define TRACE_EMITPRIV_OFFSET               18
+#define TRACE_EMITPRIV_LENGTH               1
+#define TRACE_EMITPRIV                      (0x1 << TRACE_EMITPRIV_OFFSET)
+/*
+* Emit Branch Taken and Branch Not Taken trace sequences.
+ */
+#define TRACE_EMITBRANCH_OFFSET             17
+#define TRACE_EMITBRANCH_LENGTH             1
+#define TRACE_EMITBRANCH                    (0x1 << TRACE_EMITBRANCH_OFFSET)
+/*
+* Emit PC trace sequences.
+ */
+#define TRACE_EMITPC_OFFSET                 16
+#define TRACE_EMITPC_LENGTH                 1
+#define TRACE_EMITPC                        (0x1 << TRACE_EMITPC_OFFSET)
+/*
+* Determine what happens when the trace buffer is full.  0 means wrap
+* and overwrite. 1 means turn off trace until \Fdiscard is written as 1.
+* 2 means cause a trace full exception. 3 is reserved for future use.
+ */
+#define TRACE_FULLACTION_OFFSET             8
+#define TRACE_FULLACTION_LENGTH             2
+#define TRACE_FULLACTION                    (0x3 << TRACE_FULLACTION_OFFSET)
+/*
+* 0: Trace to a dedicated on-core RAM (which is not further defined in
+* this spec).
+*
+* 1: Trace to RAM on the system bus.
+*
+* 2: Send trace data to a dedicated off-chip interface (which is not
+* defined in this spec). This does not affect execution speed.
+*
+* 3: Reserved for future use.
+*
+* Options 0 and 1 slow down execution (eg. because of system bus
+* contention).
+ */
+#define TRACE_DESTINATION_OFFSET            4
+#define TRACE_DESTINATION_LENGTH            2
+#define TRACE_DESTINATION                   (0x3 << TRACE_DESTINATION_OFFSET)
+/*
+* When 1, the trace logic may stall processor execution to ensure it
+* can emit all the trace sequences required. When 0 individual trace
+* sequences may be dropped.
+ */
+#define TRACE_STALL_OFFSET                  2
+#define TRACE_STALL_LENGTH                  1
+#define TRACE_STALL                         (0x1 << TRACE_STALL_OFFSET)
+/*
+* Writing 1 to this bit tells the trace logic that any trace
+* collected is no longer required. When tracing to RAM, it resets the
+* trace write pointer to the start of the memory, as well as
+* \Fwrapped.
+ */
+#define TRACE_DISCARD_OFFSET                1
+#define TRACE_DISCARD_LENGTH                1
+#define TRACE_DISCARD                       (0x1 << TRACE_DISCARD_OFFSET)
+#define TRACE_SUPPORTED_OFFSET              0
+#define TRACE_SUPPORTED_LENGTH              1
+#define TRACE_SUPPORTED                     (0x1 << TRACE_SUPPORTED_OFFSET)
+#define TBUFSTART                           0x729
+#define TBUFEND                             0x72a
+#define TBUFWRITE                           0x72b
+#define SHORTNAME                           0x123
+/*
+* Description of what this field is used for.
+ */
+#define SHORTNAME_FIELD_OFFSET              0
+#define SHORTNAME_FIELD_LENGTH              8
+#define SHORTNAME_FIELD                     (0xff << SHORTNAME_FIELD_OFFSET)
+#define AC_ACCESS_REGISTER                  None
+/*
+* This is 0 to indicate Access Register Command.
+ */
+#define AC_ACCESS_REGISTER_CMDTYPE_OFFSET   24
+#define AC_ACCESS_REGISTER_CMDTYPE_LENGTH   8
+#define AC_ACCESS_REGISTER_CMDTYPE          (0xff << AC_ACCESS_REGISTER_CMDTYPE_OFFSET)
+/*
+* 2: Access the lowest 32 bits of the register.
+*
+* 3: Access the lowest 64 bits of the register.
+*
+* 4: Access the lowest 128 bits of the register.
+*
+* If \Fsize specifies a size larger than the register's actual size,
+* then the access must fail. If a register is accessible, then reads of \Fsize
+* less than or equal to the register's actual size must be supported.
+ */
+#define AC_ACCESS_REGISTER_SIZE_OFFSET      20
+#define AC_ACCESS_REGISTER_SIZE_LENGTH      3
+#define AC_ACCESS_REGISTER_SIZE             (0x7 << AC_ACCESS_REGISTER_SIZE_OFFSET)
+/*
+* When 1, execute the program in the Program Buffer exactly once
+* before performing the transfer.
+* \textbf{WARNING: preexec is considered for removal.}
+ */
+#define AC_ACCESS_REGISTER_PREEXEC_OFFSET   19
+#define AC_ACCESS_REGISTER_PREEXEC_LENGTH   1
+#define AC_ACCESS_REGISTER_PREEXEC          (0x1 << AC_ACCESS_REGISTER_PREEXEC_OFFSET)
+/*
+* When 1, execute the program in the Program Buffer exactly once
+* after performing the transfer, if any.
+ */
+#define AC_ACCESS_REGISTER_POSTEXEC_OFFSET  18
+#define AC_ACCESS_REGISTER_POSTEXEC_LENGTH  1
+#define AC_ACCESS_REGISTER_POSTEXEC         (0x1 << AC_ACCESS_REGISTER_POSTEXEC_OFFSET)
+/*
+* 0: Don't do the operation specified by \Fwrite.
+*
+* 1: Do the operation specified by \Fwrite.
+ */
+#define AC_ACCESS_REGISTER_TRANSFER_OFFSET  17
+#define AC_ACCESS_REGISTER_TRANSFER_LENGTH  1
+#define AC_ACCESS_REGISTER_TRANSFER         (0x1 << AC_ACCESS_REGISTER_TRANSFER_OFFSET)
+/*
+* When \Ftransfer is set:
+* 0: Copy data from the specified register into {\tt arg0} portion
+* of {\tt data}.
+*
+* 1: Copy data from {\tt arg0} portion of {\tt data} into the
+* specified register.
+ */
+#define AC_ACCESS_REGISTER_WRITE_OFFSET     16
+#define AC_ACCESS_REGISTER_WRITE_LENGTH     1
+#define AC_ACCESS_REGISTER_WRITE            (0x1 << AC_ACCESS_REGISTER_WRITE_OFFSET)
+/*
+* Number of the register to access, as described in Table~\ref{tab:regno}.
+ */
+#define AC_ACCESS_REGISTER_REGNO_OFFSET     0
+#define AC_ACCESS_REGISTER_REGNO_LENGTH     16
+#define AC_ACCESS_REGISTER_REGNO            (0xffff << AC_ACCESS_REGISTER_REGNO_OFFSET)
+#define AC_QUICK_ACCESS                     None
+/*
+* This is 1 to indicate Quick Access command.
+ */
+#define AC_QUICK_ACCESS_CMDTYPE_OFFSET      24
+#define AC_QUICK_ACCESS_CMDTYPE_LENGTH      8
+#define AC_QUICK_ACCESS_CMDTYPE             (0xff << AC_QUICK_ACCESS_CMDTYPE_OFFSET)
index 8bcc60eada8d9eb5fbbdd8833e2463a16ae72c09..43dc7372bcd896bb4a11cb7ce3e38f5003c95ef5 100644 (file)
 #include <cassert>
 
 #include "debug_module.h"
+#include "debug_defines.h"
+#include "opcodes.h"
 #include "mmu.h"
 
 #include "debug_rom/debug_rom.h"
 
-bool debug_module_t::load(reg_t addr, size_t len, uint8_t* bytes)
+#if 1
+#  define D(x) x
+#else
+#  define D(x)
+#endif
+
+///////////////////////// debug_module_data_t
+
+debug_module_data_t::debug_module_data_t()
 {
-  addr = DEBUG_START + addr;
+  memset(data, 0, sizeof(data));
+}
 
-  if (addr >= DEBUG_RAM_START && addr + len <= DEBUG_RAM_END) {
-    memcpy(bytes, debug_ram + addr - DEBUG_RAM_START, len);
+bool debug_module_data_t::load(reg_t addr, size_t len, uint8_t* bytes)
+{
+  if (addr + len < sizeof(data)) {
+    memcpy(bytes, data + addr, len);
     return true;
   }
 
-  if (addr >= DEBUG_ROM_START && addr + len <= DEBUG_ROM_END) {
-    memcpy(bytes, debug_rom_raw + addr - DEBUG_ROM_START, len);
+  fprintf(stderr, "ERROR: invalid load from debug_module_data_t: %zd bytes at 0x%016"
+          PRIx64 "\n", len, addr);
+
+  return false;
+}
+
+bool debug_module_data_t::store(reg_t addr, size_t len, const uint8_t* bytes)
+{
+  D(fprintf(stderr, "debug_module_data_t store 0x%lx bytes at 0x%lx\n", len,
+        addr));
+
+  if (addr + len < sizeof(data)) {
+    memcpy(data + addr, bytes, len);
     return true;
   }
 
-  fprintf(stderr, "ERROR: invalid load from debug module: %zd bytes at 0x%016"
+  fprintf(stderr, "ERROR: invalid store to debug_module_data_t: %zd bytes at 0x%016"
           PRIx64 "\n", len, addr);
   return false;
 }
 
-bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes)
+uint32_t debug_module_data_t::read32(reg_t addr) const
+{
+  assert(addr + 4 <= sizeof(data));
+  return data[addr] |
+    (data[addr + 1] << 8) |
+    (data[addr + 2] << 16) |
+    (data[addr + 3] << 24);
+}
+
+void debug_module_data_t::write32(reg_t addr, uint32_t value)
+{
+  fprintf(stderr, "debug_module_data_t::write32(0x%lx, 0x%x)\n", addr, value);
+  assert(addr + 4 <= sizeof(data));
+  data[addr] = value & 0xff;
+  data[addr + 1] = (value >> 8) & 0xff;
+  data[addr + 2] = (value >> 16) & 0xff;
+  data[addr + 3] = (value >> 24) & 0xff;
+}
+
+///////////////////////// debug_module_t
+
+debug_module_t::debug_module_t(sim_t *sim) : sim(sim),
+  next_action(jal(ZERO, 0)),
+  action_executed(false)
+{
+  dmcontrol = {0};
+
+  dmstatus = {0};
+  dmstatus.authenticated = 1;
+  dmstatus.versionlo = 2;
+
+  abstractcs = {0};
+  abstractcs.progsize = progsize;
+
+  abstractauto = {0};
+
+  for (unsigned i = 0; i < DEBUG_ROM_ENTRY_SIZE / 4; i++) {
+    write32(debug_rom_entry, i, jal(ZERO, 0));
+    halted[i] = false;
+  }
+
+  memset(program_buffer, 0, sizeof(program_buffer));
+}
+
+void debug_module_t::reset()
+{
+  for (unsigned i = 0; i < sim->nprocs(); i++) {
+    processor_t *proc = sim->get_core(i);
+    if (proc)
+      proc->halt_request = false;
+  }
+
+  dmcontrol = {0};
+
+  dmstatus = {0};
+  dmstatus.authenticated = 1;
+  dmstatus.versionlo = 2;
+
+  abstractcs = {0};
+  abstractcs.datacount = sizeof(dmdata.data) / 4;
+  abstractcs.progsize = progsize;
+
+  abstractauto = {0};
+}
+
+void debug_module_t::add_device(bus_t *bus) {
+  bus->add_device(DEBUG_START, this);
+  bus->add_device(DEBUG_EXCHANGE, &dmdata);
+}
+
+bool debug_module_t::load(reg_t addr, size_t len, uint8_t* bytes)
 {
   addr = DEBUG_START + addr;
 
-  if (addr & (len-1)) {
-    fprintf(stderr, "ERROR: unaligned store to debug module: %zd bytes at 0x%016"
-            PRIx64 "\n", len, addr);
-    return false;
+  if (addr >= DEBUG_ROM_ENTRY &&
+      addr < DEBUG_ROM_ENTRY + DEBUG_ROM_ENTRY_SIZE) {
+
+    if (read32(debug_rom_entry, dmcontrol.hartsel) == jal(ZERO, 0)) {
+      // We're here in an infinite loop. That means that whatever abstract
+      // command has complete.
+      abstractcs.busy = false;
+    }
+
+    action_executed = true;
+
+    halted[(addr - DEBUG_ROM_ENTRY) / 4] = true;
+    memcpy(bytes, debug_rom_entry + addr - DEBUG_ROM_ENTRY, len);
+    return true;
+  }
+
+  if (action_executed) {
+    // Restore the jump-to-self loop.
+    write32(debug_rom_entry, dmcontrol.hartsel, next_action);
+    next_action = jal(ZERO, 0);
+    action_executed = false;
   }
 
-  if (addr >= DEBUG_RAM_START && addr + len <= DEBUG_RAM_END) {
-    memcpy(debug_ram + addr - DEBUG_RAM_START, bytes, len);
+  if (addr >= DEBUG_ROM_CODE &&
+      addr < DEBUG_ROM_CODE + DEBUG_ROM_CODE_SIZE) {
+
+    if (read32(debug_rom_code, 0) == dret()) {
+      abstractcs.busy = false;
+      halted[dmcontrol.hartsel] = false;
+    }
+
+    memcpy(bytes, debug_rom_code + addr - DEBUG_ROM_CODE, len);
     return true;
-  } else if (len == 4 && addr == DEBUG_CLEARDEBINT) {
-    clear_interrupt(bytes[0] | (bytes[1] << 8) |
-        (bytes[2] << 16) | (bytes[3] << 24));
+  }
+
+  if (addr >= DEBUG_RAM_START && addr < DEBUG_RAM_END) {
+    memcpy(bytes, program_buffer + addr - DEBUG_RAM_START, len);
     return true;
-  } else if (len == 4 && addr == DEBUG_SETHALTNOT) {
-    set_halt_notification(bytes[0] | (bytes[1] << 8) |
-        (bytes[2] << 16) | (bytes[3] << 24));
+  }
+
+  if (addr >= DEBUG_ROM_EXCEPTION &&
+      addr < DEBUG_ROM_EXCEPTION + DEBUG_ROM_EXCEPTION_SIZE) {
+    memcpy(bytes, debug_rom_exception + addr - DEBUG_ROM_EXCEPTION, len);
+    if (abstractcs.cmderr == abstractcs.CMDERR_NONE) {
+      abstractcs.cmderr = abstractcs.CMDERR_EXCEPTION;
+    }
+    return true;
+  }
+
+  fprintf(stderr, "ERROR: invalid load from debug module: %zd bytes at 0x%016"
+          PRIx64 "\n", len, addr);
+
+  return false;
+}
+
+bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes)
+{
+  addr = DEBUG_START + addr;
+
+  if (addr >= DEBUG_RAM_START && addr < DEBUG_RAM_END) {
+    memcpy(program_buffer + addr - DEBUG_RAM_START, bytes, len);
     return true;
   }
 
@@ -52,23 +191,262 @@ bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes)
   return false;
 }
 
-void debug_module_t::ram_write32(unsigned int index, uint32_t value)
+void debug_module_t::write32(uint8_t *memory, unsigned int index, uint32_t value)
 {
-  char* base = debug_ram + index * 4;
+  uint8_t* base = memory + index * 4;
   base[0] = value & 0xff;
   base[1] = (value >> 8) & 0xff;
   base[2] = (value >> 16) & 0xff;
   base[3] = (value >> 24) & 0xff;
 }
 
-uint32_t debug_module_t::ram_read32(unsigned int index)
+uint32_t debug_module_t::read32(uint8_t *memory, unsigned int index)
 {
-  // It'd be better for raw_page (and all memory) to be unsigned chars, but mem
-  // in sim_t is just chars, so I'm following that convention.
-  unsigned char* base = (unsigned char*) (debug_ram + index * 4);
+  uint8_t* base = memory + index * 4;
   uint32_t value = ((uint32_t) base[0]) |
     (((uint32_t) base[1]) << 8) |
     (((uint32_t) base[2]) << 16) |
     (((uint32_t) base[3]) << 24);
   return value;
 }
+
+processor_t *debug_module_t::current_proc() const
+{
+  processor_t *proc = NULL;
+  try {
+    proc = sim->get_core(dmcontrol.hartsel);
+  } catch (const std::out_of_range&) {
+  }
+  return proc;
+}
+
+bool debug_module_t::dmi_read(unsigned address, uint32_t *value)
+{
+  uint32_t result = 0;
+  D(fprintf(stderr, "dmi_read(0x%x) -> ", address));
+  if (address >= DMI_DATA0 && address < DMI_DATA0 + abstractcs.datacount) {
+    unsigned i = address - DMI_DATA0;
+    result = dmdata.read32(4 * i);
+
+    if (abstractcs.busy && abstractcs.cmderr == abstractcs.CMDERR_NONE) {
+      abstractcs.cmderr = abstractcs.CMDERR_BUSY;
+    }
+
+    if ((abstractauto.autoexecdata >> i) & 1)
+      perform_abstract_command();
+  } else if (address >= DMI_PROGBUF0 && address < DMI_PROGBUF0 + progsize) {
+    result = read32(program_buffer, address - DMI_PROGBUF0);
+  } else {
+    switch (address) {
+      case DMI_DMCONTROL:
+        {
+          processor_t *proc = current_proc();
+          if (proc)
+            dmcontrol.haltreq = proc->halt_request;
+
+          result = set_field(result, DMI_DMCONTROL_HALTREQ, dmcontrol.haltreq);
+          result = set_field(result, DMI_DMCONTROL_RESUMEREQ, dmcontrol.resumereq);
+          result = set_field(result, DMI_DMCONTROL_HARTSEL, dmcontrol.hartsel);
+          result = set_field(result, DMI_DMCONTROL_HARTRESET, dmcontrol.hartreset);
+         result = set_field(result, DMI_DMCONTROL_NDMRESET, dmcontrol.ndmreset);
+          result = set_field(result, DMI_DMCONTROL_DMACTIVE, dmcontrol.dmactive);
+        }
+        break;
+      case DMI_DMSTATUS:
+        {
+          processor_t *proc = current_proc();
+
+         dmstatus.allnonexistant = false;
+         dmstatus.allunavail = false;
+         dmstatus.allrunning = false;
+         dmstatus.allhalted = false;
+          if (proc) {
+            if (halted[dmcontrol.hartsel]) {
+              dmstatus.allhalted = true;
+            } else {
+              dmstatus.allrunning = true;
+            }
+          } else {
+           dmstatus.allnonexistant = true;
+          }
+         dmstatus.anynonexistant = dmstatus.allnonexistant;
+         dmstatus.anyunavail = dmstatus.allunavail;
+         dmstatus.anyrunning = dmstatus.allrunning;
+         dmstatus.anyhalted = dmstatus.allhalted;
+
+         result = set_field(result, DMI_DMSTATUS_ALLNONEXISTENT, dmstatus.allnonexistant);
+         result = set_field(result, DMI_DMSTATUS_ALLUNAVAIL, dmstatus.allunavail);
+         result = set_field(result, DMI_DMSTATUS_ALLRUNNING, dmstatus.allrunning);
+         result = set_field(result, DMI_DMSTATUS_ALLHALTED, dmstatus.allhalted);
+         result = set_field(result, DMI_DMSTATUS_ANYNONEXISTENT, dmstatus.anynonexistant);
+         result = set_field(result, DMI_DMSTATUS_ANYUNAVAIL, dmstatus.anyunavail);
+         result = set_field(result, DMI_DMSTATUS_ANYRUNNING, dmstatus.anyrunning);
+         result = set_field(result, DMI_DMSTATUS_ANYHALTED, dmstatus.anyhalted);
+          result = set_field(result, DMI_DMSTATUS_AUTHENTICATED, dmstatus.authenticated);
+          result = set_field(result, DMI_DMSTATUS_AUTHBUSY, dmstatus.authbusy);
+          result = set_field(result, DMI_DMSTATUS_VERSIONHI, dmstatus.versionhi);
+          result = set_field(result, DMI_DMSTATUS_VERSIONLO, dmstatus.versionlo);
+        }
+       break;
+      case DMI_ABSTRACTCS:
+        result = set_field(result, DMI_ABSTRACTCS_CMDERR, abstractcs.cmderr);
+        result = set_field(result, DMI_ABSTRACTCS_BUSY, abstractcs.busy);
+        result = set_field(result, DMI_ABSTRACTCS_DATACOUNT, abstractcs.datacount);
+        result = set_field(result, DMI_ABSTRACTCS_PROGSIZE, abstractcs.progsize);
+        break;
+      case DMI_ABSTRACTAUTO:
+        result = set_field(result, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF, abstractauto.autoexecprogbuf);
+        result = set_field(result, DMI_ABSTRACTAUTO_AUTOEXECDATA, abstractauto.autoexecdata);
+        break;
+      case DMI_COMMAND:
+        result = 0;
+        break;
+      default:
+        D(fprintf(stderr, "error\n"));
+        return false;
+    }
+  }
+  D(fprintf(stderr, "0x%x\n", result));
+  *value = result;
+  return true;
+}
+
+bool debug_module_t::perform_abstract_command()
+{
+  if (abstractcs.cmderr != abstractcs.CMDERR_NONE)
+    return true;
+  if (abstractcs.busy) {
+    abstractcs.cmderr = abstractcs.CMDERR_BUSY;
+    return true;
+  }
+
+  if ((command >> 24) == 0) {
+    // register access
+    unsigned size = get_field(command, AC_ACCESS_REGISTER_SIZE);
+    bool write = get_field(command, AC_ACCESS_REGISTER_WRITE);
+    unsigned regno = get_field(command, AC_ACCESS_REGISTER_REGNO);
+
+    if (regno < 0x1000 || regno >= 0x1020) {
+      abstractcs.cmderr = abstractcs.CMDERR_NOTSUP;
+      return true;
+    }
+
+    unsigned regnum = regno - 0x1000;
+
+    if (!halted[dmcontrol.hartsel]) {
+      abstractcs.cmderr = abstractcs.CMDERR_HALTRESUME;
+      return true;
+    }
+
+    switch (size) {
+      case 2:
+        if (write)
+          write32(debug_rom_code, 0, lw(regnum, ZERO, DEBUG_EXCHANGE));
+        else
+          write32(debug_rom_code, 0, sw(regnum, ZERO, DEBUG_EXCHANGE));
+        break;
+      case 3:
+        if (write)
+          write32(debug_rom_code, 0, ld(regnum, ZERO, DEBUG_EXCHANGE));
+        else
+          write32(debug_rom_code, 0, sd(regnum, ZERO, DEBUG_EXCHANGE));
+        break;
+      /*
+      case 4:
+        if (write)
+          write32(debug_rom_code, 0, lq(regnum, ZERO, DEBUG_EXCHANGE));
+        else
+          write32(debug_rom_code, 0, sq(regnum, ZERO, DEBUG_EXCHANGE));
+        break;
+        */
+      default:
+        abstractcs.cmderr = abstractcs.CMDERR_NOTSUP;
+        return true;
+    }
+    if (get_field(command, AC_ACCESS_REGISTER_POSTEXEC)) {
+      write32(debug_rom_code, 1, jal(ZERO, DEBUG_RAM_START - DEBUG_ROM_CODE - 4));
+    } else {
+      write32(debug_rom_code, 1, ebreak());
+    }
+
+    if (get_field(command, AC_ACCESS_REGISTER_PREEXEC)) {
+      write32(debug_rom_entry, dmcontrol.hartsel,
+          jal(ZERO, DEBUG_RAM_START - (DEBUG_ROM_ENTRY + 4 * dmcontrol.hartsel)));
+      next_action =
+        jal(ZERO, DEBUG_ROM_CODE - (DEBUG_ROM_ENTRY + 4 * dmcontrol.hartsel));
+    } else {
+      write32(debug_rom_entry, dmcontrol.hartsel,
+          jal(ZERO, DEBUG_ROM_CODE - (DEBUG_ROM_ENTRY + 4 * dmcontrol.hartsel)));
+    }
+
+    write32(debug_rom_exception, dmcontrol.hartsel,
+        jal(ZERO, (DEBUG_ROM_ENTRY + 4 * dmcontrol.hartsel) - DEBUG_ROM_EXCEPTION));
+    abstractcs.busy = true;
+  } else {
+    abstractcs.cmderr = abstractcs.CMDERR_NOTSUP;
+  }
+  return true;
+}
+
+bool debug_module_t::dmi_write(unsigned address, uint32_t value)
+{
+  D(fprintf(stderr, "dmi_write(0x%x, 0x%x)\n", address, value));
+  if (address >= DMI_DATA0 && address < DMI_DATA0 + abstractcs.datacount) {
+    unsigned i = address - DMI_DATA0;
+    dmdata.write32(4 * i, value);
+
+    if (abstractcs.busy && abstractcs.cmderr == abstractcs.CMDERR_NONE) {
+      abstractcs.cmderr = abstractcs.CMDERR_BUSY;
+    }
+
+    if ((abstractauto.autoexecdata >> i) & 1)
+      perform_abstract_command();
+    return true;
+
+  } else if (address >= DMI_PROGBUF0 && address < DMI_PROGBUF0 + progsize) {
+    write32(program_buffer, address - DMI_PROGBUF0, value);
+    return true;
+  } else {
+    switch (address) {
+      case DMI_DMCONTROL:
+        {
+          dmcontrol.dmactive = get_field(value, DMI_DMCONTROL_DMACTIVE);
+          if (dmcontrol.dmactive) {
+            dmcontrol.haltreq = get_field(value, DMI_DMCONTROL_HALTREQ);
+            dmcontrol.resumereq = get_field(value, DMI_DMCONTROL_RESUMEREQ);
+            dmcontrol.ndmreset = get_field(value, DMI_DMCONTROL_NDMRESET);
+            dmcontrol.hartsel = get_field(value, DMI_DMCONTROL_HARTSEL);
+          } else {
+            reset();
+          }
+          processor_t *proc = current_proc();
+          if (proc) {
+            proc->halt_request = dmcontrol.haltreq;
+            if (dmcontrol.resumereq) {
+              write32(debug_rom_code, 0, dret());
+              write32(debug_rom_entry, dmcontrol.hartsel,
+                  jal(ZERO, DEBUG_ROM_CODE - (DEBUG_ROM_ENTRY + 4 * dmcontrol.hartsel)));
+              abstractcs.busy = true;
+            }
+          }
+        }
+        return true;
+
+      case DMI_COMMAND:
+        command = value;
+        return perform_abstract_command();
+
+      case DMI_ABSTRACTCS:
+        if (get_field(value, DMI_ABSTRACTCS_CMDERR) == abstractcs.CMDERR_NONE) {
+          abstractcs.cmderr = abstractcs.CMDERR_NONE;
+        }
+        return true;
+
+      case DMI_ABSTRACTAUTO:
+        abstractauto.autoexecprogbuf = get_field(value, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF);
+        abstractauto.autoexecdata = get_field(value, DMI_ABSTRACTAUTO_AUTOEXECDATA);
+        break;
+    }
+  }
+  return false;
+}
index 53b32db9a8e6eebadaa88f3c1d2e7ead2c6b0949..ca3ff312600ce00b434f776dba420562bea0b3b3 100644 (file)
 
 #include "devices.h"
 
+class sim_t;
+
+typedef struct {
+  bool haltreq;
+  bool resumereq;
+  unsigned hartsel;
+  bool hartreset;
+  bool dmactive;
+  bool ndmreset;
+} dmcontrol_t;
+
+typedef struct {
+  bool allnonexistant;
+  bool anynonexistant;
+  bool allunavail;
+  bool anyunavail;
+  bool allrunning;
+  bool anyrunning;
+  bool allhalted;
+  bool anyhalted;
+  bool authenticated;
+  bool authbusy;
+  bool cfgstrvalid;
+  unsigned versionhi;
+  unsigned versionlo;
+} dmstatus_t;
+
+typedef struct {
+  bool busy;
+  unsigned datacount;
+  unsigned progsize;
+  enum {
+    CMDERR_NONE = 0,
+    CMDERR_BUSY = 1,
+    CMDERR_NOTSUP = 2,
+    CMDERR_EXCEPTION = 3,
+    CMDERR_HALTRESUME = 4,
+    CMDERR_OTHER = 7
+  } cmderr;
+} abstractcs_t;
+
+typedef struct {
+  unsigned autoexecprogbuf;
+  unsigned autoexecdata;
+} abstractauto_t;
+
+class debug_module_data_t : public abstract_device_t
+{
+  public:
+    debug_module_data_t();
+
+    bool load(reg_t addr, size_t len, uint8_t* bytes);
+    bool store(reg_t addr, size_t len, const uint8_t* bytes);
+
+    uint32_t read32(reg_t addr) const;
+    void write32(reg_t addr, uint32_t value);
+
+    uint8_t data[DEBUG_EXCHANGE_SIZE];
+};
+
 class debug_module_t : public abstract_device_t
 {
   public:
+    debug_module_t(sim_t *sim);
+
+    void add_device(bus_t *bus);
+
     bool load(reg_t addr, size_t len, uint8_t* bytes);
     bool store(reg_t addr, size_t len, const uint8_t* bytes);
 
-    void ram_write32(unsigned int index, uint32_t value);
-    uint32_t ram_read32(unsigned int index);
-
-    void set_interrupt(uint32_t hartid) {
-      interrupt.insert(hartid);
-    }
-    void clear_interrupt(uint32_t hartid) {
-      interrupt.erase(hartid);
-    }
-    bool get_interrupt(uint32_t hartid) const {
-      return interrupt.find(hartid) != interrupt.end();
-    }
-
-    void set_halt_notification(uint32_t hartid) {
-      halt_notification.insert(hartid);
-    }
-    void clear_halt_notification(uint32_t hartid) {
-      halt_notification.erase(hartid);
-    }
-    bool get_halt_notification(uint32_t hartid) const {
-      return halt_notification.find(hartid) != halt_notification.end();
-    }
+    // Debug Module Interface that the debugger (in our case through JTAG DTM)
+    // uses to access the DM.
+    // Return true for success, false for failure.
+    bool dmi_read(unsigned address, uint32_t *value);
+    bool dmi_write(unsigned address, uint32_t value);
 
   private:
-    // Track which interrupts from module to debugger are set.
-    std::set<uint32_t> interrupt;
-    // Track which halt notifications from debugger to module are set.
-    std::set<uint32_t> halt_notification;
-    char debug_ram[DEBUG_RAM_SIZE];
+    static const unsigned progsize = 8;
+
+    sim_t *sim;
+
+    uint8_t debug_rom_entry[DEBUG_ROM_ENTRY_SIZE];
+    uint8_t debug_rom_code[DEBUG_ROM_CODE_SIZE];
+    uint8_t debug_rom_exception[DEBUG_ROM_EXCEPTION_SIZE];
+    uint8_t program_buffer[progsize * 4];
+    bool halted[1024];
+    debug_module_data_t dmdata;
+    // Instruction that will be placed at the current hart's ROM entry address
+    // after the current action has completed.
+    uint32_t next_action;
+    bool action_executed;
+
+    void write32(uint8_t *rom, unsigned int index, uint32_t value);
+    uint32_t read32(uint8_t *rom, unsigned int index);
+
+    dmcontrol_t dmcontrol;
+    dmstatus_t dmstatus;
+    abstractcs_t abstractcs;
+    abstractauto_t abstractauto;
+    uint32_t command;
+
+    processor_t *current_proc() const;
+    void reset();
+    bool perform_abstract_command();
 };
 
 #endif
index c3487b103a25906575d2806f3646f2fe6da203bb..7667b273a7339af4a3d23413a807062b901779aa 100644 (file)
@@ -246,17 +246,19 @@ inline freg_t freg(freg_t f) { return f; }
     throw trap_illegal_instruction(0); \
   (which); })
 
-#define DEBUG_START             0x100
-#define DEBUG_ROM_START         0x800
-#define DEBUG_ROM_RESUME        (DEBUG_ROM_START + 4)
-#define DEBUG_ROM_EXCEPTION     (DEBUG_ROM_START + 8)
-#define DEBUG_ROM_END           (DEBUG_ROM_START + debug_rom_raw_len)
-#define DEBUG_RAM_START         0x400
+#define DEBUG_START             0x20000
+#define DEBUG_ROM_ENTRY         DEBUG_START
+#define DEBUG_ROM_ENTRY_SIZE    (1024 * 4)
+#define DEBUG_ROM_CODE          (DEBUG_ROM_ENTRY + DEBUG_ROM_ENTRY_SIZE)
+#define DEBUG_ROM_CODE_SIZE     256
+#define DEBUG_ROM_EXCEPTION     (DEBUG_ROM_CODE + DEBUG_ROM_CODE_SIZE)
+#define DEBUG_ROM_EXCEPTION_SIZE        4
+#define DEBUG_RAM_START         (DEBUG_ROM_EXCEPTION + DEBUG_ROM_EXCEPTION_SIZE)
 #define DEBUG_RAM_SIZE          64
 #define DEBUG_RAM_END           (DEBUG_RAM_START + DEBUG_RAM_SIZE)
-#define DEBUG_END               0xfff
-#define DEBUG_CLEARDEBINT       0x100
-#define DEBUG_SETHALTNOT        0x10c
-#define DEBUG_SIZE              (DEBUG_END - DEBUG_START + 1)
+#define DEBUG_END               DEBUG_RAM_END
+
+#define DEBUG_EXCHANGE          0x400
+#define DEBUG_EXCHANGE_SIZE     0x20
 
 #endif
index 1b53ccf7c3e4eeff9dfcf426f3b3024d5f354d99..7734ca2749d6756ca2270e6c359a3d28db712ec9 100644 (file)
@@ -63,16 +63,11 @@ bool processor_t::slow_path()
 void processor_t::step(size_t n)
 {
   if (state.dcsr.cause == DCSR_CAUSE_NONE) {
-    // TODO: get_interrupt() isn't super fast. Does that matter?
-    if (sim->debug_module.get_interrupt(id)) {
+    if (halt_request) {
       enter_debug_mode(DCSR_CAUSE_DEBUGINT);
     } else if (state.dcsr.halt) {
       enter_debug_mode(DCSR_CAUSE_HALT);
     }
-  } else {
-    // In Debug Mode, just do 11 steps at a time. Otherwise we're going to be
-    // spinning the rest of the time anyway.
-    n = std::min(n, (size_t) 11);
   }
 
   while (n > 0) {
@@ -120,6 +115,13 @@ void processor_t::step(size_t n)
             // enter_debug_mode changed state.pc, so we can't just continue.
             break;
           }
+
+          if (unlikely(state.pc >= DEBUG_ROM_ENTRY &&
+                state.pc < DEBUG_ROM_ENTRY + DEBUG_ROM_ENTRY_SIZE)) {
+            // We're spinning waiting for the debugger to tell us something.
+            // Let's go talk to the debugger.
+            return;
+          }
         }
       }
       else while (instret < n)
diff --git a/riscv/gdbserver.cc b/riscv/gdbserver.cc
deleted file mode 100644 (file)
index 01defda..0000000
+++ /dev/null
@@ -1,2163 +0,0 @@
-#include <arpa/inet.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include <cassert>
-#include <cinttypes>
-#include <cstdio>
-#include <vector>
-
-#include "disasm.h"
-#include "sim.h"
-#include "gdbserver.h"
-#include "mmu.h"
-#include "encoding.h"
-
-//////////////////////////////////////// Utility Functions
-
-#undef DEBUG
-#ifdef DEBUG
-#  define D(x) x
-#else
-#  define D(x)
-#endif // DEBUG
-
-void die(const char* msg)
-{
-  fprintf(stderr, "gdbserver code died: %s\n", msg);
-  abort();
-}
-
-// gdb's register list is defined in riscv_gdb_reg_names gdb/riscv-tdep.c in
-// its source tree. We must interpret the numbers the same here.
-enum {
-  REG_XPR0 = 0,
-  REG_XPR31 = 31,
-  REG_PC = 32,
-  REG_FPR0 = 33,
-  REG_FPR31 = 64,
-  REG_CSR0 = 65,
-  REG_MSTATUS = CSR_MSTATUS + REG_CSR0,
-  REG_CSR4095 = 4160,
-  REG_PRIV = 4161
-};
-
-//////////////////////////////////////// Functions to generate RISC-V opcodes.
-
-// TODO: Does this already exist somewhere?
-
-#define ZERO    0
-// Using regnames.cc as source. The RVG Calling Convention of the 2.0 RISC-V
-// spec says it should be 2 and 3.
-#define S0      8
-#define S1      9
-static uint32_t bits(uint32_t value, unsigned int hi, unsigned int lo) {
-  return (value >> lo) & ((1 << (hi+1-lo)) - 1);
-}
-
-static uint32_t bit(uint32_t value, unsigned int b) {
-  return (value >> b) & 1;
-}
-
-static uint32_t jal(unsigned int rd, uint32_t imm) {
-  return (bit(imm, 20) << 31) |
-    (bits(imm, 10, 1) << 21) |
-    (bit(imm, 11) << 20) |
-    (bits(imm, 19, 12) << 12) |
-    (rd << 7) |
-    MATCH_JAL;
-}
-
-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, uint16_t imm) {
-  return (csr << 20) |
-    (bits(imm, 4, 0) << 15) |
-    MATCH_CSRRCI;
-}
-
-static uint32_t csrr(unsigned int rd, unsigned int csr) {
-  return (csr << 20) | (rd << 7) | MATCH_CSRRS;
-}
-
-static uint32_t csrw(unsigned int source, unsigned int csr) {
-  return (csr << 20) | (source << 15) | MATCH_CSRRW;
-}
-
-static uint32_t fence_i()
-{
-  return MATCH_FENCE_I;
-}
-
-static uint32_t sb(unsigned int src, unsigned int base, uint16_t offset)
-{
-  return (bits(offset, 11, 5) << 25) |
-    (src << 20) |
-    (base << 15) |
-    (bits(offset, 4, 0) << 7) |
-    MATCH_SB;
-}
-
-static uint32_t sh(unsigned int src, unsigned int base, uint16_t offset)
-{
-  return (bits(offset, 11, 5) << 25) |
-    (src << 20) |
-    (base << 15) |
-    (bits(offset, 4, 0) << 7) |
-    MATCH_SH;
-}
-
-static uint32_t sw(unsigned int src, unsigned int base, uint16_t offset)
-{
-  return (bits(offset, 11, 5) << 25) |
-    (src << 20) |
-    (base << 15) |
-    (bits(offset, 4, 0) << 7) |
-    MATCH_SW;
-}
-
-static uint32_t sd(unsigned int src, unsigned int base, uint16_t offset)
-{
-  return (bits(offset, 11, 5) << 25) |
-    (bits(src, 4, 0) << 20) |
-    (base << 15) |
-    (bits(offset, 4, 0) << 7) |
-    MATCH_SD;
-}
-
-static uint32_t sq(unsigned int src, unsigned int base, uint16_t offset)
-{
-#if 0
-  return (bits(offset, 11, 5) << 25) |
-    (bits(src, 4, 0) << 20) |
-    (base << 15) |
-    (bits(offset, 4, 0) << 7) |
-    MATCH_SQ;
-#else
-  abort();
-#endif
-}
-
-static uint32_t lq(unsigned int rd, unsigned int base, uint16_t offset)
-{
-#if 0
-  return (bits(offset, 11, 0) << 20) |
-    (base << 15) |
-    (bits(rd, 4, 0) << 7) |
-    MATCH_LQ;
-#else
-  abort();
-#endif
-}
-
-static uint32_t ld(unsigned int rd, unsigned int base, uint16_t offset)
-{
-  return (bits(offset, 11, 0) << 20) |
-    (base << 15) |
-    (bits(rd, 4, 0) << 7) |
-    MATCH_LD;
-}
-
-static uint32_t lw(unsigned int rd, unsigned int base, uint16_t offset)
-{
-  return (bits(offset, 11, 0) << 20) |
-    (base << 15) |
-    (bits(rd, 4, 0) << 7) |
-    MATCH_LW;
-}
-
-static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset)
-{
-  return (bits(offset, 11, 0) << 20) |
-    (base << 15) |
-    (bits(rd, 4, 0) << 7) |
-    MATCH_LH;
-}
-
-static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset)
-{
-  return (bits(offset, 11, 0) << 20) |
-    (base << 15) |
-    (bits(rd, 4, 0) << 7) |
-    MATCH_LB;
-}
-
-static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset)
-{
-  return (bits(offset, 11, 5) << 25) |
-    (bits(src, 4, 0) << 20) |
-    (base << 15) |
-    (bits(offset, 4, 0) << 7) |
-    MATCH_FSW;
-}
-
-static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset)
-{
-  return (bits(offset, 11, 5) << 25) |
-    (bits(src, 4, 0) << 20) |
-    (base << 15) |
-    (bits(offset, 4, 0) << 7) |
-    MATCH_FSD;
-}
-
-static uint32_t flw(unsigned int dest, unsigned int base, uint16_t offset)
-{
-  return (bits(offset, 11, 0) << 20) |
-    (base << 15) |
-    (bits(dest, 4, 0) << 7) |
-    MATCH_FLW;
-}
-
-static uint32_t fld(unsigned int dest, unsigned int base, uint16_t offset)
-{
-  return (bits(offset, 11, 0) << 20) |
-    (base << 15) |
-    (bits(dest, 4, 0) << 7) |
-    MATCH_FLD;
-}
-
-static uint32_t addi(unsigned int dest, unsigned int src, uint16_t imm)
-{
-  return (bits(imm, 11, 0) << 20) |
-    (src << 15) |
-    (dest << 7) |
-    MATCH_ADDI;
-}
-
-static uint32_t ori(unsigned int dest, unsigned int src, uint16_t imm)
-{
-  return (bits(imm, 11, 0) << 20) |
-    (src << 15) |
-    (dest << 7) |
-    MATCH_ORI;
-}
-
-static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm)
-{
-  return (bits(imm, 11, 0) << 20) |
-    (src << 15) |
-    (dest << 7) |
-    MATCH_XORI;
-}
-
-static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt)
-{
-  return (bits(shamt, 4, 0) << 20) |
-    (src << 15) |
-    (dest << 7) |
-    MATCH_SRLI;
-}
-
-
-static uint32_t nop()
-{
-  return addi(0, 0, 0);
-}
-
-template <typename T>
-unsigned int circular_buffer_t<T>::size() const
-{
-  if (end >= start)
-    return end - start;
-  else
-    return end + capacity - start;
-}
-
-template <typename T>
-void circular_buffer_t<T>::consume(unsigned int bytes)
-{
-  start = (start + bytes) % capacity;
-}
-
-template <typename T>
-unsigned int circular_buffer_t<T>::contiguous_empty_size() const
-{
-  if (end >= start)
-    if (start == 0)
-      return capacity - end - 1;
-    else
-      return capacity - end;
-  else
-    return start - end - 1;
-}
-
-template <typename T>
-unsigned int circular_buffer_t<T>::contiguous_data_size() const
-{
-  if (end >= start)
-    return end - start;
-  else
-    return capacity - start;
-}
-
-template <typename T>
-void circular_buffer_t<T>::data_added(unsigned int bytes)
-{
-  end += bytes;
-  assert(end <= capacity);
-  if (end == capacity)
-    end = 0;
-}
-
-template <typename T>
-void circular_buffer_t<T>::reset()
-{
-  start = 0;
-  end = 0;
-}
-
-template <typename T>
-void circular_buffer_t<T>::append(const T *src, unsigned int count)
-{
-  unsigned int copy = std::min(count, contiguous_empty_size());
-  memcpy(contiguous_empty(), src, copy * sizeof(T));
-  data_added(copy);
-  count -= copy;
-  if (count > 0) {
-    assert(count < contiguous_empty_size());
-    memcpy(contiguous_empty(), src+copy, count * sizeof(T));
-    data_added(count);
-  }
-}
-
-////////////////////////////// Debug Operations
-
-class halt_op_t : public operation_t
-{
-  public:
-    halt_op_t(gdbserver_t& gdbserver, bool send_status=false) :
-      operation_t(gdbserver), send_status(send_status),
-      state(ST_ENTER) {};
-
-    void write_dpc_program() {
-      gs.dr_write32(0, csrsi(CSR_DCSR, DCSR_HALT));
-      gs.dr_write32(1, csrr(S0, CSR_DPC));
-      gs.dr_write_store(2, S0, SLOT_DATA0);
-      gs.dr_write_jump(3);
-      gs.set_interrupt(0);
-    }
-
-    bool perform_step(unsigned int step) {
-      switch (state) {
-        gs.tselect_valid = false;
-        case ST_ENTER:
-          if (gs.xlen == 0) {
-            gs.dr_write32(0, xori(S1, ZERO, -1));
-            gs.dr_write32(1, srli(S1, S1, 31));
-            // 0x00000001  0x00000001:ffffffff  0x00000001:ffffffff:ffffffff:ffffffff
-            gs.dr_write32(2, sw(S1, ZERO, DEBUG_RAM_START));
-            gs.dr_write32(3, srli(S1, S1, 31));
-            // 0x00000000  0x00000000:00000003  0x00000000:00000003:ffffffff:ffffffff
-            gs.dr_write32(4, sw(S1, ZERO, DEBUG_RAM_START + 4));
-            gs.dr_write_jump(5);
-            gs.set_interrupt(0);
-            state = ST_XLEN;
-
-          } else {
-            write_dpc_program();
-            state = ST_DPC;
-          }
-          return false;
-
-        case ST_XLEN:
-          {
-            uint32_t word0 = gs.dr_read32(0);
-            uint32_t word1 = gs.dr_read32(1);
-
-            if (word0 == 1 && word1 == 0) {
-              gs.xlen = 32;
-            } else if (word0 == 0xffffffff && word1 == 3) {
-              gs.xlen = 64;
-            } else if (word0 == 0xffffffff && word1 == 0xffffffff) {
-              gs.xlen = 128;
-            }
-
-            write_dpc_program();
-            state = ST_DPC;
-            return false;
-          }
-
-        case ST_DPC:
-          gs.dpc = gs.dr_read(SLOT_DATA0);
-          gs.dr_write32(0, csrr(S0, CSR_MSTATUS));
-          gs.dr_write_store(1, S0, SLOT_DATA0);
-          gs.dr_write_jump(2);
-          gs.set_interrupt(0);
-          state = ST_MSTATUS;
-          return false;
-
-        case ST_MSTATUS:
-          gs.mstatus = gs.dr_read(SLOT_DATA0);
-          gs.mstatus_dirty = false;
-          gs.dr_write32(0, csrr(S0, CSR_DCSR));
-          gs.dr_write32(1, sw(S0, 0, (uint16_t) DEBUG_RAM_START + 16));
-          gs.dr_write_jump(2);
-          gs.set_interrupt(0);
-          state = ST_DCSR;
-          return false;
-
-        case ST_DCSR:
-          gs.dcsr = gs.dr_read32(4);
-
-          gs.sptbr_valid = false;
-          gs.pte_cache.clear();
-
-          if (send_status) {
-            switch (get_field(gs.dcsr, DCSR_CAUSE)) {
-              case DCSR_CAUSE_NONE:
-                fprintf(stderr, "Internal error. Processor halted without reason.\n");
-                abort();
-
-              case DCSR_CAUSE_DEBUGINT:
-                gs.send_packet("S02");   // Pretend program received SIGINT.
-                break;
-
-              case DCSR_CAUSE_HWBP:
-              case DCSR_CAUSE_STEP:
-              case DCSR_CAUSE_HALT:
-                // There's no gdb code for this.
-                gs.send_packet("T05");
-                break;
-              case DCSR_CAUSE_SWBP:
-                gs.send_packet("T05swbreak:;");
-                break;
-            }
-          }
-
-          return true;
-
-        default:
-          assert(0);
-      }
-    }
-
-  private:
-    bool send_status;
-    enum {
-      ST_ENTER,
-      ST_XLEN,
-      ST_DPC,
-      ST_MSTATUS,
-      ST_DCSR
-    } state;
-};
-
-class continue_op_t : public operation_t
-{
-  public:
-    continue_op_t(gdbserver_t& gdbserver, bool single_step) :
-      operation_t(gdbserver), single_step(single_step) {};
-
-    bool perform_step(unsigned int step) {
-      D(fprintf(stderr, "continue step %d\n", step));
-      switch (step) {
-        case 0:
-          gs.dr_write_load(0, S0, SLOT_DATA0);
-          gs.dr_write32(1, csrw(S0, CSR_DPC));
-          // TODO: Isn't there a fence.i in Debug ROM already?
-          if (gs.fence_i_required) {
-            gs.dr_write32(2, fence_i());
-            gs.dr_write_jump(3);
-            gs.fence_i_required = false;
-          } else {
-            gs.dr_write_jump(2);
-          }
-          gs.dr_write(SLOT_DATA0, gs.dpc);
-          gs.set_interrupt(0);
-          return false;
-
-        case 1:
-          gs.dr_write_load(0, S0, SLOT_DATA0);
-          gs.dr_write32(1, csrw(S0, CSR_MSTATUS));
-          gs.dr_write_jump(2);
-          gs.dr_write(SLOT_DATA0, gs.mstatus);
-          gs.set_interrupt(0);
-          return false;
-
-        case 2:
-          gs.dr_write32(0, lw(S0, 0, (uint16_t) DEBUG_RAM_START+16));
-          gs.dr_write32(1, csrw(S0, CSR_DCSR));
-          gs.dr_write_jump(2);
-
-          reg_t dcsr = set_field(gs.dcsr, DCSR_HALT, 0);
-          dcsr = set_field(dcsr, DCSR_STEP, single_step);
-          // Software breakpoints should go here.
-          dcsr = set_field(dcsr, DCSR_EBREAKM, 1);
-          dcsr = set_field(dcsr, DCSR_EBREAKH, 1);
-          dcsr = set_field(dcsr, DCSR_EBREAKS, 1);
-          dcsr = set_field(dcsr, DCSR_EBREAKU, 1);
-          gs.dr_write32(4, dcsr);
-
-          gs.set_interrupt(0);
-          return true;
-      }
-      return false;
-    }
-
-  private:
-    bool single_step;
-};
-
-class general_registers_read_op_t : public operation_t
-{
-  // 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",
-
-  // 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
-  // register and their position within the â€˜g’ packet are determined by the
-  // gdb internal gdbarch functions DEPRECATED_REGISTER_RAW_SIZE and
-  // gdbarch_register_name.
-
-  public:
-    general_registers_read_op_t(gdbserver_t& gdbserver) :
-      operation_t(gdbserver) {};
-
-    bool perform_step(unsigned int step)
-    {
-      D(fprintf(stderr, "register_read step %d\n", step));
-      if (step == 0) {
-        gs.start_packet();
-
-        // x0 is always zero.
-        if (gs.xlen == 32) {
-          gs.send((uint32_t) 0);
-        } else {
-          gs.send((uint64_t) 0);
-        }
-
-        gs.dr_write_store(0, 1, SLOT_DATA0);
-        gs.dr_write_store(1, 2, SLOT_DATA1);
-        gs.dr_write_jump(2);
-        gs.set_interrupt(0);
-        return false;
-      }
-
-      if (gs.xlen == 32) {
-        gs.send((uint32_t) gs.dr_read(SLOT_DATA0));
-      } else {
-        gs.send((uint64_t) gs.dr_read(SLOT_DATA0));
-      }
-      if (step >= 16) {
-        gs.end_packet();
-        return true;
-      }
-
-      if (gs.xlen == 32) {
-        gs.send((uint32_t) gs.dr_read(SLOT_DATA1));
-      } else {
-        gs.send((uint64_t) gs.dr_read(SLOT_DATA1));
-      }
-
-      unsigned int current_reg = 2 * step + 1;
-      unsigned int i = 0;
-      if (current_reg == S1) {
-        gs.dr_write_load(i++, S1, SLOT_DATA_LAST);
-      }
-      gs.dr_write_store(i++, current_reg, SLOT_DATA0);
-      if (current_reg + 1 == S0) {
-        gs.dr_write32(i++, csrr(S0, CSR_DSCRATCH));
-      }
-      if (step < 15) {
-        gs.dr_write_store(i++, current_reg+1, SLOT_DATA1);
-      }
-      gs.dr_write_jump(i);
-      gs.set_interrupt(0);
-
-      return false;
-    }
-};
-
-class register_read_op_t : public operation_t
-{
-  public:
-    register_read_op_t(gdbserver_t& gdbserver, unsigned int reg) :
-      operation_t(gdbserver), reg(reg) {};
-
-    bool perform_step(unsigned int step)
-    {
-      switch (step) {
-        case 0:
-          if (reg >= REG_XPR0 && reg <= REG_XPR31) {
-            unsigned int i = 0;
-            if (reg == S0) {
-                gs.dr_write32(i++, csrr(S0, CSR_DSCRATCH));
-            }
-            if (gs.xlen == 32) {
-              gs.dr_write32(i++, sw(reg - REG_XPR0, 0, (uint16_t) DEBUG_RAM_START + 16));
-            } else {
-              gs.dr_write32(i++, sd(reg - REG_XPR0, 0, (uint16_t) DEBUG_RAM_START + 16));
-            }
-            gs.dr_write_jump(i);
-          } else if (reg == REG_PC) {
-            gs.start_packet();
-            if (gs.xlen == 32) {
-              gs.send((uint32_t) gs.dpc);
-            } else {
-              gs.send(gs.dpc);
-            }
-            gs.end_packet();
-            return true;
-          } else if (reg >= REG_FPR0 && reg <= REG_FPR31) {
-            gs.dr_write_load(0, S0, SLOT_DATA1);
-            gs.dr_write(SLOT_DATA1, set_field(gs.mstatus, MSTATUS_FS, 1));
-            gs.dr_write32(1, csrw(S0, CSR_MSTATUS));
-            gs.mstatus_dirty = true;
-            if (gs.xlen == 32) {
-              gs.dr_write32(2, fsw(reg - REG_FPR0, 0, (uint16_t) DEBUG_RAM_START + 16));
-            } else {
-              gs.dr_write32(2, fsd(reg - REG_FPR0, 0, (uint16_t) DEBUG_RAM_START + 16));
-            }
-            gs.dr_write_jump(3);
-          } else if (reg == REG_MSTATUS) {
-            gs.start_packet();
-            if (gs.xlen == 32) {
-              gs.send((uint32_t) gs.mstatus);
-            } else {
-              gs.send(gs.mstatus);
-            }
-            gs.end_packet();
-            return true;
-          } else if (reg >= REG_CSR0 && reg <= REG_CSR4095) {
-            gs.dr_write32(0, csrr(S0, reg - REG_CSR0));
-            gs.dr_write_store(1, S0, SLOT_DATA0);
-            gs.dr_write_jump(2);
-            // If we hit an exception reading the CSR, we'll end up returning ~0 as
-            // the register's value, which is what we want. (Right?)
-            gs.dr_write(SLOT_DATA0, ~(uint64_t) 0);
-          } else if (reg == REG_PRIV) {
-            gs.start_packet();
-            gs.send((uint8_t) get_field(gs.dcsr, DCSR_PRV));
-            gs.end_packet();
-            return true;
-          } else {
-            gs.send_packet("E02");
-            return true;
-          }
-          gs.set_interrupt(0);
-          return false;
-
-        case 1:
-          {
-            unsigned result = gs.dr_read32(DEBUG_RAM_SIZE / 4 - 1);
-            if (result) {
-              gs.send_packet("E03");
-              return true;
-            }
-            gs.start_packet();
-            if (gs.xlen == 32) {
-              gs.send(gs.dr_read32(4));
-            } else {
-              gs.send(gs.dr_read(SLOT_DATA0));
-            }
-            gs.end_packet();
-            return true;
-          }
-      }
-      return false;
-    }
-
-  private:
-    unsigned int reg;
-};
-
-class register_write_op_t : public operation_t
-{
-  public:
-    register_write_op_t(gdbserver_t& gdbserver, unsigned int reg, reg_t value) :
-      operation_t(gdbserver), reg(reg), value(value) {};
-
-    bool perform_step(unsigned int step)
-    {
-      switch (step) {
-        case 0:
-          gs.dr_write_load(0, S0, SLOT_DATA0);
-          gs.dr_write(SLOT_DATA0, value);
-          if (reg == S0) {
-            gs.dr_write32(1, csrw(S0, CSR_DSCRATCH));
-            gs.dr_write_jump(2);
-          } else if (reg == S1) {
-            gs.dr_write_store(1, S0, SLOT_DATA_LAST);
-            gs.dr_write_jump(2);
-          } else if (reg >= REG_XPR0 && reg <= REG_XPR31) {
-            gs.dr_write32(1, addi(reg, S0, 0));
-            gs.dr_write_jump(2);
-          } else if (reg == REG_PC) {
-            gs.dpc = value;
-            return true;
-          } else if (reg >= REG_FPR0 && reg <= REG_FPR31) {
-            gs.dr_write_load(0, S0, SLOT_DATA1);
-            gs.dr_write(SLOT_DATA1, set_field(gs.mstatus, MSTATUS_FS, 1));
-            gs.dr_write32(1, csrw(S0, CSR_MSTATUS));
-            gs.mstatus_dirty = true;
-            if (gs.xlen == 32) {
-              gs.dr_write32(2, flw(reg - REG_FPR0, 0, (uint16_t) DEBUG_RAM_START + 16));
-            } else {
-              gs.dr_write32(2, fld(reg - REG_FPR0, 0, (uint16_t) DEBUG_RAM_START + 16));
-            }
-            gs.dr_write_jump(3);
-          } else if (reg == REG_MSTATUS) {
-            gs.mstatus = value;
-            gs.mstatus_dirty = true;
-            return true;
-          } else if (reg >= REG_CSR0 && reg <= REG_CSR4095) {
-            gs.dr_write32(1, csrw(S0, reg - REG_CSR0));
-            gs.dr_write_jump(2);
-            if (reg == REG_CSR0 + CSR_SPTBR) {
-              gs.sptbr = value;
-              gs.sptbr_valid = true;
-            }
-          } else if (reg == REG_PRIV) {
-            gs.dcsr = set_field(gs.dcsr, DCSR_PRV, value);
-            return true;
-          } else {
-            gs.send_packet("E02");
-            return true;
-          }
-          gs.set_interrupt(0);
-          return false;
-
-        case 1:
-          {
-            unsigned result = gs.dr_read32(DEBUG_RAM_SIZE / 4 - 1);
-            if (result) {
-              gs.send_packet("E03");
-              return true;
-            }
-            gs.send_packet("OK");
-            return true;
-          }
-      }
-
-      assert(0);
-    }
-
-  private:
-    unsigned int reg;
-    reg_t value;
-};
-
-class memory_read_op_t : public operation_t
-{
-  public:
-    // Read length bytes from vaddr, storing the result into data.
-    // If data is NULL, send the result straight to gdb.
-    memory_read_op_t(gdbserver_t& gdbserver, reg_t vaddr, unsigned int length,
-        unsigned char *data=NULL) :
-      operation_t(gdbserver), vaddr(vaddr), length(length), data(data), index(0)
-  {
-    buf = new uint8_t[length];
-  };
-
-    ~memory_read_op_t()
-    {
-      delete[] buf;
-    }
-
-    bool perform_step(unsigned int step)
-    {
-      if (step == 0) {
-        // address goes in S0
-        paddr = gs.translate(vaddr);
-        access_size = gs.find_access_size(paddr, length);
-
-        gs.dr_write_load(0, S0, SLOT_DATA0);
-        switch (access_size) {
-          case 1:
-            gs.dr_write32(1, lb(S1, S0, 0));
-            break;
-          case 2:
-            gs.dr_write32(1, lh(S1, S0, 0));
-            break;
-          case 4:
-            gs.dr_write32(1, lw(S1, S0, 0));
-            break;
-          case 8:
-            gs.dr_write32(1, ld(S1, S0, 0));
-            break;
-        }
-        gs.dr_write_store(2, S1, SLOT_DATA1);
-        gs.dr_write_jump(3);
-        gs.dr_write(SLOT_DATA0, paddr);
-        gs.set_interrupt(0);
-
-        return false;
-      }
-
-      if (gs.dr_read32(DEBUG_RAM_SIZE / 4 - 1)) {
-        // Note that OpenOCD doesn't report this error to gdb by default. They
-        // think it can mess up stack tracing. So far I haven't seen any
-        // problems.
-        gs.send_packet("E99");
-        return true;
-      }
-
-      reg_t value = gs.dr_read(SLOT_DATA1);
-      for (unsigned int i = 0; i < access_size; i++) {
-        if (data) {
-          *(data++) = value & 0xff;
-          D(fprintf(stderr, "%02x", (unsigned int) (value & 0xff)));
-        } else {
-          buf[index++] = value & 0xff;
-        }
-        value >>= 8;
-      }
-      if (data) {
-        D(fprintf(stderr, "\n"));
-      }
-      length -= access_size;
-      paddr += access_size;
-
-      if (length == 0) {
-        if (!data) {
-          gs.start_packet();
-          char buffer[3];
-          for (unsigned int i = 0; i < index; i++) {
-            sprintf(buffer, "%02x", (unsigned int) buf[i]);
-            gs.send(buffer);
-          }
-          gs.end_packet();
-        }
-        return true;
-      } else {
-        gs.dr_write(SLOT_DATA0, paddr);
-        gs.set_interrupt(0);
-        return false;
-      }
-    }
-
-  private:
-    reg_t vaddr;
-    unsigned int length;
-    unsigned char* data;
-    reg_t paddr;
-    unsigned int access_size;
-    unsigned int index;
-    uint8_t *buf;
-};
-
-class memory_write_op_t : public operation_t
-{
-  public:
-    memory_write_op_t(gdbserver_t& gdbserver, reg_t vaddr, unsigned int length,
-        const unsigned char *data) :
-      operation_t(gdbserver), vaddr(vaddr), offset(0), length(length), data(data) {};
-
-    ~memory_write_op_t() {
-      delete[] data;
-    }
-
-    bool perform_step(unsigned int step)
-    {
-      reg_t paddr = gs.translate(vaddr);
-
-      unsigned int data_offset;
-      switch (gs.xlen) {
-        case 32:
-          data_offset = slot_offset32[SLOT_DATA1];
-          break;
-        case 64:
-          data_offset = slot_offset64[SLOT_DATA1];
-          break;
-        case 128:
-          data_offset = slot_offset128[SLOT_DATA1];
-          break;
-        default:
-          abort();
-      }
-
-      if (step == 0) {
-        access_size = gs.find_access_size(paddr, length);
-
-        D(fprintf(stderr, "write to 0x%" PRIx64 " -> 0x%" PRIx64 " (access=%d): ",
-              vaddr, paddr, access_size));
-        for (unsigned int i = 0; i < length; i++) {
-          D(fprintf(stderr, "%02x", data[i]));
-        }
-        D(fprintf(stderr, "\n"));
-
-        // address goes in S0
-        gs.dr_write_load(0, S0, SLOT_DATA0);
-        switch (access_size) {
-          case 1:
-            gs.dr_write32(1, lb(S1, 0, (uint16_t) DEBUG_RAM_START + 4*data_offset));
-            gs.dr_write32(2, sb(S1, S0, 0));
-            gs.dr_write32(data_offset, data[0]);
-            break;
-          case 2:
-            gs.dr_write32(1, lh(S1, 0, (uint16_t) DEBUG_RAM_START + 4*data_offset));
-            gs.dr_write32(2, sh(S1, S0, 0));
-            gs.dr_write32(data_offset, data[0] | (data[1] << 8));
-            break;
-          case 4:
-            gs.dr_write32(1, lw(S1, 0, (uint16_t) DEBUG_RAM_START + 4*data_offset));
-            gs.dr_write32(2, sw(S1, S0, 0));
-            gs.dr_write32(data_offset, data[0] | (data[1] << 8) |
-                (data[2] << 16) | (data[3] << 24));
-            break;
-          case 8:
-            gs.dr_write32(1, ld(S1, 0, (uint16_t) DEBUG_RAM_START + 4*data_offset));
-            gs.dr_write32(2, sd(S1, S0, 0));
-            gs.dr_write32(data_offset, data[0] | (data[1] << 8) |
-                (data[2] << 16) | (data[3] << 24));
-            gs.dr_write32(data_offset+1, data[4] | (data[5] << 8) |
-                (data[6] << 16) | (data[7] << 24));
-            break;
-          default:
-            fprintf(stderr, "gdbserver error: write %d bytes to 0x%016" PRIx64
-                    " -> 0x%016" PRIx64 "; access_size=%d\n",
-                    length, vaddr, paddr, access_size);
-            gs.send_packet("E12");
-            return true;
-        }
-        gs.dr_write_jump(3);
-        gs.dr_write(SLOT_DATA0, paddr);
-        gs.set_interrupt(0);
-
-        return false;
-      }
-
-      if (gs.dr_read32(DEBUG_RAM_SIZE / 4 - 1)) {
-        gs.send_packet("E98");
-        return true;
-      }
-
-      offset += access_size;
-      if (offset >= length) {
-        gs.send_packet("OK");
-        return true;
-      } else {
-        const unsigned char *d = data + offset;
-        switch (access_size) {
-          case 1:
-            gs.dr_write32(data_offset, d[0]);
-            break;
-          case 2:
-            gs.dr_write32(data_offset, d[0] | (d[1] << 8));
-            break;
-          case 4:
-            gs.dr_write32(data_offset, d[0] | (d[1] << 8) |
-                (d[2] << 16) | (d[3] << 24));
-            break;
-          case 8:
-            gs.dr_write32(data_offset, d[0] | (d[1] << 8) |
-                (d[2] << 16) | (d[3] << 24));
-            gs.dr_write32(data_offset+1, d[4] | (d[5] << 8) |
-                (d[6] << 16) | (d[7] << 24));
-            break;
-          default:
-            gs.send_packet("E13");
-            return true;
-        }
-        gs.dr_write(SLOT_DATA0, paddr + offset);
-        gs.set_interrupt(0);
-        return false;
-      }
-    }
-
-  private:
-    reg_t vaddr;
-    unsigned int offset;
-    unsigned int length;
-    unsigned int access_size;
-    const unsigned char *data;
-};
-
-class collect_translation_info_op_t : public operation_t
-{
-  public:
-    // Read sufficient information from the target into gdbserver structures so
-    // that it's possible to translate vaddr, vaddr+length, and all addresses
-    // in between to physical addresses.
-    collect_translation_info_op_t(gdbserver_t& gdbserver, reg_t vaddr, size_t length) :
-      operation_t(gdbserver), state(STATE_START), vaddr(vaddr), length(length) {};
-
-    bool perform_step(unsigned int step)
-    {
-      // Perform any reads from the just-completed action.
-      switch (state) {
-        case STATE_START:
-          break;
-        case STATE_READ_SPTBR:
-          gs.sptbr = gs.dr_read(SLOT_DATA0);
-          gs.sptbr_valid = true;
-          vm = decode_vm_info(gs.xlen, gs.privilege_mode(), gs.sptbr);
-          if (vm.levels == 0)
-            return true;
-          break;
-        case STATE_READ_PTE:
-          if (vm.ptesize == 4) {
-              gs.pte_cache[pte_addr] = gs.dr_read32(4);
-          } else {
-              gs.pte_cache[pte_addr] = ((uint64_t) gs.dr_read32(5) << 32) |
-                  gs.dr_read32(4);
-          }
-          D(fprintf(stderr, "pte_cache[0x%" PRIx64 "] = 0x%" PRIx64 "\n", pte_addr,
-                    gs.pte_cache[pte_addr]));
-          break;
-      }
-
-      // Set up the next action.
-      // We only get here for VM_SV32/39/38.
-
-      if (!gs.sptbr_valid) {
-        state = STATE_READ_SPTBR;
-        gs.dr_write32(0, csrr(S0, CSR_SPTBR));
-        gs.dr_write_store(1, S0, SLOT_DATA0);
-        gs.dr_write_jump(2);
-        gs.set_interrupt(0);
-        return false;
-      }
-
-      reg_t base = vm.ptbase;
-      for (int i = vm.levels - 1; i >= 0; i--) {
-        int ptshift = i * vm.idxbits;
-        reg_t idx = (vaddr >> (PGSHIFT + ptshift)) & ((1 << vm.idxbits) - 1);
-
-        pte_addr = base + idx * vm.ptesize;
-        auto it = gs.pte_cache.find(pte_addr);
-        if (it == gs.pte_cache.end()) {
-          state = STATE_READ_PTE;
-          if (vm.ptesize == 4) {
-            gs.dr_write32(0, lw(S0, 0, (uint16_t) DEBUG_RAM_START + 16));
-            gs.dr_write32(1, lw(S1, S0, 0));
-            gs.dr_write32(2, sw(S1, 0, (uint16_t) DEBUG_RAM_START + 16));
-          } else {
-            assert(gs.xlen >= 64);
-            gs.dr_write32(0, ld(S0, 0, (uint16_t) DEBUG_RAM_START + 16));
-            gs.dr_write32(1, ld(S1, S0, 0));
-            gs.dr_write32(2, sd(S1, 0, (uint16_t) DEBUG_RAM_START + 16));
-          }
-          gs.dr_write_jump(3);
-          gs.dr_write32(4, pte_addr);
-          gs.dr_write32(5, pte_addr >> 32);
-          gs.set_interrupt(0);
-          return false;
-        }
-
-        reg_t pte = gs.pte_cache[pte_addr];
-        reg_t ppn = pte >> PTE_PPN_SHIFT;
-
-        if (PTE_TABLE(pte)) { // next level of page table
-          base = ppn << PGSHIFT;
-        } else {
-          // We've collected all the data required for the translation.
-          return true;
-        }
-      }
-      fprintf(stderr,
-          "ERROR: gdbserver couldn't find appropriate PTEs to translate 0x%016" PRIx64 "\n",
-          vaddr);
-      return true;
-    }
-
-  private:
-    enum {
-      STATE_START,
-      STATE_READ_SPTBR,
-      STATE_READ_PTE
-    } state;
-    reg_t vaddr;
-    size_t length;
-    vm_info vm;
-    reg_t pte_addr;
-};
-
-class hardware_breakpoint_insert_op_t : public operation_t
-{
-  public:
-    hardware_breakpoint_insert_op_t(gdbserver_t& gdbserver,
-        hardware_breakpoint_t bp) :
-      operation_t(gdbserver), state(STATE_START), bp(bp) {};
-
-    void write_new_index_program()
-    {
-      gs.dr_write_load(0, S0, SLOT_DATA1);
-      gs.dr_write32(1, csrw(S0, CSR_TSELECT));
-      gs.dr_write32(2, csrr(S0, CSR_TSELECT));
-      gs.dr_write_store(3, S0, SLOT_DATA1);
-      gs.dr_write_jump(4);
-      gs.dr_write(SLOT_DATA1, bp.index);
-    }
-
-    bool perform_step(unsigned int step)
-    {
-      switch (state) {
-        case STATE_START:
-          bp.index = 0;
-          write_new_index_program();
-          state = STATE_CHECK_INDEX;
-          break;
-
-        case STATE_CHECK_INDEX:
-          if (gs.dr_read(SLOT_DATA1) != bp.index) {
-            // We've exhausted breakpoints without finding an appropriate one.
-            gs.send_packet("E58");
-            return true;
-          }
-
-          gs.dr_write32(0, csrr(S0, CSR_TDATA1));
-          gs.dr_write_store(1, S0, SLOT_DATA0);
-          gs.dr_write_jump(2);
-          state = STATE_CHECK_MCONTROL;
-          break;
-
-        case STATE_CHECK_MCONTROL:
-          {
-            reg_t mcontrol = gs.dr_read(SLOT_DATA0);
-            unsigned int type = mcontrol >> (gs.xlen - 4);
-            if (type == 0) {
-              // We've exhausted breakpoints without finding an appropriate one.
-              gs.send_packet("E58");
-              return true;
-            }
-
-            if (type == 2 &&
-                !get_field(mcontrol, MCONTROL_EXECUTE) &&
-                !get_field(mcontrol, MCONTROL_LOAD) &&
-                !get_field(mcontrol, MCONTROL_STORE)) {
-              // Found an unused trigger.
-              gs.dr_write_load(0, S0, SLOT_DATA1);
-              gs.dr_write32(1, csrw(S0, CSR_TDATA1));
-              gs.dr_write_jump(2);
-              mcontrol = set_field(0, MCONTROL_ACTION, MCONTROL_ACTION_DEBUG_MODE);
-              mcontrol = set_field(mcontrol, MCONTROL_DMODE(gs.xlen), 1);
-              mcontrol = set_field(mcontrol, MCONTROL_MATCH, MCONTROL_MATCH_EQUAL);
-              mcontrol = set_field(mcontrol, MCONTROL_M, 1);
-              mcontrol = set_field(mcontrol, MCONTROL_H, 1);
-              mcontrol = set_field(mcontrol, MCONTROL_S, 1);
-              mcontrol = set_field(mcontrol, MCONTROL_U, 1);
-              mcontrol = set_field(mcontrol, MCONTROL_EXECUTE, bp.execute);
-              mcontrol = set_field(mcontrol, MCONTROL_LOAD, bp.load);
-              mcontrol = set_field(mcontrol, MCONTROL_STORE, bp.store);
-              // For store triggers it's nicer to fire just before the
-              // instruction than just after. However, gdb doesn't clear the
-              // breakpoints and step before resuming from a store trigger.
-              // That means that without extra code, you'll keep hitting the
-              // same watchpoint over and over again. That's not useful at all.
-              // Instead of fixing this the right way, just set timing=1 for
-              // those triggers.
-              if (bp.load || bp.store)
-                mcontrol = set_field(mcontrol, MCONTROL_TIMING, 1);
-
-              gs.dr_write(SLOT_DATA1, mcontrol);
-              state = STATE_WRITE_ADDRESS;
-            } else {
-              bp.index++;
-              write_new_index_program();
-              state = STATE_CHECK_INDEX;
-            }
-          }
-          break;
-
-        case STATE_WRITE_ADDRESS:
-          {
-            gs.dr_write_load(0, S0, SLOT_DATA1);
-            gs.dr_write32(1, csrw(S0, CSR_TDATA2));
-            gs.dr_write_jump(2);
-            gs.dr_write(SLOT_DATA1, bp.vaddr);
-            gs.set_interrupt(0);
-            gs.send_packet("OK");
-
-            gs.hardware_breakpoints.insert(bp);
-
-            return true;
-          }
-      }
-
-      gs.set_interrupt(0);
-      return false;
-    }
-
-  private:
-    enum {
-      STATE_START,
-      STATE_CHECK_INDEX,
-      STATE_CHECK_MCONTROL,
-      STATE_WRITE_ADDRESS
-    } state;
-    hardware_breakpoint_t bp;
-};
-
-class maybe_save_tselect_op_t : public operation_t
-{
-  public:
-    maybe_save_tselect_op_t(gdbserver_t& gdbserver) : operation_t(gdbserver) {};
-    bool perform_step(unsigned int step) {
-      if (gs.tselect_valid)
-        return true;
-
-      switch (step) {
-        case 0:
-          gs.dr_write32(0, csrr(S0, CSR_TDATA1));
-          gs.dr_write_store(1, S0, SLOT_DATA0);
-          gs.dr_write_jump(2);
-          gs.set_interrupt(0);
-          return false;
-        case 1:
-          gs.tselect = gs.dr_read(SLOT_DATA0);
-          gs.tselect_valid = true;
-          break;
-      }
-      return true;
-    }
-};
-
-class maybe_restore_tselect_op_t : public operation_t
-{
-  public:
-    maybe_restore_tselect_op_t(gdbserver_t& gdbserver) : operation_t(gdbserver) {};
-    bool perform_step(unsigned int step) {
-      if (gs.tselect_valid) {
-        gs.dr_write_load(0, S0, SLOT_DATA1);
-        gs.dr_write32(1, csrw(S0, CSR_TSELECT));
-        gs.dr_write_jump(2);
-        gs.dr_write(SLOT_DATA1, gs.tselect);
-      }
-      return true;
-    }
-};
-
-class maybe_restore_mstatus_op_t : public operation_t
-{
-  public:
-    maybe_restore_mstatus_op_t(gdbserver_t& gdbserver) : operation_t(gdbserver) {};
-    bool perform_step(unsigned int step) {
-      if (gs.mstatus_dirty) {
-        gs.dr_write_load(0, S0, SLOT_DATA1);
-        gs.dr_write32(1, csrw(S0, CSR_MSTATUS));
-        gs.dr_write_jump(2);
-        gs.dr_write(SLOT_DATA1, gs.mstatus);
-      }
-      return true;
-    }
-};
-
-class hardware_breakpoint_remove_op_t : public operation_t
-{
-  public:
-    hardware_breakpoint_remove_op_t(gdbserver_t& gdbserver,
-        hardware_breakpoint_t bp) :
-      operation_t(gdbserver), bp(bp) {};
-
-    bool perform_step(unsigned int step) {
-      gs.dr_write32(0, addi(S0, ZERO, bp.index));
-      gs.dr_write32(1, csrw(S0, CSR_TSELECT));
-      gs.dr_write32(2, csrw(ZERO, CSR_TDATA1));
-      gs.dr_write_jump(3);
-      gs.set_interrupt(0);
-      return true;
-    }
-
-  private:
-    hardware_breakpoint_t bp;
-};
-
-////////////////////////////// gdbserver itself
-
-gdbserver_t::gdbserver_t(uint16_t port, sim_t *sim) :
-  xlen(0),
-  sim(sim),
-  client_fd(0),
-  // gdb likes to send 0x100000 bytes at once when downloading.
-  recv_buf(0x180000), send_buf(64 * 1024)
-{
-  socket_fd = socket(AF_INET, SOCK_STREAM, 0);
-  if (socket_fd == -1) {
-    fprintf(stderr, "failed to make socket: %s (%d)\n", strerror(errno), errno);
-    abort();
-  }
-
-  fcntl(socket_fd, F_SETFL, O_NONBLOCK);
-  int reuseaddr = 1;
-  if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
-        sizeof(int)) == -1) {
-    fprintf(stderr, "failed setsockopt: %s (%d)\n", strerror(errno), errno);
-    abort();
-  }
-
-  struct sockaddr_in addr;
-  memset(&addr, 0, sizeof(addr));
-  addr.sin_family = AF_INET;
-  addr.sin_addr.s_addr = INADDR_ANY;
-  addr.sin_port = htons(port);
-
-  if (bind(socket_fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
-    fprintf(stderr, "failed to bind socket: %s (%d)\n", strerror(errno), errno);
-    abort();
-  }
-
-  if (listen(socket_fd, 1) == -1) {
-    fprintf(stderr, "failed to listen on socket: %s (%d)\n", strerror(errno), errno);
-    abort();
-  }
-}
-
-unsigned int gdbserver_t::find_access_size(reg_t address, int length)
-{
-  reg_t composite = address | length;
-  if ((composite & 0x7) == 0 && xlen >= 64)
-    return 8;
-  if ((composite & 0x3) == 0)
-    return 4;
-  return 1;
-}
-
-reg_t gdbserver_t::translate(reg_t vaddr)
-{
-  vm_info vm = decode_vm_info(xlen, privilege_mode(), sptbr);
-  if (vm.levels == 0)
-    return vaddr;
-
-  // Handle page tables here. There's a bunch of duplicated code with
-  // collect_translation_info_op_t. :-(
-  reg_t base = vm.ptbase;
-  for (int i = vm.levels - 1; i >= 0; i--) {
-    int ptshift = i * vm.idxbits;
-    reg_t idx = (vaddr >> (PGSHIFT + ptshift)) & ((1 << vm.idxbits) - 1);
-
-    reg_t pte_addr = base + idx * vm.ptesize;
-    auto it = pte_cache.find(pte_addr);
-    if (it == pte_cache.end()) {
-      fprintf(stderr, "ERROR: gdbserver tried to translate 0x%016" PRIx64
-          " without first collecting the relevant PTEs.\n", vaddr);
-      die("gdbserver_t::translate()");
-    }
-
-    reg_t pte = pte_cache[pte_addr];
-    reg_t ppn = pte >> PTE_PPN_SHIFT;
-
-    if (PTE_TABLE(pte)) { // next level of page table
-      base = ppn << PGSHIFT;
-    } else {
-      // We've collected all the data required for the translation.
-      reg_t vpn = vaddr >> PGSHIFT;
-      reg_t paddr = (ppn | (vpn & ((reg_t(1) << ptshift) - 1))) << PGSHIFT;
-      paddr += vaddr & (PGSIZE-1);
-      D(fprintf(stderr, "gdbserver translate 0x%" PRIx64 " -> 0x%" PRIx64 "\n", vaddr, paddr));
-      return paddr;
-    }
-  }
-
-  fprintf(stderr, "ERROR: gdbserver tried to translate 0x%016" PRIx64
-          " but the relevant PTEs are invalid.\n", vaddr);
-  // TODO: Is it better to throw an exception here?
-  return -1;
-}
-
-unsigned int gdbserver_t::privilege_mode()
-{
-  unsigned int mode = get_field(dcsr, DCSR_PRV);
-  if (get_field(mstatus, MSTATUS_MPRV))
-    mode = get_field(mstatus, MSTATUS_MPP);
-  return mode;
-}
-
-void gdbserver_t::dr_write32(unsigned int index, uint32_t value)
-{
-  sim->debug_module.ram_write32(index, value);
-}
-
-void gdbserver_t::dr_write64(unsigned int index, uint64_t value)
-{
-  dr_write32(index, value);
-  dr_write32(index+1, value >> 32);
-}
-
-void gdbserver_t::dr_write(enum slot slot, uint64_t value)
-{
-  switch (xlen) {
-    case 32:
-      dr_write32(slot_offset32[slot], value);
-      break;
-    case 64:
-      dr_write64(slot_offset64[slot], value);
-      break;
-    case 128:
-    default:
-      abort();
-  }
-}
-
-void gdbserver_t::dr_write_jump(unsigned int index)
-{
-  dr_write32(index, jal(0,
-        (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*index))));
-}
-
-void gdbserver_t::dr_write_store(unsigned int index, unsigned int reg, enum slot slot)
-{
-  assert(slot != SLOT_INST0 || index > 2);
-  assert(slot != SLOT_DATA0 || index < 4 || index > 6);
-  assert(slot != SLOT_DATA1 || index < 5 || index > 10);
-  assert(slot != SLOT_DATA_LAST || index < 6 || index > 14);
-  switch (xlen) {
-    case 32:
-      return dr_write32(index,
-          sw(reg, 0, (uint16_t) DEBUG_RAM_START + 4 * slot_offset32[slot]));
-    case 64:
-      return dr_write32(index,
-          sd(reg, 0, (uint16_t) DEBUG_RAM_START + 4 * slot_offset64[slot]));
-    case 128:
-      return dr_write32(index,
-          sq(reg, 0, (uint16_t) DEBUG_RAM_START + 4 * slot_offset128[slot]));
-    default:
-      fprintf(stderr, "xlen is %d!\n", xlen);
-      abort();
-  }
-}
-
-void gdbserver_t::dr_write_load(unsigned int index, unsigned int reg, enum slot slot)
-{
-  switch (xlen) {
-    case 32:
-      return dr_write32(index,
-          lw(reg, 0, (uint16_t) DEBUG_RAM_START + 4 * slot_offset32[slot]));
-    case 64:
-      return dr_write32(index,
-          ld(reg, 0, (uint16_t) DEBUG_RAM_START + 4 * slot_offset64[slot]));
-    case 128:
-      return dr_write32(index,
-          lq(reg, 0, (uint16_t) DEBUG_RAM_START + 4 * slot_offset128[slot]));
-    default:
-      fprintf(stderr, "xlen is %d!\n", xlen);
-      abort();
-  }
-}
-
-uint32_t gdbserver_t::dr_read32(unsigned int index)
-{
-  uint32_t value = sim->debug_module.ram_read32(index);
-  D(fprintf(stderr, "read32(%d) -> 0x%x\n", index, value));
-  return value;
-}
-
-uint64_t gdbserver_t::dr_read64(unsigned int index)
-{
-  return ((uint64_t) dr_read32(index+1) << 32) | dr_read32(index);
-}
-
-uint64_t gdbserver_t::dr_read(enum slot slot)
-{
-  switch (xlen) {
-    case 32:
-      return dr_read32(slot_offset32[slot]);
-    case 64:
-      return dr_read64(slot_offset64[slot]);
-    case 128:
-      abort();
-    default:
-      abort();
-  }
-}
-
-void gdbserver_t::add_operation(operation_t* operation)
-{
-  operation_queue.push(operation);
-}
-
-void gdbserver_t::accept()
-{
-  client_fd = ::accept(socket_fd, NULL, NULL);
-  if (client_fd == -1) {
-    if (errno == EAGAIN) {
-      // No client waiting to connect right now.
-    } else {
-      fprintf(stderr, "failed to accept on socket: %s (%d)\n", strerror(errno),
-          errno);
-      abort();
-    }
-  } else {
-    fcntl(client_fd, F_SETFL, O_NONBLOCK);
-
-    expect_ack = false;
-    extended_mode = false;
-
-    // gdb wants the core to be halted when it attaches.
-    add_operation(new halt_op_t(*this));
-  }
-}
-
-void gdbserver_t::read()
-{
-  // Reading from a non-blocking socket still blocks if there is no data
-  // available.
-
-  size_t count = recv_buf.contiguous_empty_size();
-  ssize_t bytes = ::read(client_fd, recv_buf.contiguous_empty(), count);
-  if (bytes == -1) {
-    if (errno == EAGAIN) {
-      // We'll try again the next call.
-    } else {
-      fprintf(stderr, "failed to read on socket: %s (%d)\n", strerror(errno), errno);
-      abort();
-    }
-  } else if (bytes == 0) {
-    // The remote disconnected.
-    client_fd = 0;
-    processor_t *p = sim->get_core(0);
-    // TODO p->set_halted(false, HR_NONE);
-    recv_buf.reset();
-    send_buf.reset();
-  } else {
-    recv_buf.data_added(bytes);
-  }
-}
-
-void gdbserver_t::write()
-{
-  if (send_buf.empty())
-    return;
-
-  while (!send_buf.empty()) {
-    unsigned int count = send_buf.contiguous_data_size();
-    assert(count > 0);
-    ssize_t bytes = ::write(client_fd, send_buf.contiguous_data(), count);
-    if (bytes == -1) {
-      fprintf(stderr, "failed to write to socket: %s (%d)\n", strerror(errno), errno);
-      abort();
-    } else if (bytes == 0) {
-      // Client can't take any more data right now.
-      break;
-    } else {
-      D(fprintf(stderr, "wrote %zd bytes: ", bytes));
-      for (int i = 0; i < bytes; i++) {
-        D(fprintf(stderr, "%c", send_buf[i]));
-      }
-      D(fprintf(stderr, "\n"));
-      send_buf.consume(bytes);
-    }
-  }
-}
-
-void print_packet(const std::vector<uint8_t> &packet)
-{
-  for (uint8_t c : packet) {
-    if (c >= ' ' and c <= '~')
-      fprintf(stderr, "%c", c);
-    else
-      fprintf(stderr, "\\x%02x", c);
-  }
-  fprintf(stderr, "\n");
-}
-
-uint8_t compute_checksum(const std::vector<uint8_t> &packet)
-{
-  uint8_t checksum = 0;
-  for (auto i = packet.begin() + 1; i != packet.end() - 3; i++ ) {
-    checksum += *i;
-  }
-  return checksum;
-}
-
-uint8_t character_hex_value(uint8_t character)
-{
-  if (character >= '0' && character <= '9')
-    return character - '0';
-  if (character >= 'a' && character <= 'f')
-    return 10 + character - 'a';
-  if (character >= 'A' && character <= 'F')
-    return 10 + character - 'A';
-  return 0xff;
-}
-
-uint8_t extract_checksum(const std::vector<uint8_t> &packet)
-{
-  return character_hex_value(*(packet.end() - 1)) +
-    16 * character_hex_value(*(packet.end() - 2));
-}
-
-void gdbserver_t::process_requests()
-{
-  // See https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html
-
-  while (!recv_buf.empty()) {
-    std::vector<uint8_t> packet;
-    for (unsigned int i = 0; i < recv_buf.size(); i++) {
-      uint8_t b = recv_buf[i];
-
-      if (packet.empty() && expect_ack && b == '+') {
-        recv_buf.consume(1);
-        break;
-      }
-
-      if (packet.empty() && b == 3) {
-        D(fprintf(stderr, "Received interrupt\n"));
-        recv_buf.consume(1);
-        handle_interrupt();
-        break;
-      }
-
-      if (b == '$') {
-        // Start of new packet.
-        if (!packet.empty()) {
-          fprintf(stderr, "Received malformed %zd-byte packet from debug client: ",
-              packet.size());
-          print_packet(packet);
-          recv_buf.consume(i);
-          break;
-        }
-      }
-
-      packet.push_back(b);
-
-      // Packets consist of $<packet-data>#<checksum>
-      // where <checksum> is 
-      if (packet.size() >= 4 &&
-          packet[packet.size()-3] == '#') {
-        handle_packet(packet);
-        recv_buf.consume(i+1);
-        break;
-      }
-    }
-    // There's a partial packet in the buffer. Wait until we get more data to
-    // process it.
-    if (packet.size()) {
-      break;
-    }
-  }
-
-  if (recv_buf.full()) {
-    fprintf(stderr,
-        "Receive buffer is full, but no complete packet was found!\n");
-    for (unsigned line = 0; line < 8; line++) {
-      for (unsigned i = 0; i < 16; i++) {
-        fprintf(stderr, "%02x ", recv_buf.entry(line * 16 + i));
-      }
-      for (unsigned i = 0; i < 16; i++) {
-        uint8_t e = recv_buf.entry(line * 16 + i);
-        if (e >= ' ' && e <= '~')
-          fprintf(stderr, "%c", e);
-        else
-          fprintf(stderr, ".");
-      }
-      fprintf(stderr, "\n");
-    }
-    assert(!recv_buf.full());
-  }
-}
-
-void gdbserver_t::handle_halt_reason(const std::vector<uint8_t> &packet)
-{
-  send_packet("S00");
-}
-
-void gdbserver_t::handle_general_registers_read(const std::vector<uint8_t> &packet)
-{
-  add_operation(new general_registers_read_op_t(*this));
-}
-
-void gdbserver_t::set_interrupt(uint32_t hartid) {
-  sim->debug_module.set_interrupt(hartid);
-}
-
-// 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)
-{
-  uint64_t value = 0;
-
-  while (iter != end) {
-    uint8_t c = *iter;
-    uint64_t c_value = character_hex_value(c);
-    if (c_value > 15)
-      break;
-    iter++;
-    value <<= 4;
-    value += c_value;
-  }
-  return value;
-}
-
-// First byte is the least-significant one.
-// Eg. "08675309" becomes 0x09536708
-uint64_t gdbserver_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;
-  }
-  if (shift > (xlen+4)) {
-    fprintf(stderr,
-        "gdb sent too many data bytes. That means it thinks XLEN is greater "
-        "than %d.\nTo fix that, tell gdb: set arch riscv:rv%d\n",
-        xlen, xlen);
-  }
-  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)
-{
-  while (iter != end && *iter != separator) {
-    str.append(1, (char) *iter);
-    iter++;
-  }
-}
-
-void gdbserver_t::handle_register_read(const std::vector<uint8_t> &packet)
-{
-  // p n
-
-  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");
-
-  add_operation(new register_read_op_t(*this, n));
-}
-
-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++;
-
-  reg_t value = consume_hex_number_le(iter, packet.end());
-  if (*iter != '#')
-    return send_packet("E06");
-
-  processor_t *p = sim->get_core(0);
-
-  add_operation(new register_write_op_t(*this, n, value));
-}
-
-void gdbserver_t::handle_memory_read(const std::vector<uint8_t> &packet)
-{
-  // m addr,length
-  std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
-  reg_t address = consume_hex_number(iter, packet.end());
-  if (*iter != ',')
-    return send_packet("E10");
-  iter++;
-  reg_t length = consume_hex_number(iter, packet.end());
-  if (*iter != '#')
-    return send_packet("E11");
-
-  add_operation(new collect_translation_info_op_t(*this, address, length));
-  add_operation(new memory_read_op_t(*this, address, length));
-}
-
-void gdbserver_t::handle_memory_binary_write(const std::vector<uint8_t> &packet)
-{
-  // X addr,length:XX...
-  std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
-  reg_t address = consume_hex_number(iter, packet.end());
-  if (*iter != ',')
-    return send_packet("E20");
-  iter++;
-  reg_t length = consume_hex_number(iter, packet.end());
-  if (*iter != ':')
-    return send_packet("E21");
-  iter++;
-
-  if (length == 0) {
-    return send_packet("OK");
-  }
-
-  unsigned char *data = new unsigned char[length];
-  for (unsigned int i = 0; i < length; i++) {
-    if (iter == packet.end()) {
-      return send_packet("E22");
-    }
-    uint8_t c = *iter;
-    iter++;
-    if (c == '}') {
-      // The binary data representation uses 7d (ascii â€˜}’) as an escape
-      // character. Any escaped byte is transmitted as the escape character
-      // followed by the original character XORed with 0x20. For example, the
-      // byte 0x7d would be transmitted as the two bytes 0x7d 0x5d. The bytes
-      // 0x23 (ascii â€˜#’), 0x24 (ascii â€˜$’), and 0x7d (ascii â€˜}’) must always
-      // be escaped.
-      if (iter == packet.end()) {
-        return send_packet("E23");
-      }
-      c = (*iter) ^ 0x20;
-      iter++;
-    }
-    data[i] = c;
-  }
-  if (*iter != '#')
-    return send_packet("E4b"); // EOVERFLOW
-
-  add_operation(new collect_translation_info_op_t(*this, address, length));
-  add_operation(new memory_write_op_t(*this, address, length, data));
-}
-
-void gdbserver_t::handle_continue(const std::vector<uint8_t> &packet)
-{
-  // c [addr]
-  processor_t *p = sim->get_core(0);
-  if (packet[2] != '#') {
-    std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
-    dpc = consume_hex_number(iter, packet.end());
-    if (*iter != '#')
-      return send_packet("E30");
-  }
-
-  add_operation(new maybe_restore_tselect_op_t(*this));
-  add_operation(new maybe_restore_mstatus_op_t(*this));
-  add_operation(new continue_op_t(*this, false));
-}
-
-void gdbserver_t::handle_step(const std::vector<uint8_t> &packet)
-{
-  // s [addr]
-  if (packet[2] != '#') {
-    std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
-    die("handle_step");
-    //p->state.pc = consume_hex_number(iter, packet.end());
-    if (*iter != '#')
-      return send_packet("E40");
-  }
-
-  add_operation(new maybe_restore_tselect_op_t(*this));
-  add_operation(new continue_op_t(*this, true));
-}
-
-void gdbserver_t::handle_kill(const std::vector<uint8_t> &packet)
-{
-  // k
-  // The exact effect of this packet is not specified.
-  // Looks like OpenOCD disconnects?
-  // TODO
-}
-
-void gdbserver_t::handle_extended(const std::vector<uint8_t> &packet)
-{
-  // Enable extended mode. In extended mode, the remote server is made
-  // persistent. The â€˜R’ packet is used to restart the program being debugged.
-  send_packet("OK");
-  extended_mode = true;
-}
-
-void gdbserver_t::software_breakpoint_insert(reg_t vaddr, unsigned int size)
-{
-  fence_i_required = true;
-  add_operation(new collect_translation_info_op_t(*this, vaddr, size));
-  unsigned char* inst = new unsigned char[4];
-  if (size == 2) {
-    inst[0] = MATCH_C_EBREAK & 0xff;
-    inst[1] = (MATCH_C_EBREAK >> 8) & 0xff;
-  } else {
-    inst[0] = MATCH_EBREAK & 0xff;
-    inst[1] = (MATCH_EBREAK >> 8) & 0xff;
-    inst[2] = (MATCH_EBREAK >> 16) & 0xff;
-    inst[3] = (MATCH_EBREAK >> 24) & 0xff;
-  }
-
-  software_breakpoint_t bp = {
-    .vaddr = vaddr,
-    .size = size
-  };
-  software_breakpoints[vaddr] = bp;
-  add_operation(new memory_read_op_t(*this, bp.vaddr, bp.size,
-        software_breakpoints[bp.vaddr].instruction));
-  add_operation(new memory_write_op_t(*this, bp.vaddr, bp.size, inst));
-}
-
-void gdbserver_t::software_breakpoint_remove(reg_t vaddr, unsigned int size)
-{
-  fence_i_required = true;
-  add_operation(new collect_translation_info_op_t(*this, vaddr, size));
-
-  software_breakpoint_t found_bp = software_breakpoints[vaddr];
-  unsigned char* instruction = new unsigned char[4];
-  memcpy(instruction, found_bp.instruction, 4);
-  add_operation(new memory_write_op_t(*this, found_bp.vaddr,
-        found_bp.size, instruction));
-  software_breakpoints.erase(vaddr);
-}
-
-void gdbserver_t::hardware_breakpoint_insert(const hardware_breakpoint_t &bp)
-{
-  add_operation(new maybe_save_tselect_op_t(*this));
-  add_operation(new hardware_breakpoint_insert_op_t(*this, bp));
-}
-
-void gdbserver_t::hardware_breakpoint_remove(const hardware_breakpoint_t &bp)
-{
-  add_operation(new maybe_save_tselect_op_t(*this));
-  hardware_breakpoint_t found = *hardware_breakpoints.find(bp);
-  add_operation(new hardware_breakpoint_remove_op_t(*this, found));
-}
-
-void gdbserver_t::handle_breakpoint(const std::vector<uint8_t> &packet)
-{
-  // insert: Z type,addr,length
-  // remove: z type,addr,length
-
-  // type: 0 - software breakpoint, 1 - hardware breakpoint, 2 - write
-  // watchpoint, 3 - read watchpoint, 4 - access watchpoint; addr is address;
-  // length is in bytes. For a software breakpoint, length specifies the size
-  // of the instruction to be patched. For hardware breakpoints and watchpoints
-  // length specifies the memory region to be monitored. To avoid potential
-  // problems with duplicate packets, the operations should be implemented in
-  // an idempotent way.
-
-  bool insert = (packet[1] == 'Z');
-  std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
-  gdb_breakpoint_type_t type = static_cast<gdb_breakpoint_type_t>(
-      consume_hex_number(iter, packet.end()));
-  if (*iter != ',')
-    return send_packet("E50");
-  iter++;
-  reg_t address = consume_hex_number(iter, packet.end());
-  if (*iter != ',')
-    return send_packet("E51");
-  iter++;
-  unsigned int size = consume_hex_number(iter, packet.end());
-  // There may be more options after a ; here, but we don't support that.
-  if (*iter != '#')
-    return send_packet("E52");
-
-  switch (type) {
-    case GB_SOFTWARE:
-      if (size != 2 && size != 4) {
-        return send_packet("E53");
-      }
-      if (insert) {
-        software_breakpoint_insert(address, size);
-      } else {
-        software_breakpoint_remove(address, size);
-      }
-      break;
-
-    case GB_HARDWARE:
-    case GB_WRITE:
-    case GB_READ:
-    case GB_ACCESS:
-      {
-        hardware_breakpoint_t bp = {
-          .vaddr = address,
-          .size = size
-        };
-        bp.load = (type == GB_READ || type == GB_ACCESS);
-        bp.store = (type == GB_WRITE || type == GB_ACCESS);
-        bp.execute = (type == GB_HARDWARE || type == GB_ACCESS);
-        if (insert) {
-          hardware_breakpoint_insert(bp);
-          // Insert might fail if there's no space, so the insert operation will
-          // send its own OK (or not).
-          return;
-        } else {
-          hardware_breakpoint_remove(bp);
-        }
-      }
-      break;
-
-    default:
-      return send_packet("E56");
-  }
-
-  return send_packet("OK");
-}
-
-void gdbserver_t::handle_query(const std::vector<uint8_t> &packet)
-{
-  std::string name;
-  std::vector<uint8_t>::const_iterator iter = packet.begin() + 2;
-
-  consume_string(name, iter, packet.end(), ':');
-  if (iter != packet.end())
-    iter++;
-  if (name == "Supported") {
-    start_packet();
-    while (iter != packet.end()) {
-      std::string feature;
-      consume_string(feature, iter, packet.end(), ';');
-      if (iter != packet.end())
-        iter++;
-      if (feature == "swbreak+") {
-        send("swbreak+;");
-      }
-    }
-    send("PacketSize=131072;");
-    return end_packet();
-  }
-
-  D(fprintf(stderr, "Unsupported query %s\n", name.c_str()));
-  return send_packet("");
-}
-
-void gdbserver_t::handle_packet(const std::vector<uint8_t> &packet)
-{
-  if (compute_checksum(packet) != extract_checksum(packet)) {
-    fprintf(stderr, "Received %zd-byte packet with invalid checksum\n", packet.size());
-    fprintf(stderr, "Computed checksum: %x\n", compute_checksum(packet));
-    print_packet(packet);
-    send("-");
-    return;
-  }
-
-  D(fprintf(stderr, "Received %zd-byte packet from debug client: ", packet.size()));
-  D(print_packet(packet));
-  send("+");
-
-  switch (packet[1]) {
-    case '!':
-      return handle_extended(packet);
-    case '?':
-      return handle_halt_reason(packet);
-    case 'g':
-      return handle_general_registers_read(packet);
-//    case 'k':
-//      return handle_kill(packet);
-    case 'm':
-      return handle_memory_read(packet);
-//    case 'M':
-//      return handle_memory_write(packet);
-    case 'X':
-      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':
-      return handle_step(packet);
-    case 'z':
-    case 'Z':
-      return handle_breakpoint(packet);
-    case 'q':
-    case 'Q':
-      return handle_query(packet);
-  }
-
-  // Not supported.
-  D(fprintf(stderr, "** Unsupported packet: "));
-  D(print_packet(packet));
-  send_packet("");
-}
-
-void gdbserver_t::handle_interrupt()
-{
-  processor_t *p = sim->get_core(0);
-  add_operation(new halt_op_t(*this, true));
-}
-
-void gdbserver_t::handle()
-{
-  if (client_fd > 0) {
-    processor_t *p = sim->get_core(0);
-
-    bool interrupt = sim->debug_module.get_interrupt(0);
-
-    if (!interrupt && !operation_queue.empty()) {
-      operation_t *operation = operation_queue.front();
-      if (operation->step()) {
-        operation_queue.pop();
-        delete operation;
-      }
-    }
-
-    bool halt_notification = sim->debug_module.get_halt_notification(0);
-    if (halt_notification) {
-      sim->debug_module.clear_halt_notification(0);
-      add_operation(new halt_op_t(*this, true));
-    }
-
-    this->read();
-    this->write();
-
-  } else {
-    this->accept();
-  }
-
-  if (operation_queue.empty()) {
-    this->process_requests();
-  }
-}
-
-void gdbserver_t::send(const char* msg)
-{
-  unsigned int length = strlen(msg);
-  for (const char *c = msg; *c; c++)
-    running_checksum += *c;
-  send_buf.append((const uint8_t *) msg, length);
-}
-
-void gdbserver_t::send(uint64_t value)
-{
-  char buffer[3];
-  for (unsigned int i = 0; i < 8; i++) {
-    sprintf(buffer, "%02x", (int) (value & 0xff));
-    send(buffer);
-    value >>= 8;
-  }
-}
-
-void gdbserver_t::send(uint32_t value)
-{
-  char buffer[3];
-  for (unsigned int i = 0; i < 4; i++) {
-    sprintf(buffer, "%02x", (int) (value & 0xff));
-    send(buffer);
-    value >>= 8;
-  }
-}
-
-void gdbserver_t::send(uint8_t value)
-{
-  char buffer[3];
-  sprintf(buffer, "%02x", (int) value);
-  send(buffer);
-}
-
-void gdbserver_t::send_packet(const char* data)
-{
-  start_packet();
-  send(data);
-  end_packet();
-  expect_ack = true;
-}
-
-void gdbserver_t::start_packet()
-{
-  send("$");
-  running_checksum = 0;
-}
-
-void gdbserver_t::end_packet(const char* data)
-{
-  if (data) {
-    send(data);
-  }
-
-  char checksum_string[4];
-  sprintf(checksum_string, "#%02x", running_checksum);
-  send(checksum_string);
-  expect_ack = true;
-}
diff --git a/riscv/gdbserver.h b/riscv/gdbserver.h
deleted file mode 100644 (file)
index 8584215..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-#ifndef _RISCV_GDBSERVER_H
-#define _RISCV_GDBSERVER_H
-
-#include <map>
-#include <queue>
-
-#include <stdint.h>
-
-class sim_t;
-
-template <typename T>
-class circular_buffer_t
-{
-public:
-  // The buffer can store capacity-1 data elements.
-  circular_buffer_t(unsigned int capacity) : data(new T[capacity]),
-      start(0), end(0), capacity(capacity) {}
-  circular_buffer_t() : start(0), end(0), capacity(0) {}
-  ~circular_buffer_t() { delete[] data; }
-
-  T *data;
-  unsigned int start;   // Data start, inclusive.
-  unsigned int end;     // Data end, exclusive.
-  unsigned int capacity;    // Size of the buffer.
-  unsigned int size() const;
-  bool empty() const { return start == end; }
-  bool full() const { return ((end+1) % capacity) == start; }
-  T entry(unsigned index) { return data[(start + index) % capacity]; }
-
-  // Return size and address of the block of RAM where more data can be copied
-  // to be added to the buffer.
-  unsigned int contiguous_empty_size() const;
-  T *contiguous_empty() { return data + end; }
-  void data_added(unsigned int bytes);
-
-  unsigned int contiguous_data_size() const;
-  T *contiguous_data() { return data + start; }
-  // Tell the buffer that some bytes were consumed from the start of the
-  // buffer.
-  void consume(unsigned int bytes);
-
-  void reset();
-
-  T operator[](unsigned int i) const { return data[(start + i) % capacity]; }
-
-  void append(const T *src, unsigned int count);
-};
-
-// Class to track software breakpoints that we set.
-class software_breakpoint_t
-{
-  public:
-    reg_t vaddr;
-    unsigned int size;
-    unsigned char instruction[4];
-};
-
-class hardware_breakpoint_t
-{
-  public:
-    reg_t vaddr;
-    unsigned int size;
-    unsigned int index;
-    bool load, store, execute;
-};
-
-struct hardware_breakpoint_compare_t {
-  bool operator()(const hardware_breakpoint_t& a, const hardware_breakpoint_t& b) const {
-    if (a.vaddr != b.vaddr)
-      return a.vaddr < b.vaddr;
-    return a.size < b.size;
-  }
-};
-
-class gdbserver_t;
-
-class operation_t
-{
-  public:
-    operation_t(gdbserver_t& gdbserver) : gs(gdbserver), current_step(0) {}
-    virtual ~operation_t() {}
-
-    bool step() {
-      bool result = perform_step(current_step);
-      current_step++;
-      return result;
-    }
-
-    // Perform the next step of this operation (which is probably to write to
-    // Debug RAM and assert the debug interrupt).
-    // Return true if this operation is complete. In that case the object will
-    // be deleted.
-    // Return false if more steps are required the next time the debug
-    // interrupt is clear.
-    virtual bool perform_step(unsigned int step) = 0;
-
-  protected:
-    gdbserver_t& gs;
-    unsigned int current_step;
-};
-
-/*
- * word 32      64      128
- * 0    inst/0  inst/0  inst/0
- * 1    inst    inst/0  inst/0
- * 2    inst    inst    inst/0
- * 3    inst    inst    inst/0
- * 4    data0   data0   data0
- * 5    data1   data0   data0
- * 6    data2   data1   data0
- * 7            data1   data0
- * 8            data2   data1
- * 9            data2   data1
- * 10                   data1
- * 11                   data1
- * 12                   data2
- * 13                   data2
- * 14                   data2
- * 15                   data2
- */
-enum slot {
-  SLOT_INST0,
-  SLOT_DATA0,
-  SLOT_DATA1,
-  SLOT_DATA_LAST,
-};
-
-static const unsigned int slot_offset32[] = {0, 4, 5, DEBUG_RAM_SIZE/4 - 1};
-static const unsigned int slot_offset64[] = {0, 4, 6, DEBUG_RAM_SIZE/4 - 2};
-static const unsigned int slot_offset128[] = {0, 4, 8, DEBUG_RAM_SIZE/4 - 4};
-
-typedef enum {
-  GB_SOFTWARE = 0,
-  GB_HARDWARE = 1,
-  GB_WRITE = 2,
-  GB_READ = 3,
-  GB_ACCESS = 4,
-} gdb_breakpoint_type_t;
-
-class gdbserver_t
-{
-public:
-  // Create a new server, listening for connections from localhost on the given
-  // port.
-  gdbserver_t(uint16_t port, sim_t *sim);
-
-  // Process all pending messages from a client.
-  void handle();
-
-  void handle_packet(const std::vector<uint8_t> &packet);
-  void handle_interrupt();
-
-  void software_breakpoint_remove(reg_t vaddr, unsigned int size);
-  void software_breakpoint_insert(reg_t vaddr, unsigned int size);
-  void hardware_breakpoint_remove(const hardware_breakpoint_t &bp);
-  void hardware_breakpoint_insert(const hardware_breakpoint_t &bp);
-
-  void handle_breakpoint(const std::vector<uint8_t> &packet);
-  void handle_continue(const std::vector<uint8_t> &packet);
-  void handle_extended(const std::vector<uint8_t> &packet);
-  void handle_general_registers_read(const std::vector<uint8_t> &packet);
-  void continue_general_registers_read();
-  void handle_halt_reason(const std::vector<uint8_t> &packet);
-  void handle_kill(const std::vector<uint8_t> &packet);
-  void handle_memory_binary_write(const std::vector<uint8_t> &packet);
-  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 continue_register_read();
-  void handle_register_write(const std::vector<uint8_t> &packet);
-  void handle_step(const std::vector<uint8_t> &packet);
-
-  bool connected() const { return client_fd > 0; }
-
-  // TODO: Move this into its own packet sending class?
-  // Add the given message to send_buf.
-  void send(const char* msg);
-  // Hex-encode a 64-bit value, and send it to gcc in target byte order (little
-  // endian).
-  void send(uint64_t value);
-  // Hex-encode a 32-bit value, and send it to gcc in target byte order (little
-  // endian).
-  void send(uint32_t value);
-  // Hex-encode an 8-bit value, and send it to gcc.
-  void send(uint8_t value);
-  void send_packet(const char* data);
-  uint8_t running_checksum;
-  // Send "$" and clear running checksum.
-  void start_packet();
-  // Send "#" and checksum.
-  void end_packet(const char* data=NULL);
-
-  // Write value to the index'th word in Debug RAM.
-  void dr_write32(unsigned int index, uint32_t value);
-  void dr_write64(unsigned int index, uint64_t value);
-  void dr_write(enum slot slot, uint64_t value);
-  // Write jump-to-resume instruction to the index'th word in Debug RAM.
-  void dr_write_jump(unsigned int index);
-  // Write an xlen-bit store instruction.
-  void dr_write_store(unsigned int index, unsigned int reg, enum slot);
-  void dr_write_load(unsigned int index, unsigned int reg, enum slot);
-  uint32_t dr_read32(unsigned int index);
-  uint64_t dr_read64(unsigned int index);
-  uint64_t dr_read(enum slot slot);
-
-  uint64_t consume_hex_number_le(std::vector<uint8_t>::const_iterator &iter,
-      std::vector<uint8_t>::const_iterator end);
-
-  // Return access size to use when writing length bytes to address, so that
-  // every write will be aligned.
-  unsigned int find_access_size(reg_t address, int length);
-
-  void set_interrupt(uint32_t hartid);
-
-  // Members that ought to be privated, but that we'd really like to access
-  // from operation classes.
-  reg_t dpc;
-  reg_t dcsr;
-  reg_t mstatus;
-  bool mstatus_dirty;
-  reg_t sptbr;
-  bool sptbr_valid;
-  reg_t tselect;
-  bool tselect_valid;
-  bool fence_i_required;
-
-  std::map<reg_t, reg_t> pte_cache;
-
-  reg_t translate(reg_t vaddr);
-  // Return the PRV_x that is used when the code under debug performs a memory
-  // access.
-  unsigned int privilege_mode();
-
-  unsigned int xlen;
-
-  std::set<hardware_breakpoint_t, hardware_breakpoint_compare_t>
-    hardware_breakpoints;
-
-private:
-  sim_t *sim;
-  int socket_fd;
-  int client_fd;
-  circular_buffer_t<uint8_t> recv_buf;
-  circular_buffer_t<uint8_t> send_buf;
-
-  bool expect_ack;
-  bool extended_mode;
-  // Used to track whether we think the target is running. If we think it is
-  // but it isn't, we need to tell gdb about it.
-  bool running;
-
-  std::map<reg_t, software_breakpoint_t> software_breakpoints;
-
-  // Read pending data from the client.
-  void read();
-  void write();
-  // Accept a new client if there isn't one already connected.
-  void accept();
-  // Process all complete requests in recv_buf.
-  void process_requests();
-
-  std::queue<operation_t*> operation_queue;
-  void add_operation(operation_t* operation);
-};
-
-#endif
diff --git a/riscv/jtag_dtm.cc b/riscv/jtag_dtm.cc
new file mode 100644 (file)
index 0000000..cd3f3ee
--- /dev/null
@@ -0,0 +1,180 @@
+#include <stdio.h>
+
+#include "decode.h"
+#include "jtag_dtm.h"
+#include "debug_module.h"
+#include "debug_defines.h"
+
+#if 0
+#  define D(x) x
+#else
+#  define D(x)
+#endif
+
+enum {
+  IR_IDCODE=1,
+  IR_DTMCONTROL=0x10,
+  IR_DBUS=0x11
+};
+
+#define DTMCONTROL_VERSION      0xf
+#define DTMCONTROL_ABITS        (0x3f << 4)
+#define DTMCONTROL_DBUSSTAT     (3<<10)
+#define DTMCONTROL_IDLE         (7<<12)
+#define DTMCONTROL_DBUSRESET    (1<<16)
+
+#define DMI_OP                 3
+#define DMI_DATA               (0xffffffffL<<2)
+#define DMI_ADDRESS            ((1L<<(abits+34)) - (1L<<34))
+
+#define DMI_OP_STATUS_SUCCESS  0
+#define DMI_OP_STATUS_RESERVED 1
+#define DMI_OP_STATUS_FAILED   2
+#define DMI_OP_STATUS_BUSY     3
+
+#define DMI_OP_NOP             0
+#define DMI_OP_READ            1
+#define DMI_OP_WRITE           2
+#define DMI_OP_RESERVED                3
+
+jtag_dtm_t::jtag_dtm_t(debug_module_t *dm) :
+  dm(dm),
+  _tck(false), _tms(false), _tdi(false), _tdo(false),
+  dtmcontrol((abits << DTM_DTMCS_ABITS_OFFSET) | 1),
+  dmi(DMI_OP_STATUS_FAILED << DTM_DMI_OP_OFFSET),
+  _state(TEST_LOGIC_RESET)
+{
+}
+
+void jtag_dtm_t::reset() {
+  _state = TEST_LOGIC_RESET;
+}
+
+void jtag_dtm_t::set_pins(bool tck, bool tms, bool tdi) {
+  const jtag_state_t next[16][2] = {
+    /* TEST_LOGIC_RESET */    { RUN_TEST_IDLE, TEST_LOGIC_RESET },
+    /* RUN_TEST_IDLE */       { RUN_TEST_IDLE, SELECT_DR_SCAN },
+    /* SELECT_DR_SCAN */      { CAPTURE_DR, SELECT_IR_SCAN },
+    /* CAPTURE_DR */          { SHIFT_DR, EXIT1_DR },
+    /* SHIFT_DR */            { SHIFT_DR, EXIT1_DR },
+    /* EXIT1_DR */            { PAUSE_DR, UPDATE_DR },
+    /* PAUSE_DR */            { PAUSE_DR, EXIT2_DR },
+    /* EXIT2_DR */            { SHIFT_DR, UPDATE_DR },
+    /* UPDATE_DR */           { RUN_TEST_IDLE, SELECT_DR_SCAN },
+    /* SELECT_IR_SCAN */      { CAPTURE_IR, TEST_LOGIC_RESET },
+    /* CAPTURE_IR */          { SHIFT_IR, EXIT1_IR },
+    /* SHIFT_IR */            { SHIFT_IR, EXIT1_IR },
+    /* EXIT1_IR */            { PAUSE_IR, UPDATE_IR },
+    /* PAUSE_IR */            { PAUSE_IR, EXIT2_IR },
+    /* EXIT2_IR */            { SHIFT_IR, UPDATE_IR },
+    /* UPDATE_IR */           { RUN_TEST_IDLE, SELECT_DR_SCAN }
+  };
+
+  if (!_tck && tck) {
+    // Positive clock edge.
+
+    switch (_state) {
+      case SHIFT_DR:
+        dr >>= 1;
+        dr |= (uint64_t) _tdi << (dr_length-1);
+        break;
+      case SHIFT_IR:
+        ir >>= 1;
+        ir |= _tdi << (ir_length-1);
+        break;
+      default:
+        break;
+    }
+    _state = next[_state][_tms];
+    switch (_state) {
+      case TEST_LOGIC_RESET:
+        ir = IR_IDCODE;
+        break;
+      case CAPTURE_DR:
+        capture_dr();
+        break;
+      case SHIFT_DR:
+        _tdo = dr & 1;
+        break;
+      case UPDATE_DR:
+        update_dr();
+        break;
+      case CAPTURE_IR:
+        break;
+      case SHIFT_IR:
+        _tdo = ir & 1;
+        break;
+      case UPDATE_IR:
+        break;
+      default:
+        break;
+    }
+  }
+
+  D(fprintf(stderr, "state=%2d, tdi=%d, tdo=%d, tms=%d, tck=%d, ir=0x%02x, "
+        "dr=0x%lx\n",
+        _state, _tdi, _tdo, _tms, _tck, ir, dr));
+
+  _tck = tck;
+  _tms = tms;
+  _tdi = tdi;
+}
+
+void jtag_dtm_t::capture_dr()
+{
+  switch (ir) {
+    case IR_IDCODE:
+      dr = idcode;
+      dr_length = 32;
+      break;
+    case IR_DTMCONTROL:
+      dr = dtmcontrol;
+      dr_length = 32;
+      break;
+    case IR_DBUS:
+      dr = dmi;
+      dr_length = abits + 34;
+      break;
+    default:
+      D(fprintf(stderr, "Unsupported IR: 0x%x\n", ir));
+      break;
+  }
+  D(fprintf(stderr, "Capture DR; IR=0x%x, DR=0x%lx (%d bits)\n",
+        ir, dr, dr_length));
+}
+
+void jtag_dtm_t::update_dr()
+{
+  D(fprintf(stderr, "Update DR; IR=0x%x, DR=0x%lx (%d bits)\n",
+        ir, dr, dr_length));
+  switch (ir) {
+    case IR_DBUS:
+      {
+        unsigned op = get_field(dr, DMI_OP);
+        uint32_t data = get_field(dr, DMI_DATA);
+        unsigned address = get_field(dr, DMI_ADDRESS);
+
+        dmi = dr;
+
+        bool success = true;
+        if (op == DMI_OP_READ) {
+          uint32_t value;
+          if (dm->dmi_read(address, &value)) {
+            dmi = set_field(dmi, DMI_DATA, value);
+          } else {
+            success = false;
+          }
+        } else if (op == DMI_OP_WRITE) {
+          success = dm->dmi_write(address, data);
+        }
+
+        if (success) {
+          dmi = set_field(dmi, DMI_OP, DMI_OP_STATUS_SUCCESS);
+        } else {
+          dmi = set_field(dmi, DMI_OP, DMI_OP_STATUS_FAILED);
+        }
+        D(fprintf(stderr, "dmi=0x%lx\n", dmi));
+      }
+      break;
+  }
+}
diff --git a/riscv/jtag_dtm.h b/riscv/jtag_dtm.h
new file mode 100644 (file)
index 0000000..063e3f4
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef JTAG_DTM_H
+#define JTAG_DTM_H
+
+#include <stdint.h>
+
+class debug_module_t;
+
+typedef enum {
+  TEST_LOGIC_RESET,
+  RUN_TEST_IDLE,
+  SELECT_DR_SCAN,
+  CAPTURE_DR,
+  SHIFT_DR,
+  EXIT1_DR,
+  PAUSE_DR,
+  EXIT2_DR,
+  UPDATE_DR,
+  SELECT_IR_SCAN,
+  CAPTURE_IR,
+  SHIFT_IR,
+  EXIT1_IR,
+  PAUSE_IR,
+  EXIT2_IR,
+  UPDATE_IR
+} jtag_state_t;
+
+class jtag_dtm_t
+{
+  static const unsigned idcode = 0xdeadbeef;
+
+  public:
+    jtag_dtm_t(debug_module_t *dm);
+    void reset();
+
+    void set_pins(bool tck, bool tms, bool tdi);
+
+    bool tdo() const { return _tdo; }
+
+    jtag_state_t state() const { return _state; }
+
+  private:
+    debug_module_t *dm;
+    bool _tck, _tms, _tdi, _tdo;
+    uint32_t ir;
+    const unsigned ir_length = 5;
+    uint64_t dr;
+    unsigned dr_length;
+
+    // abits must come before dtmcontrol so it can easily be used in the
+    // constructor.
+    const unsigned abits = 6;
+    uint32_t dtmcontrol;
+    uint64_t dmi;
+
+    jtag_state_t _state;
+
+    void capture_dr();
+    void update_dr();
+};
+
+#endif
diff --git a/riscv/opcodes.h b/riscv/opcodes.h
new file mode 100644 (file)
index 0000000..34c089e
--- /dev/null
@@ -0,0 +1,244 @@
+#include "encoding.h"
+
+#define ZERO   0
+#define T0      5
+#define S0      8
+#define S1      9
+
+static uint32_t bits(uint32_t value, unsigned int hi, unsigned int lo) {
+  return (value >> lo) & ((1 << (hi+1-lo)) - 1);
+}
+
+static uint32_t bit(uint32_t value, unsigned int b) {
+  return (value >> b) & 1;
+}
+
+static uint32_t jal(unsigned int rd, uint32_t imm) __attribute__ ((unused));
+static uint32_t jal(unsigned int rd, uint32_t imm) {
+  return (bit(imm, 20) << 31) |
+    (bits(imm, 10, 1) << 21) |
+    (bit(imm, 11) << 20) |
+    (bits(imm, 19, 12) << 12) |
+    (rd << 7) |
+    MATCH_JAL;
+}
+
+static uint32_t csrsi(unsigned int csr, uint16_t imm) __attribute__ ((unused));
+static uint32_t csrsi(unsigned int csr, uint16_t imm) {
+  return (csr << 20) |
+    (bits(imm, 4, 0) << 15) |
+    MATCH_CSRRSI;
+}
+
+static uint32_t sw(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t sw(unsigned int src, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 5) << 25) |
+    (src << 20) |
+    (base << 15) |
+    (bits(offset, 4, 0) << 7) |
+    MATCH_SW;
+}
+
+static uint32_t sd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t sd(unsigned int src, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 5) << 25) |
+    (src << 20) |
+    (base << 15) |
+    (bits(offset, 4, 0) << 7) |
+    MATCH_SD;
+}
+
+static uint32_t sh(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t sh(unsigned int src, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 5) << 25) |
+    (src << 20) |
+    (base << 15) |
+    (bits(offset, 4, 0) << 7) |
+    MATCH_SH;
+}
+
+static uint32_t sb(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t sb(unsigned int src, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 5) << 25) |
+    (src << 20) |
+    (base << 15) |
+    (bits(offset, 4, 0) << 7) |
+    MATCH_SB;
+}
+
+static uint32_t ld(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t ld(unsigned int rd, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 0) << 20) |
+    (base << 15) |
+    (bits(rd, 4, 0) << 7) |
+    MATCH_LD;
+}
+
+static uint32_t lw(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t lw(unsigned int rd, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 0) << 20) |
+    (base << 15) |
+    (bits(rd, 4, 0) << 7) |
+    MATCH_LW;
+}
+
+static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 0) << 20) |
+    (base << 15) |
+    (bits(rd, 4, 0) << 7) |
+    MATCH_LH;
+}
+
+static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 0) << 20) |
+    (base << 15) |
+    (bits(rd, 4, 0) << 7) |
+    MATCH_LB;
+}
+
+static uint32_t csrw(unsigned int source, unsigned int csr) __attribute__ ((unused));
+static uint32_t csrw(unsigned int source, unsigned int csr) {
+  return (csr << 20) | (source << 15) | MATCH_CSRRW;
+}
+
+static uint32_t addi(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused));
+static uint32_t addi(unsigned int dest, unsigned int src, uint16_t imm)
+{
+  return (bits(imm, 11, 0) << 20) |
+    (src << 15) |
+    (dest << 7) |
+    MATCH_ADDI;
+}
+
+static uint32_t csrr(unsigned int rd, unsigned int csr) __attribute__ ((unused));
+static uint32_t csrr(unsigned int rd, unsigned int csr) {
+  return (csr << 20) | (rd << 7) | MATCH_CSRRS;
+}
+
+static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 5) << 25) |
+    (bits(src, 4, 0) << 20) |
+    (base << 15) |
+    (bits(offset, 4, 0) << 7) |
+    MATCH_FSW;
+}
+
+static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 5) << 25) |
+    (bits(src, 4, 0) << 20) |
+    (base << 15) |
+    (bits(offset, 4, 0) << 7) |
+    MATCH_FSD;
+}
+
+static uint32_t flw(unsigned int dest, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t flw(unsigned int dest, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 0) << 20) |
+    (base << 15) |
+    (bits(dest, 4, 0) << 7) |
+    MATCH_FLW;
+}
+
+static uint32_t fld(unsigned int dest, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t fld(unsigned int dest, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 0) << 20) |
+    (base << 15) |
+    (bits(dest, 4, 0) << 7) |
+    MATCH_FLD;
+}
+
+static uint32_t ebreak(void) __attribute__ ((unused));
+static uint32_t ebreak(void) { return MATCH_EBREAK; }
+static uint32_t ebreak_c(void) __attribute__ ((unused));
+static uint32_t ebreak_c(void) { return MATCH_C_EBREAK; }
+
+static uint32_t dret(void) __attribute__ ((unused));
+static uint32_t dret(void) { return MATCH_DRET; }
+
+static uint32_t fence_i(void) __attribute__ ((unused));
+static uint32_t fence_i(void)
+{
+  return MATCH_FENCE_I;
+}
+
+/*
+static uint32_t lui(unsigned int dest, uint32_t imm) __attribute__ ((unused));
+static uint32_t lui(unsigned int dest, uint32_t imm)
+{
+  return (bits(imm, 19, 0) << 12) |
+    (dest << 7) |
+    MATCH_LUI;
+}
+
+static uint32_t csrci(unsigned int csr, uint16_t imm) __attribute__ ((unused));
+static uint32_t csrci(unsigned int csr, uint16_t imm) {
+  return (csr << 20) |
+    (bits(imm, 4, 0) << 15) |
+    MATCH_CSRRCI;
+}
+
+static uint32_t li(unsigned int dest, uint16_t imm) __attribute__ ((unused));
+static uint32_t li(unsigned int dest, uint16_t imm)
+{
+       return addi(dest, 0, imm);
+}
+
+static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset)
+{
+  return (bits(offset, 11, 5) << 25) |
+    (bits(src, 4, 0) << 20) |
+    (base << 15) |
+    (bits(offset, 4, 0) << 7) |
+    MATCH_FSD;
+}
+
+static uint32_t ori(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused));
+static uint32_t ori(unsigned int dest, unsigned int src, uint16_t imm)
+{
+  return (bits(imm, 11, 0) << 20) |
+    (src << 15) |
+    (dest << 7) |
+    MATCH_ORI;
+}
+
+static uint32_t nop(void) __attribute__ ((unused));
+static uint32_t nop(void)
+{
+  return addi(0, 0, 0);
+}
+*/
+
+static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused));
+static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm)
+{
+  return (bits(imm, 11, 0) << 20) |
+    (src << 15) |
+    (dest << 7) |
+    MATCH_XORI;
+}
+
+static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt) __attribute__ ((unused));
+static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt)
+{
+       return (bits(shamt, 4, 0) << 20) |
+               (src << 15) |
+               (dest << 7) |
+               MATCH_SRLI;
+}
index ab5640e23aaca13ee2013a5ca63304ce042df59a..ef529fc20c1d6d885b2fc7b22abad7060302a68c 100644 (file)
@@ -7,7 +7,6 @@
 #include "sim.h"
 #include "mmu.h"
 #include "disasm.h"
-#include "gdbserver.h"
 #include <cinttypes>
 #include <cmath>
 #include <cstdlib>
@@ -22,7 +21,8 @@
 
 processor_t::processor_t(const char* isa, sim_t* sim, uint32_t id,
         bool halt_on_reset)
-  : debug(false), sim(sim), ext(NULL), id(id), halt_on_reset(halt_on_reset)
+  : debug(false), halt_request(false), sim(sim), ext(NULL), id(id),
+  halt_on_reset(halt_on_reset)
 {
   parse_isa_string(isa);
   register_base_instructions();
@@ -193,7 +193,7 @@ void processor_t::enter_debug_mode(uint8_t cause)
   state.dcsr.prv = state.prv;
   set_privilege(PRV_M);
   state.dpc = state.pc;
-  state.pc = DEBUG_ROM_START;
+  state.pc = debug_rom_entry();
 }
 
 void processor_t::take_trap(trap_t& t, reg_t epc)
@@ -206,6 +206,15 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
           t.get_badaddr());
   }
 
+  if (state.dcsr.cause) {
+    if (t.cause() == CAUSE_BREAKPOINT) {
+      state.pc = debug_rom_entry();
+    } else {
+      state.pc = DEBUG_ROM_EXCEPTION;
+    }
+    return;
+  }
+
   if (t.cause() == CAUSE_BREAKPOINT && (
               (state.prv == PRV_M && state.dcsr.ebreakm) ||
               (state.prv == PRV_H && state.dcsr.ebreakh) ||
@@ -215,11 +224,6 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
     return;
   }
 
-  if (state.dcsr.cause) {
-    state.pc = DEBUG_ROM_EXCEPTION;
-    return;
-  }
-
   // by default, trap to M-mode, unless delegated to S-mode
   reg_t bit = t.cause();
   reg_t deleg = state.medeleg;
@@ -261,9 +265,23 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
 
 void processor_t::disasm(insn_t insn)
 {
+  static uint64_t last_pc = 1, last_bits;
+  static uint64_t executions = 1;
+
   uint64_t bits = insn.bits() & ((1ULL << (8 * insn_length(insn.bits()))) - 1);
-  fprintf(stderr, "core %3d: 0x%016" PRIx64 " (0x%08" PRIx64 ") %s\n",
-          id, state.pc, bits, disassembler->disassemble(insn).c_str());
+  if (last_pc != state.pc || last_bits != bits) {
+    if (executions != 1) {
+      fprintf(stderr, "core %3d: Executed %" PRIx64 " times\n", id, executions);
+    }
+
+    fprintf(stderr, "core %3d: 0x%016" PRIx64 " (0x%08" PRIx64 ") %s\n",
+            id, state.pc, bits, disassembler->disassemble(insn).c_str());
+    last_pc = state.pc;
+    last_bits = bits;
+    executions = 1;
+  } else {
+    executions++;
+  }
 }
 
 int processor_t::paddr_bits()
@@ -586,19 +604,15 @@ reg_t processor_t::get_csr(int which)
       {
         uint32_t v = 0;
         v = set_field(v, DCSR_XDEBUGVER, 1);
-        v = set_field(v, DCSR_NDRESET, 0);
-        v = set_field(v, DCSR_FULLRESET, 0);
-        v = set_field(v, DCSR_PRV, state.dcsr.prv);
-        v = set_field(v, DCSR_STEP, state.dcsr.step);
-        v = set_field(v, DCSR_DEBUGINT, sim->debug_module.get_interrupt(id));
-        v = set_field(v, DCSR_STOPCYCLE, 0);
-        v = set_field(v, DCSR_STOPTIME, 0);
         v = set_field(v, DCSR_EBREAKM, state.dcsr.ebreakm);
         v = set_field(v, DCSR_EBREAKH, state.dcsr.ebreakh);
         v = set_field(v, DCSR_EBREAKS, state.dcsr.ebreaks);
         v = set_field(v, DCSR_EBREAKU, state.dcsr.ebreaku);
-        v = set_field(v, DCSR_HALT, state.dcsr.halt);
+        v = set_field(v, DCSR_STOPCYCLE, 0);
+        v = set_field(v, DCSR_STOPTIME, 0);
         v = set_field(v, DCSR_CAUSE, state.dcsr.cause);
+        v = set_field(v, DCSR_STEP, state.dcsr.step);
+        v = set_field(v, DCSR_PRV, state.dcsr.prv);
         return v;
       }
     case CSR_DPC:
index 7e9e932f7b13a8c5cd4cb3275c3a697913c6f0f1..4d94d5b42a9a181886c4a520fead3cd0edf67a97 100644 (file)
@@ -191,6 +191,13 @@ public:
   bool debug;
   // When true, take the slow simulation path.
   bool slow_path();
+  bool halted() { return state.dcsr.cause ? true : false; }
+  bool halt_request;
+  // The unique debug rom address that this hart jumps to when entering debug
+  // mode. Rely on the fact that spike hart IDs start at 0 and are consecutive.
+  uint32_t debug_rom_entry() {
+    return DEBUG_ROM_ENTRY + 4 * id;
+  }
 
   // Return the index of a trigger that matched, or -1.
   inline int trigger_match(trigger_operation_t operation, reg_t address, reg_t data)
diff --git a/riscv/remote_bitbang.cc b/riscv/remote_bitbang.cc
new file mode 100644 (file)
index 0000000..9d0ca90
--- /dev/null
@@ -0,0 +1,174 @@
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <cassert>
+#include <cstdio>
+
+#include "remote_bitbang.h"
+
+#if 1
+#  define D(x) x
+#else
+#  define D(x)
+#endif
+
+/////////// remote_bitbang_t
+
+remote_bitbang_t::remote_bitbang_t(uint16_t port, jtag_dtm_t *tap) :
+  tap(tap),
+  socket_fd(0),
+  client_fd(0),
+  recv_start(0),
+  recv_end(0)
+{
+  socket_fd = socket(AF_INET, SOCK_STREAM, 0);
+  if (socket_fd == -1) {
+    fprintf(stderr, "remote_bitbang failed to make socket: %s (%d)\n",
+        strerror(errno), errno);
+    abort();
+  }
+
+  fcntl(socket_fd, F_SETFL, O_NONBLOCK);
+  int reuseaddr = 1;
+  if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
+        sizeof(int)) == -1) {
+    fprintf(stderr, "remote_bitbang failed setsockopt: %s (%d)\n",
+        strerror(errno), errno);
+    abort();
+  }
+
+  struct sockaddr_in addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = INADDR_ANY;
+  addr.sin_port = htons(port);
+
+  if (bind(socket_fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
+    fprintf(stderr, "remote_bitbang failed to bind socket: %s (%d)\n",
+        strerror(errno), errno);
+    abort();
+  }
+
+  if (listen(socket_fd, 1) == -1) {
+    fprintf(stderr, "remote_bitbang failed to listen on socket: %s (%d)\n",
+        strerror(errno), errno);
+    abort();
+  }
+
+  socklen_t addrlen = sizeof(addr);
+  if (getsockname(socket_fd, (struct sockaddr *) &addr, &addrlen) == -1) {
+    fprintf(stderr, "remote_bitbang getsockname failed: %s (%d)\n",
+        strerror(errno), errno);
+    abort();
+  }
+
+  printf("Listening for remote bitbang connection on port %d.\n",
+      ntohs(addr.sin_port));
+  fflush(stdout);
+}
+
+void remote_bitbang_t::accept()
+{
+  client_fd = ::accept(socket_fd, NULL, NULL);
+  if (client_fd == -1) {
+    if (errno == EAGAIN) {
+      // No client waiting to connect right now.
+    } else {
+      fprintf(stderr, "failed to accept on socket: %s (%d)\n", strerror(errno),
+          errno);
+      abort();
+    }
+  } else {
+    fcntl(client_fd, F_SETFL, O_NONBLOCK);
+  }
+}
+
+void remote_bitbang_t::tick()
+{
+  if (client_fd > 0) {
+    execute_commands();
+  } else {
+    this->accept();
+  }
+}
+
+void remote_bitbang_t::execute_commands()
+{
+  static char send_buf[buf_size];
+  unsigned total_processed = 0;
+  bool quit = false;
+  bool in_rti = tap->state() == RUN_TEST_IDLE;
+  bool entered_rti = false;
+  while (1) {
+    if (recv_start < recv_end) {
+      unsigned send_offset = 0;
+      while (recv_start < recv_end) {
+        uint8_t command = recv_buf[recv_start];
+
+        switch (command) {
+          case 'B': /* fprintf(stderr, "*BLINK*\n"); */ break;
+          case 'b': /* fprintf(stderr, "_______\n"); */ break;
+          case 'r': tap->reset(); break;
+          case '0': tap->set_pins(0, 0, 0); break;
+          case '1': tap->set_pins(0, 0, 1); break;
+          case '2': tap->set_pins(0, 1, 0); break;
+          case '3': tap->set_pins(0, 1, 1); break;
+          case '4': tap->set_pins(1, 0, 0); break;
+          case '5': tap->set_pins(1, 0, 1); break;
+          case '6': tap->set_pins(1, 1, 0); break;
+          case '7': tap->set_pins(1, 1, 1); break;
+          case 'R': send_buf[send_offset++] = tap->tdo() ? '1' : '0'; break;
+          case 'Q': quit = true; break;
+          default:
+                    fprintf(stderr, "remote_bitbang got unsupported command '%c'\n",
+                        command);
+        }
+        recv_start++;
+        total_processed++;
+        if (!in_rti && tap->state() == RUN_TEST_IDLE) {
+          entered_rti = true;
+          break;
+        }
+        in_rti = false;
+      }
+      unsigned sent = 0;
+      while (sent < send_offset) {
+        ssize_t bytes = write(client_fd, send_buf + sent, send_offset);
+        if (bytes == -1) {
+          fprintf(stderr, "failed to write to socket: %s (%d)\n", strerror(errno), errno);
+          abort();
+        }
+        sent += bytes;
+      }
+    }
+
+    if (total_processed > buf_size || quit || entered_rti) {
+      // Don't go forever, because that could starve the main simulation.
+      break;
+    }
+
+    recv_start = 0;
+    recv_end = read(client_fd, recv_buf, buf_size);
+
+    if (recv_end == -1) {
+      if (errno == EAGAIN) {
+        // We'll try again the next call.
+      } else {
+        fprintf(stderr, "remote_bitbang failed to read on socket: %s (%d)\n",
+            strerror(errno), errno);
+        abort();
+      }
+    }
+    if (recv_end == 0 || quit) {
+      // The remote disconnected.
+      close(client_fd);
+      client_fd = 0;
+      break;
+    }
+  }
+}
diff --git a/riscv/remote_bitbang.h b/riscv/remote_bitbang.h
new file mode 100644 (file)
index 0000000..1db4d55
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef REMOTE_BITBANG_H
+#define REMOTE_BITBANG_H
+
+#include <stdint.h>
+
+#include "jtag_dtm.h"
+
+class remote_bitbang_t
+{
+public:
+  // Create a new server, listening for connections from localhost on the given
+  // port.
+  remote_bitbang_t(uint16_t port, jtag_dtm_t *tap);
+
+  // Do a bit of work.
+  void tick();
+
+private:
+  jtag_dtm_t *tap;
+
+  int socket_fd;
+  int client_fd;
+
+  static const ssize_t buf_size = 64 * 1024;
+  char recv_buf[buf_size];
+  ssize_t recv_start, recv_end;
+
+  // Check for a client connecting, and accept if there is one.
+  void accept();
+  // Execute any commands the client has for us.
+  void execute_commands();
+};
+
+#endif
index e9544162f756250c0c5b61493c3709c2a43eec2c..9cd8f4dbef2c08599371c3880e0498d260e19eaf 100644 (file)
@@ -23,8 +23,9 @@ riscv_hdrs = \
        rocc.h \
        insn_template.h \
        mulhi.h \
-       gdbserver.h \
        debug_module.h \
+       remote_bitbang.h \
+       jtag_dtm.h \
 
 riscv_precompiled_hdrs = \
        insn_template.h \
@@ -44,9 +45,12 @@ riscv_srcs = \
        regnames.cc \
        devices.cc \
        rom.cc \
+       rtc.cc \
        clint.cc \
        gdbserver.cc \
        debug_module.cc \
+       remote_bitbang.cc \
+       jtag_dtm.cc \
        $(riscv_gen_srcs) \
 
 riscv_test_srcs =
index 7a10c9b4d2c9a4705cf726c0bd638e242950f7b4..a44ced6a832a67950bd4d620b1b66cccde310c15 100644 (file)
@@ -2,7 +2,7 @@
 
 #include "sim.h"
 #include "mmu.h"
-#include "gdbserver.h"
+#include "remote_bitbang.h"
 #include <map>
 #include <iostream>
 #include <sstream>
@@ -25,8 +25,8 @@ static void handle_signal(int sig)
 
 sim_t::sim_t(const char* isa, size_t nprocs, size_t mem_mb, bool halted,
              const std::vector<std::string>& args)
-  : htif_t(args), procs(std::max(nprocs, size_t(1))),
-    current_step(0), current_proc(0), debug(false), gdbserver(NULL)
+  : htif_t(args), debug_module(this), procs(std::max(nprocs, size_t(1))),
+    current_step(0), current_proc(0), debug(false), remote_bitbang(NULL)
 {
   signal(SIGINT, &handle_signal);
   // allocate target machine's memory, shrinking it as necessary
@@ -44,7 +44,7 @@ sim_t::sim_t(const char* isa, size_t nprocs, size_t mem_mb, bool halted,
     fprintf(stderr, "warning: only got %zu bytes of target mem (wanted %zu)\n",
             memsz, memsz0);
 
-  bus.add_device(DEBUG_START, &debug_module);
+  debug_module.add_device(&bus);
 
   debug_mmu = new mmu_t(this, NULL);
 
@@ -82,8 +82,8 @@ void sim_t::main()
       interactive();
     else
       step(INTERLEAVE);
-    if (gdbserver) {
-      gdbserver->handle();
+    if (remote_bitbang) {
+      remote_bitbang->tick();
     }
   }
 }
index 8586bee2cf970ee449227af57b72f6da991c5f3b..d3353a1bbcfd4cebb79abcfddadd11c552b14ea1 100644 (file)
@@ -13,7 +13,7 @@
 #include <memory>
 
 class mmu_t;
-class gdbserver_t;
+class remote_bitbang_t;
 
 // this class encapsulates the processors and memory in a RISC-V machine.
 class sim_t : public htif_t
@@ -29,9 +29,14 @@ public:
   void set_log(bool value);
   void set_histogram(bool value);
   void set_procs_debug(bool value);
-  void set_gdbserver(gdbserver_t* gdbserver) { this->gdbserver = gdbserver; }
+  void set_remote_bitbang(remote_bitbang_t* remote_bitbang) {
+    this->remote_bitbang = remote_bitbang;
+  }
   const char* get_dts() { return dts.c_str(); }
   processor_t* get_core(size_t i) { return procs.at(i); }
+  unsigned nprocs() const { return procs.size(); }
+
+  debug_module_t debug_module;
 
 private:
   char* mem; // main memory
@@ -42,7 +47,6 @@ private:
   std::unique_ptr<rom_device_t> boot_rom;
   std::unique_ptr<clint_t> clint;
   bus_t bus;
-  debug_module_t debug_module;
 
   processor_t* get_core(const std::string& i);
   void step(size_t n); // step through simulation
@@ -54,7 +58,7 @@ private:
   bool debug;
   bool log;
   bool histogram_enabled; // provide a histogram of PCs
-  gdbserver_t* gdbserver;
+  remote_bitbang_t* remote_bitbang;
 
   // memory-mapped I/O routines
   bool addr_is_mem(reg_t addr) {
@@ -90,7 +94,6 @@ private:
 
   friend class processor_t;
   friend class mmu_t;
-  friend class gdbserver_t;
 
   // htif
   friend void sim_thread_main(void*);
index dde6f5a5b902e458c9b3b7f9a0ffd7aefc188590..38529b2504e3297e2101e7594cd63ec9c6db305a 100644 (file)
@@ -2,7 +2,7 @@
 
 #include "sim.h"
 #include "mmu.h"
-#include "gdbserver.h"
+#include "remote_bitbang.h"
 #include "cachesim.h"
 #include "extension.h"
 #include <dlfcn.h>
@@ -30,7 +30,7 @@ static void help()
   fprintf(stderr, "  --l2=<S>:<W>:<B>        B both powers of 2).\n");
   fprintf(stderr, "  --extension=<name>    Specify RoCC Extension\n");
   fprintf(stderr, "  --extlib=<name>       Shared library to load\n");
-  fprintf(stderr, "  --gdb-port=<port>  Listen on <port> for gdb to connect\n");
+  fprintf(stderr, "  --rbb-port=<port>     Listen on <port> for remote bitbang connection\n");
   fprintf(stderr, "  --dump-dts  Print device tree string and exit\n");
   exit(1);
 }
@@ -49,7 +49,8 @@ int main(int argc, char** argv)
   std::unique_ptr<cache_sim_t> l2;
   std::function<extension_t*()> extension;
   const char* isa = DEFAULT_ISA;
-  uint16_t gdb_port = 0;
+  uint16_t rbb_port = 0;
+  bool use_rbb = false;
 
   option_parser_t parser;
   parser.help(&help);
@@ -61,7 +62,7 @@ int main(int argc, char** argv)
   parser.option('m', 0, 1, [&](const char* s){mem_mb = atoi(s);});
   // I wanted to use --halted, but for some reason that doesn't work.
   parser.option('H', 0, 0, [&](const char* s){halted = true;});
-  parser.option(0, "gdb-port", 1, [&](const char* s){gdb_port = atoi(s);});
+  parser.option(0, "rbb-port", 1, [&](const char* s){use_rbb = true; rbb_port = atoi(s);});
   parser.option(0, "ic", 1, [&](const char* s){ic.reset(new icache_sim_t(s));});
   parser.option(0, "dc", 1, [&](const char* s){dc.reset(new dcache_sim_t(s));});
   parser.option(0, "l2", 1, [&](const char* s){l2.reset(cache_sim_t::construct(s, "L2$"));});
@@ -79,10 +80,11 @@ int main(int argc, char** argv)
   auto argv1 = parser.parse(argv);
   std::vector<std::string> htif_args(argv1, (const char*const*)argv + argc);
   sim_t s(isa, nprocs, mem_mb, halted, htif_args);
-  std::unique_ptr<gdbserver_t> gdbserver;
-  if (gdb_port) {
-    gdbserver = std::unique_ptr<gdbserver_t>(new gdbserver_t(gdb_port, &s));
-    s.set_gdbserver(&(*gdbserver));
+  std::unique_ptr<jtag_dtm_t> jtag_dtm(new jtag_dtm_t(&s.debug_module));
+  std::unique_ptr<remote_bitbang_t> remote_bitbang((remote_bitbang_t *) NULL);
+  if (use_rbb) {
+    remote_bitbang.reset(new remote_bitbang_t(rbb_port, &(*jtag_dtm)));
+    s.set_remote_bitbang(&(*remote_bitbang));
   }
 
   if (dump_dts) {