diff --git a/src/xenia/cpu/ppc/ppc_emit_fpu.cc b/src/xenia/cpu/ppc/ppc_emit_fpu.cc index 082796506..a7e824214 100644 --- a/src/xenia/cpu/ppc/ppc_emit_fpu.cc +++ b/src/xenia/cpu/ppc/ppc_emit_fpu.cc @@ -37,12 +37,7 @@ int InstrEmit_faddx(PPCHIRBuilder& f, const InstrData& i) { // frD <- (frA) + (frB) Value* v = f.Add(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB)); f.StoreFPR(i.A.FRT, v); - // f.UpdateFPRF(v); - if (i.A.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.A.Rc); return 0; } @@ -51,12 +46,7 @@ int InstrEmit_faddsx(PPCHIRBuilder& f, const InstrData& i) { Value* v = f.Add(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB)); v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE); f.StoreFPR(i.A.FRT, v); - // f.UpdateFPRF(v); - if (i.A.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.A.Rc); return 0; } @@ -64,12 +54,7 @@ int InstrEmit_fdivx(PPCHIRBuilder& f, const InstrData& i) { // frD <- frA / frB Value* v = f.Div(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB)); f.StoreFPR(i.A.FRT, v); - // f.UpdateFPRF(v); - if (i.A.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.A.Rc); return 0; } @@ -78,12 +63,7 @@ int InstrEmit_fdivsx(PPCHIRBuilder& f, const InstrData& i) { Value* v = f.Div(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB)); v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE); f.StoreFPR(i.A.FRT, v); - // f.UpdateFPRF(v); - if (i.A.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.A.Rc); return 0; } @@ -91,12 +71,7 @@ int InstrEmit_fmulx(PPCHIRBuilder& f, const InstrData& i) { // frD <- (frA) x (frC) Value* v = f.Mul(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC)); f.StoreFPR(i.A.FRT, v); - // f.UpdateFPRF(v); - if (i.A.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.A.Rc); return 0; } @@ -105,12 +80,7 @@ int InstrEmit_fmulsx(PPCHIRBuilder& f, const InstrData& i) { Value* v = f.Mul(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC)); v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE); f.StoreFPR(i.A.FRT, v); - // f.UpdateFPRF(v); - if (i.A.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.A.Rc); return 0; } @@ -120,12 +90,7 @@ int InstrEmit_fresx(PPCHIRBuilder& f, const InstrData& i) { f.Convert(f.LoadFPR(i.A.FRB), FLOAT32_TYPE)), FLOAT64_TYPE); f.StoreFPR(i.A.FRT, v); - // f.UpdateFPRF(v); - if (i.A.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.A.Rc); return 0; } @@ -134,12 +99,7 @@ int InstrEmit_frsqrtex(PPCHIRBuilder& f, const InstrData& i) { // frD <- 1/sqrt(frB) Value* v = f.RSqrt(f.LoadFPR(i.A.FRB)); f.StoreFPR(i.A.FRT, v); - // f.UpdateFPRF(v); - if (i.A.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.A.Rc); return 0; } @@ -147,12 +107,7 @@ int InstrEmit_fsubx(PPCHIRBuilder& f, const InstrData& i) { // frD <- (frA) - (frB) Value* v = f.Sub(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB)); f.StoreFPR(i.A.FRT, v); - // f.UpdateFPRF(v); - if (i.A.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.A.Rc); return 0; } @@ -161,12 +116,7 @@ int InstrEmit_fsubsx(PPCHIRBuilder& f, const InstrData& i) { Value* v = f.Sub(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB)); v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE); f.StoreFPR(i.A.FRT, v); - // f.UpdateFPRF(v); - if (i.A.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.A.Rc); return 0; } @@ -177,11 +127,7 @@ int InstrEmit_fselx(PPCHIRBuilder& f, const InstrData& i) { Value* ge = f.CompareSGE(f.LoadFPR(i.A.FRA), f.LoadZeroFloat64()); Value* v = f.Select(ge, f.LoadFPR(i.A.FRC), f.LoadFPR(i.A.FRB)); f.StoreFPR(i.A.FRT, v); - if (i.A.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.A.Rc); return 0; } @@ -190,12 +136,7 @@ int InstrEmit_fsqrtx(PPCHIRBuilder& f, const InstrData& i) { // frD <- sqrt(frB) Value* v = f.Sqrt(f.LoadFPR(i.A.FRB)); f.StoreFPR(i.A.FRT, v); - // f.UpdateFPRF(v); - if (i.A.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.A.Rc); return 0; } @@ -205,12 +146,7 @@ int InstrEmit_fsqrtsx(PPCHIRBuilder& f, const InstrData& i) { Value* v = f.Sqrt(f.LoadFPR(i.A.FRB)); v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE); f.StoreFPR(i.A.FRT, v); - // f.UpdateFPRF(v); - if (i.A.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.A.Rc); return 0; } @@ -221,12 +157,7 @@ int InstrEmit_fmaddx(PPCHIRBuilder& f, const InstrData& i) { Value* v = f.MulAdd(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC), f.LoadFPR(i.A.FRB)); f.StoreFPR(i.A.FRT, v); - // f.UpdateFPRF(v); - if (i.A.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.A.Rc); return 0; } @@ -236,12 +167,7 @@ int InstrEmit_fmaddsx(PPCHIRBuilder& f, const InstrData& i) { f.MulAdd(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC), f.LoadFPR(i.A.FRB)); v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE); f.StoreFPR(i.A.FRT, v); - // f.UpdateFPRF(v); - if (i.A.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.A.Rc); return 0; } @@ -250,12 +176,7 @@ int InstrEmit_fmsubx(PPCHIRBuilder& f, const InstrData& i) { Value* v = f.MulSub(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC), f.LoadFPR(i.A.FRB)); f.StoreFPR(i.A.FRT, v); - // f.UpdateFPRF(v); - if (i.A.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.A.Rc); return 0; } @@ -265,12 +186,7 @@ int InstrEmit_fmsubsx(PPCHIRBuilder& f, const InstrData& i) { f.MulSub(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC), f.LoadFPR(i.A.FRB)); v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE); f.StoreFPR(i.A.FRT, v); - // f.UpdateFPRF(v); - if (i.A.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.A.Rc); return 0; } @@ -279,12 +195,7 @@ int InstrEmit_fnmaddx(PPCHIRBuilder& f, const InstrData& i) { Value* v = f.Neg( f.MulAdd(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC), f.LoadFPR(i.A.FRB))); f.StoreFPR(i.A.FRT, v); - // f.UpdateFPRF(v); - if (i.A.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.A.Rc); return 0; } @@ -294,12 +205,7 @@ int InstrEmit_fnmaddsx(PPCHIRBuilder& f, const InstrData& i) { f.MulAdd(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC), f.LoadFPR(i.A.FRB))); v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE); f.StoreFPR(i.A.FRT, v); - // f.UpdateFPRF(v); - if (i.A.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.A.Rc); return 0; } @@ -308,12 +214,7 @@ int InstrEmit_fnmsubx(PPCHIRBuilder& f, const InstrData& i) { Value* v = f.Neg( f.MulSub(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC), f.LoadFPR(i.A.FRB))); f.StoreFPR(i.A.FRT, v); - // f.UpdateFPRF(v); - if (i.A.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.A.Rc); return 0; } @@ -323,12 +224,7 @@ int InstrEmit_fnmsubsx(PPCHIRBuilder& f, const InstrData& i) { f.MulSub(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC), f.LoadFPR(i.A.FRB))); v = f.Convert(f.Convert(v, FLOAT32_TYPE), FLOAT64_TYPE); f.StoreFPR(i.A.FRT, v); - // f.UpdateFPRF(v); - if (i.A.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.A.Rc); return 0; } @@ -338,12 +234,7 @@ int InstrEmit_fcfidx(PPCHIRBuilder& f, const InstrData& i) { // frD <- signed_int64_to_double( frB ) Value* v = f.Convert(f.Cast(f.LoadFPR(i.X.RB), INT64_TYPE), FLOAT64_TYPE); f.StoreFPR(i.X.RT, v); - // f.UpdateFPRF(v); - if (i.A.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.A.Rc); return 0; } @@ -354,12 +245,7 @@ int InstrEmit_fctidx(PPCHIRBuilder& f, const InstrData& i) { Value* v = f.Convert(f.LoadFPR(i.X.RB), INT64_TYPE, round_mode); v = f.Cast(v, FLOAT64_TYPE); f.StoreFPR(i.X.RT, v); - // f.UpdateFPRF(v); - if (i.X.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.X.Rc); return 0; } @@ -375,12 +261,7 @@ int InstrEmit_fctiwx(PPCHIRBuilder& f, const InstrData& i) { Value* v = f.Convert(f.LoadFPR(i.X.RB), INT32_TYPE, round_mode); v = f.Cast(f.ZeroExtend(v, INT64_TYPE), FLOAT64_TYPE); f.StoreFPR(i.X.RT, v); - // f.UpdateFPRF(v); - if (i.X.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.X.Rc); return 0; } @@ -396,12 +277,7 @@ int InstrEmit_frspx(PPCHIRBuilder& f, const InstrData& i) { Value* v = f.Convert(f.LoadFPR(i.X.RB), FLOAT32_TYPE, round_mode); v = f.Convert(v, FLOAT64_TYPE); f.StoreFPR(i.X.RT, v); - // f.UpdateFPRF(v); - if (i.X.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.X.Rc); return 0; } @@ -425,8 +301,7 @@ int InstrEmit_fcmpx_(PPCHIRBuilder& f, const InstrData& i, bool ordered) { // TODO(benvanik): update FPCC for mffsx/etc // TODO(benvanik): update VXSNAN const uint32_t crf = i.X.RT >> 2; - // f.UpdateFPRF(v); - f.UpdateCR(crf, f.LoadFPR(i.X.RA), f.LoadFPR(i.X.RB), false); + f.UpdateCR(crf, f.LoadFPR(i.X.RA), f.LoadFPR(i.X.RB)); return 0; } int InstrEmit_fcmpo(PPCHIRBuilder& f, const InstrData& i) { @@ -448,7 +323,7 @@ int InstrEmit_mffsx(PPCHIRBuilder& f, const InstrData& i) { XEINSTRNOTIMPLEMENTED(); return 1; } - Value* v = f.Cast(f.LoadFPSCR(), FLOAT64_TYPE); + Value* v = f.Cast(f.ZeroExtend(f.LoadFPSCR(), INT64_TYPE), FLOAT64_TYPE); f.StoreFPR(i.X.RT, v); return 0; } @@ -464,10 +339,6 @@ int InstrEmit_mtfsb1x(PPCHIRBuilder& f, const InstrData& i) { } int InstrEmit_mtfsfx(PPCHIRBuilder& f, const InstrData& i) { - if (i.XFL.Rc) { - XEINSTRNOTIMPLEMENTED(); - return 1; - } if (i.XFL.L) { // Move/shift. XEINSTRNOTIMPLEMENTED(); @@ -477,7 +348,11 @@ int InstrEmit_mtfsfx(PPCHIRBuilder& f, const InstrData& i) { // TODO(benvanik): use w/field mask to select bits. // i.XFL.W; // i.XFL.FM; - f.StoreFPSCR(f.Cast(f.LoadFPR(i.XFL.RB), INT64_TYPE)); + f.StoreFPSCR( + f.Truncate(f.Cast(f.LoadFPR(i.XFL.RB), INT64_TYPE), INT32_TYPE)); + } + if (i.XFL.Rc) { + f.CopyFPSCRToCR1(); } return 0; } @@ -493,11 +368,7 @@ int InstrEmit_fabsx(PPCHIRBuilder& f, const InstrData& i) { // frD <- abs(frB) Value* v = f.Abs(f.LoadFPR(i.X.RB)); f.StoreFPR(i.X.RT, v); - if (i.X.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.X.Rc); return 0; } @@ -505,11 +376,7 @@ int InstrEmit_fmrx(PPCHIRBuilder& f, const InstrData& i) { // frD <- (frB) Value* v = f.LoadFPR(i.X.RB); f.StoreFPR(i.X.RT, v); - if (i.X.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.X.Rc); return 0; } @@ -517,11 +384,7 @@ int InstrEmit_fnabsx(PPCHIRBuilder& f, const InstrData& i) { // frD <- !abs(frB) Value* v = f.Neg(f.Abs(f.LoadFPR(i.X.RB))); f.StoreFPR(i.X.RT, v); - if (i.X.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.X.Rc); return 0; } @@ -529,11 +392,7 @@ int InstrEmit_fnegx(PPCHIRBuilder& f, const InstrData& i) { // frD <- ¬ frB[0] || frB[1-63] Value* v = f.Neg(f.LoadFPR(i.X.RB)); f.StoreFPR(i.X.RT, v); - if (i.X.Rc) { - // e.update_cr_with_cond(1, v); - XEINSTRNOTIMPLEMENTED(); - return 1; - } + f.UpdateFPSCR(v, i.X.Rc); return 0; } diff --git a/src/xenia/cpu/ppc/ppc_hir_builder.cc b/src/xenia/cpu/ppc/ppc_hir_builder.cc index db4adf239..bce5d9d16 100644 --- a/src/xenia/cpu/ppc/ppc_hir_builder.cc +++ b/src/xenia/cpu/ppc/ppc_hir_builder.cc @@ -380,11 +380,11 @@ void PPCHIRBuilder::UpdateCR6(Value* src_value) { } Value* PPCHIRBuilder::LoadFPSCR() { - return LoadContext(offsetof(PPCContext, fpscr), INT64_TYPE); + return LoadContext(offsetof(PPCContext, fpscr), INT32_TYPE); } void PPCHIRBuilder::StoreFPSCR(Value* value) { - assert_true(value->type == INT64_TYPE); + assert_true(value->type == INT32_TYPE); StoreContext(offsetof(PPCContext, fpscr), value); auto& trace_reg = trace_info_.dests[trace_info_.dest_count++]; @@ -392,13 +392,59 @@ void PPCHIRBuilder::StoreFPSCR(Value* value) { trace_reg.value = value; } +void PPCHIRBuilder::UpdateFPSCR(Value* result, bool update_cr1) { + // TODO(benvanik): detect overflow and nan cases. + // fx and vx are the most important. + Value* fx = LoadConstantInt8(0); + Value* fex = LoadConstantInt8(0); + Value* vx = LoadConstantInt8(0); + Value* ox = LoadConstantInt8(0); + + if (update_cr1) { + // Store into the CR1 field. + // We do this instead of just calling CopyFPSCRToCR1 so that we don't + // have to read back the bits and do shifting work. + StoreContext(offsetof(PPCContext, cr1.cr1_fx), fx); + StoreContext(offsetof(PPCContext, cr1.cr1_fex), fex); + StoreContext(offsetof(PPCContext, cr1.cr1_vx), vx); + StoreContext(offsetof(PPCContext, cr1.cr1_ox), ox); + } + + // Generate our new bits. + Value* new_bits = Shl(ZeroExtend(fx, INT32_TYPE), 31); + new_bits = Or(new_bits, Shl(ZeroExtend(fex, INT32_TYPE), 30)); + new_bits = Or(new_bits, Shl(ZeroExtend(vx, INT32_TYPE), 29)); + new_bits = Or(new_bits, Shl(ZeroExtend(ox, INT32_TYPE), 28)); + + // Mix into fpscr while preserving sticky bits (FX and OX). + Value* bits = LoadFPSCR(); + bits = Or(And(bits, LoadConstantUint32(0x9FFFFFFF)), new_bits); + StoreFPSCR(bits); +} + +void PPCHIRBuilder::CopyFPSCRToCR1() { + // Pull out of FPSCR. + Value* fpscr = LoadFPSCR(); + StoreContext(offsetof(PPCContext, cr1.cr1_fx), + And(Truncate(Shr(fpscr, 31), INT8_TYPE), LoadConstantInt8(1))); + StoreContext(offsetof(PPCContext, cr1.cr1_fex), + And(Truncate(Shr(fpscr, 30), INT8_TYPE), LoadConstantInt8(1))); + StoreContext(offsetof(PPCContext, cr1.cr1_vx), + And(Truncate(Shr(fpscr, 29), INT8_TYPE), LoadConstantInt8(1))); + StoreContext(offsetof(PPCContext, cr1.cr1_ox), + And(Truncate(Shr(fpscr, 28), INT8_TYPE), LoadConstantInt8(1))); +} + Value* PPCHIRBuilder::LoadXER() { Value* v = Shl(ZeroExtend(LoadCA(), INT64_TYPE), 29); // TODO(benvanik): construct with other flags; overflow, etc? return v; } -void PPCHIRBuilder::StoreXER(Value* value) { assert_always(); } +void PPCHIRBuilder::StoreXER(Value* value) { + // TODO(benvanik): use other fields? For now, just pull out CA. + StoreCA(Truncate(And(Shr(value, 29), LoadConstantInt64(1)), INT8_TYPE)); +} Value* PPCHIRBuilder::LoadCA() { return LoadContext(offsetof(PPCContext, xer_ca), INT8_TYPE); diff --git a/src/xenia/cpu/ppc/ppc_hir_builder.h b/src/xenia/cpu/ppc/ppc_hir_builder.h index 634919be4..ca9830799 100644 --- a/src/xenia/cpu/ppc/ppc_hir_builder.h +++ b/src/xenia/cpu/ppc/ppc_hir_builder.h @@ -59,6 +59,8 @@ class PPCHIRBuilder : public hir::HIRBuilder { void UpdateCR6(Value* src_value); Value* LoadFPSCR(); void StoreFPSCR(Value* value); + void UpdateFPSCR(Value* result, bool update_cr1); + void CopyFPSCRToCR1(); Value* LoadXER(); void StoreXER(Value* value); // void UpdateXERWithOverflow(); diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index f1d219a9f..d293a01e5 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -504,7 +504,8 @@ X_STATUS Emulator::CompleteLaunch(const std::wstring& path, XELOGI("Launching module %s", next_module.c_str()); auto module = kernel_state_->LoadUserModule(next_module.c_str()); if (!module) { - XELOGE("Failed to load user module %s", path); + auto path_str = xe::to_string(path); + XELOGE("Failed to load user module %s", path.c_str()); return X_STATUS_NOT_FOUND; }