static bool addGeneric(PPCEmuAssembler& a, Instruction instr) { if (flags & AddSubtract) { return jit_fallback(a, instr); } bool recordCarry = false; bool recordOverflow = false; bool recordCond = false; if (flags & AddCarry) { recordCarry = true; } if (flags & AddAlwaysRecord) { recordOverflow = true; recordCond = true; } else if (flags & AddCheckRecord) { if (instr.oe) { recordOverflow = true; } if (instr.rc) { recordCond = true; } } if ((flags & AddZeroRA) && instr.rA == 0) { a.mov(a.eax, 0); } else { a.mov(a.eax, a.ppcgpr[instr.rA]); } if (flags & AddSubtract) { a.not_(a.eax); } if (flags & AddImmediate) { a.mov(a.ecx, sign_extend<16>(instr.simm)); } else if (flags & AddToZero) { a.mov(a.ecx, 0); } else if (flags & AddToMinusOne) { a.mov(a.ecx, -1); } else { a.mov(a.ecx, a.ppcgpr[instr.rB]); } if (flags & AddShifted) { a.shl(a.ecx, 16); } // Mark x64 CF based on PPC CF if (flags & AddExtended) { a.mov(a.edx, a.ppcxer); a.and_(a.edx, XERegisterBits::Carry); a.add(a.edx, 0xffffffff); a.adc(a.eax, a.ecx); } else if (flags & AddSubtract) { a.stc(); a.adc(a.eax, a.ecx); } else { a.add(a.eax, a.ecx); } if (recordCarry && recordOverflow) { a.mov(a.ecx, 0); a.setc(a.ecx.r8()); a.mov(a.edx, 0); a.seto(a.edx.r8()); a.shl(a.ecx, XERegisterBits::CarryShift); a.shl(a.edx, XERegisterBits::OverflowShift); a.or_(a.ecx, a.edx); } else if (recordCarry) { a.mov(a.ecx, 0); a.setc(a.ecx.r8()); a.shl(a.ecx, XERegisterBits::CarryShift); } else if (recordOverflow) { a.mov(a.ecx, 0); a.seto(a.ecx.r8()); a.shl(a.ecx, XERegisterBits::OverflowShift); } if (recordCarry || recordOverflow) { uint32_t mask = 0xFFFFFFFF; if (recordCarry) { mask &= ~XERegisterBits::Carry; } if (recordOverflow) { mask &= ~XERegisterBits::Overflow; } a.mov(a.edx, a.ppcxer); a.and_(a.edx, mask); a.or_(a.edx, a.ecx); a.mov(a.ppcxer, a.edx); } a.mov(a.ppcgpr[instr.rD], a.eax); if (recordCond) { updateConditionRegister(a, a.eax, a.ecx, a.edx); } return true; }