2020-02-28 09:04:28 -07:00
|
|
|
/*
|
|
|
|
DingusPPC - The Experimental PowerPC Macintosh emulator
|
2024-02-05 06:22:41 -08:00
|
|
|
Copyright (C) 2018-24 divingkatae and maximum
|
2020-02-28 09:04:28 -07:00
|
|
|
(theweirdo) spatium
|
|
|
|
|
|
|
|
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*/
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2021-10-30 16:43:13 -07:00
|
|
|
// The floating point opcodes for the processor - ppcfpopcodes.cpp
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2019-12-27 20:10:36 +01:00
|
|
|
#include "ppcemu.h"
|
2024-03-22 08:01:29 -07:00
|
|
|
#include "ppcmacros.h"
|
2019-12-27 20:00:53 +01:00
|
|
|
#include "ppcmmu.h"
|
2023-11-03 00:21:33 -07:00
|
|
|
#include <stdlib.h>
|
2023-11-30 12:00:50 +01:00
|
|
|
#include <cfenv>
|
2020-05-12 23:55:45 +05:00
|
|
|
#include <cinttypes>
|
2019-07-01 19:15:33 -07:00
|
|
|
#include <cmath>
|
2023-11-19 20:34:40 -07:00
|
|
|
#include <cfloat>
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2020-05-12 23:55:45 +05:00
|
|
|
// Storage and register retrieval functions for the floating point functions.
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2020-01-21 19:25:50 -07:00
|
|
|
double fp_return_double(uint32_t reg) {
|
2020-03-04 21:29:04 -07:00
|
|
|
return ppc_state.fpr[reg].dbl64_r;
|
2020-01-21 19:25:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t fp_return_uint64(uint32_t reg) {
|
2020-03-04 21:29:04 -07:00
|
|
|
return ppc_state.fpr[reg].int64_r;
|
2019-07-01 19:15:33 -07:00
|
|
|
}
|
|
|
|
|
2024-04-06 17:31:03 -07:00
|
|
|
inline static void ppc_update_cr1() {
|
2023-11-28 16:29:51 +01:00
|
|
|
// copy FPSCR[FX|FEX|VX|OX] to CR1
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_state.cr = (ppc_state.cr & ~CR_select::CR1_field) |
|
|
|
|
((ppc_state.fpscr >> 4) & CR_select::CR1_field);
|
2020-01-11 18:43:47 -07:00
|
|
|
}
|
|
|
|
|
2024-04-06 17:31:03 -07:00
|
|
|
static int32_t round_to_nearest(double f) {
|
2024-02-05 06:12:48 -08:00
|
|
|
return static_cast<int32_t>(static_cast<int64_t> (std::floor(f + 0.5)));
|
2020-02-16 13:40:55 -07:00
|
|
|
}
|
|
|
|
|
2023-11-30 12:00:50 +01:00
|
|
|
void set_host_rounding_mode(uint8_t mode) {
|
|
|
|
switch(mode & FPSCR::RN_MASK) {
|
|
|
|
case 0:
|
|
|
|
std::fesetround(FE_TONEAREST);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
std::fesetround(FE_TOWARDZERO);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
std::fesetround(FE_UPWARD);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
std::fesetround(FE_DOWNWARD);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void update_fpscr(uint32_t new_fpscr) {
|
|
|
|
if ((new_fpscr & FPSCR::RN_MASK) != (ppc_state.fpscr & FPSCR::RN_MASK))
|
|
|
|
set_host_rounding_mode(new_fpscr & FPSCR::RN_MASK);
|
|
|
|
|
|
|
|
ppc_state.fpscr = new_fpscr;
|
|
|
|
}
|
|
|
|
|
2024-04-06 17:31:03 -07:00
|
|
|
static int32_t round_to_zero(double f) {
|
2022-02-17 00:20:18 +01:00
|
|
|
return static_cast<int32_t>(std::trunc(f));
|
2020-02-16 13:40:55 -07:00
|
|
|
}
|
|
|
|
|
2024-04-06 17:31:03 -07:00
|
|
|
static int32_t round_to_pos_inf(double f) {
|
2022-02-17 00:20:18 +01:00
|
|
|
return static_cast<int32_t>(std::ceil(f));
|
2020-02-16 13:40:55 -07:00
|
|
|
}
|
|
|
|
|
2024-04-06 17:31:03 -07:00
|
|
|
static int32_t round_to_neg_inf(double f) {
|
2022-02-17 00:20:18 +01:00
|
|
|
return static_cast<int32_t>(std::floor(f));
|
2020-02-16 13:40:55 -07:00
|
|
|
}
|
2020-01-21 19:25:50 -07:00
|
|
|
|
2024-04-06 17:31:03 -07:00
|
|
|
inline static bool check_snan(int check_reg) {
|
2024-04-06 11:02:03 -07:00
|
|
|
uint64_t check_int = ppc_state.fpr[check_reg].int64_r;
|
|
|
|
return (((check_int & (0x7FFULL << 52)) == (0x7FFULL << 52)) &&
|
|
|
|
((check_int & ~(0xFFFULL << 52)) != 0ULL) &&
|
|
|
|
((check_int & (0x1ULL << 51)) == 0ULL));
|
2020-02-20 20:00:20 -07:00
|
|
|
}
|
|
|
|
|
2024-04-07 08:58:38 -07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2024-09-15 18:31:36 -07:00
|
|
|
inline static void max_double_check(double value_a, double value_b) {
|
|
|
|
if (((value_a == DBL_MAX) && (value_b == DBL_MAX)) ||
|
|
|
|
((value_a == -DBL_MAX) && (value_b == -DBL_MAX)))
|
|
|
|
ppc_state.fpscr |= FX | OX | XX | FI;
|
|
|
|
}
|
|
|
|
|
2024-04-06 17:31:03 -07:00
|
|
|
inline static bool check_qnan(int check_reg) {
|
2024-04-06 11:02:03 -07:00
|
|
|
uint64_t check_int = ppc_state.fpr[check_reg].int64_r;
|
|
|
|
return (((check_int & (0x7FFULL << 52)) == (0x7FFULL << 52)) &&
|
2024-08-19 21:01:07 +02:00
|
|
|
((check_int & ~(0xFFFULL << 52)) == 0ULL) &&
|
2024-04-06 11:02:03 -07:00
|
|
|
((check_int & (0x1ULL << 51)) == (0x1ULL << 51)));
|
|
|
|
}
|
2023-11-28 16:29:51 +01:00
|
|
|
|
2023-11-30 11:50:03 +01:00
|
|
|
static void fpresult_update(double set_result) {
|
2023-11-23 16:56:58 -07:00
|
|
|
if (std::isnan(set_result)) {
|
2023-12-19 11:58:12 +01:00
|
|
|
ppc_state.fpscr |= FPCC_FUNAN | FPRCD;
|
2021-10-30 16:43:13 -07:00
|
|
|
} else {
|
2023-11-30 11:50:03 +01:00
|
|
|
if (set_result > 0.0) {
|
|
|
|
ppc_state.fpscr |= FPCC_POS;
|
|
|
|
} else if (set_result < 0.0) {
|
|
|
|
ppc_state.fpscr |= FPCC_NEG;
|
|
|
|
} else {
|
|
|
|
ppc_state.fpscr |= FPCC_ZERO;
|
|
|
|
}
|
2021-10-24 14:00:35 -07:00
|
|
|
|
2023-11-30 11:50:03 +01:00
|
|
|
if (std::isinf(set_result))
|
2023-11-30 12:52:34 +01:00
|
|
|
ppc_state.fpscr |= FPCC_FUNAN;
|
2021-10-19 07:16:15 -07:00
|
|
|
}
|
2021-10-30 16:43:13 -07:00
|
|
|
}
|
2021-10-19 07:16:15 -07:00
|
|
|
|
2024-04-09 21:11:09 -07:00
|
|
|
static void ppc_update_vx() {
|
|
|
|
uint32_t fpscr_check = ppc_state.fpscr & 0x1F80700U;
|
|
|
|
if (fpscr_check)
|
|
|
|
ppc_state.fpscr |= VX;
|
|
|
|
else
|
|
|
|
ppc_state.fpscr &= ~VX;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ppc_update_fex() {
|
2024-08-19 21:01:07 +02:00
|
|
|
uint32_t fpscr_check = (((ppc_state.fpscr >> 25) & 0x1F) &
|
2024-04-09 21:11:09 -07:00
|
|
|
((ppc_state.fpscr >> 3) & 0x1F));
|
|
|
|
|
|
|
|
if (fpscr_check)
|
|
|
|
ppc_state.fpscr |= VX;
|
|
|
|
else
|
|
|
|
ppc_state.fpscr &= ~VX;
|
|
|
|
}
|
|
|
|
|
2020-05-12 23:55:45 +05:00
|
|
|
// Floating Point Arithmetic
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (fadd,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdab(instr);
|
2021-10-17 23:41:53 +02:00
|
|
|
|
2024-04-07 08:58:38 -07:00
|
|
|
snan_double_check(reg_a, reg_b);
|
2024-09-15 18:31:36 -07:00
|
|
|
max_double_check(val_reg_a, val_reg_b);
|
2024-04-07 08:58:38 -07:00
|
|
|
|
2024-02-05 06:17:52 -08:00
|
|
|
double ppc_dblresult64_d = val_reg_a + val_reg_b;
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
|
2023-11-30 11:50:03 +01:00
|
|
|
fpresult_update(ppc_dblresult64_d);
|
2024-09-15 18:31:36 -07:00
|
|
|
ppc_update_fex();
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fadd<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fadd<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (fsub,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdab(instr);
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-04-07 08:58:38 -07:00
|
|
|
snan_double_check(reg_a, reg_b);
|
|
|
|
|
2024-02-05 06:17:52 -08:00
|
|
|
double ppc_dblresult64_d = val_reg_a - val_reg_b;
|
2024-09-15 18:31:36 -07:00
|
|
|
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
|
2023-11-30 11:50:03 +01:00
|
|
|
fpresult_update(ppc_dblresult64_d);
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fsub<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fsub<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (fdiv,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdab(instr);
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-04-07 08:58:38 -07:00
|
|
|
snan_double_check(reg_a, reg_b);
|
|
|
|
|
2023-11-25 17:57:56 -08:00
|
|
|
double ppc_dblresult64_d = val_reg_a / val_reg_b;
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
|
2023-11-30 11:50:03 +01:00
|
|
|
fpresult_update(ppc_dblresult64_d);
|
2023-11-19 17:56:30 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fdiv<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fdiv<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (fmul,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdac(instr);
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-04-07 08:58:38 -07:00
|
|
|
snan_double_check(reg_a, reg_c);
|
|
|
|
|
2023-11-25 17:57:56 -08:00
|
|
|
double ppc_dblresult64_d = val_reg_a * val_reg_c;
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
|
2023-11-30 11:50:03 +01:00
|
|
|
fpresult_update(ppc_dblresult64_d);
|
2023-11-19 17:56:30 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fmul<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fmul<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (fmadd,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdabc(instr);
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-04-07 08:58:38 -07:00
|
|
|
snan_double_check(reg_a, reg_c);
|
|
|
|
snan_single_check(reg_b);
|
|
|
|
|
2023-11-25 17:57:56 -08:00
|
|
|
double ppc_dblresult64_d = std::fma(val_reg_a, val_reg_c, val_reg_b);
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
|
2023-11-30 11:50:03 +01:00
|
|
|
fpresult_update(ppc_dblresult64_d);
|
2023-11-19 17:56:30 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fmadd<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fmadd<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (fmsub,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdabc(instr);
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-04-07 08:58:38 -07:00
|
|
|
snan_double_check(reg_a, reg_c);
|
|
|
|
snan_single_check(reg_b);
|
|
|
|
|
2024-02-05 06:22:17 -08:00
|
|
|
double ppc_dblresult64_d = std::fma(val_reg_a, val_reg_c, -val_reg_b);
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
|
2023-11-30 11:50:03 +01:00
|
|
|
fpresult_update(ppc_dblresult64_d);
|
2023-11-19 17:56:30 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fmsub<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fmsub<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (fnmadd,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdabc(instr);
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-04-07 08:58:38 -07:00
|
|
|
snan_double_check(reg_a, reg_c);
|
|
|
|
snan_single_check(reg_b);
|
|
|
|
|
2024-02-05 06:22:17 -08:00
|
|
|
double ppc_dblresult64_d = -std::fma(val_reg_a, val_reg_c, val_reg_b);
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
|
2023-11-30 11:50:03 +01:00
|
|
|
fpresult_update(ppc_dblresult64_d);
|
2023-11-19 17:56:30 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fnmadd<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fnmadd<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (fnmsub,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdabc(instr);
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-04-07 08:58:38 -07:00
|
|
|
snan_double_check(reg_a, reg_c);
|
|
|
|
snan_single_check(reg_b);
|
|
|
|
|
2024-04-07 07:23:30 -07:00
|
|
|
double ppc_dblresult64_d = -std::fma(val_reg_a, val_reg_c, -val_reg_b);
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
|
2023-11-30 11:50:03 +01:00
|
|
|
fpresult_update(ppc_dblresult64_d);
|
2021-10-14 20:31:10 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fnmsub<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fnmsub<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (fadds,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdab(instr);
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-04-07 08:58:38 -07:00
|
|
|
snan_double_check(reg_a, reg_b);
|
|
|
|
|
2024-04-07 07:23:30 -07:00
|
|
|
double ppc_dblresult64_d = (float)(val_reg_a + val_reg_b);
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
|
2021-10-14 20:31:10 -07:00
|
|
|
|
2023-11-30 11:50:03 +01:00
|
|
|
fpresult_update(ppc_dblresult64_d);
|
2023-11-19 17:56:30 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fadds<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fadds<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (fsubs,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdab(instr);
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-04-07 08:58:38 -07:00
|
|
|
snan_double_check(reg_a, reg_b);
|
|
|
|
|
2023-11-25 17:57:56 -08:00
|
|
|
double ppc_dblresult64_d = (float)(val_reg_a - val_reg_b);
|
2024-09-15 18:31:36 -07:00
|
|
|
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
|
2023-11-30 11:50:03 +01:00
|
|
|
fpresult_update(ppc_dblresult64_d);
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fsubs<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fsubs<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (fdivs,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdab(instr);
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-04-07 08:58:38 -07:00
|
|
|
snan_double_check(reg_a, reg_b);
|
|
|
|
|
2023-11-25 17:57:56 -08:00
|
|
|
double ppc_dblresult64_d = (float)(val_reg_a / val_reg_b);
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
|
2023-11-30 11:50:03 +01:00
|
|
|
fpresult_update(ppc_dblresult64_d);
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fdivs<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fdivs<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (fmuls,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdac(instr);
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-04-07 08:58:38 -07:00
|
|
|
snan_double_check(reg_a, reg_c);
|
|
|
|
|
2023-11-25 17:57:56 -08:00
|
|
|
double ppc_dblresult64_d = (float)(val_reg_a * val_reg_c);
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
|
2023-11-30 11:50:03 +01:00
|
|
|
fpresult_update(ppc_dblresult64_d);
|
2023-11-23 16:56:58 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fmuls<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fmuls<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (fmadds,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdabc(instr);
|
2023-11-28 16:29:51 +01:00
|
|
|
|
2024-04-07 08:58:38 -07:00
|
|
|
snan_double_check(reg_a, reg_c);
|
|
|
|
snan_single_check(reg_b);
|
|
|
|
|
2024-02-05 06:22:17 -08:00
|
|
|
double ppc_dblresult64_d = (float)std::fma(val_reg_a, val_reg_c, val_reg_b);
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
|
2023-11-30 11:50:03 +01:00
|
|
|
fpresult_update(ppc_dblresult64_d);
|
2020-02-20 20:00:20 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fmadds<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fmadds<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (fmsubs,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdabc(instr);
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-04-07 08:58:38 -07:00
|
|
|
snan_double_check(reg_a, reg_c);
|
|
|
|
snan_single_check(reg_b);
|
|
|
|
|
2024-02-05 06:22:17 -08:00
|
|
|
double ppc_dblresult64_d = (float)std::fma(val_reg_a, val_reg_c, -val_reg_b);
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
|
2023-11-30 11:50:03 +01:00
|
|
|
fpresult_update(ppc_dblresult64_d);
|
2020-02-20 20:00:20 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fmsubs<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fmsubs<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (fnmadds,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdabc(instr);
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-04-07 08:58:38 -07:00
|
|
|
snan_double_check(reg_a, reg_c);
|
|
|
|
snan_single_check(reg_b);
|
|
|
|
|
2024-02-05 06:22:17 -08:00
|
|
|
double ppc_dblresult64_d = -(float)std::fma(val_reg_a, val_reg_c, val_reg_b);
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
|
2023-11-30 11:50:03 +01:00
|
|
|
fpresult_update(ppc_dblresult64_d);
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fnmadds<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fnmadds<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (fnmsubs,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdabc(instr);
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-04-07 08:58:38 -07:00
|
|
|
snan_double_check(reg_a, reg_c);
|
|
|
|
snan_single_check(reg_b);
|
|
|
|
|
2024-04-07 07:23:30 -07:00
|
|
|
double ppc_dblresult64_d = -(float)std::fma(val_reg_a, val_reg_c, -val_reg_b);
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
|
2023-11-30 11:50:03 +01:00
|
|
|
fpresult_update(ppc_dblresult64_d);
|
2020-02-25 07:15:42 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fnmsubs<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fnmsubs<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (fabs,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdb(instr);
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-04-07 08:58:38 -07:00
|
|
|
snan_single_check(reg_b);
|
|
|
|
|
2023-11-25 17:57:56 -08:00
|
|
|
double ppc_dblresult64_d = abs(GET_FPR(reg_b));
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fabs<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fabs<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC(fnabs,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdb(instr);
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-04-07 08:58:38 -07:00
|
|
|
snan_single_check(reg_b);
|
|
|
|
|
2023-11-25 17:57:56 -08:00
|
|
|
double ppc_dblresult64_d = abs(GET_FPR(reg_b));
|
2020-01-21 19:25:50 -07:00
|
|
|
ppc_dblresult64_d = -ppc_dblresult64_d;
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fnabs<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fnabs<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC(fneg,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdb(instr);
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-04-07 08:58:38 -07:00
|
|
|
snan_single_check(reg_b);
|
|
|
|
|
2023-11-25 17:57:56 -08:00
|
|
|
double ppc_dblresult64_d = -(GET_FPR(reg_b));
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fneg<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fneg<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC(fsel,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdabc(instr);
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2023-11-25 17:57:56 -08:00
|
|
|
double ppc_dblresult64_d = (val_reg_a >= -0.0) ? val_reg_c : val_reg_b;
|
2020-01-21 19:25:50 -07:00
|
|
|
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
|
2020-01-21 19:25:50 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fsel<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fsel<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC(fsqrt,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdb(instr);
|
2024-04-07 08:58:38 -07:00
|
|
|
|
|
|
|
snan_single_check(reg_b);
|
|
|
|
|
2023-11-23 16:56:58 -07:00
|
|
|
double testd2 = (double)(GET_FPR(reg_b));
|
2023-11-25 17:57:56 -08:00
|
|
|
double ppc_dblresult64_d = std::sqrt(testd2);
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fsqrt<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fsqrt<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC(fsqrts,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdb(instr);
|
2024-04-07 08:58:38 -07:00
|
|
|
|
|
|
|
snan_single_check(reg_b);
|
|
|
|
|
|
|
|
double testd2 = (double)(GET_FPR(reg_b));
|
2023-11-25 17:57:56 -08:00
|
|
|
double ppc_dblresult64_d = (float)std::sqrt(testd2);
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_sfpresult_flt(reg_d, ppc_dblresult64_d);
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fsqrts<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fsqrts<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (frsqrte,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdb(instr);
|
2024-04-07 08:58:38 -07:00
|
|
|
snan_single_check(reg_b);
|
2024-02-05 06:17:52 -08:00
|
|
|
|
2024-04-07 08:58:38 -07:00
|
|
|
double testd2 = (double)(GET_FPR(reg_b));
|
2024-02-05 06:17:52 -08:00
|
|
|
double ppc_dblresult64_d = 1.0 / sqrt(testd2);
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_frsqrte<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_frsqrte<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (frsp,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdb(instr);
|
2024-04-07 08:58:38 -07:00
|
|
|
snan_single_check(reg_b);
|
|
|
|
|
2023-11-25 17:57:56 -08:00
|
|
|
double ppc_dblresult64_d = (float)(GET_FPR(reg_b));
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_frsp<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_frsp<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (fres,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdb(instr);
|
2024-04-07 08:58:38 -07:00
|
|
|
|
|
|
|
snan_single_check(reg_b);
|
|
|
|
|
2024-02-16 23:52:43 -08:00
|
|
|
double start_num = GET_FPR(reg_b);
|
|
|
|
double ppc_dblresult64_d = (float)(1.0 / start_num);
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_dfpresult_flt(reg_d, ppc_dblresult64_d);
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2021-10-09 19:42:25 -07:00
|
|
|
if (start_num == 0.0) {
|
2021-10-10 07:48:49 -07:00
|
|
|
ppc_state.fpscr |= FPSCR::ZX;
|
2021-10-09 19:42:25 -07:00
|
|
|
}
|
|
|
|
else if (std::isnan(start_num)) {
|
2021-10-10 07:48:49 -07:00
|
|
|
ppc_state.fpscr |= FPSCR::VXSNAN;
|
2021-10-17 23:41:53 +02:00
|
|
|
}
|
2021-10-09 19:42:25 -07:00
|
|
|
else if (std::isinf(start_num)){
|
|
|
|
ppc_state.fpscr &= 0xFFF9FFFF;
|
2023-11-23 16:56:58 -07:00
|
|
|
ppc_state.fpscr |= FPSCR::VXSNAN;
|
2021-10-09 19:42:25 -07:00
|
|
|
}
|
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fres<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fres<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-17 08:08:29 -07:00
|
|
|
static void round_to_int(uint32_t instr, const uint8_t mode, field_rc rec) {
|
|
|
|
ppc_grab_regsfpdb(instr);
|
2021-01-25 02:27:58 +01:00
|
|
|
double val_reg_b = GET_FPR(reg_b);
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2021-02-05 12:45:57 -07:00
|
|
|
if (std::isnan(val_reg_b)) {
|
2024-01-02 21:45:29 +01:00
|
|
|
ppc_state.fpscr &= ~(FPSCR::FR | FPSCR::FI);
|
|
|
|
ppc_state.fpscr |= (FPSCR::VXCVI | FPSCR::VX);
|
|
|
|
|
2024-04-07 08:58:38 -07:00
|
|
|
if (check_snan(reg_b)) // issnan
|
2024-01-02 21:45:29 +01:00
|
|
|
ppc_state.fpscr |= FPSCR::VXSNAN;
|
|
|
|
|
2023-12-17 05:06:38 -08:00
|
|
|
if (ppc_state.fpscr & FPSCR::VE) {
|
2024-01-02 21:45:29 +01:00
|
|
|
ppc_state.fpscr |= FPSCR::FEX; // VX=1 and VE=1 cause FEX to be set
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_floating_point_exception(instr);
|
2024-01-02 21:45:29 +01:00
|
|
|
} else {
|
|
|
|
ppc_state.fpr[reg_d].int64_r = 0xFFF8000080000000ULL;
|
2023-12-17 05:06:38 -08:00
|
|
|
}
|
2024-01-02 21:45:29 +01:00
|
|
|
} else if (val_reg_b > static_cast<double>(0x7fffffff) ||
|
|
|
|
val_reg_b < -static_cast<double>(0x80000000)) {
|
|
|
|
ppc_state.fpscr &= ~(FPSCR::FR | FPSCR::FI);
|
|
|
|
ppc_state.fpscr |= (FPSCR::VXCVI | FPSCR::VX);
|
|
|
|
|
2023-12-17 05:06:38 -08:00
|
|
|
if (ppc_state.fpscr & FPSCR::VE) {
|
2024-01-02 21:45:29 +01:00
|
|
|
ppc_state.fpscr |= FPSCR::FEX; // VX=1 and VE=1 cause FEX to be set
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_floating_point_exception(instr);
|
2024-01-02 21:45:29 +01:00
|
|
|
} else {
|
|
|
|
if (val_reg_b >= 0.0f)
|
|
|
|
ppc_state.fpr[reg_d].int64_r = 0xFFF800007FFFFFFFULL;
|
|
|
|
else
|
|
|
|
ppc_state.fpr[reg_d].int64_r = 0xFFF8000080000000ULL;
|
2023-12-17 05:06:38 -08:00
|
|
|
}
|
2024-01-02 21:45:29 +01:00
|
|
|
} else {
|
2023-11-25 17:57:56 -08:00
|
|
|
uint64_t ppc_result64_d;
|
2024-01-02 21:45:29 +01:00
|
|
|
switch (mode & 0x3) {
|
2021-02-05 12:45:57 -07:00
|
|
|
case 0:
|
2024-02-18 07:06:27 -07:00
|
|
|
ppc_result64_d = uint32_t(round_to_nearest(val_reg_b));
|
2021-10-09 15:08:53 -07:00
|
|
|
break;
|
2021-02-05 12:45:57 -07:00
|
|
|
case 1:
|
2024-02-18 07:06:27 -07:00
|
|
|
ppc_result64_d = uint32_t(round_to_zero(val_reg_b));
|
2021-10-09 15:08:53 -07:00
|
|
|
break;
|
2021-02-05 12:45:57 -07:00
|
|
|
case 2:
|
2024-02-18 07:06:27 -07:00
|
|
|
ppc_result64_d = uint32_t(round_to_pos_inf(val_reg_b));
|
2021-10-09 15:08:53 -07:00
|
|
|
break;
|
2021-02-05 12:45:57 -07:00
|
|
|
case 3:
|
2024-02-18 07:06:27 -07:00
|
|
|
ppc_result64_d = uint32_t(round_to_neg_inf(val_reg_b));
|
2021-10-09 15:08:53 -07:00
|
|
|
break;
|
2021-02-05 12:45:57 -07:00
|
|
|
}
|
2020-02-16 13:40:55 -07:00
|
|
|
|
2024-02-05 06:09:49 -08:00
|
|
|
ppc_result64_d |= 0xFFF8000000000000ULL;
|
|
|
|
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_dfpresult_int(reg_d, ppc_result64_d);
|
2021-02-05 12:45:57 -07:00
|
|
|
}
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2019-07-01 19:15:33 -07:00
|
|
|
}
|
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (fctiw,
|
2024-09-17 08:08:29 -07:00
|
|
|
round_to_int(instr, ppc_state.fpscr & 0x3, rec);
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fctiw<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fctiw<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (fctiwz,
|
2024-09-17 08:08:29 -07:00
|
|
|
round_to_int(instr, 1, rec);
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fctiwz<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fctiwz<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2020-05-12 23:55:45 +05:00
|
|
|
// Floating Point Store and Load
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODE (lfs,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdia(instr);
|
|
|
|
uint32_t ea = int32_t(int16_t(instr));
|
2024-08-19 21:01:07 +02:00
|
|
|
ea += (reg_a) ? val_reg_a : 0;
|
2024-09-17 08:08:29 -07:00
|
|
|
uint32_t result = mmu_read_vmem<uint32_t>(ea, instr);
|
2024-02-04 03:23:24 -08:00
|
|
|
ppc_state.fpr[reg_d].dbl64_r = *(float*)(&result);
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODE (lfsu,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdia(instr);
|
2021-01-25 01:29:58 +01:00
|
|
|
if (reg_a) {
|
2024-09-17 08:08:29 -07:00
|
|
|
uint32_t ea = int32_t(int16_t(instr));
|
2024-08-19 21:01:07 +02:00
|
|
|
ea += (reg_a) ? val_reg_a : 0;
|
2024-09-17 08:08:29 -07:00
|
|
|
uint32_t result = mmu_read_vmem<uint32_t>(ea, instr);
|
2024-02-04 03:23:24 -08:00
|
|
|
ppc_state.fpr[reg_d].dbl64_r = *(float*)(&result);
|
2024-08-19 21:01:07 +02:00
|
|
|
ppc_state.gpr[reg_a] = ea;
|
2020-05-12 23:55:45 +05:00
|
|
|
} else {
|
2020-11-30 20:59:36 +01:00
|
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
2020-01-25 19:30:55 -07:00
|
|
|
}
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODE (lfsx,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdiab(instr);
|
2024-08-19 21:01:07 +02:00
|
|
|
uint32_t ea = val_reg_b + (reg_a ? val_reg_a : 0);
|
2024-09-17 08:08:29 -07:00
|
|
|
uint32_t result = mmu_read_vmem<uint32_t>(ea, instr);
|
2024-02-04 03:23:24 -08:00
|
|
|
ppc_state.fpr[reg_d].dbl64_r = *(float*)(&result);
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODE (lfsux,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdiab(instr);
|
2021-01-25 01:29:58 +01:00
|
|
|
if (reg_a) {
|
2024-08-19 21:01:07 +02:00
|
|
|
uint32_t ea = val_reg_a + val_reg_b;
|
2024-09-17 08:08:29 -07:00
|
|
|
uint32_t result = mmu_read_vmem<uint32_t>(ea, instr);
|
2024-02-04 03:23:24 -08:00
|
|
|
ppc_state.fpr[reg_d].dbl64_r = *(float*)(&result);
|
2024-08-19 21:01:07 +02:00
|
|
|
ppc_state.gpr[reg_a] = ea;
|
2020-05-12 23:55:45 +05:00
|
|
|
} else {
|
2020-11-30 20:59:36 +01:00
|
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
2020-01-25 19:30:55 -07:00
|
|
|
}
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODE (lfd,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdia(instr);
|
|
|
|
uint32_t ea = int32_t(int16_t(instr));
|
2024-08-19 21:01:07 +02:00
|
|
|
ea += (reg_a) ? val_reg_a : 0;
|
2024-09-17 08:08:29 -07:00
|
|
|
uint64_t ppc_result64_d = mmu_read_vmem<uint64_t>(ea, instr);
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_dfpresult_int(reg_d, ppc_result64_d);
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODE (lfdu,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdia(instr);
|
2020-11-29 06:52:01 -07:00
|
|
|
if (reg_a != 0) {
|
2024-09-17 08:08:29 -07:00
|
|
|
uint32_t ea = int32_t(int16_t(instr));
|
2024-08-19 21:01:07 +02:00
|
|
|
ea += val_reg_a;
|
2024-09-17 08:08:29 -07:00
|
|
|
uint64_t ppc_result64_d = mmu_read_vmem<uint64_t>(ea, instr);
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_dfpresult_int(reg_d, ppc_result64_d);
|
2024-08-19 21:01:07 +02:00
|
|
|
ppc_state.gpr[reg_a] = ea;
|
2020-05-12 23:55:45 +05:00
|
|
|
} else {
|
2020-11-30 20:59:36 +01:00
|
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
2020-01-25 19:30:55 -07:00
|
|
|
}
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2020-01-25 19:30:55 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODE (lfdx,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdiab(instr);
|
2024-08-19 21:01:07 +02:00
|
|
|
uint32_t ea = val_reg_b + (reg_a ? val_reg_a : 0);
|
2024-09-17 08:08:29 -07:00
|
|
|
uint64_t ppc_result64_d = mmu_read_vmem<uint64_t>(ea, instr);
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_dfpresult_int(reg_d, ppc_result64_d);
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2020-01-25 19:30:55 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODE (lfdux,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdiab(instr);
|
2021-01-25 01:29:58 +01:00
|
|
|
if (reg_a) {
|
2024-08-19 21:01:07 +02:00
|
|
|
uint32_t ea = val_reg_a + val_reg_b;
|
2024-09-17 08:08:29 -07:00
|
|
|
uint64_t ppc_result64_d = mmu_read_vmem<uint64_t>(ea, instr);
|
2024-03-22 08:01:29 -07:00
|
|
|
ppc_store_dfpresult_int(reg_d, ppc_result64_d);
|
2024-08-19 21:01:07 +02:00
|
|
|
ppc_state.gpr[reg_a] = ea;
|
2020-05-12 23:55:45 +05:00
|
|
|
} else {
|
2020-11-30 20:59:36 +01:00
|
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
2020-01-25 19:30:55 -07:00
|
|
|
}
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODE (stfs,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpsia(instr);
|
|
|
|
uint32_t ea = int32_t(int16_t(instr));
|
2024-08-19 21:01:07 +02:00
|
|
|
ea += (reg_a) ? val_reg_a : 0;
|
2024-09-08 13:19:07 -07:00
|
|
|
float result = float(ppc_state.fpr[reg_s].dbl64_r);
|
2024-09-17 08:08:29 -07:00
|
|
|
mmu_write_vmem<uint32_t>(ea, instr, *(uint32_t*)(&result));
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODE (stfsu,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpsia(instr);
|
2020-11-29 06:52:01 -07:00
|
|
|
if (reg_a != 0) {
|
2024-09-17 08:08:29 -07:00
|
|
|
uint32_t ea = int32_t(int16_t(instr));
|
2024-08-19 21:01:07 +02:00
|
|
|
ea += val_reg_a;
|
2024-09-08 13:19:07 -07:00
|
|
|
float result = float(ppc_state.fpr[reg_s].dbl64_r);
|
2024-09-17 08:08:29 -07:00
|
|
|
mmu_write_vmem<uint32_t>(ea, instr, *(uint32_t*)(&result));
|
2024-08-19 21:01:07 +02:00
|
|
|
ppc_state.gpr[reg_a] = ea;
|
2020-05-12 23:55:45 +05:00
|
|
|
} else {
|
2020-11-30 20:59:36 +01:00
|
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
2020-01-25 19:30:55 -07:00
|
|
|
}
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODE (stfsx,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpsiab(instr);
|
2024-08-19 21:01:07 +02:00
|
|
|
uint32_t ea = val_reg_b + (reg_a ? val_reg_a : 0);
|
2024-09-08 13:19:07 -07:00
|
|
|
float result = float(ppc_state.fpr[reg_s].dbl64_r);
|
2024-09-17 08:08:29 -07:00
|
|
|
mmu_write_vmem<uint32_t>(ea, instr, *(uint32_t*)(&result));
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2020-01-25 19:30:55 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODE (stfsux,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpsiab(instr);
|
2021-01-25 01:29:58 +01:00
|
|
|
if (reg_a) {
|
2024-08-19 21:01:07 +02:00
|
|
|
uint32_t ea = val_reg_a + val_reg_b;
|
2024-09-08 13:19:07 -07:00
|
|
|
float result = float(ppc_state.fpr[reg_s].dbl64_r);
|
2024-09-17 08:08:29 -07:00
|
|
|
mmu_write_vmem<uint32_t>(ea, instr, *(uint32_t*)(&result));
|
2024-08-19 21:01:07 +02:00
|
|
|
ppc_state.gpr[reg_a] = ea;
|
2020-05-12 23:55:45 +05:00
|
|
|
} else {
|
2020-11-30 20:59:36 +01:00
|
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
2020-01-25 19:30:55 -07:00
|
|
|
}
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODE (stfd,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpsia(instr);
|
|
|
|
uint32_t ea = int32_t(int16_t(instr));
|
2024-08-19 21:01:07 +02:00
|
|
|
ea += reg_a ? val_reg_a : 0;
|
2024-09-17 08:08:29 -07:00
|
|
|
mmu_write_vmem<uint64_t>(ea, instr, ppc_state.fpr[reg_s].int64_r);
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODE (stfdu,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpsia(instr);
|
2020-11-29 06:52:01 -07:00
|
|
|
if (reg_a != 0) {
|
2024-09-17 08:08:29 -07:00
|
|
|
uint32_t ea = int32_t(int16_t(instr));
|
2024-08-19 21:01:07 +02:00
|
|
|
ea += val_reg_a;
|
2024-09-17 08:08:29 -07:00
|
|
|
mmu_write_vmem<uint64_t>(ea, instr, ppc_state.fpr[reg_s].int64_r);
|
2024-08-19 21:01:07 +02:00
|
|
|
ppc_state.gpr[reg_a] = ea;
|
2020-05-12 23:55:45 +05:00
|
|
|
} else {
|
2020-11-30 20:59:36 +01:00
|
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
2020-01-25 19:30:55 -07:00
|
|
|
}
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODE (stfdx,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpsiab(instr);
|
2024-08-19 21:01:07 +02:00
|
|
|
uint32_t ea = val_reg_b + (reg_a ? val_reg_a : 0);
|
2024-09-17 08:08:29 -07:00
|
|
|
mmu_write_vmem<uint64_t>(ea, instr, ppc_state.fpr[reg_s].int64_r);
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODE (stfdux,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpsiab(instr);
|
2020-11-29 06:52:01 -07:00
|
|
|
if (reg_a != 0) {
|
2024-08-19 21:01:07 +02:00
|
|
|
uint32_t ea = val_reg_a + val_reg_b;
|
2024-09-17 08:08:29 -07:00
|
|
|
mmu_write_vmem<uint64_t>(ea, instr, ppc_state.fpr[reg_s].int64_r);
|
2024-08-19 21:01:07 +02:00
|
|
|
ppc_state.gpr[reg_a] = ea;
|
2020-05-12 23:55:45 +05:00
|
|
|
} else {
|
2020-11-30 20:59:36 +01:00
|
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
|
2020-01-25 19:30:55 -07:00
|
|
|
}
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODE (stfiwx,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpsiab(instr);
|
2024-08-19 21:01:07 +02:00
|
|
|
uint32_t ea = val_reg_b + (reg_a ? val_reg_a : 0);
|
2024-09-17 08:08:29 -07:00
|
|
|
mmu_write_vmem<uint32_t>(ea, instr, uint32_t(ppc_state.fpr[reg_s].int64_r));
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2020-01-21 19:25:50 -07:00
|
|
|
|
2020-05-12 23:55:45 +05:00
|
|
|
// Floating Point Register Transfer
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (fmr,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpdb(instr);
|
2021-01-24 23:06:33 +01:00
|
|
|
ppc_state.fpr[reg_d].dbl64_r = ppc_state.fpr[reg_b].dbl64_r;
|
2023-11-19 17:56:30 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_fmr<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_fmr<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODE601REC (mffs,
|
2024-09-17 08:08:29 -07:00
|
|
|
int reg_d = (instr >> 21) & 31;
|
2023-11-29 18:55:15 +01:00
|
|
|
|
2024-03-07 02:21:01 -08:00
|
|
|
ppc_state.fpr[reg_d].int64_r = uint64_t(ppc_state.fpscr) | (for601 ? 0xFFFFFFFF00000000ULL : 0xFFF8000000000000ULL);
|
2024-02-05 06:02:26 -08:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2024-02-05 06:02:26 -08:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2024-02-05 06:02:26 -08:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_mffs<NOT601, RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_mffs<NOT601, RC1>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_mffs<IS601, RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_mffs<IS601, RC1>(uint32_t instr);
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (mtfsf,
|
2024-09-17 08:08:29 -07:00
|
|
|
int reg_b = (instr >> 11) & 0x1F;
|
|
|
|
uint8_t fm = (instr >> 17) & 0xFF;
|
2024-01-02 16:44:21 +01:00
|
|
|
|
2023-11-28 07:06:04 -07:00
|
|
|
uint32_t cr_mask = 0;
|
2024-01-02 16:44:21 +01:00
|
|
|
|
|
|
|
if (fm == 0xFFU) // the fast case
|
|
|
|
cr_mask = 0xFFFFFFFFUL;
|
|
|
|
else { // the slow case
|
|
|
|
if (fm & 0x80) cr_mask |= 0xF0000000UL;
|
|
|
|
if (fm & 0x40) cr_mask |= 0x0F000000UL;
|
|
|
|
if (fm & 0x20) cr_mask |= 0x00F00000UL;
|
|
|
|
if (fm & 0x10) cr_mask |= 0x000F0000UL;
|
|
|
|
if (fm & 0x08) cr_mask |= 0x0000F000UL;
|
|
|
|
if (fm & 0x04) cr_mask |= 0x00000F00UL;
|
|
|
|
if (fm & 0x02) cr_mask |= 0x000000F0UL;
|
|
|
|
if (fm & 0x01) cr_mask |= 0x0000000FUL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ensure neither FEX nor VX will be changed
|
|
|
|
cr_mask &= ~(FPSCR::FEX | FPSCR::VX);
|
|
|
|
|
|
|
|
// copy FPR[reg_b] to FPSCR under control of cr_mask
|
|
|
|
ppc_state.fpscr = (ppc_state.fpscr & ~cr_mask) | (ppc_state.fpr[reg_b].int64_r & cr_mask);
|
2019-07-11 22:27:14 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2020-01-11 18:43:47 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_mtfsf<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_mtfsf<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (mtfsfi,
|
2024-09-17 08:08:29 -07:00
|
|
|
int crf_d = (instr >> 21) & 0x1C;
|
|
|
|
uint32_t imm = (instr << 16) & 0xF0000000UL;
|
2024-01-02 16:12:12 +01:00
|
|
|
|
|
|
|
// prepare field mask and ensure that neither FEX nor VX will be changed
|
|
|
|
uint32_t mask = (0xF0000000UL >> crf_d) & ~(FPSCR::FEX | FPSCR::VX);
|
|
|
|
|
|
|
|
// copy imm to FPSCR[crf_d] under control of the field mask
|
|
|
|
ppc_state.fpscr = (ppc_state.fpscr & ~mask) | ((imm >> crf_d) & mask);
|
|
|
|
|
2024-04-09 21:11:09 -07:00
|
|
|
// Update FEX and VX according to the "usual rule"
|
|
|
|
ppc_update_vx();
|
|
|
|
ppc_update_fex();
|
2020-01-11 18:43:47 -07:00
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_mtfsfi<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_mtfsfi<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (mtfsb0,
|
2024-09-17 08:08:29 -07:00
|
|
|
int crf_d = (instr >> 21) & 0x1F;
|
2024-04-06 11:02:03 -07:00
|
|
|
if (!crf_d || (crf_d > 2)) { // FEX and VX can't be explicitly cleared
|
2021-07-09 01:02:44 +02:00
|
|
|
ppc_state.fpscr &= ~(0x80000000UL >> crf_d);
|
2019-07-01 19:15:33 -07:00
|
|
|
}
|
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_mtfsb0<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_mtfsb0<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODEREC (mtfsb1,
|
2024-09-17 08:08:29 -07:00
|
|
|
int crf_d = (instr >> 21) & 0x1F;
|
2024-04-06 11:02:03 -07:00
|
|
|
if (!crf_d || (crf_d > 2)) { // FEX and VX can't be explicitly set
|
2021-07-09 01:02:44 +02:00
|
|
|
ppc_state.fpscr |= (0x80000000UL >> crf_d);
|
2019-07-01 19:15:33 -07:00
|
|
|
}
|
|
|
|
|
2024-03-24 12:21:19 -07:00
|
|
|
if (rec)
|
2023-11-29 18:52:14 +01:00
|
|
|
ppc_update_cr1();
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-17 21:18:54 -07:00
|
|
|
template void dppc_interpreter::ppc_mtfsb1<RC0>(uint32_t instr);
|
|
|
|
template void dppc_interpreter::ppc_mtfsb1<RC1>(uint32_t instr);
|
2024-03-24 12:21:19 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODE (mcrfs,
|
2024-09-17 08:08:29 -07:00
|
|
|
int crf_d = (instr >> 21) & 0x1C;
|
|
|
|
int crf_s = (instr >> 16) & 0x1C;
|
2023-12-17 05:03:36 -08:00
|
|
|
ppc_state.cr = (
|
|
|
|
(ppc_state.cr & ~(0xF0000000UL >> crf_d)) |
|
|
|
|
(((ppc_state.fpscr << crf_s) & 0xF0000000UL) >> crf_d)
|
|
|
|
);
|
|
|
|
ppc_state.fpscr &= ~((0xF0000000UL >> crf_s) & (
|
|
|
|
// keep only the FPSCR bits that can be explicitly cleared
|
|
|
|
FPSCR::FX | FPSCR::OX |
|
|
|
|
FPSCR::UX | FPSCR::ZX | FPSCR::XX | FPSCR::VXSNAN |
|
|
|
|
FPSCR::VXISI | FPSCR::VXIDI | FPSCR::VXZDZ | FPSCR::VXIMZ |
|
|
|
|
FPSCR::VXVC |
|
|
|
|
FPSCR::VXSOFT | FPSCR::VXSQRT | FPSCR::VXCVI
|
|
|
|
));
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2020-05-12 23:55:45 +05:00
|
|
|
// Floating Point Comparisons
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODE (fcmpo,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpsab(instr);
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2023-12-16 05:30:02 -08:00
|
|
|
uint32_t cmp_c = 0;
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2020-01-21 19:25:50 -07:00
|
|
|
if (std::isnan(db_test_a) || std::isnan(db_test_b)) {
|
2023-12-19 14:26:51 +01:00
|
|
|
cmp_c |= CRx_bit::CR_SO;
|
2024-08-19 21:01:07 +02:00
|
|
|
ppc_state.fpscr |= FX | VX;
|
2024-04-06 11:02:03 -07:00
|
|
|
if (check_snan(reg_a) || check_snan(reg_b)) {
|
|
|
|
ppc_state.fpscr |= VXSNAN;
|
|
|
|
}
|
|
|
|
if (!(ppc_state.fpscr & FEX) || check_qnan(reg_a) || check_qnan(reg_b)) {
|
|
|
|
ppc_state.fpscr |= VXVC;
|
|
|
|
}
|
2021-10-30 16:43:13 -07:00
|
|
|
}
|
2023-11-19 17:56:30 -07:00
|
|
|
else if (db_test_a < db_test_b) {
|
2023-12-19 14:26:51 +01:00
|
|
|
cmp_c |= CRx_bit::CR_LT;
|
2022-02-17 00:11:14 +01:00
|
|
|
}
|
2021-10-30 16:43:13 -07:00
|
|
|
else if (db_test_a > db_test_b) {
|
2023-12-19 14:26:51 +01:00
|
|
|
cmp_c |= CRx_bit::CR_GT;
|
2021-10-30 16:43:13 -07:00
|
|
|
}
|
|
|
|
else {
|
2023-12-19 14:26:51 +01:00
|
|
|
cmp_c |= CRx_bit::CR_EQ;
|
2019-07-01 19:15:33 -07:00
|
|
|
}
|
|
|
|
|
2024-04-06 11:02:03 -07:00
|
|
|
ppc_state.fpscr &= ~VE; //kludge to pass tests
|
2023-12-19 11:58:12 +01:00
|
|
|
ppc_state.fpscr = (ppc_state.fpscr & ~FPSCR::FPCC_MASK) | (cmp_c >> 16); // update FPCC
|
2024-02-18 07:06:27 -07:00
|
|
|
ppc_state.cr = ((ppc_state.cr & ~(0xF0000000 >> crf_d)) | (cmp_c >> crf_d));
|
2024-04-06 11:02:03 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
OPCODE (fcmpu,
|
2024-09-17 08:08:29 -07:00
|
|
|
ppc_grab_regsfpsab(instr);
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2023-12-16 05:30:02 -08:00
|
|
|
uint32_t cmp_c = 0;
|
2019-07-01 19:15:33 -07:00
|
|
|
|
2020-01-21 19:25:50 -07:00
|
|
|
if (std::isnan(db_test_a) || std::isnan(db_test_b)) {
|
2023-12-19 14:26:51 +01:00
|
|
|
cmp_c |= CRx_bit::CR_SO;
|
2024-04-06 11:02:03 -07:00
|
|
|
if (check_snan(reg_a) || check_snan(reg_b)) {
|
|
|
|
ppc_state.fpscr |= FX | VX | VXSNAN;
|
|
|
|
}
|
2021-10-30 16:43:13 -07:00
|
|
|
}
|
2023-11-19 17:56:30 -07:00
|
|
|
else if (db_test_a < db_test_b) {
|
2023-12-19 14:26:51 +01:00
|
|
|
cmp_c |= CRx_bit::CR_LT;
|
2022-02-17 00:11:14 +01:00
|
|
|
}
|
2021-10-30 16:43:13 -07:00
|
|
|
else if (db_test_a > db_test_b) {
|
2023-12-19 14:26:51 +01:00
|
|
|
cmp_c |= CRx_bit::CR_GT;
|
2021-10-30 16:43:13 -07:00
|
|
|
}
|
|
|
|
else {
|
2023-12-19 14:26:51 +01:00
|
|
|
cmp_c |= CRx_bit::CR_EQ;
|
2019-07-01 19:15:33 -07:00
|
|
|
}
|
|
|
|
|
2024-04-06 11:02:03 -07:00
|
|
|
ppc_state.fpscr &= ~VE; //kludge to pass tests
|
2023-12-19 11:58:12 +01:00
|
|
|
ppc_state.fpscr = (ppc_state.fpscr & ~FPSCR::FPCC_MASK) | (cmp_c >> 16); // update FPCC
|
2024-02-18 07:06:27 -07:00
|
|
|
ppc_state.cr = ((ppc_state.cr & ~(0xF0000000UL >> crf_d)) | (cmp_c >> crf_d));
|
2024-04-06 11:02:03 -07:00
|
|
|
|
2024-09-21 17:56:18 -07:00
|
|
|
)
|