feat(npc): ebreak support through external inst matching
This commit is contained in:
parent
55230247b2
commit
e99236f711
8 changed files with 97 additions and 25 deletions
|
@ -49,7 +49,9 @@ vpiHandle pc = nullptr;
|
|||
namespace NPC {
|
||||
void npc_memcpy(paddr_t addr, void *buf, size_t sz, bool direction) {
|
||||
if (direction == TRM_FROM_MACHINE) {
|
||||
memcpy(buf, static_cast<Memory<int, 128 * 1024> *>(pmem_get())->mem.data(),
|
||||
memcpy(
|
||||
buf,
|
||||
static_cast<Memory<int, 128 * 1024> *>(pmem_get())->guest_to_host(addr),
|
||||
sz);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -79,5 +79,8 @@ public:
|
|||
// printf("waddr: 0x%x\n", waddr);
|
||||
mem[addr_to_index((uint32_t)waddr)] = expand_bits(wmask) & wdata;
|
||||
}
|
||||
void *guest_to_host(std::size_t addr) {
|
||||
return mem.data() + addr_to_index(addr);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -34,19 +34,29 @@ struct DifftestTrmInterface : public TrmInterface {
|
|||
fetch_state();
|
||||
};
|
||||
exec = [this](uint64_t n) {
|
||||
while (n--) {
|
||||
bool enable_disasm = true;
|
||||
if (n > 30) {
|
||||
enable_disasm = false;
|
||||
}
|
||||
|
||||
while (n--) {
|
||||
word_t pc = this->ref.at("pc");
|
||||
word_t inst = this->ref.at(pc);
|
||||
if (enable_disasm)
|
||||
std::cout << d.disassemble(pc, (uint8_t *)&inst, WORD_BYTES)
|
||||
<< std::endl;
|
||||
if (inst == 1048691) {
|
||||
// ebreak
|
||||
throw TrmRuntimeException(TrmRuntimeException::EBREAK, "ebreak");
|
||||
}
|
||||
this->ref.exec(1);
|
||||
this->dut.exec(1);
|
||||
this->ref.fetch_state();
|
||||
this->dut.fetch_state();
|
||||
if (*(CPUState *)this->ref.cpu_state !=
|
||||
*(CPUState *)this->dut.cpu_state) {
|
||||
throw std::runtime_error("Difftest failed");
|
||||
throw TrmRuntimeException(TrmRuntimeException::DIFFTEST_FAILED,
|
||||
"Difftest failed");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -96,6 +96,21 @@ public:
|
|||
virtual void print(std::ostream &os) const = 0;
|
||||
};
|
||||
|
||||
class TrmRuntimeException : public std::exception {
|
||||
private:
|
||||
const char *msg_;
|
||||
int code_;
|
||||
|
||||
public:
|
||||
enum { EBREAK, DIFFTEST_FAILED };
|
||||
TrmRuntimeException(int code, const char *message)
|
||||
: code_(code), msg_(message) {}
|
||||
|
||||
virtual const char *what() const throw() { return msg_; }
|
||||
|
||||
int error_code() const { return code_; }
|
||||
};
|
||||
|
||||
struct RefTrmInterface : TrmInterface {
|
||||
RefTrmInterface(std::filesystem::path lib_file) {
|
||||
void *handle = dlopen(lib_file.c_str(), RTLD_LAZY);
|
||||
|
|
|
@ -83,6 +83,12 @@ void Console::registerCommand(const std::string &s, CommandFunction f) {
|
|||
pimpl_->commands_[s] = f;
|
||||
}
|
||||
|
||||
void Console::removeCommands(const std::vector<std::string> sv) {
|
||||
for (auto const &s : sv) {
|
||||
pimpl_->commands_.erase(s);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> Console::getRegisteredCommands() const {
|
||||
std::vector<std::string> allCommands;
|
||||
for (auto &pair : pimpl_->commands_)
|
||||
|
|
|
@ -64,6 +64,13 @@ public:
|
|||
*/
|
||||
void registerCommand(const std::string &s, CommandFunction f);
|
||||
|
||||
/**
|
||||
* @brief This function removes a list of registered commands.
|
||||
*
|
||||
* @param sv The vector of command names to be removed.
|
||||
*/
|
||||
void removeCommands(const std::vector<std::string> sv);
|
||||
|
||||
/**
|
||||
* @brief This function returns a list with the currently available commands.
|
||||
*
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <console.hpp>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <trm_interface.hpp>
|
||||
#include <types.h>
|
||||
|
||||
|
@ -13,7 +14,12 @@ using ret = cr::Console::ReturnCode;
|
|||
|
||||
namespace SDB {
|
||||
|
||||
enum SDBStatus { SDB_SUCCESS, SDB_WRONG_ARGUMENT, SDB_DIFFTEST_FAILED };
|
||||
enum SDBStatus {
|
||||
SDB_SUCCESS,
|
||||
SDB_EBREAK = 2,
|
||||
SDB_WRONG_ARGUMENT,
|
||||
SDB_DIFFTEST_FAILED
|
||||
};
|
||||
|
||||
class SDBHandlers;
|
||||
|
||||
|
@ -36,10 +42,11 @@ private:
|
|||
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);
|
||||
int exec_catch(uint64_t);
|
||||
|
||||
public:
|
||||
SDBHandlers(const TrmInterface &funcs) : funcs(funcs){};
|
||||
void registerHandlers(cr::Console *c);
|
||||
void register_handlers(cr::Console *c);
|
||||
};
|
||||
|
||||
class SDB {
|
||||
|
@ -54,24 +61,34 @@ public:
|
|||
: handlers(SDBHandlers{funcs}), funcs(funcs) {
|
||||
c = std::make_unique<CppReadline::Console>(greeting);
|
||||
|
||||
handlers.registerHandlers(c.get());
|
||||
handlers.register_handlers(c.get());
|
||||
};
|
||||
|
||||
int main_loop() {
|
||||
int retCode;
|
||||
int ret_code;
|
||||
funcs.init(0);
|
||||
std::vector<std::string> step_commands{"c", "continue", "si",
|
||||
"step-instruction"};
|
||||
do {
|
||||
retCode = c->readLine();
|
||||
ret_code = c->readLine();
|
||||
// We can also change the prompt based on last return value:
|
||||
if (retCode == ret::Ok)
|
||||
if (ret_code == SDB_SUCCESS || ret_code == SDB_EBREAK)
|
||||
c->setGreeting("\033[1;34m(npc)\033[0m ");
|
||||
else
|
||||
c->setGreeting("\033[1;31m(npc)\033[0m ");
|
||||
|
||||
if (retCode == SDB_WRONG_ARGUMENT) {
|
||||
std::cout << "Wrong argument give to command\n";
|
||||
switch (ret_code) {
|
||||
case SDB_EBREAK: {
|
||||
std::cout << "\033[1;31m=== ebreak ===\033[0m" << std::endl;
|
||||
c->removeCommands(step_commands);
|
||||
break;
|
||||
}
|
||||
} while (retCode != ret::Quit);
|
||||
case SDB_WRONG_ARGUMENT: {
|
||||
std::cout << "Wrong argument(s) is given to command handler\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (ret_code != ret::Quit);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -20,11 +20,28 @@ std::ostream &operator<<(std::ostream &os, const TrmInterface &d) {
|
|||
|
||||
namespace SDB {
|
||||
|
||||
int SDBHandlers::exec_catch(uint64_t n) {
|
||||
try {
|
||||
this->funcs.exec(n);
|
||||
} catch (TrmRuntimeException &e) {
|
||||
switch (e.error_code()) {
|
||||
case TrmRuntimeException::EBREAK:
|
||||
return SDB_EBREAK;
|
||||
case TrmRuntimeException::DIFFTEST_FAILED:
|
||||
std::cout << "Difftest Failed" << std::endl << funcs << std::endl;
|
||||
return SDB_DIFFTEST_FAILED;
|
||||
default:
|
||||
std::cerr << "Unknown error code" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
return SDB_SUCCESS;
|
||||
}
|
||||
|
||||
int SDBHandlers::cmd_continue(const cr::Console::Arguments &input) {
|
||||
if (input.size() > 1)
|
||||
return SDB_WRONG_ARGUMENT;
|
||||
this->funcs.exec(-1);
|
||||
return SDB_SUCCESS;
|
||||
return exec_catch(-1);
|
||||
}
|
||||
|
||||
int SDBHandlers::cmd_step(const std::vector<std::string> &input) {
|
||||
|
@ -32,14 +49,8 @@ int SDBHandlers::cmd_step(const std::vector<std::string> &input) {
|
|||
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;
|
||||
}
|
||||
return exec_catch(step_count);
|
||||
// std::cout << funcs << std::endl;
|
||||
return SDB_SUCCESS;
|
||||
}
|
||||
|
||||
int SDBHandlers::cmd_info_registers(const std::vector<std::string> &input) {
|
||||
|
@ -72,7 +83,7 @@ int SDBHandlers::cmd_print(const std::vector<std::string> &input) {
|
|||
return SDB_SUCCESS;
|
||||
}
|
||||
|
||||
void SDBHandlers::registerHandlers(cr::Console *c) {
|
||||
void SDBHandlers::register_handlers(cr::Console *c) {
|
||||
for (auto &h : this->all_handlers) {
|
||||
for (auto &name : h.names) {
|
||||
std::function<int(std::vector<std::string>)> f{
|
||||
|
@ -81,4 +92,5 @@ void SDBHandlers::registerHandlers(cr::Console *c) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace SDB
|
||||
|
|
Loading…
Reference in a new issue