Browse Source

Move boost asio socket interface to socketif_t

This reduces dependencies on config.h in sim.h
pull/1169/head
Jerry Zhao 3 years ago
parent
commit
68a3039598
  1. 73
      riscv/interactive.cc
  2. 4
      riscv/riscv.mk.in
  3. 25
      riscv/sim.cc
  4. 21
      riscv/sim.h
  5. 74
      riscv/socketif.cc
  6. 32
      riscv/socketif.h
  7. 27
      spike_main/spike.cc

73
riscv/interactive.cc

@ -1,10 +1,12 @@
// See LICENSE for license details.
#include "config.h"
#include "sim.h"
#include "decode.h"
#include "disasm.h"
#include "mmu.h"
#include "vector_unit.h"
#include "socketif.h"
#include <sys/mman.h>
#include <termios.h>
#include <map>
@ -247,58 +249,6 @@ static std::string readline(int fd)
return s.substr(initial_s_len);
}
#ifdef HAVE_BOOST_ASIO
// read input command string
std::string sim_t::rin(boost::asio::streambuf *bout_ptr) {
std::string s;
if (acceptor_ptr) { // if we are listening, get commands from socket
try {
socket_ptr.reset(new boost::asio::ip::tcp::socket(*io_service_ptr));
acceptor_ptr->accept(*socket_ptr); // wait for someone to open connection
boost::asio::streambuf buf;
boost::asio::read_until(*socket_ptr, buf, "\n"); // wait for command
s = boost::asio::buffer_cast<const char*>(buf.data());
boost::erase_all(s, "\r"); // get rid off any cr and lf
boost::erase_all(s, "\n");
// The socket client is a web server and it appends the IP of the computer
// that sent the command from its web browser.
// For now, erase the IP if it is there.
boost::regex re(" ((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\\.){3}"
"(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])$");
s = boost::regex_replace(s, re, (std::string)"");
// TODO: check the IP against the IP used to upload RISC-V source files
} catch (std::exception& e) {
std::cerr << e.what() << std::endl;
}
// output goes to socket
sout_.rdbuf(bout_ptr);
} else { // if we are not listening on a socket, get commands from terminal
s = readline(2); // 2 is stderr, but when doing reads it reverts to stdin
// output goes to stderr
sout_.rdbuf(std::cerr.rdbuf());
}
return s;
}
// write sout_ to socket (via bout)
void sim_t::wout(boost::asio::streambuf *bout_ptr) {
if (!cmd_file && acceptor_ptr) { // only if we are not getting command inputs from a file
// and if a socket has been created
try {
boost::system::error_code ignored_error;
boost::asio::write(*socket_ptr, *bout_ptr, boost::asio::transfer_all(), ignored_error);
socket_ptr->close(); // close the socket after each command input/ouput
// This is need to in order to make the socket interface
// acessible by HTTP GET via a socket client in a web server.
} catch (std::exception& e) {
std::cerr << e.what() << std::endl;
}
}
}
#endif
void sim_t::interactive()
{
typedef void (sim_t::*interactive_func)(const std::string&, const std::vector<std::string>&);
@ -330,9 +280,6 @@ void sim_t::interactive()
while (!done())
{
#ifdef HAVE_BOOST_ASIO
boost::asio::streambuf bout; // socket output
#endif
std::string s;
char cmd_str[MAX_CMD_STR+1]; // only used for following fscanf
// first get commands from file, if cmd_file has been set
@ -345,10 +292,14 @@ void sim_t::interactive()
// when there are no commands left from file or if there was no file from the beginning
cmd_file = NULL; // mark file pointer as being not valid, so any method can test this easily
#ifdef HAVE_BOOST_ASIO
s = rin(&bout); // get command string from socket or terminal
#else
s = readline(2); // 2 is stderr, but when doing reads it reverts to stdin
if (socketif) {
s = socketif->rin(sout_); // get command string from socket or terminal
}
else
#endif
{
s = readline(2); // 2 is stderr, but when doing reads it reverts to stdin
}
}
std::stringstream ss(s);
@ -360,7 +311,8 @@ void sim_t::interactive()
set_procs_debug(true);
step(1);
#ifdef HAVE_BOOST_ASIO
wout(&bout); // socket output, if required
if (socketif)
socketif->wout(); // socket output, if required
#endif
continue;
}
@ -380,7 +332,8 @@ void sim_t::interactive()
out << "Bad or missing arguments for command " << cmd << std::endl;
}
#ifdef HAVE_BOOST_ASIO
wout(&bout); // socket output, if required
if (socketif)
socketif->wout(); // socket output, if required
#endif
}
ctrlc_pressed = false;

4
riscv/riscv.mk.in

@ -42,7 +42,8 @@ riscv_hdrs = \
jtag_dtm.h \
csrs.h \
triggers.h \
vector_unit.h
vector_unit.h \
socketif.h \
riscv_install_hdrs = \
abstract_device.h \
@ -96,6 +97,7 @@ riscv_srcs = \
csrs.cc \
triggers.cc \
vector_unit.cc \
socketif.cc \
$(riscv_gen_srcs) \
riscv_test_srcs =

25
riscv/sim.cc

@ -1,5 +1,6 @@
// See LICENSE for license details.
#include "config.h"
#include "sim.h"
#include "mmu.h"
#include "dts.h"
@ -7,6 +8,7 @@
#include "byteorder.h"
#include "platform.h"
#include "libfdt.h"
#include "socketif.h"
#include <fstream>
#include <map>
#include <iostream>
@ -35,9 +37,7 @@ sim_t::sim_t(const cfg_t *cfg, bool halted,
const debug_module_config_t &dm_config,
const char *log_path,
bool dtb_enabled, const char *dtb_file,
#ifdef HAVE_BOOST_ASIO
boost::asio::io_service *io_service_ptr, boost::asio::ip::tcp::acceptor *acceptor_ptr, // option -s
#endif
bool socket_enabled,
FILE *cmd_file) // needed for command line option --cmd
: htif_t(args),
isa(cfg->isa(), cfg->priv()),
@ -49,10 +49,6 @@ sim_t::sim_t(const cfg_t *cfg, bool halted,
dtb_enabled(dtb_enabled),
log_file(log_path),
cmd_file(cmd_file),
#ifdef HAVE_BOOST_ASIO
io_service_ptr(io_service_ptr), // socket interface
acceptor_ptr(acceptor_ptr),
#endif
sout_(nullptr),
current_step(0),
current_proc(0),
@ -74,6 +70,21 @@ sim_t::sim_t(const cfg_t *cfg, bool halted,
debug_module.add_device(&bus);
socketif = NULL;
#ifdef HAVE_BOOST_ASIO
if (socket_enabled) {
socketif = new socketif_t();
}
#else
if (socket_enabled) {
fputs("Socket support requires compilation with boost asio; "
"please rebuild the riscv-isa-sim project using "
"\"configure --with-boost-asio\".\n",
stderr);
abort();
}
#endif
#ifndef RISCV_ENABLE_DUAL_ENDIAN
if (cfg->endianness != memif_endianness_little) {
fputs("Big-endian support has not been prroperly enabled; "

21
riscv/sim.h

@ -4,13 +4,6 @@
#define _RISCV_SIM_H
#include "config.h"
#ifdef HAVE_BOOST_ASIO
#include <boost/algorithm/string.hpp>
#include <boost/regex.hpp>
#include <boost/asio.hpp>
#endif
#include "cfg.h"
#include "debug_module.h"
#include "devices.h"
@ -27,6 +20,7 @@
class mmu_t;
class remote_bitbang_t;
class socketif_t;
// this class encapsulates the processors and memory in a RISC-V machine.
class sim_t : public htif_t, public simif_t
@ -38,9 +32,7 @@ public:
const std::vector<std::string>& args,
const debug_module_config_t &dm_config, const char *log_path,
bool dtb_enabled, const char *dtb_file,
#ifdef HAVE_BOOST_ASIO
boost::asio::io_service *io_service_ptr_ctor, boost::asio::ip::tcp::acceptor *acceptor_ptr_ctor, // option -s
#endif
bool socket_enabled,
FILE *cmd_file); // needed for command line option --cmd
~sim_t();
@ -89,14 +81,7 @@ private:
FILE *cmd_file; // pointer to debug command input file
#ifdef HAVE_BOOST_ASIO
// the following are needed for command socket interface
boost::asio::io_service *io_service_ptr;
boost::asio::ip::tcp::acceptor *acceptor_ptr;
std::unique_ptr<boost::asio::ip::tcp::socket> socket_ptr;
std::string rin(boost::asio::streambuf *bout_ptr); // read input command string
void wout(boost::asio::streambuf *bout_ptr); // write output to socket
#endif
socketif_t *socketif;
std::ostream sout_; // used for socket and terminal interface
processor_t* get_core(const std::string& i);

74
riscv/socketif.cc

@ -0,0 +1,74 @@
// See LICENSE for license details.
#include "socketif.h"
#ifdef HAVE_BOOST_ASIO
#include <iostream>
socketif_t::socketif_t()
{
try { // create socket server
using boost::asio::ip::tcp;
io_service_ptr = new boost::asio::io_service;
acceptor_ptr = new tcp::acceptor(*io_service_ptr, tcp::endpoint(tcp::v4(), 0));
// acceptor is created passing argument port=0, so O.S. will choose a free port
std::string name = boost::asio::ip::host_name();
std::cout << "Listening for debug commands on " << name.substr(0,name.find('.'))
<< " port " << acceptor_ptr->local_endpoint().port() << " ." << std::endl;
// at the end, add space and some other character for convenience of javascript .split(" ")
} catch (std::exception& e) {
std::cerr << e.what() << std::endl;
exit(-1);
}
}
socketif_t::~socketif_t()
{
delete io_service_ptr;
delete acceptor_ptr;
}
// read input command string
std::string socketif_t::rin(std::ostream &sout_)
{
std::string s;
try {
socket_ptr.reset(new boost::asio::ip::tcp::socket(*io_service_ptr));
acceptor_ptr->accept(*socket_ptr); // wait for someone to open connection
boost::asio::streambuf buf;
boost::asio::read_until(*socket_ptr, buf, "\n"); // wait for command
s = boost::asio::buffer_cast<const char*>(buf.data());
boost::erase_all(s, "\r"); // get rid off any cr and lf
boost::erase_all(s, "\n");
// The socket client is a web server and it appends the IP of the computer
// that sent the command from its web browser.
// For now, erase the IP if it is there.
boost::regex re(" ((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\\.){3}"
"(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])$");
s = boost::regex_replace(s, re, (std::string)"");
// TODO: check the IP against the IP used to upload RISC-V source files
} catch (std::exception& e) {
std::cerr << e.what() << std::endl;
}
// output goes to socket
sout_.rdbuf(&bout);
return s;
}
// write sout_ to socket (via bout)
void socketif_t::wout() {
try {
boost::system::error_code ignored_error;
boost::asio::write(*socket_ptr, bout, boost::asio::transfer_all(), ignored_error);
socket_ptr->close(); // close the socket after each command input/ouput
// This is need to in order to make the socket interface
// acessible by HTTP GET via a socket client in a web server.
} catch (std::exception& e) {
std::cerr << e.what() << std::endl;
}
}
#endif

32
riscv/socketif.h

@ -0,0 +1,32 @@
// See LICENSE for license details.
#ifndef _RISCV_SOCKETIF_H
#define _RISCV_SOCKETIF_H
#include "config.h"
#ifdef HAVE_BOOST_ASIO
#include <boost/algorithm/string.hpp>
#include <boost/regex.hpp>
#include <boost/asio.hpp>
class socketif_t
{
public:
socketif_t();
~socketif_t();
std::string rin(std::ostream &sout_); // read input command string
void wout(); // write output to socket
private:
// the following are needed for command socket interface
boost::asio::io_service *io_service_ptr;
boost::asio::ip::tcp::acceptor *acceptor_ptr;
std::unique_ptr<boost::asio::ip::tcp::socket> socket_ptr;
boost::asio::streambuf bout;
};
#endif
#endif

27
spike_main/spike.cc

@ -497,29 +497,6 @@ int main(int argc, char** argv)
}
}
#ifdef HAVE_BOOST_ASIO
boost::asio::io_service *io_service_ptr = NULL; // needed for socket command interface option -s
boost::asio::ip::tcp::acceptor *acceptor_ptr = NULL;
if (socket) { // if command line option -s is set
try
{ // create socket server
using boost::asio::ip::tcp;
io_service_ptr = new boost::asio::io_service;
acceptor_ptr = new tcp::acceptor(*io_service_ptr, tcp::endpoint(tcp::v4(), 0));
// aceptor is created passing argument port=0, so O.S. will choose a free port
std::string name = boost::asio::ip::host_name();
std::cout << "Listening for debug commands on " << name.substr(0,name.find('.'))
<< " port " << acceptor_ptr->local_endpoint().port() << " ." << std::endl;
// at the end, add space and some other character for convenience of javascript .split(" ")
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
exit(-1);
}
}
#endif
if (cfg.explicit_hartids) {
if (nprocs.overridden() && (nprocs() != cfg.nprocs())) {
std::cerr << "Number of specified hartids ("
@ -542,9 +519,7 @@ int main(int argc, char** argv)
sim_t s(&cfg, halted,
mems, plugin_devices, htif_args, dm_config, log_path, dtb_enabled, dtb_file,
#ifdef HAVE_BOOST_ASIO
io_service_ptr, acceptor_ptr,
#endif
socket,
cmd_file);
std::unique_ptr<remote_bitbang_t> remote_bitbang((remote_bitbang_t *) NULL);
std::unique_ptr<jtag_dtm_t> jtag_dtm(

Loading…
Cancel
Save