test_generator.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  1. /* This file is part of the dynarmic project.
  2. * Copyright (c) 2022 MerryMage
  3. * SPDX-License-Identifier: 0BSD
  4. */
  5. #include <algorithm>
  6. #include <array>
  7. #include <cstdio>
  8. #include <cstdlib>
  9. #include <functional>
  10. #include <limits>
  11. #include <optional>
  12. #include <tuple>
  13. #include <vector>
  14. #include <mcl/bit/swap.hpp>
  15. #include <mcl/macro/architecture.hpp>
  16. #include <mcl/stdint.hpp>
  17. #include "./A32/testenv.h"
  18. #include "./A64/testenv.h"
  19. #include "./fuzz_util.h"
  20. #include "./rand_int.h"
  21. #include "dynarmic/common/fp/fpcr.h"
  22. #include "dynarmic/common/fp/fpsr.h"
  23. #include "dynarmic/frontend/A32/ITState.h"
  24. #include "dynarmic/frontend/A32/a32_location_descriptor.h"
  25. #include "dynarmic/frontend/A32/a32_types.h"
  26. #include "dynarmic/frontend/A32/translate/a32_translate.h"
  27. #include "dynarmic/frontend/A64/a64_location_descriptor.h"
  28. #include "dynarmic/frontend/A64/a64_types.h"
  29. #include "dynarmic/frontend/A64/translate/a64_translate.h"
  30. #include "dynarmic/interface/A32/a32.h"
  31. #include "dynarmic/interface/A64/a64.h"
  32. #include "dynarmic/ir/basic_block.h"
  33. #include "dynarmic/ir/location_descriptor.h"
  34. #include "dynarmic/ir/opcodes.h"
  35. // Must be declared last for all necessary operator<< to be declared prior to this.
  36. #include <fmt/format.h>
  37. #include <fmt/ostream.h>
  38. constexpr bool mask_fpsr_cum_bits = true;
  39. namespace {
  40. using namespace Dynarmic;
  41. bool ShouldTestInst(IR::Block& block) {
  42. if (auto terminal = block.GetTerminal(); boost::get<IR::Term::Interpret>(&terminal)) {
  43. return false;
  44. }
  45. for (const auto& ir_inst : block) {
  46. switch (ir_inst.GetOpcode()) {
  47. // A32
  48. case IR::Opcode::A32GetFpscr:
  49. case IR::Opcode::A32ExceptionRaised:
  50. case IR::Opcode::A32CallSupervisor:
  51. case IR::Opcode::A32CoprocInternalOperation:
  52. case IR::Opcode::A32CoprocSendOneWord:
  53. case IR::Opcode::A32CoprocSendTwoWords:
  54. case IR::Opcode::A32CoprocGetOneWord:
  55. case IR::Opcode::A32CoprocGetTwoWords:
  56. case IR::Opcode::A32CoprocLoadWords:
  57. case IR::Opcode::A32CoprocStoreWords:
  58. // A64
  59. case IR::Opcode::A64ExceptionRaised:
  60. case IR::Opcode::A64CallSupervisor:
  61. case IR::Opcode::A64DataCacheOperationRaised:
  62. case IR::Opcode::A64GetCNTPCT:
  63. // Unimplemented
  64. case IR::Opcode::SignedSaturatedAdd8:
  65. case IR::Opcode::SignedSaturatedAdd16:
  66. case IR::Opcode::SignedSaturatedAdd32:
  67. case IR::Opcode::SignedSaturatedAdd64:
  68. case IR::Opcode::SignedSaturatedDoublingMultiplyReturnHigh16:
  69. case IR::Opcode::SignedSaturatedDoublingMultiplyReturnHigh32:
  70. case IR::Opcode::SignedSaturatedSub8:
  71. case IR::Opcode::SignedSaturatedSub16:
  72. case IR::Opcode::SignedSaturatedSub32:
  73. case IR::Opcode::SignedSaturatedSub64:
  74. case IR::Opcode::UnsignedSaturatedAdd8:
  75. case IR::Opcode::UnsignedSaturatedAdd16:
  76. case IR::Opcode::UnsignedSaturatedAdd32:
  77. case IR::Opcode::UnsignedSaturatedAdd64:
  78. case IR::Opcode::UnsignedSaturatedSub8:
  79. case IR::Opcode::UnsignedSaturatedSub16:
  80. case IR::Opcode::UnsignedSaturatedSub32:
  81. case IR::Opcode::UnsignedSaturatedSub64:
  82. case IR::Opcode::VectorMaxS64:
  83. case IR::Opcode::VectorMaxU64:
  84. case IR::Opcode::VectorMinS64:
  85. case IR::Opcode::VectorMinU64:
  86. case IR::Opcode::VectorMultiply64:
  87. case IR::Opcode::SM4AccessSubstitutionBox:
  88. // Half-prec conversions
  89. case IR::Opcode::FPHalfToFixedS16:
  90. case IR::Opcode::FPHalfToFixedS32:
  91. case IR::Opcode::FPHalfToFixedS64:
  92. case IR::Opcode::FPHalfToFixedU16:
  93. case IR::Opcode::FPHalfToFixedU32:
  94. case IR::Opcode::FPHalfToFixedU64:
  95. // Half-precision
  96. case IR::Opcode::FPAbs16:
  97. case IR::Opcode::FPMulAdd16:
  98. case IR::Opcode::FPMulSub16:
  99. case IR::Opcode::FPNeg16:
  100. case IR::Opcode::FPRecipEstimate16:
  101. case IR::Opcode::FPRecipExponent16:
  102. case IR::Opcode::FPRecipStepFused16:
  103. case IR::Opcode::FPRoundInt16:
  104. case IR::Opcode::FPRSqrtEstimate16:
  105. case IR::Opcode::FPRSqrtStepFused16:
  106. case IR::Opcode::FPVectorAbs16:
  107. case IR::Opcode::FPVectorEqual16:
  108. case IR::Opcode::FPVectorMulAdd16:
  109. case IR::Opcode::FPVectorNeg16:
  110. case IR::Opcode::FPVectorRecipEstimate16:
  111. case IR::Opcode::FPVectorRecipStepFused16:
  112. case IR::Opcode::FPVectorRoundInt16:
  113. case IR::Opcode::FPVectorRSqrtEstimate16:
  114. case IR::Opcode::FPVectorRSqrtStepFused16:
  115. case IR::Opcode::FPVectorToSignedFixed16:
  116. case IR::Opcode::FPVectorToUnsignedFixed16:
  117. case IR::Opcode::FPVectorFromHalf32:
  118. case IR::Opcode::FPVectorToHalf32:
  119. return false;
  120. default:
  121. continue;
  122. }
  123. }
  124. return true;
  125. }
  126. bool ShouldTestA32Inst(u32 instruction, u32 pc, bool is_thumb, bool is_last_inst, A32::ITState it_state = {}) {
  127. const A32::LocationDescriptor location = A32::LocationDescriptor{pc, {}, {}}.SetTFlag(is_thumb).SetIT(it_state);
  128. IR::Block block{location};
  129. const bool should_continue = A32::TranslateSingleInstruction(block, location, instruction);
  130. if (!should_continue && !is_last_inst) {
  131. return false;
  132. }
  133. return ShouldTestInst(block);
  134. }
  135. bool ShouldTestA64Inst(u32 instruction, u64 pc, bool is_last_inst) {
  136. const A64::LocationDescriptor location = A64::LocationDescriptor{pc, {}};
  137. IR::Block block{location};
  138. const bool should_continue = A64::TranslateSingleInstruction(block, location, instruction);
  139. if (!should_continue && !is_last_inst) {
  140. return false;
  141. }
  142. return ShouldTestInst(block);
  143. }
  144. u32 GenRandomArmInst(u32 pc, bool is_last_inst) {
  145. static const struct InstructionGeneratorInfo {
  146. std::vector<InstructionGenerator> generators;
  147. std::vector<InstructionGenerator> invalid;
  148. } instructions = [] {
  149. const std::vector<std::tuple<std::string, const char*>> list{
  150. #define INST(fn, name, bitstring) {#fn, bitstring},
  151. #include "dynarmic/frontend/A32/decoder/arm.inc"
  152. #include "dynarmic/frontend/A32/decoder/asimd.inc"
  153. #include "dynarmic/frontend/A32/decoder/vfp.inc"
  154. #undef INST
  155. };
  156. std::vector<InstructionGenerator> generators;
  157. std::vector<InstructionGenerator> invalid;
  158. // List of instructions not to test
  159. static constexpr std::array do_not_test{
  160. // Translating load/stores
  161. "arm_LDRBT", "arm_LDRBT", "arm_LDRHT", "arm_LDRHT", "arm_LDRSBT", "arm_LDRSBT", "arm_LDRSHT", "arm_LDRSHT", "arm_LDRT", "arm_LDRT",
  162. "arm_STRBT", "arm_STRBT", "arm_STRHT", "arm_STRHT", "arm_STRT", "arm_STRT",
  163. // Exclusive load/stores
  164. "arm_LDREXB", "arm_LDREXD", "arm_LDREXH", "arm_LDREX", "arm_LDAEXB", "arm_LDAEXD", "arm_LDAEXH", "arm_LDAEX",
  165. "arm_STREXB", "arm_STREXD", "arm_STREXH", "arm_STREX", "arm_STLEXB", "arm_STLEXD", "arm_STLEXH", "arm_STLEX",
  166. "arm_SWP", "arm_SWPB",
  167. // Elevated load/store multiple instructions.
  168. "arm_LDM_eret", "arm_LDM_usr",
  169. "arm_STM_usr",
  170. // Coprocessor
  171. "arm_CDP", "arm_LDC", "arm_MCR", "arm_MCRR", "arm_MRC", "arm_MRRC", "arm_STC",
  172. // System
  173. "arm_CPS", "arm_RFE", "arm_SRS",
  174. // Undefined
  175. "arm_UDF",
  176. // FPSCR is inaccurate
  177. "vfp_VMRS",
  178. // Incorrect Unicorn implementations
  179. "asimd_VRECPS", // Unicorn does not fuse the multiply and subtraction, resulting in being off by 1ULP.
  180. "asimd_VRSQRTS", // Unicorn does not fuse the multiply and subtraction, resulting in being off by 1ULP.
  181. "vfp_VCVT_from_fixed", // Unicorn does not do round-to-nearest-even for this instruction correctly.
  182. };
  183. for (const auto& [fn, bitstring] : list) {
  184. if (std::find(do_not_test.begin(), do_not_test.end(), fn) != do_not_test.end()) {
  185. invalid.emplace_back(InstructionGenerator{bitstring});
  186. continue;
  187. }
  188. generators.emplace_back(InstructionGenerator{bitstring});
  189. }
  190. return InstructionGeneratorInfo{generators, invalid};
  191. }();
  192. while (true) {
  193. const size_t index = RandInt<size_t>(0, instructions.generators.size() - 1);
  194. const u32 inst = instructions.generators[index].Generate();
  195. if ((instructions.generators[index].Mask() & 0xF0000000) == 0 && (inst & 0xF0000000) == 0xF0000000) {
  196. continue;
  197. }
  198. if (ShouldTestA32Inst(inst, pc, false, is_last_inst)) {
  199. return inst;
  200. }
  201. }
  202. }
  203. std::vector<u16> GenRandomThumbInst(u32 pc, bool is_last_inst, A32::ITState it_state = {}) {
  204. static const struct InstructionGeneratorInfo {
  205. std::vector<InstructionGenerator> generators;
  206. std::vector<InstructionGenerator> invalid;
  207. } instructions = [] {
  208. const std::vector<std::tuple<std::string, const char*>> list{
  209. #define INST(fn, name, bitstring) {#fn, bitstring},
  210. #include "dynarmic/frontend/A32/decoder/thumb16.inc"
  211. #include "dynarmic/frontend/A32/decoder/thumb32.inc"
  212. #undef INST
  213. };
  214. const std::vector<std::tuple<std::string, const char*>> vfp_list{
  215. #define INST(fn, name, bitstring) {#fn, bitstring},
  216. #include "dynarmic/frontend/A32/decoder/vfp.inc"
  217. #undef INST
  218. };
  219. const std::vector<std::tuple<std::string, const char*>> asimd_list{
  220. #define INST(fn, name, bitstring) {#fn, bitstring},
  221. #include "dynarmic/frontend/A32/decoder/asimd.inc"
  222. #undef INST
  223. };
  224. std::vector<InstructionGenerator> generators;
  225. std::vector<InstructionGenerator> invalid;
  226. // List of instructions not to test
  227. static constexpr std::array do_not_test{
  228. "thumb16_BKPT",
  229. "thumb16_IT",
  230. // Exclusive load/stores
  231. "thumb32_LDREX",
  232. "thumb32_LDREXB",
  233. "thumb32_LDREXD",
  234. "thumb32_LDREXH",
  235. "thumb32_STREX",
  236. "thumb32_STREXB",
  237. "thumb32_STREXD",
  238. "thumb32_STREXH",
  239. // Coprocessor
  240. "thumb32_CDP",
  241. "thumb32_LDC",
  242. "thumb32_MCR",
  243. "thumb32_MCRR",
  244. "thumb32_MRC",
  245. "thumb32_MRRC",
  246. "thumb32_STC",
  247. };
  248. for (const auto& [fn, bitstring] : list) {
  249. if (std::find(do_not_test.begin(), do_not_test.end(), fn) != do_not_test.end()) {
  250. invalid.emplace_back(InstructionGenerator{bitstring});
  251. continue;
  252. }
  253. generators.emplace_back(InstructionGenerator{bitstring});
  254. }
  255. for (const auto& [fn, bs] : vfp_list) {
  256. std::string bitstring = bs;
  257. if (bitstring.substr(0, 4) == "cccc" || bitstring.substr(0, 4) == "----") {
  258. bitstring.replace(0, 4, "1110");
  259. }
  260. if (std::find(do_not_test.begin(), do_not_test.end(), fn) != do_not_test.end()) {
  261. invalid.emplace_back(InstructionGenerator{bitstring.c_str()});
  262. continue;
  263. }
  264. generators.emplace_back(InstructionGenerator{bitstring.c_str()});
  265. }
  266. for (const auto& [fn, bs] : asimd_list) {
  267. std::string bitstring = bs;
  268. if (bitstring.substr(0, 7) == "1111001") {
  269. const char U = bitstring[7];
  270. bitstring.replace(0, 8, "111-1111");
  271. bitstring[3] = U;
  272. } else if (bitstring.substr(0, 8) == "11110100") {
  273. bitstring.replace(0, 8, "11111001");
  274. } else {
  275. ASSERT_FALSE("Unhandled ASIMD instruction: {} {}", fn, bs);
  276. }
  277. if (std::find(do_not_test.begin(), do_not_test.end(), fn) != do_not_test.end()) {
  278. invalid.emplace_back(InstructionGenerator{bitstring.c_str()});
  279. continue;
  280. }
  281. generators.emplace_back(InstructionGenerator{bitstring.c_str()});
  282. }
  283. return InstructionGeneratorInfo{generators, invalid};
  284. }();
  285. while (true) {
  286. const size_t index = RandInt<size_t>(0, instructions.generators.size() - 1);
  287. const u32 inst = instructions.generators[index].Generate();
  288. const bool is_four_bytes = (inst >> 16) != 0;
  289. if (ShouldTestA32Inst(is_four_bytes ? mcl::bit::swap_halves_32(inst) : inst, pc, true, is_last_inst, it_state)) {
  290. if (is_four_bytes)
  291. return {static_cast<u16>(inst >> 16), static_cast<u16>(inst)};
  292. return {static_cast<u16>(inst)};
  293. }
  294. }
  295. }
  296. u32 GenRandomA64Inst(u64 pc, bool is_last_inst) {
  297. static const struct InstructionGeneratorInfo {
  298. std::vector<InstructionGenerator> generators;
  299. std::vector<InstructionGenerator> invalid;
  300. } instructions = [] {
  301. const std::vector<std::tuple<std::string, const char*>> list{
  302. #define INST(fn, name, bitstring) {#fn, bitstring},
  303. #include "dynarmic/frontend/A64/decoder/a64.inc"
  304. #undef INST
  305. };
  306. std::vector<InstructionGenerator> generators;
  307. std::vector<InstructionGenerator> invalid;
  308. // List of instructions not to test
  309. const std::vector<std::string> do_not_test{
  310. // Dynarmic and QEMU currently differ on how the exclusive monitor's address range works.
  311. "STXR",
  312. "STLXR",
  313. "STXP",
  314. "STLXP",
  315. "LDXR",
  316. "LDAXR",
  317. "LDXP",
  318. "LDAXP",
  319. // Behaviour differs from QEMU
  320. "MSR_reg",
  321. "MSR_imm",
  322. "MRS",
  323. };
  324. for (const auto& [fn, bitstring] : list) {
  325. if (fn == "UnallocatedEncoding") {
  326. continue;
  327. }
  328. if (std::find(do_not_test.begin(), do_not_test.end(), fn) != do_not_test.end()) {
  329. invalid.emplace_back(InstructionGenerator{bitstring});
  330. continue;
  331. }
  332. generators.emplace_back(InstructionGenerator{bitstring});
  333. }
  334. return InstructionGeneratorInfo{generators, invalid};
  335. }();
  336. while (true) {
  337. const size_t index = RandInt<size_t>(0, instructions.generators.size() - 1);
  338. const u32 inst = instructions.generators[index].Generate();
  339. if (std::any_of(instructions.invalid.begin(), instructions.invalid.end(), [inst](const auto& invalid) { return invalid.Match(inst); })) {
  340. continue;
  341. }
  342. if (ShouldTestA64Inst(inst, pc, is_last_inst)) {
  343. return inst;
  344. }
  345. }
  346. }
  347. template<typename TestEnv>
  348. Dynarmic::A32::UserConfig GetA32UserConfig(TestEnv& testenv, bool noopt) {
  349. Dynarmic::A32::UserConfig user_config;
  350. user_config.optimizations &= ~OptimizationFlag::FastDispatch;
  351. user_config.callbacks = &testenv;
  352. if (noopt) {
  353. user_config.optimizations = no_optimizations;
  354. }
  355. return user_config;
  356. }
  357. template<size_t num_jit_reruns = 1, typename TestEnv>
  358. void RunTestInstance(Dynarmic::A32::Jit& jit,
  359. TestEnv& jit_env,
  360. const std::array<u32, 16>& regs,
  361. const std::array<u32, 64>& vecs,
  362. const std::vector<typename TestEnv::InstructionType>& instructions,
  363. const u32 cpsr,
  364. const u32 fpscr,
  365. const size_t ticks_left) {
  366. const u32 initial_pc = regs[15];
  367. const u32 num_words = initial_pc / sizeof(typename TestEnv::InstructionType);
  368. const u32 code_mem_size = num_words + static_cast<u32>(instructions.size());
  369. fmt::print("instructions:");
  370. for (auto instruction : instructions) {
  371. if constexpr (sizeof(decltype(instruction)) == 2) {
  372. fmt::print(" {:04x}", instruction);
  373. } else {
  374. fmt::print(" {:08x}", instruction);
  375. }
  376. }
  377. fmt::print("\n");
  378. fmt::print("initial_regs:");
  379. for (u32 i : regs) {
  380. fmt::print(" {:08x}", i);
  381. }
  382. fmt::print("\n");
  383. fmt::print("initial_vecs:");
  384. for (u32 i : vecs) {
  385. fmt::print(" {:08x}", i);
  386. }
  387. fmt::print("\n");
  388. fmt::print("initial_cpsr: {:08x}\n", cpsr);
  389. fmt::print("initial_fpcr: {:08x}\n", fpscr);
  390. jit.ClearCache();
  391. for (size_t jit_rerun_count = 0; jit_rerun_count < num_jit_reruns; ++jit_rerun_count) {
  392. jit_env.code_mem.resize(code_mem_size);
  393. std::fill(jit_env.code_mem.begin(), jit_env.code_mem.end(), TestEnv::infinite_loop);
  394. std::copy(instructions.begin(), instructions.end(), jit_env.code_mem.begin() + num_words);
  395. jit_env.PadCodeMem();
  396. jit_env.modified_memory.clear();
  397. jit_env.interrupts.clear();
  398. jit.Regs() = regs;
  399. jit.ExtRegs() = vecs;
  400. jit.SetFpscr(fpscr);
  401. jit.SetCpsr(cpsr);
  402. jit_env.ticks_left = ticks_left;
  403. jit.Run();
  404. }
  405. fmt::print("final_regs:");
  406. for (u32 i : jit.Regs()) {
  407. fmt::print(" {:08x}", i);
  408. }
  409. fmt::print("\n");
  410. fmt::print("final_vecs:");
  411. for (u32 i : jit.ExtRegs()) {
  412. fmt::print(" {:08x}", i);
  413. }
  414. fmt::print("\n");
  415. fmt::print("final_cpsr: {:08x}\n", jit.Cpsr());
  416. fmt::print("final_fpsr: {:08x}\n", mask_fpsr_cum_bits ? jit.Fpscr() & 0xffffff00 : jit.Fpscr());
  417. fmt::print("mod_mem: ");
  418. for (auto [addr, value] : jit_env.modified_memory) {
  419. fmt::print("{:08x}:{:02x} ", addr, value);
  420. }
  421. fmt::print("\n");
  422. fmt::print("interrupts:\n");
  423. for (const auto& i : jit_env.interrupts) {
  424. std::puts(i.c_str());
  425. }
  426. fmt::print("===\n");
  427. }
  428. Dynarmic::A64::UserConfig GetA64UserConfig(A64TestEnv& jit_env, bool noopt) {
  429. Dynarmic::A64::UserConfig jit_user_config{&jit_env};
  430. jit_user_config.optimizations &= ~OptimizationFlag::FastDispatch;
  431. // The below corresponds to the settings for qemu's aarch64_max_initfn
  432. jit_user_config.dczid_el0 = 7;
  433. jit_user_config.ctr_el0 = 0x80038003;
  434. if (noopt) {
  435. jit_user_config.optimizations = no_optimizations;
  436. }
  437. return jit_user_config;
  438. }
  439. template<size_t num_jit_reruns = 2>
  440. void RunTestInstance(Dynarmic::A64::Jit& jit,
  441. A64TestEnv& jit_env,
  442. const std::array<u64, 31>& regs,
  443. const std::array<std::array<u64, 2>, 32>& vecs,
  444. const std::vector<u32>& instructions,
  445. const u32 pstate,
  446. const u32 fpcr,
  447. const u64 initial_sp,
  448. const u64 start_address,
  449. const size_t ticks_left) {
  450. jit.ClearCache();
  451. for (size_t jit_rerun_count = 0; jit_rerun_count < num_jit_reruns; ++jit_rerun_count) {
  452. jit_env.code_mem = instructions;
  453. jit_env.code_mem.emplace_back(0x14000000); // B .
  454. jit_env.code_mem_start_address = start_address;
  455. jit_env.modified_memory.clear();
  456. jit_env.interrupts.clear();
  457. jit.SetRegisters(regs);
  458. jit.SetVectors(vecs);
  459. jit.SetPC(start_address);
  460. jit.SetSP(initial_sp);
  461. jit.SetFpcr(fpcr);
  462. jit.SetFpsr(0);
  463. jit.SetPstate(pstate);
  464. jit.ClearCache();
  465. jit_env.ticks_left = ticks_left;
  466. jit.Run();
  467. }
  468. fmt::print("instructions:");
  469. for (u32 instruction : instructions) {
  470. fmt::print(" {:08x}", instruction);
  471. }
  472. fmt::print("\n");
  473. fmt::print("initial_regs:");
  474. for (u64 i : regs) {
  475. fmt::print(" {:016x}", i);
  476. }
  477. fmt::print("\n");
  478. fmt::print("initial_vecs:");
  479. for (auto i : vecs) {
  480. fmt::print(" {:016x}:{:016x}", i[0], i[1]);
  481. }
  482. fmt::print("\n");
  483. fmt::print("initial_sp: {:016x}\n", initial_sp);
  484. fmt::print("initial_pstate: {:08x}\n", pstate);
  485. fmt::print("initial_fpcr: {:08x}\n", fpcr);
  486. fmt::print("final_regs:");
  487. for (u64 i : jit.GetRegisters()) {
  488. fmt::print(" {:016x}", i);
  489. }
  490. fmt::print("\n");
  491. fmt::print("final_vecs:");
  492. for (auto i : jit.GetVectors()) {
  493. fmt::print(" {:016x}:{:016x}", i[0], i[1]);
  494. }
  495. fmt::print("\n");
  496. fmt::print("final_sp: {:016x}\n", jit.GetSP());
  497. fmt::print("final_pc: {:016x}\n", jit.GetPC());
  498. fmt::print("final_pstate: {:08x}\n", jit.GetPstate());
  499. fmt::print("final_fpcr: {:08x}\n", jit.GetFpcr());
  500. fmt::print("final_qc : {}\n", FP::FPSR{jit.GetFpsr()}.QC());
  501. fmt::print("mod_mem:");
  502. for (auto [addr, value] : jit_env.modified_memory) {
  503. fmt::print(" {:08x}:{:02x}", addr, value);
  504. }
  505. fmt::print("\n");
  506. fmt::print("interrupts:\n");
  507. for (const auto& i : jit_env.interrupts) {
  508. std::puts(i.c_str());
  509. }
  510. fmt::print("===\n");
  511. }
  512. } // Anonymous namespace
  513. void TestThumb(size_t num_instructions, size_t num_iterations, bool noopt) {
  514. ThumbTestEnv jit_env{};
  515. Dynarmic::A32::Jit jit{GetA32UserConfig(jit_env, noopt)};
  516. std::array<u32, 16> regs;
  517. std::array<u32, 64> ext_reg;
  518. std::vector<u16> instructions;
  519. for (size_t iteration = 0; iteration < num_iterations; ++iteration) {
  520. std::generate(regs.begin(), regs.end(), [] { return RandInt<u32>(0, ~u32(0)); });
  521. std::generate(ext_reg.begin(), ext_reg.end(), [] { return RandInt<u32>(0, ~u32(0)); });
  522. const u32 start_address = 100;
  523. const u32 cpsr = (RandInt<u32>(0, 0xF) << 28) | 0x1F0;
  524. const u32 fpcr = RandomFpcr();
  525. instructions.clear();
  526. for (size_t i = 0; i < num_instructions; ++i) {
  527. const auto inst = GenRandomThumbInst(static_cast<u32>(start_address + 2 * instructions.size()), i == num_instructions - 1);
  528. instructions.insert(instructions.end(), inst.begin(), inst.end());
  529. }
  530. regs[15] = start_address;
  531. RunTestInstance(jit, jit_env, regs, ext_reg, instructions, cpsr, fpcr, num_instructions);
  532. }
  533. }
  534. void TestArm(size_t num_instructions, size_t num_iterations, bool noopt) {
  535. ArmTestEnv jit_env{};
  536. Dynarmic::A32::Jit jit{GetA32UserConfig(jit_env, noopt)};
  537. std::array<u32, 16> regs;
  538. std::array<u32, 64> ext_reg;
  539. std::vector<u32> instructions;
  540. for (size_t iteration = 0; iteration < num_iterations; ++iteration) {
  541. std::generate(regs.begin(), regs.end(), [] { return RandInt<u32>(0, ~u32(0)); });
  542. std::generate(ext_reg.begin(), ext_reg.end(), [] { return RandInt<u32>(0, ~u32(0)); });
  543. const u32 start_address = 100;
  544. const u32 cpsr = (RandInt<u32>(0, 0xF) << 28);
  545. const u32 fpcr = RandomFpcr();
  546. instructions.clear();
  547. for (size_t i = 0; i < num_instructions; ++i) {
  548. instructions.emplace_back(GenRandomArmInst(static_cast<u32>(start_address + 4 * instructions.size()), i == num_instructions - 1));
  549. }
  550. regs[15] = start_address;
  551. RunTestInstance(jit, jit_env, regs, ext_reg, instructions, cpsr, fpcr, num_instructions);
  552. }
  553. }
  554. void TestA64(size_t num_instructions, size_t num_iterations, bool noopt) {
  555. A64TestEnv jit_env{};
  556. Dynarmic::A64::Jit jit{GetA64UserConfig(jit_env, noopt)};
  557. std::array<u64, 31> regs;
  558. std::array<std::array<u64, 2>, 32> vecs;
  559. std::vector<u32> instructions;
  560. for (size_t iteration = 0; iteration < num_iterations; ++iteration) {
  561. std::generate(regs.begin(), regs.end(), [] { return RandInt<u64>(0, ~u64(0)); });
  562. std::generate(vecs.begin(), vecs.end(), RandomVector);
  563. const u32 start_address = 100;
  564. const u32 pstate = (RandInt<u32>(0, 0xF) << 28);
  565. const u32 fpcr = RandomFpcr();
  566. const u64 initial_sp = RandInt<u64>(0x30'0000'0000, 0x40'0000'0000) * 4;
  567. instructions.clear();
  568. for (size_t i = 0; i < num_instructions; ++i) {
  569. instructions.emplace_back(GenRandomA64Inst(static_cast<u32>(start_address + 4 * instructions.size()), i == num_instructions - 1));
  570. }
  571. RunTestInstance(jit, jit_env, regs, vecs, instructions, pstate, fpcr, initial_sp, start_address, num_instructions);
  572. }
  573. }
  574. static std::optional<size_t> str2sz(char const* s) {
  575. char* end = nullptr;
  576. errno = 0;
  577. const long l = std::strtol(s, &end, 10);
  578. if (errno == ERANGE || l < 0) {
  579. return std::nullopt;
  580. }
  581. if (*s == '\0' || *end != '\0') {
  582. return std::nullopt;
  583. }
  584. return static_cast<size_t>(l);
  585. }
  586. int main(int argc, char* argv[]) {
  587. if (argc < 5 || argc > 6) {
  588. fmt::print("Usage: {} <thumb|arm|a64> <seed> <instruction_count> <iteration_count> [noopt]\n", argv[0]);
  589. return 1;
  590. }
  591. const auto seed = str2sz(argv[2]);
  592. const auto instruction_count = str2sz(argv[3]);
  593. const auto iterator_count = str2sz(argv[4]);
  594. const bool noopt = argc == 6 && (strcmp(argv[5], "noopt") == 0);
  595. if (!seed || !instruction_count || !iterator_count) {
  596. fmt::print("invalid numeric arguments\n");
  597. return 1;
  598. }
  599. detail::g_rand_int_generator.seed(static_cast<std::mt19937::result_type>(*seed));
  600. if (strcmp(argv[1], "thumb") == 0) {
  601. TestThumb(*instruction_count, *iterator_count, noopt);
  602. } else if (strcmp(argv[1], "arm") == 0) {
  603. TestArm(*instruction_count, *iterator_count, noopt);
  604. } else if (strcmp(argv[1], "a64") == 0) {
  605. TestA64(*instruction_count, *iterator_count, noopt);
  606. } else {
  607. fmt::print("unrecognized instruction class\n");
  608. return 1;
  609. }
  610. return 0;
  611. }