feat(npc): difftest execution abstraction layer

This commit is contained in:
xinyangli 2024-04-10 20:12:41 +08:00
parent e828e140cd
commit 89847cfdb4
Signed by: xin
SSH key fingerprint: SHA256:qZ/tzd8lYRtUFSrfBDBMcUqV4GHKxqeqRA3huItgvbk
17 changed files with 1076 additions and 276 deletions

View file

@ -1,4 +1,3 @@
add_subdirectory(disasm)
if (ENABLE_SDB)
add_subdirectory(sdb)
endif()

View file

@ -1,4 +1 @@
add_library(disasm disasm.cpp)
target_include_directories(disasm PUBLIC include)
llvm_map_components_to_libnames(LLVM_LIBS ${LLVM_TARGETS_TO_BUILD})
target_link_libraries(disasm PUBLIC ${LLVM_LIBS})

View file

@ -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)

View file

@ -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:

View file

@ -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