PageRenderTime 56ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp

https://github.com/bunnei/dolphin
C++ | 485 lines | 422 code | 38 blank | 25 comment | 100 complexity | 7726d8c452b7a7b8d840ee1f3a901985 MD5 | raw file
Possible License(s): GPL-2.0
  1. // Copyright 2013 Dolphin Emulator Project
  2. // Licensed under GPLv2
  3. // Refer to the license.txt file included.
  4. #include <cmath>
  5. #include <limits>
  6. #ifdef _WIN32
  7. #define _interlockedbittestandset workaround_ms_header_bug_platform_sdk6_set
  8. #define _interlockedbittestandreset workaround_ms_header_bug_platform_sdk6_reset
  9. #define _interlockedbittestandset64 workaround_ms_header_bug_platform_sdk6_set64
  10. #define _interlockedbittestandreset64 workaround_ms_header_bug_platform_sdk6_reset64
  11. #include <intrin.h>
  12. #undef _interlockedbittestandset
  13. #undef _interlockedbittestandreset
  14. #undef _interlockedbittestandset64
  15. #undef _interlockedbittestandreset64
  16. #endif
  17. #include "Common/MathUtil.h"
  18. #include "Core/PowerPC/Interpreter/Interpreter.h"
  19. #include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h"
  20. using namespace MathUtil;
  21. void UpdateSSEState();
  22. // Extremely rare - actually, never seen.
  23. // Star Wars : Rogue Leader spams that at some point :|
  24. void Interpreter::Helper_UpdateCR1()
  25. {
  26. SetCRField(1, (FPSCR.FX << 4) | (FPSCR.FEX << 3) | (FPSCR.VX << 2) | FPSCR.OX);
  27. }
  28. void Interpreter::Helper_FloatCompareOrdered(UGeckoInstruction _inst, double fa, double fb)
  29. {
  30. int compareResult;
  31. if (fa < fb)
  32. {
  33. compareResult = FPCC::FL;
  34. }
  35. else if (fa > fb)
  36. {
  37. compareResult = FPCC::FG;
  38. }
  39. else if (fa == fb)
  40. {
  41. compareResult = FPCC::FE;
  42. }
  43. else // NaN
  44. {
  45. FPSCR.FX = 1;
  46. compareResult = FPCC::FU;
  47. if (IsSNAN(fa) || IsSNAN(fb))
  48. {
  49. SetFPException(FPSCR_VXSNAN);
  50. if (FPSCR.VE == 0)
  51. {
  52. SetFPException(FPSCR_VXVC);
  53. }
  54. }
  55. else // QNaN
  56. {
  57. SetFPException(FPSCR_VXVC);
  58. }
  59. }
  60. FPSCR.FPRF = compareResult;
  61. SetCRField(_inst.CRFD, compareResult);
  62. }
  63. void Interpreter::Helper_FloatCompareUnordered(UGeckoInstruction _inst, double fa, double fb)
  64. {
  65. int compareResult;
  66. if (fa < fb)
  67. {
  68. compareResult = FPCC::FL;
  69. }
  70. else if (fa > fb)
  71. {
  72. compareResult = FPCC::FG;
  73. }
  74. else if (fa == fb)
  75. {
  76. compareResult = FPCC::FE;
  77. }
  78. else
  79. {
  80. compareResult = FPCC::FU;
  81. if (IsSNAN(fa) || IsSNAN(fb))
  82. {
  83. FPSCR.FX = 1;
  84. SetFPException(FPSCR_VXSNAN);
  85. }
  86. }
  87. FPSCR.FPRF = compareResult;
  88. SetCRField(_inst.CRFD, compareResult);
  89. }
  90. void Interpreter::fcmpo(UGeckoInstruction _inst)
  91. {
  92. Helper_FloatCompareOrdered(_inst, rPS0(_inst.FA), rPS0(_inst.FB));
  93. }
  94. void Interpreter::fcmpu(UGeckoInstruction _inst)
  95. {
  96. Helper_FloatCompareUnordered(_inst, rPS0(_inst.FA), rPS0(_inst.FB));
  97. }
  98. // Apply current rounding mode
  99. void Interpreter::fctiwx(UGeckoInstruction _inst)
  100. {
  101. const double b = rPS0(_inst.FB);
  102. u32 value;
  103. if (b > (double)0x7fffffff)
  104. {
  105. value = 0x7fffffff;
  106. SetFPException(FPSCR_VXCVI);
  107. FPSCR.FI = 0;
  108. FPSCR.FR = 0;
  109. }
  110. else if (b < -(double)0x80000000)
  111. {
  112. value = 0x80000000;
  113. SetFPException(FPSCR_VXCVI);
  114. FPSCR.FI = 0;
  115. FPSCR.FR = 0;
  116. }
  117. else
  118. {
  119. s32 i = 0;
  120. switch (FPSCR.RN)
  121. {
  122. case 0: // nearest
  123. {
  124. double t = b + 0.5;
  125. i = (s32)t;
  126. if (t - i < 0 || (t - i == 0 && b > 0)) i--;
  127. break;
  128. }
  129. case 1: // zero
  130. i = (s32)b;
  131. break;
  132. case 2: // +inf
  133. i = (s32)b;
  134. if (b - i > 0) i++;
  135. break;
  136. case 3: // -inf
  137. i = (s32)b;
  138. if (b - i < 0) i--;
  139. break;
  140. }
  141. value = (u32)i;
  142. double di = i;
  143. if (di == b)
  144. {
  145. FPSCR.FI = 0;
  146. FPSCR.FR = 0;
  147. }
  148. else
  149. {
  150. SetFI(1);
  151. FPSCR.FR = fabs(di) > fabs(b);
  152. }
  153. }
  154. // based on HW tests
  155. // FPRF is not affected
  156. riPS0(_inst.FD) = 0xfff8000000000000ull | value;
  157. if (value == 0 && ( (*(u64*)&b) & DOUBLE_SIGN ))
  158. riPS0(_inst.FD) |= 0x100000000ull;
  159. if (_inst.Rc)
  160. Helper_UpdateCR1();
  161. }
  162. // Always round toward zero
  163. void Interpreter::fctiwzx(UGeckoInstruction _inst)
  164. {
  165. const double b = rPS0(_inst.FB);
  166. u32 value;
  167. if (b > (double)0x7fffffff)
  168. {
  169. value = 0x7fffffff;
  170. SetFPException(FPSCR_VXCVI);
  171. FPSCR.FI = 0;
  172. FPSCR.FR = 0;
  173. }
  174. else if (b < -(double)0x80000000)
  175. {
  176. value = 0x80000000;
  177. SetFPException(FPSCR_VXCVI);
  178. FPSCR.FI = 0;
  179. FPSCR.FR = 0;
  180. }
  181. else
  182. {
  183. s32 i = (s32)b;
  184. double di = i;
  185. if (di == b)
  186. {
  187. FPSCR.FI = 0;
  188. FPSCR.FR = 0;
  189. }
  190. else
  191. {
  192. SetFI(1);
  193. FPSCR.FR = fabs(di) > fabs(b);
  194. }
  195. value = (u32)i;
  196. }
  197. // based on HW tests
  198. // FPRF is not affected
  199. riPS0(_inst.FD) = 0xfff8000000000000ull | value;
  200. if (value == 0 && ( (*(u64*)&b) & DOUBLE_SIGN ))
  201. riPS0(_inst.FD) |= 0x100000000ull;
  202. if (_inst.Rc)
  203. Helper_UpdateCR1();
  204. }
  205. void Interpreter::fmrx(UGeckoInstruction _inst)
  206. {
  207. riPS0(_inst.FD) = riPS0(_inst.FB);
  208. // This is a binary instruction. Does not alter FPSCR
  209. if (_inst.Rc) Helper_UpdateCR1();
  210. }
  211. void Interpreter::fabsx(UGeckoInstruction _inst)
  212. {
  213. rPS0(_inst.FD) = fabs(rPS0(_inst.FB));
  214. // This is a binary instruction. Does not alter FPSCR
  215. if (_inst.Rc) Helper_UpdateCR1();
  216. }
  217. void Interpreter::fnabsx(UGeckoInstruction _inst)
  218. {
  219. riPS0(_inst.FD) = riPS0(_inst.FB) | (1ULL << 63);
  220. // This is a binary instruction. Does not alter FPSCR
  221. if (_inst.Rc) Helper_UpdateCR1();
  222. }
  223. void Interpreter::fnegx(UGeckoInstruction _inst)
  224. {
  225. riPS0(_inst.FD) = riPS0(_inst.FB) ^ (1ULL << 63);
  226. // This is a binary instruction. Does not alter FPSCR
  227. if (_inst.Rc) Helper_UpdateCR1();
  228. }
  229. void Interpreter::fselx(UGeckoInstruction _inst)
  230. {
  231. rPS0(_inst.FD) = (rPS0(_inst.FA) >= -0.0) ? rPS0(_inst.FC) : rPS0(_inst.FB);
  232. // This is a binary instruction. Does not alter FPSCR
  233. if (_inst.Rc) Helper_UpdateCR1();
  234. }
  235. // !!! warning !!!
  236. // PS1 must be set to the value of PS0 or DragonballZ will be f**ked up
  237. // PS1 is said to be undefined
  238. void Interpreter::frspx(UGeckoInstruction _inst) // round to single
  239. {
  240. double b = rPS0(_inst.FB);
  241. double rounded = ForceSingle(b);
  242. SetFI(b != rounded);
  243. FPSCR.FR = fabs(rounded) > fabs(b);
  244. UpdateFPRF(rounded);
  245. rPS0(_inst.FD) = rPS1(_inst.FD) = rounded;
  246. return;
  247. }
  248. void Interpreter::fmulx(UGeckoInstruction _inst)
  249. {
  250. rPS0(_inst.FD) = ForceDouble(NI_mul(rPS0(_inst.FA), rPS0(_inst.FC)));
  251. FPSCR.FI = 0; // are these flags important?
  252. FPSCR.FR = 0;
  253. UpdateFPRF(rPS0(_inst.FD));
  254. if (_inst.Rc) Helper_UpdateCR1();
  255. }
  256. void Interpreter::fmulsx(UGeckoInstruction _inst)
  257. {
  258. double d_value = NI_mul(rPS0(_inst.FA), rPS0(_inst.FC));
  259. rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(d_value);
  260. //FPSCR.FI = d_value != rPS0(_inst.FD);
  261. FPSCR.FI = 0;
  262. FPSCR.FR = 0;
  263. UpdateFPRF(rPS0(_inst.FD));
  264. if (_inst.Rc) Helper_UpdateCR1();
  265. }
  266. void Interpreter::fmaddx(UGeckoInstruction _inst)
  267. {
  268. double result = ForceDouble(NI_madd( rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB) ));
  269. rPS0(_inst.FD) = result;
  270. UpdateFPRF(result);
  271. if (_inst.Rc) Helper_UpdateCR1();
  272. }
  273. void Interpreter::fmaddsx(UGeckoInstruction _inst)
  274. {
  275. double d_value = NI_madd( rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB) );
  276. rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(d_value);
  277. FPSCR.FI = d_value != rPS0(_inst.FD);
  278. FPSCR.FR = 0;
  279. UpdateFPRF(rPS0(_inst.FD));
  280. if (_inst.Rc) Helper_UpdateCR1();
  281. }
  282. void Interpreter::faddx(UGeckoInstruction _inst)
  283. {
  284. rPS0(_inst.FD) = ForceDouble(NI_add(rPS0(_inst.FA), rPS0(_inst.FB)));
  285. UpdateFPRF(rPS0(_inst.FD));
  286. if (_inst.Rc) Helper_UpdateCR1();
  287. }
  288. void Interpreter::faddsx(UGeckoInstruction _inst)
  289. {
  290. rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(NI_add(rPS0(_inst.FA), rPS0(_inst.FB)));
  291. UpdateFPRF(rPS0(_inst.FD));
  292. if (_inst.Rc) Helper_UpdateCR1();
  293. }
  294. void Interpreter::fdivx(UGeckoInstruction _inst)
  295. {
  296. double a = rPS0(_inst.FA);
  297. double b = rPS0(_inst.FB);
  298. if (a != a) rPS0(_inst.FD) = a;
  299. else if (b != b) rPS0(_inst.FD) = b;
  300. else
  301. {
  302. rPS0(_inst.FD) = ForceDouble(a / b);
  303. if (b == 0.0)
  304. {
  305. if (a == 0.0)
  306. {
  307. SetFPException(FPSCR_VXZDZ);
  308. rPS0(_inst.FD) = PPC_NAN;
  309. }
  310. SetFPException(FPSCR_ZX);
  311. }
  312. else
  313. {
  314. if (IsINF(a) && IsINF(b))
  315. {
  316. SetFPException(FPSCR_VXIDI);
  317. rPS0(_inst.FD) = PPC_NAN;
  318. }
  319. }
  320. }
  321. UpdateFPRF(rPS0(_inst.FD));
  322. // FR,FI,OX,UX???
  323. if (_inst.Rc) Helper_UpdateCR1();
  324. }
  325. void Interpreter::fdivsx(UGeckoInstruction _inst)
  326. {
  327. double a = rPS0(_inst.FA);
  328. double b = rPS0(_inst.FB);
  329. double res;
  330. if (a != a) res = a;
  331. else if (b != b) res = b;
  332. else
  333. {
  334. res = ForceSingle(a / b);
  335. if (b == 0.0)
  336. {
  337. if (a == 0.0)
  338. {
  339. SetFPException(FPSCR_VXZDZ);
  340. res = PPC_NAN;
  341. }
  342. SetFPException(FPSCR_ZX);
  343. }
  344. else
  345. {
  346. if (IsINF(a) && IsINF(b))
  347. {
  348. SetFPException(FPSCR_VXIDI);
  349. res = PPC_NAN;
  350. }
  351. }
  352. }
  353. rPS0(_inst.FD) = rPS1(_inst.FD) = res;
  354. UpdateFPRF(rPS0(_inst.FD));
  355. if (_inst.Rc) Helper_UpdateCR1();
  356. }
  357. // Single precision only.
  358. void Interpreter::fresx(UGeckoInstruction _inst)
  359. {
  360. double b = rPS0(_inst.FB);
  361. rPS0(_inst.FD) = rPS1(_inst.FD) = ApproximateReciprocal(b);
  362. if (b == 0.0)
  363. {
  364. SetFPException(FPSCR_ZX);
  365. }
  366. UpdateFPRF(rPS0(_inst.FD));
  367. if (_inst.Rc) Helper_UpdateCR1();
  368. }
  369. void Interpreter::frsqrtex(UGeckoInstruction _inst)
  370. {
  371. double b = rPS0(_inst.FB);
  372. if (b < 0.0)
  373. {
  374. SetFPException(FPSCR_VXSQRT);
  375. }
  376. else if (b == 0.0)
  377. {
  378. SetFPException(FPSCR_ZX);
  379. }
  380. rPS0(_inst.FD) = ApproximateReciprocalSquareRoot(b);
  381. UpdateFPRF(rPS0(_inst.FD));
  382. if (_inst.Rc) Helper_UpdateCR1();
  383. }
  384. void Interpreter::fmsubx(UGeckoInstruction _inst)
  385. {
  386. rPS0(_inst.FD) = ForceDouble(NI_msub( rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB) ));
  387. UpdateFPRF(rPS0(_inst.FD));
  388. if (_inst.Rc) Helper_UpdateCR1();
  389. }
  390. void Interpreter::fmsubsx(UGeckoInstruction _inst)
  391. {
  392. rPS0(_inst.FD) = rPS1(_inst.FD) =
  393. ForceSingle( NI_msub(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB) ));
  394. UpdateFPRF(rPS0(_inst.FD));
  395. if (_inst.Rc) Helper_UpdateCR1();
  396. }
  397. void Interpreter::fnmaddx(UGeckoInstruction _inst)
  398. {
  399. rPS0(_inst.FD) = ForceDouble(-NI_madd(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB)));
  400. UpdateFPRF(rPS0(_inst.FD));
  401. if (_inst.Rc) Helper_UpdateCR1();
  402. }
  403. void Interpreter::fnmaddsx(UGeckoInstruction _inst)
  404. {
  405. rPS0(_inst.FD) = rPS1(_inst.FD) =
  406. ForceSingle(-NI_madd(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB)));
  407. UpdateFPRF(rPS0(_inst.FD));
  408. if (_inst.Rc) Helper_UpdateCR1();
  409. }
  410. void Interpreter::fnmsubx(UGeckoInstruction _inst)
  411. {
  412. rPS0(_inst.FD) = ForceDouble(-NI_msub(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB)));
  413. UpdateFPRF(rPS0(_inst.FD));
  414. if (_inst.Rc) Helper_UpdateCR1();
  415. }
  416. // fnmsubsx does not handle QNAN properly - see NI_msub
  417. void Interpreter::fnmsubsx(UGeckoInstruction _inst)
  418. {
  419. rPS0(_inst.FD) = rPS1(_inst.FD) =
  420. ForceSingle(-NI_msub(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB)));
  421. UpdateFPRF(rPS0(_inst.FD));
  422. if (_inst.Rc) Helper_UpdateCR1();
  423. }
  424. void Interpreter::fsubx(UGeckoInstruction _inst)
  425. {
  426. rPS0(_inst.FD) = ForceDouble(NI_sub(rPS0(_inst.FA), rPS0(_inst.FB)));
  427. UpdateFPRF(rPS0(_inst.FD));
  428. if (_inst.Rc) Helper_UpdateCR1();
  429. }
  430. void Interpreter::fsubsx(UGeckoInstruction _inst)
  431. {
  432. rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(NI_sub(rPS0(_inst.FA), rPS0(_inst.FB)));
  433. UpdateFPRF(rPS0(_inst.FD));
  434. if (_inst.Rc) Helper_UpdateCR1();
  435. }
  436. void Interpreter::fsqrtx(UGeckoInstruction _inst)
  437. {
  438. // GEKKO is not supposed to support this instruction.
  439. // PanicAlert("fsqrtx");
  440. double b = rPS0(_inst.FB);
  441. if (b < 0.0) {
  442. FPSCR.VXSQRT = 1;
  443. }
  444. rPS0(_inst.FD) = sqrt(b);
  445. UpdateFPRF(rPS0(_inst.FD));
  446. if (_inst.Rc) Helper_UpdateCR1();
  447. }