SoftFPU.cpp 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737
  1. /*
  2. * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2021, Leon Albrecht <leon2002.la@gmail.com>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include "SoftFPU.h"
  8. #include "Emulator.h"
  9. #include "SoftCPU.h"
  10. #include "ValueWithShadow.h"
  11. #include <AK/BitCast.h>
  12. #include <AK/NumericLimits.h>
  13. #include <AK/UFixedBigInt.h>
  14. #include <unistd.h>
  15. #if defined(__GNUC__) && !defined(__clang__)
  16. # pragma GCC optimize("O3")
  17. #endif
  18. #define TODO_INSN() \
  19. do { \
  20. reportln("\n=={}== Unimplemented instruction: {}\n", getpid(), __FUNCTION__); \
  21. m_emulator.dump_backtrace(); \
  22. _exit(0); \
  23. } while (0)
  24. template<typename T>
  25. ALWAYS_INLINE void warn_if_uninitialized(T value_with_shadow, const char* message)
  26. {
  27. if (value_with_shadow.is_uninitialized()) [[unlikely]] {
  28. reportln("\033[31;1mWarning! Use of uninitialized value: {}\033[0m\n", message);
  29. UserspaceEmulator::Emulator::the().dump_backtrace();
  30. }
  31. }
  32. namespace UserspaceEmulator {
  33. ALWAYS_INLINE void SoftFPU::warn_if_fpu_not_set_absolute(u8 index) const
  34. {
  35. if (!fpu_is_set(index)) [[unlikely]] {
  36. // FIXME: Are we supposed to set a flag here?
  37. // We might need to raise a stack underflow here
  38. reportln("\033[31;1mWarning! Read of uninitialized value on the FPU Stack ({} abs)\033[0m\n", index);
  39. m_emulator.dump_backtrace();
  40. }
  41. }
  42. ALWAYS_INLINE void SoftFPU::warn_if_mmx_absolute(u8 index) const
  43. {
  44. if (m_reg_is_mmx[index]) [[unlikely]] {
  45. reportln("\033[31;1mWarning! Use of an MMX register as an FPU value ({} abs)\033[0m\n", index);
  46. m_emulator.dump_backtrace();
  47. }
  48. }
  49. ALWAYS_INLINE void SoftFPU::warn_if_fpu_absolute(u8 index) const
  50. {
  51. if (!m_reg_is_mmx[index]) [[unlikely]] {
  52. reportln("\033[31;1mWarning! Use of an FPU value ({} abs) as an MMX register\033[0m\n", index);
  53. m_emulator.dump_backtrace();
  54. }
  55. }
  56. ALWAYS_INLINE long double SoftFPU::fpu_get(u8 index) const
  57. {
  58. VERIFY(index < 8);
  59. warn_if_fpu_not_set_absolute(index);
  60. warn_if_mmx_absolute(index);
  61. u8 effective_index = (m_fpu_stack_top + index) % 8;
  62. return m_storage[effective_index].fp;
  63. }
  64. ALWAYS_INLINE void SoftFPU::fpu_set_absolute(u8 index, long double value)
  65. {
  66. VERIFY(index < 8);
  67. set_tag_from_value_absolute(index, value);
  68. m_storage[index].fp = value;
  69. m_reg_is_mmx[index] = false;
  70. }
  71. ALWAYS_INLINE void SoftFPU::fpu_set(u8 index, long double value)
  72. {
  73. VERIFY(index < 8);
  74. fpu_set_absolute((m_fpu_stack_top + index) % 8, value);
  75. }
  76. ALWAYS_INLINE MMX SoftFPU::mmx_get(u8 index) const
  77. {
  78. VERIFY(index < 8);
  79. warn_if_fpu_absolute(index);
  80. return m_storage[index].mmx;
  81. }
  82. ALWAYS_INLINE void SoftFPU::mmx_set(u8 index, MMX value)
  83. {
  84. m_storage[index].mmx = value;
  85. // The high bytes are set to 0b11... to make the floating-point value NaN.
  86. // This way we are technically able to find out if we are reading the wrong
  87. // type, but this is still difficult, so we use our own lookup for that
  88. m_storage[index].__high = 0xFFFFU;
  89. m_reg_is_mmx[index] = true;
  90. }
  91. ALWAYS_INLINE void SoftFPU::fpu_push(long double value)
  92. {
  93. if (fpu_is_set(7))
  94. fpu_set_stack_overflow();
  95. m_fpu_stack_top = (m_fpu_stack_top - 1u) % 8;
  96. fpu_set(0, value);
  97. }
  98. ALWAYS_INLINE long double SoftFPU::fpu_pop()
  99. {
  100. warn_if_mmx_absolute(m_fpu_stack_top);
  101. if (!fpu_is_set(0))
  102. fpu_set_stack_underflow();
  103. auto ret = fpu_get(0);
  104. fpu_set_tag(0, FPU_Tag::Empty);
  105. m_fpu_stack_top = (m_fpu_stack_top + 1u) % 8;
  106. return ret;
  107. }
  108. ALWAYS_INLINE void SoftFPU::fpu_set_exception(FPU_Exception ex)
  109. {
  110. switch (ex) {
  111. case FPU_Exception::StackFault:
  112. m_fpu_error_stackfault = 1;
  113. m_fpu_error_invalid = 1; // Implies InvalidOperation
  114. break;
  115. case FPU_Exception::InvalidOperation:
  116. m_fpu_error_invalid = 1;
  117. if (!m_fpu_mask_invalid)
  118. break;
  119. return;
  120. case FPU_Exception::DenormalizedOperand:
  121. m_fpu_error_denorm = 1;
  122. if (!m_fpu_mask_denorm)
  123. break;
  124. return;
  125. case FPU_Exception::ZeroDivide:
  126. m_fpu_error_zero_div = 1;
  127. if (!m_fpu_mask_zero_div)
  128. break;
  129. return;
  130. case FPU_Exception::Overflow:
  131. m_fpu_error_overflow = 1;
  132. if (!m_fpu_mask_overflow)
  133. break;
  134. return;
  135. case FPU_Exception::Underflow:
  136. m_fpu_error_underflow = 1;
  137. if (!m_fpu_mask_underflow)
  138. break;
  139. return;
  140. case FPU_Exception::Precision:
  141. m_fpu_error_precision = 1;
  142. if (!m_fpu_mask_precision)
  143. break;
  144. return;
  145. }
  146. // set exception bit
  147. m_fpu_error_summary = 1;
  148. // FIXME: set traceback
  149. // For that we need to get the currently executing instruction and
  150. // the previous eip
  151. // FIXME: Call FPU Exception handler
  152. reportln("Trying to call Exception handler from {}", fpu_exception_string(ex));
  153. fpu_dump_env();
  154. m_emulator.dump_backtrace();
  155. TODO();
  156. }
  157. template<Arithmetic T>
  158. ALWAYS_INLINE T SoftFPU::fpu_round(long double value) const
  159. {
  160. // FIXME: may need to set indefinite values manually
  161. switch (fpu_get_round_mode()) {
  162. case RoundingMode::NEAREST:
  163. return static_cast<T>(roundl(value));
  164. case RoundingMode::DOWN:
  165. return static_cast<T>(floorl(value));
  166. case RoundingMode::UP:
  167. return static_cast<T>(ceill(value));
  168. case RoundingMode::TRUNC:
  169. return static_cast<T>(truncl(value));
  170. default:
  171. VERIFY_NOT_REACHED();
  172. }
  173. }
  174. template<Arithmetic T>
  175. ALWAYS_INLINE T SoftFPU::fpu_round_checked(long double value)
  176. {
  177. T result = fpu_round<T>(value);
  178. if (result != value)
  179. fpu_set_exception(FPU_Exception::Precision);
  180. if (result > value)
  181. set_c1(1);
  182. else
  183. set_c1(0);
  184. return result;
  185. }
  186. template<FloatingPoint T>
  187. ALWAYS_INLINE T SoftFPU::fpu_convert(long double value) const
  188. {
  189. // FIXME: actually round the right way
  190. return static_cast<T>(value);
  191. }
  192. template<FloatingPoint T>
  193. ALWAYS_INLINE T SoftFPU::fpu_convert_checked(long double value)
  194. {
  195. T result = fpu_convert<T>(value);
  196. if (auto rnd = value - result) {
  197. if (rnd > 0)
  198. set_c1(1);
  199. else
  200. set_c1(0);
  201. fpu_set_exception(FPU_Exception::Precision);
  202. }
  203. return result;
  204. }
  205. // Instructions
  206. // DATA TRANSFER
  207. void SoftFPU::FLD_RM32(const X86::Instruction& insn)
  208. {
  209. if (insn.modrm().is_register()) {
  210. fpu_push(fpu_get(insn.modrm().register_index()));
  211. } else {
  212. auto new_f32 = insn.modrm().read32(m_cpu, insn);
  213. // FIXME: Respect shadow values
  214. fpu_push(bit_cast<float>(new_f32.value()));
  215. }
  216. }
  217. void SoftFPU::FLD_RM64(const X86::Instruction& insn)
  218. {
  219. VERIFY(!insn.modrm().is_register());
  220. auto new_f64 = insn.modrm().read64(m_cpu, insn);
  221. // FIXME: Respect shadow values
  222. fpu_push(bit_cast<double>(new_f64.value()));
  223. }
  224. void SoftFPU::FLD_RM80(const X86::Instruction& insn)
  225. {
  226. VERIFY(!insn.modrm().is_register());
  227. // long doubles can be up to 128 bits wide in memory for reasons (alignment) and only uses 80 bits of precision
  228. // GCC uses 12 bytes in 32 bit and 16 bytes in 64 bit mode
  229. // so in the 32 bit case we read a bit to much, but that shouldn't be an issue.
  230. // FIXME: Respect shadow values
  231. u128 new_f80 = insn.modrm().read128(m_cpu, insn).value();
  232. fpu_push(*(long double*)new_f80.bytes().data());
  233. }
  234. void SoftFPU::FST_RM32(const X86::Instruction& insn)
  235. {
  236. VERIFY(!insn.modrm().is_register());
  237. float f32 = fpu_convert_checked<float>(fpu_get(0));
  238. if (fpu_is_set(0))
  239. insn.modrm().write32(m_cpu, insn, shadow_wrap_as_initialized(bit_cast<u32>(f32)));
  240. else
  241. insn.modrm().write32(m_cpu, insn, ValueWithShadow<u32>(bit_cast<u32>(f32), 0u));
  242. }
  243. void SoftFPU::FST_RM64(const X86::Instruction& insn)
  244. {
  245. if (insn.modrm().is_register()) {
  246. fpu_set(insn.modrm().register_index(), fpu_get(0));
  247. } else {
  248. double f64 = fpu_convert_checked<double>(fpu_get(0));
  249. if (fpu_is_set(0))
  250. insn.modrm().write64(m_cpu, insn, shadow_wrap_as_initialized(bit_cast<u64>(f64)));
  251. else
  252. insn.modrm().write64(m_cpu, insn, ValueWithShadow<u64>(bit_cast<u64>(f64), 0ULL));
  253. }
  254. }
  255. void SoftFPU::FSTP_RM32(const X86::Instruction& insn)
  256. {
  257. FST_RM32(insn);
  258. fpu_pop();
  259. }
  260. void SoftFPU::FSTP_RM64(const X86::Instruction& insn)
  261. {
  262. FST_RM64(insn);
  263. fpu_pop();
  264. }
  265. void SoftFPU::FSTP_RM80(const X86::Instruction& insn)
  266. {
  267. if (insn.modrm().is_register()) {
  268. fpu_set(insn.modrm().register_index(), fpu_get(0));
  269. fpu_pop();
  270. } else {
  271. // FIXME: Respect more shadow values
  272. // long doubles can be up to 128 bits wide in memory for reasons (alignment) and only uses 80 bits of precision
  273. // gcc uses 12 byte in 32 bit and 16 byte in 64 bit mode
  274. // due to only 10 bytes being used, we just write these 10 into memory
  275. // We have to do .bytes().data() to get around static type analysis
  276. ValueWithShadow<u128> f80 { 0u, 0u };
  277. u128 value {};
  278. f80 = insn.modrm().read128(m_cpu, insn);
  279. *(long double*)value.bytes().data() = fpu_pop();
  280. memcpy(f80.value().bytes().data(), &value, 10); // copy
  281. memset(f80.shadow().bytes().data(), 0x01, 10); // mark as initialized
  282. insn.modrm().write128(m_cpu, insn, f80);
  283. }
  284. }
  285. void SoftFPU::FILD_RM16(const X86::Instruction& insn)
  286. {
  287. VERIFY(!insn.modrm().is_register());
  288. auto m16int = insn.modrm().read16(m_cpu, insn);
  289. warn_if_uninitialized(m16int, "int16 loaded as float");
  290. fpu_push(static_cast<long double>(static_cast<i16>(m16int.value())));
  291. }
  292. void SoftFPU::FILD_RM32(const X86::Instruction& insn)
  293. {
  294. VERIFY(!insn.modrm().is_register());
  295. auto m32int = insn.modrm().read32(m_cpu, insn);
  296. warn_if_uninitialized(m32int, "int32 loaded as float");
  297. fpu_push(static_cast<long double>(static_cast<i32>(m32int.value())));
  298. }
  299. void SoftFPU::FILD_RM64(const X86::Instruction& insn)
  300. {
  301. VERIFY(!insn.modrm().is_register());
  302. auto m64int = insn.modrm().read64(m_cpu, insn);
  303. warn_if_uninitialized(m64int, "int64 loaded as float");
  304. fpu_push(static_cast<long double>(static_cast<i64>(m64int.value())));
  305. }
  306. void SoftFPU::FIST_RM16(const X86::Instruction& insn)
  307. {
  308. VERIFY(!insn.modrm().is_register());
  309. auto f = fpu_get(0);
  310. set_c1(0);
  311. auto int16 = fpu_round_checked<i16>(f);
  312. // FIXME: Respect shadow values
  313. insn.modrm().write16(m_cpu, insn, shadow_wrap_as_initialized(bit_cast<u16>(int16)));
  314. }
  315. void SoftFPU::FIST_RM32(const X86::Instruction& insn)
  316. {
  317. VERIFY(!insn.modrm().is_register());
  318. auto f = fpu_get(0);
  319. set_c1(0);
  320. auto int32 = fpu_round_checked<i32>(f);
  321. // FIXME: Respect shadow values
  322. insn.modrm().write32(m_cpu, insn, shadow_wrap_as_initialized(bit_cast<u32>(int32)));
  323. }
  324. void SoftFPU::FISTP_RM16(const X86::Instruction& insn)
  325. {
  326. FIST_RM16(insn);
  327. fpu_pop();
  328. }
  329. void SoftFPU::FISTP_RM32(const X86::Instruction& insn)
  330. {
  331. FIST_RM32(insn);
  332. fpu_pop();
  333. }
  334. void SoftFPU::FISTP_RM64(const X86::Instruction& insn)
  335. {
  336. VERIFY(!insn.modrm().is_register());
  337. auto f = fpu_pop();
  338. set_c1(0);
  339. auto i64 = fpu_round_checked<int64_t>(f);
  340. // FIXME: Respect shadow values
  341. insn.modrm().write64(m_cpu, insn, shadow_wrap_as_initialized(bit_cast<u64>(i64)));
  342. }
  343. void SoftFPU::FISTTP_RM16(const X86::Instruction& insn)
  344. {
  345. VERIFY(!insn.modrm().is_register());
  346. set_c1(0);
  347. i16 value = static_cast<i16>(fpu_pop());
  348. // FIXME: Respect shadow values
  349. insn.modrm().write16(m_cpu, insn, shadow_wrap_as_initialized(bit_cast<u16>(value)));
  350. }
  351. void SoftFPU::FISTTP_RM32(const X86::Instruction& insn)
  352. {
  353. VERIFY(!insn.modrm().is_register());
  354. i32 value = static_cast<i32>(fpu_pop());
  355. set_c1(0);
  356. // FIXME: Respect shadow values
  357. insn.modrm().write32(m_cpu, insn, shadow_wrap_as_initialized(bit_cast<u32>(value)));
  358. }
  359. void SoftFPU::FISTTP_RM64(const X86::Instruction& insn)
  360. {
  361. VERIFY(!insn.modrm().is_register());
  362. set_c1(0);
  363. i64 value = static_cast<i64>(fpu_pop());
  364. // FIXME: Respect shadow values
  365. insn.modrm().write64(m_cpu, insn, shadow_wrap_as_initialized(bit_cast<u64>(value)));
  366. }
  367. void SoftFPU::FBLD_M80(const X86::Instruction&) { TODO_INSN(); }
  368. void SoftFPU::FBSTP_M80(const X86::Instruction&) { TODO_INSN(); }
  369. void SoftFPU::FXCH(const X86::Instruction& insn)
  370. {
  371. // FIXME: implicit argument `D9 C9` -> st[0] <-> st[1]?
  372. VERIFY(insn.modrm().is_register());
  373. set_c1(0);
  374. auto tmp = fpu_get(0);
  375. fpu_set(0, fpu_get(insn.modrm().register_index()));
  376. fpu_set(insn.modrm().register_index(), tmp);
  377. }
  378. void SoftFPU::FCMOVE(const X86::Instruction& insn)
  379. {
  380. VERIFY(insn.modrm().is_register());
  381. if (m_cpu.zf())
  382. fpu_set(0, fpu_get(insn.modrm().rm()));
  383. }
  384. void SoftFPU::FCMOVNE(const X86::Instruction& insn)
  385. {
  386. VERIFY(insn.modrm().is_register());
  387. if (!m_cpu.zf())
  388. fpu_set(0, fpu_get((insn.modrm().reg_fpu())));
  389. }
  390. void SoftFPU::FCMOVB(const X86::Instruction& insn)
  391. {
  392. VERIFY(insn.modrm().is_register());
  393. if (m_cpu.cf())
  394. fpu_set(0, fpu_get(insn.modrm().rm()));
  395. }
  396. void SoftFPU::FCMOVNB(const X86::Instruction& insn)
  397. {
  398. VERIFY(insn.modrm().is_register());
  399. if (!m_cpu.cf())
  400. fpu_set(0, fpu_get(insn.modrm().rm()));
  401. }
  402. void SoftFPU::FCMOVBE(const X86::Instruction& insn)
  403. {
  404. VERIFY(insn.modrm().is_register());
  405. if (m_cpu.cf() || m_cpu.zf())
  406. fpu_set(0, fpu_get(insn.modrm().rm()));
  407. }
  408. void SoftFPU::FCMOVNBE(const X86::Instruction& insn)
  409. {
  410. VERIFY(insn.modrm().is_register());
  411. if (!(m_cpu.cf() || m_cpu.zf()))
  412. fpu_set(0, fpu_get(insn.modrm().rm()));
  413. }
  414. void SoftFPU::FCMOVU(const X86::Instruction& insn)
  415. {
  416. VERIFY(insn.modrm().is_register());
  417. if (m_cpu.pf())
  418. fpu_set(0, fpu_get((insn.modrm().reg_fpu())));
  419. }
  420. void SoftFPU::FCMOVNU(const X86::Instruction& insn)
  421. {
  422. VERIFY(insn.modrm().is_register());
  423. if (!m_cpu.pf())
  424. fpu_set(0, fpu_get((insn.modrm().reg_fpu())));
  425. }
  426. // BASIC ARITHMETIC
  427. void SoftFPU::FADD_RM32(const X86::Instruction& insn)
  428. {
  429. // XXX look at ::INC_foo for how mem/reg stuff is handled, and use that here too to make sure this is only called for mem32 ops
  430. if (insn.modrm().is_register()) {
  431. fpu_set(0, fpu_get(insn.modrm().register_index()) + fpu_get(0));
  432. } else {
  433. auto new_f32 = insn.modrm().read32(m_cpu, insn);
  434. // FIXME: Respect shadow values
  435. auto f32 = bit_cast<float>(new_f32.value());
  436. fpu_set(0, fpu_get(0) + f32);
  437. }
  438. }
  439. void SoftFPU::FADD_RM64(const X86::Instruction& insn)
  440. {
  441. // XXX look at ::INC_foo for how mem/reg stuff is handled, and use that here too to make sure this is only called for mem64 ops
  442. if (insn.modrm().is_register()) {
  443. fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) + fpu_get(0));
  444. } else {
  445. auto new_f64 = insn.modrm().read64(m_cpu, insn);
  446. // FIXME: Respect shadow values
  447. auto f64 = bit_cast<double>(new_f64.value());
  448. fpu_set(0, fpu_get(0) + f64);
  449. }
  450. }
  451. void SoftFPU::FADDP(const X86::Instruction& insn)
  452. {
  453. VERIFY(insn.modrm().is_register());
  454. fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) + fpu_get(0));
  455. fpu_pop();
  456. }
  457. void SoftFPU::FIADD_RM32(const X86::Instruction& insn)
  458. {
  459. VERIFY(!insn.modrm().is_register());
  460. auto m32int = (i32)insn.modrm().read32(m_cpu, insn).value();
  461. // FIXME: Respect shadow values
  462. fpu_set(0, fpu_get(0) + (long double)m32int);
  463. }
  464. void SoftFPU::FIADD_RM16(const X86::Instruction& insn)
  465. {
  466. VERIFY(!insn.modrm().is_register());
  467. auto m16int = (i16)insn.modrm().read16(m_cpu, insn).value();
  468. // FIXME: Respect shadow values
  469. fpu_set(0, fpu_get(0) + (long double)m16int);
  470. }
  471. void SoftFPU::FSUB_RM32(const X86::Instruction& insn)
  472. {
  473. if (insn.modrm().is_register()) {
  474. fpu_set(0, fpu_get(0) - fpu_get(insn.modrm().register_index()));
  475. } else {
  476. auto new_f32 = insn.modrm().read32(m_cpu, insn);
  477. // FIXME: Respect shadow values
  478. auto f32 = bit_cast<float>(new_f32.value());
  479. fpu_set(0, fpu_get(0) - f32);
  480. }
  481. }
  482. void SoftFPU::FSUB_RM64(const X86::Instruction& insn)
  483. {
  484. if (insn.modrm().is_register()) {
  485. fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) - fpu_get(0));
  486. } else {
  487. auto new_f64 = insn.modrm().read64(m_cpu, insn);
  488. // FIXME: Respect shadow values
  489. auto f64 = bit_cast<double>(new_f64.value());
  490. fpu_set(0, fpu_get(0) - f64);
  491. }
  492. }
  493. void SoftFPU::FSUBP(const X86::Instruction& insn)
  494. {
  495. VERIFY(insn.modrm().is_register());
  496. fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) - fpu_get(0));
  497. fpu_pop();
  498. }
  499. void SoftFPU::FSUBR_RM32(const X86::Instruction& insn)
  500. {
  501. if (insn.modrm().is_register()) {
  502. fpu_set(0, fpu_get(insn.modrm().register_index()) - fpu_get(0));
  503. } else {
  504. auto new_f32 = insn.modrm().read32(m_cpu, insn);
  505. // FIXME: Respect shadow values
  506. auto f32 = bit_cast<float>(new_f32.value());
  507. fpu_set(0, f32 - fpu_get(0));
  508. }
  509. }
  510. void SoftFPU::FSUBR_RM64(const X86::Instruction& insn)
  511. {
  512. if (insn.modrm().is_register()) {
  513. fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) - fpu_get(0));
  514. } else {
  515. auto new_f64 = insn.modrm().read64(m_cpu, insn);
  516. // FIXME: Respect shadow values
  517. auto f64 = bit_cast<double>(new_f64.value());
  518. fpu_set(0, f64 - fpu_get(0));
  519. }
  520. }
  521. void SoftFPU::FSUBRP(const X86::Instruction& insn)
  522. {
  523. VERIFY(insn.modrm().is_register());
  524. fpu_set(insn.modrm().register_index(), fpu_get(0) - fpu_get(insn.modrm().register_index()));
  525. fpu_pop();
  526. }
  527. void SoftFPU::FISUB_RM32(const X86::Instruction& insn)
  528. {
  529. VERIFY(!insn.modrm().is_register());
  530. auto m32int = (i32)insn.modrm().read32(m_cpu, insn).value();
  531. // FIXME: Respect shadow values
  532. fpu_set(0, fpu_get(0) - (long double)m32int);
  533. }
  534. void SoftFPU::FISUB_RM16(const X86::Instruction& insn)
  535. {
  536. VERIFY(!insn.modrm().is_register());
  537. auto m16int = (i16)insn.modrm().read16(m_cpu, insn).value();
  538. // FIXME: Respect shadow values
  539. fpu_set(0, fpu_get(0) - (long double)m16int);
  540. }
  541. void SoftFPU::FISUBR_RM16(const X86::Instruction& insn)
  542. {
  543. VERIFY(!insn.modrm().is_register());
  544. auto m16int = (i16)insn.modrm().read16(m_cpu, insn).value();
  545. // FIXME: Respect shadow values
  546. fpu_set(0, (long double)m16int - fpu_get(0));
  547. }
  548. void SoftFPU::FISUBR_RM32(const X86::Instruction& insn)
  549. {
  550. VERIFY(!insn.modrm().is_register());
  551. auto m32int = (i32)insn.modrm().read32(m_cpu, insn).value();
  552. // FIXME: Respect shadow values
  553. fpu_set(0, (long double)m32int - fpu_get(0));
  554. }
  555. void SoftFPU::FMUL_RM32(const X86::Instruction& insn)
  556. {
  557. // XXX look at ::INC_foo for how mem/reg stuff is handled, and use that here too to make sure this is only called for mem32 ops
  558. if (insn.modrm().is_register()) {
  559. fpu_set(0, fpu_get(0) * fpu_get(insn.modrm().register_index()));
  560. } else {
  561. auto new_f32 = insn.modrm().read32(m_cpu, insn);
  562. // FIXME: Respect shadow values
  563. auto f32 = bit_cast<float>(new_f32.value());
  564. fpu_set(0, fpu_get(0) * f32);
  565. }
  566. }
  567. void SoftFPU::FMUL_RM64(const X86::Instruction& insn)
  568. {
  569. // XXX look at ::INC_foo for how mem/reg stuff is handled, and use that here too to make sure this is only called for mem64 ops
  570. if (insn.modrm().is_register()) {
  571. fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) * fpu_get(0));
  572. } else {
  573. auto new_f64 = insn.modrm().read64(m_cpu, insn);
  574. // FIXME: Respect shadow values
  575. auto f64 = bit_cast<double>(new_f64.value());
  576. fpu_set(0, fpu_get(0) * f64);
  577. }
  578. }
  579. void SoftFPU::FMULP(const X86::Instruction& insn)
  580. {
  581. VERIFY(insn.modrm().is_register());
  582. fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) * fpu_get(0));
  583. fpu_pop();
  584. }
  585. void SoftFPU::FIMUL_RM32(const X86::Instruction& insn)
  586. {
  587. VERIFY(!insn.modrm().is_register());
  588. auto m32int = (i32)insn.modrm().read32(m_cpu, insn).value();
  589. // FIXME: Respect shadow values
  590. fpu_set(0, fpu_get(0) * (long double)m32int);
  591. }
  592. void SoftFPU::FIMUL_RM16(const X86::Instruction& insn)
  593. {
  594. VERIFY(!insn.modrm().is_register());
  595. auto m16int = (i16)insn.modrm().read16(m_cpu, insn).value();
  596. // FIXME: Respect shadow values
  597. fpu_set(0, fpu_get(0) * (long double)m16int);
  598. }
  599. void SoftFPU::FDIV_RM32(const X86::Instruction& insn)
  600. {
  601. if (insn.modrm().is_register()) {
  602. fpu_set(0, fpu_get(0) / fpu_get(insn.modrm().register_index()));
  603. } else {
  604. auto new_f32 = insn.modrm().read32(m_cpu, insn);
  605. // FIXME: Respect shadow values
  606. auto f32 = bit_cast<float>(new_f32.value());
  607. // FIXME: Raise IA on + infinity / +-infinity, +-0 / +-0, raise Z on finite / +-0
  608. fpu_set(0, fpu_get(0) / f32);
  609. }
  610. }
  611. void SoftFPU::FDIV_RM64(const X86::Instruction& insn)
  612. {
  613. if (insn.modrm().is_register()) {
  614. fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) / fpu_get(0));
  615. } else {
  616. auto new_f64 = insn.modrm().read64(m_cpu, insn);
  617. // FIXME: Respect shadow values
  618. auto f64 = bit_cast<double>(new_f64.value());
  619. // FIXME: Raise IA on + infinity / +-infinity, +-0 / +-0, raise Z on finite / +-0
  620. fpu_set(0, fpu_get(0) / f64);
  621. }
  622. }
  623. void SoftFPU::FDIVP(const X86::Instruction& insn)
  624. {
  625. VERIFY(insn.modrm().is_register());
  626. // FIXME: Raise IA on + infinity / +-infinity, +-0 / +-0, raise Z on finite / +-0
  627. fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) / fpu_get(0));
  628. fpu_pop();
  629. }
  630. void SoftFPU::FDIVR_RM32(const X86::Instruction& insn)
  631. {
  632. if (insn.modrm().is_register()) {
  633. fpu_set(0, fpu_get(insn.modrm().register_index()) / fpu_get(0));
  634. } else {
  635. auto new_f32 = insn.modrm().read32(m_cpu, insn);
  636. // FIXME: Respect shadow values
  637. auto f32 = bit_cast<float>(new_f32.value());
  638. // FIXME: Raise IA on + infinity / +-infinity, +-0 / +-0, raise Z on finite / +-0
  639. fpu_set(0, f32 / fpu_get(0));
  640. }
  641. }
  642. void SoftFPU::FDIVR_RM64(const X86::Instruction& insn)
  643. {
  644. if (insn.modrm().is_register()) {
  645. // XXX this is FDIVR, Instruction decodes this weirdly
  646. //fpu_set(insn.modrm().register_index(), fpu_get(0) / fpu_get(insn.modrm().register_index()));
  647. fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) / fpu_get(0));
  648. } else {
  649. auto new_f64 = insn.modrm().read64(m_cpu, insn);
  650. // FIXME: Respect shadow values
  651. auto f64 = bit_cast<double>(new_f64.value());
  652. // FIXME: Raise IA on + infinity / +-infinity, +-0 / +-0, raise Z on finite / +-0
  653. fpu_set(0, f64 / fpu_get(0));
  654. }
  655. }
  656. void SoftFPU::FDIVRP(const X86::Instruction& insn)
  657. {
  658. VERIFY(insn.modrm().is_register());
  659. // FIXME: Raise IA on + infinity / +-infinity, +-0 / +-0, raise Z on finite / +-0
  660. fpu_set(insn.modrm().register_index(), fpu_get(0) / fpu_get(insn.modrm().register_index()));
  661. fpu_pop();
  662. }
  663. void SoftFPU::FIDIV_RM16(const X86::Instruction& insn)
  664. {
  665. VERIFY(!insn.modrm().is_register());
  666. auto m16int = (i16)insn.modrm().read16(m_cpu, insn).value();
  667. // FIXME: Respect shadow values
  668. // FIXME: Raise IA on 0 / _=0, raise Z on finite / +-0
  669. fpu_set(0, fpu_get(0) / (long double)m16int);
  670. }
  671. void SoftFPU::FIDIV_RM32(const X86::Instruction& insn)
  672. {
  673. VERIFY(!insn.modrm().is_register());
  674. auto m32int = (i32)insn.modrm().read32(m_cpu, insn).value();
  675. // FIXME: Respect shadow values
  676. // FIXME: Raise IA on 0 / _=0, raise Z on finite / +-0
  677. fpu_set(0, fpu_get(0) / (long double)m32int);
  678. }
  679. void SoftFPU::FIDIVR_RM16(const X86::Instruction& insn)
  680. {
  681. VERIFY(!insn.modrm().is_register());
  682. auto m16int = (i16)insn.modrm().read16(m_cpu, insn).value();
  683. // FIXME: Respect shadow values
  684. // FIXME: Raise IA on 0 / _=0, raise Z on finite / +-0
  685. fpu_set(0, (long double)m16int / fpu_get(0));
  686. }
  687. void SoftFPU::FIDIVR_RM32(const X86::Instruction& insn)
  688. {
  689. VERIFY(!insn.modrm().is_register());
  690. auto m32int = (i32)insn.modrm().read32(m_cpu, insn).value();
  691. // FIXME: Respect shadow values
  692. // FIXME: Raise IA on 0 / _=0, raise Z on finite / +-0
  693. fpu_set(0, (long double)m32int / fpu_get(0));
  694. }
  695. void SoftFPU::FPREM(const X86::Instruction&)
  696. {
  697. // FIXME: There are some exponent shenanigans supposed to be here
  698. long double top = fpu_get(0);
  699. long double one = fpu_get(1);
  700. int Q = static_cast<int>(truncl(top / one));
  701. top = top - (one * Q);
  702. set_c2(0);
  703. set_c1(Q & 1);
  704. set_c3((Q >> 1) & 1);
  705. set_c0((Q >> 2) & 1);
  706. fpu_set(0, top);
  707. }
  708. void SoftFPU::FPREM1(const X86::Instruction&)
  709. {
  710. // FIXME: There are some exponent shenanigans supposed to be here
  711. long double top = fpu_get(0);
  712. long double one = fpu_get(1);
  713. int Q = static_cast<int>(roundl(top / one));
  714. top = top - (one * Q);
  715. set_c2(0);
  716. set_c1(Q & 1);
  717. set_c3((Q >> 1) & 1);
  718. set_c0((Q >> 2) & 1);
  719. fpu_set(0, top);
  720. }
  721. void SoftFPU::FABS(const X86::Instruction&)
  722. {
  723. set_c1(0);
  724. fpu_set(0, __builtin_fabsl(fpu_get(0)));
  725. }
  726. void SoftFPU::FCHS(const X86::Instruction&)
  727. {
  728. set_c1(0);
  729. fpu_set(0, -fpu_get(0));
  730. }
  731. void SoftFPU::FRNDINT(const X86::Instruction&)
  732. {
  733. auto res = fpu_round_checked<long double>(fpu_get(0));
  734. fpu_set(0, res);
  735. }
  736. void SoftFPU::FSCALE(const X86::Instruction&)
  737. {
  738. // FIXME: set C1 upon stack overflow or if result was rounded
  739. fpu_set(0, fpu_get(0) * powl(2, truncl(fpu_get(1))));
  740. }
  741. void SoftFPU::FSQRT(const X86::Instruction&)
  742. {
  743. // FIXME: set C1 upon stack overflow or if result was rounded
  744. fpu_set(0, sqrtl(fpu_get(0)));
  745. }
  746. void SoftFPU::FXTRACT(const X86::Instruction&) { TODO_INSN(); }
  747. // COMPARISON
  748. // FIXME: there may be an implicit argument, how is this conveyed by the insn
  749. void SoftFPU::FCOM_RM32(const X86::Instruction&) { TODO_INSN(); }
  750. void SoftFPU::FCOM_RM64(const X86::Instruction&) { TODO_INSN(); }
  751. void SoftFPU::FCOMP_RM32(const X86::Instruction&) { TODO_INSN(); }
  752. void SoftFPU::FCOMP_RM64(const X86::Instruction&) { TODO_INSN(); }
  753. void SoftFPU::FCOMPP(const X86::Instruction&)
  754. {
  755. if (fpu_isnan(0) || fpu_isnan(1)) {
  756. fpu_set_exception(FPU_Exception::InvalidOperation);
  757. if (m_fpu_mask_invalid)
  758. fpu_set_unordered();
  759. } else {
  760. set_c2(0);
  761. set_c0(fpu_get(0) < fpu_get(1));
  762. set_c3(fpu_get(0) == fpu_get(1));
  763. }
  764. fpu_pop();
  765. fpu_pop();
  766. }
  767. void SoftFPU::FUCOM(const X86::Instruction&) { TODO_INSN(); } // Needs QNaN detection
  768. void SoftFPU::FUCOMP(const X86::Instruction&) { TODO_INSN(); }
  769. void SoftFPU::FUCOMPP(const X86::Instruction&) { TODO_INSN(); }
  770. void SoftFPU::FICOM_RM16(const X86::Instruction& insn)
  771. {
  772. // FIXME: Check for denormals
  773. VERIFY(insn.modrm().is_register());
  774. auto val_shd = insn.modrm().read16(m_cpu, insn);
  775. warn_if_uninitialized(val_shd, "int16 compare to float");
  776. auto val = static_cast<i16>(val_shd.value());
  777. if (fpu_isnan(0)) {
  778. fpu_set_unordered();
  779. } else {
  780. set_c0(fpu_get(0) < val);
  781. set_c2(0);
  782. set_c3(fpu_get(0) == val);
  783. }
  784. set_c1(0);
  785. }
  786. void SoftFPU::FICOM_RM32(const X86::Instruction& insn)
  787. {
  788. // FIXME: Check for denormals
  789. VERIFY(insn.modrm().is_register());
  790. auto val_shd = insn.modrm().read32(m_cpu, insn);
  791. warn_if_uninitialized(val_shd, "int32 compare to float");
  792. auto val = static_cast<i32>(val_shd.value());
  793. if (fpu_isnan(0)) {
  794. fpu_set_unordered();
  795. } else {
  796. set_c0(fpu_get(0) < val);
  797. set_c2(0);
  798. set_c3(fpu_get(0) == val);
  799. }
  800. set_c1(0);
  801. }
  802. void SoftFPU::FICOMP_RM16(const X86::Instruction& insn)
  803. {
  804. FICOM_RM16(insn);
  805. fpu_pop();
  806. }
  807. void SoftFPU::FICOMP_RM32(const X86::Instruction& insn)
  808. {
  809. FICOM_RM32(insn);
  810. fpu_pop();
  811. }
  812. void SoftFPU::FCOMI(const X86::Instruction& insn)
  813. {
  814. auto i = insn.modrm().rm();
  815. // FIXME: QNaN / exception handling.
  816. set_c0(0);
  817. if (isnan(fpu_get(0)) || isnan(fpu_get(1))) {
  818. fpu_set_exception(FPU_Exception::InvalidOperation);
  819. m_cpu.set_zf(1);
  820. m_cpu.set_pf(1);
  821. m_cpu.set_cf(1);
  822. }
  823. if (!fpu_is_set(1))
  824. fpu_set_exception(FPU_Exception::Underflow);
  825. m_cpu.set_zf(fpu_get(0) == fpu_get(i));
  826. m_cpu.set_pf(false);
  827. m_cpu.set_cf(fpu_get(0) < fpu_get(i));
  828. // FIXME: is this supposed to be here?
  829. // m_cpu.set_of(false);
  830. // FIXME: Taint should be based on ST(0) and ST(i)
  831. m_cpu.m_flags_tainted = false;
  832. }
  833. void SoftFPU::FCOMIP(const X86::Instruction& insn)
  834. {
  835. FCOMI(insn);
  836. fpu_pop();
  837. }
  838. void SoftFPU::FUCOMI(const X86::Instruction& insn)
  839. {
  840. auto i = insn.modrm().rm();
  841. // FIXME: Unordered comparison checks.
  842. // FIXME: QNaN / exception handling.
  843. set_c1(0);
  844. if (fpu_isnan(0) || fpu_isnan(i)) {
  845. m_cpu.set_zf(true);
  846. m_cpu.set_pf(true);
  847. m_cpu.set_cf(true);
  848. } else {
  849. m_cpu.set_zf(fpu_get(0) == fpu_get(i));
  850. m_cpu.set_pf(false);
  851. m_cpu.set_cf(fpu_get(0) < fpu_get(i));
  852. m_cpu.set_of(false);
  853. }
  854. // FIXME: Taint should be based on ST(0) and ST(i)
  855. m_cpu.m_flags_tainted = false;
  856. }
  857. void SoftFPU::FUCOMIP(const X86::Instruction& insn)
  858. {
  859. FUCOMI(insn);
  860. fpu_pop();
  861. }
  862. void SoftFPU::FTST(const X86::Instruction&)
  863. {
  864. // FIXME: maybe check for denormal
  865. set_c1(0);
  866. if (fpu_isnan(0))
  867. // raise #IA?
  868. fpu_set_unordered();
  869. else {
  870. set_c0(fpu_get(0) < 0.);
  871. set_c2(0);
  872. set_c3(fpu_get(0) == 0.);
  873. }
  874. }
  875. void SoftFPU::FXAM(const X86::Instruction&)
  876. {
  877. if (m_reg_is_mmx[m_fpu_stack_top]) {
  878. // technically a subset of NaN/INF, with the Tag set to valid,
  879. // but we have our own helper for this
  880. set_c0(0);
  881. set_c2(0);
  882. set_c3(0);
  883. } else {
  884. switch (fpu_get_tag(0)) {
  885. case FPU_Tag::Valid:
  886. set_c0(0);
  887. set_c2(1);
  888. set_c3(0);
  889. break;
  890. case FPU_Tag::Zero:
  891. set_c0(1);
  892. set_c2(0);
  893. set_c3(0);
  894. break;
  895. case FPU_Tag::Special:
  896. if (isinf(fpu_get(0))) {
  897. set_c0(1);
  898. set_c2(1);
  899. set_c3(0);
  900. } else if (isnan(fpu_get(0))) {
  901. set_c0(1);
  902. set_c2(0);
  903. set_c3(0);
  904. } else {
  905. // denormalized
  906. set_c0(0);
  907. set_c2(1);
  908. set_c3(1);
  909. }
  910. break;
  911. case FPU_Tag::Empty:
  912. set_c0(1);
  913. set_c2(0);
  914. set_c3(1);
  915. break;
  916. default:
  917. VERIFY_NOT_REACHED();
  918. }
  919. }
  920. set_c1(signbit(fpu_get(0)));
  921. }
  922. // TRANSCENDENTAL
  923. void SoftFPU::FSIN(const X86::Instruction&)
  924. {
  925. // FIXME: set C1 upon stack overflow or if result was rounded
  926. // FIXME: Set C2 to 1 if ST(0) is outside range of -2^63 to +2^63; else set to 0
  927. fpu_set(0, sinl(fpu_get(0)));
  928. }
  929. void SoftFPU::FCOS(const X86::Instruction&)
  930. {
  931. // FIXME: set C1 upon stack overflow or if result was rounded
  932. // FIXME: Set C2 to 1 if ST(0) is outside range of -2^63 to +2^63; else set to 0
  933. fpu_set(0, cosl(fpu_get(0)));
  934. }
  935. void SoftFPU::FSINCOS(const X86::Instruction&)
  936. {
  937. // FIXME: set C1 upon stack overflow or if result was rounded
  938. // FIXME: Set C2 to 1 if ST(0) is outside range of -2^63 to +2^63; else set to 0s
  939. long double sin = sinl(fpu_get(0));
  940. long double cos = cosl(fpu_get(0));
  941. fpu_set(0, sin);
  942. fpu_push(cos);
  943. }
  944. void SoftFPU::FPTAN(const X86::Instruction&)
  945. {
  946. // FIXME: set C1 upon stack overflow or if result was rounded
  947. // FIXME: Set C2 to 1 if ST(0) is outside range of -2^63 to +2^63; else set to 0
  948. fpu_set(0, tanl(fpu_get(0)));
  949. fpu_push(1.0f);
  950. }
  951. void SoftFPU::FPATAN(const X86::Instruction&)
  952. {
  953. // FIXME: set C1 on stack underflow, or on rounding
  954. // FIXME: Exceptions
  955. fpu_set(1, atan2l(fpu_get(1), fpu_get(0)));
  956. fpu_pop();
  957. }
  958. void SoftFPU::F2XM1(const X86::Instruction&)
  959. {
  960. // FIXME: validate ST(0) is in range –1.0 to +1.0
  961. auto val = fpu_get(0);
  962. // FIXME: Set C0, C2, C3 in FPU status word.
  963. fpu_set(0, powl(2, val) - 1.0l);
  964. }
  965. void SoftFPU::FYL2X(const X86::Instruction&)
  966. {
  967. // FIXME: raise precision and under/overflow
  968. // FIXME: detect denormal operands
  969. // FIXME: QNaN
  970. auto f0 = fpu_get(0);
  971. auto f1 = fpu_get(1);
  972. if (f0 < 0. || isnan(f0) || isnan(f1)
  973. || (isinf(f0) && f1 == 0.) || (f0 == 1. && isinf(f1)))
  974. fpu_set_exception(FPU_Exception::InvalidOperation);
  975. if (f0 == 0.)
  976. fpu_set_exception(FPU_Exception::ZeroDivide);
  977. fpu_set(1, f1 * log2l(f0));
  978. fpu_pop();
  979. }
  980. void SoftFPU::FYL2XP1(const X86::Instruction&)
  981. {
  982. // FIXME: raise #O #U #P #D
  983. // FIXME: QNaN
  984. auto f0 = fpu_get(0);
  985. auto f1 = fpu_get(1);
  986. if (isnan(f0) || isnan(f1)
  987. || (isinf(f1) && f0 == 0))
  988. fpu_set_exception(FPU_Exception::InvalidOperation);
  989. fpu_set(1, (f1 * log2l(f0 + 1.0l)));
  990. fpu_pop();
  991. }
  992. // LOAD CONSTANT
  993. void SoftFPU::FLD1(const X86::Instruction&)
  994. {
  995. fpu_push(1.0l);
  996. }
  997. void SoftFPU::FLDZ(const X86::Instruction&)
  998. {
  999. fpu_push(0.0l);
  1000. }
  1001. void SoftFPU::FLDPI(const X86::Instruction&)
  1002. {
  1003. fpu_push(M_PIl);
  1004. }
  1005. void SoftFPU::FLDL2E(const X86::Instruction&)
  1006. {
  1007. fpu_push(M_LOG2El);
  1008. }
  1009. void SoftFPU::FLDLN2(const X86::Instruction&)
  1010. {
  1011. fpu_push(M_LN2l);
  1012. }
  1013. void SoftFPU::FLDL2T(const X86::Instruction&)
  1014. {
  1015. fpu_push(log2l(10.0l));
  1016. }
  1017. void SoftFPU::FLDLG2(const X86::Instruction&)
  1018. {
  1019. fpu_push(log10l(2.0l));
  1020. }
  1021. // CONTROL
  1022. void SoftFPU::FINCSTP(const X86::Instruction&)
  1023. {
  1024. m_fpu_stack_top = (m_fpu_stack_top + 1u) % 8u;
  1025. set_c1(0);
  1026. }
  1027. void SoftFPU::FDECSTP(const X86::Instruction&)
  1028. {
  1029. m_fpu_stack_top = (m_fpu_stack_top - 1u) % 8u;
  1030. set_c1(0);
  1031. }
  1032. void SoftFPU::FFREE(const X86::Instruction& insn)
  1033. {
  1034. fpu_set_tag(insn.modrm().reg_fpu(), FPU_Tag::Empty);
  1035. }
  1036. void SoftFPU::FFREEP(const X86::Instruction& insn)
  1037. {
  1038. FFREE(insn);
  1039. fpu_pop();
  1040. }
  1041. void SoftFPU::FNINIT(const X86::Instruction&)
  1042. {
  1043. m_fpu_cw = 0x037F;
  1044. m_fpu_sw = 0;
  1045. m_fpu_tw = 0xFFFF;
  1046. m_fpu_ip = 0;
  1047. m_fpu_cs = 0;
  1048. m_fpu_dp = 0;
  1049. m_fpu_ds = 0;
  1050. m_fpu_iop = 0;
  1051. };
  1052. void SoftFPU::FNCLEX(const X86::Instruction&)
  1053. {
  1054. m_fpu_error_invalid = 0;
  1055. m_fpu_error_denorm = 0;
  1056. m_fpu_error_zero_div = 0;
  1057. m_fpu_error_overflow = 0;
  1058. m_fpu_error_underflow = 0;
  1059. m_fpu_error_precision = 0;
  1060. m_fpu_error_stackfault = 0;
  1061. m_fpu_busy = 0;
  1062. }
  1063. void SoftFPU::FNSTCW(const X86::Instruction& insn)
  1064. {
  1065. insn.modrm().write16(m_cpu, insn, shadow_wrap_as_initialized(m_fpu_cw));
  1066. }
  1067. void SoftFPU::FLDCW(const X86::Instruction& insn)
  1068. {
  1069. m_fpu_cw = insn.modrm().read16(m_cpu, insn).value();
  1070. }
  1071. void SoftFPU::FNSTENV(const X86::Instruction& insn)
  1072. {
  1073. // Assuming we are always in Protected mode
  1074. // FIXME: 16-bit Format
  1075. // 32-bit Format
  1076. /* 31--------------16---------------0
  1077. * | | CW | 0
  1078. * +----------------+---------------+
  1079. * | | SW | 4
  1080. * +----------------+---------------+
  1081. * | | TW | 8
  1082. * +----------------+---------------+
  1083. * | FIP | 12
  1084. * +----+-----------+---------------+
  1085. * |0000|fpuOp[10:0]| FIP_sel | 16
  1086. * +----+-----------+---------------+
  1087. * | FDP | 20
  1088. * +----------------+---------------+
  1089. * | | FDP_ds | 24
  1090. * +----------------|---------------+
  1091. * */
  1092. auto address = insn.modrm().resolve(m_cpu, insn);
  1093. m_cpu.write_memory16(address, shadow_wrap_as_initialized(m_fpu_cw));
  1094. address.set_offset(address.offset() + 4);
  1095. m_cpu.write_memory16(address, shadow_wrap_as_initialized(m_fpu_sw));
  1096. address.set_offset(address.offset() + 4);
  1097. m_cpu.write_memory16(address, shadow_wrap_as_initialized(m_fpu_tw));
  1098. address.set_offset(address.offset() + 4);
  1099. m_cpu.write_memory32(address, shadow_wrap_as_initialized(m_fpu_ip));
  1100. address.set_offset(address.offset() + 4);
  1101. m_cpu.write_memory16(address, shadow_wrap_as_initialized(m_fpu_cs));
  1102. address.set_offset(address.offset() + 2);
  1103. m_cpu.write_memory16(address, shadow_wrap_as_initialized<u16>(m_fpu_iop & 0x3FFU));
  1104. address.set_offset(address.offset() + 2);
  1105. m_cpu.write_memory32(address, shadow_wrap_as_initialized(m_fpu_dp));
  1106. address.set_offset(address.offset() + 4);
  1107. m_cpu.write_memory16(address, shadow_wrap_as_initialized(m_fpu_ds));
  1108. }
  1109. void SoftFPU::FLDENV(const X86::Instruction& insn)
  1110. {
  1111. // Assuming we are always in Protected mode
  1112. // FIXME: 16-bit Format
  1113. auto address = insn.modrm().resolve(m_cpu, insn);
  1114. // FIXME: Shadow Values
  1115. m_fpu_cw = m_cpu.read_memory16(address).value();
  1116. address.set_offset(address.offset() + 4);
  1117. m_fpu_sw = m_cpu.read_memory16(address).value();
  1118. address.set_offset(address.offset() + 4);
  1119. m_fpu_tw = m_cpu.read_memory16(address).value();
  1120. address.set_offset(address.offset() + 4);
  1121. m_fpu_ip = m_cpu.read_memory32(address).value();
  1122. address.set_offset(address.offset() + 4);
  1123. m_fpu_cs = m_cpu.read_memory16(address).value();
  1124. address.set_offset(address.offset() + 2);
  1125. m_fpu_iop = m_cpu.read_memory16(address).value();
  1126. address.set_offset(address.offset() + 2);
  1127. m_fpu_dp = m_cpu.read_memory32(address).value();
  1128. address.set_offset(address.offset() + 4);
  1129. m_fpu_ds = m_cpu.read_memory16(address).value();
  1130. }
  1131. void SoftFPU::FNSAVE(const X86::Instruction& insn)
  1132. {
  1133. FNSTENV(insn);
  1134. auto address = insn.modrm().resolve(m_cpu, insn);
  1135. address.set_offset(address.offset() + 28); // size of the ENV
  1136. // write fpu-stack to memory
  1137. u8 raw_data[80];
  1138. for (int i = 0; i < 8; ++i) {
  1139. memcpy(raw_data + 10 * i, &m_storage[i], 10);
  1140. }
  1141. for (int i = 0; i < 5; ++i) {
  1142. // FIXME: Shadow Value
  1143. m_cpu.write_memory128(address, shadow_wrap_as_initialized(((u128*)raw_data)[i]));
  1144. address.set_offset(address.offset() + 16);
  1145. }
  1146. FNINIT(insn);
  1147. }
  1148. void SoftFPU::FRSTOR(const X86::Instruction& insn)
  1149. {
  1150. FLDENV(insn);
  1151. auto address = insn.modrm().resolve(m_cpu, insn);
  1152. address.set_offset(address.offset() + 28); // size of the ENV
  1153. // read fpu-stack from memory
  1154. u8 raw_data[80];
  1155. for (int i = 0; i < 5; ++i) {
  1156. // FIXME: Shadow Value
  1157. ((u128*)raw_data)[i] = m_cpu.read_memory128(address).value();
  1158. address.set_offset(address.offset() + 16);
  1159. }
  1160. for (int i = 0; i < 8; ++i) {
  1161. memcpy(&m_storage[i], raw_data + 10 * i, 10);
  1162. }
  1163. memset(m_reg_is_mmx, 0, sizeof(m_reg_is_mmx));
  1164. }
  1165. void SoftFPU::FNSTSW(const X86::Instruction& insn)
  1166. {
  1167. insn.modrm().write16(m_cpu, insn, shadow_wrap_as_initialized(m_fpu_sw));
  1168. }
  1169. void SoftFPU::FNSTSW_AX(const X86::Instruction&)
  1170. {
  1171. m_cpu.set_ax(shadow_wrap_as_initialized(m_fpu_sw));
  1172. }
  1173. // FIXME: FWAIT
  1174. void SoftFPU::FNOP(const X86::Instruction&) { }
  1175. // DO NOTHING?
  1176. void SoftFPU::FNENI(const X86::Instruction&) { TODO_INSN(); }
  1177. void SoftFPU::FNDISI(const X86::Instruction&) { TODO_INSN(); }
  1178. void SoftFPU::FNSETPM(const X86::Instruction&) { TODO_INSN(); }
  1179. // MMX
  1180. // helpers
  1181. #define LOAD_MM_MM64M() \
  1182. MMX mm; \
  1183. MMX mm64m; \
  1184. if (insn.modrm().mod() == 0b11) { /* 0b11 signals a register */ \
  1185. mm64m = mmx_get(insn.modrm().rm()); \
  1186. } else { \
  1187. auto temp = insn.modrm().read64(m_cpu, insn); \
  1188. warn_if_uninitialized(temp, "Read of uninitialized Memory as Packed integer"); \
  1189. mm64m.raw = temp.value(); \
  1190. } \
  1191. mm = mmx_get(insn.modrm().reg())
  1192. #define MMX_intrinsic(intrinsic, res_type, actor_type) \
  1193. LOAD_MM_MM64M(); \
  1194. mm.res_type = __builtin_ia32_##intrinsic(mm.actor_type, mm64m.actor_type); \
  1195. mmx_set(insn.modrm().reg(), mm); \
  1196. mmx_common();
  1197. // ARITHMETIC
  1198. void SoftFPU::PADDB_mm1_mm2m64(const X86::Instruction& insn)
  1199. {
  1200. LOAD_MM_MM64M();
  1201. mm.v8 += mm64m.v8;
  1202. mmx_set(insn.modrm().reg(), mm);
  1203. mmx_common();
  1204. }
  1205. void SoftFPU::PADDW_mm1_mm2m64(const X86::Instruction& insn)
  1206. {
  1207. LOAD_MM_MM64M();
  1208. mm.v16 += mm64m.v16;
  1209. mmx_set(insn.modrm().reg(), mm);
  1210. mmx_common();
  1211. }
  1212. void SoftFPU::PADDD_mm1_mm2m64(const X86::Instruction& insn)
  1213. {
  1214. LOAD_MM_MM64M();
  1215. mm.v32 += mm64m.v32;
  1216. mmx_set(insn.modrm().reg(), mm);
  1217. mmx_common();
  1218. }
  1219. void SoftFPU::PADDSB_mm1_mm2m64(const X86::Instruction& insn)
  1220. {
  1221. MMX_intrinsic(paddsb, v8, v8);
  1222. }
  1223. void SoftFPU::PADDSW_mm1_mm2m64(const X86::Instruction& insn)
  1224. {
  1225. MMX_intrinsic(paddsw, v16, v16);
  1226. }
  1227. void SoftFPU::PADDUSB_mm1_mm2m64(const X86::Instruction& insn)
  1228. {
  1229. MMX_intrinsic(paddusb, v8, v8);
  1230. }
  1231. void SoftFPU::PADDUSW_mm1_mm2m64(const X86::Instruction& insn)
  1232. {
  1233. MMX_intrinsic(paddusw, v16, v16);
  1234. }
  1235. void SoftFPU::PSUBB_mm1_mm2m64(const X86::Instruction& insn)
  1236. {
  1237. LOAD_MM_MM64M();
  1238. mm.v8 -= mm64m.v8;
  1239. mmx_set(insn.modrm().reg(), mm);
  1240. mmx_common();
  1241. }
  1242. void SoftFPU::PSUBW_mm1_mm2m64(const X86::Instruction& insn)
  1243. {
  1244. LOAD_MM_MM64M();
  1245. mm.v16 -= mm64m.v16;
  1246. mmx_set(insn.modrm().reg(), mm);
  1247. mmx_common();
  1248. }
  1249. void SoftFPU::PSUBD_mm1_mm2m64(const X86::Instruction& insn)
  1250. {
  1251. LOAD_MM_MM64M();
  1252. mm.v32 -= mm64m.v32;
  1253. mmx_set(insn.modrm().reg(), mm);
  1254. mmx_common();
  1255. }
  1256. void SoftFPU::PSUBSB_mm1_mm2m64(const X86::Instruction& insn)
  1257. {
  1258. MMX_intrinsic(psubsb, v8, v8);
  1259. }
  1260. void SoftFPU::PSUBSW_mm1_mm2m64(const X86::Instruction& insn)
  1261. {
  1262. MMX_intrinsic(psubsw, v16, v16);
  1263. }
  1264. void SoftFPU::PSUBUSB_mm1_mm2m64(const X86::Instruction& insn)
  1265. {
  1266. MMX_intrinsic(psubusb, v8, v8);
  1267. }
  1268. void SoftFPU::PSUBUSW_mm1_mm2m64(const X86::Instruction& insn)
  1269. {
  1270. MMX_intrinsic(psubusw, v16, v16);
  1271. }
  1272. void SoftFPU::PMULHW_mm1_mm2m64(const X86::Instruction& insn)
  1273. {
  1274. MMX_intrinsic(pmulhw, v16, v16);
  1275. }
  1276. void SoftFPU::PMULLW_mm1_mm2m64(const X86::Instruction& insn)
  1277. {
  1278. MMX_intrinsic(pmullw, v16, v16);
  1279. }
  1280. void SoftFPU::PMADDWD_mm1_mm2m64(const X86::Instruction& insn)
  1281. {
  1282. MMX_intrinsic(pmaddwd, v32, v16);
  1283. }
  1284. // COMPARISON
  1285. void SoftFPU::PCMPEQB_mm1_mm2m64(const X86::Instruction& insn)
  1286. {
  1287. LOAD_MM_MM64M();
  1288. mm.v8 = mm.v8 == mm64m.v8;
  1289. mmx_set(insn.modrm().reg(), mm);
  1290. mmx_common();
  1291. }
  1292. void SoftFPU::PCMPEQW_mm1_mm2m64(const X86::Instruction& insn)
  1293. {
  1294. LOAD_MM_MM64M();
  1295. mm.v16 = mm.v16 == mm64m.v16;
  1296. mmx_set(insn.modrm().reg(), mm);
  1297. mmx_common();
  1298. }
  1299. void SoftFPU::PCMPEQD_mm1_mm2m64(const X86::Instruction& insn)
  1300. {
  1301. LOAD_MM_MM64M();
  1302. mm.v32 = mm.v32 == mm64m.v32;
  1303. mmx_set(insn.modrm().reg(), mm);
  1304. mmx_common();
  1305. }
  1306. void SoftFPU::PCMPGTB_mm1_mm2m64(const X86::Instruction& insn)
  1307. {
  1308. LOAD_MM_MM64M();
  1309. mm.v8 = mm.v8 > mm64m.v8;
  1310. mmx_set(insn.modrm().reg(), mm);
  1311. mmx_common();
  1312. }
  1313. void SoftFPU::PCMPGTW_mm1_mm2m64(const X86::Instruction& insn)
  1314. {
  1315. LOAD_MM_MM64M();
  1316. mm.v16 = mm.v16 > mm64m.v16;
  1317. mmx_set(insn.modrm().reg(), mm);
  1318. mmx_common();
  1319. }
  1320. void SoftFPU::PCMPGTD_mm1_mm2m64(const X86::Instruction& insn)
  1321. {
  1322. LOAD_MM_MM64M();
  1323. mm.v32 = mm.v32 > mm64m.v32;
  1324. mmx_set(insn.modrm().reg(), mm);
  1325. mmx_common();
  1326. }
  1327. // CONVERSION
  1328. void SoftFPU::PACKSSDW_mm1_mm2m64(const X86::Instruction& insn)
  1329. {
  1330. MMX_intrinsic(packssdw, v16, v32);
  1331. }
  1332. void SoftFPU::PACKSSWB_mm1_mm2m64(const X86::Instruction& insn)
  1333. {
  1334. MMX_intrinsic(packsswb, v8, v16);
  1335. }
  1336. void SoftFPU::PACKUSWB_mm1_mm2m64(const X86::Instruction& insn)
  1337. {
  1338. MMX_intrinsic(packuswb, v8, v16);
  1339. }
  1340. // UNPACK
  1341. void SoftFPU::PUNPCKHBW_mm1_mm2m64(const X86::Instruction& insn)
  1342. {
  1343. MMX_intrinsic(punpckhbw, v8, v8);
  1344. }
  1345. void SoftFPU::PUNPCKHWD_mm1_mm2m64(const X86::Instruction& insn)
  1346. {
  1347. MMX_intrinsic(punpckhwd, v16, v16);
  1348. }
  1349. void SoftFPU::PUNPCKHDQ_mm1_mm2m64(const X86::Instruction& insn)
  1350. {
  1351. MMX_intrinsic(punpckhdq, v32, v32);
  1352. }
  1353. void SoftFPU::PUNPCKLBW_mm1_mm2m32(const X86::Instruction& insn)
  1354. {
  1355. MMX_intrinsic(punpcklbw, v8, v8);
  1356. }
  1357. void SoftFPU::PUNPCKLWD_mm1_mm2m32(const X86::Instruction& insn)
  1358. {
  1359. MMX_intrinsic(punpcklwd, v16, v16);
  1360. }
  1361. void SoftFPU::PUNPCKLDQ_mm1_mm2m32(const X86::Instruction& insn)
  1362. {
  1363. MMX_intrinsic(punpckldq, v32, v32);
  1364. }
  1365. // LOGICAL
  1366. void SoftFPU::PAND_mm1_mm2m64(const X86::Instruction& insn)
  1367. {
  1368. LOAD_MM_MM64M();
  1369. mm.raw &= mm64m.raw;
  1370. mmx_set(insn.modrm().reg(), mm);
  1371. mmx_common();
  1372. }
  1373. void SoftFPU::PANDN_mm1_mm2m64(const X86::Instruction& insn)
  1374. {
  1375. LOAD_MM_MM64M();
  1376. mm.raw &= ~mm64m.raw;
  1377. mmx_set(insn.modrm().reg(), mm);
  1378. mmx_common();
  1379. }
  1380. void SoftFPU::POR_mm1_mm2m64(const X86::Instruction& insn)
  1381. {
  1382. LOAD_MM_MM64M();
  1383. mm.raw |= mm64m.raw;
  1384. mmx_set(insn.modrm().reg(), mm);
  1385. mmx_common();
  1386. }
  1387. void SoftFPU::PXOR_mm1_mm2m64(const X86::Instruction& insn)
  1388. {
  1389. LOAD_MM_MM64M();
  1390. mm.raw ^= mm64m.raw;
  1391. mmx_set(insn.modrm().reg(), mm);
  1392. mmx_common();
  1393. }
  1394. // SHIFT
  1395. void SoftFPU::PSLLW_mm1_mm2m64(const X86::Instruction& insn)
  1396. {
  1397. LOAD_MM_MM64M();
  1398. mm.v16 <<= mm64m.v16;
  1399. mmx_set(insn.modrm().reg(), mm);
  1400. mmx_common();
  1401. }
  1402. void SoftFPU::PSLLW_mm1_imm8(const X86::Instruction& insn)
  1403. {
  1404. u8 imm = insn.imm8();
  1405. MMX mm = mmx_get(insn.modrm().reg());
  1406. mm.v16 <<= imm;
  1407. mmx_set(insn.modrm().reg(), mm);
  1408. mmx_common();
  1409. }
  1410. void SoftFPU::PSLLD_mm1_mm2m64(const X86::Instruction& insn)
  1411. {
  1412. LOAD_MM_MM64M();
  1413. mm.v32 <<= mm64m.v32;
  1414. mmx_set(insn.modrm().reg(), mm);
  1415. mmx_common();
  1416. }
  1417. void SoftFPU::PSLLD_mm1_imm8(const X86::Instruction& insn)
  1418. {
  1419. u8 imm = insn.imm8();
  1420. MMX mm = mmx_get(insn.modrm().reg());
  1421. mm.v32 <<= imm;
  1422. mmx_set(insn.modrm().reg(), mm);
  1423. mmx_common();
  1424. }
  1425. void SoftFPU::PSLLQ_mm1_mm2m64(const X86::Instruction& insn)
  1426. {
  1427. LOAD_MM_MM64M();
  1428. mm.raw <<= mm64m.raw;
  1429. mmx_set(insn.modrm().reg(), mm);
  1430. mmx_common();
  1431. }
  1432. void SoftFPU::PSLLQ_mm1_imm8(const X86::Instruction& insn)
  1433. {
  1434. u8 imm = insn.imm8();
  1435. MMX mm = mmx_get(insn.modrm().reg());
  1436. mm.raw <<= imm;
  1437. mmx_set(insn.modrm().reg(), mm);
  1438. mmx_common();
  1439. }
  1440. void SoftFPU::PSRAW_mm1_mm2m64(const X86::Instruction& insn)
  1441. {
  1442. LOAD_MM_MM64M();
  1443. mm.v16 >>= mm64m.v16;
  1444. mmx_set(insn.modrm().reg(), mm);
  1445. mmx_common();
  1446. }
  1447. void SoftFPU::PSRAW_mm1_imm8(const X86::Instruction& insn)
  1448. {
  1449. u8 imm = insn.imm8();
  1450. MMX mm = mmx_get(insn.modrm().reg());
  1451. mm.v16 >>= imm;
  1452. mmx_set(insn.modrm().reg(), mm);
  1453. mmx_common();
  1454. }
  1455. void SoftFPU::PSRAD_mm1_mm2m64(const X86::Instruction& insn)
  1456. {
  1457. LOAD_MM_MM64M();
  1458. mm.v32 >>= mm64m.v32;
  1459. mmx_set(insn.modrm().reg(), mm);
  1460. mmx_common();
  1461. }
  1462. void SoftFPU::PSRAD_mm1_imm8(const X86::Instruction& insn)
  1463. {
  1464. u8 imm = insn.imm8();
  1465. MMX mm = mmx_get(insn.modrm().reg());
  1466. mm.v32 >>= imm;
  1467. mmx_set(insn.modrm().reg(), mm);
  1468. mmx_common();
  1469. }
  1470. void SoftFPU::PSRLW_mm1_mm2m64(const X86::Instruction& insn)
  1471. {
  1472. LOAD_MM_MM64M();
  1473. mm.v16u >>= mm64m.v16u;
  1474. mmx_set(insn.modrm().reg(), mm);
  1475. mmx_common();
  1476. }
  1477. void SoftFPU::PSRLW_mm1_imm8(const X86::Instruction& insn)
  1478. {
  1479. u8 imm = insn.imm8();
  1480. MMX mm = mmx_get(insn.modrm().reg());
  1481. mm.v16u >>= imm;
  1482. mmx_set(insn.modrm().reg(), mm);
  1483. mmx_common();
  1484. }
  1485. void SoftFPU::PSRLD_mm1_mm2m64(const X86::Instruction& insn)
  1486. {
  1487. LOAD_MM_MM64M();
  1488. mm.v32u >>= mm64m.v32u;
  1489. mmx_set(insn.modrm().reg(), mm);
  1490. mmx_common();
  1491. }
  1492. void SoftFPU::PSRLD_mm1_imm8(const X86::Instruction& insn)
  1493. {
  1494. u8 imm = insn.imm8();
  1495. MMX mm = mmx_get(insn.modrm().reg());
  1496. mm.v32u >>= imm;
  1497. mmx_set(insn.modrm().reg(), mm);
  1498. mmx_common();
  1499. }
  1500. void SoftFPU::PSRLQ_mm1_mm2m64(const X86::Instruction& insn)
  1501. {
  1502. LOAD_MM_MM64M();
  1503. mm.raw >>= mm64m.raw;
  1504. mmx_set(insn.modrm().reg(), mm);
  1505. mmx_common();
  1506. }
  1507. void SoftFPU::PSRLQ_mm1_imm8(const X86::Instruction& insn)
  1508. {
  1509. u8 imm = insn.imm8();
  1510. MMX mm = mmx_get(insn.modrm().reg());
  1511. mm.raw >>= imm;
  1512. mmx_set(insn.modrm().reg(), mm);
  1513. mmx_common();
  1514. }
  1515. // DATA TRANSFER
  1516. void SoftFPU::MOVD_mm1_rm32(const X86::Instruction& insn)
  1517. {
  1518. u8 mmx_index = insn.modrm().reg();
  1519. // FIXME:: Shadow Value
  1520. // upper half is zeroed out
  1521. mmx_set(mmx_index, { .raw = insn.modrm().read32(m_cpu, insn).value() });
  1522. mmx_common();
  1523. };
  1524. void SoftFPU::MOVD_rm32_mm2(const X86::Instruction& insn)
  1525. {
  1526. u8 mmx_index = insn.modrm().reg();
  1527. // FIXME:: Shadow Value
  1528. insn.modrm().write32(m_cpu, insn,
  1529. shadow_wrap_as_initialized(static_cast<u32>(mmx_get(mmx_index).raw)));
  1530. mmx_common();
  1531. };
  1532. void SoftFPU::MOVQ_mm1_mm2m64(const X86::Instruction& insn)
  1533. {
  1534. // FIXME: Shadow Value
  1535. if (insn.modrm().mod() == 0b11) {
  1536. // instruction
  1537. mmx_set(insn.modrm().reg(),
  1538. mmx_get(insn.modrm().rm()));
  1539. } else {
  1540. mmx_set(insn.modrm().reg(),
  1541. { .raw = insn.modrm().read64(m_cpu, insn).value() });
  1542. }
  1543. mmx_common();
  1544. }
  1545. void SoftFPU::MOVQ_mm1m64_mm2(const X86::Instruction& insn)
  1546. {
  1547. if (insn.modrm().mod() == 0b11) {
  1548. // instruction
  1549. mmx_set(insn.modrm().rm(),
  1550. mmx_get(insn.modrm().reg()));
  1551. } else {
  1552. // FIXME: Shadow Value
  1553. insn.modrm().write64(m_cpu, insn,
  1554. shadow_wrap_as_initialized(mmx_get(insn.modrm().reg()).raw));
  1555. }
  1556. mmx_common();
  1557. }
  1558. void SoftFPU::MOVQ_mm1_rm64(const X86::Instruction&) { TODO_INSN(); }; // long mode
  1559. void SoftFPU::MOVQ_rm64_mm2(const X86::Instruction&) { TODO_INSN(); }; // long mode
  1560. // EMPTY MMX STATE
  1561. void SoftFPU::EMMS(const X86::Instruction&)
  1562. {
  1563. // clear tagword
  1564. m_fpu_tw = 0xFFFF;
  1565. }
  1566. }