diff options
author | Andrew Waterman <waterman@cs.berkeley.edu> | 2014-12-20 13:37:14 -0800 |
---|---|---|
committer | Andrew Waterman <waterman@cs.berkeley.edu> | 2014-12-20 13:37:14 -0800 |
commit | 416c8be88c712a99451f3770534a7fe712cb17af (patch) | |
tree | 7157bc929b92b8a48bf3514f06ae5a51b3e5937f /spike_main | |
parent | e26e8c58799c2b179940b83e1ab4f376a132774d (diff) | |
download | spike-416c8be88c712a99451f3770534a7fe712cb17af.zip spike-416c8be88c712a99451f3770534a7fe712cb17af.tar.gz spike-416c8be88c712a99451f3770534a7fe712cb17af.tar.bz2 |
Support building from within root directory
Diffstat (limited to 'spike_main')
-rw-r--r-- | spike_main/disasm.cc | 395 | ||||
-rw-r--r-- | spike_main/extensions.cc | 35 | ||||
-rw-r--r-- | spike_main/riscv-dis.cc | 45 | ||||
-rw-r--r-- | spike_main/spike.cc | 81 | ||||
-rw-r--r-- | spike_main/spike_main.ac | 1 | ||||
-rw-r--r-- | spike_main/spike_main.mk.in | 14 | ||||
-rw-r--r-- | spike_main/termios-xspike.cc | 29 | ||||
-rw-r--r-- | spike_main/xspike.cc | 102 |
8 files changed, 702 insertions, 0 deletions
diff --git a/spike_main/disasm.cc b/spike_main/disasm.cc new file mode 100644 index 0000000..8fb1db8 --- /dev/null +++ b/spike_main/disasm.cc @@ -0,0 +1,395 @@ +// See LICENSE for license details. + +#include "disasm.h" +#include <string> +#include <vector> +#include <cstdarg> +#include <sstream> +#include <stdlib.h> + + +struct : public arg_t { + std::string to_string(insn_t insn) const { + return std::to_string((int)insn.i_imm()) + '(' + xpr_name[insn.rs1()] + ')'; + } +} load_address; + +struct : public arg_t { + std::string to_string(insn_t insn) const { + return std::to_string((int)insn.s_imm()) + '(' + xpr_name[insn.rs1()] + ')'; + } +} store_address; + +struct : public arg_t { + std::string to_string(insn_t insn) const { + return std::string("0(") + xpr_name[insn.rs1()] + ')'; + } +} amo_address; + +struct : public arg_t { + std::string to_string(insn_t insn) const { + return xpr_name[insn.rd()]; + } +} xrd; + +struct : public arg_t { + std::string to_string(insn_t insn) const { + return xpr_name[insn.rs1()]; + } +} xrs1; + +struct : public arg_t { + std::string to_string(insn_t insn) const { + return xpr_name[insn.rs2()]; + } +} xrs2; + +struct : public arg_t { + std::string to_string(insn_t insn) const { + return fpr_name[insn.rd()]; + } +} frd; + +struct : public arg_t { + std::string to_string(insn_t insn) const { + return fpr_name[insn.rs1()]; + } +} frs1; + +struct : public arg_t { + std::string to_string(insn_t insn) const { + return fpr_name[insn.rs2()]; + } +} frs2; + +struct : public arg_t { + std::string to_string(insn_t insn) const { + return fpr_name[insn.rs3()]; + } +} frs3; + +struct : public arg_t { + std::string to_string(insn_t insn) const { + switch (insn.csr()) + { + #define DECLARE_CSR(name, num) case num: return #name; + #include "encoding.h" + #undef DECLARE_CSR + default: return "unknown"; + } + } +} csr; + +struct : public arg_t { + std::string to_string(insn_t insn) const { + return std::to_string((int)insn.i_imm()); + } +} imm; + +struct : public arg_t { + std::string to_string(insn_t insn) const { + std::stringstream s; + s << std::hex << "0x" << ((uint32_t)insn.u_imm() >> 12); + return s.str(); + } +} bigimm; + +struct : public arg_t { + std::string to_string(insn_t insn) const { + return std::to_string(insn.rs1()); + } +} zimm5; + +struct : public arg_t { + std::string to_string(insn_t insn) const { + std::stringstream s; + int32_t target = insn.sb_imm(); + char sign = target >= 0 ? '+' : '-'; + s << "pc " << sign << ' ' << abs(target); + return s.str(); + } +} branch_target; + +struct : public arg_t { + std::string to_string(insn_t insn) const { + std::stringstream s; + int32_t target = insn.uj_imm(); + char sign = target >= 0 ? '+' : '-'; + s << "pc " << sign << std::hex << " 0x" << abs(target); + return s.str(); + } +} jump_target; + +std::string disassembler_t::disassemble(insn_t insn) +{ + const disasm_insn_t* disasm_insn = lookup(insn); + return disasm_insn ? disasm_insn->to_string(insn) : "unknown"; +} + +disassembler_t::disassembler_t() +{ + const uint32_t mask_rd = 0x1fUL << 7; + const uint32_t match_rd_ra = 1UL << 7; + const uint32_t mask_rs1 = 0x1fUL << 15; + const uint32_t match_rs1_ra = 1UL << 15; + const uint32_t mask_rs2 = 0x1fUL << 20; + const uint32_t mask_imm = 0xfffUL << 20; + + #define DECLARE_INSN(code, match, mask) \ + const uint32_t match_##code = match; \ + const uint32_t mask_##code = mask; + #include "encoding.h" + #undef DECLARE_INSN + + // explicit per-instruction disassembly + #define DISASM_INSN(name, code, extra, ...) \ + add_insn(new disasm_insn_t(name, match_##code, mask_##code | (extra), __VA_ARGS__)); + #define DEFINE_NOARG(code) \ + add_insn(new disasm_insn_t(#code, match_##code, mask_##code, {})); + #define DEFINE_RTYPE(code) DISASM_INSN(#code, code, 0, {&xrd, &xrs1, &xrs2}) + #define DEFINE_ITYPE(code) DISASM_INSN(#code, code, 0, {&xrd, &xrs1, &imm}) + #define DEFINE_I0TYPE(name, code) DISASM_INSN(name, code, mask_rs1, {&xrd, &imm}) + #define DEFINE_I1TYPE(name, code) DISASM_INSN(name, code, mask_imm, {&xrd, &xrs1}) + #define DEFINE_I2TYPE(name, code) DISASM_INSN(name, code, mask_rd | mask_imm, {&xrs1}) + #define DEFINE_LTYPE(code) DISASM_INSN(#code, code, 0, {&xrd, &bigimm}) + #define DEFINE_BTYPE(code) DISASM_INSN(#code, code, 0, {&xrs1, &xrs2, &branch_target}) + #define DEFINE_B0TYPE(name, code) DISASM_INSN(name, code, mask_rs1 | mask_rs2, {&branch_target}) + #define DEFINE_B1TYPE(name, code) DISASM_INSN(name, code, mask_rs2, {&xrs1, &branch_target}) + #define DEFINE_XLOAD(code) DISASM_INSN(#code, code, 0, {&xrd, &load_address}) + #define DEFINE_XSTORE(code) DISASM_INSN(#code, code, 0, {&xrs2, &store_address}) + #define DEFINE_XAMO(code) DISASM_INSN(#code, code, 0, {&xrd, &xrs2, &amo_address}) + #define DEFINE_FLOAD(code) DISASM_INSN(#code, code, 0, {&frd, &load_address}) + #define DEFINE_FSTORE(code) DISASM_INSN(#code, code, 0, {&frs2, &store_address}) + #define DEFINE_FRTYPE(code) DISASM_INSN(#code, code, 0, {&frd, &frs1, &frs2}) + #define DEFINE_FR1TYPE(code) DISASM_INSN(#code, code, 0, {&frd, &frs1}) + #define DEFINE_FR3TYPE(code) DISASM_INSN(#code, code, 0, {&frd, &frs1, &frs2, &frs3}) + #define DEFINE_FXTYPE(code) DISASM_INSN(#code, code, 0, {&xrd, &frs1}) + #define DEFINE_XFTYPE(code) DISASM_INSN(#code, code, 0, {&frd, &xrs1}) + + DEFINE_XLOAD(lb) + DEFINE_XLOAD(lbu) + DEFINE_XLOAD(lh) + DEFINE_XLOAD(lhu) + DEFINE_XLOAD(lw) + DEFINE_XLOAD(lwu) + DEFINE_XLOAD(ld) + + DEFINE_XSTORE(sb) + DEFINE_XSTORE(sh) + DEFINE_XSTORE(sw) + DEFINE_XSTORE(sd) + + DEFINE_XAMO(amoadd_w) + DEFINE_XAMO(amoswap_w) + DEFINE_XAMO(amoand_w) + DEFINE_XAMO(amoor_w) + DEFINE_XAMO(amoxor_w) + DEFINE_XAMO(amomin_w) + DEFINE_XAMO(amomax_w) + DEFINE_XAMO(amominu_w) + DEFINE_XAMO(amomaxu_w) + DEFINE_XAMO(amoadd_d) + DEFINE_XAMO(amoswap_d) + DEFINE_XAMO(amoand_d) + DEFINE_XAMO(amoor_d) + DEFINE_XAMO(amoxor_d) + DEFINE_XAMO(amomin_d) + DEFINE_XAMO(amomax_d) + DEFINE_XAMO(amominu_d) + DEFINE_XAMO(amomaxu_d) + + DEFINE_XAMO(lr_w) + DEFINE_XAMO(sc_w) + DEFINE_XAMO(lr_d) + DEFINE_XAMO(sc_d) + + DEFINE_FLOAD(flw) + DEFINE_FLOAD(fld) + + DEFINE_FSTORE(fsw) + DEFINE_FSTORE(fsd) + + add_insn(new disasm_insn_t("j", match_jal, mask_jal | mask_rd, {&jump_target})); + add_insn(new disasm_insn_t("jal", match_jal | match_rd_ra, mask_jal | mask_rd, {&jump_target})); + add_insn(new disasm_insn_t("jal", match_jal, mask_jal, {&xrd, &jump_target})); + + DEFINE_B0TYPE("b", beq); + DEFINE_B1TYPE("beqz", beq); + DEFINE_B1TYPE("bnez", bne); + DEFINE_B1TYPE("bltz", blt); + DEFINE_B1TYPE("bgez", bge); + DEFINE_BTYPE(beq) + DEFINE_BTYPE(bne) + DEFINE_BTYPE(blt) + DEFINE_BTYPE(bge) + DEFINE_BTYPE(bltu) + DEFINE_BTYPE(bgeu) + + DEFINE_LTYPE(lui); + DEFINE_LTYPE(auipc); + + DEFINE_I2TYPE("jr", jalr); + add_insn(new disasm_insn_t("jalr", match_jalr | match_rd_ra, mask_jalr | mask_rd | mask_imm, {&xrs1})); + add_insn(new disasm_insn_t("ret", match_jalr | match_rs1_ra, mask_jalr | mask_rd | mask_rs1 | mask_imm, {})); + DEFINE_ITYPE(jalr); + + add_insn(new disasm_insn_t("nop", match_addi, mask_addi | mask_rd | mask_rs1 | mask_imm, {})); + add_insn(new disasm_insn_t(" - ", match_xor, mask_xor | mask_rd | mask_rs1 | mask_rs2, {})); // for machine-generated bubbles + DEFINE_I0TYPE("li", addi); + DEFINE_I1TYPE("move", addi); + DEFINE_ITYPE(addi); + DEFINE_ITYPE(slli); + DEFINE_ITYPE(slti); + DEFINE_ITYPE(sltiu); + DEFINE_ITYPE(xori); + DEFINE_ITYPE(srli); + DEFINE_ITYPE(srai); + DEFINE_ITYPE(ori); + DEFINE_ITYPE(andi); + DEFINE_ITYPE(addiw); + DEFINE_ITYPE(slliw); + DEFINE_ITYPE(srliw); + DEFINE_ITYPE(sraiw); + + DEFINE_RTYPE(add); + DEFINE_RTYPE(sub); + DEFINE_RTYPE(sll); + DEFINE_RTYPE(slt); + DEFINE_RTYPE(sltu); + DEFINE_RTYPE(xor); + DEFINE_RTYPE(srl); + DEFINE_RTYPE(sra); + DEFINE_RTYPE(or); + DEFINE_RTYPE(and); + DEFINE_RTYPE(mul); + DEFINE_RTYPE(mulh); + DEFINE_RTYPE(mulhu); + DEFINE_RTYPE(mulhsu); + DEFINE_RTYPE(div); + DEFINE_RTYPE(divu); + DEFINE_RTYPE(rem); + DEFINE_RTYPE(remu); + DEFINE_RTYPE(addw); + DEFINE_RTYPE(subw); + DEFINE_RTYPE(sllw); + DEFINE_RTYPE(srlw); + DEFINE_RTYPE(sraw); + DEFINE_RTYPE(mulw); + DEFINE_RTYPE(divw); + DEFINE_RTYPE(divuw); + DEFINE_RTYPE(remw); + DEFINE_RTYPE(remuw); + + DEFINE_NOARG(scall); + DEFINE_NOARG(sbreak); + DEFINE_NOARG(fence); + DEFINE_NOARG(fence_i); + + add_insn(new disasm_insn_t("csrr", match_csrrs, mask_csrrs | mask_rs1, {&xrd, &csr})); + add_insn(new disasm_insn_t("csrw", match_csrrw, mask_csrrw | mask_rd, {&csr, &xrs1})); + add_insn(new disasm_insn_t("csrrw", match_csrrw, mask_csrrw, {&xrd, &csr, &xrs1})); + add_insn(new disasm_insn_t("csrrs", match_csrrs, mask_csrrs, {&xrd, &csr, &xrs1})); + add_insn(new disasm_insn_t("csrrc", match_csrrc, mask_csrrc, {&xrd, &csr, &xrs1})); + add_insn(new disasm_insn_t("csrrwi", match_csrrwi, mask_csrrwi, {&xrd, &csr, &zimm5})); + add_insn(new disasm_insn_t("csrrsi", match_csrrsi, mask_csrrsi, {&xrd, &csr, &zimm5})); + add_insn(new disasm_insn_t("csrrci", match_csrrci, mask_csrrci, {&xrd, &csr, &zimm5})); + DEFINE_NOARG(sret) + + DEFINE_FRTYPE(fadd_s); + DEFINE_FRTYPE(fsub_s); + DEFINE_FRTYPE(fmul_s); + DEFINE_FRTYPE(fdiv_s); + DEFINE_FR1TYPE(fsqrt_s); + DEFINE_FRTYPE(fmin_s); + DEFINE_FRTYPE(fmax_s); + DEFINE_FR3TYPE(fmadd_s); + DEFINE_FR3TYPE(fmsub_s); + DEFINE_FR3TYPE(fnmadd_s); + DEFINE_FR3TYPE(fnmsub_s); + DEFINE_FRTYPE(fsgnj_s); + DEFINE_FRTYPE(fsgnjn_s); + DEFINE_FRTYPE(fsgnjx_s); + DEFINE_FR1TYPE(fcvt_s_d); + DEFINE_XFTYPE(fcvt_s_l); + DEFINE_XFTYPE(fcvt_s_lu); + DEFINE_XFTYPE(fcvt_s_w); + DEFINE_XFTYPE(fcvt_s_wu); + DEFINE_XFTYPE(fcvt_s_wu); + DEFINE_XFTYPE(fmv_s_x); + DEFINE_FXTYPE(fcvt_l_s); + DEFINE_FXTYPE(fcvt_lu_s); + DEFINE_FXTYPE(fcvt_w_s); + DEFINE_FXTYPE(fcvt_wu_s); + DEFINE_FXTYPE(fclass_s); + DEFINE_FXTYPE(fmv_x_s); + DEFINE_FXTYPE(feq_s); + DEFINE_FXTYPE(flt_s); + DEFINE_FXTYPE(fle_s); + + DEFINE_FRTYPE(fadd_d); + DEFINE_FRTYPE(fsub_d); + DEFINE_FRTYPE(fmul_d); + DEFINE_FRTYPE(fdiv_d); + DEFINE_FR1TYPE(fsqrt_d); + DEFINE_FRTYPE(fmin_d); + DEFINE_FRTYPE(fmax_d); + DEFINE_FR3TYPE(fmadd_d); + DEFINE_FR3TYPE(fmsub_d); + DEFINE_FR3TYPE(fnmadd_d); + DEFINE_FR3TYPE(fnmsub_d); + DEFINE_FRTYPE(fsgnj_d); + DEFINE_FRTYPE(fsgnjn_d); + DEFINE_FRTYPE(fsgnjx_d); + DEFINE_FR1TYPE(fcvt_d_s); + DEFINE_XFTYPE(fcvt_d_l); + DEFINE_XFTYPE(fcvt_d_lu); + DEFINE_XFTYPE(fcvt_d_w); + DEFINE_XFTYPE(fcvt_d_wu); + DEFINE_XFTYPE(fcvt_d_wu); + DEFINE_XFTYPE(fmv_d_x); + DEFINE_FXTYPE(fcvt_l_d); + DEFINE_FXTYPE(fcvt_lu_d); + DEFINE_FXTYPE(fcvt_w_d); + DEFINE_FXTYPE(fcvt_wu_d); + DEFINE_FXTYPE(fclass_d); + DEFINE_FXTYPE(fmv_x_d); + DEFINE_FXTYPE(feq_d); + DEFINE_FXTYPE(flt_d); + DEFINE_FXTYPE(fle_d); + + // provide a default disassembly for all instructions as a fallback + #define DECLARE_INSN(code, match, mask) \ + add_insn(new disasm_insn_t(#code " (args unknown)", match, mask, {})); + #include "encoding.h" + #undef DECLARE_INSN +} + +const disasm_insn_t* disassembler_t::lookup(insn_t insn) +{ + size_t idx = insn.bits() % HASH_SIZE; + for (size_t j = 0; j < chain[idx].size(); j++) + if(*chain[idx][j] == insn) + return chain[idx][j]; + + idx = HASH_SIZE; + for (size_t j = 0; j < chain[idx].size(); j++) + if(*chain[idx][j] == insn) + return chain[idx][j]; + + return NULL; +} + +void disassembler_t::add_insn(disasm_insn_t* insn) +{ + size_t idx = HASH_SIZE; + if (insn->get_mask() % HASH_SIZE == HASH_SIZE - 1) + idx = insn->get_match() % HASH_SIZE; + chain[idx].push_back(insn); +} + +disassembler_t::~disassembler_t() +{ + for (size_t i = 0; i < HASH_SIZE+1; i++) + for (size_t j = 0; j < chain[i].size(); j++) + delete chain[i][j]; +} diff --git a/spike_main/extensions.cc b/spike_main/extensions.cc new file mode 100644 index 0000000..315621f --- /dev/null +++ b/spike_main/extensions.cc @@ -0,0 +1,35 @@ +#include "extension.h" +#include <string> +#include <map> +#include <dlfcn.h> + +static std::map<std::string, std::function<extension_t*()>>& extensions() +{ + static std::map<std::string, std::function<extension_t*()>> v; + return v; +} + +void register_extension(const char* name, std::function<extension_t*()> f) +{ + extensions()[name] = f; +} + +std::function<extension_t*()> find_extension(const char* name) +{ + if (!extensions().count(name)) { + // try to find extension xyz by loading libxyz.so + std::string libname = std::string("lib") + name + ".so"; + if (!dlopen(libname.c_str(), RTLD_LAZY)) { + fprintf(stderr, "couldn't find extension '%s' (or library '%s')\n", + name, libname.c_str()); + exit(-1); + } + if (!extensions().count(name)) { + fprintf(stderr, "couldn't find extension '%s' in shared library '%s'\n", + name, libname.c_str()); + exit(-1); + } + } + + return extensions()[name]; +} diff --git a/spike_main/riscv-dis.cc b/spike_main/riscv-dis.cc new file mode 100644 index 0000000..d0af451 --- /dev/null +++ b/spike_main/riscv-dis.cc @@ -0,0 +1,45 @@ +// See LICENSE for license details. + +// This little program finds occurrences of strings like +// DASM(ffabc013) +// in its input, then replaces them with the disassembly +// enclosed hexadecimal number, interpreted as a RISC-V +// instruction. + +#include "disasm.h" +#include "extension.h" +#include <iostream> +#include <string> +#include <cstdint> +#include <fesvr/option_parser.h> +using namespace std; + +int main(int argc, char** argv) +{ + string s; + disassembler_t d; + + std::function<extension_t*()> extension; + option_parser_t parser; + parser.option(0, "extension", 1, [&](const char* s){extension = find_extension(s);}); + + while (getline(cin, s)) + { + for (size_t start = 0; (start = s.find("DASM(", start)) != string::npos; ) + { + size_t end = s.find(')', start); + if (end == string::npos) + break; + + size_t numstart = start + strlen("DASM("); + insn_bits_t bits = strtoull(&s[numstart], NULL, 16); + string dis = d.disassemble(bits); + s = s.substr(0, start) + dis + s.substr(end+1); + start += dis.length(); + } + + cout << s << '\n'; + } + + return 0; +} diff --git a/spike_main/spike.cc b/spike_main/spike.cc new file mode 100644 index 0000000..ab5cea5 --- /dev/null +++ b/spike_main/spike.cc @@ -0,0 +1,81 @@ +// See LICENSE for license details. + +#include "sim.h" +#include "htif.h" +#include "cachesim.h" +#include "extension.h" +#include <dlfcn.h> +#include <fesvr/option_parser.h> +#include <stdio.h> +#include <stdlib.h> +#include <getopt.h> +#include <vector> +#include <string> +#include <memory> + +static void help() +{ + fprintf(stderr, "usage: spike [host options] <target program> [target options]\n"); + fprintf(stderr, "Host Options:\n"); + fprintf(stderr, " -p <n> Simulate <n> processors\n"); + fprintf(stderr, " -m <n> Provide <n> MB of target memory\n"); + fprintf(stderr, " -d Interactive debug mode\n"); + fprintf(stderr, " -g Track histogram of PCs\n"); + fprintf(stderr, " -h Print this help message\n"); + fprintf(stderr, " --ic=<S>:<W>:<B> Instantiate a cache model with S sets,\n"); + fprintf(stderr, " --dc=<S>:<W>:<B> W ways, and B-byte blocks (with S and\n"); + 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"); + exit(1); +} + +int main(int argc, char** argv) +{ + bool debug = false; + bool histogram = false; + size_t nprocs = 1; + size_t mem_mb = 0; + std::unique_ptr<icache_sim_t> ic; + std::unique_ptr<dcache_sim_t> dc; + std::unique_ptr<cache_sim_t> l2; + std::function<extension_t*()> extension; + + option_parser_t parser; + parser.help(&help); + parser.option('h', 0, 0, [&](const char* s){help();}); + parser.option('d', 0, 0, [&](const char* s){debug = true;}); + parser.option('g', 0, 0, [&](const char* s){histogram = true;}); + parser.option('p', 0, 1, [&](const char* s){nprocs = atoi(s);}); + parser.option('m', 0, 1, [&](const char* s){mem_mb = 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$"));}); + parser.option(0, "extension", 1, [&](const char* s){extension = find_extension(s);}); + parser.option(0, "extlib", 1, [&](const char *s){ + void *lib = dlopen(s, RTLD_NOW | RTLD_GLOBAL); + if (lib == NULL) { + fprintf(stderr, "Unable to load extlib '%s': %s\n", s, dlerror()); + exit(-1); + } + }); + + auto argv1 = parser.parse(argv); + if (!*argv1) + help(); + std::vector<std::string> htif_args(argv1, (const char*const*)argv + argc); + sim_t s(nprocs, mem_mb, htif_args); + + if (ic && l2) ic->set_miss_handler(&*l2); + if (dc && l2) dc->set_miss_handler(&*l2); + for (size_t i = 0; i < nprocs; i++) + { + if (ic) s.get_core(i)->get_mmu()->register_memtracer(&*ic); + if (dc) s.get_core(i)->get_mmu()->register_memtracer(&*dc); + if (extension) s.get_core(i)->register_extension(extension()); + } + + s.set_debug(debug); + s.set_histogram(histogram); + return s.run(); +} diff --git a/spike_main/spike_main.ac b/spike_main/spike_main.ac new file mode 100644 index 0000000..f8d63ce --- /dev/null +++ b/spike_main/spike_main.ac @@ -0,0 +1 @@ +AC_CHECK_LIB(dl, dlopen, [], [AC_MSG_ERROR([libdl is required])]) diff --git a/spike_main/spike_main.mk.in b/spike_main/spike_main.mk.in new file mode 100644 index 0000000..0ac70ef --- /dev/null +++ b/spike_main/spike_main.mk.in @@ -0,0 +1,14 @@ +spike_main_subproject_deps = \ + softfloat \ + riscv \ + +spike_main_install_prog_srcs = \ + spike.cc \ + riscv-dis.cc \ + xspike.cc \ + termios-xspike.cc \ + +spike_main_hdrs = \ + +spike_main_srcs = \ + extensions.cc \ diff --git a/spike_main/termios-xspike.cc b/spike_main/termios-xspike.cc new file mode 100644 index 0000000..e533933 --- /dev/null +++ b/spike_main/termios-xspike.cc @@ -0,0 +1,29 @@ +// See LICENSE for license details. + +// termios-xspike sets up a canonical terminal and blocks forever. +// It allows us to send Ctrl-C etc. to the target machine. + +#include <unistd.h> +#include <termios.h> +#include <signal.h> +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> + +int main() +{ + struct termios old_tios; + if (tcgetattr(0, &old_tios) < 0) + return -1; + + signal(SIGTERM, [](int) { }); + + struct termios new_tios = old_tios; + new_tios.c_lflag &= ~(ICANON | ECHO | ISIG); + if (tcsetattr(0, TCSANOW, &new_tios) < 0) + return -1; + + pause(); + + return tcsetattr(0, TCSANOW, &old_tios); +} diff --git a/spike_main/xspike.cc b/spike_main/xspike.cc new file mode 100644 index 0000000..4331dbe --- /dev/null +++ b/spike_main/xspike.cc @@ -0,0 +1,102 @@ +// See LICENSE for license details. + +// xspike forks an xterm for spike's target machine console, +// preserving the current terminal for debugging. + +#include <unistd.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/wait.h> +#include <cstdio> +#include <climits> +#include <cstring> +#include <stdexcept> + +static pid_t fork_spike(int tty_fd, int argc, char** argv); +static pid_t fork_xterm(int* tty_fd); + +int main(int argc, char** argv) +{ + int tty_fd, wait_status, ret = -1; + pid_t xterm, spike; + + static bool signal_exit = false; + auto handle_signal = [](int) { signal_exit = true; }; + + if ((xterm = fork_xterm(&tty_fd)) < 0) + { + fprintf(stderr, "could not open xterm\n"); + goto out; + } + + signal(SIGINT, handle_signal); + + if ((spike = fork_spike(tty_fd, argc, argv)) < 0) + { + fprintf(stderr, "could not open spike\n"); + goto close_xterm; + } + + while ((ret = waitpid(spike, &wait_status, 0)) < 0) + if (signal_exit) + break; + + if (ret < 0) // signal_exit + kill(spike, SIGTERM); + else + ret = WIFEXITED(wait_status) ? WEXITSTATUS(wait_status) : -1; + +close_xterm: + kill(-xterm, SIGTERM); +out: + return ret; +} + +static pid_t fork_spike(int tty_fd, int argc, char** argv) +{ + pid_t pid = fork(); + if (pid < 0) + return -1; + + if (pid == 0) + { + if (dup2(tty_fd, STDIN_FILENO) < 0 || dup2(tty_fd, STDOUT_FILENO) < 0) + return -1; + execvp("spike", argv); + return -1; + } + + return pid; +} + +static pid_t fork_xterm(int* tty_fd) +{ + static const char cmd[] = "3>&1 xterm -title xspike -e sh -c 'tty 1>&3; termios-xspike'"; + + int fds[2]; + if (pipe(fds) < 0) + return -1; + + pid_t pid = fork(); + if (pid < 0) + return -1; + + if (pid == 0) + { + setpgid(0, 0); + if (dup2(fds[1], STDOUT_FILENO) < 0) + return -1; + execl("/bin/sh", "sh", "-c", cmd, NULL); + return -1; + } + + char tty[NAME_MAX]; + ssize_t ttylen = read(fds[0], tty, sizeof(tty)); + if (ttylen <= 1 || tty[ttylen-1] != '\n') + return -1; + tty[ttylen-1] = '\0'; + if ((*tty_fd = open(tty, O_RDWR)) < 0) + return -1; + + return pid; +} |