1 // Copyright 2008 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4
5 #include <cmath>
6 #include <limits>
7
8 #include "Common/CommonTypes.h"
9 #include "Common/FloatUtils.h"
10 #include "Core/PowerPC/Interpreter/Interpreter.h"
11 #include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h"
12 #include "Core/PowerPC/PowerPC.h"
13
14 namespace
15 {
16 // Apply current rounding mode
17 enum class RoundingMode
18 {
19 Nearest = 0b00,
20 TowardsZero = 0b01,
21 TowardsPositiveInfinity = 0b10,
22 TowardsNegativeInfinity = 0b11
23 };
24
SetFI(UReg_FPSCR * fpscr,int FI)25 static void SetFI(UReg_FPSCR* fpscr, int FI)
26 {
27 if (FI)
28 {
29 SetFPException(fpscr, FPSCR_XX);
30 }
31 fpscr->FI = FI;
32 }
33
34 // Note that the convert to integer operation is defined
35 // in Appendix C.4.2 in PowerPC Microprocessor Family:
36 // The Programming Environments Manual for 32 and 64-bit Microprocessors
ConvertToInteger(UGeckoInstruction inst,RoundingMode rounding_mode)37 void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode)
38 {
39 const double b = rPS(inst.FB).PS0AsDouble();
40 u32 value;
41 bool exception_occurred = false;
42
43 if (std::isnan(b))
44 {
45 if (Common::IsSNAN(b))
46 SetFPException(&FPSCR, FPSCR_VXSNAN);
47
48 value = 0x80000000;
49 SetFPException(&FPSCR, FPSCR_VXCVI);
50 exception_occurred = true;
51 }
52 else if (b > static_cast<double>(0x7fffffff))
53 {
54 // Positive large operand or +inf
55 value = 0x7fffffff;
56 SetFPException(&FPSCR, FPSCR_VXCVI);
57 exception_occurred = true;
58 }
59 else if (b < -static_cast<double>(0x80000000))
60 {
61 // Negative large operand or -inf
62 value = 0x80000000;
63 SetFPException(&FPSCR, FPSCR_VXCVI);
64 exception_occurred = true;
65 }
66 else
67 {
68 s32 i = 0;
69 switch (rounding_mode)
70 {
71 case RoundingMode::Nearest:
72 {
73 const double t = b + 0.5;
74 i = static_cast<s32>(t);
75
76 if (t - i < 0 || (t - i == 0 && b > 0))
77 {
78 i--;
79 }
80 break;
81 }
82 case RoundingMode::TowardsZero:
83 i = static_cast<s32>(b);
84 break;
85 case RoundingMode::TowardsPositiveInfinity:
86 i = static_cast<s32>(b);
87 if (b - i > 0)
88 {
89 i++;
90 }
91 break;
92 case RoundingMode::TowardsNegativeInfinity:
93 i = static_cast<s32>(b);
94 if (b - i < 0)
95 {
96 i--;
97 }
98 break;
99 }
100 value = static_cast<u32>(i);
101 const double di = i;
102 if (di == b)
103 {
104 FPSCR.ClearFIFR();
105 }
106 else
107 {
108 // Also sets FPSCR[XX]
109 SetFI(&FPSCR, 1);
110 FPSCR.FR = fabs(di) > fabs(b);
111 }
112 }
113
114 if (exception_occurred)
115 {
116 FPSCR.ClearFIFR();
117 }
118
119 if (!exception_occurred || FPSCR.VE == 0)
120 {
121 // Based on HW tests
122 // FPRF is not affected
123 u64 result = 0xfff8000000000000ull | value;
124 if (value == 0 && std::signbit(b))
125 result |= 0x100000000ull;
126
127 rPS(inst.FD).SetPS0(result);
128 }
129
130 if (inst.Rc)
131 PowerPC::ppcState.UpdateCR1();
132 }
133 } // Anonymous namespace
134
Helper_FloatCompareOrdered(UGeckoInstruction inst,double fa,double fb)135 void Interpreter::Helper_FloatCompareOrdered(UGeckoInstruction inst, double fa, double fb)
136 {
137 FPCC compare_result;
138
139 if (std::isnan(fa) || std::isnan(fb))
140 {
141 compare_result = FPCC::FU;
142 if (Common::IsSNAN(fa) || Common::IsSNAN(fb))
143 {
144 SetFPException(&FPSCR, FPSCR_VXSNAN);
145 if (FPSCR.VE == 0)
146 {
147 SetFPException(&FPSCR, FPSCR_VXVC);
148 }
149 }
150 else // QNaN
151 {
152 SetFPException(&FPSCR, FPSCR_VXVC);
153 }
154 }
155 else if (fa < fb)
156 {
157 compare_result = FPCC::FL;
158 }
159 else if (fa > fb)
160 {
161 compare_result = FPCC::FG;
162 }
163 else // Equals
164 {
165 compare_result = FPCC::FE;
166 }
167
168 const u32 compare_value = static_cast<u32>(compare_result);
169
170 // Clear and set the FPCC bits accordingly.
171 FPSCR.FPRF = (FPSCR.FPRF & ~0xF) | compare_value;
172
173 PowerPC::ppcState.cr.SetField(inst.CRFD, compare_value);
174 }
175
Helper_FloatCompareUnordered(UGeckoInstruction inst,double fa,double fb)176 void Interpreter::Helper_FloatCompareUnordered(UGeckoInstruction inst, double fa, double fb)
177 {
178 FPCC compare_result;
179
180 if (std::isnan(fa) || std::isnan(fb))
181 {
182 compare_result = FPCC::FU;
183
184 if (Common::IsSNAN(fa) || Common::IsSNAN(fb))
185 {
186 SetFPException(&FPSCR, FPSCR_VXSNAN);
187 }
188 }
189 else if (fa < fb)
190 {
191 compare_result = FPCC::FL;
192 }
193 else if (fa > fb)
194 {
195 compare_result = FPCC::FG;
196 }
197 else // Equals
198 {
199 compare_result = FPCC::FE;
200 }
201
202 const u32 compare_value = static_cast<u32>(compare_result);
203
204 // Clear and set the FPCC bits accordingly.
205 FPSCR.FPRF = (FPSCR.FPRF & ~0xF) | compare_value;
206
207 PowerPC::ppcState.cr.SetField(inst.CRFD, compare_value);
208 }
209
fcmpo(UGeckoInstruction inst)210 void Interpreter::fcmpo(UGeckoInstruction inst)
211 {
212 const auto& a = rPS(inst.FA);
213 const auto& b = rPS(inst.FB);
214
215 Helper_FloatCompareOrdered(inst, a.PS0AsDouble(), b.PS0AsDouble());
216 }
217
fcmpu(UGeckoInstruction inst)218 void Interpreter::fcmpu(UGeckoInstruction inst)
219 {
220 const auto& a = rPS(inst.FA);
221 const auto& b = rPS(inst.FB);
222
223 Helper_FloatCompareUnordered(inst, a.PS0AsDouble(), b.PS0AsDouble());
224 }
225
fctiwx(UGeckoInstruction inst)226 void Interpreter::fctiwx(UGeckoInstruction inst)
227 {
228 ConvertToInteger(inst, static_cast<RoundingMode>(FPSCR.RN));
229 }
230
fctiwzx(UGeckoInstruction inst)231 void Interpreter::fctiwzx(UGeckoInstruction inst)
232 {
233 ConvertToInteger(inst, RoundingMode::TowardsZero);
234 }
235
fmrx(UGeckoInstruction inst)236 void Interpreter::fmrx(UGeckoInstruction inst)
237 {
238 rPS(inst.FD).SetPS0(rPS(inst.FB).PS0AsU64());
239
240 // This is a binary instruction. Does not alter FPSCR
241 if (inst.Rc)
242 PowerPC::ppcState.UpdateCR1();
243 }
244
fabsx(UGeckoInstruction inst)245 void Interpreter::fabsx(UGeckoInstruction inst)
246 {
247 rPS(inst.FD).SetPS0(fabs(rPS(inst.FB).PS0AsDouble()));
248
249 // This is a binary instruction. Does not alter FPSCR
250 if (inst.Rc)
251 PowerPC::ppcState.UpdateCR1();
252 }
253
fnabsx(UGeckoInstruction inst)254 void Interpreter::fnabsx(UGeckoInstruction inst)
255 {
256 rPS(inst.FD).SetPS0(rPS(inst.FB).PS0AsU64() | (UINT64_C(1) << 63));
257
258 // This is a binary instruction. Does not alter FPSCR
259 if (inst.Rc)
260 PowerPC::ppcState.UpdateCR1();
261 }
262
fnegx(UGeckoInstruction inst)263 void Interpreter::fnegx(UGeckoInstruction inst)
264 {
265 rPS(inst.FD).SetPS0(rPS(inst.FB).PS0AsU64() ^ (UINT64_C(1) << 63));
266
267 // This is a binary instruction. Does not alter FPSCR
268 if (inst.Rc)
269 PowerPC::ppcState.UpdateCR1();
270 }
271
fselx(UGeckoInstruction inst)272 void Interpreter::fselx(UGeckoInstruction inst)
273 {
274 const auto& a = rPS(inst.FA);
275 const auto& b = rPS(inst.FB);
276 const auto& c = rPS(inst.FC);
277
278 rPS(inst.FD).SetPS0((a.PS0AsDouble() >= -0.0) ? c.PS0AsDouble() : b.PS0AsDouble());
279
280 // This is a binary instruction. Does not alter FPSCR
281 if (inst.Rc)
282 PowerPC::ppcState.UpdateCR1();
283 }
284
285 // !!! warning !!!
286 // PS1 must be set to the value of PS0 or DragonballZ will be f**ked up
287 // PS1 is said to be undefined
frspx(UGeckoInstruction inst)288 void Interpreter::frspx(UGeckoInstruction inst) // round to single
289 {
290 const double b = rPS(inst.FB).PS0AsDouble();
291 const double rounded = ForceSingle(FPSCR, b);
292
293 if (std::isnan(b))
294 {
295 const bool is_snan = Common::IsSNAN(b);
296
297 if (is_snan)
298 SetFPException(&FPSCR, FPSCR_VXSNAN);
299
300 if (!is_snan || FPSCR.VE == 0)
301 {
302 rPS(inst.FD).Fill(rounded);
303 PowerPC::UpdateFPRF(b);
304 }
305
306 FPSCR.ClearFIFR();
307 }
308 else
309 {
310 SetFI(&FPSCR, b != rounded);
311 FPSCR.FR = fabs(rounded) > fabs(b);
312 PowerPC::UpdateFPRF(rounded);
313 rPS(inst.FD).Fill(rounded);
314 }
315
316 if (inst.Rc)
317 PowerPC::ppcState.UpdateCR1();
318 }
319
fmulx(UGeckoInstruction inst)320 void Interpreter::fmulx(UGeckoInstruction inst)
321 {
322 const auto& a = rPS(inst.FA);
323 const auto& c = rPS(inst.FC);
324
325 const FPResult product = NI_mul(&FPSCR, a.PS0AsDouble(), c.PS0AsDouble());
326
327 if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
328 {
329 const double result = ForceDouble(FPSCR, product.value);
330
331 rPS(inst.FD).SetPS0(result);
332 FPSCR.FI = 0; // are these flags important?
333 FPSCR.FR = 0;
334 PowerPC::UpdateFPRF(result);
335 }
336
337 if (inst.Rc)
338 PowerPC::ppcState.UpdateCR1();
339 }
fmulsx(UGeckoInstruction inst)340 void Interpreter::fmulsx(UGeckoInstruction inst)
341 {
342 const auto& a = rPS(inst.FA);
343 const auto& c = rPS(inst.FC);
344
345 const double c_value = Force25Bit(c.PS0AsDouble());
346 const FPResult d_value = NI_mul(&FPSCR, a.PS0AsDouble(), c_value);
347
348 if (FPSCR.VE == 0 || d_value.HasNoInvalidExceptions())
349 {
350 const double result = ForceSingle(FPSCR, d_value.value);
351
352 rPS(inst.FD).Fill(result);
353 FPSCR.FI = 0;
354 FPSCR.FR = 0;
355 PowerPC::UpdateFPRF(result);
356 }
357
358 if (inst.Rc)
359 PowerPC::ppcState.UpdateCR1();
360 }
361
fmaddx(UGeckoInstruction inst)362 void Interpreter::fmaddx(UGeckoInstruction inst)
363 {
364 const auto& a = rPS(inst.FA);
365 const auto& b = rPS(inst.FB);
366 const auto& c = rPS(inst.FC);
367 const FPResult product = NI_madd(&FPSCR, a.PS0AsDouble(), c.PS0AsDouble(), b.PS0AsDouble());
368
369 if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
370 {
371 const double result = ForceDouble(FPSCR, product.value);
372 rPS(inst.FD).SetPS0(result);
373 PowerPC::UpdateFPRF(result);
374 }
375
376 if (inst.Rc)
377 PowerPC::ppcState.UpdateCR1();
378 }
379
fmaddsx(UGeckoInstruction inst)380 void Interpreter::fmaddsx(UGeckoInstruction inst)
381 {
382 const auto& a = rPS(inst.FA);
383 const auto& b = rPS(inst.FB);
384 const auto& c = rPS(inst.FC);
385
386 const double c_value = Force25Bit(c.PS0AsDouble());
387 const FPResult d_value = NI_madd(&FPSCR, a.PS0AsDouble(), c_value, b.PS0AsDouble());
388
389 if (FPSCR.VE == 0 || d_value.HasNoInvalidExceptions())
390 {
391 const double result = ForceSingle(FPSCR, d_value.value);
392
393 rPS(inst.FD).Fill(result);
394 FPSCR.FI = d_value.value != result;
395 FPSCR.FR = 0;
396 PowerPC::UpdateFPRF(result);
397 }
398
399 if (inst.Rc)
400 PowerPC::ppcState.UpdateCR1();
401 }
402
faddx(UGeckoInstruction inst)403 void Interpreter::faddx(UGeckoInstruction inst)
404 {
405 const auto& a = rPS(inst.FA);
406 const auto& b = rPS(inst.FB);
407
408 const FPResult sum = NI_add(&FPSCR, a.PS0AsDouble(), b.PS0AsDouble());
409
410 if (FPSCR.VE == 0 || sum.HasNoInvalidExceptions())
411 {
412 const double result = ForceDouble(FPSCR, sum.value);
413 rPS(inst.FD).SetPS0(result);
414 PowerPC::UpdateFPRF(result);
415 }
416
417 if (inst.Rc)
418 PowerPC::ppcState.UpdateCR1();
419 }
faddsx(UGeckoInstruction inst)420 void Interpreter::faddsx(UGeckoInstruction inst)
421 {
422 const auto& a = rPS(inst.FA);
423 const auto& b = rPS(inst.FB);
424
425 const FPResult sum = NI_add(&FPSCR, a.PS0AsDouble(), b.PS0AsDouble());
426
427 if (FPSCR.VE == 0 || sum.HasNoInvalidExceptions())
428 {
429 const double result = ForceSingle(FPSCR, sum.value);
430 rPS(inst.FD).Fill(result);
431 PowerPC::UpdateFPRF(result);
432 }
433
434 if (inst.Rc)
435 PowerPC::ppcState.UpdateCR1();
436 }
437
fdivx(UGeckoInstruction inst)438 void Interpreter::fdivx(UGeckoInstruction inst)
439 {
440 const auto& a = rPS(inst.FA);
441 const auto& b = rPS(inst.FB);
442
443 const FPResult quotient = NI_div(&FPSCR, a.PS0AsDouble(), b.PS0AsDouble());
444 const bool not_divide_by_zero = FPSCR.ZE == 0 || quotient.exception != FPSCR_ZX;
445 const bool not_invalid = FPSCR.VE == 0 || quotient.HasNoInvalidExceptions();
446
447 if (not_divide_by_zero && not_invalid)
448 {
449 const double result = ForceDouble(FPSCR, quotient.value);
450 rPS(inst.FD).SetPS0(result);
451 PowerPC::UpdateFPRF(result);
452 }
453
454 // FR,FI,OX,UX???
455 if (inst.Rc)
456 PowerPC::ppcState.UpdateCR1();
457 }
fdivsx(UGeckoInstruction inst)458 void Interpreter::fdivsx(UGeckoInstruction inst)
459 {
460 const auto& a = rPS(inst.FA);
461 const auto& b = rPS(inst.FB);
462
463 const FPResult quotient = NI_div(&FPSCR, a.PS0AsDouble(), b.PS0AsDouble());
464 const bool not_divide_by_zero = FPSCR.ZE == 0 || quotient.exception != FPSCR_ZX;
465 const bool not_invalid = FPSCR.VE == 0 || quotient.HasNoInvalidExceptions();
466
467 if (not_divide_by_zero && not_invalid)
468 {
469 const double result = ForceSingle(FPSCR, quotient.value);
470 rPS(inst.FD).Fill(result);
471 PowerPC::UpdateFPRF(result);
472 }
473
474 if (inst.Rc)
475 PowerPC::ppcState.UpdateCR1();
476 }
477
478 // Single precision only.
fresx(UGeckoInstruction inst)479 void Interpreter::fresx(UGeckoInstruction inst)
480 {
481 const double b = rPS(inst.FB).PS0AsDouble();
482
483 const auto compute_result = [inst](double value) {
484 const double result = Common::ApproximateReciprocal(value);
485 rPS(inst.FD).Fill(result);
486 PowerPC::UpdateFPRF(result);
487 };
488
489 if (b == 0.0)
490 {
491 SetFPException(&FPSCR, FPSCR_ZX);
492 FPSCR.ClearFIFR();
493
494 if (FPSCR.ZE == 0)
495 compute_result(b);
496 }
497 else if (Common::IsSNAN(b))
498 {
499 SetFPException(&FPSCR, FPSCR_VXSNAN);
500 FPSCR.ClearFIFR();
501
502 if (FPSCR.VE == 0)
503 compute_result(b);
504 }
505 else
506 {
507 if (std::isnan(b) || std::isinf(b))
508 FPSCR.ClearFIFR();
509
510 compute_result(b);
511 }
512
513 if (inst.Rc)
514 PowerPC::ppcState.UpdateCR1();
515 }
516
frsqrtex(UGeckoInstruction inst)517 void Interpreter::frsqrtex(UGeckoInstruction inst)
518 {
519 const double b = rPS(inst.FB).PS0AsDouble();
520
521 const auto compute_result = [inst](double value) {
522 const double result = Common::ApproximateReciprocalSquareRoot(value);
523 rPS(inst.FD).SetPS0(result);
524 PowerPC::UpdateFPRF(result);
525 };
526
527 if (b < 0.0)
528 {
529 SetFPException(&FPSCR, FPSCR_VXSQRT);
530 FPSCR.ClearFIFR();
531
532 if (FPSCR.VE == 0)
533 compute_result(b);
534 }
535 else if (b == 0.0)
536 {
537 SetFPException(&FPSCR, FPSCR_ZX);
538 FPSCR.ClearFIFR();
539
540 if (FPSCR.ZE == 0)
541 compute_result(b);
542 }
543 else if (Common::IsSNAN(b))
544 {
545 SetFPException(&FPSCR, FPSCR_VXSNAN);
546 FPSCR.ClearFIFR();
547
548 if (FPSCR.VE == 0)
549 compute_result(b);
550 }
551 else
552 {
553 if (std::isnan(b) || std::isinf(b))
554 FPSCR.ClearFIFR();
555
556 compute_result(b);
557 }
558
559 if (inst.Rc)
560 PowerPC::ppcState.UpdateCR1();
561 }
562
fmsubx(UGeckoInstruction inst)563 void Interpreter::fmsubx(UGeckoInstruction inst)
564 {
565 const auto& a = rPS(inst.FA);
566 const auto& b = rPS(inst.FB);
567 const auto& c = rPS(inst.FC);
568
569 const FPResult product = NI_msub(&FPSCR, a.PS0AsDouble(), c.PS0AsDouble(), b.PS0AsDouble());
570
571 if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
572 {
573 const double result = ForceDouble(FPSCR, product.value);
574 rPS(inst.FD).SetPS0(result);
575 PowerPC::UpdateFPRF(result);
576 }
577
578 if (inst.Rc)
579 PowerPC::ppcState.UpdateCR1();
580 }
581
fmsubsx(UGeckoInstruction inst)582 void Interpreter::fmsubsx(UGeckoInstruction inst)
583 {
584 const auto& a = rPS(inst.FA);
585 const auto& b = rPS(inst.FB);
586 const auto& c = rPS(inst.FC);
587
588 const double c_value = Force25Bit(c.PS0AsDouble());
589 const FPResult product = NI_msub(&FPSCR, a.PS0AsDouble(), c_value, b.PS0AsDouble());
590
591 if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
592 {
593 const double result = ForceSingle(FPSCR, product.value);
594 rPS(inst.FD).Fill(result);
595 PowerPC::UpdateFPRF(result);
596 }
597
598 if (inst.Rc)
599 PowerPC::ppcState.UpdateCR1();
600 }
601
fnmaddx(UGeckoInstruction inst)602 void Interpreter::fnmaddx(UGeckoInstruction inst)
603 {
604 const auto& a = rPS(inst.FA);
605 const auto& b = rPS(inst.FB);
606 const auto& c = rPS(inst.FC);
607
608 const FPResult product = NI_madd(&FPSCR, a.PS0AsDouble(), c.PS0AsDouble(), b.PS0AsDouble());
609
610 if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
611 {
612 const double tmp = ForceDouble(FPSCR, product.value);
613 const double result = std::isnan(tmp) ? tmp : -tmp;
614
615 rPS(inst.FD).SetPS0(result);
616 PowerPC::UpdateFPRF(result);
617 }
618
619 if (inst.Rc)
620 PowerPC::ppcState.UpdateCR1();
621 }
622
fnmaddsx(UGeckoInstruction inst)623 void Interpreter::fnmaddsx(UGeckoInstruction inst)
624 {
625 const auto& a = rPS(inst.FA);
626 const auto& b = rPS(inst.FB);
627 const auto& c = rPS(inst.FC);
628
629 const double c_value = Force25Bit(c.PS0AsDouble());
630 const FPResult product = NI_madd(&FPSCR, a.PS0AsDouble(), c_value, b.PS0AsDouble());
631
632 if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
633 {
634 const double tmp = ForceSingle(FPSCR, product.value);
635 const double result = std::isnan(tmp) ? tmp : -tmp;
636
637 rPS(inst.FD).Fill(result);
638 PowerPC::UpdateFPRF(result);
639 }
640
641 if (inst.Rc)
642 PowerPC::ppcState.UpdateCR1();
643 }
644
fnmsubx(UGeckoInstruction inst)645 void Interpreter::fnmsubx(UGeckoInstruction inst)
646 {
647 const auto& a = rPS(inst.FA);
648 const auto& b = rPS(inst.FB);
649 const auto& c = rPS(inst.FC);
650
651 const FPResult product = NI_msub(&FPSCR, a.PS0AsDouble(), c.PS0AsDouble(), b.PS0AsDouble());
652
653 if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
654 {
655 const double tmp = ForceDouble(FPSCR, product.value);
656 const double result = std::isnan(tmp) ? tmp : -tmp;
657
658 rPS(inst.FD).SetPS0(result);
659 PowerPC::UpdateFPRF(result);
660 }
661
662 if (inst.Rc)
663 PowerPC::ppcState.UpdateCR1();
664 }
665
fnmsubsx(UGeckoInstruction inst)666 void Interpreter::fnmsubsx(UGeckoInstruction inst)
667 {
668 const auto& a = rPS(inst.FA);
669 const auto& b = rPS(inst.FB);
670 const auto& c = rPS(inst.FC);
671
672 const double c_value = Force25Bit(c.PS0AsDouble());
673 const FPResult product = NI_msub(&FPSCR, a.PS0AsDouble(), c_value, b.PS0AsDouble());
674
675 if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
676 {
677 const double tmp = ForceSingle(FPSCR, product.value);
678 const double result = std::isnan(tmp) ? tmp : -tmp;
679
680 rPS(inst.FD).Fill(result);
681 PowerPC::UpdateFPRF(result);
682 }
683
684 if (inst.Rc)
685 PowerPC::ppcState.UpdateCR1();
686 }
687
fsubx(UGeckoInstruction inst)688 void Interpreter::fsubx(UGeckoInstruction inst)
689 {
690 const auto& a = rPS(inst.FA);
691 const auto& b = rPS(inst.FB);
692
693 const FPResult difference = NI_sub(&FPSCR, a.PS0AsDouble(), b.PS0AsDouble());
694
695 if (FPSCR.VE == 0 || difference.HasNoInvalidExceptions())
696 {
697 const double result = ForceDouble(FPSCR, difference.value);
698 rPS(inst.FD).SetPS0(result);
699 PowerPC::UpdateFPRF(result);
700 }
701
702 if (inst.Rc)
703 PowerPC::ppcState.UpdateCR1();
704 }
705
fsubsx(UGeckoInstruction inst)706 void Interpreter::fsubsx(UGeckoInstruction inst)
707 {
708 const auto& a = rPS(inst.FA);
709 const auto& b = rPS(inst.FB);
710
711 const FPResult difference = NI_sub(&FPSCR, a.PS0AsDouble(), b.PS0AsDouble());
712
713 if (FPSCR.VE == 0 || difference.HasNoInvalidExceptions())
714 {
715 const double result = ForceSingle(FPSCR, difference.value);
716 rPS(inst.FD).Fill(result);
717 PowerPC::UpdateFPRF(result);
718 }
719
720 if (inst.Rc)
721 PowerPC::ppcState.UpdateCR1();
722 }
723