Core/DSPCore: Extended opcode handling fixes

* Make writeToBackLog private to DSPIntExtOps.cpp 
  (JIT variants of 'l and 'ln are disabled and broken as is)
* Make zeroing of the backlog conditional on doing an interpreter fallback and
  do it at a few more places
* Fix selection of cleanup for extended opcodes.
* Fix the DSP unit tests to correctly emit the function prolog/epilog
  (else EBX wouldn't be saved)
* Add a few more DSP unit tests


git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6325 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
pierre
2010-10-31 23:26:18 +00:00
parent 2f2a76b28a
commit 4b9831cdce
8 changed files with 269 additions and 15 deletions

View File

@ -93,6 +93,7 @@ void DSPEmitter::checkExceptions(u32 retval) {
void DSPEmitter::EmitInstruction(UDSPInstruction inst)
{
const DSPOPCTemplate *tinst = GetOpTemplate(inst);
bool ext_is_jit = false;
// Call extended
if (tinst->extended) {
@ -100,15 +101,19 @@ void DSPEmitter::EmitInstruction(UDSPInstruction inst)
if (! extOpTable[inst & 0x7F]->jitFunc) {
// Fall back to interpreter
ABI_CallFunctionC16((void*)extOpTable[inst & 0x7F]->intFunc, inst);
ext_is_jit = false;
} else {
(this->*extOpTable[inst & 0x7F]->jitFunc)(inst);
ext_is_jit = true;
}
} else {
if (!extOpTable[inst & 0xFF]->jitFunc) {
// Fall back to interpreter
ABI_CallFunctionC16((void*)extOpTable[inst & 0xFF]->intFunc, inst);
ext_is_jit = false;
} else {
(this->*extOpTable[inst & 0xFF]->jitFunc)(inst);
ext_is_jit = true;
}
}
}
@ -125,8 +130,10 @@ void DSPEmitter::EmitInstruction(UDSPInstruction inst)
// Backlog
if (tinst->extended) {
if (! extOpTable[inst & 0x7F]->jitFunc) {
ABI_CallFunction((void*)applyWriteBackLog);
if (!ext_is_jit) {
//need to call the online cleanup function because
//the writeBackLog gets populated at runtime
ABI_CallFunction((void*)::applyWriteBackLog);
} else {
popExtValueToReg();
}

View File

@ -64,6 +64,7 @@ public:
void popExtValueToReg();
void pushExtValueFromMem(u16 dreg, u16 sreg);
void zeroWriteBackLog(const UDSPInstruction opc);
// Ext commands
void l(const UDSPInstruction opc);
void ln(const UDSPInstruction opc);

View File

@ -28,6 +28,13 @@
// registers will wrap in odd ways, dictated by the corresponding wrapping
// register, WR0-3.
// Needs comments.
inline static void writeToBackLog(int i, int idx, u16 value)
{
writeBackLog[i] = value;
writeBackLogIdx[i] = idx;
}
namespace DSPInterpreter
{

View File

@ -61,11 +61,4 @@ void nop(const UDSPInstruction opc);
} // end namespace Ext
} // end namespace DSPinterpeter
// Needs comments.
inline void writeToBackLog(int i, int idx, u16 value)
{
writeBackLog[i] = value;
writeBackLogIdx[i] = idx;
}
#endif

View File

@ -19,8 +19,6 @@
#include "x64Emitter.h"
#include "ABI.h"
#include "../DSPIntExtOps.h" // remove when getting rid of writebacklog
// See docs in the interpeter
using namespace Gen;
// DR $arR
@ -94,6 +92,7 @@ void DSPEmitter::l(const UDSPInstruction opc)
if ((dreg >= DSP_REG_ACM0) && (g_dsp.r[DSP_REG_SR] & SR_40_MODE_BIT))
{
/*
u16 val;
ext_dmem_read(sreg);
MOV(16, M(&val), R(EAX));
@ -102,6 +101,7 @@ void DSPEmitter::l(const UDSPInstruction opc)
writeToBackLog(1, dreg, val);
writeToBackLog(2, dreg - DSP_REG_ACM0 + DSP_REG_ACL0, 0);
increment_addr_reg(sreg);
*/
}
else
{
@ -127,6 +127,7 @@ void DSPEmitter::ln(const UDSPInstruction opc)
if ((dreg >= DSP_REG_ACM0) && (g_dsp.r[DSP_REG_SR] & SR_40_MODE_BIT))
{
/*
u16 val;
ext_dmem_read(sreg);
MOV(16, M(&val), R(EAX));
@ -134,6 +135,7 @@ void DSPEmitter::ln(const UDSPInstruction opc)
writeToBackLog(1, dreg, val);
writeToBackLog(2, dreg - DSP_REG_ACM0 + DSP_REG_ACL0, 0);
increase_addr_reg(sreg);
*/
}
else
{
@ -700,8 +702,8 @@ void DSPEmitter::pushExtValueFromReg(u16 dreg, u16 sreg) {
void DSPEmitter::pushExtValueFromMem(u16 dreg, u16 sreg) {
ext_dmem_read(sreg);
MOV(16, R(EBX), R(EAX));
MOVZX(32, 16, EBX, R(EAX));
storeIndex = dreg;
}
@ -726,3 +728,26 @@ void DSPEmitter::popExtValueToReg() {
// TODO handle commands such as 'l
}
// This function is being called in the main op after all input regs were read
// and before it writes into any regs. This way we can always use bitwise or to
// apply the ext command output, because if the main op didn't change the value
// then 0 | ext output = ext output and if it did then bitwise or is still the
// right thing to do
//this is only needed as long as we do fallback for ext ops
void DSPEmitter::zeroWriteBackLog(const UDSPInstruction opc)
{
const DSPOPCTemplate *tinst = GetOpTemplate(opc);
// Call extended
if (!tinst->extended)
return;
if ((opc >> 12) == 0x3) {
if (! extOpTable[opc & 0x7F]->jitFunc)
ABI_CallFunction((void*)::zeroWriteBackLog);
} else {
if (! extOpTable[opc & 0xFF]->jitFunc)
ABI_CallFunction((void*)::zeroWriteBackLog);
}
return;
}

View File

@ -88,6 +88,7 @@ void DSPEmitter::nx(const UDSPInstruction opc)
void DSPEmitter::dar(const UDSPInstruction opc)
{
// g_dsp.r[opc & 0x3] = dsp_decrement_addr_reg(opc & 0x3);
zeroWriteBackLog(opc);
decrement_addr_reg(opc & 0x3);
}
@ -98,6 +99,7 @@ void DSPEmitter::dar(const UDSPInstruction opc)
void DSPEmitter::iar(const UDSPInstruction opc)
{
// g_dsp.r[opc & 0x3] = dsp_increment_addr_reg(opc & 0x3);
zeroWriteBackLog(opc);
increment_addr_reg(opc & 0x3);
}
@ -109,6 +111,7 @@ void DSPEmitter::subarn(const UDSPInstruction opc)
{
// u8 dreg = opc & 0x3;
// g_dsp.r[dreg] = dsp_decrease_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + dreg]);
zeroWriteBackLog(opc);
decrease_addr_reg(opc & 0x3);
}
@ -123,6 +126,7 @@ void DSPEmitter::addarn(const UDSPInstruction opc)
// g_dsp.r[dreg] = dsp_increase_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg]);
// From looking around it is always called with the matching index register
zeroWriteBackLog(opc);
increase_addr_reg(opc & 0x3);
}
@ -180,7 +184,7 @@ void DSPEmitter::sbset(const UDSPInstruction opc)
// but it's harder to know exactly what effect they have.
void DSPEmitter::srbith(const UDSPInstruction opc)
{
ABI_CallFunction((void *)zeroWriteBackLog);
zeroWriteBackLog(opc);
switch ((opc >> 8) & 0xf)
{
// M0/M2 change the multiplier mode (it can multiply by 2 for free).