Merge pull request #21 from dingusdev/floating-point

Floating point fixes. Rehauled floating-point emulation code. Fixed a test suite for floating points.
This commit is contained in:
dingusdev 2021-10-19 07:18:21 -07:00 committed by GitHub
commit 7919cd0590
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 4577 additions and 386 deletions

View File

@ -169,6 +169,7 @@ if (DPPC_BUILD_PPC_TESTS)
TARGET testppc POST_BUILD TARGET testppc POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy COMMAND ${CMAKE_COMMAND} -E copy
"${PROJECT_SOURCE_DIR}/cpu/ppc/test/ppcinttests.csv" "${PROJECT_SOURCE_DIR}/cpu/ppc/test/ppcinttests.csv"
"${PROJECT_SOURCE_DIR}/cpu/ppc/test/ppcfloattests.csv"
"${PROJECT_SOURCE_DIR}/cpu/ppc/test/ppcdisasmtest.csv" "${PROJECT_SOURCE_DIR}/cpu/ppc/test/ppcdisasmtest.csv"
$<TARGET_FILE_DIR:${PROJECT_NAME}>) $<TARGET_FILE_DIR:${PROJECT_NAME}>)
endif() endif()

View File

@ -200,6 +200,71 @@ enum class BB_end_kind {
BB_RFI /* the rfi instruction is encountered */ BB_RFI /* the rfi instruction is encountered */
}; };
enum CR_select : int32_t {
CR0_field = (0xF << 28),
CR1_field = (0xF << 24),
};
enum CRx_bit : uint32_t {
CR_SO = 0,
CR_EQ,
CR_GT,
CR_LT
};
enum CR1_bit : uint32_t {
CR1_OX = 24,
CR1_VX,
CR1_FEX,
CR1_FX,
};
enum FPSCR : uint32_t {
RN = 0x3,
NI = 0x4,
XE = 0x8,
ZE = 0x10,
UE = 0x20,
OE = 0x40,
VE = 0x80,
VXCVI = 0x100,
VXSQRT = 0x200,
VXSOFT = 0x400,
FPRF = 0x1F000,
FPCC_FUNAN = 0x10000,
FPCC_NEG = 0x8000,
FPCC_POS = 0x4000,
FPCC_ZERO = 0x2000,
FPCC_FPRCD = 0x1000,
FI = 0x20000,
FR = 0x40000,
VXVC = 0x80000,
VXIMZ = 0x100000,
VXZDZ = 0x200000,
VXIDI = 0x400000,
VXISI = 0x800000,
VXSNAN = 0x1000000,
XX = 0x2000000,
ZX = 0x4000000,
UX = 0x8000000,
OX = 0x10000000,
VX = 0x20000000,
FEX = 0x40000000,
FX = 0x80000000
};
//for inf and nan checks
enum FPOP : int {
DIV = 0x12,
SUB = 0x14,
ADD = 0x15,
MUL = 0x19,
FMSUB = 0x1C,
FMADD = 0x1D,
FNMSUB = 0x1E,
FNMADD = 0x1F,
};
/** PowerPC exception types. */ /** PowerPC exception types. */
enum class Except_Type { enum class Except_Type {
EXC_SYSTEM_RESET = 1, EXC_SYSTEM_RESET = 1,
@ -271,7 +336,6 @@ void ppc_opcode63();
void initialize_ppc_opcode_tables(); void initialize_ppc_opcode_tables();
extern bool ppc_confirm_inf_nan(uint64_t input_a, uint64_t input_b, bool is_single, uint32_t op);
extern double fp_return_double(uint32_t reg); extern double fp_return_double(uint32_t reg);
extern uint64_t fp_return_uint64(uint32_t reg); extern uint64_t fp_return_uint64(uint32_t reg);
@ -416,15 +480,10 @@ extern void ppc_mtspr();
extern void ppc_mtfsb0(); extern void ppc_mtfsb0();
extern void ppc_mtfsb1(); extern void ppc_mtfsb1();
extern void ppc_mcrfs(); extern void ppc_mcrfs();
extern void ppc_mtfsb0dot();
extern void ppc_mtfsb1dot();
extern void ppc_fmr(); extern void ppc_fmr();
extern void ppc_mffs(); extern void ppc_mffs();
extern void ppc_mffsdot();
extern void ppc_mtfsf(); extern void ppc_mtfsf();
extern void ppc_mtfsfdot();
extern void ppc_mtfsfi(); extern void ppc_mtfsfi();
extern void ppc_mtfsfidot();
extern void ppc_addi(); extern void ppc_addi();
extern void ppc_addic(); extern void ppc_addic();

View File

@ -253,8 +253,7 @@ void ppc_opcode31() {
oe_flag = ppc_cur_instruction & 0x400; oe_flag = ppc_cur_instruction & 0x400;
#ifdef EXHAUSTIVE_DEBUG #ifdef EXHAUSTIVE_DEBUG
uint32_t regrab = (uint32_t)subop_grab; LOG_F(INFO, "Executing Opcode 31 table subopcode entry %n \n", (uint32_t)subop_grab);
LOG_F(INFO, "Executing Opcode 63 table subopcode entry \n", regrab);
#endif // EXHAUSTIVE_DEBUG #endif // EXHAUSTIVE_DEBUG
SubOpcode31Grabber[subop_grab](); SubOpcode31Grabber[subop_grab]();
@ -264,8 +263,7 @@ void ppc_opcode59() {
uint16_t subop_grab = (ppc_cur_instruction >> 1) & 0x1F; uint16_t subop_grab = (ppc_cur_instruction >> 1) & 0x1F;
rc_flag = ppc_cur_instruction & 1; rc_flag = ppc_cur_instruction & 1;
#ifdef EXHAUSTIVE_DEBUG #ifdef EXHAUSTIVE_DEBUG
uint32_t regrab = (uint32_t)subop_grab; LOG_F(INFO, "Executing Opcode 59 table subopcode entry %n \n", (uint32_t)subop_grab);
LOG_F(INFO, "Executing Opcode 59 table subopcode entry \n", regrab);
#endif // EXHAUSTIVE_DEBUG #endif // EXHAUSTIVE_DEBUG
SubOpcode59Grabber[subop_grab](); SubOpcode59Grabber[subop_grab]();
} }
@ -274,8 +272,7 @@ void ppc_opcode63() {
uint16_t subop_grab = (ppc_cur_instruction >> 1) & 0x3FF; uint16_t subop_grab = (ppc_cur_instruction >> 1) & 0x3FF;
rc_flag = ppc_cur_instruction & 1; rc_flag = ppc_cur_instruction & 1;
#ifdef EXHAUSTIVE_DEBUG #ifdef EXHAUSTIVE_DEBUG
uint32_t regrab = (uint32_t)subop_grab; LOG_F(INFO, "Executing Opcode 63 table subopcode entry %n \n", (uint32_t)subop_grab);
LOG_F(INFO, "Executing Opcode 63 table subopcode entry \n", regrab);
#endif // EXHAUSTIVE_DEBUG #endif // EXHAUSTIVE_DEBUG
SubOpcode63Grabber[subop_grab](); SubOpcode63Grabber[subop_grab]();
} }

View File

@ -25,6 +25,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "ppcmmu.h" #include "ppcmmu.h"
#include <array> #include <array>
#include <cfenv> #include <cfenv>
#include <cfloat>
#include <cinttypes> #include <cinttypes>
#include <cmath> #include <cmath>
#include <iostream> #include <iostream>
@ -150,20 +151,11 @@ void ppc_fp_changecrf1() {
ppc_state.fpscr |= 0xf0000000; ppc_state.fpscr |= 0xf0000000;
} }
void ppc_divbyzero(uint64_t input_a, uint64_t input_b, bool is_single) {
if (input_b == 0) {
ppc_state.fpscr |= 0x84000000;
if (input_a == 0) {
ppc_state.fpscr |= 0x200000;
}
}
}
int64_t round_to_nearest(double f) { int64_t round_to_nearest(double f) {
if (f >= 0.0) { if (f >= 0.0) {
return static_cast<int32_t>(static_cast<int64_t> (f + 0.5)); return static_cast<int32_t>(static_cast<int64_t> (ceil(f)));
} else { } else {
return static_cast<int32_t>(static_cast<int64_t> (-f + 0.5)); return static_cast<int32_t>(static_cast<int64_t> (floor(f)));
} }
} }
@ -179,153 +171,113 @@ int64_t round_to_neg_inf(double f) {
return static_cast<int32_t>(floor(f)); return static_cast<int32_t>(floor(f));
} }
void ppc_toggle_fpscr_fex() { void update_fex() {
bool fex_result = ((ppc_state.fpscr & 0x20000000) & (ppc_state.fpscr & 0x80)); int fex_result = !!((ppc_state.fpscr & (ppc_state.fpscr << 22)) & 0x3E000000);
fex_result |= ((ppc_state.fpscr & 0x10000000) & (ppc_state.fpscr & 0x40)); ppc_state.fpscr = (ppc_state.fpscr & ~0x40000000) | (fex_result << 30);
fex_result |= ((ppc_state.fpscr & 0x8000000) & (ppc_state.fpscr & 0x20));
fex_result |= ((ppc_state.fpscr & 0x4000000) & (ppc_state.fpscr & 0x10));
fex_result |= ((ppc_state.fpscr & 0x2000000) & (ppc_state.fpscr & 0x8));
ppc_state.fpscr |= (fex_result << 30);
} }
bool ppc_confirm_inf_nan(int chosen_reg_1, int chosen_reg_2, bool is_single, uint32_t op) { template <typename T, const FPOP fpop>
uint64_t input_a = ppc_state.fpr[chosen_reg_1].int64_r; void ppc_confirm_inf_nan(int chosen_reg_1, int chosen_reg_2, int chosen_reg_3, bool rc_flag = false) {
uint64_t input_b = ppc_state.fpr[chosen_reg_2].int64_r; T input_a = T(ppc_state.fpr[chosen_reg_1].int64_r);
T input_b = T(ppc_state.fpr[chosen_reg_2].int64_r);
T input_c = T(ppc_state.fpr[chosen_reg_3].int64_r);
if (is_single) { ppc_state.fpscr &= 0x7fbfffff;
uint32_t exp_a = (input_a >> 23) & 0xff;
uint32_t exp_b = (input_b >> 23) & 0xff;
ppc_state.fpscr &= 0x7fbfffff; switch (fpop) {
case FPOP::DIV:
if (isnan(input_a) && isnan(input_b)) {
ppc_state.fpscr |= (FPSCR::FX | FPSCR::VXIDI);
} else if ((input_a == FP_ZERO) && (input_b == FP_ZERO)) {
ppc_state.fpscr |= (FPSCR::FX | FPSCR::VXZDZ);
}
update_fex();
break;
case FPOP::SUB:
if (isnan(input_a) && isnan(input_b)) {
ppc_state.fpscr |= (FPSCR::FX | FPSCR::VXISI);
}
update_fex();
break;
case FPOP::ADD:
if (isnan(input_a) && isnan(input_b)) {
ppc_state.fpscr |= (FPSCR::FX | FPSCR::VXISI);
}
update_fex();
break;
case FPOP::MUL:
if (((input_a == FP_ZERO) && (input_c == FP_INFINITE)) ||
((input_c == FP_ZERO) && (input_a == FP_INFINITE))) {
ppc_state.fpscr |=
(FPSCR::FX | FPSCR::VXSNAN |
FPSCR::VXIMZ);
}
update_fex();
break;
case FPOP::FMSUB:
case FPOP::FNMSUB:
if (isnan(input_a) || isnan(input_b) || isnan(input_c)) {
ppc_state.fpscr |= FPSCR::VXSNAN;
if (((input_a == FP_ZERO) && (input_c == FP_INFINITE)) ||
((input_c == FP_ZERO) && (input_a == FP_INFINITE))) {
ppc_state.fpscr |= FPSCR::VXIMZ;
}
}
switch (op) { update_fex();
case 36:
if ((exp_a == 0xff) && (exp_b == 0xff)) {
ppc_state.fpscr |= 0x80400000;
ppc_toggle_fpscr_fex();
return true;
} else if ((input_a == 0) && (input_b == 0)) {
ppc_state.fpscr |= 0x80200000;
ppc_toggle_fpscr_fex();
return true;
}
break; break;
case 40: case FPOP::FMADD:
if ((exp_a == 0xff) && (exp_b == 0xff)) { case FPOP::FNMADD:
ppc_state.fpscr |= 0x80800000; if (isnan(input_a) || isnan(input_b) || isnan(input_c)) {
ppc_toggle_fpscr_fex(); ppc_state.fpscr |= (FPSCR::VXSNAN | FPSCR::FPCC_FUNAN);
return true;
} }
update_fex();
break; break;
case 50:
if (((exp_a == 0xff) & (input_b == 0)) | ((exp_b == 0xff) & (input_a == 0))) {
ppc_state.fpscr |= 0x80100000;
ppc_toggle_fpscr_fex();
return true;
}
break;
case 56:
case 58:
if ((exp_a == 0xff) && (exp_b == 0xff)) {
ppc_state.fpscr |= 0x80800000;
ppc_toggle_fpscr_fex();
return true;
}
break;
default:
return false;
} }
} else {
uint32_t exp_a = (input_a >> 52) & 0x7ff;
uint32_t exp_b = (input_b >> 52) & 0x7ff;
ppc_state.fpscr &= 0x7fbfffff;
switch (op) {
case 36:
if ((exp_a == 0x7ff) && (exp_b == 0x7ff)) {
ppc_state.fpscr |= 0x80400000;
ppc_toggle_fpscr_fex();
return true;
} else if ((input_a == 0) && (input_b == 0)) {
ppc_state.fpscr |= 0x80200000;
ppc_toggle_fpscr_fex();
return true;
}
break;
case 40:
if ((exp_a == 0x7ff) && (exp_b == 0x7ff)) {
ppc_state.fpscr |= 0x80800000;
ppc_toggle_fpscr_fex();
return true;
}
break;
case 50:
if (((exp_a == 0x7ff) & (input_b == 0)) | ((exp_b == 0x7ff) & (input_a == 0))) {
ppc_state.fpscr |= 0x80100000;
ppc_toggle_fpscr_fex();
return true;
}
break;
case 56:
case 58:
if ((exp_a == 0xff) && (exp_b == 0xff)) {
ppc_state.fpscr |= 0x80800000;
ppc_toggle_fpscr_fex();
return true;
}
break;
default:
return false;
}
}
return false;
} }
void fpresult_update(uint64_t set_result, bool confirm_arc) { void fpresult_update(double set_result, bool confirm_arc) {
bool confirm_ov = (bool)std::fetestexcept(FE_OVERFLOW); bool confirm_ov = (bool)std::fetestexcept(FE_OVERFLOW);
if (ppc_state.fpscr & 0x3)
ppc_state.cr |= 0x2;
if (set_result > 0.0) {
ppc_state.fpscr |= FPSCR::FPCC_POS;
} else if (set_result < 0.0) {
ppc_state.fpscr |= FPSCR::FPCC_NEG;
} else if (set_result == 0.0) {
ppc_state.fpscr |= FPSCR::FPCC_ZERO;
} else {
ppc_state.fpscr |= FPSCR::FPCC_FPRCD;
}
if (confirm_ov) { if (confirm_ov) {
ppc_state.fpscr |= 0x80001000; ppc_state.fpscr |= (FPSCR::FX | (FPSCR::FPRF & FPSCR::FPCC_FUNAN));
} }
if (confirm_arc) { if (confirm_arc) {
ppc_state.fpscr |= 0x80010000; ppc_state.fpscr |= (FPSCR::FX | (FPSCR::FPRF & FPSCR::FPCC_FUNAN));
ppc_state.fpscr &= 0xFFFF0FFF; //ppc_state.fpscr &= 0xFFFF0FFF;
if (set_result == 0) {
ppc_state.fpscr |= 0x2000;
} else {
if (set_result < 0) {
ppc_state.fpscr |= 0x8000;
} else if (set_result > 0) {
ppc_state.fpscr |= 0x4000;
} else {
ppc_state.fpscr |= 0x1000;
}
}
}
}
void ppc_frsqrte_result() {
if (ppc_result64_d & 0x007FF000000000000UL) {
} }
} }
void ppc_changecrf1() { void ppc_changecrf1() {
ppc_state.cr &= 0xF0FFFFFF; ppc_state.cr &= ~((uint32_t)CR_select::CR1_field);
ppc_state.cr |= (ppc_state.fpscr & 0xF0000000) >> 4; ppc_state.cr |= (ppc_state.fpscr & (uint32_t)CR_select::CR0_field) >> 4;
} }
// Floating Point Arithmetic // Floating Point Arithmetic
void dppc_interpreter::ppc_fadd() { void dppc_interpreter::ppc_fadd() {
ppc_grab_regsfpdab(); ppc_grab_regsfpdab();
if (!ppc_confirm_inf_nan(reg_a, reg_b, false, 58)) { ppc_dblresult64_d = val_reg_a + val_reg_b;
ppc_dblresult64_d = val_reg_a + val_reg_b;
if (!isnan(ppc_dblresult64_d)) {
ppc_store_dfpresult_flt(reg_d); ppc_store_dfpresult_flt(reg_d);
fpresult_update(ppc_dblresult64_d, rc_flag);
} else {
ppc_confirm_inf_nan<double, ADD>(reg_a, reg_b, 0, rc_flag);
} }
if (rc_flag) if (rc_flag)
@ -335,9 +287,13 @@ void dppc_interpreter::ppc_fadd() {
void dppc_interpreter::ppc_fsub() { void dppc_interpreter::ppc_fsub() {
ppc_grab_regsfpdab(); ppc_grab_regsfpdab();
if (!ppc_confirm_inf_nan(reg_a, reg_b, false, 56)) { ppc_dblresult64_d = val_reg_a - val_reg_b;
ppc_dblresult64_d = val_reg_a - val_reg_b;
if (!isnan(ppc_dblresult64_d)) {
ppc_store_dfpresult_flt(reg_d); ppc_store_dfpresult_flt(reg_d);
fpresult_update(ppc_dblresult64_d, rc_flag);
} else {
ppc_confirm_inf_nan<double, SUB>(reg_a, reg_b, 0, rc_flag);
} }
if (rc_flag) if (rc_flag)
@ -347,9 +303,13 @@ void dppc_interpreter::ppc_fsub() {
void dppc_interpreter::ppc_fdiv() { void dppc_interpreter::ppc_fdiv() {
ppc_grab_regsfpdab(); ppc_grab_regsfpdab();
if (!ppc_confirm_inf_nan(reg_a, reg_b, false, 36)) { ppc_dblresult64_d = val_reg_a / val_reg_b;
ppc_dblresult64_d = val_reg_a / val_reg_b;
if (!isnan(ppc_dblresult64_d)) {
ppc_store_dfpresult_flt(reg_d); ppc_store_dfpresult_flt(reg_d);
fpresult_update(ppc_dblresult64_d, rc_flag);
} else {
ppc_confirm_inf_nan<double, DIV>(reg_a, reg_b, 0, rc_flag);
} }
if (rc_flag) if (rc_flag)
@ -359,9 +319,13 @@ void dppc_interpreter::ppc_fdiv() {
void dppc_interpreter::ppc_fmul() { void dppc_interpreter::ppc_fmul() {
ppc_grab_regsfpdac(); ppc_grab_regsfpdac();
if (!ppc_confirm_inf_nan(reg_a, reg_c, false, 50)) { ppc_dblresult64_d = val_reg_a * val_reg_c;
ppc_dblresult64_d = val_reg_a * val_reg_c;
if (!isnan(ppc_dblresult64_d)) {
ppc_store_dfpresult_flt(reg_d); ppc_store_dfpresult_flt(reg_d);
fpresult_update(ppc_dblresult64_d, rc_flag);
} else {
ppc_confirm_inf_nan<double, MUL>(reg_a, reg_b, 0, rc_flag);
} }
if (rc_flag) if (rc_flag)
@ -371,14 +335,14 @@ void dppc_interpreter::ppc_fmul() {
void dppc_interpreter::ppc_fmadd() { void dppc_interpreter::ppc_fmadd() {
ppc_grab_regsfpdabc(); ppc_grab_regsfpdabc();
if (!ppc_confirm_inf_nan(reg_a, reg_c, false, 50)) { ppc_dblresult64_d = std::fma(val_reg_a, val_reg_c, val_reg_b);
ppc_dblresult64_d = (val_reg_a * val_reg_c);
if (!ppc_confirm_inf_nan(reg_a, reg_b, false, 58)) {
ppc_dblresult64_d += val_reg_b;
}
}
ppc_store_dfpresult_flt(reg_d); if (!isnan(ppc_dblresult64_d)) {
ppc_store_dfpresult_flt(reg_d);
fpresult_update(ppc_dblresult64_d, rc_flag);
} else {
ppc_confirm_inf_nan<double, FMADD>(reg_a, reg_b, reg_c);
}
if (rc_flag) if (rc_flag)
ppc_changecrf1(); ppc_changecrf1();
@ -387,14 +351,15 @@ void dppc_interpreter::ppc_fmadd() {
void dppc_interpreter::ppc_fmsub() { void dppc_interpreter::ppc_fmsub() {
ppc_grab_regsfpdabc(); ppc_grab_regsfpdabc();
if (!ppc_confirm_inf_nan(reg_a, reg_c, false, 50)) { ppc_dblresult64_d = (val_reg_a * val_reg_c);
ppc_dblresult64_d = (val_reg_a * val_reg_c); ppc_dblresult64_d -= val_reg_b;
if (!ppc_confirm_inf_nan(reg_d, reg_b, false, 56)) {
ppc_dblresult64_d -= val_reg_b;
}
}
ppc_store_dfpresult_flt(reg_d); if (!isnan(ppc_dblresult64_d)) {
ppc_store_dfpresult_flt(reg_d);
fpresult_update(ppc_dblresult64_d, rc_flag);
} else {
ppc_confirm_inf_nan<double, FMSUB>(reg_a, reg_b, reg_c);
}
if (rc_flag) if (rc_flag)
ppc_changecrf1(); ppc_changecrf1();
@ -403,15 +368,16 @@ void dppc_interpreter::ppc_fmsub() {
void dppc_interpreter::ppc_fnmadd() { void dppc_interpreter::ppc_fnmadd() {
ppc_grab_regsfpdabc(); ppc_grab_regsfpdabc();
if (!ppc_confirm_inf_nan(reg_a, reg_c, false, 50)) { ppc_dblresult64_d = (val_reg_a * val_reg_c);
ppc_dblresult64_d = (val_reg_a * val_reg_c); ppc_dblresult64_d += val_reg_b;
if (!ppc_confirm_inf_nan(reg_a, reg_b, false, 58)) {
ppc_dblresult64_d += val_reg_b;
}
}
ppc_dblresult64_d = -ppc_dblresult64_d; if (!isnan(ppc_dblresult64_d)) {
ppc_store_dfpresult_flt(reg_d); ppc_store_dfpresult_flt(reg_d);
fpresult_update(ppc_dblresult64_d, rc_flag);
}
else {
ppc_confirm_inf_nan<double, FNMADD>(reg_a, reg_b, reg_c);
}
if (rc_flag) if (rc_flag)
ppc_changecrf1(); ppc_changecrf1();
@ -420,15 +386,16 @@ void dppc_interpreter::ppc_fnmadd() {
void dppc_interpreter::ppc_fnmsub() { void dppc_interpreter::ppc_fnmsub() {
ppc_grab_regsfpdabc(); ppc_grab_regsfpdabc();
if (!ppc_confirm_inf_nan(reg_a, reg_c, false, 50)) { ppc_dblresult64_d = (val_reg_a * val_reg_c);
ppc_dblresult64_d = (val_reg_a * val_reg_c); ppc_dblresult64_d -= val_reg_b;
if (!ppc_confirm_inf_nan(reg_d, reg_b, false, 56)) {
ppc_dblresult64_d -= val_reg_b;
}
}
ppc_dblresult64_d = -ppc_dblresult64_d; ppc_dblresult64_d = -ppc_dblresult64_d;
ppc_store_dfpresult_flt(reg_d); if (!isnan(ppc_dblresult64_d)) {
ppc_store_dfpresult_flt(reg_d);
fpresult_update(ppc_dblresult64_d, rc_flag);
} else {
ppc_confirm_inf_nan<double, FNMSUB>(reg_a, reg_b, reg_c);
}
if (rc_flag) if (rc_flag)
ppc_changecrf1(); ppc_changecrf1();
@ -437,10 +404,14 @@ void dppc_interpreter::ppc_fnmsub() {
void dppc_interpreter::ppc_fadds() { void dppc_interpreter::ppc_fadds() {
ppc_grab_regsfpdab(); ppc_grab_regsfpdab();
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 58)) { float intermediate = (float)val_reg_a + (float)val_reg_b;
float intermediate = (float)val_reg_a + (float)val_reg_b; ppc_dblresult64_d = static_cast<double>(intermediate);
ppc_dblresult64_d = static_cast<double>(intermediate);
if (!isnan(ppc_dblresult64_d)) {
ppc_store_sfpresult_flt(reg_d); ppc_store_sfpresult_flt(reg_d);
fpresult_update(ppc_dblresult64_d, rc_flag);
} else {
ppc_confirm_inf_nan<float, ADD>(reg_a, reg_b, 0);
} }
if (rc_flag) if (rc_flag)
@ -450,23 +421,14 @@ void dppc_interpreter::ppc_fadds() {
void dppc_interpreter::ppc_fsubs() { void dppc_interpreter::ppc_fsubs() {
ppc_grab_regsfpdab(); ppc_grab_regsfpdab();
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 56)) { float intermediate = (float)val_reg_a - (float)val_reg_b;
float intermediate = (float)val_reg_a - (float)val_reg_b; ppc_dblresult64_d = static_cast<double>(intermediate);
ppc_dblresult64_d = static_cast<double>(intermediate);
ppc_store_sfpresult_flt(reg_d); if (!isnan(ppc_dblresult64_d)) {
}
if (rc_flag)
ppc_changecrf1();
}
void dppc_interpreter::ppc_fmuls() {
ppc_grab_regsfpdac();
if (!ppc_confirm_inf_nan(reg_a, reg_c, true, 50)) {
float intermediate = (float)val_reg_a * (float)val_reg_c;
ppc_dblresult64_d = static_cast<double>(intermediate);
ppc_store_sfpresult_flt(reg_d); ppc_store_sfpresult_flt(reg_d);
fpresult_update(ppc_dblresult64_d, rc_flag);
} else {
ppc_confirm_inf_nan<float, SUB>(reg_a, reg_b, 0);
} }
if (rc_flag) if (rc_flag)
@ -476,10 +438,31 @@ void dppc_interpreter::ppc_fmuls() {
void dppc_interpreter::ppc_fdivs() { void dppc_interpreter::ppc_fdivs() {
ppc_grab_regsfpdab(); ppc_grab_regsfpdab();
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 36)) { float intermediate = (float)val_reg_a / (float)val_reg_b;
float intermediate = (float)val_reg_a / (float)val_reg_b; ppc_dblresult64_d = static_cast<double>(intermediate);
ppc_dblresult64_d = static_cast<double>(intermediate);
if (!isnan(ppc_dblresult64_d)) {
ppc_store_sfpresult_flt(reg_d); ppc_store_sfpresult_flt(reg_d);
fpresult_update(ppc_dblresult64_d, rc_flag);
} else {
ppc_confirm_inf_nan<float, DIV>(reg_a, reg_b, 0);
}
if (rc_flag)
ppc_changecrf1();
}
void dppc_interpreter::ppc_fmuls() {
ppc_grab_regsfpdac();
float intermediate = (float)val_reg_a * (float)val_reg_c;
ppc_dblresult64_d = static_cast<double>(intermediate);
if (!isnan(ppc_dblresult64_d)) {
ppc_store_sfpresult_flt(reg_d);
fpresult_update(ppc_dblresult64_d, rc_flag);
} else {
ppc_confirm_inf_nan<float, MUL>(reg_a, 0, reg_c);
} }
if (rc_flag) if (rc_flag)
@ -489,16 +472,14 @@ void dppc_interpreter::ppc_fdivs() {
void dppc_interpreter::ppc_fmadds() { void dppc_interpreter::ppc_fmadds() {
ppc_grab_regsfpdabc(); ppc_grab_regsfpdabc();
float intermediate; ppc_dblresult64_d = static_cast<double>(
std::fma((float)val_reg_a, (float)val_reg_c, (float)val_reg_b));
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 58)) { if (!isnan(ppc_dblresult64_d)) {
intermediate = (float)val_reg_a * (float)val_reg_c; ppc_store_sfpresult_flt(reg_d);
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 58)) { fpresult_update(ppc_dblresult64_d, rc_flag);
intermediate += (float)val_reg_b; } else {
ppc_dblresult64_d = static_cast<double>(intermediate); ppc_confirm_inf_nan<float, FMADD>(reg_a, reg_b, reg_c);
ppc_store_sfpresult_flt(reg_d);
}
} }
if (rc_flag) if (rc_flag)
@ -508,16 +489,15 @@ void dppc_interpreter::ppc_fmadds() {
void dppc_interpreter::ppc_fmsubs() { void dppc_interpreter::ppc_fmsubs() {
ppc_grab_regsfpdabc(); ppc_grab_regsfpdabc();
float intermediate; float intermediate = (float)val_reg_a * (float)val_reg_c;
intermediate -= (float)val_reg_b;
ppc_dblresult64_d = static_cast<double>(intermediate);
if (!ppc_confirm_inf_nan(reg_a, reg_c, false, 50)) { if (!isnan(ppc_dblresult64_d)) {
intermediate = (float)val_reg_a * (float)val_reg_c; ppc_store_sfpresult_flt(reg_d);
if (!ppc_confirm_inf_nan(reg_d, reg_b, false, 56)) { fpresult_update(ppc_dblresult64_d, rc_flag);
intermediate -= (float)val_reg_b; } else {
ppc_dblresult64_d = static_cast<double>(intermediate); ppc_confirm_inf_nan<float, FMSUB>(reg_a, reg_b, reg_c);
ppc_store_sfpresult_flt(reg_d);
}
} }
if (rc_flag) if (rc_flag)
@ -527,18 +507,16 @@ void dppc_interpreter::ppc_fmsubs() {
void dppc_interpreter::ppc_fnmadds() { void dppc_interpreter::ppc_fnmadds() {
ppc_grab_regsfpdabc(); ppc_grab_regsfpdabc();
float intermediate; float intermediate = (float)val_reg_a * (float)val_reg_c;
intermediate += (float)val_reg_b;
intermediate = -intermediate;
ppc_dblresult64_d = static_cast<double>(intermediate);
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 58)) { if (!isnan(ppc_dblresult64_d)) {
intermediate = (float)val_reg_a * (float)val_reg_c; ppc_store_sfpresult_flt(reg_d);
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 58)) { fpresult_update(ppc_dblresult64_d, rc_flag);
intermediate += (float)val_reg_b; } else {
intermediate = -intermediate; ppc_confirm_inf_nan<float, FNMADD>(reg_a, reg_b, reg_c);
ppc_dblresult64_d = static_cast<double>(intermediate);
ppc_store_sfpresult_flt(reg_d);
}
} }
if (rc_flag) if (rc_flag)
@ -548,18 +526,17 @@ void dppc_interpreter::ppc_fnmadds() {
void dppc_interpreter::ppc_fnmsubs() { void dppc_interpreter::ppc_fnmsubs() {
ppc_grab_regsfpdabc(); ppc_grab_regsfpdabc();
float intermediate; float intermediate = (float)val_reg_a * (float)val_reg_c;
intermediate -= (float)val_reg_b;
intermediate = -intermediate;
ppc_dblresult64_d = static_cast<double>(intermediate);
if (!ppc_confirm_inf_nan(reg_a, reg_c, false, 50)) {
intermediate = (float)val_reg_a * (float)val_reg_c;
if (!ppc_confirm_inf_nan(reg_d, reg_b, false, 56)) {
intermediate -= (float)val_reg_b;
intermediate = -intermediate;
ppc_dblresult64_d = static_cast<double>(intermediate); if (!isnan(ppc_dblresult64_d)) {
ppc_store_sfpresult_flt(reg_d);
ppc_store_sfpresult_flt(reg_d); fpresult_update(ppc_dblresult64_d, rc_flag);
} } else {
ppc_confirm_inf_nan<float, FNMSUB>(reg_a, reg_b, reg_c);
} }
if (rc_flag) if (rc_flag)
@ -603,7 +580,7 @@ void dppc_interpreter::ppc_fneg() {
void dppc_interpreter::ppc_fsel() { void dppc_interpreter::ppc_fsel() {
ppc_grab_regsfpdabc(); ppc_grab_regsfpdabc();
ppc_dblresult64_d = (val_reg_a >= 0.0) ? val_reg_c : val_reg_b; ppc_dblresult64_d = (val_reg_a >= -0.0) ? val_reg_c : val_reg_b;
ppc_store_dfpresult_flt(reg_d); ppc_store_dfpresult_flt(reg_d);
@ -658,11 +635,23 @@ void dppc_interpreter::ppc_frsp() {
void dppc_interpreter::ppc_fres() { void dppc_interpreter::ppc_fres() {
ppc_grab_regsfpdb(); ppc_grab_regsfpdb();
float testf2 = (float)GET_FPR(reg_b); double start_num = GET_FPR(reg_b);
float testf2 = (float)start_num;
testf2 = 1 / testf2; testf2 = 1 / testf2;
ppc_dblresult64_d = (double)testf2; ppc_dblresult64_d = (double)testf2;
ppc_store_dfpresult_flt(reg_d); ppc_store_dfpresult_flt(reg_d);
if (start_num == 0.0) {
ppc_state.fpscr |= FPSCR::ZX;
}
else if (std::isnan(start_num)) {
ppc_state.fpscr |= FPSCR::VXSNAN;
}
else if (std::isinf(start_num)){
ppc_state.fpscr |= FPSCR::VXSNAN;
ppc_state.fpscr &= 0xFFF9FFFF;
}
if (rc_flag) if (rc_flag)
ppc_changecrf1(); ppc_changecrf1();
} }
@ -673,26 +662,30 @@ void dppc_interpreter::ppc_fctiw() {
if (std::isnan(val_reg_b)) { if (std::isnan(val_reg_b)) {
ppc_state.fpr[reg_d].int64_r = 0x80000000; ppc_state.fpr[reg_d].int64_r = 0x80000000;
ppc_state.fpscr |= 0x1000100; ppc_state.fpscr |= FPSCR::VXSNAN | FPSCR::VXCVI;
} }
else if (val_reg_b > static_cast<double>(0x7fffffff)) { else if (val_reg_b > static_cast<double>(0x7fffffff)) {
ppc_state.fpr[reg_d].int64_r = 0x7fffffff; ppc_state.fpr[reg_d].int64_r = 0x7fffffff;
ppc_state.fpscr |= 0x100; ppc_state.fpscr |= FPSCR::VXCVI;
} }
else if (val_reg_b < -static_cast<double>(0x80000000)) { else if (val_reg_b < -static_cast<double>(0x80000000)) {
ppc_state.fpr[reg_d].int64_r = 0x80000000; ppc_state.fpr[reg_d].int64_r = 0x80000000;
ppc_state.fpscr |= 0x100; ppc_state.fpscr |= FPSCR::VXCVI;
} }
else { else {
switch (ppc_state.fpscr & 0x3) { switch (ppc_state.fpscr & 0x3) {
case 0: case 0:
ppc_result64_d = round_to_nearest(val_reg_b); ppc_result64_d = round_to_nearest(val_reg_b);
break;
case 1: case 1:
ppc_result64_d = round_to_zero(val_reg_b); ppc_result64_d = round_to_zero(val_reg_b);
break;
case 2: case 2:
ppc_result64_d = round_to_pos_inf(val_reg_b); ppc_result64_d = round_to_pos_inf(val_reg_b);
break;
case 3: case 3:
ppc_result64_d = round_to_neg_inf(val_reg_b); ppc_result64_d = round_to_neg_inf(val_reg_b);
break;
} }
ppc_store_dfpresult_int(reg_d); ppc_store_dfpresult_int(reg_d);
@ -709,15 +702,15 @@ void dppc_interpreter::ppc_fctiwz() {
if (std::isnan(val_reg_b)) { if (std::isnan(val_reg_b)) {
ppc_state.fpr[reg_d].int64_r = 0x80000000; ppc_state.fpr[reg_d].int64_r = 0x80000000;
ppc_state.fpscr |= 0x1000100; ppc_state.fpscr |= FPSCR::VXSNAN | FPSCR::VXCVI;
} }
else if (val_reg_b > static_cast<double>(0x7fffffff)) { else if (val_reg_b > static_cast<double>(0x7fffffff)) {
ppc_state.fpr[reg_d].int64_r = 0x7fffffff; ppc_state.fpr[reg_d].int64_r = 0x7fffffff;
ppc_state.fpscr |= 0x100; ppc_state.fpscr |= FPSCR::VXCVI;
} }
else if (val_reg_b < -static_cast<double>(0x80000000)) { else if (val_reg_b < -static_cast<double>(0x80000000)) {
ppc_state.fpr[reg_d].int64_r = 0x80000000; ppc_state.fpr[reg_d].int64_r = 0x80000000;
ppc_state.fpscr |= 0x100; ppc_state.fpscr |= FPSCR::VXCVI;
} }
else { else {
ppc_result64_d = round_to_zero(val_reg_b); ppc_result64_d = round_to_zero(val_reg_b);
@ -914,22 +907,14 @@ void dppc_interpreter::ppc_fmr() {
ppc_state.fpr[reg_d].dbl64_r = ppc_state.fpr[reg_b].dbl64_r; ppc_state.fpr[reg_d].dbl64_r = ppc_state.fpr[reg_b].dbl64_r;
} }
void dppc_interpreter::ppc_mffs() { void dppc_interpreter::ppc_mffs() {
ppc_grab_regsda(); ppc_grab_regsda();
uint64_t fpstore1 = ppc_state.fpr[reg_d].int64_r & 0xFFFFFFFF00000000; uint64_t fpstore1 = ppc_state.fpr[reg_d].int64_r & ((uint64_t)0xFFF80000 << 32);
uint64_t fpstore2 = ppc_state.fpscr & 0x00000000FFFFFFFF; fpstore1 |= (uint64_t)ppc_state.fpscr;
fpstore1 |= fpstore2;
fp_save_uint64(fpstore1); fp_save_uint64(fpstore1);
}
void dppc_interpreter::ppc_mffsdot() { if (rc_flag)
ppc_grab_regsda(); ppc_fp_changecrf1();
uint64_t fpstore1 = ppc_state.fpr[reg_d].int64_r & 0xFFFFFFFF00000000;
uint64_t fpstore2 = ppc_state.fpscr & 0x00000000FFFFFFFF;
fpstore1 |= fpstore2;
fp_save_uint64(fpstore1);
ppc_fp_changecrf1();
} }
void dppc_interpreter::ppc_mtfsf() { void dppc_interpreter::ppc_mtfsf() {
@ -945,22 +930,9 @@ void dppc_interpreter::ppc_mtfsf() {
crm += (((fm_mask >> 7) & 1) == 1) ? 0x0000000F : 0x00000000; crm += (((fm_mask >> 7) & 1) == 1) ? 0x0000000F : 0x00000000;
uint32_t quickfprval = (uint32_t)ppc_state.fpr[reg_b].int64_r; uint32_t quickfprval = (uint32_t)ppc_state.fpr[reg_b].int64_r;
ppc_state.fpscr = (quickfprval & crm) | (quickfprval & ~(crm)); ppc_state.fpscr = (quickfprval & crm) | (quickfprval & ~(crm));
}
void dppc_interpreter::ppc_mtfsfdot() { if (rc_flag)
reg_b = (ppc_cur_instruction >> 11) & 31; ppc_fp_changecrf1();
uint32_t fm_mask = (ppc_cur_instruction >> 17) & 255;
crm += ((fm_mask & 1) == 1) ? 0xF0000000 : 0x00000000;
crm += (((fm_mask >> 1) & 1) == 1) ? 0x0F000000 : 0x00000000;
crm += (((fm_mask >> 2) & 1) == 1) ? 0x00F00000 : 0x00000000;
crm += (((fm_mask >> 3) & 1) == 1) ? 0x000F0000 : 0x00000000;
crm += (((fm_mask >> 4) & 1) == 1) ? 0x0000F000 : 0x00000000;
crm += (((fm_mask >> 5) & 1) == 1) ? 0x00000F00 : 0x00000000;
crm += (((fm_mask >> 6) & 1) == 1) ? 0x000000F0 : 0x00000000;
crm += (((fm_mask >> 7) & 1) == 1) ? 0x0000000F : 0x00000000;
uint32_t quickfprval = (uint32_t)ppc_state.fpr[reg_b].int64_r;
ppc_state.fpscr = (quickfprval & crm) | (quickfprval & ~(crm));
ppc_fp_changecrf1();
} }
void dppc_interpreter::ppc_mtfsfi() { void dppc_interpreter::ppc_mtfsfi() {
@ -969,15 +941,9 @@ void dppc_interpreter::ppc_mtfsfi() {
crf_d = crf_d << 2; crf_d = crf_d << 2;
ppc_state.fpscr = (ppc_state.cr & ~(0xF0000000UL >> crf_d)) | ppc_state.fpscr = (ppc_state.cr & ~(0xF0000000UL >> crf_d)) |
((ppc_state.spr[SPR::XER] & 0xF0000000UL) >> crf_d); ((ppc_state.spr[SPR::XER] & 0xF0000000UL) >> crf_d);
}
void dppc_interpreter::ppc_mtfsfidot() { if (rc_flag)
ppc_result_b = (ppc_cur_instruction >> 11) & 15; ppc_fp_changecrf1();
crf_d = (ppc_cur_instruction >> 23) & 7;
crf_d = crf_d << 2;
ppc_state.fpscr = (ppc_state.cr & ~(0xF0000000UL >> crf_d)) |
((ppc_state.spr[SPR::XER] & 0xF0000000UL) >> crf_d);
ppc_fp_changecrf1();
} }
void dppc_interpreter::ppc_mtfsb0() { void dppc_interpreter::ppc_mtfsb0() {
@ -985,14 +951,9 @@ void dppc_interpreter::ppc_mtfsb0() {
if ((crf_d == 0) || (crf_d > 2)) { if ((crf_d == 0) || (crf_d > 2)) {
ppc_state.fpscr &= ~(0x80000000UL >> crf_d); ppc_state.fpscr &= ~(0x80000000UL >> crf_d);
} }
}
void dppc_interpreter::ppc_mtfsb0dot() { if (rc_flag)
crf_d = (ppc_cur_instruction >> 21) & 0x1F; ppc_fp_changecrf1();
if ((crf_d == 0) || (crf_d > 2)) {
ppc_state.fpscr &= ~(0x80000000UL >> crf_d);
}
ppc_fp_changecrf1();
} }
void dppc_interpreter::ppc_mtfsb1() { void dppc_interpreter::ppc_mtfsb1() {
@ -1000,14 +961,9 @@ void dppc_interpreter::ppc_mtfsb1() {
if ((crf_d == 0) || (crf_d > 2)) { if ((crf_d == 0) || (crf_d > 2)) {
ppc_state.fpscr |= (0x80000000UL >> crf_d); ppc_state.fpscr |= (0x80000000UL >> crf_d);
} }
}
void dppc_interpreter::ppc_mtfsb1dot() { if (rc_flag)
crf_d = (ppc_cur_instruction >> 21) & 0x1F; ppc_fp_changecrf1();
if ((crf_d == 0) || (crf_d > 2)) {
ppc_state.fpscr |= (0x80000000UL >> crf_d);
}
ppc_fp_changecrf1();
} }
void dppc_interpreter::ppc_mcrfs() { void dppc_interpreter::ppc_mcrfs() {
@ -1027,25 +983,28 @@ void dppc_interpreter::ppc_fcmpo() {
ppc_state.fpscr &= 0xFFFF0FFF; ppc_state.fpscr &= 0xFFFF0FFF;
if (std::isnan(db_test_a) || std::isnan(db_test_b)) { if (std::isnan(db_test_a) || std::isnan(db_test_b)) {
cmp_c |= 0x01; cmp_c |= (1 << (uint32_t)CRx_bit::CR_SO);
} else if (db_test_a < db_test_b) { } else if (db_test_a < db_test_b) {
cmp_c |= 0x08; cmp_c |= (1 << (uint32_t)CRx_bit::CR_LT);
} else if (db_test_a > db_test_b) { } else if (db_test_a > db_test_b) {
cmp_c |= 0x04; cmp_c |= (1 << (uint32_t)CRx_bit::CR_GT);
} else { } else {
cmp_c |= 0x02; cmp_c |= (1 << (uint32_t)CRx_bit::CR_EQ);
} }
ppc_state.fpscr |= (cmp_c << 12); fpresult_update(db_test_a, true);
ppc_state.cr = ((ppc_state.cr & ~(0xf0000000 >> crf_d)) | ((cmp_c + xercon) >> crf_d));
if ((db_test_a == snan) || (db_test_b == snan)) { ppc_state.fpscr = (ppc_state.fpscr & ~(FPSCR::FPRF)) | (cmp_c << 12);
ppc_state.fpscr |= 0x1000000; ppc_state.cr =
((ppc_state.cr & ~((uint32_t)CR_select::CR0_field >> crf_d)) | ((cmp_c + xercon) >> crf_d));
if (std::isnan(db_test_a) || std::isnan(db_test_b)) {
ppc_state.fpscr |= FPSCR::VXSNAN;
if (ppc_state.fpscr & 0x80) { if (ppc_state.fpscr & 0x80) {
ppc_state.fpscr |= 0x80000; ppc_state.fpscr |= FPSCR::VXVC;
} }
} else if ((db_test_a == qnan) || (db_test_b == qnan)) { } else if ((db_test_a == qnan) || (db_test_b == qnan)) {
ppc_state.fpscr |= 0x80000; ppc_state.fpscr |= FPSCR::VXVC;
} }
} }
@ -1055,19 +1014,22 @@ void dppc_interpreter::ppc_fcmpu() {
ppc_state.fpscr &= 0xFFFF0FFF; ppc_state.fpscr &= 0xFFFF0FFF;
if (std::isnan(db_test_a) || std::isnan(db_test_b)) { if (std::isnan(db_test_a) || std::isnan(db_test_b)) {
cmp_c |= 0x01; cmp_c |= (1 << (uint32_t)CRx_bit::CR_SO);
} else if (db_test_a < db_test_b) { } else if (db_test_a < db_test_b) {
cmp_c |= 0x08; cmp_c |= (1 << (uint32_t)CRx_bit::CR_LT);
} else if (db_test_a > db_test_b) { } else if (db_test_a > db_test_b) {
cmp_c |= 0x04; cmp_c |= (1 << (uint32_t)CRx_bit::CR_GT);
} else { } else {
cmp_c |= 0x02; cmp_c |= (1 << (uint32_t)CRx_bit::CR_EQ);
} }
ppc_state.fpscr |= (cmp_c << 12); fpresult_update(db_test_a, true);
ppc_state.cr = ((ppc_state.cr & ~(0xf0000000 >> crf_d)) | ((cmp_c + xercon) >> crf_d));
if ((db_test_a == snan) || (db_test_b == snan)) { ppc_state.fpscr = (ppc_state.fpscr & ~(FPSCR::FPRF)) | (cmp_c << 12);
ppc_state.fpscr |= 0x1000000; ppc_state.cr =
((ppc_state.cr & ~((uint32_t)CR_select::CR0_field >> crf_d)) | ((cmp_c + xercon) >> crf_d));
if (std::isnan(db_test_a) || std::isnan(db_test_b)) {
ppc_state.fpscr |= FPSCR::VXSNAN;
} }
} }

View File

@ -127,14 +127,18 @@ def gen_ppc_opcode(opc_str, imm):
return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (0x12 << 1) return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (0x12 << 1)
elif opc_str == "FDIV.": elif opc_str == "FDIV.":
return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (0x12 << 1) + 1 return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (0x12 << 1) + 1
elif opc_str == "FDIVS":
return (0x3B << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (0x12 << 1)
elif opc_str == "FDIVS.":
return (0x3B << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (0x12 << 1) + 1
elif opc_str == "FMADD": elif opc_str == "FMADD":
return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (4 << 6) + (0x1D << 1) return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (5 << 6) + (0x1D << 1)
elif opc_str == "FMADD.": elif opc_str == "FMADD.":
return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (4 << 6) + (0x1D << 1) + 1 return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (5 << 6) + (0x1D << 1) + 1
elif opc_str == "FMADDS": elif opc_str == "FMADDS":
return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (4 << 6) + (0x1D << 1) return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (5 << 6) + (0x1D << 1)
elif opc_str == "FMADDS.": elif opc_str == "FMADDS.":
return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (4 << 6) + (0x1D << 1) + 1 return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (5 << 6) + (0x1D << 1) + 1
elif opc_str == "FMUL": elif opc_str == "FMUL":
return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 6) + (0x19 << 1) return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 6) + (0x19 << 1)
elif opc_str == "FMUL.": elif opc_str == "FMUL.":
@ -152,29 +156,29 @@ def gen_ppc_opcode(opc_str, imm):
elif opc_str == "FMULS.": elif opc_str == "FMULS.":
return (0x3B << 26) + (3 << 21) + (3 << 16) + (4 << 6) + (0x28 << 1) + 1 return (0x3B << 26) + (3 << 21) + (3 << 16) + (4 << 6) + (0x28 << 1) + 1
elif opc_str == "FMSUB": elif opc_str == "FMSUB":
return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (4 << 6) + (0x1C << 1) return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (5 << 6) + (0x1C << 1)
elif opc_str == "FMSUB.": elif opc_str == "FMSUB.":
return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (4 << 6) + (0x1C << 1) + 1 return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (5 << 6) + (0x1C << 1) + 1
elif opc_str == "FMSUBS": elif opc_str == "FMSUBS":
return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (4 << 6) + (0x1C << 1) return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (5 << 6) + (0x1C << 1)
elif opc_str == "FMSUBS.": elif opc_str == "FMSUBS.":
return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (4 << 6) + (0x1C << 1) + 1 return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (5 << 6) + (0x1C << 1) + 1
elif opc_str == "FNMADD": elif opc_str == "FNMADD":
return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (4 << 6) + (0x1F << 1) return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (5 << 6) + (0x1F << 1)
elif opc_str == "FNMADD.": elif opc_str == "FNMADD.":
return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (4 << 6) + (0x1F << 1) + 1 return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (5 << 6) + (0x1F << 1) + 1
elif opc_str == "FNMADDS": elif opc_str == "FNMADDS":
return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (4 << 6) + (0x1F << 1) return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (5 << 6) + (0x1F << 1)
elif opc_str == "FNMADDS.": elif opc_str == "FNMADDS.":
return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (4 << 6) + (0x1F << 1) + 1 return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (5 << 6) + (0x1F << 1) + 1
elif opc_str == "FNMSUB": elif opc_str == "FNMSUB":
return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (4 << 6) + (0x1C << 1) return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (5 << 6) + (0x1C << 1)
elif opc_str == "FNMSUB.": elif opc_str == "FNMSUB.":
return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (4 << 6) + (0x1C << 1) + 1 return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (5 << 6) + (0x1C << 1) + 1
elif opc_str == "FNMSUBS": elif opc_str == "FNMSUBS":
return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (4 << 6) + (0x1C << 1) return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (5 << 6) + (0x1C << 1)
elif opc_str == "FNMSUBS.": elif opc_str == "FNMSUBS.":
return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (4 << 6) + (0x1C << 1) + 1 return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (5 << 6) + (0x1C << 1) + 1
elif opc_str == "FSUB": elif opc_str == "FSUB":
return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (0x15 << 1) return (0x3F << 26) + (3 << 21) + (3 << 16) + (4 << 11) + (0x15 << 1)
elif opc_str == "FSUB.": elif opc_str == "FSUB.":
@ -346,7 +350,6 @@ def extract_rot_params(line):
pos += 16 pos += 16
return (sh, mb, me) return (sh, mb, me)
if __name__ == "__main__": if __name__ == "__main__":
with open("ppcinttest.txt", "r") as in_file: with open("ppcinttest.txt", "r") as in_file:
with open("ppcinttests.csv", "w") as out_file: with open("ppcinttests.csv", "w") as out_file:
@ -404,41 +407,152 @@ if __name__ == "__main__":
line = line.strip() line = line.strip()
opcode = (line[0:8]).rstrip().upper() opcode = (line[0:8]).rstrip().upper()
out_file.write(opcode + ",") out_file.write(opcode+ ",")
out_file.write("0x{:X}".format(gen_ppc_opcode(opcode, 0)))
if opcode.startswith("RLWI"): pos = 10
sh, mb, me = extract_rot_params(line) checkstring = ''
out_file.write("0x{:X}".format(gen_rot_opcode(opcode, sh, mb, me)))
else:
imm = extract_imm(line)
out_file.write("0x{:X}".format(gen_ppc_opcode(opcode, imm)))
pos = 12
while pos < len(line): while pos < len(line):
reg_id = line[pos:pos+4] if (line[pos].isalnum()):
if reg_id.startswith("frD"): checkstring += line[pos]
out_file.write(",frD=" + line[pos+4:pos+14])
pos += 16 if ("RTN" in checkstring):
elif reg_id.startswith("frA"): if (line[pos+1:pos+2] == "I"):
out_file.write(",frA=" + line[pos+4:pos+14]) out_file.write(",round=RNI")
pos += 16 checkstring = ''
elif reg_id.startswith("frB"): else:
out_file.write(",frB=" + line[pos+4:pos+14]) out_file.write(",round=RTN")
pos += 16 checkstring = ''
elif reg_id.startswith("frC"): pos += 1
out_file.write(",frC=" + line[pos+4:pos+14]) elif ("RTZ" in checkstring):
pos += 16 out_file.write(",round=RTZ")
elif reg_id.startswith("FPSCR:"): checkstring = ''
out_file.write(",FPSCR=" + line[pos+7:pos+17]) pos += 1
pos += 19 elif ("RTPI" in checkstring):
elif reg_id.startswith("CR:"): out_file.write(",round=RPI")
out_file.write(",CR=" + line[pos+4:pos+14]) checkstring = ''
pos += 17 pos += 1
elif reg_id.startswith("imm"): elif ("VE" in checkstring):
pos += 17 # ignore immediate operands out_file.write(",round=VEN")
else: checkstring = ''
out_file.write("Unknown reg ID" + reg_id) pos += 1
break elif ("frD" in checkstring):
out_file.write(",frD=0x" + line[pos+4:pos+20])
checkstring = ''
elif ("frA" in checkstring): #sloppy temp code
check2 = line[pos+1:pos+10]
if ("-inf" in check2):
out_file.write(",frA=-inf")
elif ("inf" in check2):
out_file.write(",frA=inf")
pos += 1
elif ("nan" in check2):
out_file.write(",frA=nan")
pos += 1
elif ("-0." or "-2." or "-4." or \
"-6." or "-8." or "-7." or\
"-5." or "-3." or "-1." or \
"-9." in check2):
get_pos = line[pos+2:pos+16].strip("|")
out_file.write(",frA=" + get_pos.strip())
elif ("0." or "2." or "4." or \
"6." or "8." or "7." or\
"5." or "3." or "1." or \
"9." in check2):
get_pos = line[pos+2:pos+15]
out_file.write(",frA=" + get_pos.strip())
checkstring = ''
elif ("frB" in checkstring): #sloppy temp code
check2 = line[pos+1:pos+10]
if ("-inf" in check2):
out_file.write(",frB=-inf")
elif ("inf" in check2):
out_file.write(",frB=inf")
pos += 1
elif ("nan" in check2):
out_file.write(",frB=nan")
pos += 1
elif ("-0." or "-2." or "-4." or \
"-6." or "-8." or "-7." or\
"-5." or "-3." or "-1." or \
"-9." in check2):
get_pos = line[pos+2:pos+16].strip("|")
out_file.write(",frB=" + get_pos.strip())
elif ("0." or "2." or "4." or \
"6." or "8." or "7." or\
"5." or "3." or "1." or \
"9." in check2):
get_pos = line[pos+2:pos+15]
out_file.write(",frB=" + get_pos.strip())
checkstring = ''
elif ("frC" in checkstring): #sloppy temp code
check2 = line[pos+1:pos+10]
if ("-inf" in check2):
out_file.write(",frC=-inf")
elif ("inf" in check2):
out_file.write(",frC=inf")
pos += 1
elif ("nan" in check2):
out_file.write(",frC=nan")
pos += 1
elif ("-0." or "-2." or "-4." or \
"-6." or "-8." or "-7." or\
"-5." or "-3." or "-1." or \
"-9." in check2):
get_pos = line[pos+2:pos+16].strip("|")
out_file.write(",frC=" + get_pos.strip())
elif ("0." or "2." or "4." or \
"6." or "8." or "7." or\
"5." or "3." or "1." or \
"9." in check2):
get_pos = line[pos+2:pos+15]
out_file.write(",frC=" + get_pos.strip())
checkstring = ''
elif ("FPSCR" in checkstring):
out_file.write(",FPSCR=" + line[pos+3:pos+13])
checkstring = ''
elif ("CR" in checkstring):
out_file.write(",CR=0x0" + line[pos+6:pos+14])
checkstring = ''
pos += 1
out_file.write("\n") # reg_id = line[pos:pos+4]
# if reg_id.startswith("frD"):
# out_file.write(",frD=" + line[pos+4:pos+22])
# pos += 24
# elif reg_id.startswith("frA"):
# out_file.write(",frA=" + line[pos+4:pos+14])
# pos += 16
# elif reg_id.startswith("frB"):
# out_file.write(",frB=" + line[pos+4:pos+14])
# pos += 16
# elif reg_id.startswith("frC"):
# out_file.write(",frC=" + line[pos+4:pos+14])
# pos += 16
# elif reg_id.startswith("FPSCR:"):
# out_file.write(",FPSCR=" + line[pos+7:pos+17])
# pos += 19
# elif reg_id.startswith("CR:"):
# out_file.write(",CR=" + line[pos+4:pos+14])
# pos += 17
# elif reg_id.startswith("VE)"):
# out_file.write("round=VEN" + line[pos+4:pos+20])
# pos += 17
# elif reg_id.startswith("TN)"):
# out_file.write("round=RTN" + line[pos+4:pos+20])
# pos += 17
# elif reg_id.startswith("TZ)"):
# out_file.write("round=RTZ" + line[pos+4:pos+20])
# pos += 17
# elif reg_id.startswith("NI)"):
# out_file.write("round=RNI" + line[pos+4:pos+20])
# pos += 17
# elif reg_id.startswith("PI)"):
# out_file.write("round=RPI" + line[pos+4:pos+20])
# pos += 17
# else:
# out_file.write("Unknown reg ID" + reg_id)
# break
out_file.write("\n")

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
#include "../ppcdisasm.h" #include "../ppcdisasm.h"
#include "../ppcemu.h" #include "../ppcemu.h"
#include <cmath>
#include <fstream> #include <fstream>
#include <iomanip> #include <iomanip>
#include <iostream> #include <iostream>
@ -148,7 +149,7 @@ static void read_test_float_data() {
uint32_t opcode, dest, src1, src2, check_xer, check_cr, check_fpscr; uint32_t opcode, dest, src1, src2, check_xer, check_cr, check_fpscr;
uint64_t dest_64, src1_64, src2_64; uint64_t dest_64, src1_64, src2_64;
float sfp_dest, sfp_src1, sfp_src2, sfp_src3; //float sfp_dest, sfp_src1, sfp_src2, sfp_src3;
double dfp_dest, dfp_src1, dfp_src2, dfp_src3; double dfp_dest, dfp_src1, dfp_src2, dfp_src3;
string rounding_mode; string rounding_mode;
@ -181,48 +182,50 @@ static void read_test_float_data() {
opcode = stoul(tokens[1], NULL, 16); opcode = stoul(tokens[1], NULL, 16);
dest = 0;
src1 = 0; src1 = 0;
src2 = 0; src2 = 0;
check_xer = 0; check_xer = 0;
check_cr = 0; check_cr = 0;
check_fpscr = 0; check_fpscr = 0;
sfp_dest = 0.0; //sfp_dest = 0.0;
sfp_src1 = 0.0; //sfp_src1 = 0.0;
sfp_src2 = 0.0; //sfp_src2 = 0.0;
sfp_src3 = 0.0; //sfp_src3 = 0.0;
dfp_dest = 0.0; dfp_dest = 0.0;
dfp_src1 = 0.0; dfp_src1 = 0.0;
dfp_src2 = 0.0; dfp_src2 = 0.0;
dfp_src3 = 0.0; dfp_src3 = 0.0;
dest_64 = 0;
for (i = 2; i < tokens.size(); i++) { for (i = 2; i < tokens.size(); i++) {
if (tokens[i].rfind("frD=", 0) == 0) { if (tokens[i].rfind("frD=", 0) == 0) {
dfp_dest = stoul(tokens[i].substr(4), NULL, 16); dest_64 = stoull(tokens[i].substr(4), NULL, 16);
} else if (tokens[i].rfind("frA=", 0) == 0) { } else if (tokens[i].rfind("frA=", 0) == 0) {
dfp_src1 = stoul(tokens[i].substr(4), NULL, 16); dfp_src1 = stod(tokens[i].substr(4), NULL);
} else if (tokens[i].rfind("frB=", 0) == 0) { } else if (tokens[i].rfind("frB=", 0) == 0) {
dfp_src2 = stoul(tokens[i].substr(4), NULL, 16); dfp_src2 = stod(tokens[i].substr(4), NULL);
} else if (tokens[i].rfind("frC=", 0) == 0) { } else if (tokens[i].rfind("frC=", 0) == 0) {
dfp_src3 = stoul(tokens[i].substr(4), NULL, 16); dfp_src3 = stod(tokens[i].substr(4), NULL);
} else if (tokens[i].rfind("round=", 0) == 0) { } else if (tokens[i].rfind("round=", 0) == 0) {
rounding_mode = tokens[i].substr(6, 3); rounding_mode = tokens[i].substr(6, 3);
ppc_state.fpscr &= 0xFFFFFFFC; ppc_state.fpscr &= 0xFFFFFFFC;
if (rounding_mode.compare("RTN") == 0) { if (rounding_mode.compare("RTN") == 0) {
ppc_state.fpscr |= 0x0; ppc_state.fpscr = 0x0;
} else if (rounding_mode.compare("RTZ") == 0) { } else if (rounding_mode.compare("RTZ") == 0) {
ppc_state.fpscr |= 0x1; ppc_state.fpscr = 0x1;
} else if (rounding_mode.compare("RPI") == 0) { } else if (rounding_mode.compare("RPI") == 0) {
ppc_state.fpscr |= 0x2; ppc_state.fpscr = 0x2;
} else if (rounding_mode.compare("RNI") == 0) { } else if (rounding_mode.compare("RNI") == 0) {
ppc_state.fpscr |= 0x3; ppc_state.fpscr = 0x3;
} else if (rounding_mode.compare("VEN") == 0) {
ppc_state.fpscr = FPSCR::VE;
} else { } else {
cout << "ILLEGAL ROUNDING METHOD: " << tokens[i] << " in line " << lineno cout << "ILLEGAL ROUNDING METHOD: " << tokens[i] << " in line " << lineno
<< ". Exiting..." << endl; << ". Exiting..." << endl;
exit(0); exit(0);
} }
} else if (tokens[i].rfind("FPSCR=", 0) == 0) { } else if (tokens[i].rfind("FPSCR=", 0) == 0) {
check_cr = stoul(tokens[i].substr(6), NULL, 16); check_fpscr = stoul(tokens[i].substr(6), NULL, 16);
} else if (tokens[i].rfind("CR=", 0) == 0) { } else if (tokens[i].rfind("CR=", 0) == 0) {
check_cr = stoul(tokens[i].substr(3), NULL, 16); check_cr = stoul(tokens[i].substr(3), NULL, 16);
} else { } else {
@ -239,7 +242,6 @@ static void read_test_float_data() {
ppc_state.fpr[4].dbl64_r = dfp_src2; ppc_state.fpr[4].dbl64_r = dfp_src2;
ppc_state.fpr[5].dbl64_r = dfp_src3; ppc_state.fpr[5].dbl64_r = dfp_src3;
ppc_state.spr[SPR::XER] = 0;
ppc_state.cr = 0; ppc_state.cr = 0;
ppc_cur_instruction = opcode; ppc_cur_instruction = opcode;
@ -248,13 +250,14 @@ static void read_test_float_data() {
ntested++; ntested++;
if ((tokens[0].rfind("FCMP") && (ppc_state.gpr[3] != dest)) || (ppc_state.fpscr != check_fpscr) || if ((tokens[0].rfind("FCMP") && (ppc_state.fpr[3].int64_r != dest_64)) ||
(ppc_state.fpscr != check_fpscr) ||
(ppc_state.cr != check_cr)) { (ppc_state.cr != check_cr)) {
cout << "Mismatch: instr=" << tokens[0] << ", src1=0x" << hex << src1 << ", src2=0x" << hex cout << "Mismatch: instr=" << tokens[0] << ", src1=" << scientific << dfp_src1 << ", src2=" << scientific << dfp_src2 << ", src3=" << scientific << dfp_src3 << endl;
<< src2 << endl; cout << "expected: dest=0x" << hex << dest_64 << ", FPSCR=0x" << hex << check_fpscr
cout << "expected: dest=0x" << hex << dest << ", FPSCR=0x" << hex << check_xer << ", CR=0x" << ", CR=0x"
<< hex << check_cr << endl; << hex << check_cr << endl;
cout << "got: dest=0x" << hex << ppc_state.gpr[3] << ", FPSCR=0x" << hex cout << "got: dest=0x" << hex << ppc_state.fpr[3].int64_r << ", FPSCR=0x" << hex
<< ppc_state.fpscr << ", CR=0x" << hex << ppc_state.cr << endl; << ppc_state.fpscr << ", CR=0x" << hex << ppc_state.cr << endl;
cout << "Test file line #: " << dec << lineno << endl << endl; cout << "Test file line #: " << dec << lineno << endl << endl;