From ca67d025e2cfd0d04adad7782c69cf37dcb4358f Mon Sep 17 00:00:00 2001 From: pierre Date: Sat, 12 Mar 2011 17:50:19 +0000 Subject: [PATCH] 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 --- Source/Core/Core/Src/DSP/DSPEmitter.h | 1 + Source/Core/Core/Src/DSP/Jit/DSPJitExtOps.cpp | 56 ++++++++--- .../Core/Core/Src/DSP/Jit/DSPJitLoadStore.cpp | 48 ++++++---- Source/Core/Core/Src/DSP/Jit/DSPJitMisc.cpp | 94 ++++++++++++++++++- 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;