fuzz_arm.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  1. /* This file is part of the dynarmic project.
  2. * Copyright (c) 2016 MerryMage
  3. * SPDX-License-Identifier: 0BSD
  4. */
  5. #include <algorithm>
  6. #include <array>
  7. #include <cstdio>
  8. #include <functional>
  9. #include <tuple>
  10. #include <type_traits>
  11. #include <vector>
  12. #include <catch2/catch_test_macros.hpp>
  13. #include <mcl/bit/bit_count.hpp>
  14. #include <mcl/bit/swap.hpp>
  15. #include <mcl/scope_exit.hpp>
  16. #include <mcl/stdint.hpp>
  17. #include "../fuzz_util.h"
  18. #include "../rand_int.h"
  19. #include "../unicorn_emu/a32_unicorn.h"
  20. #include "./testenv.h"
  21. #include "dynarmic/common/fp/fpcr.h"
  22. #include "dynarmic/common/fp/fpsr.h"
  23. #include "dynarmic/common/llvm_disassemble.h"
  24. #include "dynarmic/common/variant_util.h"
  25. #include "dynarmic/frontend/A32/ITState.h"
  26. #include "dynarmic/frontend/A32/a32_location_descriptor.h"
  27. #include "dynarmic/frontend/A32/a32_types.h"
  28. #include "dynarmic/frontend/A32/translate/a32_translate.h"
  29. #include "dynarmic/interface/A32/a32.h"
  30. #include "dynarmic/ir/basic_block.h"
  31. #include "dynarmic/ir/location_descriptor.h"
  32. #include "dynarmic/ir/opcodes.h"
  33. // Must be declared last for all necessary operator<< to be declared prior to this.
  34. #include <fmt/format.h>
  35. #include <fmt/ostream.h>
  36. namespace {
  37. using namespace Dynarmic;
  38. template<typename Fn>
  39. bool AnyLocationDescriptorForTerminalHas(IR::Terminal terminal, Fn fn) {
  40. return Common::VisitVariant<bool>(terminal, [&](auto t) -> bool {
  41. using T = std::decay_t<decltype(t)>;
  42. if constexpr (std::is_same_v<T, IR::Term::Invalid>) {
  43. return false;
  44. } else if constexpr (std::is_same_v<T, IR::Term::ReturnToDispatch>) {
  45. return false;
  46. } else if constexpr (std::is_same_v<T, IR::Term::LinkBlock>) {
  47. return fn(t.next);
  48. } else if constexpr (std::is_same_v<T, IR::Term::LinkBlockFast>) {
  49. return fn(t.next);
  50. } else if constexpr (std::is_same_v<T, IR::Term::PopRSBHint>) {
  51. return false;
  52. } else if constexpr (std::is_same_v<T, IR::Term::Interpret>) {
  53. return fn(t.next);
  54. } else if constexpr (std::is_same_v<T, IR::Term::FastDispatchHint>) {
  55. return false;
  56. } else if constexpr (std::is_same_v<T, IR::Term::If>) {
  57. return AnyLocationDescriptorForTerminalHas(t.then_, fn) || AnyLocationDescriptorForTerminalHas(t.else_, fn);
  58. } else if constexpr (std::is_same_v<T, IR::Term::CheckBit>) {
  59. return AnyLocationDescriptorForTerminalHas(t.then_, fn) || AnyLocationDescriptorForTerminalHas(t.else_, fn);
  60. } else if constexpr (std::is_same_v<T, IR::Term::CheckHalt>) {
  61. return AnyLocationDescriptorForTerminalHas(t.else_, fn);
  62. } else {
  63. ASSERT_MSG(false, "Invalid terminal type");
  64. return false;
  65. }
  66. });
  67. }
  68. bool ShouldTestInst(u32 instruction, u32 pc, bool is_thumb, bool is_last_inst, A32::ITState it_state = {}) {
  69. const A32::LocationDescriptor location = A32::LocationDescriptor{pc, {}, {}}.SetTFlag(is_thumb).SetIT(it_state);
  70. IR::Block block{location};
  71. const bool should_continue = A32::TranslateSingleInstruction(block, location, instruction);
  72. if (!should_continue && !is_last_inst) {
  73. return false;
  74. }
  75. if (auto terminal = block.GetTerminal(); boost::get<IR::Term::Interpret>(&terminal)) {
  76. return false;
  77. }
  78. if (AnyLocationDescriptorForTerminalHas(block.GetTerminal(), [&](IR::LocationDescriptor ld) { return A32::LocationDescriptor{ld}.PC() <= pc; })) {
  79. return false;
  80. }
  81. for (const auto& ir_inst : block) {
  82. switch (ir_inst.GetOpcode()) {
  83. case IR::Opcode::A32ExceptionRaised:
  84. case IR::Opcode::A32CallSupervisor:
  85. case IR::Opcode::A32CoprocInternalOperation:
  86. case IR::Opcode::A32CoprocSendOneWord:
  87. case IR::Opcode::A32CoprocSendTwoWords:
  88. case IR::Opcode::A32CoprocGetOneWord:
  89. case IR::Opcode::A32CoprocGetTwoWords:
  90. case IR::Opcode::A32CoprocLoadWords:
  91. case IR::Opcode::A32CoprocStoreWords:
  92. return false;
  93. // Currently unimplemented in Unicorn
  94. case IR::Opcode::FPVectorRecipEstimate16:
  95. case IR::Opcode::FPVectorRSqrtEstimate16:
  96. case IR::Opcode::VectorPolynomialMultiplyLong64:
  97. return false;
  98. default:
  99. continue;
  100. }
  101. }
  102. return true;
  103. }
  104. u32 GenRandomArmInst(u32 pc, bool is_last_inst) {
  105. static const struct InstructionGeneratorInfo {
  106. std::vector<InstructionGenerator> generators;
  107. std::vector<InstructionGenerator> invalid;
  108. } instructions = [] {
  109. const std::vector<std::tuple<std::string, const char*>> list{
  110. #define INST(fn, name, bitstring) {#fn, bitstring},
  111. #include "dynarmic/frontend/A32/decoder/arm.inc"
  112. #include "dynarmic/frontend/A32/decoder/asimd.inc"
  113. #include "dynarmic/frontend/A32/decoder/vfp.inc"
  114. #undef INST
  115. };
  116. std::vector<InstructionGenerator> generators;
  117. std::vector<InstructionGenerator> invalid;
  118. // List of instructions not to test
  119. static constexpr std::array do_not_test{
  120. // Translating load/stores
  121. "arm_LDRBT", "arm_LDRBT", "arm_LDRHT", "arm_LDRHT", "arm_LDRSBT", "arm_LDRSBT", "arm_LDRSHT", "arm_LDRSHT", "arm_LDRT", "arm_LDRT",
  122. "arm_STRBT", "arm_STRBT", "arm_STRHT", "arm_STRHT", "arm_STRT", "arm_STRT",
  123. // Exclusive load/stores
  124. "arm_LDREXB", "arm_LDREXD", "arm_LDREXH", "arm_LDREX", "arm_LDAEXB", "arm_LDAEXD", "arm_LDAEXH", "arm_LDAEX",
  125. "arm_STREXB", "arm_STREXD", "arm_STREXH", "arm_STREX", "arm_STLEXB", "arm_STLEXD", "arm_STLEXH", "arm_STLEX",
  126. "arm_SWP", "arm_SWPB",
  127. // Elevated load/store multiple instructions.
  128. "arm_LDM_eret", "arm_LDM_usr",
  129. "arm_STM_usr",
  130. // Hint instructions
  131. "arm_NOP", "arm_PLD_imm", "arm_PLD_reg", "arm_SEV",
  132. "arm_WFE", "arm_WFI", "arm_YIELD",
  133. // E, T, J
  134. "arm_BLX_reg", "arm_BLX_imm", "arm_BXJ", "arm_SETEND",
  135. // Coprocessor
  136. "arm_CDP", "arm_LDC", "arm_MCR", "arm_MCRR", "arm_MRC", "arm_MRRC", "arm_STC",
  137. // System
  138. "arm_CPS", "arm_RFE", "arm_SRS",
  139. // Undefined
  140. "arm_UDF",
  141. // FPSCR is inaccurate
  142. "vfp_VMRS",
  143. // Incorrect Unicorn implementations
  144. "asimd_VRECPS", // Unicorn does not fuse the multiply and subtraction, resulting in being off by 1ULP.
  145. "asimd_VRSQRTS", // Unicorn does not fuse the multiply and subtraction, resulting in being off by 1ULP.
  146. "vfp_VCVT_from_fixed", // Unicorn does not do round-to-nearest-even for this instruction correctly.
  147. };
  148. for (const auto& [fn, bitstring] : list) {
  149. if (std::find(do_not_test.begin(), do_not_test.end(), fn) != do_not_test.end()) {
  150. invalid.emplace_back(InstructionGenerator{bitstring});
  151. continue;
  152. }
  153. generators.emplace_back(InstructionGenerator{bitstring});
  154. }
  155. return InstructionGeneratorInfo{generators, invalid};
  156. }();
  157. while (true) {
  158. const size_t index = RandInt<size_t>(0, instructions.generators.size() - 1);
  159. const u32 inst = instructions.generators[index].Generate();
  160. if ((instructions.generators[index].Mask() & 0xF0000000) == 0 && (inst & 0xF0000000) == 0xF0000000) {
  161. continue;
  162. }
  163. if (ShouldTestInst(inst, pc, false, is_last_inst)) {
  164. return inst;
  165. }
  166. }
  167. }
  168. std::vector<u16> GenRandomThumbInst(u32 pc, bool is_last_inst, A32::ITState it_state = {}) {
  169. static const struct InstructionGeneratorInfo {
  170. std::vector<InstructionGenerator> generators;
  171. std::vector<InstructionGenerator> invalid;
  172. } instructions = [] {
  173. const std::vector<std::tuple<std::string, const char*>> list{
  174. #define INST(fn, name, bitstring) {#fn, bitstring},
  175. #include "dynarmic/frontend/A32/decoder/thumb16.inc"
  176. #include "dynarmic/frontend/A32/decoder/thumb32.inc"
  177. #undef INST
  178. };
  179. const std::vector<std::tuple<std::string, const char*>> vfp_list{
  180. #define INST(fn, name, bitstring) {#fn, bitstring},
  181. #include "dynarmic/frontend/A32/decoder/vfp.inc"
  182. #undef INST
  183. };
  184. const std::vector<std::tuple<std::string, const char*>> asimd_list{
  185. #define INST(fn, name, bitstring) {#fn, bitstring},
  186. #include "dynarmic/frontend/A32/decoder/asimd.inc"
  187. #undef INST
  188. };
  189. std::vector<InstructionGenerator> generators;
  190. std::vector<InstructionGenerator> invalid;
  191. // List of instructions not to test
  192. static constexpr std::array do_not_test{
  193. "thumb16_BKPT",
  194. "thumb16_IT",
  195. "thumb16_SETEND",
  196. // Exclusive load/stores
  197. "thumb32_LDREX",
  198. "thumb32_LDREXB",
  199. "thumb32_LDREXD",
  200. "thumb32_LDREXH",
  201. "thumb32_STREX",
  202. "thumb32_STREXB",
  203. "thumb32_STREXD",
  204. "thumb32_STREXH",
  205. // FPSCR is inaccurate
  206. "vfp_VMRS",
  207. // Unicorn is incorrect?
  208. "thumb32_MRS_reg",
  209. "thumb32_MSR_reg",
  210. // Unicorn has incorrect implementation (incorrect rounding and unsets CPSR.T??)
  211. "vfp_VCVT_to_fixed",
  212. "vfp_VCVT_from_fixed",
  213. "asimd_VRECPS", // Unicorn does not fuse the multiply and subtraction, resulting in being off by 1ULP.
  214. "asimd_VRSQRTS", // Unicorn does not fuse the multiply and subtraction, resulting in being off by 1ULP.
  215. // Coprocessor
  216. "thumb32_CDP",
  217. "thumb32_LDC",
  218. "thumb32_MCR",
  219. "thumb32_MCRR",
  220. "thumb32_MRC",
  221. "thumb32_MRRC",
  222. "thumb32_STC",
  223. };
  224. for (const auto& [fn, bitstring] : list) {
  225. if (std::find(do_not_test.begin(), do_not_test.end(), fn) != do_not_test.end()) {
  226. invalid.emplace_back(InstructionGenerator{bitstring});
  227. continue;
  228. }
  229. generators.emplace_back(InstructionGenerator{bitstring});
  230. }
  231. for (const auto& [fn, bs] : vfp_list) {
  232. std::string bitstring = bs;
  233. if (bitstring.substr(0, 4) == "cccc" || bitstring.substr(0, 4) == "----") {
  234. bitstring.replace(0, 4, "1110");
  235. }
  236. if (std::find(do_not_test.begin(), do_not_test.end(), fn) != do_not_test.end()) {
  237. invalid.emplace_back(InstructionGenerator{bitstring.c_str()});
  238. continue;
  239. }
  240. generators.emplace_back(InstructionGenerator{bitstring.c_str()});
  241. }
  242. for (const auto& [fn, bs] : asimd_list) {
  243. std::string bitstring = bs;
  244. if (bitstring.substr(0, 7) == "1111001") {
  245. const char U = bitstring[7];
  246. bitstring.replace(0, 8, "111-1111");
  247. bitstring[3] = U;
  248. } else if (bitstring.substr(0, 8) == "11110100") {
  249. bitstring.replace(0, 8, "11111001");
  250. } else {
  251. ASSERT_FALSE("Unhandled ASIMD instruction: {} {}", fn, bs);
  252. }
  253. if (std::find(do_not_test.begin(), do_not_test.end(), fn) != do_not_test.end()) {
  254. invalid.emplace_back(InstructionGenerator{bitstring.c_str()});
  255. continue;
  256. }
  257. generators.emplace_back(InstructionGenerator{bitstring.c_str()});
  258. }
  259. return InstructionGeneratorInfo{generators, invalid};
  260. }();
  261. while (true) {
  262. const size_t index = RandInt<size_t>(0, instructions.generators.size() - 1);
  263. const u32 inst = instructions.generators[index].Generate();
  264. const bool is_four_bytes = (inst >> 16) != 0;
  265. if (ShouldTestInst(is_four_bytes ? mcl::bit::swap_halves_32(inst) : inst, pc, true, is_last_inst, it_state)) {
  266. if (is_four_bytes)
  267. return {static_cast<u16>(inst >> 16), static_cast<u16>(inst)};
  268. return {static_cast<u16>(inst)};
  269. }
  270. }
  271. }
  272. template<typename TestEnv>
  273. Dynarmic::A32::UserConfig GetUserConfig(TestEnv& testenv) {
  274. Dynarmic::A32::UserConfig user_config;
  275. user_config.optimizations &= ~OptimizationFlag::FastDispatch;
  276. user_config.callbacks = &testenv;
  277. user_config.always_little_endian = true;
  278. return user_config;
  279. }
  280. template<typename TestEnv>
  281. static void RunTestInstance(Dynarmic::A32::Jit& jit,
  282. A32Unicorn<TestEnv>& uni,
  283. TestEnv& jit_env,
  284. TestEnv& uni_env,
  285. const typename A32Unicorn<TestEnv>::RegisterArray& regs,
  286. const typename A32Unicorn<TestEnv>::ExtRegArray& vecs,
  287. const std::vector<typename TestEnv::InstructionType>& instructions,
  288. const u32 cpsr,
  289. const u32 fpscr,
  290. const size_t ticks_left) {
  291. const u32 initial_pc = regs[15];
  292. const u32 num_words = initial_pc / sizeof(typename TestEnv::InstructionType);
  293. const u32 code_mem_size = num_words + static_cast<u32>(instructions.size());
  294. const u32 expected_end_pc = code_mem_size * sizeof(typename TestEnv::InstructionType);
  295. jit_env.code_mem.resize(code_mem_size);
  296. uni_env.code_mem.resize(code_mem_size);
  297. std::fill(jit_env.code_mem.begin(), jit_env.code_mem.end(), TestEnv::infinite_loop);
  298. std::fill(uni_env.code_mem.begin(), uni_env.code_mem.end(), TestEnv::infinite_loop);
  299. std::copy(instructions.begin(), instructions.end(), jit_env.code_mem.begin() + num_words);
  300. std::copy(instructions.begin(), instructions.end(), uni_env.code_mem.begin() + num_words);
  301. jit_env.PadCodeMem();
  302. uni_env.PadCodeMem();
  303. jit_env.modified_memory.clear();
  304. uni_env.modified_memory.clear();
  305. jit_env.interrupts.clear();
  306. uni_env.interrupts.clear();
  307. jit.Regs() = regs;
  308. jit.ExtRegs() = vecs;
  309. jit.SetFpscr(fpscr);
  310. jit.SetCpsr(cpsr);
  311. jit.ClearCache();
  312. uni.SetRegisters(regs);
  313. uni.SetExtRegs(vecs);
  314. uni.SetFpscr(fpscr);
  315. uni.EnableFloatingPointAccess();
  316. uni.SetCpsr(cpsr);
  317. uni.ClearPageCache();
  318. jit_env.ticks_left = ticks_left;
  319. jit.Run();
  320. uni_env.ticks_left = instructions.size(); // Unicorn counts thumb instructions weirdly.
  321. uni.Run();
  322. SCOPE_FAIL {
  323. fmt::print("Instruction Listing:\n");
  324. fmt::print("{}\n", Common::DisassembleAArch32(std::is_same_v<TestEnv, ThumbTestEnv>, initial_pc, (const u8*)instructions.data(), instructions.size() * sizeof(instructions[0])));
  325. fmt::print("Initial register listing:\n");
  326. for (size_t i = 0; i < regs.size(); ++i) {
  327. fmt::print("{:3s}: {:08x}\n", static_cast<A32::Reg>(i), regs[i]);
  328. }
  329. for (size_t i = 0; i < vecs.size(); ++i) {
  330. fmt::print("{:3s}: {:08x}\n", static_cast<A32::ExtReg>(i), vecs[i]);
  331. }
  332. fmt::print("cpsr {:08x}\n", cpsr);
  333. fmt::print("fpcr {:08x}\n", fpscr);
  334. fmt::print("fpcr.AHP {}\n", FP::FPCR{fpscr}.AHP());
  335. fmt::print("fpcr.DN {}\n", FP::FPCR{fpscr}.DN());
  336. fmt::print("fpcr.FZ {}\n", FP::FPCR{fpscr}.FZ());
  337. fmt::print("fpcr.RMode {}\n", static_cast<size_t>(FP::FPCR{fpscr}.RMode()));
  338. fmt::print("fpcr.FZ16 {}\n", FP::FPCR{fpscr}.FZ16());
  339. fmt::print("\n");
  340. fmt::print("Final register listing:\n");
  341. fmt::print(" unicorn dynarmic\n");
  342. const auto uni_regs = uni.GetRegisters();
  343. for (size_t i = 0; i < regs.size(); ++i) {
  344. fmt::print("{:3s}: {:08x} {:08x} {}\n", static_cast<A32::Reg>(i), uni_regs[i], jit.Regs()[i], uni_regs[i] != jit.Regs()[i] ? "*" : "");
  345. }
  346. const auto uni_ext_regs = uni.GetExtRegs();
  347. for (size_t i = 0; i < vecs.size(); ++i) {
  348. fmt::print("s{:2d}: {:08x} {:08x} {}\n", static_cast<size_t>(i), uni_ext_regs[i], jit.ExtRegs()[i], uni_ext_regs[i] != jit.ExtRegs()[i] ? "*" : "");
  349. }
  350. fmt::print("cpsr {:08x} {:08x} {}\n", uni.GetCpsr(), jit.Cpsr(), uni.GetCpsr() != jit.Cpsr() ? "*" : "");
  351. fmt::print("fpsr {:08x} {:08x} {}\n", uni.GetFpscr(), jit.Fpscr(), (uni.GetFpscr() & 0xF0000000) != (jit.Fpscr() & 0xF0000000) ? "*" : "");
  352. fmt::print("\n");
  353. fmt::print("Modified memory:\n");
  354. fmt::print(" uni dyn\n");
  355. auto uni_iter = uni_env.modified_memory.begin();
  356. auto jit_iter = jit_env.modified_memory.begin();
  357. while (uni_iter != uni_env.modified_memory.end() || jit_iter != jit_env.modified_memory.end()) {
  358. if (uni_iter == uni_env.modified_memory.end() || (jit_iter != jit_env.modified_memory.end() && uni_iter->first > jit_iter->first)) {
  359. fmt::print("{:08x}: {:02x} *\n", jit_iter->first, jit_iter->second);
  360. jit_iter++;
  361. } else if (jit_iter == jit_env.modified_memory.end() || jit_iter->first > uni_iter->first) {
  362. fmt::print("{:08x}: {:02x} *\n", uni_iter->first, uni_iter->second);
  363. uni_iter++;
  364. } else if (uni_iter->first == jit_iter->first) {
  365. fmt::print("{:08x}: {:02x} {:02x} {}\n", uni_iter->first, uni_iter->second, jit_iter->second, uni_iter->second != jit_iter->second ? "*" : "");
  366. uni_iter++;
  367. jit_iter++;
  368. }
  369. }
  370. fmt::print("\n");
  371. fmt::print("x86_64:\n");
  372. jit.DumpDisassembly();
  373. fmt::print("Interrupts:\n");
  374. for (const auto& i : uni_env.interrupts) {
  375. std::puts(i.c_str());
  376. }
  377. };
  378. REQUIRE(uni_env.code_mem_modified_by_guest == jit_env.code_mem_modified_by_guest);
  379. if (uni_env.code_mem_modified_by_guest) {
  380. return;
  381. }
  382. // Qemu doesn't do Thumb transitions??
  383. {
  384. const u32 uni_pc = uni.GetPC();
  385. const bool is_thumb = (jit.Cpsr() & (1 << 5)) != 0;
  386. const u32 new_uni_pc = uni_pc & (is_thumb ? 0xFFFFFFFE : 0xFFFFFFFC);
  387. uni.SetPC(new_uni_pc);
  388. }
  389. if (uni.GetRegisters()[15] > jit.Regs()[15]) {
  390. int trials = 0;
  391. while (jit.Regs()[15] >= initial_pc && jit.Regs()[15] < expected_end_pc && trials++ < 100 && uni.GetRegisters()[15] != jit.Regs()[15]) {
  392. fmt::print("Warning: Possible unicorn overrrun, attempt recovery\n");
  393. jit.Step();
  394. }
  395. }
  396. REQUIRE(uni.GetRegisters() == jit.Regs());
  397. REQUIRE(uni.GetExtRegs() == jit.ExtRegs());
  398. REQUIRE((uni.GetCpsr() & 0xFFFFFDDF) == (jit.Cpsr() & 0xFFFFFDDF));
  399. REQUIRE((uni.GetFpscr() & 0xF8000000) == (jit.Fpscr() & 0xF8000000));
  400. REQUIRE(uni_env.modified_memory == jit_env.modified_memory);
  401. REQUIRE(uni_env.interrupts.empty());
  402. }
  403. } // Anonymous namespace
  404. TEST_CASE("A32: Single random arm instruction", "[arm]") {
  405. ArmTestEnv jit_env{};
  406. ArmTestEnv uni_env{};
  407. Dynarmic::A32::Jit jit{GetUserConfig(jit_env)};
  408. A32Unicorn<ArmTestEnv> uni{uni_env};
  409. A32Unicorn<ArmTestEnv>::RegisterArray regs;
  410. A32Unicorn<ArmTestEnv>::ExtRegArray ext_reg;
  411. std::vector<u32> instructions(1);
  412. for (size_t iteration = 0; iteration < 100000; ++iteration) {
  413. std::generate(regs.begin(), regs.end(), [] { return RandInt<u32>(0, ~u32(0)); });
  414. std::generate(ext_reg.begin(), ext_reg.end(), [] { return RandInt<u32>(0, ~u32(0)); });
  415. const u32 start_address = 100;
  416. const u32 cpsr = (RandInt<u32>(0, 0xF) << 28) | 0x10;
  417. const u32 fpcr = RandomFpcr();
  418. instructions[0] = GenRandomArmInst(start_address, true);
  419. INFO("Instruction: 0x" << std::hex << instructions[0]);
  420. regs[15] = start_address;
  421. RunTestInstance(jit, uni, jit_env, uni_env, regs, ext_reg, instructions, cpsr, fpcr, 1);
  422. }
  423. }
  424. TEST_CASE("A32: Small random arm block", "[arm]") {
  425. ArmTestEnv jit_env{};
  426. ArmTestEnv uni_env{};
  427. Dynarmic::A32::Jit jit{GetUserConfig(jit_env)};
  428. A32Unicorn<ArmTestEnv> uni{uni_env};
  429. A32Unicorn<ArmTestEnv>::RegisterArray regs;
  430. A32Unicorn<ArmTestEnv>::ExtRegArray ext_reg;
  431. std::vector<u32> instructions(5);
  432. for (size_t iteration = 0; iteration < 100000; ++iteration) {
  433. std::generate(regs.begin(), regs.end(), [] { return RandInt<u32>(0, ~u32(0)); });
  434. std::generate(ext_reg.begin(), ext_reg.end(), [] { return RandInt<u32>(0, ~u32(0)); });
  435. const u32 start_address = 100;
  436. const u32 cpsr = (RandInt<u32>(0, 0xF) << 28) | 0x10;
  437. const u32 fpcr = RandomFpcr();
  438. instructions[0] = GenRandomArmInst(start_address + 0, false);
  439. instructions[1] = GenRandomArmInst(start_address + 4, false);
  440. instructions[2] = GenRandomArmInst(start_address + 8, false);
  441. instructions[3] = GenRandomArmInst(start_address + 12, false);
  442. instructions[4] = GenRandomArmInst(start_address + 16, true);
  443. INFO("Instruction 1: 0x" << std::hex << instructions[0]);
  444. INFO("Instruction 2: 0x" << std::hex << instructions[1]);
  445. INFO("Instruction 3: 0x" << std::hex << instructions[2]);
  446. INFO("Instruction 4: 0x" << std::hex << instructions[3]);
  447. INFO("Instruction 5: 0x" << std::hex << instructions[4]);
  448. regs[15] = start_address;
  449. RunTestInstance(jit, uni, jit_env, uni_env, regs, ext_reg, instructions, cpsr, fpcr, 5);
  450. }
  451. }
  452. TEST_CASE("A32: Large random arm block", "[arm]") {
  453. ArmTestEnv jit_env{};
  454. ArmTestEnv uni_env{};
  455. Dynarmic::A32::Jit jit{GetUserConfig(jit_env)};
  456. A32Unicorn<ArmTestEnv> uni{uni_env};
  457. A32Unicorn<ArmTestEnv>::RegisterArray regs;
  458. A32Unicorn<ArmTestEnv>::ExtRegArray ext_reg;
  459. constexpr size_t instruction_count = 100;
  460. std::vector<u32> instructions(instruction_count);
  461. for (size_t iteration = 0; iteration < 10000; ++iteration) {
  462. std::generate(regs.begin(), regs.end(), [] { return RandInt<u32>(0, ~u32(0)); });
  463. std::generate(ext_reg.begin(), ext_reg.end(), [] { return RandInt<u32>(0, ~u32(0)); });
  464. const u64 start_address = 100;
  465. const u32 cpsr = (RandInt<u32>(0, 0xF) << 28) | 0x10;
  466. const u32 fpcr = RandomFpcr();
  467. for (size_t j = 0; j < instruction_count; ++j) {
  468. instructions[j] = GenRandomArmInst(start_address + j * 4, j == instruction_count - 1);
  469. }
  470. regs[15] = start_address;
  471. RunTestInstance(jit, uni, jit_env, uni_env, regs, ext_reg, instructions, cpsr, fpcr, 100);
  472. }
  473. }
  474. TEST_CASE("A32: Single random thumb instruction", "[thumb]") {
  475. ThumbTestEnv jit_env{};
  476. ThumbTestEnv uni_env{};
  477. Dynarmic::A32::Jit jit{GetUserConfig(jit_env)};
  478. A32Unicorn<ThumbTestEnv> uni{uni_env};
  479. A32Unicorn<ThumbTestEnv>::RegisterArray regs;
  480. A32Unicorn<ThumbTestEnv>::ExtRegArray ext_reg;
  481. std::vector<u16> instructions;
  482. for (size_t iteration = 0; iteration < 100000; ++iteration) {
  483. std::generate(regs.begin(), regs.end(), [] { return RandInt<u32>(0, ~u32(0)); });
  484. std::generate(ext_reg.begin(), ext_reg.end(), [] { return RandInt<u32>(0, ~u32(0)); });
  485. const u32 start_address = 100;
  486. const u32 cpsr = (RandInt<u32>(0, 0xF) << 28) | 0x1F0;
  487. const u32 fpcr = RandomFpcr();
  488. instructions = GenRandomThumbInst(start_address, true);
  489. INFO("Instruction: 0x" << std::hex << instructions[0]);
  490. regs[15] = start_address;
  491. RunTestInstance(jit, uni, jit_env, uni_env, regs, ext_reg, instructions, cpsr, fpcr, 1);
  492. }
  493. }
  494. TEST_CASE("A32: Single random thumb instruction (offset)", "[thumb]") {
  495. ThumbTestEnv jit_env{};
  496. ThumbTestEnv uni_env{};
  497. Dynarmic::A32::Jit jit{GetUserConfig(jit_env)};
  498. A32Unicorn<ThumbTestEnv> uni{uni_env};
  499. A32Unicorn<ThumbTestEnv>::RegisterArray regs;
  500. A32Unicorn<ThumbTestEnv>::ExtRegArray ext_reg;
  501. std::vector<u16> instructions;
  502. for (size_t iteration = 0; iteration < 100000; ++iteration) {
  503. std::generate(regs.begin(), regs.end(), [] { return RandInt<u32>(0, ~u32(0)); });
  504. std::generate(ext_reg.begin(), ext_reg.end(), [] { return RandInt<u32>(0, ~u32(0)); });
  505. const u32 start_address = 100;
  506. const u32 cpsr = (RandInt<u32>(0, 0xF) << 28) | 0x1F0;
  507. const u32 fpcr = RandomFpcr();
  508. instructions.clear();
  509. instructions.push_back(0xbf00); // NOP
  510. const std::vector<u16> inst = GenRandomThumbInst(start_address + 2, true);
  511. instructions.insert(instructions.end(), inst.begin(), inst.end());
  512. INFO("Instruction: 0x" << std::hex << inst[0]);
  513. regs[15] = start_address;
  514. RunTestInstance(jit, uni, jit_env, uni_env, regs, ext_reg, instructions, cpsr, fpcr, 2);
  515. }
  516. }
  517. TEST_CASE("A32: Small random thumb block", "[thumb]") {
  518. ThumbTestEnv jit_env{};
  519. ThumbTestEnv uni_env{};
  520. Dynarmic::A32::Jit jit{GetUserConfig(jit_env)};
  521. A32Unicorn<ThumbTestEnv> uni{uni_env};
  522. A32Unicorn<ThumbTestEnv>::RegisterArray regs;
  523. A32Unicorn<ThumbTestEnv>::ExtRegArray ext_reg;
  524. std::vector<u16> instructions;
  525. for (size_t iteration = 0; iteration < 100000; ++iteration) {
  526. std::generate(regs.begin(), regs.end(), [] { return RandInt<u32>(0, ~u32(0)); });
  527. std::generate(ext_reg.begin(), ext_reg.end(), [] { return RandInt<u32>(0, ~u32(0)); });
  528. const u32 start_address = 100;
  529. const u32 cpsr = (RandInt<u32>(0, 0xF) << 28) | 0x1F0;
  530. const u32 fpcr = RandomFpcr();
  531. instructions.clear();
  532. for (size_t i = 0; i < 5; i++) {
  533. const std::vector<u16> inst = GenRandomThumbInst(start_address + instructions.size() * 2, i == 4);
  534. instructions.insert(instructions.end(), inst.begin(), inst.end());
  535. }
  536. regs[15] = start_address;
  537. RunTestInstance(jit, uni, jit_env, uni_env, regs, ext_reg, instructions, cpsr, fpcr, 5);
  538. }
  539. }
  540. TEST_CASE("A32: Test thumb IT instruction", "[thumb]") {
  541. ThumbTestEnv jit_env{};
  542. ThumbTestEnv uni_env{};
  543. Dynarmic::A32::Jit jit{GetUserConfig(jit_env)};
  544. A32Unicorn<ThumbTestEnv> uni{uni_env};
  545. A32Unicorn<ThumbTestEnv>::RegisterArray regs;
  546. A32Unicorn<ThumbTestEnv>::ExtRegArray ext_reg;
  547. std::vector<u16> instructions;
  548. for (size_t iteration = 0; iteration < 100000; ++iteration) {
  549. std::generate(regs.begin(), regs.end(), [] { return RandInt<u32>(0, ~u32(0)); });
  550. std::generate(ext_reg.begin(), ext_reg.end(), [] { return RandInt<u32>(0, ~u32(0)); });
  551. const size_t pre_instructions = RandInt<size_t>(0, 3);
  552. const size_t post_instructions = RandInt<size_t>(5, 8);
  553. const u32 start_address = 100;
  554. const u32 cpsr = (RandInt<u32>(0, 0xF) << 28) | 0x1F0;
  555. const u32 fpcr = RandomFpcr();
  556. instructions.clear();
  557. for (size_t i = 0; i < pre_instructions; i++) {
  558. const std::vector<u16> inst = GenRandomThumbInst(start_address + instructions.size() * 2, false);
  559. instructions.insert(instructions.end(), inst.begin(), inst.end());
  560. }
  561. // Emit IT instruction
  562. A32::ITState it_state = [&] {
  563. while (true) {
  564. const u16 imm8 = RandInt<u16>(0, 0xFF);
  565. if (mcl::bit::get_bits<0, 3>(imm8) == 0b0000 || mcl::bit::get_bits<4, 7>(imm8) == 0b1111 || (mcl::bit::get_bits<4, 7>(imm8) == 0b1110 && mcl::bit::count_ones(mcl::bit::get_bits<0, 3>(imm8)) != 1)) {
  566. continue;
  567. }
  568. instructions.push_back(0b1011111100000000 | imm8);
  569. return A32::ITState{static_cast<u8>(imm8)};
  570. }
  571. }();
  572. for (size_t i = 0; i < post_instructions; i++) {
  573. const std::vector<u16> inst = GenRandomThumbInst(start_address + instructions.size() * 2, i == post_instructions - 1, it_state);
  574. instructions.insert(instructions.end(), inst.begin(), inst.end());
  575. it_state = it_state.Advance();
  576. }
  577. regs[15] = start_address;
  578. RunTestInstance(jit, uni, jit_env, uni_env, regs, ext_reg, instructions, cpsr, fpcr, pre_instructions + 1 + post_instructions);
  579. }
  580. }