Beispiel #1
0
static void
andGeneric(ThreadState *state, Instruction instr)
{
   uint32_t s, a, b;

   s = state->gpr[instr.rS];

   if (flags & AndImmediate) {
      b = instr.uimm;
   } else {
      b = state->gpr[instr.rB];
   }

   if (flags & AndShifted) {
      b <<= 16;
   }

   if (flags & AndComplement) {
      b = ~b;
   }

   a = s & b;
   state->gpr[instr.rA] = a;

   if (flags & AndAlwaysRecord) {
      updateConditionRegister(state, a);
   } else if (flags & AndCheckRecord) {
      if (instr.rc) {
         updateConditionRegister(state, a);
      }
   }
}
Beispiel #2
0
static bool
orGeneric(PPCEmuAssembler& a, Instruction instr)
{
   a.mov(a.eax, a.ppcgpr[instr.rS]);

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

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

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

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

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

   return true;
}
Beispiel #3
0
static bool
mulUnsignedGeneric(PPCEmuAssembler& a, Instruction instr)
{
   a.mov(a.eax, a.ppcgpr[instr.rA]);

   if (flags & MulImmediate) {
      a.mov(a.ecx, sign_extend<16>(instr.simm));
   } else {
      a.mov(a.ecx, a.ppcgpr[instr.rB]);
   }

   a.mul(a.ecx);

   if (flags & MulLow) {
      a.mov(a.ppcgpr[instr.rD], a.eax);

      if (flags & MulCheckRecord) {
         if (instr.rc) {
            updateConditionRegister(a, a.eax, a.ecx, a.edx);
         }
      }
   } else if (flags & MulHigh) {
      a.mov(a.ppcgpr[instr.rD], a.edx);

      if (flags & MulCheckRecord) {
         if (instr.rc) {
            updateConditionRegister(a, a.edx, a.ecx, a.eax);
         }
      }
   } else {
      assert(0);
   }

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

   if (flags & ShiftImmediate) {
      if (flags & ShiftLeft) {
         a.shl(a.eax, instr.sh);
      } else if (flags & ShiftRight) {
         a.shr(a.eax, instr.sh);
      } else {
         assert(0);
      }
   } else {
      a.mov(a.ecx, a.ppcgpr[instr.rB]);

      if (flags & ShiftLeft) {
         a.shl(a.eax, a.ecx.r8());
      } else if (flags & ShiftRight) {
         a.shr(a.eax, a.ecx.r8());
      } else {
         assert(0);
      }
   }

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

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

   return true;
}
Beispiel #5
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;
}
Beispiel #6
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;
}
Beispiel #7
0
// Count Leading Zeroes Word
static bool
cntlzw(PPCEmuAssembler& a, Instruction instr)
{
   asmjit::Label lblZero(a);

   a.mov(a.ecx, a.ppcgpr[instr.rS]);
   a.mov(a.eax, 32);

   a.cmp(a.ecx, 0);
   a.je(lblZero);

   a.mov(a.edx, 0);
   a.bsr(a.edx, a.ecx);

   a.dec(a.eax);
   a.sub(a.eax, a.edx);

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

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

   return true;
}
Beispiel #8
0
// Extend Sign Half Word
static void
extsh(ThreadState *state, Instruction instr)
{
   uint32_t a, s;

   s = state->gpr[instr.rS];

   a = sign_extend<16>(s);
   state->gpr[instr.rA] = a;

   if (instr.rc) {
      updateConditionRegister(state, a);
   }
}
Beispiel #9
0
// Equivalent
static void
eqv(ThreadState *state, Instruction instr)
{
   uint32_t a, s, b;

   s = state->gpr[instr.rS];
   b = state->gpr[instr.rB];

   a = ~(s ^ b);
   state->gpr[instr.rA] = a;

   if (instr.rc) {
      updateConditionRegister(state, a);
   }
}
Beispiel #10
0
// Extend Sign Half Word
static bool
extsh(PPCEmuAssembler& a, Instruction instr)
{
   a.mov(a.eax, a.ppcgpr[instr.rS]);

   a.movsx(a.eax, a.eax.r16());

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

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

   return true;
}
Beispiel #11
0
// NOR
static bool
nor(PPCEmuAssembler& a, Instruction instr)
{
   a.mov(a.eax, a.ppcgpr[instr.rS]);
   a.mov(a.ecx, a.ppcgpr[instr.rB]);

   a.or_(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;
}
Beispiel #12
0
// Count Leading Zeroes Word
static void
cntlzw(ThreadState *state, Instruction instr)
{
   unsigned long a;
   uint32_t s;

   s = state->gpr[instr.rS];

   if (!_BitScanReverse(&a, s)) {
      a = 32;
   } else {
      a = 31 - a;
   }

   state->gpr[instr.rA] = a;

   if (instr.rc) {
      updateConditionRegister(state, a);
   }
}
Beispiel #13
0
static void
divGeneric(ThreadState *state, Instruction instr)
{
   Type a, b, d;
   a = state->gpr[instr.rA];
   b = state->gpr[instr.rB];

   d = a / b;
   state->gpr[instr.rD] = d;

   auto overflow = (b == 0);
   
   if (std::is_signed<Type>::value && (a == 0x80000000 && b == -1)) {
      overflow = true;
   }

   if (instr.oe) {
      updateOverflow(state, overflow);
   }

   if (instr.rc) {
      updateConditionRegister(state, d);
   }
}
Beispiel #14
0
static void
addGeneric(ThreadState *state, Instruction instr)
{
   uint32_t a, b, d;

   // Get a value
   if ((flags & AddZeroRA) && instr.rA == 0) {
      a = 0;
   } else {
      a = state->gpr[instr.rA];
   }

   if (flags & AddSubtract) {
      a = ~a;
   }

   // Get b value
   if (flags & AddImmediate) {
      b = sign_extend<16>(instr.simm);
   } else if (flags & AddToZero) {
      b = 0;
   } else if (flags & AddToMinusOne) {
      b = -1;
   } else {
      b = state->gpr[instr.rB];
   }

   if (flags & AddShifted) {
      b <<= 16;
   }

   // Calculate d
   d = a + b;

   // Add xer[ca] if needed
   if (flags & AddExtended) {
      d += state->xer.ca;
   } else if (flags & AddSubtract) {
      d += 1;
   }

   // Update rD
   state->gpr[instr.rD] = d;

   // Check for carry/overflow
   auto carry = d < a;
   auto overflow = !!get_bit<31>((a ^ d) & (b ^ d));

   if (flags & AddCarry) {
      updateCarry(state, carry);
   }

   if (flags & AddAlwaysRecord) {
      updateOverflow(state, overflow);
      updateConditionRegister(state, d);
   } else if (flags & AddCheckRecord) {
      if (instr.oe) {
         updateOverflow(state, overflow);
      }

      if (instr.rc) {
         updateConditionRegister(state, d);
      }
   }
}
Beispiel #15
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;
}