test_reader.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. /* This file is part of the dynarmic project.
  2. * Copyright (c) 2023 MerryMage
  3. * SPDX-License-Identifier: 0BSD
  4. */
  5. #include <array>
  6. #include <iostream>
  7. #include <string>
  8. #include <string_view>
  9. #include <vector>
  10. #include <fmt/format.h>
  11. #include <mcl/stdint.hpp>
  12. #include "./A32/testenv.h"
  13. #include "./A64/testenv.h"
  14. #include "dynarmic/common/fp/fpsr.h"
  15. #include "dynarmic/interface/A32/a32.h"
  16. #include "dynarmic/interface/A64/a64.h"
  17. const bool mask_fpsr_cum_bits = true;
  18. using namespace Dynarmic;
  19. void SkipWhitespace(std::string_view& sv) {
  20. auto nextpos{sv.find_first_not_of(' ')};
  21. if (nextpos != std::string::npos) {
  22. sv.remove_prefix(nextpos);
  23. }
  24. }
  25. void SkipHeader(std::string_view& sv) {
  26. sv.remove_prefix(sv.find_first_of(':') + 1);
  27. SkipWhitespace(sv);
  28. }
  29. std::string_view NextToken(std::string_view& sv) {
  30. auto nextpos{sv.find_first_of(' ')};
  31. auto tok{sv.substr(0, nextpos)};
  32. sv.remove_prefix(nextpos == std::string::npos ? sv.size() : nextpos);
  33. SkipWhitespace(sv);
  34. return tok;
  35. }
  36. u64 ParseHex(std::string_view hex) {
  37. u64 result = 0;
  38. while (!hex.empty()) {
  39. result <<= 4;
  40. if (hex.front() >= '0' && hex.front() <= '9') {
  41. result += hex.front() - '0';
  42. } else if (hex.front() >= 'a' && hex.front() <= 'f') {
  43. result += hex.front() - 'a' + 0xA;
  44. } else if (hex.front() >= 'A' && hex.front() <= 'F') {
  45. result += hex.front() - 'A' + 0xA;
  46. } else if (hex.front() == ':') {
  47. return result;
  48. } else {
  49. fmt::print("Character {} is not a valid hex character\n", hex.front());
  50. }
  51. hex.remove_prefix(1);
  52. }
  53. return result;
  54. }
  55. template<typename TestEnv>
  56. Dynarmic::A32::UserConfig GetA32UserConfig(TestEnv& testenv, bool noopt) {
  57. Dynarmic::A32::UserConfig user_config;
  58. user_config.optimizations &= ~OptimizationFlag::FastDispatch;
  59. user_config.callbacks = &testenv;
  60. user_config.very_verbose_debugging_output = true;
  61. if (noopt) {
  62. user_config.optimizations = no_optimizations;
  63. }
  64. return user_config;
  65. }
  66. template<size_t num_jit_reruns = 1, typename TestEnv>
  67. void RunTestInstance(Dynarmic::A32::Jit& jit,
  68. TestEnv& jit_env,
  69. const std::array<u32, 16>& regs,
  70. const std::array<u32, 64>& vecs,
  71. const std::vector<typename TestEnv::InstructionType>& instructions,
  72. const u32 cpsr,
  73. const u32 fpscr,
  74. const size_t ticks_left) {
  75. const u32 initial_pc = regs[15];
  76. const u32 num_words = initial_pc / sizeof(typename TestEnv::InstructionType);
  77. const u32 code_mem_size = num_words + static_cast<u32>(instructions.size());
  78. jit.ClearCache();
  79. for (size_t jit_rerun_count = 0; jit_rerun_count < num_jit_reruns; ++jit_rerun_count) {
  80. jit_env.code_mem.resize(code_mem_size);
  81. std::fill(jit_env.code_mem.begin(), jit_env.code_mem.end(), TestEnv::infinite_loop);
  82. std::copy(instructions.begin(), instructions.end(), jit_env.code_mem.begin() + num_words);
  83. jit_env.PadCodeMem();
  84. jit_env.modified_memory.clear();
  85. jit_env.interrupts.clear();
  86. jit.Regs() = regs;
  87. jit.ExtRegs() = vecs;
  88. jit.SetFpscr(fpscr);
  89. jit.SetCpsr(cpsr);
  90. jit_env.ticks_left = ticks_left;
  91. jit.Run();
  92. }
  93. fmt::print("instructions:");
  94. for (auto instruction : instructions) {
  95. if constexpr (sizeof(decltype(instruction)) == 2) {
  96. fmt::print(" {:04x}", instruction);
  97. } else {
  98. fmt::print(" {:08x}", instruction);
  99. }
  100. }
  101. fmt::print("\n");
  102. fmt::print("initial_regs:");
  103. for (u32 i : regs) {
  104. fmt::print(" {:08x}", i);
  105. }
  106. fmt::print("\n");
  107. fmt::print("initial_vecs:");
  108. for (u32 i : vecs) {
  109. fmt::print(" {:08x}", i);
  110. }
  111. fmt::print("\n");
  112. fmt::print("initial_cpsr: {:08x}\n", cpsr);
  113. fmt::print("initial_fpcr: {:08x}\n", fpscr);
  114. fmt::print("final_regs:");
  115. for (u32 i : jit.Regs()) {
  116. fmt::print(" {:08x}", i);
  117. }
  118. fmt::print("\n");
  119. fmt::print("final_vecs:");
  120. for (u32 i : jit.ExtRegs()) {
  121. fmt::print(" {:08x}", i);
  122. }
  123. fmt::print("\n");
  124. fmt::print("final_cpsr: {:08x}\n", jit.Cpsr());
  125. fmt::print("final_fpsr: {:08x}\n", mask_fpsr_cum_bits ? jit.Fpscr() & 0xffffff00 : jit.Fpscr());
  126. fmt::print("mod_mem: ");
  127. for (auto [addr, value] : jit_env.modified_memory) {
  128. fmt::print("{:08x}:{:02x} ", addr, value);
  129. }
  130. fmt::print("\n");
  131. fmt::print("interrupts:\n");
  132. for (const auto& i : jit_env.interrupts) {
  133. std::puts(i.c_str());
  134. }
  135. fmt::print("===\n");
  136. }
  137. A64::UserConfig GetA64UserConfig(A64TestEnv& jit_env, bool noopt) {
  138. A64::UserConfig jit_user_config{&jit_env};
  139. jit_user_config.optimizations &= ~OptimizationFlag::FastDispatch;
  140. // The below corresponds to the settings for qemu's aarch64_max_initfn
  141. jit_user_config.dczid_el0 = 7;
  142. jit_user_config.ctr_el0 = 0x80038003;
  143. jit_user_config.very_verbose_debugging_output = true;
  144. if (noopt) {
  145. jit_user_config.optimizations = no_optimizations;
  146. }
  147. return jit_user_config;
  148. }
  149. template<size_t num_jit_reruns = 1>
  150. void RunTestInstance(A64::Jit& jit,
  151. A64TestEnv& jit_env,
  152. const std::array<u64, 31>& regs,
  153. const std::array<std::array<u64, 2>, 32>& vecs,
  154. const std::vector<u32>& instructions,
  155. const u32 pstate,
  156. const u32 fpcr,
  157. const u64 initial_sp,
  158. const u64 start_address,
  159. const size_t ticks_left) {
  160. jit.ClearCache();
  161. for (size_t jit_rerun_count = 0; jit_rerun_count < num_jit_reruns; ++jit_rerun_count) {
  162. jit_env.code_mem = instructions;
  163. jit_env.code_mem.emplace_back(0x14000000); // B .
  164. jit_env.code_mem_start_address = start_address;
  165. jit_env.modified_memory.clear();
  166. jit_env.interrupts.clear();
  167. jit.SetRegisters(regs);
  168. jit.SetVectors(vecs);
  169. jit.SetPC(start_address);
  170. jit.SetSP(initial_sp);
  171. jit.SetFpcr(fpcr);
  172. jit.SetFpsr(0);
  173. jit.SetPstate(pstate);
  174. jit.ClearCache();
  175. jit_env.ticks_left = ticks_left;
  176. jit.Run();
  177. }
  178. fmt::print("instructions:");
  179. for (u32 instruction : instructions) {
  180. fmt::print(" {:08x}", instruction);
  181. }
  182. fmt::print("\n");
  183. fmt::print("initial_regs:");
  184. for (u64 i : regs) {
  185. fmt::print(" {:016x}", i);
  186. }
  187. fmt::print("\n");
  188. fmt::print("initial_vecs:");
  189. for (auto i : vecs) {
  190. fmt::print(" {:016x}:{:016x}", i[0], i[1]);
  191. }
  192. fmt::print("\n");
  193. fmt::print("initial_sp: {:016x}\n", initial_sp);
  194. fmt::print("initial_pstate: {:08x}\n", pstate);
  195. fmt::print("initial_fpcr: {:08x}\n", fpcr);
  196. fmt::print("final_regs:");
  197. for (u64 i : jit.GetRegisters()) {
  198. fmt::print(" {:016x}", i);
  199. }
  200. fmt::print("\n");
  201. fmt::print("final_vecs:");
  202. for (auto i : jit.GetVectors()) {
  203. fmt::print(" {:016x}:{:016x}", i[0], i[1]);
  204. }
  205. fmt::print("\n");
  206. fmt::print("final_sp: {:016x}\n", jit.GetSP());
  207. fmt::print("final_pc: {:016x}\n", jit.GetPC());
  208. fmt::print("final_pstate: {:08x}\n", jit.GetPstate());
  209. fmt::print("final_fpcr: {:08x}\n", jit.GetFpcr());
  210. fmt::print("final_qc : {}\n", FP::FPSR{jit.GetFpsr()}.QC());
  211. fmt::print("mod_mem:");
  212. for (auto [addr, value] : jit_env.modified_memory) {
  213. fmt::print(" {:08x}:{:02x}", addr, value);
  214. }
  215. fmt::print("\n");
  216. fmt::print("interrupts:\n");
  217. for (const auto& i : jit_env.interrupts) {
  218. std::puts(i.c_str());
  219. }
  220. fmt::print("===\n");
  221. }
  222. void RunThumb(bool noopt) {
  223. std::array<u32, 16> initial_regs{};
  224. std::array<u32, 64> initial_vecs{};
  225. std::vector<u16> instructions{};
  226. u32 initial_cpsr = 0;
  227. u32 initial_fpcr = 0;
  228. std::string line;
  229. while (std::getline(std::cin, line)) {
  230. std::string_view sv{line};
  231. if (sv.starts_with("instructions:")) {
  232. SkipHeader(sv);
  233. while (!sv.empty()) {
  234. instructions.emplace_back((u16)ParseHex(NextToken(sv)));
  235. }
  236. } else if (sv.starts_with("initial_regs:")) {
  237. SkipHeader(sv);
  238. for (size_t i = 0; i < initial_regs.size(); ++i) {
  239. initial_regs[i] = (u32)ParseHex(NextToken(sv));
  240. }
  241. } else if (sv.starts_with("initial_vecs:")) {
  242. SkipHeader(sv);
  243. for (size_t i = 0; i < initial_vecs.size(); ++i) {
  244. initial_vecs[i] = (u32)ParseHex(NextToken(sv));
  245. }
  246. } else if (sv.starts_with("initial_cpsr:")) {
  247. SkipHeader(sv);
  248. initial_cpsr = (u32)ParseHex(NextToken(sv));
  249. } else if (sv.starts_with("initial_fpcr:")) {
  250. SkipHeader(sv);
  251. initial_fpcr = (u32)ParseHex(NextToken(sv));
  252. }
  253. }
  254. ThumbTestEnv jit_env{};
  255. A32::Jit jit{GetA32UserConfig(jit_env, noopt)};
  256. RunTestInstance(jit,
  257. jit_env,
  258. initial_regs,
  259. initial_vecs,
  260. instructions,
  261. initial_cpsr,
  262. initial_fpcr,
  263. instructions.size());
  264. }
  265. void RunArm(bool noopt) {
  266. std::array<u32, 16> initial_regs{};
  267. std::array<u32, 64> initial_vecs{};
  268. std::vector<u32> instructions{};
  269. u32 initial_cpsr = 0;
  270. u32 initial_fpcr = 0;
  271. std::string line;
  272. while (std::getline(std::cin, line)) {
  273. std::string_view sv{line};
  274. if (sv.starts_with("instructions:")) {
  275. SkipHeader(sv);
  276. while (!sv.empty()) {
  277. instructions.emplace_back((u32)ParseHex(NextToken(sv)));
  278. }
  279. } else if (sv.starts_with("initial_regs:")) {
  280. SkipHeader(sv);
  281. for (size_t i = 0; i < initial_regs.size(); ++i) {
  282. initial_regs[i] = (u32)ParseHex(NextToken(sv));
  283. }
  284. } else if (sv.starts_with("initial_vecs:")) {
  285. SkipHeader(sv);
  286. for (size_t i = 0; i < initial_vecs.size(); ++i) {
  287. initial_vecs[i] = (u32)ParseHex(NextToken(sv));
  288. }
  289. } else if (sv.starts_with("initial_cpsr:")) {
  290. SkipHeader(sv);
  291. initial_cpsr = (u32)ParseHex(NextToken(sv));
  292. } else if (sv.starts_with("initial_fpcr:")) {
  293. SkipHeader(sv);
  294. initial_fpcr = (u32)ParseHex(NextToken(sv));
  295. }
  296. }
  297. ArmTestEnv jit_env{};
  298. A32::Jit jit{GetA32UserConfig(jit_env, noopt)};
  299. RunTestInstance(jit,
  300. jit_env,
  301. initial_regs,
  302. initial_vecs,
  303. instructions,
  304. initial_cpsr,
  305. initial_fpcr,
  306. instructions.size());
  307. }
  308. void RunA64(bool noopt) {
  309. std::array<u64, 31> initial_regs{};
  310. std::array<std::array<u64, 2>, 32> initial_vecs{};
  311. std::vector<u32> instructions{};
  312. u32 initial_pstate = 0;
  313. u32 initial_fpcr = 0;
  314. u64 initial_sp = 0;
  315. u64 start_address = 100;
  316. std::string line;
  317. while (std::getline(std::cin, line)) {
  318. std::string_view sv{line};
  319. if (sv.starts_with("instructions:")) {
  320. SkipHeader(sv);
  321. while (!sv.empty()) {
  322. instructions.emplace_back((u32)ParseHex(NextToken(sv)));
  323. }
  324. } else if (sv.starts_with("initial_regs:")) {
  325. SkipHeader(sv);
  326. for (size_t i = 0; i < initial_regs.size(); ++i) {
  327. initial_regs[i] = ParseHex(NextToken(sv));
  328. }
  329. } else if (sv.starts_with("initial_vecs:")) {
  330. SkipHeader(sv);
  331. for (size_t i = 0; i < initial_vecs.size(); ++i) {
  332. auto tok{NextToken(sv)};
  333. initial_vecs[i][0] = ParseHex(tok);
  334. tok.remove_prefix(tok.find_first_of(':') + 1);
  335. initial_vecs[i][1] = ParseHex(tok);
  336. }
  337. } else if (sv.starts_with("initial_sp:")) {
  338. SkipHeader(sv);
  339. initial_sp = ParseHex(NextToken(sv));
  340. } else if (sv.starts_with("initial_pstate:")) {
  341. SkipHeader(sv);
  342. initial_pstate = (u32)ParseHex(NextToken(sv));
  343. } else if (sv.starts_with("initial_fpcr:")) {
  344. SkipHeader(sv);
  345. initial_fpcr = (u32)ParseHex(NextToken(sv));
  346. }
  347. }
  348. A64TestEnv jit_env{};
  349. A64::Jit jit{GetA64UserConfig(jit_env, noopt)};
  350. RunTestInstance(jit,
  351. jit_env,
  352. initial_regs,
  353. initial_vecs,
  354. instructions,
  355. initial_pstate,
  356. initial_fpcr,
  357. initial_sp,
  358. start_address,
  359. instructions.size());
  360. }
  361. int main(int argc, char** argv) {
  362. if (argc < 2 || argc > 3) {
  363. fmt::print("Usage: {} <thumb|arm|a64> [noopt]\n", argv[0]);
  364. return 1;
  365. }
  366. const bool noopt = argc == 3 && (strcmp(argv[2], "noopt") == 0);
  367. if (strcmp(argv[1], "thumb") == 0) {
  368. RunThumb(noopt);
  369. } else if (strcmp(argv[1], "arm") == 0) {
  370. RunArm(noopt);
  371. } else if (strcmp(argv[1], "a64") == 0) {
  372. RunA64(noopt);
  373. } else {
  374. fmt::print("unrecognized instruction class\n");
  375. return 1;
  376. }
  377. return 0;
  378. }