Example #1
0
static bool
rlwGeneric(PPCEmuAssembler& a, Instruction instr)
{
   a.mov(a.eax, a.ppcgpr[instr.rS]);

   if (flags & RlwImmediate) {
      a.rol(a.eax, instr.sh);
   } else {
      a.mov(a.ecx, a.ppcgpr[instr.rB]);
      a.and_(a.ecx, 0x1f);
      a.rol(a.eax, a.ecx.r8());
   }

   auto m = make_ppc_bitmask(instr.mb, instr.me);

   if (flags & RlwAnd) {
      a.and_(a.eax, m);
   } else if (flags & RlwInsert) {
      a.and_(a.eax, m);
      a.mov(a.ecx, a.ppcgpr[instr.rA]);
      a.and_(a.ecx, ~m);
      a.or_(a.eax, a.ecx);
   }

   a.mov(a.ppcgpr[instr.rA], a.eax);

   if (instr.rc) {
      updateConditionRegister(a, a.eax, a.ecx, a.edx);
   }

   return true;
}
Example #2
0
// Move to Condition Register from XER
static bool
mcrxr(PPCEmuAssembler& a, Instruction instr)
{
   uint32_t crshift = (7 - instr.crfD) * 4;

   a.mov(a.eax, a.ppcxer);
   a.mov(a.ecx, a.eax);

   // Grab CRXR
   a.shr(a.ecx, XERegisterBits::XRShift);
   a.and_(a.ecx, 0xF);

   // Clear XER CRXR
   a.and_(a.eax, ~XERegisterBits::XR);
   a.mov(a.ppcxer, a.eax);

   // Set CRF
   a.shl(a.ecx, crshift);
   a.mov(a.eax, a.ppccr);
   a.and_(a.eax, ~(0xF << crshift));
   a.or_(a.eax, a.ecx);
   a.mov(a.ppccr, a.eax);

   return true;
}
Example #3
0
void setCRB(PPCEmuAssembler& a, uint32_t bit, const asmjit::X86GpReg& value, const asmjit::X86GpReg& tmp, const asmjit::X86GpReg& tmp2) {
   auto shift = 31 - bit;
   a.mov(tmp, a.ppccr);
   a.and_(tmp, ~(1 << shift));
   a.mov(tmp2, value);
   a.and_(tmp2, 1);
   a.shl(tmp2, shift);
   a.or_(tmp, tmp2);
   a.mov(a.ppccr, tmp);
}
Example #4
0
// Negate
static bool
neg(PPCEmuAssembler& a, Instruction instr)
{
   a.mov(a.eax, a.ppcgpr[instr.rA]);
   a.neg(a.eax);
   a.mov(a.ppcgpr[instr.rD], a.eax);

   if (instr.oe) {
      a.mov(a.ecx, 0);
      a.seto(a.ecx.r8());

      // Reset overflow
      a.mov(a.edx, a.ppcxer);
      a.and_(a.edx, ~XERegisterBits::Overflow);

      a.shiftTo(a.ecx, 0, XERegisterBits::Overflow);
      a.or_(a.edx, a.ecx);
      a.shiftTo(a.ecx, XERegisterBits::Overflow, XERegisterBits::StickyOV);
      a.or_(a.edx, a.ecx);

      a.mov(a.ppcxer, a.edx);
   }

   if (instr.rc) {
      updateConditionRegister(a, a.eax, a.ecx, a.edx);
   }

   return true;
}
Example #5
0
static bool
andGeneric(PPCEmuAssembler& a, Instruction instr)
{
   a.mov(a.eax, a.ppcgpr[instr.rS]);

   if (flags & AndImmediate) {
      a.mov(a.ecx, instr.uimm);
   } else {
      a.mov(a.ecx, a.ppcgpr[instr.rB]);
   }

   if (flags & AndShifted) {
      a.shl(a.ecx, 16);
   }

   if (flags & AndComplement) {
      a.not_(a.ecx);
   }

   a.and_(a.eax, a.ecx);

   a.mov(a.ppcgpr[instr.rA], a.eax);

   if (flags & AndAlwaysRecord) {
      updateConditionRegister(a, a.eax, a.ecx, a.edx);
   } else if (flags & AndCheckRecord) {
      if (instr.rc) {
         updateConditionRegister(a, a.eax, a.ecx, a.edx);
      }
   }

   return true;
}
Example #6
0
// Move Condition Register Field
static bool
mcrf(PPCEmuAssembler& a, Instruction instr)
{
   uint32_t crshifts = (7 - instr.crfS) * 4;
   uint32_t crshiftd = (7 - instr.crfD) * 4;

   a.mov(a.eax, a.ppccr);
   a.mov(a.ecx, a.eax);
   a.and_(a.ecx, ~(0xF << crshifts));
   a.shr(a.ecx, crshifts);
   a.shl(a.ecx, crshiftd);
   a.and_(a.eax, ~(0xF << crshiftd));
   a.or_(a.eax, a.ecx);
   a.mov(a.ppccr, a.eax);

   return true;
}
Example #7
0
// Condition Register AND
static bool
crand(PPCEmuAssembler& a, Instruction instr)
{
   getTwoCRB(a, instr.crbA, a.eax, instr.crbB, a.ecx);
   a.and_(a.eax, a.ecx);
   setCRB(a, instr.crbD, a.eax, a.ecx, a.edx);
   return true;
}
Example #8
0
// Move to Condition Register Fields
static bool
mtcrf(PPCEmuAssembler& a, Instruction instr)
{
   uint32_t crm = instr.crm;
   uint32_t mask = 0;
   for (auto i = 0u; i < 8; ++i) {
      if (crm & (1 << i)) {
         mask |= 0xf << (i * 4);
      }
   }

   a.mov(a.eax, a.ppcgpr[instr.rS]);
   a.and_(a.eax, mask);
   a.mov(a.ecx, a.ppccr);
   a.and_(a.ecx, ~mask);
   a.or_(a.eax, a.ecx);
   a.mov(a.ppccr, a.eax);
   return true;
}
Example #9
0
static bool
shiftArithmetic(PPCEmuAssembler& a, Instruction instr)
{
   if (flags & ShiftImmediate && instr.sh == 0) {
      // Clear Carry Flag
      a.mov(a.ecx, a.ppcxer);
      a.and_(a.ecx, ~XERegisterBits::Carry);
      a.mov(a.ppcxer, a.ecx);
      return true;
   }

   return jit_fallback(a, instr);
}
Example #10
0
// Update cr0 with value
static void
updateConditionRegister(PPCEmuAssembler& a, const asmjit::X86GpReg& value, const asmjit::X86GpReg& tmp, const asmjit::X86GpReg& tmp2)
{
   auto crtarget = 0;
   auto crshift = (7 - crtarget) * 4;

   a.mov(tmp, a.ppccr);
   a.and_(tmp, ~(0xF << crshift));

   a.cmp(value, 0);

   a.lahf();
   a.mov(tmp2, 0);
   a.sete(tmp2.r8());
   a.shl(tmp2, crshift + ConditionRegisterFlag::ZeroShift);
   a.or_(tmp, tmp2);

   a.sahf();
   a.mov(tmp2, 0);
   a.setg(tmp2.r8());
   a.shl(tmp2, crshift + ConditionRegisterFlag::PositiveShift);
   a.or_(tmp, tmp2);

   a.sahf();
   a.mov(tmp2, 0);
   a.setl(tmp2.r8());
   a.shl(tmp2, crshift + ConditionRegisterFlag::NegativeShift);
   a.or_(tmp, tmp2);

   a.mov(tmp2, a.ppcxer);
   a.and_(tmp2, XERegisterBits::StickyOV);
   a.shiftTo(tmp2, XERegisterBits::StickyOVShift, crshift + ConditionRegisterFlag::SummaryOverflowShift);
   a.or_(tmp, tmp2);

   a.mov(a.ppccr, tmp);
}
Example #11
0
void getTwoCRB(PPCEmuAssembler& a,
      uint32_t bita, const asmjit::X86GpReg& da, 
      uint32_t bitb, const asmjit::X86GpReg& db) {
   auto shifta = 31 - bita;
   auto shiftb = 31 - bitb;
   a.mov(da, a.ppccr);
   a.mov(db, da);
   if (shifta > 0) {
      a.shr(da, shifta);
   }
   if (shiftb > 0) {
      a.shr(db, shiftb);
   }
   a.and_(da, 1);
   a.and_(db, 1);
}
Example #12
0
// NAND
static bool
nand(PPCEmuAssembler& a, Instruction instr)
{
   a.mov(a.eax, a.ppcgpr[instr.rS]);
   a.mov(a.ecx, a.ppcgpr[instr.rB]);

   a.and_(a.eax, a.ecx);
   a.not_(a.eax);

   a.mov(a.ppcgpr[instr.rA], a.eax);

   if (instr.rc) {
      updateConditionRegister(a, a.eax, a.ecx, a.edx);
   }

   return true;
}
Example #13
0
// Data Cache Block Zero
static bool
dcbz(PPCEmuAssembler& a, Instruction instr)
{
   auto src = a.allocGpTmp().r32();

   if (instr.rA == 0) {
      a.mov(src, 0);
   } else {
      a.mov(src, a.loadRegisterRead(a.gpr[instr.rA]));
   }

   a.add(src, a.loadRegisterRead(a.gpr[instr.rB]));

   // Align down
   a.and_(src, ~static_cast<uint32_t>(31));

   // Write 32 bytes of zero's there
   a.mov(asmjit::X86Mem(a.membaseReg, src, 0, 0, 8), 0);
   a.mov(asmjit::X86Mem(a.membaseReg, src, 0, 8, 8), 0);
   a.mov(asmjit::X86Mem(a.membaseReg, src, 0, 16, 8), 0);
   a.mov(asmjit::X86Mem(a.membaseReg, src, 0, 24, 8), 0);

   return true;
}
Example #14
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;
}
Example #15
0
static bool
cmpGeneric(PPCEmuAssembler& a, Instruction instr)
{
   uint32_t crshift = (7 - instr.crfD) * 4;

   // Load CRF
   a.mov(a.edx, a.ppccr);
   
   // Mask CRF
   uint32_t mask = 0xFFFFFFFF;
   mask &= ~(0xF << crshift);
   a.and_(a.edx, mask);

   // Summary Overflow
   a.mov(a.eax, a.ppcxer);
   a.and_(a.eax, XERegisterBits::StickyOV);
   a.shr(a.eax, XERegisterBits::StickyOVShift);
   a.shl(a.eax, ConditionRegisterFlag::SummaryOverflowShift << crshift);
   a.or_(a.edx, a.eax);

   // Perform Comparison
   a.mov(a.eax, a.ppcgpr[instr.rA]);

   if (flags & CmpImmediate) {
      if (std::is_signed<Type>::value) {
         a.mov(a.ecx, sign_extend<16>(instr.simm));
      } else {
         a.mov(a.ecx, instr.uimm);
      }
   } else {
      a.mov(a.ecx, a.ppcgpr[instr.rB]);
   }

   a.cmp(a.eax, a.ecx);
   a.mov(a.r8d, 0);
   if (std::is_unsigned<Type>::value) {
      a.seta(a.r8d.r8());
   } else {
      a.setg(a.r8d.r8());
   }
   a.mov(a.r9d, 0);
   if (std::is_unsigned<Type>::value) {
      a.setb(a.r9d.r8());
   } else {
      a.setl(a.r9d.r8());
   }

   a.mov(a.ecx, 0);
   a.sete(a.ecx.r8());
   a.shl(a.ecx, crshift + ConditionRegisterFlag::ZeroShift);
   a.or_(a.edx, a.ecx);

   a.mov(a.ecx, a.r8d);
   a.shl(a.ecx, crshift + ConditionRegisterFlag::PositiveShift);
   a.or_(a.edx, a.ecx);
   
   a.mov(a.ecx, a.r9d);
   a.shl(a.ecx, crshift + ConditionRegisterFlag::NegativeShift);
   a.or_(a.edx, a.ecx);

   a.mov(a.ppccr, a.edx);

   return true;
}