Example #1
0
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;
}