From d1f2cf337e1a0be8eada2afadd745e1374b4a000 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 3 Feb 2017 11:29:54 -0800 Subject: [PATCH] OpenOCD connects, and sends some data that we receive. --- riscv/remote_bitbang.cc | 211 ++++++++++++++++++++++++++++++++++++++++ riscv/remote_bitbang.h | 70 +++++++++++++ riscv/riscv.mk.in | 4 +- riscv/sim.cc | 8 +- riscv/sim.h | 9 +- spike_main/spike.cc | 16 +-- 6 files changed, 300 insertions(+), 18 deletions(-) create mode 100644 riscv/remote_bitbang.cc create mode 100644 riscv/remote_bitbang.h diff --git a/riscv/remote_bitbang.cc b/riscv/remote_bitbang.cc new file mode 100644 index 0000000..13b6a3c --- /dev/null +++ b/riscv/remote_bitbang.cc @@ -0,0 +1,211 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "remote_bitbang.h" + +#define DEBUG +#ifdef DEBUG +# define D(x) x +#else +# define D(x) +#endif // DEBUG + +/////////// Circular buffer + +template +unsigned int circular_buffer_t::size() const +{ + if (end >= start) + return end - start; + else + return end + capacity - start; +} + +template +void circular_buffer_t::consume(unsigned int bytes) +{ + start = (start + bytes) % capacity; +} + +template +unsigned int circular_buffer_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 +unsigned int circular_buffer_t::contiguous_data_size() const +{ + if (end >= start) + return end - start; + else + return capacity - start; +} + +template +void circular_buffer_t::data_added(unsigned int bytes) +{ + end += bytes; + assert(end <= capacity); + if (end == capacity) + end = 0; +} + +template +void circular_buffer_t::reset() +{ + start = 0; + end = 0; +} + +template +void circular_buffer_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 index 0000000..165cc40 --- /dev/null +++ b/riscv/remote_bitbang.h @@ -0,0 +1,70 @@ +#ifndef REMOTE_BITBANG_H +#define REMOTE_BITBANG_H + +#include + +class sim_t; + +template +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 recv_buf; + circular_buffer_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 diff --git a/riscv/riscv.mk.in b/riscv/riscv.mk.in index 552187a..695803b 100644 --- a/riscv/riscv.mk.in +++ b/riscv/riscv.mk.in @@ -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 = diff --git a/riscv/sim.cc b/riscv/sim.cc index b455105..86e23b0 100644 --- a/riscv/sim.cc +++ b/riscv/sim.cc @@ -2,7 +2,7 @@ #include "sim.h" #include "mmu.h" -#include "gdbserver.h" +#include "remote_bitbang.h" #include #include #include @@ -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& 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(); } } } diff --git a/riscv/sim.h b/riscv/sim.h index 5d165c9..c8ba407 100644 --- a/riscv/sim.h +++ b/riscv/sim.h @@ -13,7 +13,7 @@ #include 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*); diff --git a/spike_main/spike.cc b/spike_main/spike.cc index 424bf37..576c01f 100644 --- a/spike_main/spike.cc +++ b/spike_main/spike.cc @@ -2,7 +2,7 @@ #include "sim.h" #include "mmu.h" -#include "gdbserver.h" +#include "remote_bitbang.h" #include "cachesim.h" #include "extension.h" #include @@ -30,7 +30,7 @@ static void help() fprintf(stderr, " --l2=:: B both powers of 2).\n"); fprintf(stderr, " --extension= Specify RoCC Extension\n"); fprintf(stderr, " --extlib= Shared library to load\n"); - fprintf(stderr, " --gdb-port= Listen on for gdb to connect\n"); + fprintf(stderr, " --rbb-port= Listen on 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 l2; std::function 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 htif_args(argv1, (const char*const*)argv + argc); sim_t s(isa, nprocs, mem_mb, halted, htif_args); - std::unique_ptr gdbserver; - if (gdb_port) { - gdbserver = std::unique_ptr(new gdbserver_t(gdb_port, &s)); - s.set_gdbserver(&(*gdbserver)); + std::unique_ptr remote_bitbang; + if (rbb_port) { + remote_bitbang = std::unique_ptr(new remote_bitbang_t(rbb_port, &s)); + s.set_remote_bitbang(&(*remote_bitbang)); } if (dump_config_string) { -- 2.30.2