aboutsummaryrefslogtreecommitdiffhomepage
path: root/tests
diff options
context:
space:
mode:
authorMerry <[email protected]>2023-01-20 11:50:41 +0000
committerMerry <[email protected]>2023-01-20 11:50:41 +0000
commit2a87337141a9d848276bed4188dbdeab2bd0a770 (patch)
tree066bc9bb1a6f0b66726c0072f5ad14f9717f895f /tests
parentf0ebdf278cf59eb90a56a159c374028eef059253 (diff)
downloaddynarmic-2a87337141a9d848276bed4188dbdeab2bd0a770.tar.gz
dynarmic-2a87337141a9d848276bed4188dbdeab2bd0a770.zip
test_reader: Add A32 modes
Diffstat (limited to 'tests')
-rw-r--r--tests/test_reader.cpp315
1 files changed, 263 insertions, 52 deletions
diff --git a/tests/test_reader.cpp b/tests/test_reader.cpp
index c0ddac28..7c60a9f9 100644
--- a/tests/test_reader.cpp
+++ b/tests/test_reader.cpp
@@ -12,12 +12,148 @@
#include <fmt/format.h>
#include <mcl/stdint.hpp>
+#include "./A32/testenv.h"
#include "./A64/testenv.h"
#include "dynarmic/common/fp/fpsr.h"
+#include "dynarmic/interface/A32/a32.h"
#include "dynarmic/interface/A64/a64.h"
+const bool mask_fpsr_cum_bits = true;
+
using namespace Dynarmic;
+void SkipWhitespace(std::string_view& sv) {
+ auto nextpos{sv.find_first_not_of(' ')};
+ if (nextpos != std::string::npos) {
+ sv.remove_prefix(nextpos);
+ }
+}
+
+void SkipHeader(std::string_view& sv) {
+ sv.remove_prefix(sv.find_first_of(':') + 1);
+ SkipWhitespace(sv);
+}
+
+std::string_view NextToken(std::string_view& sv) {
+ auto nextpos{sv.find_first_of(' ')};
+ auto tok{sv.substr(0, nextpos)};
+ sv.remove_prefix(nextpos == std::string::npos ? sv.size() : nextpos);
+ SkipWhitespace(sv);
+ return tok;
+}
+
+u64 ParseHex(std::string_view hex) {
+ u64 result = 0;
+ while (!hex.empty()) {
+ result <<= 4;
+ if (hex.front() >= '0' && hex.front() <= '9') {
+ result += hex.front() - '0';
+ } else if (hex.front() >= 'a' && hex.front() <= 'f') {
+ result += hex.front() - 'a' + 0xA;
+ } else if (hex.front() >= 'A' && hex.front() <= 'F') {
+ result += hex.front() - 'A' + 0xA;
+ } else if (hex.front() == ':') {
+ return result;
+ } else {
+ fmt::print("Character {} is not a valid hex character\n", hex.front());
+ }
+ hex.remove_prefix(1);
+ }
+ return result;
+}
+
+template<typename TestEnv>
+Dynarmic::A32::UserConfig GetA32UserConfig(TestEnv& testenv) {
+ Dynarmic::A32::UserConfig user_config;
+ user_config.optimizations &= ~OptimizationFlag::FastDispatch;
+ user_config.callbacks = &testenv;
+ user_config.very_verbose_debugging_output = true;
+ return user_config;
+}
+
+template<size_t num_jit_reruns = 1, typename TestEnv>
+void RunTestInstance(Dynarmic::A32::Jit& jit,
+ TestEnv& jit_env,
+ const std::array<u32, 16>& regs,
+ const std::array<u32, 64>& vecs,
+ const std::vector<typename TestEnv::InstructionType>& instructions,
+ const u32 cpsr,
+ const u32 fpscr,
+ const size_t ticks_left) {
+ const u32 initial_pc = regs[15];
+ const u32 num_words = initial_pc / sizeof(typename TestEnv::InstructionType);
+ const u32 code_mem_size = num_words + static_cast<u32>(instructions.size());
+
+ jit.ClearCache();
+
+ for (size_t jit_rerun_count = 0; jit_rerun_count < num_jit_reruns; ++jit_rerun_count) {
+ jit_env.code_mem.resize(code_mem_size);
+ std::fill(jit_env.code_mem.begin(), jit_env.code_mem.end(), TestEnv::infinite_loop);
+
+ std::copy(instructions.begin(), instructions.end(), jit_env.code_mem.begin() + num_words);
+ jit_env.PadCodeMem();
+ jit_env.modified_memory.clear();
+ jit_env.interrupts.clear();
+
+ jit.Regs() = regs;
+ jit.ExtRegs() = vecs;
+ jit.SetFpscr(fpscr);
+ jit.SetCpsr(cpsr);
+
+ jit_env.ticks_left = ticks_left;
+ jit.Run();
+ }
+
+ fmt::print("instructions:");
+ for (auto instruction : instructions) {
+ if constexpr (sizeof(decltype(instruction)) == 2) {
+ fmt::print(" {:04x}", instruction);
+ } else {
+ fmt::print(" {:08x}", instruction);
+ }
+ }
+ fmt::print("\n");
+
+ fmt::print("initial_regs:");
+ for (u32 i : regs) {
+ fmt::print(" {:08x}", i);
+ }
+ fmt::print("\n");
+ fmt::print("initial_vecs:");
+ for (u32 i : vecs) {
+ fmt::print(" {:08x}", i);
+ }
+ fmt::print("\n");
+ fmt::print("initial_cpsr: {:08x}\n", cpsr);
+ fmt::print("initial_fpcr: {:08x}\n", fpscr);
+
+ fmt::print("final_regs:");
+ for (u32 i : jit.Regs()) {
+ fmt::print(" {:08x}", i);
+ }
+ fmt::print("\n");
+ fmt::print("final_vecs:");
+ for (u32 i : jit.ExtRegs()) {
+ fmt::print(" {:08x}", i);
+ }
+ fmt::print("\n");
+ fmt::print("final_cpsr: {:08x}\n", jit.Cpsr());
+ fmt::print("final_fpsr: {:08x}\n", mask_fpsr_cum_bits ? jit.Fpscr() & 0xffffff00 : jit.Fpscr());
+
+ fmt::print("mod_mem: ");
+ for (auto [addr, value] : jit_env.modified_memory) {
+ fmt::print("{:08x}:{:02x} ", addr, value);
+ }
+ fmt::print("\n");
+
+ fmt::print("interrupts:\n");
+ for (const auto& i : jit_env.interrupts) {
+ std::puts(i.c_str());
+ }
+
+ fmt::print("===\n");
+}
+
A64::UserConfig GetA64UserConfig(A64TestEnv& jit_env) {
A64::UserConfig jit_user_config{&jit_env};
jit_user_config.optimizations &= ~OptimizationFlag::FastDispatch;
@@ -111,7 +247,101 @@ void RunTestInstance(A64::Jit& jit,
fmt::print("===\n");
}
-int main() {
+void RunThumb() {
+ std::array<u32, 16> initial_regs{};
+ std::array<u32, 64> initial_vecs{};
+ std::vector<u16> instructions{};
+ u32 initial_cpsr = 0;
+ u32 initial_fpcr = 0;
+
+ std::string line;
+ while (std::getline(std::cin, line)) {
+ std::string_view sv{line};
+
+ if (sv.starts_with("instructions:")) {
+ SkipHeader(sv);
+ while (!sv.empty()) {
+ instructions.emplace_back((u16)ParseHex(NextToken(sv)));
+ }
+ } else if (sv.starts_with("initial_regs:")) {
+ SkipHeader(sv);
+ for (size_t i = 0; i < initial_regs.size(); ++i) {
+ initial_regs[i] = (u32)ParseHex(NextToken(sv));
+ }
+ } else if (sv.starts_with("initial_vecs:")) {
+ SkipHeader(sv);
+ for (size_t i = 0; i < initial_vecs.size(); ++i) {
+ initial_vecs[i] = (u32)ParseHex(NextToken(sv));
+ }
+ } else if (sv.starts_with("initial_cpsr:")) {
+ SkipHeader(sv);
+ initial_cpsr = (u32)ParseHex(NextToken(sv));
+ } else if (sv.starts_with("initial_fpcr:")) {
+ SkipHeader(sv);
+ initial_fpcr = (u32)ParseHex(NextToken(sv));
+ }
+ }
+
+ ThumbTestEnv jit_env{};
+ A32::Jit jit{GetA32UserConfig(jit_env)};
+ RunTestInstance(jit,
+ jit_env,
+ initial_regs,
+ initial_vecs,
+ instructions,
+ initial_cpsr,
+ initial_fpcr,
+ instructions.size());
+}
+
+void RunArm() {
+ std::array<u32, 16> initial_regs{};
+ std::array<u32, 64> initial_vecs{};
+ std::vector<u32> instructions{};
+ u32 initial_cpsr = 0;
+ u32 initial_fpcr = 0;
+
+ std::string line;
+ while (std::getline(std::cin, line)) {
+ std::string_view sv{line};
+
+ if (sv.starts_with("instructions:")) {
+ SkipHeader(sv);
+ while (!sv.empty()) {
+ instructions.emplace_back((u32)ParseHex(NextToken(sv)));
+ }
+ } else if (sv.starts_with("initial_regs:")) {
+ SkipHeader(sv);
+ for (size_t i = 0; i < initial_regs.size(); ++i) {
+ initial_regs[i] = (u32)ParseHex(NextToken(sv));
+ }
+ } else if (sv.starts_with("initial_vecs:")) {
+ SkipHeader(sv);
+ for (size_t i = 0; i < initial_vecs.size(); ++i) {
+ initial_vecs[i] = (u32)ParseHex(NextToken(sv));
+ }
+ } else if (sv.starts_with("initial_cpsr:")) {
+ SkipHeader(sv);
+ initial_cpsr = (u32)ParseHex(NextToken(sv));
+ } else if (sv.starts_with("initial_fpcr:")) {
+ SkipHeader(sv);
+ initial_fpcr = (u32)ParseHex(NextToken(sv));
+ }
+ }
+
+ ArmTestEnv jit_env{};
+ A32::Jit jit{GetA32UserConfig(jit_env)};
+ RunTestInstance(jit,
+ jit_env,
+ initial_regs,
+ initial_vecs,
+ instructions,
+ initial_cpsr,
+ initial_fpcr,
+ instructions.size());
+}
+
+void RunA64() {
std::array<u64, 31> initial_regs{};
std::array<std::array<u64, 2>, 32> initial_vecs{};
std::vector<u32> instructions{};
@@ -124,70 +354,33 @@ int main() {
while (std::getline(std::cin, line)) {
std::string_view sv{line};
- const auto skip_ws = [&] {
- auto nextpos{sv.find_first_not_of(' ')};
- if (nextpos != std::string::npos) {
- sv.remove_prefix(nextpos);
- }
- };
- const auto skip_header = [&] {
- sv.remove_prefix(sv.find_first_of(':') + 1);
- skip_ws();
- };
- const auto next_token = [&] {
- auto nextpos{sv.find_first_of(' ')};
- auto tok{sv.substr(0, nextpos)};
- sv.remove_prefix(nextpos == std::string::npos ? sv.size() : nextpos);
- skip_ws();
- return tok;
- };
- const auto parse_hex = [&](std::string_view hex) {
- u64 result = 0;
- while (!hex.empty()) {
- result <<= 4;
- if (hex.front() >= '0' && hex.front() <= '9') {
- result += hex.front() - '0';
- } else if (hex.front() >= 'a' && hex.front() <= 'f') {
- result += hex.front() - 'a' + 0xA;
- } else if (hex.front() >= 'A' && hex.front() <= 'F') {
- result += hex.front() - 'A' + 0xA;
- } else if (hex.front() == ':') {
- return result;
- } else {
- fmt::print("Character {} is not a valid hex character\n", hex.front());
- }
- hex.remove_prefix(1);
- }
- return result;
- };
-
if (sv.starts_with("instructions:")) {
- skip_header();
+ SkipHeader(sv);
while (!sv.empty()) {
- instructions.emplace_back((u32)parse_hex(next_token()));
+ instructions.emplace_back((u32)ParseHex(NextToken(sv)));
}
} else if (sv.starts_with("initial_regs:")) {
- skip_header();
+ SkipHeader(sv);
for (size_t i = 0; i < initial_regs.size(); ++i) {
- initial_regs[i] = parse_hex(next_token());
+ initial_regs[i] = ParseHex(NextToken(sv));
}
} else if (sv.starts_with("initial_vecs:")) {
- skip_header();
+ SkipHeader(sv);
for (size_t i = 0; i < initial_vecs.size(); ++i) {
- auto tok{next_token()};
- initial_vecs[i][0] = parse_hex(tok);
+ auto tok{NextToken(sv)};
+ initial_vecs[i][0] = ParseHex(tok);
tok.remove_prefix(tok.find_first_of(':') + 1);
- initial_vecs[i][1] = parse_hex(tok);
+ initial_vecs[i][1] = ParseHex(tok);
}
} else if (sv.starts_with("initial_sp:")) {
- skip_header();
- initial_sp = parse_hex(next_token());
+ SkipHeader(sv);
+ initial_sp = ParseHex(NextToken(sv));
} else if (sv.starts_with("initial_pstate:")) {
- skip_header();
- initial_pstate = (u32)parse_hex(next_token());
+ SkipHeader(sv);
+ initial_pstate = (u32)ParseHex(NextToken(sv));
} else if (sv.starts_with("initial_fpcr:")) {
- skip_header();
- initial_fpcr = (u32)parse_hex(next_token());
+ SkipHeader(sv);
+ initial_fpcr = (u32)ParseHex(NextToken(sv));
}
}
@@ -203,6 +396,24 @@ int main() {
initial_sp,
start_address,
instructions.size());
+}
+
+int main(int argc, char** argv) {
+ if (argc != 2) {
+ fmt::print("Usage: {} <thumb|arm|a64>\n", argv[0]);
+ return 1;
+ }
+
+ if (strcmp(argv[1], "thumb") == 0) {
+ RunThumb();
+ } else if (strcmp(argv[1], "arm") == 0) {
+ RunArm();
+ } else if (strcmp(argv[1], "a64") == 0) {
+ RunA64();
+ } else {
+ fmt::print("unrecognized instruction class\n");
+ return 1;
+ }
return 0;
}