summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorpierre <pierre@pirsoft.de>2011-03-12 17:50:19 +0000
committerpierre <pierre@pirsoft.de>2011-03-12 17:50:19 +0000
commitca67d025e2cfd0d04adad7782c69cf37dcb4358f (patch)
treedeeb54d5a502fc20cacae535a338d2fd78c332b5 /Source/Core
parent26b6a9af612b65aa31e249ae17cc68c13e43b4ba (diff)
Core/DSP/Jit: Implement Saturation/Limiting when reading ACM* in 40 bit mode
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@7336 8ced0084-cf51-0410-be5f-012b33b47a6e
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Core/Src/DSP/DSPEmitter.h1
-rw-r--r--Source/Core/Core/Src/DSP/Jit/DSPJitExtOps.cpp56
-rw-r--r--Source/Core/Core/Src/DSP/Jit/DSPJitLoadStore.cpp48
-rw-r--r--Source/Core/Core/Src/DSP/Jit/DSPJitMisc.cpp94
4 files changed, 165 insertions, 34 deletions
diff --git a/Source/Core/Core/Src/DSP/DSPEmitter.h b/Source/Core/Core/Src/DSP/DSPEmitter.h
index a9b357b0a4..6c6b97b9c7 100644
--- a/Source/Core/Core/Src/DSP/DSPEmitter.h
+++ b/Source/Core/Core/Src/DSP/DSPEmitter.h
@@ -116,6 +116,7 @@ public:
void dsp_conditional_extend_accum(int reg);
void dsp_conditional_extend_accum_imm(int reg, u16 val);
void dsp_op_read_reg(int reg, Gen::X64Reg host_dreg, DSPJitSignExtend extend = NONE);
+ void dsp_op_read_reg_and_saturate(int reg, Gen::X64Reg host_dreg, DSPJitSignExtend extend = NONE);
// Commands
void dar(const UDSPInstruction opc);
diff --git a/Source/Core/Core/Src/DSP/Jit/DSPJitExtOps.cpp b/Source/Core/Core/Src/DSP/Jit/DSPJitExtOps.cpp
index 0d2d28deb3..5e0bece632 100644
--- a/Source/Core/Core/Src/DSP/Jit/DSPJitExtOps.cpp
+++ b/Source/Core/Core/Src/DSP/Jit/DSPJitExtOps.cpp
@@ -68,7 +68,11 @@ void DSPEmitter::mv(const UDSPInstruction opc)
{
u8 sreg = (opc & 0x3) + DSP_REG_ACL0;
u8 dreg = ((opc >> 2) & 0x3);
- pushExtValueFromReg(dreg + DSP_REG_AXL0, sreg);
+ if (sreg >= DSP_REG_ACM0) {
+ dsp_op_read_reg_and_saturate(sreg, RBX, ZERO);
+ storeIndex = dreg + DSP_REG_AXL0;
+ } else
+ pushExtValueFromReg(dreg + DSP_REG_AXL0, sreg);
}
// S @$arD, $acS.S
@@ -85,7 +89,10 @@ void DSPEmitter::s(const UDSPInstruction opc)
X64Reg tmp1;
gpr.getFreeXReg(tmp1);
- dsp_op_read_reg(sreg, tmp1, ZERO);
+ if (sreg >= DSP_REG_ACM0)
+ dsp_op_read_reg_and_saturate(sreg, tmp1, ZERO);
+ else
+ dsp_op_read_reg(sreg, tmp1, ZERO);
// u16 val = g_dsp.r[src];
dmem_write(tmp1);
@@ -107,7 +114,10 @@ void DSPEmitter::sn(const UDSPInstruction opc)
X64Reg tmp1;
gpr.getFreeXReg(tmp1);
- dsp_op_read_reg(sreg, tmp1, ZERO);
+ if (sreg >= DSP_REG_ACM0)
+ dsp_op_read_reg_and_saturate(sreg, tmp1, ZERO);
+ else
+ dsp_op_read_reg(sreg, tmp1, ZERO);
dmem_write(tmp1);
gpr.putXReg(tmp1);
@@ -177,7 +187,10 @@ void DSPEmitter::ls(const UDSPInstruction opc)
X64Reg tmp1;
gpr.getFreeXReg(tmp1);
- get_acc_m(sreg, tmp1, false);
+ if (sreg >= DSP_REG_ACM0)
+ dsp_op_read_reg_and_saturate(sreg + DSP_REG_ACM0, tmp1, ZERO);
+ else
+ dsp_op_read_reg(sreg + DSP_REG_ACM0, tmp1, ZERO);
dmem_write(tmp1);
gpr.putXReg(tmp1);
@@ -204,7 +217,10 @@ void DSPEmitter::lsn(const UDSPInstruction opc)
X64Reg tmp1;
gpr.getFreeXReg(tmp1);
- get_acc_m(sreg, tmp1, false);
+ if (sreg >= DSP_REG_ACM0)
+ dsp_op_read_reg_and_saturate(sreg + DSP_REG_ACM0, tmp1, ZERO);
+ else
+ dsp_op_read_reg(sreg + DSP_REG_ACM0, tmp1, ZERO);
dmem_write(tmp1);
gpr.putXReg(tmp1);
@@ -230,7 +246,10 @@ void DSPEmitter::lsm(const UDSPInstruction opc)
X64Reg tmp1;
gpr.getFreeXReg(tmp1);
- get_acc_m(sreg, tmp1, false);
+ if (sreg >= DSP_REG_ACM0)
+ dsp_op_read_reg_and_saturate(sreg + DSP_REG_ACM0, tmp1, ZERO);
+ else
+ dsp_op_read_reg(sreg + DSP_REG_ACM0, tmp1, ZERO);
dmem_write(tmp1);
gpr.putXReg(tmp1);
@@ -257,7 +276,10 @@ void DSPEmitter::lsnm(const UDSPInstruction opc)
X64Reg tmp1;
gpr.getFreeXReg(tmp1);
- get_acc_m(sreg, tmp1, false);
+ if (sreg >= DSP_REG_ACM0)
+ dsp_op_read_reg_and_saturate(sreg + DSP_REG_ACM0, tmp1, ZERO);
+ else
+ dsp_op_read_reg(sreg + DSP_REG_ACM0, tmp1, ZERO);
dmem_write(tmp1);
gpr.putXReg(tmp1);
@@ -282,7 +304,10 @@ void DSPEmitter::sl(const UDSPInstruction opc)
X64Reg tmp1;
gpr.getFreeXReg(tmp1);
- get_acc_m(sreg, tmp1, false);
+ if (sreg >= DSP_REG_ACM0)
+ dsp_op_read_reg_and_saturate(sreg + DSP_REG_ACM0, tmp1, ZERO);
+ else
+ dsp_op_read_reg(sreg + DSP_REG_ACM0, tmp1, ZERO);
dmem_write(tmp1);
gpr.putXReg(tmp1);
@@ -308,7 +333,10 @@ void DSPEmitter::sln(const UDSPInstruction opc)
X64Reg tmp1;
gpr.getFreeXReg(tmp1);
- get_acc_m(sreg, tmp1, false);
+ if (sreg >= DSP_REG_ACM0)
+ dsp_op_read_reg_and_saturate(sreg + DSP_REG_ACM0, tmp1, ZERO);
+ else
+ dsp_op_read_reg(sreg + DSP_REG_ACM0, tmp1, ZERO);
dmem_write(tmp1);
gpr.putXReg(tmp1);
@@ -334,7 +362,10 @@ void DSPEmitter::slm(const UDSPInstruction opc)
X64Reg tmp1;
gpr.getFreeXReg(tmp1);
- get_acc_m(sreg, tmp1, false);
+ if (sreg >= DSP_REG_ACM0)
+ dsp_op_read_reg_and_saturate(sreg + DSP_REG_ACM0, tmp1, ZERO);
+ else
+ dsp_op_read_reg(sreg + DSP_REG_ACM0, tmp1, ZERO);
dmem_write(tmp1);
gpr.putXReg(tmp1);
@@ -360,7 +391,10 @@ void DSPEmitter::slnm(const UDSPInstruction opc)
X64Reg tmp1;
gpr.getFreeXReg(tmp1);
- get_acc_m(sreg, tmp1, false);
+ if (sreg >= DSP_REG_ACM0)
+ dsp_op_read_reg_and_saturate(sreg + DSP_REG_ACM0, tmp1, ZERO);
+ else
+ dsp_op_read_reg(sreg + DSP_REG_ACM0, tmp1, ZERO);
dmem_write(tmp1);
gpr.putXReg(tmp1);
diff --git a/Source/Core/Core/Src/DSP/Jit/DSPJitLoadStore.cpp b/Source/Core/Core/Src/DSP/Jit/DSPJitLoadStore.cpp
index f51ea96099..a784e2dd2d 100644
--- a/Source/Core/Core/Src/DSP/Jit/DSPJitLoadStore.cpp
+++ b/Source/Core/Core/Src/DSP/Jit/DSPJitLoadStore.cpp
@@ -39,7 +39,10 @@ void DSPEmitter::srs(const UDSPInstruction opc)
X64Reg tmp1;
gpr.getFreeXReg(tmp1);
- dsp_op_read_reg(reg, tmp1, ZERO);
+ if (reg >= DSP_REG_ACM0)
+ dsp_op_read_reg_and_saturate(reg, tmp1, ZERO);
+ else
+ dsp_op_read_reg(reg, tmp1, ZERO);
dsp_op_read_reg(DSP_REG_CR, RAX, ZERO);
SHL(16, R(EAX), Imm8(8));
OR(16, R(EAX), Imm16(opc & 0xFF));
@@ -77,7 +80,6 @@ void DSPEmitter::lrs(const UDSPInstruction opc)
// 0000 0000 110d dddd
// mmmm mmmm mmmm mmmm
// Move value from data memory pointed by address M to register $D.
-// FIXME: Perform additional operation depending on destination register.
void DSPEmitter::lr(const UDSPInstruction opc)
{
int reg = opc & DSP_REG_MASK;
@@ -91,7 +93,6 @@ void DSPEmitter::lr(const UDSPInstruction opc)
// 0000 0000 111s ssss
// mmmm mmmm mmmm mmmm
// Store value from register $S to a memory pointed by address M.
-// FIXME: Perform additional operation depending on destination register.
void DSPEmitter::sr(const UDSPInstruction opc)
{
u8 reg = opc & DSP_REG_MASK;
@@ -100,7 +101,10 @@ void DSPEmitter::sr(const UDSPInstruction opc)
X64Reg tmp1;
gpr.getFreeXReg(tmp1);
- dsp_op_read_reg(reg, tmp1);
+ if (reg >= DSP_REG_ACM0)
+ dsp_op_read_reg_and_saturate(reg, tmp1);
+ else
+ dsp_op_read_reg(reg, tmp1);
dmem_write_imm(address, tmp1);
gpr.putXReg(tmp1);
@@ -128,7 +132,6 @@ void DSPEmitter::si(const UDSPInstruction opc)
// LRR $D, @$S
// 0001 1000 0ssd dddd
// Move value from data memory pointed by addressing register $S to register $D.
-// FIXME: Perform additional operation depending on destination register.
void DSPEmitter::lrr(const UDSPInstruction opc)
{
u8 sreg = (opc >> 5) & 0x3;
@@ -150,7 +153,6 @@ void DSPEmitter::lrr(const UDSPInstruction opc)
// 0001 1000 1ssd dddd
// Move value from data memory pointed by addressing register $S toregister $D.
// Decrement register $S.
-// FIXME: Perform additional operation depending on destination register.
void DSPEmitter::lrrd(const UDSPInstruction opc)
{
u8 sreg = (opc >> 5) & 0x3;
@@ -173,7 +175,6 @@ void DSPEmitter::lrrd(const UDSPInstruction opc)
// 0001 1001 0ssd dddd
// Move value from data memory pointed by addressing register $S to register $D.
// Increment register $S.
-// FIXME: Perform additional operation depending on destination register.
void DSPEmitter::lrri(const UDSPInstruction opc)
{
u8 sreg = (opc >> 5) & 0x3;
@@ -196,7 +197,6 @@ void DSPEmitter::lrri(const UDSPInstruction opc)
// 0001 1001 1ssd dddd
// Move value from data memory pointed by addressing register $S to register $D.
// Add indexing register $(0x4+S) to register $S.
-// FIXME: Perform additional operation depending on destination register.
void DSPEmitter::lrrn(const UDSPInstruction opc)
{
u8 sreg = (opc >> 5) & 0x3;
@@ -219,7 +219,6 @@ void DSPEmitter::lrrn(const UDSPInstruction opc)
// 0001 1010 0dds ssss
// Store value from source register $S to a memory location pointed by
// addressing register $D.
-// FIXME: Perform additional operation depending on source register.
void DSPEmitter::srr(const UDSPInstruction opc)
{
u8 dreg = (opc >> 5) & 0x3;
@@ -228,7 +227,10 @@ void DSPEmitter::srr(const UDSPInstruction opc)
X64Reg tmp1;
gpr.getFreeXReg(tmp1);
- dsp_op_read_reg(sreg, tmp1);
+ if (sreg >= DSP_REG_ACM0)
+ dsp_op_read_reg_and_saturate(sreg, tmp1);
+ else
+ dsp_op_read_reg(sreg, tmp1);
dsp_op_read_reg(dreg, RAX, ZERO);
dmem_write(tmp1);
@@ -239,7 +241,6 @@ void DSPEmitter::srr(const UDSPInstruction opc)
// 0001 1010 1dds ssss
// Store value from source register $S to a memory location pointed by
// addressing register $D. Decrement register $D.
-// FIXME: Perform additional operation depending on source register.
void DSPEmitter::srrd(const UDSPInstruction opc)
{
u8 dreg = (opc >> 5) & 0x3;
@@ -248,7 +249,10 @@ void DSPEmitter::srrd(const UDSPInstruction opc)
X64Reg tmp1;
gpr.getFreeXReg(tmp1);
- dsp_op_read_reg(sreg, tmp1);
+ if (sreg >= DSP_REG_ACM0)
+ dsp_op_read_reg_and_saturate(sreg, tmp1);
+ else
+ dsp_op_read_reg(sreg, tmp1);
dsp_op_read_reg(dreg, RAX, ZERO);
dmem_write(tmp1);
@@ -261,7 +265,6 @@ void DSPEmitter::srrd(const UDSPInstruction opc)
// 0001 1011 0dds ssss
// Store value from source register $S to a memory location pointed by
// addressing register $D. Increment register $D.
-// FIXME: Perform additional operation depending on source register.
void DSPEmitter::srri(const UDSPInstruction opc)
{
u8 dreg = (opc >> 5) & 0x3;
@@ -270,7 +273,10 @@ void DSPEmitter::srri(const UDSPInstruction opc)
X64Reg tmp1;
gpr.getFreeXReg(tmp1);
- dsp_op_read_reg(sreg, tmp1);
+ if (sreg >= DSP_REG_ACM0)
+ dsp_op_read_reg_and_saturate(sreg, tmp1);
+ else
+ dsp_op_read_reg(sreg, tmp1);
dsp_op_read_reg(dreg, RAX, ZERO);
dmem_write(tmp1);
@@ -283,7 +289,6 @@ void DSPEmitter::srri(const UDSPInstruction opc)
// 0001 1011 1dds ssss
// Store value from source register $S to a memory location pointed by
// addressing register $D. Add DSP_REG_IX0 register to register $D.
-// FIXME: Perform additional operation depending on source register.
void DSPEmitter::srrn(const UDSPInstruction opc)
{
u8 dreg = (opc >> 5) & 0x3;
@@ -292,7 +297,10 @@ void DSPEmitter::srrn(const UDSPInstruction opc)
X64Reg tmp1;
gpr.getFreeXReg(tmp1);
- dsp_op_read_reg(sreg, tmp1);
+ if (sreg >= DSP_REG_ACM0)
+ dsp_op_read_reg_and_saturate(sreg, tmp1);
+ else
+ dsp_op_read_reg(sreg, tmp1);
dsp_op_read_reg(dreg, RAX, ZERO);
dmem_write(tmp1);
@@ -319,7 +327,7 @@ void DSPEmitter::ilrr(const UDSPInstruction opc)
gpr.putXReg(tmp1);
set_acc_m(dreg, R(RAX));
- dsp_conditional_extend_accum(dreg);
+ dsp_conditional_extend_accum(dreg + DSP_REG_ACM0);
}
// ILRRD $acD.m, @$arS
@@ -340,7 +348,7 @@ void DSPEmitter::ilrrd(const UDSPInstruction opc)
gpr.putXReg(tmp1);
set_acc_m(dreg, R(RAX));
- dsp_conditional_extend_accum(dreg);
+ dsp_conditional_extend_accum(dreg + DSP_REG_ACM0);
decrement_addr_reg(reg);
}
@@ -362,7 +370,7 @@ void DSPEmitter::ilrri(const UDSPInstruction opc)
gpr.putXReg(tmp1);
set_acc_m(dreg, R(RAX));
- dsp_conditional_extend_accum(dreg);
+ dsp_conditional_extend_accum(dreg + DSP_REG_ACM0);
increment_addr_reg(reg);
}
@@ -385,7 +393,7 @@ void DSPEmitter::ilrrn(const UDSPInstruction opc)
gpr.putXReg(tmp1);
set_acc_m(dreg, R(RAX));
- dsp_conditional_extend_accum(dreg);
+ dsp_conditional_extend_accum(dreg + DSP_REG_ACM0);
increase_addr_reg(reg, reg);
}
diff --git a/Source/Core/Core/Src/DSP/Jit/DSPJitMisc.cpp b/Source/Core/Core/Src/DSP/Jit/DSPJitMisc.cpp
index c733e0367c..a9c490c157 100644
--- a/Source/Core/Core/Src/DSP/Jit/DSPJitMisc.cpp
+++ b/Source/Core/Core/Src/DSP/Jit/DSPJitMisc.cpp
@@ -239,16 +239,105 @@ void DSPEmitter::dsp_op_read_reg(int reg, Gen::X64Reg host_dreg, DSPJitSignExten
}
}
+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.
-// FIXME: Perform additional operation depending on destination register.
void DSPEmitter::mrr(const UDSPInstruction opc)
{
u8 sreg = opc & 0x1f;
u8 dreg = (opc >> 5) & 0x1f;
- dsp_op_read_reg(sreg, EDX);
+ if (sreg >= DSP_REG_ACM0)
+ dsp_op_read_reg_and_saturate(sreg, EDX);
+ else
+ dsp_op_read_reg(sreg, EDX);
dsp_op_write_reg(dreg, EDX);
dsp_conditional_extend_accum(dreg);
}
@@ -273,7 +362,6 @@ void DSPEmitter::lri(const UDSPInstruction opc)
// LRIS $(0x18+D), #I
// 0000 1ddd iiii iiii
// Load immediate value I (8-bit sign extended) to accumulator register.
-// FIXME: Perform additional operation depending on destination register.
void DSPEmitter::lris(const UDSPInstruction opc)
{
u8 reg = ((opc >> 8) & 0x7) + DSP_REG_AXL0;