blob: a64c6895f5d2d186c05c5a612c1b8d3cb2bed48a [file] [log] [blame]
#include "sim/renode/kelvin_renode.h"
#include <cstdint>
#include <string>
#include "sim/kelvin_top.h"
#include "sim/renode/renode_debug_interface.h"
#include "googletest/include/gtest/gtest.h"
#include "absl/log/check.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "riscv/riscv_debug_info.h"
#include "mpact/sim/util/program_loader/elf_program_loader.h"
namespace {
using kelvin::sim::KelvinTop;
using kelvin::sim::renode::RenodeDebugInterface;
constexpr char kFileName[] = "hello_world_mpause.elf";
constexpr char kBinFileName[] = "hello_world_mpause.bin";
constexpr char kEbreakFileName[] = "kelvin_ebreak.elf";
// The depot path to the test directory.
constexpr char kDepotPath[] = "sim/test/";
constexpr char kTopName[] = "test";
class KelvinRenodeTest : public testing::Test {
protected:
KelvinRenodeTest() { top_ = new kelvin::sim::KelvinRenode(kTopName); }
~KelvinRenodeTest() override { delete top_; }
RenodeDebugInterface *top_ = nullptr;
};
// Test the implementation of the added methods in the RenodeDebugInterface.
TEST_F(KelvinRenodeTest, RegisterIds) {
uint32_t word_value;
for (int i = 0; i < 32; i++) {
uint32_t reg_id =
i + static_cast<uint32_t>(mpact::sim::riscv::DebugRegisterEnum::kX0);
auto result = top_->ReadRegister(reg_id);
EXPECT_TRUE(result.status().ok());
word_value = result.value();
EXPECT_TRUE(top_->WriteRegister(reg_id, word_value + 1).ok());
result = top_->ReadRegister(reg_id);
EXPECT_TRUE(result.status().ok());
EXPECT_EQ(result.value(), word_value + 1);
}
// Not found.
EXPECT_EQ(top_->ReadRegister(0xfff).status().code(),
absl::StatusCode::kNotFound);
EXPECT_EQ(top_->WriteRegister(0xfff, word_value).code(),
absl::StatusCode::kNotFound);
}
TEST_F(KelvinRenodeTest, RunElfProgram) {
std::string file_name = absl::StrCat(kDepotPath, "testfiles/", kFileName);
// Load the program.
auto *loader = new mpact::sim::util::ElfProgramLoader(top_);
auto result = loader->LoadProgram(file_name);
CHECK_OK(result);
auto entry_point = result.value();
// Run the program.
testing::internal::CaptureStdout();
EXPECT_TRUE(top_->WriteRegister("pc", entry_point).ok());
EXPECT_TRUE(top_->Run().ok());
EXPECT_TRUE(top_->Wait().ok());
// Check the results.
auto halt_result = top_->GetLastHaltReason();
CHECK_OK(halt_result);
EXPECT_EQ(static_cast<int>(halt_result.value()),
static_cast<int>(KelvinTop::HaltReason::kUserRequest));
const std::string stdout_str = testing::internal::GetCapturedStdout();
EXPECT_EQ("Program exits properly\n", stdout_str);
// Clean up.
delete loader;
}
TEST_F(KelvinRenodeTest, RunEbreakElfProgram) {
std::string file_name =
absl::StrCat(kDepotPath, "testfiles/", kEbreakFileName);
// Load the program.
auto *loader = new mpact::sim::util::ElfProgramLoader(top_);
auto result = loader->LoadProgram(file_name);
CHECK_OK(result);
auto entry_point = result.value();
// Run the program.
testing::internal::CaptureStdout();
EXPECT_TRUE(top_->WriteRegister("pc", entry_point).ok());
EXPECT_TRUE(top_->Run().ok());
EXPECT_TRUE(top_->Wait().ok());
// Check the results.
auto halt_result = top_->GetLastHaltReason();
CHECK_OK(halt_result);
EXPECT_EQ(static_cast<int>(halt_result.value()),
static_cast<int>(kelvin::sim::kHaltAbort));
const std::string stdout_str = testing::internal::GetCapturedStdout();
EXPECT_EQ("Program exits with fault\n", stdout_str);
// Clean up.
delete loader;
}
TEST_F(KelvinRenodeTest, RunBinProgram) {
std::string file_name = absl::StrCat(kDepotPath, "testfiles/", kBinFileName);
constexpr uint64_t kBinFileAddress = 0x0;
constexpr uint64_t kBinFileEntryPoint = 0x0;
auto res = top_->LoadImage(file_name, kBinFileAddress);
EXPECT_TRUE(res.ok());
// Run the program.
testing::internal::CaptureStdout();
EXPECT_TRUE(top_->WriteRegister("pc", kBinFileEntryPoint).ok());
EXPECT_TRUE(top_->Run().ok());
EXPECT_TRUE(top_->Wait().ok());
// Check the results.
auto halt_result = top_->GetLastHaltReason();
CHECK_OK(halt_result);
EXPECT_EQ(static_cast<int>(halt_result.value()),
static_cast<int>(KelvinTop::HaltReason::kUserRequest));
const std::string stdout_str = testing::internal::GetCapturedStdout();
EXPECT_EQ("Program exits properly\n", stdout_str);
}
} // namespace