DSPLLE: Some cleanup. Possibly very small speed increase.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5535 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
hrydgard
2010-05-29 18:22:50 +00:00
parent 926f96daf0
commit 659d5705c9
5 changed files with 113 additions and 96 deletions

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="Windows-1252"?> <?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject <VisualStudioProject
ProjectType="Visual C++" ProjectType="Visual C++"
Version="9.00" Version="9,00"
Name="DSPCore" Name="DSPCore"
ProjectGUID="{838A89A3-3AA0-4A45-ACBE-3D1E0980C2ED}" ProjectGUID="{838A89A3-3AA0-4A45-ACBE-3D1E0980C2ED}"
RootNamespace="DSPCore" RootNamespace="DSPCore"
@ -447,21 +447,29 @@
</File> </File>
</Filter> </Filter>
<Filter <Filter
Name="JIT" Name="JIT"
> >
<File <File
RelativePath=".\Src\Jit\DSPJitExtOps.cpp" RelativePath=".\Src\DSPEmitter.cpp"
> >
</File> </File>
<File <File
RelativePath=".\Src\Jit\DSPJitUtil.cpp" RelativePath=".\Src\DSPEmitter.h"
> >
</File> </File>
<File <File
RelativePath=".\Src\Jit\DSPJitMisc.cpp" RelativePath=".\Src\Jit\DSPJitExtOps.cpp"
> >
</File> </File>
</Filter> <File
RelativePath=".\Src\Jit\DSPJitMisc.cpp"
>
</File>
<File
RelativePath=".\Src\Jit\DSPJitUtil.cpp"
>
</File>
</Filter>
<File <File
RelativePath=".\Src\assemble.cpp" RelativePath=".\Src\assemble.cpp"
> >
@ -511,12 +519,12 @@
> >
</File> </File>
<File <File
RelativePath=".\Src\DSPCore.cpp" RelativePath=".\Src\DSPCommon.h"
> >
</File> </File>
<File <File
RelativePath=".\Src\DSPCommon.h" RelativePath=".\Src\DSPCore.cpp"
> >
</File> </File>
<File <File
RelativePath=".\Src\DSPCore.h" RelativePath=".\Src\DSPCore.h"
@ -542,14 +550,6 @@
RelativePath=".\Src\DSPInterpreter.h" RelativePath=".\Src\DSPInterpreter.h"
> >
</File> </File>
<File
RelativePath=".\Src\DSPEmitter.cpp"
>
</File>
<File
RelativePath=".\Src\DSPEmitter.h"
>
</File>
<File <File
RelativePath=".\Src\DSPMemoryMap.cpp" RelativePath=".\Src\DSPMemoryMap.cpp"
> >

View File

@ -95,7 +95,7 @@ void AnalyzeRange(int start_addr, int end_addr)
continue; continue;
} }
code_flags[addr] |= CODE_START_OF_INST; code_flags[addr] |= CODE_START_OF_INST;
// Look for loops. (this is not used atm) // Look for loops.
if ((inst & 0xffe0) == 0x0060 || (inst & 0xff00) == 0x1100) { if ((inst & 0xffe0) == 0x0060 || (inst & 0xff00) == 0x1100) {
// BLOOP, BLOOPI // BLOOP, BLOOPI
u16 loop_end = dsp_imem_read(addr + 1); u16 loop_end = dsp_imem_read(addr + 1);

View File

@ -25,7 +25,7 @@
#include "x64Emitter.h" #include "x64Emitter.h"
#include "ABI.h" #include "ABI.h"
#define BLOCK_SIZE 250 #define MAX_BLOCK_SIZE 250
using namespace Gen; using namespace Gen;
@ -36,33 +36,30 @@ DSPEmitter::DSPEmitter() : storeIndex(-1)
AllocCodeSpace(COMPILED_CODE_SIZE); AllocCodeSpace(COMPILED_CODE_SIZE);
blocks = new CompiledCode[MAX_BLOCKS]; blocks = new CompiledCode[MAX_BLOCKS];
endBlock = new bool[MAX_BLOCKS]; blockSize = new u16[0x10000];
ClearIRAM();
for(int i = 0x0000; i < MAX_BLOCKS; i++)
{
blocks[i] = CompileCurrent;
blockSize[i] = 0;
endBlock[i] = false;
}
compileSR = 0; compileSR = 0;
compileSR |= SR_INT_ENABLE; compileSR |= SR_INT_ENABLE;
compileSR |= SR_EXT_INT_ENABLE; compileSR |= SR_EXT_INT_ENABLE;
CompileDispatcher();
} }
DSPEmitter::~DSPEmitter() DSPEmitter::~DSPEmitter()
{ {
delete[] blocks; delete[] blocks;
delete[] endBlock; delete[] blockSize;
FreeCodeSpace(); FreeCodeSpace();
} }
void DSPEmitter::ClearIRAM() { void DSPEmitter::ClearIRAM() {
// TODO: Does not clear codespace // ClearCodeSpace();
for(int i = 0x0000; i < 0x1000; i++) for(int i = 0x0000; i < 0x1000; i++)
{ {
blocks[i] = CompileCurrent; blocks[i] = NULL;
blockSize[i] = 0; blockSize[i] = 0;
endBlock[i] = false;
} }
} }
@ -100,7 +97,7 @@ void DSPEmitter::checkExceptions() {
SetJumpTarget(skipCheck); SetJumpTarget(skipCheck);
} }
void DSPEmitter::WriteCallInterpreter(UDSPInstruction inst) void DSPEmitter::EmitInstruction(UDSPInstruction inst)
{ {
const DSPOPCTemplate *tinst = GetOpTemplate(inst); const DSPOPCTemplate *tinst = GetOpTemplate(inst);
@ -108,12 +105,14 @@ void DSPEmitter::WriteCallInterpreter(UDSPInstruction inst)
if (tinst->extended) { if (tinst->extended) {
if ((inst >> 12) == 0x3) { if ((inst >> 12) == 0x3) {
if (! extOpTable[inst & 0x7F]->jitFunc) { if (! extOpTable[inst & 0x7F]->jitFunc) {
// Fall back to interpreter
ABI_CallFunctionC16((void*)extOpTable[inst & 0x7F]->intFunc, inst); ABI_CallFunctionC16((void*)extOpTable[inst & 0x7F]->intFunc, inst);
} else { } else {
(this->*extOpTable[inst & 0x7F]->jitFunc)(inst); (this->*extOpTable[inst & 0x7F]->jitFunc)(inst);
} }
} else { } else {
if (!extOpTable[inst & 0xFF]->jitFunc) { if (!extOpTable[inst & 0xFF]->jitFunc) {
// Fall back to interpreter
ABI_CallFunctionC16((void*)extOpTable[inst & 0xFF]->intFunc, inst); ABI_CallFunctionC16((void*)extOpTable[inst & 0xFF]->intFunc, inst);
} else { } else {
(this->*extOpTable[inst & 0xFF]->jitFunc)(inst); (this->*extOpTable[inst & 0xFF]->jitFunc)(inst);
@ -122,10 +121,14 @@ void DSPEmitter::WriteCallInterpreter(UDSPInstruction inst)
} }
// Main instruction // Main instruction
if (!opTable[inst]->jitFunc) if (!opTable[inst]->jitFunc) {
// Fall back to interpreter
ABI_CallFunctionC16((void*)opTable[inst]->intFunc, inst); ABI_CallFunctionC16((void*)opTable[inst]->intFunc, inst);
}
else else
{
(this->*opTable[inst]->jitFunc)(inst); (this->*opTable[inst]->jitFunc)(inst);
}
// Backlog // Backlog
if (tinst->extended) { if (tinst->extended) {
@ -144,7 +147,7 @@ void DSPEmitter::unknown_instruction(UDSPInstruction inst)
void DSPEmitter::Default(UDSPInstruction _inst) void DSPEmitter::Default(UDSPInstruction _inst)
{ {
WriteCallInterpreter(_inst); EmitInstruction(_inst);
} }
const u8 *DSPEmitter::Compile(int start_addr) { const u8 *DSPEmitter::Compile(int start_addr) {
@ -155,52 +158,50 @@ const u8 *DSPEmitter::Compile(int start_addr) {
int addr = start_addr; int addr = start_addr;
checkExceptions(); checkExceptions();
while (addr < start_addr + BLOCK_SIZE) while (addr < start_addr + MAX_BLOCK_SIZE)
{ {
UDSPInstruction inst = dsp_imem_read(addr); UDSPInstruction inst = dsp_imem_read(addr);
const DSPOPCTemplate *opcode = GetOpTemplate(inst); const DSPOPCTemplate *opcode = GetOpTemplate(inst);
// Increment PC // Increment PC - we shouldn't need to do this for every instruction. only for branches and end of block.
ADD(16, M(&(g_dsp.pc)), Imm16(1)); ADD(16, M(&(g_dsp.pc)), Imm16(1));
WriteCallInterpreter(inst); EmitInstruction(inst);
blockSize[start_addr]++; // Handle loop condition, only if current instruction was flagged as a loop destination
// by the analyzer. COMMENTED OUT - this breaks Zelda TP. Bah.
// Handle loop condition. Change to TEST // if (DSPAnalyzer::code_flags[addr] & DSPAnalyzer::CODE_LOOP_END)
MOVZX(32, 16, EAX, M(&(g_dsp.r[DSP_REG_ST2]))); {
CMP(32, R(EAX), Imm32(0)); // TODO: Change to TEST for some reason (who added this comment?)
FixupBranch rLoopAddressExit = J_CC(CC_LE); MOVZX(32, 16, EAX, M(&(g_dsp.r[DSP_REG_ST2])));
CMP(32, R(EAX), Imm32(0));
FixupBranch rLoopAddressExit = J_CC(CC_LE);
MOVZX(32, 16, EAX, M(&(g_dsp.r[DSP_REG_ST3]))); MOVZX(32, 16, EAX, M(&(g_dsp.r[DSP_REG_ST3])));
CMP(32, R(EAX), Imm32(0)); CMP(32, R(EAX), Imm32(0));
FixupBranch rLoopCounterExit = J_CC(CC_LE); FixupBranch rLoopCounterExit = J_CC(CC_LE);
// These functions branch and therefore only need to be called in the // These functions branch and therefore only need to be called in the
// end of each block and in this order // end of each block and in this order
ABI_CallFunction((void *)&DSPInterpreter::HandleLoop); ABI_CallFunction((void *)&DSPInterpreter::HandleLoop);
// ABI_RestoreStack(0); // ABI_RestoreStack(0);
ABI_PopAllCalleeSavedRegsAndAdjustStack(); ABI_PopAllCalleeSavedRegsAndAdjustStack();
RET(); RET();
SetJumpTarget(rLoopAddressExit); SetJumpTarget(rLoopAddressExit);
SetJumpTarget(rLoopCounterExit); SetJumpTarget(rLoopCounterExit);
// End the block where the loop ends
if ((inst & 0xffe0) == 0x0060 || (inst & 0xff00) == 0x1100) {
// BLOOP, BLOOPI
endBlock[dsp_imem_read(addr + 1)] = true;
} else if ((inst & 0xffe0) == 0x0040 || (inst & 0xff00) == 0x1000) {
// LOOP, LOOPI
endBlock[addr + 1] = true;
} }
if (opcode->branch || endBlock[addr] // End the block if we're at a loop end.
|| (DSPAnalyzer::code_flags[addr] & DSPAnalyzer::CODE_IDLE_SKIP)) { if (opcode->branch ||
(DSPAnalyzer::code_flags[addr] & DSPAnalyzer::CODE_LOOP_END) ||
(DSPAnalyzer::code_flags[addr] & DSPAnalyzer::CODE_IDLE_SKIP)) {
break; break;
} }
addr += opcode->size; addr += opcode->size;
blockSize[start_addr]++;
} }
// ABI_RestoreStack(0); // ABI_RestoreStack(0);
@ -212,40 +213,50 @@ const u8 *DSPEmitter::Compile(int start_addr) {
return entryPoint; return entryPoint;
} }
void STACKALIGN DSPEmitter::CompileDispatcher()
{
// TODO
}
// Don't use the % operator in the inner loop. It's slow.
void STACKALIGN DSPEmitter::RunBlock(int cycles) void STACKALIGN DSPEmitter::RunBlock(int cycles)
{ {
// How does this variable work?
static int idleskip = 0; static int idleskip = 0;
// Trigger an external interrupt at the start of the cycle
u16 block_cycles = 501;
#define BURST_LENGTH 512 // Must be a power of two
u16 block_cycles = BURST_LENGTH + 1;
// Trigger an external interrupt at the start of the cycle
while (!(g_dsp.cr & CR_HALT)) while (!(g_dsp.cr & CR_HALT))
{ {
if (block_cycles > 500) if (block_cycles > BURST_LENGTH)
{ {
block_cycles = 0; block_cycles = 0;
} }
// Compile the block if needed // Compile the block if needed
if (blocks[g_dsp.pc] == CompileCurrent) if (!blocks[g_dsp.pc])
{ {
blockSize[g_dsp.pc] = 0; blockSize[g_dsp.pc] = 0;
blocks[g_dsp.pc](); CompileCurrent();
} }
// Execute the block if we have enough cycles // Execute the block if we have enough cycles
if (cycles > blockSize[g_dsp.pc]) if (cycles > blockSize[g_dsp.pc])
{ {
u16 start_addr = g_dsp.pc; u16 start_addr = g_dsp.pc;
if (idleskip % 100 > 95 && (DSPAnalyzer::code_flags[g_dsp.pc] & DSPAnalyzer::CODE_IDLE_SKIP)) {
// 5%. Not sure where the rationale originally came from.
if (((idleskip & 127) > 121) &&
(DSPAnalyzer::code_flags[g_dsp.pc] & DSPAnalyzer::CODE_IDLE_SKIP)) {
block_cycles = 0; block_cycles = 0;
} else } else {
blocks[g_dsp.pc](); blocks[g_dsp.pc]();
}
idleskip++; idleskip++;
if ((idleskip & (BURST_LENGTH - 1)) == 0)
if (idleskip % 500 == 0)
idleskip = 0; idleskip = 0;
block_cycles += blockSize[start_addr]; block_cycles += blockSize[start_addr];
cycles -= blockSize[start_addr]; cycles -= blockSize[start_addr];
} }

View File

@ -29,27 +29,19 @@ typedef void (*CompiledCode)();
class DSPEmitter : public Gen::XCodeBlock class DSPEmitter : public Gen::XCodeBlock
{ {
CompiledCode *blocks;
u16 blockSize[0x10000];
bool *endBlock;
u16 compileSR;
// The index of the last stored ext value (compile time).
int storeIndex;
DISALLOW_COPY_AND_ASSIGN(DSPEmitter);
void ToMask(Gen::X64Reg value_reg = Gen::EDI, Gen::X64Reg temp_reg = Gen::ESI);
public: public:
DSPEmitter(); DSPEmitter();
~DSPEmitter(); ~DSPEmitter();
const u8 *m_compiledCode; const u8 *m_compiledCode;
void WriteCallInterpreter(UDSPInstruction inst); void EmitInstruction(UDSPInstruction inst);
void unknown_instruction(UDSPInstruction inst); void unknown_instruction(UDSPInstruction inst);
void Default(UDSPInstruction _inst); void Default(UDSPInstruction _inst);
void ClearIRAM(); void ClearIRAM();
void CompileDispatcher();
const u8 *Compile(int start_addr); const u8 *Compile(int start_addr);
void STACKALIGN RunBlock(int cycles); void STACKALIGN RunBlock(int cycles);
@ -103,6 +95,20 @@ public:
void sbclr(const UDSPInstruction opc); void sbclr(const UDSPInstruction opc);
void sbset(const UDSPInstruction opc); void sbset(const UDSPInstruction opc);
void srbith(const UDSPInstruction opc); void srbith(const UDSPInstruction opc);
private:
CompiledCode *blocks;
u16 *blockSize;
u16 compileSR;
u8 *dispatcher;
// The index of the last stored ext value (compile time).
int storeIndex;
DISALLOW_COPY_AND_ASSIGN(DSPEmitter);
void ToMask(Gen::X64Reg value_reg = Gen::EDI, Gen::X64Reg temp_reg = Gen::ESI);
}; };

View File

@ -41,7 +41,7 @@ SDSP DSPJitTester::RunJit(SDSP dsp_settings)
ResetJit(); ResetJit();
memcpy(&g_dsp, &dsp_settings, sizeof(SDSP)); memcpy(&g_dsp, &dsp_settings, sizeof(SDSP));
const u8* code = jit.GetCodePtr(); const u8* code = jit.GetCodePtr();
jit.WriteCallInterpreter(instruction); jit.EmitInstruction(instruction);
jit.RET(); jit.RET();
((void(*)())code)(); ((void(*)())code)();
@ -113,8 +113,8 @@ void DSPJitTester::DumpJittedCode()
{ {
ResetJit(); ResetJit();
const u8* code = jit.GetCodePtr(); const u8* code = jit.GetCodePtr();
jit.WriteCallInterpreter(instruction); jit.EmitInstruction(instruction);
int code_size = jit.GetCodePtr() - code; size_t code_size = jit.GetCodePtr() - code;
printf("%s emitted: ", instruction_name); printf("%s emitted: ", instruction_name);
for (int i = 0; i < code_size; i++) for (int i = 0; i < code_size; i++)