// In: RAX: s64 _Value void DSPEmitter::Update_SR_Register16(X64Reg val) { OpArg sr_reg; gpr.GetReg(DSP_REG_SR, sr_reg); AND(16, sr_reg, Imm16(~SR_CMP_MASK)); // // 0x04 // if (_Value == 0) g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO; TEST(64, R(val), R(val)); FixupBranch notZero = J_CC(CC_NZ); OR(16, sr_reg, Imm16(SR_ARITH_ZERO | SR_TOP2BITS)); FixupBranch end = J(); SetJumpTarget(notZero); // // 0x08 // if (_Value < 0) g_dsp.r[DSP_REG_SR] |= SR_SIGN; FixupBranch greaterThanEqual = J_CC(CC_GE); OR(16, sr_reg, Imm16(SR_SIGN)); SetJumpTarget(greaterThanEqual); // // 0x20 - Checks if top bits of m are equal // if ((((u16)_Value >> 14) == 0) || (((u16)_Value >> 14) == 3)) SHR(16, R(val), Imm8(14)); TEST(16, R(val), R(val)); FixupBranch isZero = J_CC(CC_Z); CMP(16, R(val), Imm16(3)); FixupBranch notThree = J_CC(CC_NE); SetJumpTarget(isZero); // g_dsp.r[DSP_REG_SR] |= SR_TOP2BITS; OR(16, sr_reg, Imm16(SR_TOP2BITS)); SetJumpTarget(notThree); SetJumpTarget(end); gpr.PutReg(DSP_REG_SR); }
// In: RAX: s64 _Value // Clobbers RDX void DSPEmitter::Update_SR_Register64(Gen::X64Reg val) { // g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK; OpArg sr_reg; gpr.GetReg(DSP_REG_SR, sr_reg); AND(16, sr_reg, Imm16(~SR_CMP_MASK)); gpr.PutReg(DSP_REG_SR); Update_SR_Register(val); }
// In: RAX: s64 _Value // Clobbers RCX void DSPEmitter::Update_SR_Register16_OverS32(Gen::X64Reg val) { OpArg sr_reg; gpr.GetReg(DSP_REG_SR, sr_reg); AND(16, sr_reg, Imm16(~SR_CMP_MASK)); // // 0x10 // if (_Value != (s32)_Value) g_dsp.r[DSP_REG_SR] |= SR_OVER_S32; MOVSX(64, 32, RCX, R(val)); CMP(64, R(RCX), R(val)); FixupBranch noOverS32 = J_CC(CC_E); OR(16, sr_reg, Imm16(SR_OVER_S32)); SetJumpTarget(noOverS32); gpr.PutReg(DSP_REG_SR); // // 0x20 - Checks if top bits of m are equal // if ((((u16)_Value >> 14) == 0) || (((u16)_Value >> 14) == 3)) // AND(32, R(val), Imm32(0xc0000000)); Update_SR_Register16(val); }
TEST_F(x64EmitterTest, PUSH_Immediate) { emitter->PUSH(64, Imm8(0xf0)); ExpectDisassembly("push 0xfffffffffffffff0"); // X64 is weird like that... this pushes 2 bytes, not 8 bytes with sext. emitter->PUSH(64, Imm16(0xe0f0)); ExpectDisassembly("push 0xe0f0"); emitter->PUSH(64, Imm32(0xc0d0e0f0)); ExpectDisassembly("push 0xffffffffc0d0e0f0"); }
// In: RAX: s64 _Value // Clobbers RDX void DSPEmitter::Update_SR_Register(Gen::X64Reg val) { OpArg sr_reg; gpr.GetReg(DSP_REG_SR, sr_reg); // // 0x04 // if (_Value == 0) g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO; TEST(64, R(val), R(val)); FixupBranch notZero = J_CC(CC_NZ); OR(16, sr_reg, Imm16(SR_ARITH_ZERO | SR_TOP2BITS)); FixupBranch end = J(); SetJumpTarget(notZero); // // 0x08 // if (_Value < 0) g_dsp.r[DSP_REG_SR] |= SR_SIGN; FixupBranch greaterThanEqual = J_CC(CC_GE); OR(16, sr_reg, Imm16(SR_SIGN)); SetJumpTarget(greaterThanEqual); // // 0x10 // if (_Value != (s32)_Value) g_dsp.r[DSP_REG_SR] |= SR_OVER_S32; MOVSX(64, 32, RDX, R(val)); CMP(64, R(RDX), R(val)); FixupBranch noOverS32 = J_CC(CC_E); OR(16, sr_reg, Imm16(SR_OVER_S32)); SetJumpTarget(noOverS32); // // 0x20 - Checks if top bits of m are equal // if (((_Value & 0xc0000000) == 0) || ((_Value & 0xc0000000) == 0xc0000000)) MOV(32, R(RDX), Imm32(0xc0000000)); AND(32, R(val), R(RDX)); FixupBranch zeroC = J_CC(CC_Z); CMP(32, R(val), R(RDX)); FixupBranch cC = J_CC(CC_NE); SetJumpTarget(zeroC); // g_dsp.r[DSP_REG_SR] |= SR_TOP2BITS; OR(16, sr_reg, Imm16(SR_TOP2BITS)); SetJumpTarget(cC); SetJumpTarget(end); gpr.PutReg(DSP_REG_SR); }
// In: (val): s64 _Value // In: (carry_ovfl): 1 = carry, 2 = overflow // Clobbers RDX void DSPEmitter::Update_SR_Register64_Carry(X64Reg val, X64Reg carry_ovfl, bool carry_eq) { OpArg sr_reg; gpr.GetReg(DSP_REG_SR, sr_reg); // g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK; AND(16, sr_reg, Imm16(~SR_CMP_MASK)); CMP(64, R(carry_ovfl), R(val)); // 0x01 // g_dsp.r[DSP_REG_SR] |= SR_CARRY; // Carry = (acc>res) // Carry2 = (acc>=res) FixupBranch noCarry = J_CC(carry_eq ? CC_B : CC_BE); OR(16, sr_reg, Imm16(SR_CARRY)); SetJumpTarget(noCarry); // 0x02 and 0x80 // g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW; // g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW_STICKY; // Overflow = ((acc ^ res) & (ax ^ res)) < 0 XOR(64, R(carry_ovfl), R(val)); XOR(64, R(RDX), R(val)); TEST(64, R(carry_ovfl), R(RDX)); FixupBranch noOverflow = J_CC(CC_GE); OR(16, sr_reg, Imm16(SR_OVERFLOW | SR_OVERFLOW_STICKY)); SetJumpTarget(noOverflow); gpr.PutReg(DSP_REG_SR); if (carry_eq) { Update_SR_Register(); } else { Update_SR_Register(val); } }