309 changes: 1 addition & 308 deletions Source/Core/Core/Src/DSP/Jit/DSPJitMisc.cpp
Expand Up @@ -9,310 +9,6 @@
#include "x64ABI.h"
using namespace Gen;

//clobbers:
//EAX = (s8)g_dsp.reg_stack_ptr[stack_reg]
//expects:
void DSPEmitter::dsp_reg_stack_push(int stack_reg)
{
//g_dsp.reg_stack_ptr[stack_reg]++;
//g_dsp.reg_stack_ptr[stack_reg] &= DSP_STACK_MASK;
MOV(8, R(AL), M(&g_dsp.reg_stack_ptr[stack_reg]));
ADD(8, R(AL), Imm8(1));
AND(8, R(AL), Imm8(DSP_STACK_MASK));
MOV(8, M(&g_dsp.reg_stack_ptr[stack_reg]), R(AL));

X64Reg tmp1;
gpr.getFreeXReg(tmp1);
//g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]] = g_dsp.r[DSP_REG_ST0 + stack_reg];
MOV(16, R(tmp1), M(&g_dsp.r.st[stack_reg]));
#ifdef _M_IX86 // All32
MOVZX(32, 8, EAX, R(AL));
#else
MOVZX(64, 8, RAX, R(AL));
#endif
MOV(16, MComplex(EAX, EAX, 1,
PtrOffset(&g_dsp.reg_stack[stack_reg][0],0)), R(tmp1));
gpr.putXReg(tmp1);
}

//clobbers:
//EAX = (s8)g_dsp.reg_stack_ptr[stack_reg]
//expects:
void DSPEmitter::dsp_reg_stack_pop(int stack_reg)
{
//g_dsp.r[DSP_REG_ST0 + stack_reg] = g_dsp.reg_stack[stack_reg][g_dsp.reg_stack_ptr[stack_reg]];
MOV(8, R(AL), M(&g_dsp.reg_stack_ptr[stack_reg]));
X64Reg tmp1;
gpr.getFreeXReg(tmp1);
#ifdef _M_IX86 // All32
MOVZX(32, 8, EAX, R(AL));
#else
MOVZX(64, 8, RAX, R(AL));
#endif
MOV(16, R(tmp1), MComplex(EAX, EAX, 1,
PtrOffset(&g_dsp.reg_stack[stack_reg][0],0)));
MOV(16, M(&g_dsp.r.st[stack_reg]), R(tmp1));
gpr.putXReg(tmp1);

//g_dsp.reg_stack_ptr[stack_reg]--;
//g_dsp.reg_stack_ptr[stack_reg] &= DSP_STACK_MASK;
SUB(8, R(AL), Imm8(1));
AND(8, R(AL), Imm8(DSP_STACK_MASK));
MOV(8, M(&g_dsp.reg_stack_ptr[stack_reg]), R(AL));
}


void DSPEmitter::dsp_reg_store_stack(int stack_reg, Gen::X64Reg host_sreg)
{
if (host_sreg != EDX) {
MOV(16, R(EDX), R(host_sreg));
}
dsp_reg_stack_push(stack_reg);
//g_dsp.r[DSP_REG_ST0 + stack_reg] = val;
MOV(16, M(&g_dsp.r.st[stack_reg]), R(EDX));
}

void DSPEmitter::dsp_reg_load_stack(int stack_reg, Gen::X64Reg host_dreg)
{
//u16 val = g_dsp.r[DSP_REG_ST0 + stack_reg];
MOV(16, R(EDX), M(&g_dsp.r.st[stack_reg]));
dsp_reg_stack_pop(stack_reg);
if (host_dreg != EDX) {
MOV(16, R(host_dreg), R(EDX));
}
}

void DSPEmitter::dsp_reg_store_stack_imm(int stack_reg, u16 val)
{
dsp_reg_stack_push(stack_reg);
//g_dsp.r[DSP_REG_ST0 + stack_reg] = val;
MOV(16, M(&g_dsp.r.st[stack_reg]), Imm16(val));
}

void DSPEmitter::dsp_op_write_reg(int reg, Gen::X64Reg host_sreg)
{
switch (reg & 0x1f) {
// 8-bit sign extended registers.
case DSP_REG_ACH0:
case DSP_REG_ACH1:
gpr.writeReg(reg, R(host_sreg));
break;

// Stack registers.
case DSP_REG_ST0:
case DSP_REG_ST1:
case DSP_REG_ST2:
case DSP_REG_ST3:
dsp_reg_store_stack(reg - DSP_REG_ST0, host_sreg);
break;

default:
gpr.writeReg(reg, R(host_sreg));
break;
}
}

void DSPEmitter::dsp_op_write_reg_imm(int reg, u16 val)
{
switch (reg & 0x1f) {
// 8-bit sign extended registers. Should look at prod.h too...
case DSP_REG_ACH0:
case DSP_REG_ACH1:
gpr.writeReg(reg, Imm16((u16)(s16)(s8)(u8)val));
break;
// Stack registers.
case DSP_REG_ST0:
case DSP_REG_ST1:
case DSP_REG_ST2:
case DSP_REG_ST3:
dsp_reg_store_stack_imm(reg - DSP_REG_ST0, val);
break;

default:
gpr.writeReg(reg, Imm16(val));
break;
}
}

void DSPEmitter::dsp_conditional_extend_accum(int reg)
{
switch (reg)
{
case DSP_REG_ACM0:
case DSP_REG_ACM1:
{
OpArg sr_reg;
gpr.getReg(DSP_REG_SR,sr_reg);
DSPJitRegCache c(gpr);
TEST(16, sr_reg, Imm16(SR_40_MODE_BIT));
FixupBranch not_40bit = J_CC(CC_Z,true);
//if (g_dsp.r[DSP_REG_SR] & SR_40_MODE_BIT)
//{
// Sign extend into whole accum.
//u16 val = g_dsp.r[reg];
get_acc_m(reg - DSP_REG_ACM0, EAX);
SHR(32, R(EAX), Imm8(16));
//g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACH0] = (val & 0x8000) ? 0xFFFF : 0x0000;
//g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACL0] = 0;
set_acc_h(reg - DSP_REG_ACM0, R(RAX));
set_acc_l(reg - DSP_REG_ACM0, Imm16(0));
//}
gpr.flushRegs(c);
SetJumpTarget(not_40bit);
gpr.putReg(DSP_REG_SR, false);
}
}
}

void DSPEmitter::dsp_conditional_extend_accum_imm(int reg, u16 val)
{
switch (reg)
{
case DSP_REG_ACM0:
case DSP_REG_ACM1:
{
OpArg sr_reg;
gpr.getReg(DSP_REG_SR,sr_reg);
DSPJitRegCache c(gpr);
TEST(16, sr_reg, Imm16(SR_40_MODE_BIT));
FixupBranch not_40bit = J_CC(CC_Z, true);
//if (g_dsp.r[DSP_REG_SR] & SR_40_MODE_BIT)
//{
// Sign extend into whole accum.
//g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACH0] = (val & 0x8000) ? 0xFFFF : 0x0000;
//g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACL0] = 0;
set_acc_h(reg - DSP_REG_ACM0, Imm16((val & 0x8000)?0xffff:0x0000));
set_acc_l(reg - DSP_REG_ACM0, Imm16(0));
//}
gpr.flushRegs(c);
SetJumpTarget(not_40bit);
gpr.putReg(DSP_REG_SR, false);
}
}
}

void DSPEmitter::dsp_op_read_reg(int reg, Gen::X64Reg host_dreg, DSPJitSignExtend extend)
{
switch (reg & 0x1f)
{
case DSP_REG_ST0:
case DSP_REG_ST1:
case DSP_REG_ST2:
case DSP_REG_ST3:
dsp_reg_load_stack(reg - DSP_REG_ST0, host_dreg);
switch(extend) {
case SIGN:
#ifdef _M_IX86 // All32
MOVSX(32, 16, host_dreg, R(host_dreg));
#else
MOVSX(64, 16, host_dreg, R(host_dreg));
#endif
break;
case ZERO:
#ifdef _M_IX86 // All32
MOVZX(32, 16, host_dreg, R(host_dreg));
#else
MOVZX(64, 16, host_dreg, R(host_dreg));
#endif
break;
case NONE:
default:
break;
}
return;
default:
gpr.readReg(reg, host_dreg, extend);
return;
}
}

void DSPEmitter::dsp_op_read_reg_and_saturate(int reg, Gen::X64Reg host_dreg, DSPJitSignExtend extend)
{
//we already know this is ACCM0 or ACCM1
#ifdef _M_IX86 // All32
gpr.readReg(reg, host_dreg, extend);
#else
OpArg acc_reg;
gpr.getReg(reg-DSP_REG_ACM0+DSP_REG_ACC0_64, acc_reg);
#endif
OpArg sr_reg;
gpr.getReg(DSP_REG_SR,sr_reg);

DSPJitRegCache c(gpr);
TEST(16, sr_reg, Imm16(SR_40_MODE_BIT));
FixupBranch not_40bit = J_CC(CC_Z, true);

#ifdef _M_IX86 // All32
DSPJitRegCache c2(gpr);
gpr.putReg(DSP_REG_SR, false);
X64Reg tmp1;
gpr.getFreeXReg(tmp1);
gpr.readReg(reg-DSP_REG_ACM0+DSP_REG_ACH0, tmp1, NONE);
MOVSX(32,16,host_dreg,R(host_dreg));
SHL(32, R(tmp1), Imm8(16));
MOV(16,R(tmp1),R(host_dreg));
CMP(32,R(host_dreg), R(tmp1));

FixupBranch no_saturate = J_CC(CC_Z);

CMP(32,R(tmp1),Imm32(0));
FixupBranch negative = J_CC(CC_LE);

MOV(32,R(host_dreg),Imm32(0x7fff));//this works for all extend modes
FixupBranch done_positive = J();

SetJumpTarget(negative);
if (extend == NONE || extend == ZERO)
MOV(32,R(host_dreg),Imm32(0x00008000));
else
MOV(32,R(host_dreg),Imm32(0xffff8000));
FixupBranch done_negative = J();

SetJumpTarget(no_saturate);
if (extend == ZERO)
MOVZX(32,16,host_dreg,R(host_dreg));
SetJumpTarget(done_positive);
SetJumpTarget(done_negative);
gpr.putXReg(tmp1);
gpr.flushRegs(c2);
SetJumpTarget(not_40bit);
gpr.flushRegs(c);
#else

MOVSX(64,32,host_dreg,acc_reg);
CMP(64,R(host_dreg),acc_reg);
FixupBranch no_saturate = J_CC(CC_Z);

CMP(64,acc_reg,Imm32(0));
FixupBranch negative = J_CC(CC_LE);

MOV(64,R(host_dreg),Imm32(0x7fff));//this works for all extend modes
FixupBranch done_positive = J();

SetJumpTarget(negative);
if (extend == NONE || extend == ZERO)
MOV(64,R(host_dreg),Imm32(0x00008000));
else
MOV(64,R(host_dreg),Imm32(0xffff8000));
FixupBranch done_negative = J();

SetJumpTarget(no_saturate);
SetJumpTarget(not_40bit);

MOV(64, R(host_dreg), acc_reg);
if (extend == NONE || extend == ZERO)
SHR(64, R(host_dreg), Imm8(16));
else
SAR(64, R(host_dreg), Imm8(16));
SetJumpTarget(done_positive);
SetJumpTarget(done_negative);
gpr.flushRegs(c);
gpr.putReg(reg-DSP_REG_ACM0+DSP_REG_ACC0_64, false);
#endif

gpr.putReg(DSP_REG_SR, false);
}

// MRR $D, $S
// 0001 11dd ddds ssss
// Move value from register $S to register $D.
Expand All @@ -321,10 +17,7 @@ void DSPEmitter::mrr(const UDSPInstruction opc)
u8 sreg = opc & 0x1f;
u8 dreg = (opc >> 5) & 0x1f;

if (sreg >= DSP_REG_ACM0)
dsp_op_read_reg_and_saturate(sreg, EDX);
else
dsp_op_read_reg(sreg, EDX);
dsp_op_read_reg(sreg, EDX);
dsp_op_write_reg(dreg, EDX);
dsp_conditional_extend_accum(dreg);
}
Expand Down
56 changes: 44 additions & 12 deletions Source/Core/Core/Src/DSP/Jit/DSPJitRegCache.cpp
Expand Up @@ -255,6 +255,18 @@ void DSPJitRegCache::flushRegs(DSPJitRegCache &cache, bool emit)
regs[i].last_use_ctr = cache.regs[i].last_use_ctr;
}

//sync the freely used xregs
if (!emit) {
for(i = 0; i < NUMXREGS; i++) {
if (cache.xregs[i].guest_reg == DSP_REG_USED &&
xregs[i].guest_reg == DSP_REG_NONE)
xregs[i].guest_reg = DSP_REG_USED;
if (cache.xregs[i].guest_reg == DSP_REG_NONE &&
xregs[i].guest_reg == DSP_REG_USED)
xregs[i].guest_reg = DSP_REG_NONE;
}
}

//consistency checks
for(i = 0; i < NUMXREGS; i++)
{
Expand Down Expand Up @@ -389,7 +401,7 @@ void DSPJitRegCache::loadRegs(bool emit)
for(unsigned int i = 0; i <= DSP_REG_MAX_MEM_BACKED; i++)
{
if (regs[i].host_reg != INVALID_REG)
movToHostReg(i,regs[i].host_reg);
movToHostReg(i,regs[i].host_reg, emit);
}

if (emit)
Expand Down Expand Up @@ -519,7 +531,7 @@ void DSPJitRegCache::popRegs() {
for(unsigned int i = 0; i <= DSP_REG_MAX_MEM_BACKED; i++)
{
if (regs[i].host_reg != INVALID_REG)
movToHostReg(i,regs[i].host_reg);
movToHostReg(i,regs[i].host_reg, true);
}
}

Expand Down Expand Up @@ -916,17 +928,38 @@ void DSPJitRegCache::writeReg(int dreg, OpArg arg)
{
OpArg reg;
getReg(dreg, reg, false);

switch(regs[dreg].size)
if (arg.IsImm())
{
case 2: emitter.MOV(16, reg, arg); break;
case 4: emitter.MOV(32, reg, arg); break;
switch(regs[dreg].size)
{
case 2: emitter.MOV(16, reg, Imm16(arg.offset)); break;
case 4: emitter.MOV(32, reg, Imm32(arg.offset)); break;
#ifdef _M_X64
case 8: emitter.MOV(64, reg, arg); break;
case 8:
if ((s32)arg.offset == (s64)arg.offset)
emitter.MOV(64, reg, Imm32(arg.offset));
else
emitter.MOV(64, reg, Imm64(arg.offset));
break;
#endif
default:
_assert_msg_(DSPLLE, 0, "unsupported memory size");
break;
default:
_assert_msg_(DSPLLE, 0, "unsupported memory size");
break;
}
}
else
{
switch(regs[dreg].size)
{
case 2: emitter.MOV(16, reg, arg); break;
case 4: emitter.MOV(32, reg, arg); break;
#ifdef _M_X64
case 8: emitter.MOV(64, reg, arg); break;
#endif
default:
_assert_msg_(DSPLLE, 0, "unsupported memory size");
break;
}
}
putReg(dreg, true);
}
Expand Down Expand Up @@ -1042,8 +1075,7 @@ void DSPJitRegCache::getXReg(X64Reg reg)

if (xregs[reg].guest_reg != DSP_REG_NONE)
spillXReg(reg);

_assert_msg_(DSPLLE, xregs[reg].guest_reg != DSP_REG_NONE, "register already in use");
_assert_msg_(DSPLLE, xregs[reg].guest_reg == DSP_REG_NONE, "register already in use");
xregs[reg].guest_reg = DSP_REG_USED;
}

Expand Down
368 changes: 362 additions & 6 deletions Source/Core/Core/Src/DSP/Jit/DSPJitUtil.cpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp
Expand Up @@ -1997,7 +1997,7 @@ void Jit64::slwx(UGeckoInstruction inst)
}
else
{
MOV(32, gpr.R(a), gpr.R(a));
MOVZX(64, 32, gpr.R(a).GetSimpleReg(), gpr.R(a));
}
gpr.UnlockAll();
gpr.UnlockAllX();
Expand Down