diff options
Diffstat (limited to 'riscv/interactive.cc')
-rw-r--r-- | riscv/interactive.cc | 336 |
1 files changed, 285 insertions, 51 deletions
diff --git a/riscv/interactive.cc b/riscv/interactive.cc index 88eb86b..cf95bf6 100644 --- a/riscv/interactive.cc +++ b/riscv/interactive.cc @@ -20,13 +20,45 @@ #include <algorithm> #include <math.h> +#ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + #define MAX_CMD_STR 40 // maximum possible size of a command line +#define BITS_PER_CHAR 8 #define STR_(X) #X // these definitions allow to use a macro as a string #define STR(X) STR_(X) DECLARE_TRAP(-1, interactive) +static std::vector<std::string> history_commands; + +// if input an arrow/home key, there will be a 3/4-key input sequence, +// so we use an uint32_t to buffer it +typedef uint32_t keybuffer_t; + +enum KEYCODE +{ + KEYCODE_HEADER0 = 0x1b, + KEYCODE_HEADER1 = 0x1b5b, + KEYCODE_LEFT = 0x1b5b44, + KEYCODE_RIGHT = 0x1b5b43, + KEYCODE_UP = 0x1b5b41, + KEYCODE_DOWN = 0x1b5b42, + KEYCODE_HOME0 = 0x1b5b48, + KEYCODE_HOME1_0 = 0x1b5b31, + KEYCODE_HOME1_1 = 0x1b5b317e, + KEYCODE_END0 = 0x1b5b46, + KEYCODE_END1_0 = 0x1b5b34, + KEYCODE_END1_1 = 0x1b5b347e, + KEYCODE_BACKSPACE0 = 0x8, + KEYCODE_BACKSPACE1_0 = 0x1b5b33, + KEYCODE_BACKSPACE1_1 = 0x1b5b337e, + KEYCODE_BACKSPACE2 = 0x7f, + KEYCODE_ENTER = '\n', +}; + processor_t *sim_t::get_core(const std::string& i) { char *ptr; @@ -36,30 +68,182 @@ processor_t *sim_t::get_core(const std::string& i) return get_core(p); } +static void clear_str(bool noncanonical, int fd, std::string target_str) +{ + if (noncanonical) + { + std::string clear_motion; + clear_motion += '\r'; + for (unsigned i = 0; i < target_str.size(); i++) + { + clear_motion += ' '; + } + clear_motion += '\r'; + if (write(fd, clear_motion.c_str(), clear_motion.size() + 1)) + ; // shut up gcc + } +} + +static void send_key(bool noncanonical, int fd, keybuffer_t key_code, const int len) +{ + if (noncanonical) + { + std::string key_motion; + for (int i = len - 1; i >= 0; i--) + { + key_motion += (char) ((key_code >> (i * BITS_PER_CHAR)) & 0xff); + } + if (write(fd, key_motion.c_str(), len) != len) + ; // shut up gcc + } +} + static std::string readline(int fd) { struct termios tios; + // try to make sure the terminal is noncanonical and nonecho + if (tcgetattr(fd, &tios) == 0) + { + tios.c_lflag &= (~ICANON); + tios.c_lflag &= (~ECHO); + tcsetattr(fd, TCSANOW, &tios); + } bool noncanonical = tcgetattr(fd, &tios) == 0 && (tios.c_lflag & ICANON) == 0; - std::string s; + std::string s_head = std::string("(spike) "); + std::string s = s_head; + keybuffer_t key_buffer = 0; + // index for up/down arrow + size_t history_index = 0; + // position for left/right arrow + size_t cursor_pos = s.size(); + const size_t initial_s_len = cursor_pos; + std::cerr << s << std::flush; for (char ch; read(fd, &ch, 1) == 1; ) { - if (ch == '\x7f') + uint32_t keycode = key_buffer << BITS_PER_CHAR | ch; + switch (keycode) { - if (s.empty()) - continue; - s.erase(s.end()-1); - - if (noncanonical && write(fd, "\b \b", 3) != 3) {} + // the partial keycode, add to the key_buffer + case KEYCODE_HEADER0: + case KEYCODE_HEADER1: + case KEYCODE_HOME1_0: + case KEYCODE_END1_0: + case KEYCODE_BACKSPACE1_0: + key_buffer = keycode; + break; + // for backspace key + case KEYCODE_BACKSPACE0: + case KEYCODE_BACKSPACE1_1: + case KEYCODE_BACKSPACE2: + if (cursor_pos <= initial_s_len) + continue; + clear_str(noncanonical, fd, s); + cursor_pos--; + s.erase(cursor_pos, 1); + if (noncanonical && write(fd, s.c_str(), s.size() + 1) != 1) + ; // shut up gcc + // move cursor by left arrow key + for (unsigned i = 0; i < s.size() - cursor_pos; i++) { + send_key(noncanonical, fd, KEYCODE_LEFT, 3); + } + key_buffer = 0; + break; + case KEYCODE_HOME0: + case KEYCODE_HOME1_1: + // move cursor by left arrow key + for (unsigned i = 0; i < cursor_pos - initial_s_len; i++) { + send_key(noncanonical, fd, KEYCODE_LEFT, 3); + } + cursor_pos = initial_s_len; + key_buffer = 0; + break; + case KEYCODE_END0: + case KEYCODE_END1_1: + // move cursor by right arrow key + for (unsigned i = 0; i < s.size() - cursor_pos; i++) { + send_key(noncanonical, fd, KEYCODE_RIGHT, 3); + } + cursor_pos = s.size(); + key_buffer = 0; + break; + case KEYCODE_UP: + // up arrow + if (history_commands.size() > 0) { + clear_str(noncanonical, fd, s); + history_index = std::min(history_commands.size(), history_index + 1); + s = history_commands[history_commands.size() - history_index]; + if (noncanonical && write(fd, s.c_str(), s.size() + 1)) + ; // shut up gcc + cursor_pos = s.size(); + } + key_buffer = 0; + break; + case KEYCODE_DOWN: + // down arrow + if (history_commands.size() > 0) { + clear_str(noncanonical, fd, s); + history_index = std::max(0, (int)history_index - 1); + if (history_index == 0) { + s = s_head; + } else { + s = history_commands[history_commands.size() - history_index]; + } + if (noncanonical && write(fd, s.c_str(), s.size() + 1)) + ; // shut up gcc + cursor_pos = s.size(); + } + key_buffer = 0; + break; + case KEYCODE_LEFT: + if (s.size() > initial_s_len) { + cursor_pos = cursor_pos - 1; + if ((int)cursor_pos < (int)initial_s_len) { + cursor_pos = initial_s_len; + } else { + send_key(noncanonical, fd, KEYCODE_LEFT, 3); + } + } + key_buffer = 0; + break; + case KEYCODE_RIGHT: + if (s.size() > initial_s_len) { + cursor_pos = cursor_pos + 1; + if (cursor_pos > s.size()) { + cursor_pos = s.size(); + } else { + send_key(noncanonical, fd, KEYCODE_RIGHT, 3); + } + } + key_buffer = 0; + break; + case KEYCODE_ENTER: + if (noncanonical && write(fd, &ch, 1) != 1) + ; // shut up gcc + if (s.size() > initial_s_len && (history_commands.size() == 0 || s != history_commands[history_commands.size() - 1])) { + history_commands.push_back(s); + } + return s.substr(initial_s_len); + default: + DEFAULT_KEY: + // unknown buffered key, do nothing + if (key_buffer != 0) { + key_buffer = 0; + break; + } + clear_str(noncanonical, fd, s); + s.insert(cursor_pos, 1, ch); + cursor_pos++; + if (noncanonical && write(fd, s.c_str(), s.size() + 1) != 1) + ; // shut up gcc + // send left arrow key to move cursor + for (unsigned i = 0; i < s.size() - cursor_pos; i++) { + send_key(noncanonical, fd, KEYCODE_LEFT, 3); + } + break; } - else if (noncanonical && write(fd, &ch, 1) != 1) {} - - if (ch == '\n') - break; - if (ch != '\x7f') - s += ch; } - return s; + return s.substr(initial_s_len); } #ifdef HAVE_BOOST_ASIO @@ -90,7 +274,6 @@ std::string sim_t::rin(boost::asio::streambuf *bout_ptr) { // output goes to socket sout_.rdbuf(bout_ptr); } else { // if we are not listening on a socket, get commands from terminal - std::cerr << ": " << std::flush; s = readline(2); // 2 is stderr, but when doing reads it reverts to stdin // output goes to stderr sout_.rdbuf(std::cerr.rdbuf()); @@ -132,9 +315,12 @@ void sim_t::interactive() funcs["pc"] = &sim_t::interactive_pc; funcs["mem"] = &sim_t::interactive_mem; funcs["str"] = &sim_t::interactive_str; + funcs["mtime"] = &sim_t::interactive_mtime; + funcs["mtimecmp"] = &sim_t::interactive_mtimecmp; funcs["until"] = &sim_t::interactive_until_silent; funcs["untiln"] = &sim_t::interactive_until_noisy; funcs["while"] = &sim_t::interactive_until_silent; + funcs["dump"] = &sim_t::interactive_dumpmems; funcs["quit"] = &sim_t::interactive_quit; funcs["q"] = funcs["quit"]; funcs["help"] = &sim_t::interactive_help; @@ -150,17 +336,16 @@ void sim_t::interactive() // first get commands from file, if cmd_file has been set if (cmd_file && !feof(cmd_file) && fscanf(cmd_file,"%" STR(MAX_CMD_STR) "[^\n]\n", cmd_str)==1) { // up to MAX_CMD_STR characters before \n, skipping \n - s = cmd_str; - // while we get input from file, output goes to stderr - sout_.rdbuf(std::cerr.rdbuf()); + s = cmd_str; + // while we get input from file, output goes to stderr + sout_.rdbuf(std::cerr.rdbuf()); } else { - // 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 + // 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 + s = rin(&bout); // get command string from socket or terminal #else - std::cerr << ": " << std::flush; - s = readline(2); // 2 is stderr, but when doing reads it reverts to stdin + s = readline(2); // 2 is stderr, but when doing reads it reverts to stdin #endif } @@ -211,15 +396,20 @@ void sim_t::interactive_help(const std::string& cmd, const std::vector<std::stri "fregd <core> <reg> # Display double precision <reg> in <core>\n" "vreg <core> [reg] # Display vector [reg] (all if omitted) in <core>\n" "pc <core> # Show current PC in <core>\n" - "mem <hex addr> # Show contents of physical memory\n" - "str <core> <hex addr> # Show NUL-terminated C string at <hex addr> in core <core>\n" + "mem [core] <hex addr> # Show contents of virtual memory <hex addr> in [core] (physical memory <hex addr> if omitted)\n" + "str [core] <hex addr> # Show NUL-terminated C string at virtual address <hex addr> in [core] (physical address <hex addr> if omitted)\n" + "dump # Dump physical memory to binary files\n" + "mtime # Show mtime\n" + "mtimecmp <core> # Show mtimecmp for <core>\n" "until reg <core> <reg> <val> # Stop when <reg> in <core> hits <val>\n" + "untiln reg <core> <reg> <val> # Run noisy and stop when <reg> in <core> hits <val>\n" "until pc <core> <val> # Stop when PC in <core> hits <val>\n" "untiln pc <core> <val> # Run noisy and stop when PC in <core> hits <val>\n" - "until mem <addr> <val> # Stop when memory <addr> becomes <val>\n" + "until mem [core] <addr> <val> # Stop when virtual memory <addr> in [core] (physical address <addr> if omitted) becomes <val>\n" + "untiln mem [core] <addr> <val> # Run noisy and stop when virtual memory <addr> in [core] (physical address <addr> if omitted) becomes <val>\n" "while reg <core> <reg> <val> # Run while <reg> in <core> is <val>\n" "while pc <core> <val> # Run while PC in <core> is <val>\n" - "while mem <addr> <val> # Run while memory <addr> is <val>\n" + "while mem [core] <addr> <val> # Run while virtual memory <addr> in [core] (physical memory <addr> if omitted) is <val>\n" "run [count] # Resume noisy execution (until CTRL+C, or [count] insns)\n" "r [count] Alias for run\n" "rs [count] # Resume silent execution (until CTRL+C, or [count] insns)\n" @@ -269,7 +459,7 @@ reg_t sim_t::get_pc(const std::vector<std::string>& args) void sim_t::interactive_pc(const std::string& cmd, const std::vector<std::string>& args) { - if(args.size() != 1) + if (args.size() != 1) throw trap_interactive(); processor_t *p = get_core(args[0]); @@ -305,19 +495,33 @@ reg_t sim_t::get_reg(const std::vector<std::string>& args) return p->get_state()->XPR[r]; } -freg_t sim_t::get_freg(const std::vector<std::string>& args) +freg_t sim_t::get_freg(const std::vector<std::string>& args, int size) { - if(args.size() != 2) + if (args.size() != 2) throw trap_interactive(); processor_t *p = get_core(args[0]); - int r = std::find(fpr_name, fpr_name + NFPR, args[1]) - fpr_name; - if (r == NFPR) - r = atoi(args[1].c_str()); - if (r >= NFPR) - throw trap_interactive(); - - return p->get_state()->FPR[r]; + if (p->extension_enabled(EXT_ZFINX)) { + int r = std::find(xpr_name, xpr_name + NXPR, args[1]) - xpr_name; + if (r == NXPR) + r = atoi(args[1].c_str()); + if (r >= NXPR) + throw trap_interactive(); + if ((p->get_xlen() == 32) && (size == 64)) { + if (r % 2 != 0) + throw trap_interactive(); + return freg(f64(r== 0 ? reg_t(0) : (READ_REG(r + 1) << 32) + zext32(READ_REG(r)))); + } else { //xlen >= size + return {p->get_state()->XPR[r] | ~(((uint64_t)-1) >> (64 - size)) ,(uint64_t)-1}; + } + } else { + int r = std::find(fpr_name, fpr_name + NFPR, args[1]) - fpr_name; + if (r == NFPR) + r = atoi(args[1].c_str()); + if (r >= NFPR) + throw trap_interactive(); + return p->get_state()->FPR[r]; + } } void sim_t::interactive_vreg(const std::string& cmd, const std::vector<std::string>& args) @@ -347,9 +551,9 @@ void sim_t::interactive_vreg(const std::string& cmd, const std::vector<std::stri for (int r = rstart; r < rend; ++r) { out << std::setfill (' ') << std::left << std::setw(4) << vr_name[r] << std::right << ": "; - for (int e = num_elem-1; e >= 0; --e){ + for (int e = num_elem-1; e >= 0; --e) { uint64_t val; - switch(elen){ + switch (elen) { case 8: val = p->VU.elt<uint64_t>(r, e); out << std::dec << "[" << e << "]: 0x" << std::hex << std::setfill ('0') << std::setw(16) << val << " "; @@ -372,11 +576,10 @@ void sim_t::interactive_vreg(const std::string& cmd, const std::vector<std::stri } } - void sim_t::interactive_reg(const std::string& cmd, const std::vector<std::string>& args) { if (args.size() < 1) - throw trap_interactive(); + throw trap_interactive(); processor_t *p = get_core(args[0]); int max_xlen = p->get_isa().get_max_xlen(); @@ -389,14 +592,14 @@ void sim_t::interactive_reg(const std::string& cmd, const std::vector<std::strin for (int r = 0; r < NXPR; ++r) { out << std::setfill(' ') << std::setw(4) << xpr_name[r] - << ": 0x" << std::setfill('0') << std::setw(max_xlen/4) - << zext(p->get_state()->XPR[r], max_xlen); + << ": 0x" << std::setfill('0') << std::setw(max_xlen/4) + << zext(p->get_state()->XPR[r], max_xlen); if ((r + 1) % 4 == 0) out << std::endl; } } else { - out << "0x" << std::setfill('0') << std::setw(max_xlen/4) - << zext(get_reg(args), max_xlen) << std::endl; + out << "0x" << std::setfill('0') << std::setw(max_xlen/4) + << zext(get_reg(args), max_xlen) << std::endl; } } @@ -409,7 +612,7 @@ union fpr void sim_t::interactive_freg(const std::string& cmd, const std::vector<std::string>& args) { - freg_t r = get_freg(args); + freg_t r = get_freg(args, 64); std::ostream out(sout_.rdbuf()); out << std::hex << "0x" << std::setfill ('0') << std::setw(16) << r.v[1] << std::setw(16) << r.v[0] << std::endl; @@ -418,7 +621,7 @@ void sim_t::interactive_freg(const std::string& cmd, const std::vector<std::stri void sim_t::interactive_fregh(const std::string& cmd, const std::vector<std::string>& args) { fpr f; - f.r = freg(f16_to_f32(f16(get_freg(args)))); + f.r = freg(f16_to_f32(f16(get_freg(args, 16)))); std::ostream out(sout_.rdbuf()); out << (isBoxedF32(f.r) ? (double)f.s : NAN) << std::endl; @@ -427,7 +630,7 @@ void sim_t::interactive_fregh(const std::string& cmd, const std::vector<std::str void sim_t::interactive_fregs(const std::string& cmd, const std::vector<std::string>& args) { fpr f; - f.r = get_freg(args); + f.r = get_freg(args, 32); std::ostream out(sout_.rdbuf()); out << (isBoxedF32(f.r) ? (double)f.s : NAN) << std::endl; @@ -436,7 +639,7 @@ void sim_t::interactive_fregs(const std::string& cmd, const std::vector<std::str void sim_t::interactive_fregd(const std::string& cmd, const std::vector<std::string>& args) { fpr f; - f.r = get_freg(args); + f.r = get_freg(args, 64); std::ostream out(sout_.rdbuf()); out << (isBoxedF64(f.r) ? f.d : NAN) << std::endl; @@ -460,7 +663,7 @@ reg_t sim_t::get_mem(const std::vector<std::string>& args) if (addr == LONG_MAX) addr = strtoul(addr_str.c_str(),NULL,16); - switch(addr % 8) + switch (addr % 8) { case 0: val = mmu->load_uint64(addr); @@ -507,7 +710,7 @@ void sim_t::interactive_str(const std::string& cmd, const std::vector<std::strin std::ostream out(sout_.rdbuf()); char ch; - while((ch = mmu->load_uint8(addr++))) + while ((ch = mmu->load_uint8(addr++))) out << ch; out << std::endl; @@ -577,3 +780,34 @@ void sim_t::interactive_until(const std::string& cmd, const std::vector<std::str step(1); } } + +void sim_t::interactive_dumpmems(const std::string& cmd, const std::vector<std::string>& args) +{ + for (unsigned i = 0; i < mems.size(); i++) { + std::stringstream mem_fname; + mem_fname << "mem.0x" << std::hex << mems[i].first << ".bin"; + + std::ofstream mem_file(mem_fname.str()); + mems[i].second->dump(mem_file); + mem_file.close(); + } +} + +void sim_t::interactive_mtime(const std::string& cmd, const std::vector<std::string>& args) +{ + std::ostream out(sout_.rdbuf()); + out << std::hex << std::setfill('0') << "0x" << std::setw(16) + << clint->get_mtime() << std::endl; +} + +void sim_t::interactive_mtimecmp(const std::string& cmd, const std::vector<std::string>& args) +{ + if (args.size() != 1) + throw trap_interactive(); + + processor_t *p = get_core(args[0]); + std::ostream out(sout_.rdbuf()); + out << std::hex << std::setfill('0') << "0x" << std::setw(16) + << clint->get_mtimecmp(p->get_id()) << std::endl; +} + |