1 // Copyright 2010 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4 
5 // Additional copyrights go to Duddie and Tratax (c) 2004
6 
7 #include "Core/DSP/DSPCore.h"
8 #include "Core/DSP/Jit/x64/DSPEmitter.h"
9 
10 using namespace Gen;
11 
12 namespace DSP::JIT::x64
13 {
14 // In: val: s64 _Value
15 // Clobbers scratch
Update_SR_Register(Gen::X64Reg val,Gen::X64Reg scratch)16 void DSPEmitter::Update_SR_Register(Gen::X64Reg val, Gen::X64Reg scratch)
17 {
18   ASSERT(val != scratch);
19 
20   const OpArg sr_reg = m_gpr.GetReg(DSP_REG_SR);
21   //	// 0x04
22   //	if (_Value == 0) g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO;
23   TEST(64, R(val), R(val));
24   FixupBranch notZero = J_CC(CC_NZ);
25   OR(16, sr_reg, Imm16(SR_ARITH_ZERO | SR_TOP2BITS));
26   FixupBranch end = J();
27   SetJumpTarget(notZero);
28 
29   //	// 0x08
30   //	if (_Value < 0) g_dsp.r[DSP_REG_SR] |= SR_SIGN;
31   FixupBranch greaterThanEqual = J_CC(CC_GE);
32   OR(16, sr_reg, Imm16(SR_SIGN));
33   SetJumpTarget(greaterThanEqual);
34 
35   //	// 0x10
36   //	if (_Value != (s32)_Value) g_dsp.r[DSP_REG_SR] |= SR_OVER_S32;
37   MOVSX(64, 32, scratch, R(val));
38   CMP(64, R(scratch), R(val));
39   FixupBranch noOverS32 = J_CC(CC_E);
40   OR(16, sr_reg, Imm16(SR_OVER_S32));
41   SetJumpTarget(noOverS32);
42 
43   //	// 0x20 - Checks if top bits of m are equal
44   //	if (((_Value & 0xc0000000) == 0) || ((_Value & 0xc0000000) == 0xc0000000))
45   MOV(32, R(scratch), Imm32(0xc0000000));
46   AND(32, R(val), R(scratch));
47   FixupBranch zeroC = J_CC(CC_Z);
48   CMP(32, R(val), R(scratch));
49   FixupBranch cC = J_CC(CC_NE);
50   SetJumpTarget(zeroC);
51   //		g_dsp.r[DSP_REG_SR] |= SR_TOP2BITS;
52   OR(16, sr_reg, Imm16(SR_TOP2BITS));
53   SetJumpTarget(cC);
54   SetJumpTarget(end);
55   m_gpr.PutReg(DSP_REG_SR);
56 }
57 
58 // In: val: s64 _Value
59 // Clobbers scratch
Update_SR_Register64(Gen::X64Reg val,Gen::X64Reg scratch)60 void DSPEmitter::Update_SR_Register64(Gen::X64Reg val, Gen::X64Reg scratch)
61 {
62   //	g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK;
63   const OpArg sr_reg = m_gpr.GetReg(DSP_REG_SR);
64   AND(16, sr_reg, Imm16(~SR_CMP_MASK));
65   m_gpr.PutReg(DSP_REG_SR);
66   Update_SR_Register(val, scratch);
67 }
68 
69 // In: (val): s64 _Value
70 // In: (carry_ovfl): 1 = carry, 2 = overflow
71 // Clobbers RDX
Update_SR_Register64_Carry(X64Reg val,X64Reg carry_ovfl,bool carry_eq)72 void DSPEmitter::Update_SR_Register64_Carry(X64Reg val, X64Reg carry_ovfl, bool carry_eq)
73 {
74   const OpArg sr_reg = m_gpr.GetReg(DSP_REG_SR);
75   //	g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK;
76   AND(16, sr_reg, Imm16(~SR_CMP_MASK));
77 
78   CMP(64, R(carry_ovfl), R(val));
79 
80   // 0x01
81   //	g_dsp.r[DSP_REG_SR] |= SR_CARRY;
82   // Carry = (acc>res)
83   // Carry2 = (acc>=res)
84   FixupBranch noCarry = J_CC(carry_eq ? CC_B : CC_BE);
85   OR(16, sr_reg, Imm16(SR_CARRY));
86   SetJumpTarget(noCarry);
87 
88   // 0x02 and 0x80
89   //	g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW;
90   //	g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW_STICKY;
91   // Overflow = ((acc ^ res) & (ax ^ res)) < 0
92   XOR(64, R(carry_ovfl), R(val));
93   XOR(64, R(RDX), R(val));
94   TEST(64, R(carry_ovfl), R(RDX));
95   FixupBranch noOverflow = J_CC(CC_GE);
96   OR(16, sr_reg, Imm16(SR_OVERFLOW | SR_OVERFLOW_STICKY));
97   SetJumpTarget(noOverflow);
98 
99   m_gpr.PutReg(DSP_REG_SR);
100   if (carry_eq)
101   {
102     Update_SR_Register();
103   }
104   else
105   {
106     Update_SR_Register(val);
107   }
108 }
109 
110 // In: RAX: s64 _Value
Update_SR_Register16(X64Reg val)111 void DSPEmitter::Update_SR_Register16(X64Reg val)
112 {
113   const OpArg sr_reg = m_gpr.GetReg(DSP_REG_SR);
114   AND(16, sr_reg, Imm16(~SR_CMP_MASK));
115 
116   //	// 0x04
117   //	if (_Value == 0) g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO;
118   TEST(64, R(val), R(val));
119   FixupBranch notZero = J_CC(CC_NZ);
120   OR(16, sr_reg, Imm16(SR_ARITH_ZERO | SR_TOP2BITS));
121   FixupBranch end = J();
122   SetJumpTarget(notZero);
123 
124   //	// 0x08
125   //	if (_Value < 0) g_dsp.r[DSP_REG_SR] |= SR_SIGN;
126   FixupBranch greaterThanEqual = J_CC(CC_GE);
127   OR(16, sr_reg, Imm16(SR_SIGN));
128   SetJumpTarget(greaterThanEqual);
129 
130   //	// 0x20 - Checks if top bits of m are equal
131   //	if ((((u16)_Value >> 14) == 0) || (((u16)_Value >> 14) == 3))
132   SHR(16, R(val), Imm8(14));
133   TEST(16, R(val), R(val));
134   FixupBranch isZero = J_CC(CC_Z);
135   CMP(16, R(val), Imm16(3));
136   FixupBranch notThree = J_CC(CC_NE);
137   SetJumpTarget(isZero);
138   //		g_dsp.r[DSP_REG_SR] |= SR_TOP2BITS;
139   OR(16, sr_reg, Imm16(SR_TOP2BITS));
140   SetJumpTarget(notThree);
141   SetJumpTarget(end);
142   m_gpr.PutReg(DSP_REG_SR);
143 }
144 
145 // In: RAX: s64 _Value
146 // Clobbers RCX
Update_SR_Register16_OverS32(Gen::X64Reg val)147 void DSPEmitter::Update_SR_Register16_OverS32(Gen::X64Reg val)
148 {
149   const OpArg sr_reg = m_gpr.GetReg(DSP_REG_SR);
150   AND(16, sr_reg, Imm16(~SR_CMP_MASK));
151 
152   //	// 0x10
153   //	if (_Value != (s32)_Value) g_dsp.r[DSP_REG_SR] |= SR_OVER_S32;
154   MOVSX(64, 32, RCX, R(val));
155   CMP(64, R(RCX), R(val));
156   FixupBranch noOverS32 = J_CC(CC_E);
157   OR(16, sr_reg, Imm16(SR_OVER_S32));
158   SetJumpTarget(noOverS32);
159 
160   m_gpr.PutReg(DSP_REG_SR);
161   //	// 0x20 - Checks if top bits of m are equal
162   //	if ((((u16)_Value >> 14) == 0) || (((u16)_Value >> 14) == 3))
163   // AND(32, R(val), Imm32(0xc0000000));
164   Update_SR_Register16(val);
165 }
166 
167 }  // namespace DSP::JIT::x64
168