feat(npc): difftest execution abstraction layer
This commit is contained in:
parent
e828e140cd
commit
89847cfdb4
17 changed files with 1076 additions and 276 deletions
|
@ -4,11 +4,14 @@ find_package(BISON REQUIRED)
|
|||
set(PARSER_DIR "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
set(LEXER_OUT "${PARSER_DIR}/lexer.c")
|
||||
set(PARSER_OUT "${PARSER_DIR}/parser.c")
|
||||
flex_target(LEXER addrexp.l "${LEXER_OUT}" DEFINES_FILE "${PARSER_DIR}/addrexp_lex.h")
|
||||
bison_target(PARSER addrexp.y "${PARSER_OUT}" DEFINES_FILE "${PARSER_DIR}/addrexp.h")
|
||||
flex_target(LEXER addrexp.l "${LEXER_OUT}" DEFINES_FILE "${PARSER_DIR}/include/addrexp_lex.h")
|
||||
bison_target(PARSER addrexp.y "${PARSER_OUT}" DEFINES_FILE "${PARSER_DIR}/include/addrexp.h")
|
||||
add_flex_bison_dependency(LEXER PARSER)
|
||||
|
||||
add_library(sdb sdb.cpp console.cpp "${LEXER_OUT}" "${PARSER_OUT}")
|
||||
add_library(sdb sdb.cpp console.cpp disasm.cpp "${LEXER_OUT}" "${PARSER_OUT}")
|
||||
llvm_map_components_to_libnames(LLVM_LIBS ${LLVM_TARGETS_TO_BUILD})
|
||||
target_link_libraries(sdb PUBLIC ${LLVM_LIBS})
|
||||
target_link_libraries(sdb PRIVATE ${Readline_LIBRARY})
|
||||
target_include_directories(sdb PRIVATE ${PARSER_DIR}/include)
|
||||
target_include_directories(sdb PRIVATE ${Readline_INCLUDE_DIR})
|
||||
target_include_directories(sdb PUBLIC include)
|
||||
|
|
87
npc/utils/sdb/disasm.cpp
Normal file
87
npc/utils/sdb/disasm.cpp
Normal file
|
@ -0,0 +1,87 @@
|
|||
#include <disasm.hpp>
|
||||
#include <llvm/MC/MCAsmInfo.h>
|
||||
#include <llvm/MC/MCContext.h>
|
||||
#include <llvm/MC/MCDisassembler/MCDisassembler.h>
|
||||
#include <llvm/MC/MCInstPrinter.h>
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
#if LLVM_VERSION_MAJOR >= 14
|
||||
#include <llvm/MC/TargetRegistry.h>
|
||||
#if LLVM_VERSION_MAJOR >= 15
|
||||
#include <llvm/MC/MCSubtargetInfo.h>
|
||||
#endif
|
||||
#else
|
||||
#include <llvm/Support/TargetRegistry.h>
|
||||
#endif
|
||||
#include <iostream>
|
||||
#include <llvm/Support/TargetSelect.h>
|
||||
#include <sstream>
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 11
|
||||
#error Please use LLVM with major version >= 11
|
||||
#endif
|
||||
|
||||
Disassembler::Disassembler(std::string triple) : triple(triple) {
|
||||
llvm::InitializeAllTargetInfos();
|
||||
llvm::InitializeAllTargetMCs();
|
||||
llvm::InitializeAllAsmParsers();
|
||||
llvm::InitializeAllDisassemblers();
|
||||
|
||||
std::string errstr;
|
||||
|
||||
llvm::MCInstrInfo *gMII = nullptr;
|
||||
llvm::MCRegisterInfo *gMRI = nullptr;
|
||||
auto target = llvm::TargetRegistry::lookupTarget(triple, errstr);
|
||||
if (!target) {
|
||||
llvm::errs() << "Can't find target for " << triple << ": " << errstr
|
||||
<< "\n";
|
||||
assert(0);
|
||||
}
|
||||
|
||||
llvm::MCTargetOptions MCOptions;
|
||||
gSTI = target->createMCSubtargetInfo(triple, "", "");
|
||||
std::string isa = target->getName();
|
||||
if (isa == "riscv32" || isa == "riscv64") {
|
||||
gSTI->ApplyFeatureFlag("+m");
|
||||
gSTI->ApplyFeatureFlag("+a");
|
||||
gSTI->ApplyFeatureFlag("+c");
|
||||
gSTI->ApplyFeatureFlag("+f");
|
||||
gSTI->ApplyFeatureFlag("+d");
|
||||
}
|
||||
gMII = target->createMCInstrInfo();
|
||||
gMRI = target->createMCRegInfo(triple);
|
||||
auto AsmInfo = target->createMCAsmInfo(*gMRI, triple, MCOptions);
|
||||
#if LLVM_VERSION_MAJOR >= 13
|
||||
auto llvmTripleTwine = llvm::Twine(triple);
|
||||
auto llvmtriple = llvm::Triple(llvmTripleTwine);
|
||||
auto Ctx = new llvm::MCContext(llvmtriple, AsmInfo, gMRI, nullptr);
|
||||
#else
|
||||
auto Ctx = new llvm::MCContext(AsmInfo, gMRI, nullptr);
|
||||
#endif
|
||||
gDisassembler = target->createMCDisassembler(*gSTI, *Ctx);
|
||||
gIP = target->createMCInstPrinter(llvm::Triple(triple),
|
||||
AsmInfo->getAssemblerDialect(), *AsmInfo,
|
||||
*gMII, *gMRI);
|
||||
gIP->setPrintImmHex(true);
|
||||
gIP->setPrintBranchImmAsAddress(true);
|
||||
if (isa == "riscv32" || isa == "riscv64")
|
||||
gIP->applyTargetSpecificCLOption("no-aliases");
|
||||
}
|
||||
|
||||
std::string Disassembler::disassemble(uint64_t pc, uint8_t *code, int nbyte) {
|
||||
llvm::MCInst inst;
|
||||
llvm::ArrayRef<uint8_t> arr(code, nbyte);
|
||||
uint64_t dummy_size = 0;
|
||||
gDisassembler->getInstruction(inst, dummy_size, arr, pc, llvm::nulls());
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "0x" << std::hex << pc << ": ";
|
||||
std::string s = ss.str();
|
||||
llvm::raw_string_ostream os{s};
|
||||
gIP->printInst(&inst, pc, "", *gSTI, os);
|
||||
|
||||
return s;
|
||||
}
|
17
npc/utils/sdb/include/disasm.hpp
Normal file
17
npc/utils/sdb/include/disasm.hpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef _NPC_UTILS_DISASM_
|
||||
#define _NPC_UTILS_DISASM_
|
||||
#include "llvm/MC/MCDisassembler/MCDisassembler.h"
|
||||
#include "llvm/MC/MCInstPrinter.h"
|
||||
|
||||
class Disassembler {
|
||||
llvm::MCDisassembler *gDisassembler = nullptr;
|
||||
llvm::MCSubtargetInfo *gSTI = nullptr;
|
||||
llvm::MCInstPrinter *gIP = nullptr;
|
||||
std::string triple;
|
||||
|
||||
public:
|
||||
Disassembler(std::string);
|
||||
std::string disassemble(uint64_t pc, uint8_t *code, int nbyte);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -3,9 +3,9 @@
|
|||
|
||||
#include <components.hpp>
|
||||
#include <console.hpp>
|
||||
#include <difftest.hpp>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <trm_interface.hpp>
|
||||
#include <types.h>
|
||||
|
||||
namespace cr = CppReadline;
|
||||
|
@ -13,122 +13,53 @@ using ret = cr::Console::ReturnCode;
|
|||
|
||||
namespace SDB {
|
||||
|
||||
enum SDBStatus {
|
||||
SDB_SUCCESS,
|
||||
SDB_WRONG_ARGUMENT,
|
||||
};
|
||||
enum SDBStatus { SDB_SUCCESS, SDB_WRONG_ARGUMENT, SDB_DIFFTEST_FAILED };
|
||||
|
||||
class SDBHandlers;
|
||||
|
||||
struct Handler {
|
||||
const std::vector<const char *> names;
|
||||
cr::Console::CommandFunction f;
|
||||
// cr::Console::CommandFunction f;
|
||||
std::function<int(SDBHandlers *, const cr::Console::Arguments &)> f;
|
||||
};
|
||||
|
||||
template <const DifftestInterface &funcs> class _SDBHandlers {
|
||||
using CPUState = CPUStateBase<uint32_t, 32>;
|
||||
|
||||
class SDBHandlers {
|
||||
private:
|
||||
std::vector<Handler> all_handlers;
|
||||
const TrmInterface &funcs;
|
||||
std::vector<Handler> all_handlers = {
|
||||
Handler{{"c", "continue"}, &SDBHandlers::cmd_continue},
|
||||
Handler{{"si", "step-instruction"}, &SDBHandlers::cmd_step},
|
||||
Handler{{"info-r"}, &SDBHandlers::cmd_info_registers},
|
||||
Handler{{"p", "print"}, &SDBHandlers::cmd_print},
|
||||
};
|
||||
int cmd_continue(const cr::Console::Arguments &input);
|
||||
int cmd_step(const std::vector<std::string> &input);
|
||||
int cmd_info_registers(const std::vector<std::string> &input);
|
||||
int cmd_print(const std::vector<std::string> &input);
|
||||
|
||||
public:
|
||||
static CPUState cpu;
|
||||
|
||||
private:
|
||||
static _SDBHandlers<funcs> *instance;
|
||||
static int cmd_continue(const cr::Console::Arguments &input);
|
||||
static int cmd_step(const std::vector<std::string> &input);
|
||||
static int cmd_info_registers(const std::vector<std::string> &input);
|
||||
static int cmd_print(const std::vector<std::string> &input);
|
||||
_SDBHandlers<funcs>(std::vector<Handler> all_handlers)
|
||||
: all_handlers(all_handlers){};
|
||||
|
||||
public:
|
||||
_SDBHandlers<funcs>(const _SDBHandlers<funcs> &) = delete;
|
||||
_SDBHandlers<funcs> operator=(const _SDBHandlers<funcs> &) = delete;
|
||||
|
||||
static _SDBHandlers<funcs> *getInstance() {
|
||||
if (instance == nullptr) {
|
||||
std::vector<Handler> all_handlers{
|
||||
Handler{{"c", "continue"}, &_SDBHandlers::cmd_continue},
|
||||
Handler{{"si", "step-instruction"}, &_SDBHandlers::cmd_step},
|
||||
};
|
||||
instance = new _SDBHandlers<funcs>(all_handlers);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
SDBHandlers(const TrmInterface &funcs) : funcs(funcs){};
|
||||
void registerHandlers(cr::Console *c);
|
||||
};
|
||||
|
||||
template <const DifftestInterface &funcs>
|
||||
_SDBHandlers<funcs> *_SDBHandlers<funcs>::instance = nullptr;
|
||||
|
||||
template <const DifftestInterface &funcs>
|
||||
CPUState _SDBHandlers<funcs>::cpu = CPUState();
|
||||
|
||||
template <const DifftestInterface &funcs>
|
||||
int _SDBHandlers<funcs>::cmd_continue(const cr::Console::Arguments &input) {
|
||||
if (input.size() > 1)
|
||||
return SDB_WRONG_ARGUMENT;
|
||||
funcs.exec(-1);
|
||||
return SDB_SUCCESS;
|
||||
}
|
||||
|
||||
template <const DifftestInterface &funcs>
|
||||
int _SDBHandlers<funcs>::cmd_step(const std::vector<std::string> &input) {
|
||||
if (input.size() > 2) {
|
||||
return SDB_WRONG_ARGUMENT;
|
||||
}
|
||||
uint64_t step_count = input.size() == 2 ? std::stoull(input[1]) : 1;
|
||||
funcs.exec(step_count);
|
||||
return SDB_SUCCESS;
|
||||
}
|
||||
|
||||
template <const DifftestInterface &funcs>
|
||||
int _SDBHandlers<funcs>::cmd_info_registers(
|
||||
const std::vector<std::string> &input) {
|
||||
if (input.size() > 1)
|
||||
return SDB_WRONG_ARGUMENT;
|
||||
std::cout << _SDBHandlers<funcs>::getInstance()->cpu << std::endl;
|
||||
return SDB_SUCCESS;
|
||||
}
|
||||
|
||||
template <const DifftestInterface &funcs>
|
||||
int _SDBHandlers<funcs>::cmd_print(const std::vector<std::string> &input) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
template <const DifftestInterface &funcs>
|
||||
void _SDBHandlers<funcs>::registerHandlers(cr::Console *c) {
|
||||
for (auto &h : this->all_handlers) {
|
||||
for (auto &name : h.names) {
|
||||
c->registerCommand(name, h.f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <const DifftestInterface &funcs> class SDB {
|
||||
class SDB {
|
||||
private:
|
||||
std::unique_ptr<CppReadline::Console> c;
|
||||
using SDBHandlers = _SDBHandlers<funcs>;
|
||||
const TrmInterface &funcs;
|
||||
SDBHandlers handlers;
|
||||
|
||||
public:
|
||||
SDB(std::string const &greeting = "\033[1;34m(npc)\033[0m ") {
|
||||
SDB(const TrmInterface &funcs,
|
||||
std::string const &greeting = "\033[1;34m(npc)\033[0m ")
|
||||
: handlers(SDBHandlers{funcs}), funcs(funcs) {
|
||||
c = std::make_unique<CppReadline::Console>(greeting);
|
||||
SDBHandlers::getInstance()->registerHandlers(c.get());
|
||||
};
|
||||
|
||||
word_t reg_str2val(const char *name, bool *success) {
|
||||
try {
|
||||
*success = true;
|
||||
return SDBHandlers::getInstance()->cpu.at(name);
|
||||
} catch (std::runtime_error) {
|
||||
*success = false;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
handlers.registerHandlers(c.get());
|
||||
};
|
||||
|
||||
int main_loop() {
|
||||
int retCode;
|
||||
funcs.init(0);
|
||||
do {
|
||||
retCode = c->readLine();
|
||||
// We can also change the prompt based on last return value:
|
||||
|
|
|
@ -1,10 +1,84 @@
|
|||
#include <components.hpp>
|
||||
#include <console.hpp>
|
||||
#include <difftest.hpp>
|
||||
#include <disasm.hpp>
|
||||
#include <sdb.hpp>
|
||||
#include <stdexcept>
|
||||
#include <trm_interface.hpp>
|
||||
#include <types.h>
|
||||
extern "C" {
|
||||
#include <addrexp.h>
|
||||
#include <addrexp_lex.h>
|
||||
}
|
||||
|
||||
namespace cr = CppReadline;
|
||||
using ret = cr::Console::ReturnCode;
|
||||
|
||||
namespace SDB {}
|
||||
std::ostream &operator<<(std::ostream &os, const TrmInterface &d) {
|
||||
d.print(os);
|
||||
return os;
|
||||
};
|
||||
|
||||
namespace SDB {
|
||||
|
||||
int SDBHandlers::cmd_continue(const cr::Console::Arguments &input) {
|
||||
if (input.size() > 1)
|
||||
return SDB_WRONG_ARGUMENT;
|
||||
this->funcs.exec(-1);
|
||||
return SDB_SUCCESS;
|
||||
}
|
||||
|
||||
int SDBHandlers::cmd_step(const std::vector<std::string> &input) {
|
||||
if (input.size() > 2) {
|
||||
return SDB_WRONG_ARGUMENT;
|
||||
}
|
||||
uint64_t step_count = input.size() == 2 ? std::stoull(input[1]) : 1;
|
||||
try {
|
||||
this->funcs.exec(step_count);
|
||||
} catch (std::runtime_error) {
|
||||
std::cout << "Difftest Failed" << std::endl << funcs << std::endl;
|
||||
return SDB_DIFFTEST_FAILED;
|
||||
}
|
||||
// std::cout << funcs << std::endl;
|
||||
return SDB_SUCCESS;
|
||||
}
|
||||
|
||||
int SDBHandlers::cmd_info_registers(const std::vector<std::string> &input) {
|
||||
if (input.size() > 1)
|
||||
return SDB_WRONG_ARGUMENT;
|
||||
std::cout << this->funcs << std::endl;
|
||||
return SDB_SUCCESS;
|
||||
}
|
||||
|
||||
word_t parse_expr(const char *arg) {
|
||||
if (arg == NULL) {
|
||||
puts("Invalid expr argument.");
|
||||
return 0;
|
||||
} else {
|
||||
word_t res;
|
||||
yy_scan_string(arg);
|
||||
yyparse(&res);
|
||||
yylex_destroy();
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
int SDBHandlers::cmd_print(const std::vector<std::string> &input) {
|
||||
word_t buf[2];
|
||||
word_t addr = parse_expr(input[1].c_str());
|
||||
this->funcs.memcpy(addr, &buf, sizeof(word_t), TRM_FROM_MACHINE);
|
||||
// TODO: Difftest only
|
||||
std::cout << std::hex << "dut: 0x" << buf[0] << ' ' << "ref: 0x" << buf[1]
|
||||
<< std::dec << std::endl;
|
||||
return SDB_SUCCESS;
|
||||
}
|
||||
|
||||
void SDBHandlers::registerHandlers(cr::Console *c) {
|
||||
for (auto &h : this->all_handlers) {
|
||||
for (auto &name : h.names) {
|
||||
std::function<int(std::vector<std::string>)> f{
|
||||
std::bind(h.f, this, std::placeholders::_1)};
|
||||
c->registerCommand(name, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace SDB
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue