From a5a5410515dddb6ff3f43953f73f8bc34d78094e Mon Sep 17 00:00:00 2001
From: dingusdev <52434309+dingusdev@users.noreply.github.com>
Date: Sun, 7 Apr 2024 08:58:38 -0700
Subject: [PATCH] Continued fixing floating-point ops

---
 cpu/ppc/ppcfpopcodes.cpp | 75 +++++++++++++++++++++++++++++++++++++---
 1 file changed, 71 insertions(+), 4 deletions(-)

diff --git a/cpu/ppc/ppcfpopcodes.cpp b/cpu/ppc/ppcfpopcodes.cpp
index 42e50b1..e8993e0 100644
--- a/cpu/ppc/ppcfpopcodes.cpp
+++ b/cpu/ppc/ppcfpopcodes.cpp
@@ -93,6 +93,16 @@ inline static bool check_snan(int check_reg) {
         ((check_int & (0x1ULL << 51)) == 0ULL));
 }
 
+inline static void snan_single_check(int reg_a) {
+    if (check_snan(reg_a))
+        ppc_state.fpscr |= FX | VX | VXSNAN;
+}
+
+inline static void snan_double_check(int reg_a, int reg_b) {
+    if (check_snan(reg_a) || check_snan(reg_b))
+        ppc_state.fpscr |= FX | VX | VXSNAN;
+}
+
 inline static bool check_qnan(int check_reg) {
     uint64_t check_int = ppc_state.fpr[check_reg].int64_r;
     return (((check_int & (0x7FFULL << 52)) == (0x7FFULL << 52)) &&
@@ -122,6 +132,8 @@ template <field_rc rec>
 void dppc_interpreter::ppc_fadd() {
     ppc_grab_regsfpdab(ppc_cur_instruction);
 
+    snan_double_check(reg_a, reg_b);
+
     double ppc_dblresult64_d = val_reg_a + val_reg_b;
     ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
     fpresult_update(ppc_dblresult64_d);
@@ -137,6 +149,8 @@ template <field_rc rec>
 void dppc_interpreter::ppc_fsub() {
     ppc_grab_regsfpdab(ppc_cur_instruction);
 
+    snan_double_check(reg_a, reg_b);
+
     double ppc_dblresult64_d = val_reg_a - val_reg_b;
     ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
     fpresult_update(ppc_dblresult64_d);
@@ -152,6 +166,8 @@ template <field_rc rec>
 void dppc_interpreter::ppc_fdiv() {
     ppc_grab_regsfpdab(ppc_cur_instruction);
 
+    snan_double_check(reg_a, reg_b);
+
     double ppc_dblresult64_d = val_reg_a / val_reg_b;
     ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
     fpresult_update(ppc_dblresult64_d);
@@ -167,6 +183,8 @@ template <field_rc rec>
 void dppc_interpreter::ppc_fmul() {
     ppc_grab_regsfpdac(ppc_cur_instruction);
 
+    snan_double_check(reg_a, reg_c);
+
     double ppc_dblresult64_d = val_reg_a * val_reg_c;
     ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
     fpresult_update(ppc_dblresult64_d);
@@ -182,6 +200,9 @@ template <field_rc rec>
 void dppc_interpreter::ppc_fmadd() {
     ppc_grab_regsfpdabc(ppc_cur_instruction);
 
+    snan_double_check(reg_a, reg_c);
+    snan_single_check(reg_b);
+
     double ppc_dblresult64_d = std::fma(val_reg_a, val_reg_c, val_reg_b);
     ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
     fpresult_update(ppc_dblresult64_d);
@@ -197,6 +218,9 @@ template <field_rc rec>
 void dppc_interpreter::ppc_fmsub() {
     ppc_grab_regsfpdabc(ppc_cur_instruction);
 
+    snan_double_check(reg_a, reg_c);
+    snan_single_check(reg_b);
+
     double ppc_dblresult64_d = std::fma(val_reg_a, val_reg_c, -val_reg_b);
     ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
     fpresult_update(ppc_dblresult64_d);
@@ -212,6 +236,9 @@ template <field_rc rec>
 void dppc_interpreter::ppc_fnmadd() {
     ppc_grab_regsfpdabc(ppc_cur_instruction);
 
+    snan_double_check(reg_a, reg_c);
+    snan_single_check(reg_b);
+
     double ppc_dblresult64_d = -std::fma(val_reg_a, val_reg_c, val_reg_b);
     ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
     fpresult_update(ppc_dblresult64_d);
@@ -227,6 +254,9 @@ template <field_rc rec>
 void dppc_interpreter::ppc_fnmsub() {
     ppc_grab_regsfpdabc(ppc_cur_instruction);
 
+    snan_double_check(reg_a, reg_c);
+    snan_single_check(reg_b);
+
     double ppc_dblresult64_d = -std::fma(val_reg_a, val_reg_c, -val_reg_b);
     ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
     fpresult_update(ppc_dblresult64_d);
@@ -242,6 +272,8 @@ template <field_rc rec>
 void dppc_interpreter::ppc_fadds() {
     ppc_grab_regsfpdab(ppc_cur_instruction);
 
+    snan_double_check(reg_a, reg_b);
+
     double ppc_dblresult64_d = (float)(val_reg_a + val_reg_b);
     ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
 
@@ -258,6 +290,8 @@ template <field_rc rec>
 void dppc_interpreter::ppc_fsubs() {
     ppc_grab_regsfpdab(ppc_cur_instruction);
 
+    snan_double_check(reg_a, reg_b);
+
     double ppc_dblresult64_d = (float)(val_reg_a - val_reg_b);
     ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
     fpresult_update(ppc_dblresult64_d);
@@ -273,6 +307,8 @@ template <field_rc rec>
 void dppc_interpreter::ppc_fdivs() {
     ppc_grab_regsfpdab(ppc_cur_instruction);
 
+    snan_double_check(reg_a, reg_b);
+
     double ppc_dblresult64_d = (float)(val_reg_a / val_reg_b);
     ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
     fpresult_update(ppc_dblresult64_d);
@@ -288,6 +324,8 @@ template <field_rc rec>
 void dppc_interpreter::ppc_fmuls() {
     ppc_grab_regsfpdac(ppc_cur_instruction);
 
+    snan_double_check(reg_a, reg_c);
+
     double ppc_dblresult64_d = (float)(val_reg_a * val_reg_c);
     ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
     fpresult_update(ppc_dblresult64_d);
@@ -303,6 +341,9 @@ template <field_rc rec>
 void dppc_interpreter::ppc_fmadds() {
     ppc_grab_regsfpdabc(ppc_cur_instruction);
 
+    snan_double_check(reg_a, reg_c);
+    snan_single_check(reg_b);
+
     double ppc_dblresult64_d = (float)std::fma(val_reg_a, val_reg_c, val_reg_b);
     ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
     fpresult_update(ppc_dblresult64_d);
@@ -318,6 +359,9 @@ template <field_rc rec>
 void dppc_interpreter::ppc_fmsubs() {
     ppc_grab_regsfpdabc(ppc_cur_instruction);
 
+    snan_double_check(reg_a, reg_c);
+    snan_single_check(reg_b);
+
     double ppc_dblresult64_d = (float)std::fma(val_reg_a, val_reg_c, -val_reg_b);
     ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
     fpresult_update(ppc_dblresult64_d);
@@ -333,6 +377,9 @@ template <field_rc rec>
 void dppc_interpreter::ppc_fnmadds() {
     ppc_grab_regsfpdabc(ppc_cur_instruction);
 
+    snan_double_check(reg_a, reg_c);
+    snan_single_check(reg_b);
+
     double ppc_dblresult64_d = -(float)std::fma(val_reg_a, val_reg_c, val_reg_b);
     ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
     fpresult_update(ppc_dblresult64_d);
@@ -348,6 +395,9 @@ template <field_rc rec>
 void dppc_interpreter::ppc_fnmsubs() {
     ppc_grab_regsfpdabc(ppc_cur_instruction);
 
+    snan_double_check(reg_a, reg_c);
+    snan_single_check(reg_b);
+
     double ppc_dblresult64_d = -(float)std::fma(val_reg_a, val_reg_c, -val_reg_b);
     ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
     fpresult_update(ppc_dblresult64_d);
@@ -363,6 +413,8 @@ template <field_rc rec>
 void dppc_interpreter::ppc_fabs() {
     ppc_grab_regsfpdb(ppc_cur_instruction);
 
+    snan_single_check(reg_b);
+
     double ppc_dblresult64_d = abs(GET_FPR(reg_b));
 
     ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
@@ -378,6 +430,8 @@ template <field_rc rec>
 void dppc_interpreter::ppc_fnabs() {
     ppc_grab_regsfpdb(ppc_cur_instruction);
 
+    snan_single_check(reg_b);
+
     double ppc_dblresult64_d = abs(GET_FPR(reg_b));
     ppc_dblresult64_d = -ppc_dblresult64_d;
 
@@ -394,6 +448,8 @@ template <field_rc rec>
 void dppc_interpreter::ppc_fneg() {
     ppc_grab_regsfpdb(ppc_cur_instruction);
 
+    snan_single_check(reg_b);
+
     double ppc_dblresult64_d = -(GET_FPR(reg_b));
 
     ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
@@ -423,6 +479,9 @@ template void dppc_interpreter::ppc_fsel<RC1>();
 template <field_rc rec>
 void dppc_interpreter::ppc_fsqrt() {
     ppc_grab_regsfpdb(ppc_cur_instruction);
+
+    snan_single_check(reg_b);
+
     double testd2 = (double)(GET_FPR(reg_b));
     double ppc_dblresult64_d = std::sqrt(testd2);
     ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
@@ -437,7 +496,10 @@ template void dppc_interpreter::ppc_fsqrt<RC1>();
 template <field_rc rec>
 void dppc_interpreter::ppc_fsqrts() {
     ppc_grab_regsfpdb(ppc_cur_instruction);
-    double testd2     = (double)(GET_FPR(reg_b));
+
+    snan_single_check(reg_b);
+
+    double testd2            = (double)(GET_FPR(reg_b));
     double ppc_dblresult64_d = (float)std::sqrt(testd2);
     ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
 
@@ -451,10 +513,10 @@ template void dppc_interpreter::ppc_fsqrts<RC1>();
 template <field_rc rec>
 void dppc_interpreter::ppc_frsqrte() {
     ppc_grab_regsfpdb(ppc_cur_instruction);
-    double testd2 = (double)(GET_FPR(reg_b));
+    snan_single_check(reg_b);
 
+    double testd2            = (double)(GET_FPR(reg_b));
     double ppc_dblresult64_d = 1.0 / sqrt(testd2);
-
     ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
 
     if (rec)
@@ -467,6 +529,8 @@ template void dppc_interpreter::ppc_frsqrte<RC1>();
 template <field_rc rec>
 void dppc_interpreter::ppc_frsp() {
     ppc_grab_regsfpdb(ppc_cur_instruction);
+    snan_single_check(reg_b);
+
     double ppc_dblresult64_d = (float)(GET_FPR(reg_b));
     ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
 
@@ -480,6 +544,9 @@ template void dppc_interpreter::ppc_frsp<RC1>();
 template <field_rc rec>
 void dppc_interpreter::ppc_fres() {
     ppc_grab_regsfpdb(ppc_cur_instruction);
+
+    snan_single_check(reg_b);
+
     double start_num = GET_FPR(reg_b);
     double ppc_dblresult64_d = (float)(1.0 / start_num);
     ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
@@ -510,7 +577,7 @@ static void round_to_int(const uint8_t mode, field_rc rec) {
         ppc_state.fpscr &= ~(FPSCR::FR | FPSCR::FI);
         ppc_state.fpscr |= (FPSCR::VXCVI | FPSCR::VX);
 
-        if (!(ppc_state.fpr[reg_b].int64_r & 0x0008000000000000)) // issnan
+        if (check_snan(reg_b)) // issnan
             ppc_state.fpscr |= FPSCR::VXSNAN;
 
         if (ppc_state.fpscr & FPSCR::VE) {