--- /dev/null
+#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();
+ }
+}
--- /dev/null
+#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
rocc.h \
insn_template.h \
mulhi.h \
- gdbserver.h \
debug_module.h \
+ remote_bitbang.h \
riscv_precompiled_hdrs = \
insn_template.h \
devices.cc \
rom.cc \
rtc.cc \
- gdbserver.cc \
debug_module.cc \
+ remote_bitbang.cc \
$(riscv_gen_srcs) \
riscv_test_srcs =
#include "sim.h"
#include "mmu.h"
-#include "gdbserver.h"
+#include "remote_bitbang.h"
#include <map>
#include <iostream>
#include <sstream>
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
interactive();
else
step(INTERLEAVE);
- if (gdbserver) {
- gdbserver->handle();
+ if (remote_bitbang) {
+ remote_bitbang->tick();
}
}
}
#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
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); }
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) {
friend class processor_t;
friend class mmu_t;
- friend class gdbserver_t;
// htif
friend void sim_thread_main(void*);
#include "sim.h"
#include "mmu.h"
-#include "gdbserver.h"
+#include "remote_bitbang.h"
#include "cachesim.h"
#include "extension.h"
#include <dlfcn.h>
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);
}
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);
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$"));});
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) {