OpenOCD connects, and sends some data that we receive.
authorTim Newsome <tim@sifive.com>
Fri, 3 Feb 2017 19:29:54 +0000 (11:29 -0800)
committerTim Newsome <tim@sifive.com>
Fri, 3 Feb 2017 19:29:54 +0000 (11:29 -0800)
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/riscv/remote_bitbang.cc b/riscv/remote_bitbang.cc
new file mode 100644 (file)
index 0000000..13b6a3c
--- /dev/null
@@ -0,0 +1,211 @@
+#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"
+
+#define DEBUG
+#ifdef DEBUG
+#  define D(x) x
+#else
+#  define D(x)
+#endif // DEBUG
+
+/////////// Circular buffer
+
+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);
+  }
+}
+
+/////////// remote_bitbang_t
+
+remote_bitbang_t::remote_bitbang_t(uint16_t port, sim_t *sim) :
+  socket_fd(0),
+  client_fd(0),
+  recv_buf(64 * 1024),
+  send_buf(64 * 1024)
+{
+  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();
+  }
+}
+
+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::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;
+    recv_buf.reset();
+    send_buf.reset();
+  } else {
+    recv_buf.data_added(bytes);
+    D(fprintf(stderr, "receive buffer: "));
+    for (unsigned i = 0; i < recv_buf.size(); i++) {
+      D(fprintf(stderr, "%c", recv_buf[i]));
+    }
+    D(fprintf(stderr, "\n"));
+  }
+}
+
+void remote_bitbang_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 remote_bitbang_t::tick()
+{
+  if (client_fd > 0) {
+    this->read();
+    this->write();
+  } else {
+    this->accept();
+  }
+}
diff --git a/riscv/remote_bitbang.h b/riscv/remote_bitbang.h
new file mode 100644 (file)
index 0000000..165cc40
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef REMOTE_BITBANG_H
+#define REMOTE_BITBANG_H
+
+#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 remote_bitbang_t
+{
+public:
+  // Create a new server, listening for connections from localhost on the given
+  // port.
+  remote_bitbang_t(uint16_t port, sim_t *sim);
+
+  // Do a bit of work.
+  void tick();
+
+private:
+  int socket_fd;
+  int client_fd;
+  circular_buffer_t<uint8_t> recv_buf;
+  circular_buffer_t<uint8_t> send_buf;
+
+  // Check for a client connecting, and accept if there is one.
+  void accept();
+  // Read as much into recv_buf as possible.
+  void read();
+  // Write as much of send_buf as possible.
+  void write();
+};
+
+#endif
index 552187ab19d077a833c416aaf41c8638140b480f..695803b142ffb0b60b61d3673f379aee7eb8df47 100644 (file)
@@ -23,8 +23,8 @@ riscv_hdrs = \
        rocc.h \
        insn_template.h \
        mulhi.h \
-       gdbserver.h \
        debug_module.h \
+       remote_bitbang.h \
 
 riscv_precompiled_hdrs = \
        insn_template.h \
@@ -45,8 +45,8 @@ riscv_srcs = \
        devices.cc \
        rom.cc \
        rtc.cc \
-       gdbserver.cc \
        debug_module.cc \
+       remote_bitbang.cc \
        $(riscv_gen_srcs) \
 
 riscv_test_srcs =
index b455105913531b40712627634f38dad243ef4a62..86e23b0908650b7ac45caf6a336cc3fc000bf369 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>
@@ -23,7 +23,7 @@ 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)
+    current_step(0), current_proc(0), debug(false), remote_bitbang(NULL)
 {
   signal(SIGINT, &handle_signal);
   // allocate target machine's memory, shrinking it as necessary
@@ -77,8 +77,8 @@ void sim_t::main()
       interactive();
     else
       step(INTERLEAVE);
-    if (gdbserver) {
-      gdbserver->handle();
+    if (remote_bitbang) {
+      remote_bitbang->tick();
     }
   }
 }
index 5d165c9793532f334f117eb8f5c7b71fffcabd15..c8ba4073c02157538060c42cc4c9dd86ba98826c 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,7 +29,9 @@ 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_config_string() { return config_string.c_str(); }
   processor_t* get_core(size_t i) { return procs.at(i); }
 
@@ -53,7 +55,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) {
@@ -88,7 +90,6 @@ private:
 
   friend class processor_t;
   friend class mmu_t;
-  friend class gdbserver_t;
 
   // htif
   friend void sim_thread_main(void*);
index 424bf37820661cd0a690958c34a35ea282fc8913..576c01f4ec24b8af77b86bfc79945858dc36d6b2 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-config-string  Print platform configuration string and exit\n");
   exit(1);
 }
@@ -49,7 +49,7 @@ 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;
 
   option_parser_t parser;
   parser.help(&help);
@@ -61,7 +61,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){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 +79,10 @@ 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<remote_bitbang_t> remote_bitbang;
+  if (rbb_port) {
+    remote_bitbang = std::unique_ptr<remote_bitbang_t>(new remote_bitbang_t(rbb_port, &s));
+    s.set_remote_bitbang(&(*remote_bitbang));
   }
 
   if (dump_config_string) {