Merge pull request #9348 from lioncash/dsp-deglobal
DSP: Eliminate most global state
This commit is contained in:
commit
3f68aceaca
|
@ -1096,6 +1096,13 @@ public:
|
||||||
ABI_CallFunction(func);
|
ABI_CallFunction(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename FunctionPointer>
|
||||||
|
void ABI_CallFunctionP(FunctionPointer func, const void* param1)
|
||||||
|
{
|
||||||
|
MOV(64, R(ABI_PARAM1), Imm64(reinterpret_cast<u64>(param1)));
|
||||||
|
ABI_CallFunction(func);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename FunctionPointer>
|
template <typename FunctionPointer>
|
||||||
void ABI_CallFunctionPC(FunctionPointer func, const void* param1, u32 param2)
|
void ABI_CallFunctionPC(FunctionPointer func, const void* param1, u32 param2)
|
||||||
{
|
{
|
||||||
|
@ -1122,6 +1129,15 @@ public:
|
||||||
ABI_CallFunction(func);
|
ABI_CallFunction(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pass a pointer and register as a parameter.
|
||||||
|
template <typename FunctionPointer>
|
||||||
|
void ABI_CallFunctionPR(FunctionPointer func, const void* ptr, X64Reg reg1)
|
||||||
|
{
|
||||||
|
MOV(64, R(ABI_PARAM2), R(reg1));
|
||||||
|
MOV(64, R(ABI_PARAM1), Imm64(reinterpret_cast<u64>(ptr)));
|
||||||
|
ABI_CallFunction(func);
|
||||||
|
}
|
||||||
|
|
||||||
// Pass two registers as parameters.
|
// Pass two registers as parameters.
|
||||||
template <typename FunctionPointer>
|
template <typename FunctionPointer>
|
||||||
void ABI_CallFunctionRR(FunctionPointer func, X64Reg reg1, X64Reg reg2)
|
void ABI_CallFunctionRR(FunctionPointer func, X64Reg reg1, X64Reg reg2)
|
||||||
|
@ -1130,6 +1146,15 @@ public:
|
||||||
ABI_CallFunction(func);
|
ABI_CallFunction(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pass a pointer and two registers as parameters.
|
||||||
|
template <typename FunctionPointer>
|
||||||
|
void ABI_CallFunctionPRR(FunctionPointer func, const void* ptr, X64Reg reg1, X64Reg reg2)
|
||||||
|
{
|
||||||
|
MOVTwo(64, ABI_PARAM2, reg1, 0, ABI_PARAM3, reg2);
|
||||||
|
MOV(64, R(ABI_PARAM1), Imm64(reinterpret_cast<u64>(ptr)));
|
||||||
|
ABI_CallFunction(func);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename FunctionPointer>
|
template <typename FunctionPointer>
|
||||||
void ABI_CallFunctionAC(int bits, FunctionPointer func, const Gen::OpArg& arg1, u32 param2)
|
void ABI_CallFunctionAC(int bits, FunctionPointer func, const Gen::OpArg& arg1, u32 param2)
|
||||||
{
|
{
|
||||||
|
|
|
@ -111,23 +111,18 @@ add_library(core
|
||||||
DSP/DSPDisassembler.cpp
|
DSP/DSPDisassembler.cpp
|
||||||
DSP/DSPDisassembler.h
|
DSP/DSPDisassembler.h
|
||||||
DSP/DSPHWInterface.cpp
|
DSP/DSPHWInterface.cpp
|
||||||
DSP/DSPHWInterface.h
|
|
||||||
DSP/DSPMemoryMap.cpp
|
DSP/DSPMemoryMap.cpp
|
||||||
DSP/DSPMemoryMap.h
|
|
||||||
DSP/DSPStacks.cpp
|
DSP/DSPStacks.cpp
|
||||||
DSP/DSPStacks.h
|
|
||||||
DSP/DSPTables.cpp
|
DSP/DSPTables.cpp
|
||||||
DSP/DSPTables.h
|
DSP/DSPTables.h
|
||||||
DSP/LabelMap.cpp
|
DSP/LabelMap.cpp
|
||||||
DSP/LabelMap.h
|
DSP/LabelMap.h
|
||||||
DSP/Interpreter/DSPIntArithmetic.cpp
|
DSP/Interpreter/DSPIntArithmetic.cpp
|
||||||
DSP/Interpreter/DSPIntBranch.cpp
|
DSP/Interpreter/DSPIntBranch.cpp
|
||||||
DSP/Interpreter/DSPIntCCUtil.cpp
|
|
||||||
DSP/Interpreter/DSPIntCCUtil.h
|
DSP/Interpreter/DSPIntCCUtil.h
|
||||||
DSP/Interpreter/DSPInterpreter.cpp
|
DSP/Interpreter/DSPInterpreter.cpp
|
||||||
DSP/Interpreter/DSPInterpreter.h
|
DSP/Interpreter/DSPInterpreter.h
|
||||||
DSP/Interpreter/DSPIntExtOps.cpp
|
DSP/Interpreter/DSPIntExtOps.cpp
|
||||||
DSP/Interpreter/DSPIntExtOps.h
|
|
||||||
DSP/Interpreter/DSPIntLoadStore.cpp
|
DSP/Interpreter/DSPIntLoadStore.cpp
|
||||||
DSP/Interpreter/DSPIntMisc.cpp
|
DSP/Interpreter/DSPIntMisc.cpp
|
||||||
DSP/Interpreter/DSPIntMultiplier.cpp
|
DSP/Interpreter/DSPIntMultiplier.cpp
|
||||||
|
@ -186,8 +181,6 @@ add_library(core
|
||||||
HW/DSPHLE/MailHandler.h
|
HW/DSPHLE/MailHandler.h
|
||||||
HW/DSPHLE/DSPHLE.cpp
|
HW/DSPHLE/DSPHLE.cpp
|
||||||
HW/DSPHLE/DSPHLE.h
|
HW/DSPHLE/DSPHLE.h
|
||||||
HW/DSPLLE/DSPDebugInterface.cpp
|
|
||||||
HW/DSPLLE/DSPDebugInterface.h
|
|
||||||
HW/DSPLLE/DSPHost.cpp
|
HW/DSPLLE/DSPHost.cpp
|
||||||
HW/DSPLLE/DSPSymbols.cpp
|
HW/DSPLLE/DSPSymbols.cpp
|
||||||
HW/DSPLLE/DSPSymbols.h
|
HW/DSPLLE/DSPSymbols.h
|
||||||
|
|
|
@ -58,7 +58,6 @@
|
||||||
<ClCompile Include="DSP\DSPTables.cpp" />
|
<ClCompile Include="DSP\DSPTables.cpp" />
|
||||||
<ClCompile Include="DSP\Interpreter\DSPIntArithmetic.cpp" />
|
<ClCompile Include="DSP\Interpreter\DSPIntArithmetic.cpp" />
|
||||||
<ClCompile Include="DSP\Interpreter\DSPIntBranch.cpp" />
|
<ClCompile Include="DSP\Interpreter\DSPIntBranch.cpp" />
|
||||||
<ClCompile Include="DSP\Interpreter\DSPIntCCUtil.cpp" />
|
|
||||||
<ClCompile Include="DSP\Interpreter\DSPInterpreter.cpp" />
|
<ClCompile Include="DSP\Interpreter\DSPInterpreter.cpp" />
|
||||||
<ClCompile Include="DSP\Interpreter\DSPIntExtOps.cpp" />
|
<ClCompile Include="DSP\Interpreter\DSPIntExtOps.cpp" />
|
||||||
<ClCompile Include="DSP\Interpreter\DSPIntLoadStore.cpp" />
|
<ClCompile Include="DSP\Interpreter\DSPIntLoadStore.cpp" />
|
||||||
|
@ -107,7 +106,6 @@
|
||||||
<ClCompile Include="HW\DSPHLE\UCodes\INIT.cpp" />
|
<ClCompile Include="HW\DSPHLE\UCodes\INIT.cpp" />
|
||||||
<ClCompile Include="HW\DSPHLE\UCodes\ROM.cpp" />
|
<ClCompile Include="HW\DSPHLE\UCodes\ROM.cpp" />
|
||||||
<ClCompile Include="HW\DSPHLE\UCodes\Zelda.cpp" />
|
<ClCompile Include="HW\DSPHLE\UCodes\Zelda.cpp" />
|
||||||
<ClCompile Include="HW\DSPLLE\DSPDebugInterface.cpp" />
|
|
||||||
<ClCompile Include="HW\DSPLLE\DSPHost.cpp" />
|
<ClCompile Include="HW\DSPLLE\DSPHost.cpp" />
|
||||||
<ClCompile Include="HW\DSPLLE\DSPLLE.cpp" />
|
<ClCompile Include="HW\DSPLLE\DSPLLE.cpp" />
|
||||||
<ClCompile Include="HW\DSPLLE\DSPLLEGlobals.cpp" />
|
<ClCompile Include="HW\DSPLLE\DSPLLEGlobals.cpp" />
|
||||||
|
@ -420,13 +418,9 @@
|
||||||
<ClInclude Include="DSP\DSPCore.h" />
|
<ClInclude Include="DSP\DSPCore.h" />
|
||||||
<ClInclude Include="DSP\DSPDisassembler.h" />
|
<ClInclude Include="DSP\DSPDisassembler.h" />
|
||||||
<ClInclude Include="DSP\DSPHost.h" />
|
<ClInclude Include="DSP\DSPHost.h" />
|
||||||
<ClInclude Include="DSP\DSPHWInterface.h" />
|
|
||||||
<ClInclude Include="DSP\DSPMemoryMap.h" />
|
|
||||||
<ClInclude Include="DSP\DSPStacks.h" />
|
|
||||||
<ClInclude Include="DSP\DSPTables.h" />
|
<ClInclude Include="DSP\DSPTables.h" />
|
||||||
<ClInclude Include="DSP\Interpreter\DSPIntCCUtil.h" />
|
<ClInclude Include="DSP\Interpreter\DSPIntCCUtil.h" />
|
||||||
<ClInclude Include="DSP\Interpreter\DSPInterpreter.h" />
|
<ClInclude Include="DSP\Interpreter\DSPInterpreter.h" />
|
||||||
<ClInclude Include="DSP\Interpreter\DSPIntExtOps.h" />
|
|
||||||
<ClInclude Include="DSP\Interpreter\DSPIntTables.h" />
|
<ClInclude Include="DSP\Interpreter\DSPIntTables.h" />
|
||||||
<ClInclude Include="DSP\Interpreter\DSPIntUtil.h" />
|
<ClInclude Include="DSP\Interpreter\DSPIntUtil.h" />
|
||||||
<ClInclude Include="DSP\Jit\DSPEmitterBase.h" />
|
<ClInclude Include="DSP\Jit\DSPEmitterBase.h" />
|
||||||
|
@ -466,7 +460,6 @@
|
||||||
<ClInclude Include="HW\DSPHLE\UCodes\INIT.h" />
|
<ClInclude Include="HW\DSPHLE\UCodes\INIT.h" />
|
||||||
<ClInclude Include="HW\DSPHLE\UCodes\ROM.h" />
|
<ClInclude Include="HW\DSPHLE\UCodes\ROM.h" />
|
||||||
<ClInclude Include="HW\DSPHLE\UCodes\Zelda.h" />
|
<ClInclude Include="HW\DSPHLE\UCodes\Zelda.h" />
|
||||||
<ClInclude Include="HW\DSPLLE\DSPDebugInterface.h" />
|
|
||||||
<ClInclude Include="HW\DSPLLE\DSPLLE.h" />
|
<ClInclude Include="HW\DSPLLE\DSPLLE.h" />
|
||||||
<ClInclude Include="HW\DSPLLE\DSPLLEGlobals.h" />
|
<ClInclude Include="HW\DSPLLE\DSPLLEGlobals.h" />
|
||||||
<ClInclude Include="HW\DSPLLE\DSPSymbols.h" />
|
<ClInclude Include="HW\DSPLLE\DSPSymbols.h" />
|
||||||
|
|
|
@ -233,9 +233,6 @@
|
||||||
<ClCompile Include="DSP\Interpreter\DSPIntBranch.cpp">
|
<ClCompile Include="DSP\Interpreter\DSPIntBranch.cpp">
|
||||||
<Filter>DSPCore\Interpreter</Filter>
|
<Filter>DSPCore\Interpreter</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="DSP\Interpreter\DSPIntCCUtil.cpp">
|
|
||||||
<Filter>DSPCore\Interpreter</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="DSP\Interpreter\DSPInterpreter.cpp">
|
<ClCompile Include="DSP\Interpreter\DSPInterpreter.cpp">
|
||||||
<Filter>DSPCore\Interpreter</Filter>
|
<Filter>DSPCore\Interpreter</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -416,9 +413,6 @@
|
||||||
<ClCompile Include="HW\DSPHLE\MailHandler.cpp">
|
<ClCompile Include="HW\DSPHLE\MailHandler.cpp">
|
||||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE</Filter>
|
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="HW\DSPLLE\DSPDebugInterface.cpp">
|
|
||||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\LLE</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="HW\DSPLLE\DSPHost.cpp">
|
<ClCompile Include="HW\DSPLLE\DSPHost.cpp">
|
||||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\LLE</Filter>
|
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\LLE</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -1070,9 +1064,6 @@
|
||||||
<ClInclude Include="DSP\Interpreter\DSPInterpreter.h">
|
<ClInclude Include="DSP\Interpreter\DSPInterpreter.h">
|
||||||
<Filter>DSPCore\Interpreter</Filter>
|
<Filter>DSPCore\Interpreter</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="DSP\Interpreter\DSPIntExtOps.h">
|
|
||||||
<Filter>DSPCore\Interpreter</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="DSP\Interpreter\DSPIntTables.h">
|
<ClInclude Include="DSP\Interpreter\DSPIntTables.h">
|
||||||
<Filter>DSPCore\Interpreter</Filter>
|
<Filter>DSPCore\Interpreter</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -1199,9 +1190,6 @@
|
||||||
<ClInclude Include="HW\DSPHLE\MailHandler.h">
|
<ClInclude Include="HW\DSPHLE\MailHandler.h">
|
||||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE</Filter>
|
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="HW\DSPLLE\DSPDebugInterface.h">
|
|
||||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\LLE</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="DSP\DSPHost.h">
|
<ClInclude Include="DSP\DSPHost.h">
|
||||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\LLE</Filter>
|
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\LLE</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -1388,15 +1376,6 @@
|
||||||
<ClInclude Include="DSPEmulator.h">
|
<ClInclude Include="DSPEmulator.h">
|
||||||
<Filter>DSPCore</Filter>
|
<Filter>DSPCore</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="DSP\DSPHWInterface.h">
|
|
||||||
<Filter>DSPCore</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="DSP\DSPMemoryMap.h">
|
|
||||||
<Filter>DSPCore</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="DSP\DSPStacks.h">
|
|
||||||
<Filter>DSPCore</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="DSP\DSPTables.h">
|
<ClInclude Include="DSP\DSPTables.h">
|
||||||
<Filter>DSPCore</Filter>
|
<Filter>DSPCore</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
|
|
||||||
#include "Core/DSP/DSPMemoryMap.h"
|
#include "Core/DSP/DSPCore.h"
|
||||||
#include "Core/DSP/DSPTables.h"
|
#include "Core/DSP/DSPTables.h"
|
||||||
|
|
||||||
namespace DSP::Analyzer
|
namespace DSP::Analyzer
|
||||||
|
@ -72,7 +72,7 @@ void Reset()
|
||||||
code_flags.fill(0);
|
code_flags.fill(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnalyzeRange(u16 start_addr, u16 end_addr)
|
void AnalyzeRange(const SDSP& dsp, u16 start_addr, u16 end_addr)
|
||||||
{
|
{
|
||||||
// First we run an extremely simplified version of a disassembler to find
|
// First we run an extremely simplified version of a disassembler to find
|
||||||
// where all instructions start.
|
// where all instructions start.
|
||||||
|
@ -82,7 +82,7 @@ void AnalyzeRange(u16 start_addr, u16 end_addr)
|
||||||
u16 last_arithmetic = 0;
|
u16 last_arithmetic = 0;
|
||||||
for (u16 addr = start_addr; addr < end_addr;)
|
for (u16 addr = start_addr; addr < end_addr;)
|
||||||
{
|
{
|
||||||
UDSPInstruction inst = dsp_imem_read(addr);
|
const UDSPInstruction inst = dsp.ReadIMEM(addr);
|
||||||
const DSPOPCTemplate* opcode = GetOpTemplate(inst);
|
const DSPOPCTemplate* opcode = GetOpTemplate(inst);
|
||||||
if (!opcode)
|
if (!opcode)
|
||||||
{
|
{
|
||||||
|
@ -94,7 +94,7 @@ void AnalyzeRange(u16 start_addr, u16 end_addr)
|
||||||
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);
|
const u16 loop_end = dsp.ReadIMEM(addr + 1);
|
||||||
code_flags[addr] |= CODE_LOOP_START;
|
code_flags[addr] |= CODE_LOOP_START;
|
||||||
code_flags[loop_end] |= CODE_LOOP_END;
|
code_flags[loop_end] |= CODE_LOOP_END;
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,7 @@ void AnalyzeRange(u16 start_addr, u16 end_addr)
|
||||||
found = true;
|
found = true;
|
||||||
if (idle_skip_sigs[s][i] == 0xFFFF)
|
if (idle_skip_sigs[s][i] == 0xFFFF)
|
||||||
continue;
|
continue;
|
||||||
if (idle_skip_sigs[s][i] != dsp_imem_read(static_cast<u16>(addr + i)))
|
if (idle_skip_sigs[s][i] != dsp.ReadIMEM(static_cast<u16>(addr + i)))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (found)
|
if (found)
|
||||||
|
@ -153,11 +153,11 @@ void AnalyzeRange(u16 start_addr, u16 end_addr)
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
void Analyze()
|
void Analyze(const SDSP& dsp)
|
||||||
{
|
{
|
||||||
Reset();
|
Reset();
|
||||||
AnalyzeRange(0x0000, 0x1000); // IRAM
|
AnalyzeRange(dsp, 0x0000, 0x1000); // IRAM
|
||||||
AnalyzeRange(0x8000, 0x9000); // IROM
|
AnalyzeRange(dsp, 0x8000, 0x9000); // IROM
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 GetCodeFlags(u16 address)
|
u8 GetCodeFlags(u16 address)
|
||||||
|
|
|
@ -6,6 +6,11 @@
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
|
namespace DSP
|
||||||
|
{
|
||||||
|
struct SDSP;
|
||||||
|
}
|
||||||
|
|
||||||
// Basic code analysis.
|
// Basic code analysis.
|
||||||
namespace DSP::Analyzer
|
namespace DSP::Analyzer
|
||||||
{
|
{
|
||||||
|
@ -28,7 +33,7 @@ enum
|
||||||
// all old analysis away. Luckily the entire address space is only 64K code
|
// all old analysis away. Luckily the entire address space is only 64K code
|
||||||
// words and the actual code space 8K instructions in total, so we can do
|
// words and the actual code space 8K instructions in total, so we can do
|
||||||
// some pretty expensive analysis if necessary.
|
// some pretty expensive analysis if necessary.
|
||||||
void Analyze();
|
void Analyze(const SDSP& dsp);
|
||||||
|
|
||||||
// Retrieves the flags set during analysis for code in memory.
|
// Retrieves the flags set during analysis for code in memory.
|
||||||
u8 GetCodeFlags(u16 address);
|
u8 GetCodeFlags(u16 address);
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "Common/ChunkFile.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/Event.h"
|
#include "Common/Event.h"
|
||||||
#include "Common/Hash.h"
|
#include "Common/Hash.h"
|
||||||
|
@ -18,24 +19,18 @@
|
||||||
|
|
||||||
#include "Core/DSP/DSPAccelerator.h"
|
#include "Core/DSP/DSPAccelerator.h"
|
||||||
#include "Core/DSP/DSPAnalyzer.h"
|
#include "Core/DSP/DSPAnalyzer.h"
|
||||||
#include "Core/DSP/DSPHWInterface.h"
|
|
||||||
#include "Core/DSP/DSPHost.h"
|
#include "Core/DSP/DSPHost.h"
|
||||||
#include "Core/DSP/Interpreter/DSPIntUtil.h"
|
|
||||||
#include "Core/DSP/Interpreter/DSPInterpreter.h"
|
#include "Core/DSP/Interpreter/DSPInterpreter.h"
|
||||||
#include "Core/DSP/Jit/DSPEmitterBase.h"
|
#include "Core/DSP/Jit/DSPEmitterBase.h"
|
||||||
|
|
||||||
namespace DSP
|
namespace DSP
|
||||||
{
|
{
|
||||||
SDSP g_dsp;
|
// not needed for game ucodes (it slows down interpreter/dspjit32 + easier to compare int VS
|
||||||
DSPBreakpoints g_dsp_breakpoints;
|
// dspjit64 without it)
|
||||||
static State core_state = State::Stopped;
|
//#define PRECISE_BACKLOG
|
||||||
bool g_init_hax = false;
|
|
||||||
std::unique_ptr<JIT::DSPEmitter> g_dsp_jit;
|
|
||||||
std::unique_ptr<DSPCaptureLogger> g_dsp_cap;
|
|
||||||
static Common::Event step_event;
|
|
||||||
|
|
||||||
// Returns false if the hash fails and the user hits "Yes"
|
// Returns false if the hash fails and the user hits "Yes"
|
||||||
static bool VerifyRoms()
|
static bool VerifyRoms(const SDSP& dsp)
|
||||||
{
|
{
|
||||||
struct DspRomHashes
|
struct DspRomHashes
|
||||||
{
|
{
|
||||||
|
@ -64,8 +59,10 @@ static bool VerifyRoms()
|
||||||
{0x128ea7a2, 0xa4a575f5},
|
{0x128ea7a2, 0xa4a575f5},
|
||||||
}};
|
}};
|
||||||
|
|
||||||
const u32 hash_irom = Common::HashAdler32(reinterpret_cast<u8*>(g_dsp.irom), DSP_IROM_BYTE_SIZE);
|
const u32 hash_irom =
|
||||||
const u32 hash_drom = Common::HashAdler32(reinterpret_cast<u8*>(g_dsp.coef), DSP_COEF_BYTE_SIZE);
|
Common::HashAdler32(reinterpret_cast<const u8*>(dsp.irom), DSP_IROM_BYTE_SIZE);
|
||||||
|
const u32 hash_drom =
|
||||||
|
Common::HashAdler32(reinterpret_cast<const u8*>(dsp.coef), DSP_COEF_BYTE_SIZE);
|
||||||
int rom_idx = -1;
|
int rom_idx = -1;
|
||||||
|
|
||||||
for (size_t i = 0; i < known_roms.size(); ++i)
|
for (size_t i = 0; i < known_roms.size(); ++i)
|
||||||
|
@ -104,151 +101,141 @@ static bool VerifyRoms()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DSPCore_FreeMemoryPages()
|
|
||||||
{
|
|
||||||
Common::FreeMemoryPages(g_dsp.irom, DSP_IROM_BYTE_SIZE);
|
|
||||||
Common::FreeMemoryPages(g_dsp.iram, DSP_IRAM_BYTE_SIZE);
|
|
||||||
Common::FreeMemoryPages(g_dsp.dram, DSP_DRAM_BYTE_SIZE);
|
|
||||||
Common::FreeMemoryPages(g_dsp.coef, DSP_COEF_BYTE_SIZE);
|
|
||||||
g_dsp.irom = g_dsp.iram = g_dsp.dram = g_dsp.coef = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
class LLEAccelerator final : public Accelerator
|
class LLEAccelerator final : public Accelerator
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
explicit LLEAccelerator(SDSP& dsp) : m_dsp{dsp} {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
u8 ReadMemory(u32 address) override { return Host::ReadHostMemory(address); }
|
u8 ReadMemory(u32 address) override { return Host::ReadHostMemory(address); }
|
||||||
void WriteMemory(u32 address, u8 value) override { Host::WriteHostMemory(value, address); }
|
void WriteMemory(u32 address, u8 value) override { Host::WriteHostMemory(value, address); }
|
||||||
void OnEndException() override { DSPCore_SetException(ExceptionType::AcceleratorOverflow); }
|
void OnEndException() override { m_dsp.SetException(ExceptionType::AcceleratorOverflow); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
SDSP& m_dsp;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool DSPCore_Init(const DSPInitOptions& opts)
|
SDSP::SDSP(DSPCore& core) : m_dsp_core{core}
|
||||||
{
|
{
|
||||||
g_dsp.step_counter = 0;
|
}
|
||||||
g_init_hax = false;
|
|
||||||
|
|
||||||
g_dsp.accelerator = std::make_unique<LLEAccelerator>();
|
SDSP::~SDSP() = default;
|
||||||
|
|
||||||
g_dsp.irom = static_cast<u16*>(Common::AllocateMemoryPages(DSP_IROM_BYTE_SIZE));
|
bool SDSP::Initialize(const DSPInitOptions& opts)
|
||||||
g_dsp.iram = static_cast<u16*>(Common::AllocateMemoryPages(DSP_IRAM_BYTE_SIZE));
|
{
|
||||||
g_dsp.dram = static_cast<u16*>(Common::AllocateMemoryPages(DSP_DRAM_BYTE_SIZE));
|
step_counter = 0;
|
||||||
g_dsp.coef = static_cast<u16*>(Common::AllocateMemoryPages(DSP_COEF_BYTE_SIZE));
|
accelerator = std::make_unique<LLEAccelerator>(*this);
|
||||||
|
|
||||||
memcpy(g_dsp.irom, opts.irom_contents.data(), DSP_IROM_BYTE_SIZE);
|
irom = static_cast<u16*>(Common::AllocateMemoryPages(DSP_IROM_BYTE_SIZE));
|
||||||
memcpy(g_dsp.coef, opts.coef_contents.data(), DSP_COEF_BYTE_SIZE);
|
iram = static_cast<u16*>(Common::AllocateMemoryPages(DSP_IRAM_BYTE_SIZE));
|
||||||
|
dram = static_cast<u16*>(Common::AllocateMemoryPages(DSP_DRAM_BYTE_SIZE));
|
||||||
|
coef = static_cast<u16*>(Common::AllocateMemoryPages(DSP_COEF_BYTE_SIZE));
|
||||||
|
|
||||||
|
std::memcpy(irom, opts.irom_contents.data(), DSP_IROM_BYTE_SIZE);
|
||||||
|
std::memcpy(coef, opts.coef_contents.data(), DSP_COEF_BYTE_SIZE);
|
||||||
|
|
||||||
// Try to load real ROM contents.
|
// Try to load real ROM contents.
|
||||||
if (!VerifyRoms())
|
if (!VerifyRoms(*this))
|
||||||
{
|
{
|
||||||
DSPCore_FreeMemoryPages();
|
FreeMemoryPages();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&g_dsp.r, 0, sizeof(g_dsp.r));
|
std::memset(&r, 0, sizeof(r));
|
||||||
|
|
||||||
std::fill(std::begin(g_dsp.reg_stack_ptrs), std::end(g_dsp.reg_stack_ptrs), 0);
|
std::fill(std::begin(reg_stack_ptrs), std::end(reg_stack_ptrs), 0);
|
||||||
|
|
||||||
for (auto& stack : g_dsp.reg_stacks)
|
for (auto& stack : reg_stacks)
|
||||||
std::fill(std::begin(stack), std::end(stack), 0);
|
std::fill(std::begin(stack), std::end(stack), 0);
|
||||||
|
|
||||||
// Fill IRAM with HALT opcodes.
|
// Fill IRAM with HALT opcodes.
|
||||||
std::fill(g_dsp.iram, g_dsp.iram + DSP_IRAM_SIZE, 0x0021);
|
std::fill(iram, iram + DSP_IRAM_SIZE, 0x0021);
|
||||||
|
|
||||||
// Just zero out DRAM.
|
// Just zero out DRAM.
|
||||||
std::fill(g_dsp.dram, g_dsp.dram + DSP_DRAM_SIZE, 0);
|
std::fill(dram, dram + DSP_DRAM_SIZE, 0);
|
||||||
|
|
||||||
// Copied from a real console after the custom UCode has been loaded.
|
// Copied from a real console after the custom UCode has been loaded.
|
||||||
// These are the indexing wrapping registers.
|
// These are the indexing wrapping registers.
|
||||||
std::fill(std::begin(g_dsp.r.wr), std::end(g_dsp.r.wr), 0xffff);
|
std::fill(std::begin(r.wr), std::end(r.wr), 0xffff);
|
||||||
|
|
||||||
g_dsp.r.sr |= SR_INT_ENABLE;
|
r.sr |= SR_INT_ENABLE;
|
||||||
g_dsp.r.sr |= SR_EXT_INT_ENABLE;
|
r.sr |= SR_EXT_INT_ENABLE;
|
||||||
|
|
||||||
g_dsp.cr = 0x804;
|
cr = 0x804;
|
||||||
gdsp_ifx_init();
|
InitializeIFX();
|
||||||
// Mostly keep IRAM write protected. We unprotect only when DMA-ing
|
// Mostly keep IRAM write protected. We unprotect only when DMA-ing
|
||||||
// in new ucodes.
|
// in new ucodes.
|
||||||
Common::WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false);
|
Common::WriteProtectMemory(iram, DSP_IRAM_BYTE_SIZE, false);
|
||||||
|
|
||||||
// Initialize JIT, if necessary
|
|
||||||
if (opts.core_type == DSPInitOptions::CoreType::JIT64)
|
|
||||||
g_dsp_jit = JIT::CreateDSPEmitter();
|
|
||||||
|
|
||||||
g_dsp_cap.reset(opts.capture_logger);
|
|
||||||
|
|
||||||
core_state = State::Running;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPCore_Shutdown()
|
void SDSP::Reset()
|
||||||
{
|
{
|
||||||
if (core_state == State::Stopped)
|
pc = DSP_RESET_VECTOR;
|
||||||
return;
|
std::fill(std::begin(r.wr), std::end(r.wr), 0xffff);
|
||||||
|
|
||||||
core_state = State::Stopped;
|
|
||||||
|
|
||||||
g_dsp_jit.reset();
|
|
||||||
|
|
||||||
DSPCore_FreeMemoryPages();
|
|
||||||
|
|
||||||
g_dsp_cap.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPCore_Reset()
|
void SDSP::Shutdown()
|
||||||
{
|
{
|
||||||
g_dsp.pc = DSP_RESET_VECTOR;
|
FreeMemoryPages();
|
||||||
|
|
||||||
std::fill(std::begin(g_dsp.r.wr), std::end(g_dsp.r.wr), 0xffff);
|
|
||||||
|
|
||||||
Analyzer::Analyze();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPCore_SetException(ExceptionType exception)
|
void SDSP::FreeMemoryPages()
|
||||||
{
|
{
|
||||||
g_dsp.exceptions |= 1 << static_cast<std::underlying_type_t<ExceptionType>>(exception);
|
Common::FreeMemoryPages(irom, DSP_IROM_BYTE_SIZE);
|
||||||
|
Common::FreeMemoryPages(iram, DSP_IRAM_BYTE_SIZE);
|
||||||
|
Common::FreeMemoryPages(dram, DSP_DRAM_BYTE_SIZE);
|
||||||
|
Common::FreeMemoryPages(coef, DSP_COEF_BYTE_SIZE);
|
||||||
|
irom = nullptr;
|
||||||
|
iram = nullptr;
|
||||||
|
dram = nullptr;
|
||||||
|
coef = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify that an external interrupt is pending (used by thread mode)
|
void SDSP::SetException(ExceptionType exception)
|
||||||
void DSPCore_SetExternalInterrupt(bool val)
|
|
||||||
{
|
{
|
||||||
g_dsp.external_interrupt_waiting = val;
|
exceptions |= 1 << static_cast<std::underlying_type_t<ExceptionType>>(exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Coming from the CPU
|
void SDSP::SetExternalInterrupt(bool val)
|
||||||
void DSPCore_CheckExternalInterrupt()
|
|
||||||
{
|
{
|
||||||
if (!Interpreter::dsp_SR_is_flag_set(SR_EXT_INT_ENABLE))
|
external_interrupt_waiting = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDSP::CheckExternalInterrupt()
|
||||||
|
{
|
||||||
|
if (!IsSRFlagSet(SR_EXT_INT_ENABLE))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Signal the SPU about new mail
|
// Signal the SPU about new mail
|
||||||
DSPCore_SetException(ExceptionType::ExternalInterrupt);
|
SetException(ExceptionType::ExternalInterrupt);
|
||||||
|
|
||||||
g_dsp.cr &= ~CR_EXTERNAL_INT;
|
cr &= ~CR_EXTERNAL_INT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPCore_CheckExceptions()
|
void SDSP::CheckExceptions()
|
||||||
{
|
{
|
||||||
// Early out to skip the loop in the common case.
|
// Early out to skip the loop in the common case.
|
||||||
if (g_dsp.exceptions == 0)
|
if (exceptions == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (int i = 7; i > 0; i--)
|
for (int i = 7; i > 0; i--)
|
||||||
{
|
{
|
||||||
// Seems exp int are not masked by sr_int_enable
|
// Seems exp int are not masked by sr_int_enable
|
||||||
if (g_dsp.exceptions & (1 << i))
|
if ((exceptions & (1U << i)) != 0)
|
||||||
{
|
{
|
||||||
if (Interpreter::dsp_SR_is_flag_set(SR_INT_ENABLE) ||
|
if (IsSRFlagSet(SR_INT_ENABLE) || i == static_cast<int>(ExceptionType::ExternalInterrupt))
|
||||||
i == static_cast<int>(ExceptionType::ExternalInterrupt))
|
|
||||||
{
|
{
|
||||||
// store pc and sr until RTI
|
// store pc and sr until RTI
|
||||||
dsp_reg_store_stack(StackRegister::Call, g_dsp.pc);
|
StoreStack(StackRegister::Call, pc);
|
||||||
dsp_reg_store_stack(StackRegister::Data, g_dsp.r.sr);
|
StoreStack(StackRegister::Data, r.sr);
|
||||||
|
|
||||||
g_dsp.pc = i * 2;
|
pc = static_cast<u16>(i * 2);
|
||||||
g_dsp.exceptions &= ~(1 << i);
|
exceptions &= ~(1 << i);
|
||||||
if (i == 7)
|
if (i == 7)
|
||||||
g_dsp.r.sr &= ~SR_EXT_INT_ENABLE;
|
r.sr &= ~SR_EXT_INT_ENABLE;
|
||||||
else
|
else
|
||||||
g_dsp.r.sr &= ~SR_INT_ENABLE;
|
r.sr &= ~SR_INT_ENABLE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -261,34 +248,225 @@ void DSPCore_CheckExceptions()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u16 SDSP::ReadRegister(size_t reg) const
|
||||||
|
{
|
||||||
|
switch (reg)
|
||||||
|
{
|
||||||
|
case DSP_REG_AR0:
|
||||||
|
case DSP_REG_AR1:
|
||||||
|
case DSP_REG_AR2:
|
||||||
|
case DSP_REG_AR3:
|
||||||
|
return r.ar[reg - DSP_REG_AR0];
|
||||||
|
case DSP_REG_IX0:
|
||||||
|
case DSP_REG_IX1:
|
||||||
|
case DSP_REG_IX2:
|
||||||
|
case DSP_REG_IX3:
|
||||||
|
return r.ix[reg - DSP_REG_IX0];
|
||||||
|
case DSP_REG_WR0:
|
||||||
|
case DSP_REG_WR1:
|
||||||
|
case DSP_REG_WR2:
|
||||||
|
case DSP_REG_WR3:
|
||||||
|
return r.wr[reg - DSP_REG_WR0];
|
||||||
|
case DSP_REG_ST0:
|
||||||
|
case DSP_REG_ST1:
|
||||||
|
case DSP_REG_ST2:
|
||||||
|
case DSP_REG_ST3:
|
||||||
|
return r.st[reg - DSP_REG_ST0];
|
||||||
|
case DSP_REG_ACH0:
|
||||||
|
case DSP_REG_ACH1:
|
||||||
|
return r.ac[reg - DSP_REG_ACH0].h;
|
||||||
|
case DSP_REG_CR:
|
||||||
|
return r.cr;
|
||||||
|
case DSP_REG_SR:
|
||||||
|
return r.sr;
|
||||||
|
case DSP_REG_PRODL:
|
||||||
|
return r.prod.l;
|
||||||
|
case DSP_REG_PRODM:
|
||||||
|
return r.prod.m;
|
||||||
|
case DSP_REG_PRODH:
|
||||||
|
return r.prod.h;
|
||||||
|
case DSP_REG_PRODM2:
|
||||||
|
return r.prod.m2;
|
||||||
|
case DSP_REG_AXL0:
|
||||||
|
case DSP_REG_AXL1:
|
||||||
|
return r.ax[reg - DSP_REG_AXL0].l;
|
||||||
|
case DSP_REG_AXH0:
|
||||||
|
case DSP_REG_AXH1:
|
||||||
|
return r.ax[reg - DSP_REG_AXH0].h;
|
||||||
|
case DSP_REG_ACL0:
|
||||||
|
case DSP_REG_ACL1:
|
||||||
|
return r.ac[reg - DSP_REG_ACL0].l;
|
||||||
|
case DSP_REG_ACM0:
|
||||||
|
case DSP_REG_ACM1:
|
||||||
|
return r.ac[reg - DSP_REG_ACM0].m;
|
||||||
|
default:
|
||||||
|
ASSERT_MSG(DSP_CORE, 0, "cannot happen");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDSP::WriteRegister(size_t reg, u16 val)
|
||||||
|
{
|
||||||
|
switch (reg)
|
||||||
|
{
|
||||||
|
case DSP_REG_AR0:
|
||||||
|
case DSP_REG_AR1:
|
||||||
|
case DSP_REG_AR2:
|
||||||
|
case DSP_REG_AR3:
|
||||||
|
r.ar[reg - DSP_REG_AR0] = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_IX0:
|
||||||
|
case DSP_REG_IX1:
|
||||||
|
case DSP_REG_IX2:
|
||||||
|
case DSP_REG_IX3:
|
||||||
|
r.ix[reg - DSP_REG_IX0] = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_WR0:
|
||||||
|
case DSP_REG_WR1:
|
||||||
|
case DSP_REG_WR2:
|
||||||
|
case DSP_REG_WR3:
|
||||||
|
r.wr[reg - DSP_REG_WR0] = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_ST0:
|
||||||
|
case DSP_REG_ST1:
|
||||||
|
case DSP_REG_ST2:
|
||||||
|
case DSP_REG_ST3:
|
||||||
|
r.st[reg - DSP_REG_ST0] = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_ACH0:
|
||||||
|
case DSP_REG_ACH1:
|
||||||
|
r.ac[reg - DSP_REG_ACH0].h = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_CR:
|
||||||
|
r.cr = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_SR:
|
||||||
|
r.sr = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_PRODL:
|
||||||
|
r.prod.l = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_PRODM:
|
||||||
|
r.prod.m = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_PRODH:
|
||||||
|
r.prod.h = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_PRODM2:
|
||||||
|
r.prod.m2 = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_AXL0:
|
||||||
|
case DSP_REG_AXL1:
|
||||||
|
r.ax[reg - DSP_REG_AXL0].l = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_AXH0:
|
||||||
|
case DSP_REG_AXH1:
|
||||||
|
r.ax[reg - DSP_REG_AXH0].h = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_ACL0:
|
||||||
|
case DSP_REG_ACL1:
|
||||||
|
r.ac[reg - DSP_REG_ACL0].l = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_ACM0:
|
||||||
|
case DSP_REG_ACM1:
|
||||||
|
r.ac[reg - DSP_REG_ACM0].m = val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDSP::DoState(PointerWrap& p)
|
||||||
|
{
|
||||||
|
p.Do(r);
|
||||||
|
p.Do(pc);
|
||||||
|
p.Do(cr);
|
||||||
|
p.Do(reg_stack_ptrs);
|
||||||
|
p.Do(exceptions);
|
||||||
|
p.Do(external_interrupt_waiting);
|
||||||
|
|
||||||
|
for (auto& stack : reg_stacks)
|
||||||
|
{
|
||||||
|
p.Do(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Do(step_counter);
|
||||||
|
p.DoArray(ifx_regs);
|
||||||
|
accelerator->DoState(p);
|
||||||
|
p.Do(mbox[0]);
|
||||||
|
p.Do(mbox[1]);
|
||||||
|
Common::UnWriteProtectMemory(iram, DSP_IRAM_BYTE_SIZE, false);
|
||||||
|
p.DoArray(iram, DSP_IRAM_SIZE);
|
||||||
|
Common::WriteProtectMemory(iram, DSP_IRAM_BYTE_SIZE, false);
|
||||||
|
// TODO: This uses the wrong endianness (producing bad disassembly)
|
||||||
|
// and a bogus byte count (producing bad hashes)
|
||||||
|
if (p.GetMode() == PointerWrap::MODE_READ)
|
||||||
|
Host::CodeLoaded(m_dsp_core, reinterpret_cast<const u8*>(iram), DSP_IRAM_BYTE_SIZE);
|
||||||
|
p.DoArray(dram, DSP_DRAM_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
DSPCore::DSPCore()
|
||||||
|
: m_dsp{*this}, m_dsp_interpreter{std::make_unique<Interpreter::Interpreter>(*this)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DSPCore::~DSPCore() = default;
|
||||||
|
|
||||||
|
bool DSPCore::Initialize(const DSPInitOptions& opts)
|
||||||
|
{
|
||||||
|
if (!m_dsp.Initialize(opts))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_init_hax = false;
|
||||||
|
|
||||||
|
// Initialize JIT, if necessary
|
||||||
|
if (opts.core_type == DSPInitOptions::CoreType::JIT64)
|
||||||
|
m_dsp_jit = JIT::CreateDSPEmitter(*this);
|
||||||
|
|
||||||
|
m_dsp_cap.reset(opts.capture_logger);
|
||||||
|
|
||||||
|
m_core_state = State::Running;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPCore::Shutdown()
|
||||||
|
{
|
||||||
|
if (m_core_state == State::Stopped)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_core_state = State::Stopped;
|
||||||
|
|
||||||
|
m_dsp_jit.reset();
|
||||||
|
m_dsp.Shutdown();
|
||||||
|
m_dsp_cap.reset();
|
||||||
|
}
|
||||||
|
|
||||||
// Delegate to JIT or interpreter as appropriate.
|
// Delegate to JIT or interpreter as appropriate.
|
||||||
// Handle state changes and stepping.
|
// Handle state changes and stepping.
|
||||||
int DSPCore_RunCycles(int cycles)
|
int DSPCore::RunCycles(int cycles)
|
||||||
{
|
{
|
||||||
if (g_dsp_jit)
|
if (m_dsp_jit)
|
||||||
{
|
{
|
||||||
return g_dsp_jit->RunCycles(static_cast<u16>(cycles));
|
return m_dsp_jit->RunCycles(static_cast<u16>(cycles));
|
||||||
}
|
}
|
||||||
|
|
||||||
while (cycles > 0)
|
while (cycles > 0)
|
||||||
{
|
{
|
||||||
switch (core_state)
|
switch (m_core_state)
|
||||||
{
|
{
|
||||||
case State::Running:
|
case State::Running:
|
||||||
// Seems to slow things down
|
// Seems to slow things down
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||||
cycles = Interpreter::RunCyclesDebug(cycles);
|
cycles = m_dsp_interpreter->RunCyclesDebug(cycles);
|
||||||
#else
|
#else
|
||||||
cycles = Interpreter::RunCycles(cycles);
|
cycles = m_dsp_interpreter->RunCycles(cycles);
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case State::Stepping:
|
case State::Stepping:
|
||||||
step_event.Wait();
|
m_step_event.Wait();
|
||||||
if (core_state != State::Stepping)
|
if (m_core_state != State::Stepping)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Interpreter::Step();
|
m_dsp_interpreter->Step();
|
||||||
cycles--;
|
cycles--;
|
||||||
|
|
||||||
Host::UpdateDebugger();
|
Host::UpdateDebugger();
|
||||||
|
@ -300,151 +478,123 @@ int DSPCore_RunCycles(int cycles)
|
||||||
return cycles;
|
return cycles;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPCore_SetState(State new_state)
|
void DSPCore::Step()
|
||||||
{
|
{
|
||||||
core_state = new_state;
|
if (m_core_state == State::Stepping)
|
||||||
|
m_step_event.Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPCore::Reset()
|
||||||
|
{
|
||||||
|
m_dsp.Reset();
|
||||||
|
Analyzer::Analyze(m_dsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPCore::ClearIRAM()
|
||||||
|
{
|
||||||
|
if (!m_dsp_jit)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_dsp_jit->ClearIRAM();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPCore::SetState(State new_state)
|
||||||
|
{
|
||||||
|
m_core_state = new_state;
|
||||||
|
|
||||||
// kick the event, in case we are waiting
|
// kick the event, in case we are waiting
|
||||||
if (new_state == State::Running)
|
if (new_state == State::Running)
|
||||||
step_event.Set();
|
m_step_event.Set();
|
||||||
|
|
||||||
Host::UpdateDebugger();
|
Host::UpdateDebugger();
|
||||||
}
|
}
|
||||||
|
|
||||||
State DSPCore_GetState()
|
State DSPCore::GetState() const
|
||||||
{
|
{
|
||||||
return core_state;
|
return m_core_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPCore_Step()
|
void DSPCore::SetException(ExceptionType exception)
|
||||||
{
|
{
|
||||||
if (core_state == State::Stepping)
|
m_dsp.SetException(exception);
|
||||||
step_event.Set();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 DSPCore_ReadRegister(size_t reg)
|
void DSPCore::SetExternalInterrupt(bool val)
|
||||||
{
|
{
|
||||||
switch (reg)
|
m_dsp.SetExternalInterrupt(val);
|
||||||
{
|
|
||||||
case DSP_REG_AR0:
|
|
||||||
case DSP_REG_AR1:
|
|
||||||
case DSP_REG_AR2:
|
|
||||||
case DSP_REG_AR3:
|
|
||||||
return g_dsp.r.ar[reg - DSP_REG_AR0];
|
|
||||||
case DSP_REG_IX0:
|
|
||||||
case DSP_REG_IX1:
|
|
||||||
case DSP_REG_IX2:
|
|
||||||
case DSP_REG_IX3:
|
|
||||||
return g_dsp.r.ix[reg - DSP_REG_IX0];
|
|
||||||
case DSP_REG_WR0:
|
|
||||||
case DSP_REG_WR1:
|
|
||||||
case DSP_REG_WR2:
|
|
||||||
case DSP_REG_WR3:
|
|
||||||
return g_dsp.r.wr[reg - DSP_REG_WR0];
|
|
||||||
case DSP_REG_ST0:
|
|
||||||
case DSP_REG_ST1:
|
|
||||||
case DSP_REG_ST2:
|
|
||||||
case DSP_REG_ST3:
|
|
||||||
return g_dsp.r.st[reg - DSP_REG_ST0];
|
|
||||||
case DSP_REG_ACH0:
|
|
||||||
case DSP_REG_ACH1:
|
|
||||||
return g_dsp.r.ac[reg - DSP_REG_ACH0].h;
|
|
||||||
case DSP_REG_CR:
|
|
||||||
return g_dsp.r.cr;
|
|
||||||
case DSP_REG_SR:
|
|
||||||
return g_dsp.r.sr;
|
|
||||||
case DSP_REG_PRODL:
|
|
||||||
return g_dsp.r.prod.l;
|
|
||||||
case DSP_REG_PRODM:
|
|
||||||
return g_dsp.r.prod.m;
|
|
||||||
case DSP_REG_PRODH:
|
|
||||||
return g_dsp.r.prod.h;
|
|
||||||
case DSP_REG_PRODM2:
|
|
||||||
return g_dsp.r.prod.m2;
|
|
||||||
case DSP_REG_AXL0:
|
|
||||||
case DSP_REG_AXL1:
|
|
||||||
return g_dsp.r.ax[reg - DSP_REG_AXL0].l;
|
|
||||||
case DSP_REG_AXH0:
|
|
||||||
case DSP_REG_AXH1:
|
|
||||||
return g_dsp.r.ax[reg - DSP_REG_AXH0].h;
|
|
||||||
case DSP_REG_ACL0:
|
|
||||||
case DSP_REG_ACL1:
|
|
||||||
return g_dsp.r.ac[reg - DSP_REG_ACL0].l;
|
|
||||||
case DSP_REG_ACM0:
|
|
||||||
case DSP_REG_ACM1:
|
|
||||||
return g_dsp.r.ac[reg - DSP_REG_ACM0].m;
|
|
||||||
default:
|
|
||||||
ASSERT_MSG(DSP_CORE, 0, "cannot happen");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPCore_WriteRegister(size_t reg, u16 val)
|
void DSPCore::CheckExternalInterrupt()
|
||||||
{
|
{
|
||||||
switch (reg)
|
m_dsp.CheckExternalInterrupt();
|
||||||
{
|
|
||||||
case DSP_REG_AR0:
|
|
||||||
case DSP_REG_AR1:
|
|
||||||
case DSP_REG_AR2:
|
|
||||||
case DSP_REG_AR3:
|
|
||||||
g_dsp.r.ar[reg - DSP_REG_AR0] = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_IX0:
|
|
||||||
case DSP_REG_IX1:
|
|
||||||
case DSP_REG_IX2:
|
|
||||||
case DSP_REG_IX3:
|
|
||||||
g_dsp.r.ix[reg - DSP_REG_IX0] = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_WR0:
|
|
||||||
case DSP_REG_WR1:
|
|
||||||
case DSP_REG_WR2:
|
|
||||||
case DSP_REG_WR3:
|
|
||||||
g_dsp.r.wr[reg - DSP_REG_WR0] = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_ST0:
|
|
||||||
case DSP_REG_ST1:
|
|
||||||
case DSP_REG_ST2:
|
|
||||||
case DSP_REG_ST3:
|
|
||||||
g_dsp.r.st[reg - DSP_REG_ST0] = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_ACH0:
|
|
||||||
case DSP_REG_ACH1:
|
|
||||||
g_dsp.r.ac[reg - DSP_REG_ACH0].h = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_CR:
|
|
||||||
g_dsp.r.cr = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_SR:
|
|
||||||
g_dsp.r.sr = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_PRODL:
|
|
||||||
g_dsp.r.prod.l = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_PRODM:
|
|
||||||
g_dsp.r.prod.m = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_PRODH:
|
|
||||||
g_dsp.r.prod.h = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_PRODM2:
|
|
||||||
g_dsp.r.prod.m2 = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_AXL0:
|
|
||||||
case DSP_REG_AXL1:
|
|
||||||
g_dsp.r.ax[reg - DSP_REG_AXL0].l = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_AXH0:
|
|
||||||
case DSP_REG_AXH1:
|
|
||||||
g_dsp.r.ax[reg - DSP_REG_AXH0].h = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_ACL0:
|
|
||||||
case DSP_REG_ACL1:
|
|
||||||
g_dsp.r.ac[reg - DSP_REG_ACL0].l = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_ACM0:
|
|
||||||
case DSP_REG_ACM1:
|
|
||||||
g_dsp.r.ac[reg - DSP_REG_ACM0].m = val;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DSPCore::CheckExceptions()
|
||||||
|
{
|
||||||
|
m_dsp.CheckExceptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 DSPCore::ReadRegister(size_t reg) const
|
||||||
|
{
|
||||||
|
return m_dsp.ReadRegister(reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPCore::WriteRegister(size_t reg, u16 val)
|
||||||
|
{
|
||||||
|
m_dsp.WriteRegister(reg, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 DSPCore::PeekMailbox(Mailbox mailbox) const
|
||||||
|
{
|
||||||
|
return m_dsp.PeekMailbox(mailbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 DSPCore::ReadMailboxLow(Mailbox mailbox)
|
||||||
|
{
|
||||||
|
return m_dsp.ReadMailboxLow(mailbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 DSPCore::ReadMailboxHigh(Mailbox mailbox)
|
||||||
|
{
|
||||||
|
return m_dsp.ReadMailboxHigh(mailbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPCore::WriteMailboxLow(Mailbox mailbox, u16 value)
|
||||||
|
{
|
||||||
|
m_dsp.WriteMailboxLow(mailbox, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPCore::WriteMailboxHigh(Mailbox mailbox, u16 value)
|
||||||
|
{
|
||||||
|
m_dsp.WriteMailboxHigh(mailbox, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPCore::LogIFXRead(u16 address, u16 read_value)
|
||||||
|
{
|
||||||
|
m_dsp_cap->LogIFXRead(address, read_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPCore::LogIFXWrite(u16 address, u16 written_value)
|
||||||
|
{
|
||||||
|
m_dsp_cap->LogIFXWrite(address, written_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPCore::LogDMA(u16 control, u32 gc_address, u16 dsp_address, u16 length, const u8* data)
|
||||||
|
{
|
||||||
|
m_dsp_cap->LogDMA(control, gc_address, dsp_address, length, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DSPCore::IsJITCreated() const
|
||||||
|
{
|
||||||
|
return m_dsp_jit != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPCore::DoState(PointerWrap& p)
|
||||||
|
{
|
||||||
|
m_dsp.DoState(p);
|
||||||
|
p.Do(m_init_hax);
|
||||||
|
|
||||||
|
if (m_dsp_jit)
|
||||||
|
m_dsp_jit->DoState(p);
|
||||||
}
|
}
|
||||||
} // namespace DSP
|
} // namespace DSP
|
||||||
|
|
|
@ -11,12 +11,21 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "Common/Event.h"
|
||||||
#include "Core/DSP/DSPBreakpoints.h"
|
#include "Core/DSP/DSPBreakpoints.h"
|
||||||
#include "Core/DSP/DSPCaptureLogger.h"
|
#include "Core/DSP/DSPCaptureLogger.h"
|
||||||
|
|
||||||
|
class PointerWrap;
|
||||||
|
|
||||||
namespace DSP
|
namespace DSP
|
||||||
{
|
{
|
||||||
class Accelerator;
|
class Accelerator;
|
||||||
|
class DSPCore;
|
||||||
|
|
||||||
|
namespace Interpreter
|
||||||
|
{
|
||||||
|
class Interpreter;
|
||||||
|
}
|
||||||
|
|
||||||
namespace JIT
|
namespace JIT
|
||||||
{
|
{
|
||||||
|
@ -216,6 +225,12 @@ enum class ExceptionType
|
||||||
ExternalInterrupt = 7 // 0x000e external int (message from CPU)
|
ExternalInterrupt = 7 // 0x000e external int (message from CPU)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum Mailbox : int
|
||||||
|
{
|
||||||
|
MAILBOX_CPU,
|
||||||
|
MAILBOX_DSP
|
||||||
|
};
|
||||||
|
|
||||||
struct DSP_Regs
|
struct DSP_Regs
|
||||||
{
|
{
|
||||||
u16 ar[4];
|
u16 ar[4];
|
||||||
|
@ -259,61 +274,6 @@ struct DSP_Regs
|
||||||
} ac[2];
|
} ac[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
// All the state of the DSP should be in this struct. Any DSP state that is not filled on init
|
|
||||||
// should be moved here.
|
|
||||||
struct SDSP
|
|
||||||
{
|
|
||||||
DSP_Regs r;
|
|
||||||
u16 pc;
|
|
||||||
#if PROFILE
|
|
||||||
u16 err_pc;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// This is NOT the same cr as r.cr.
|
|
||||||
// This register is shared with the main emulation, see DSP.cpp
|
|
||||||
// The engine has control over 0x0C07 of this reg.
|
|
||||||
// Bits are defined in a struct in DSP.cpp.
|
|
||||||
u16 cr;
|
|
||||||
|
|
||||||
u8 reg_stack_ptrs[4];
|
|
||||||
u8 exceptions; // pending exceptions
|
|
||||||
volatile bool external_interrupt_waiting;
|
|
||||||
bool reset_dspjit_codespace;
|
|
||||||
|
|
||||||
// DSP hardware stacks. They're mapped to a bunch of registers, such that writes
|
|
||||||
// to them push and reads pop.
|
|
||||||
// Let's make stack depth 32 for now, which is way more than what's needed.
|
|
||||||
// The real DSP has different depths for the different stacks, but it would
|
|
||||||
// be strange if any ucode relied on stack overflows since on the DSP, when
|
|
||||||
// the stack overflows, you're screwed.
|
|
||||||
u16 reg_stacks[4][DSP_STACK_DEPTH];
|
|
||||||
|
|
||||||
// For debugging.
|
|
||||||
u32 iram_crc;
|
|
||||||
u64 step_counter;
|
|
||||||
|
|
||||||
// Mailbox.
|
|
||||||
std::atomic<u32> mbox[2];
|
|
||||||
|
|
||||||
// Accelerator / DMA / other hardware registers. Not GPRs.
|
|
||||||
std::array<u16, 256> ifx_regs;
|
|
||||||
|
|
||||||
std::unique_ptr<Accelerator> accelerator;
|
|
||||||
|
|
||||||
// When state saving, all of the above can just be memcpy'd into the save state.
|
|
||||||
// The below needs special handling.
|
|
||||||
u16* iram;
|
|
||||||
u16* dram;
|
|
||||||
u16* irom;
|
|
||||||
u16* coef;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern SDSP g_dsp;
|
|
||||||
extern DSPBreakpoints g_dsp_breakpoints;
|
|
||||||
extern bool g_init_hax;
|
|
||||||
extern std::unique_ptr<JIT::DSPEmitter> g_dsp_jit;
|
|
||||||
extern std::unique_ptr<DSPCaptureLogger> g_dsp_cap;
|
|
||||||
|
|
||||||
struct DSPInitOptions
|
struct DSPInitOptions
|
||||||
{
|
{
|
||||||
// DSP IROM blob, which is where the DSP boots from. Embedded into the DSP.
|
// DSP IROM blob, which is where the DSP boots from. Embedded into the DSP.
|
||||||
|
@ -338,19 +298,158 @@ struct DSPInitOptions
|
||||||
DSPInitOptions() : capture_logger(new DefaultDSPCaptureLogger()) {}
|
DSPInitOptions() : capture_logger(new DefaultDSPCaptureLogger()) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initializes the DSP emulator using the provided options. Takes ownership of
|
// All the state of the DSP should be in this struct. Any DSP state that is not filled on init
|
||||||
// all the pointers contained in the options structure.
|
// should be moved here.
|
||||||
bool DSPCore_Init(const DSPInitOptions& opts);
|
struct SDSP
|
||||||
|
{
|
||||||
|
explicit SDSP(DSPCore& core);
|
||||||
|
~SDSP();
|
||||||
|
|
||||||
void DSPCore_Reset();
|
SDSP(const SDSP&) = delete;
|
||||||
void DSPCore_Shutdown(); // Frees all allocated memory.
|
SDSP& operator=(const SDSP&) = delete;
|
||||||
|
|
||||||
void DSPCore_CheckExternalInterrupt();
|
SDSP(SDSP&&) = delete;
|
||||||
void DSPCore_CheckExceptions();
|
SDSP& operator=(SDSP&&) = delete;
|
||||||
void DSPCore_SetExternalInterrupt(bool val);
|
|
||||||
|
|
||||||
// sets a flag in the pending exception register.
|
// Initializes overall state.
|
||||||
void DSPCore_SetException(ExceptionType exception);
|
bool Initialize(const DSPInitOptions& opts);
|
||||||
|
|
||||||
|
// Shuts down any necessary DSP state.
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
// Resets DSP state as if the reset exception vector has been taken.
|
||||||
|
void Reset();
|
||||||
|
|
||||||
|
// Initializes the IFX registers.
|
||||||
|
void InitializeIFX();
|
||||||
|
|
||||||
|
// Writes to IFX registers.
|
||||||
|
void WriteIFX(u32 address, u16 value);
|
||||||
|
|
||||||
|
// Reads from IFX registers.
|
||||||
|
u16 ReadIFX(u16 address);
|
||||||
|
|
||||||
|
// Checks the whole value within a mailbox.
|
||||||
|
u32 PeekMailbox(Mailbox mailbox) const;
|
||||||
|
|
||||||
|
// Reads the low part of the value in the specified mailbox.
|
||||||
|
u16 ReadMailboxLow(Mailbox mailbox);
|
||||||
|
|
||||||
|
// Reads the high part of the value in the specified mailbox.
|
||||||
|
u16 ReadMailboxHigh(Mailbox mailbox);
|
||||||
|
|
||||||
|
// Writes to the low part of the mailbox.
|
||||||
|
void WriteMailboxLow(Mailbox mailbox, u16 value);
|
||||||
|
|
||||||
|
// Writes to the high part of the mailbox.
|
||||||
|
void WriteMailboxHigh(Mailbox mailbox, u16 value);
|
||||||
|
|
||||||
|
// Reads from instruction memory.
|
||||||
|
u16 ReadIMEM(u16 address) const;
|
||||||
|
|
||||||
|
// Reads from data memory.
|
||||||
|
u16 ReadDMEM(u16 address);
|
||||||
|
|
||||||
|
// Write to data memory.
|
||||||
|
void WriteDMEM(u16 address, u16 value);
|
||||||
|
|
||||||
|
// Fetches the next instruction and increments the PC.
|
||||||
|
u16 FetchInstruction();
|
||||||
|
|
||||||
|
// Fetches the instruction at the PC address, but doesn't increment the PC.
|
||||||
|
u16 PeekInstruction() const;
|
||||||
|
|
||||||
|
// Skips over the next instruction in memory.
|
||||||
|
void SkipInstruction();
|
||||||
|
|
||||||
|
// Sets the given flags in the SR register.
|
||||||
|
void SetSRFlag(u16 flag) { r.sr |= flag; }
|
||||||
|
|
||||||
|
// Whether or not the given flag is set in the SR register.
|
||||||
|
bool IsSRFlagSet(u16 flag) const { return (r.sr & flag) != 0; }
|
||||||
|
|
||||||
|
// Indicates that a particular exception has occurred
|
||||||
|
// and sets a flag in the pending exception register.
|
||||||
|
void SetException(ExceptionType exception);
|
||||||
|
|
||||||
|
// Checks if any exceptions occurred an updates the DSP state as appropriate.
|
||||||
|
void CheckExceptions();
|
||||||
|
|
||||||
|
// Notify that an external interrupt is pending (used by thread mode)
|
||||||
|
void SetExternalInterrupt(bool val);
|
||||||
|
|
||||||
|
// Coming from the CPU
|
||||||
|
void CheckExternalInterrupt();
|
||||||
|
|
||||||
|
// Stores a value into the specified stack
|
||||||
|
void StoreStack(StackRegister stack_reg, u16 val);
|
||||||
|
|
||||||
|
// Pops a value off of the specified stack
|
||||||
|
u16 PopStack(StackRegister stack_reg);
|
||||||
|
|
||||||
|
// Reads the current value from a particular register.
|
||||||
|
u16 ReadRegister(size_t reg) const;
|
||||||
|
|
||||||
|
// Writes a value to a given register.
|
||||||
|
void WriteRegister(size_t reg, u16 val);
|
||||||
|
|
||||||
|
// Saves and loads any necessary state.
|
||||||
|
void DoState(PointerWrap& p);
|
||||||
|
|
||||||
|
DSP_Regs r{};
|
||||||
|
u16 pc = 0;
|
||||||
|
|
||||||
|
// This is NOT the same cr as r.cr.
|
||||||
|
// This register is shared with the main emulation, see DSP.cpp
|
||||||
|
// The engine has control over 0x0C07 of this reg.
|
||||||
|
// Bits are defined in a struct in DSP.cpp.
|
||||||
|
u16 cr = 0;
|
||||||
|
|
||||||
|
u8 reg_stack_ptrs[4]{};
|
||||||
|
u8 exceptions = 0; // pending exceptions
|
||||||
|
volatile bool external_interrupt_waiting = false;
|
||||||
|
bool reset_dspjit_codespace = false;
|
||||||
|
|
||||||
|
// DSP hardware stacks. They're mapped to a bunch of registers, such that writes
|
||||||
|
// to them push and reads pop.
|
||||||
|
// Let's make stack depth 32 for now, which is way more than what's needed.
|
||||||
|
// The real DSP has different depths for the different stacks, but it would
|
||||||
|
// be strange if any ucode relied on stack overflows since on the DSP, when
|
||||||
|
// the stack overflows, you're screwed.
|
||||||
|
u16 reg_stacks[4][DSP_STACK_DEPTH]{};
|
||||||
|
|
||||||
|
// For debugging.
|
||||||
|
u32 iram_crc = 0;
|
||||||
|
u64 step_counter = 0;
|
||||||
|
|
||||||
|
// Mailbox.
|
||||||
|
std::atomic<u32> mbox[2];
|
||||||
|
|
||||||
|
// Accelerator / DMA / other hardware registers. Not GPRs.
|
||||||
|
std::array<u16, 256> ifx_regs{};
|
||||||
|
|
||||||
|
std::unique_ptr<Accelerator> accelerator;
|
||||||
|
|
||||||
|
// When state saving, all of the above can just be memcpy'd into the save state.
|
||||||
|
// The below needs special handling.
|
||||||
|
u16* iram = nullptr;
|
||||||
|
u16* dram = nullptr;
|
||||||
|
u16* irom = nullptr;
|
||||||
|
u16* coef = nullptr;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void FreeMemoryPages();
|
||||||
|
|
||||||
|
void DoDMA();
|
||||||
|
const u8* DDMAIn(u16 dsp_addr, u32 addr, u32 size);
|
||||||
|
const u8* DDMAOut(u16 dsp_addr, u32 addr, u32 size);
|
||||||
|
const u8* IDMAIn(u16 dsp_addr, u32 addr, u32 size);
|
||||||
|
const u8* IDMAOut(u16 dsp_addr, u32 addr, u32 size);
|
||||||
|
|
||||||
|
u16 ReadIFXImpl(u16 address);
|
||||||
|
|
||||||
|
DSPCore& m_dsp_core;
|
||||||
|
};
|
||||||
|
|
||||||
enum class State
|
enum class State
|
||||||
{
|
{
|
||||||
|
@ -359,14 +458,115 @@ enum class State
|
||||||
Stepping,
|
Stepping,
|
||||||
};
|
};
|
||||||
|
|
||||||
int DSPCore_RunCycles(int cycles);
|
class DSPCore
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DSPCore();
|
||||||
|
~DSPCore();
|
||||||
|
|
||||||
// These are meant to be called from the UI thread.
|
DSPCore(const DSPCore&) = delete;
|
||||||
void DSPCore_SetState(State new_state);
|
DSPCore& operator=(const DSPCore&) = delete;
|
||||||
State DSPCore_GetState();
|
|
||||||
|
|
||||||
void DSPCore_Step();
|
DSPCore(DSPCore&&) = delete;
|
||||||
|
DSPCore& operator=(DSPCore&&) = delete;
|
||||||
|
|
||||||
u16 DSPCore_ReadRegister(size_t reg);
|
// Initializes the DSP emulator using the provided options. Takes ownership of
|
||||||
void DSPCore_WriteRegister(size_t reg, u16 val);
|
// all the pointers contained in the options structure.
|
||||||
|
bool Initialize(const DSPInitOptions& opts);
|
||||||
|
|
||||||
|
// Shuts down the DSP core and cleans up any necessary state.
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
// Delegates to JIT or interpreter as appropriate.
|
||||||
|
// Handle state changes and stepping.
|
||||||
|
int RunCycles(int cycles);
|
||||||
|
|
||||||
|
// Steps the DSP by a single instruction.
|
||||||
|
void Step();
|
||||||
|
|
||||||
|
// Resets DSP state as if the reset exception vector has been taken.
|
||||||
|
void Reset();
|
||||||
|
|
||||||
|
// Clears the DSP instruction RAM.
|
||||||
|
void ClearIRAM();
|
||||||
|
|
||||||
|
// Dictates whether or not the DSP is currently stopped, running or stepping
|
||||||
|
// through instructions.
|
||||||
|
void SetState(State new_state);
|
||||||
|
|
||||||
|
// Retrieves the current execution state of the DSP.
|
||||||
|
State GetState() const;
|
||||||
|
|
||||||
|
// Indicates that a particular exception has occurred
|
||||||
|
// and sets a flag in the pending exception register.
|
||||||
|
void SetException(ExceptionType exception);
|
||||||
|
|
||||||
|
// Notify that an external interrupt is pending (used by thread mode)
|
||||||
|
void SetExternalInterrupt(bool val);
|
||||||
|
|
||||||
|
// Coming from the CPU
|
||||||
|
void CheckExternalInterrupt();
|
||||||
|
|
||||||
|
// Checks if any exceptions occurred an updates the DSP state as appropriate.
|
||||||
|
void CheckExceptions();
|
||||||
|
|
||||||
|
// Reads the current value from a particular register.
|
||||||
|
u16 ReadRegister(size_t reg) const;
|
||||||
|
|
||||||
|
// Writes a value to a given register.
|
||||||
|
void WriteRegister(size_t reg, u16 val);
|
||||||
|
|
||||||
|
// Checks the value within a mailbox.
|
||||||
|
u32 PeekMailbox(Mailbox mailbox) const;
|
||||||
|
|
||||||
|
// Reads the low part of the specified mailbox register.
|
||||||
|
u16 ReadMailboxLow(Mailbox mailbox);
|
||||||
|
|
||||||
|
// Reads the high part of the specified mailbox register.
|
||||||
|
u16 ReadMailboxHigh(Mailbox mailbox);
|
||||||
|
|
||||||
|
// Writes to the low part of the mailbox register.
|
||||||
|
void WriteMailboxLow(Mailbox mailbox, u16 value);
|
||||||
|
|
||||||
|
// Writes to the high part of the mailbox register.
|
||||||
|
void WriteMailboxHigh(Mailbox mailbox, u16 value);
|
||||||
|
|
||||||
|
// Logs an IFX register read.
|
||||||
|
void LogIFXRead(u16 address, u16 read_value);
|
||||||
|
|
||||||
|
// Logs an IFX register write.
|
||||||
|
void LogIFXWrite(u16 address, u16 written_value);
|
||||||
|
|
||||||
|
// Logs a DMA operation
|
||||||
|
void LogDMA(u16 control, u32 gc_address, u16 dsp_address, u16 length, const u8* data);
|
||||||
|
|
||||||
|
// Whether or not the JIT has been created.
|
||||||
|
bool IsJITCreated() const;
|
||||||
|
|
||||||
|
// Writes or loads state for savestates.
|
||||||
|
void DoState(PointerWrap& p);
|
||||||
|
|
||||||
|
// Accessors for the DSP breakpoint facilities.
|
||||||
|
DSPBreakpoints& BreakPoints() { return m_dsp_breakpoints; }
|
||||||
|
const DSPBreakpoints& BreakPoints() const { return m_dsp_breakpoints; }
|
||||||
|
|
||||||
|
SDSP& DSPState() { return m_dsp; }
|
||||||
|
const SDSP& DSPState() const { return m_dsp; }
|
||||||
|
|
||||||
|
Interpreter::Interpreter& GetInterpreter() { return *m_dsp_interpreter; }
|
||||||
|
const Interpreter::Interpreter& GetInterpreter() const { return *m_dsp_interpreter; }
|
||||||
|
|
||||||
|
bool GetInitHax() const { return m_init_hax; }
|
||||||
|
void SetInitHax(bool value) { m_init_hax = value; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
SDSP m_dsp;
|
||||||
|
DSPBreakpoints m_dsp_breakpoints;
|
||||||
|
State m_core_state = State::Stopped;
|
||||||
|
bool m_init_hax = false;
|
||||||
|
std::unique_ptr<Interpreter::Interpreter> m_dsp_interpreter;
|
||||||
|
std::unique_ptr<JIT::DSPEmitter> m_dsp_jit;
|
||||||
|
std::unique_ptr<DSPCaptureLogger> m_dsp_cap;
|
||||||
|
Common::Event m_step_event;
|
||||||
|
};
|
||||||
} // namespace DSP
|
} // namespace DSP
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
// Licensed under GPLv2+
|
// Licensed under GPLv2+
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include "Core/DSP/DSPHWInterface.h"
|
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -23,349 +21,346 @@
|
||||||
|
|
||||||
namespace DSP
|
namespace DSP
|
||||||
{
|
{
|
||||||
static void gdsp_do_dma();
|
void SDSP::InitializeIFX()
|
||||||
|
|
||||||
void gdsp_ifx_init()
|
|
||||||
{
|
{
|
||||||
g_dsp.ifx_regs.fill(0);
|
ifx_regs.fill(0);
|
||||||
|
|
||||||
g_dsp.mbox[MAILBOX_CPU].store(0);
|
mbox[MAILBOX_CPU].store(0);
|
||||||
g_dsp.mbox[MAILBOX_DSP].store(0);
|
mbox[MAILBOX_DSP].store(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 gdsp_mbox_peek(Mailbox mbx)
|
u32 SDSP::PeekMailbox(Mailbox mailbox) const
|
||||||
{
|
{
|
||||||
return g_dsp.mbox[mbx].load();
|
return mbox[mailbox].load();
|
||||||
}
|
}
|
||||||
|
|
||||||
void gdsp_mbox_write_h(Mailbox mbx, u16 val)
|
u16 SDSP::ReadMailboxLow(Mailbox mailbox)
|
||||||
{
|
{
|
||||||
const u32 old_value = g_dsp.mbox[mbx].load(std::memory_order_acquire);
|
const u32 value = mbox[mailbox].load(std::memory_order_acquire);
|
||||||
const u32 new_value = (old_value & 0xffff) | (val << 16);
|
mbox[mailbox].store(value & ~0x80000000, std::memory_order_release);
|
||||||
|
|
||||||
g_dsp.mbox[mbx].store(new_value & ~0x80000000, std::memory_order_release);
|
if (m_dsp_core.GetInitHax() && mailbox == MAILBOX_DSP)
|
||||||
}
|
|
||||||
|
|
||||||
void gdsp_mbox_write_l(Mailbox mbx, u16 val)
|
|
||||||
{
|
{
|
||||||
const u32 old_value = g_dsp.mbox[mbx].load(std::memory_order_acquire);
|
m_dsp_core.SetInitHax(false);
|
||||||
const u32 new_value = (old_value & ~0xffff) | val;
|
m_dsp_core.Reset();
|
||||||
|
|
||||||
g_dsp.mbox[mbx].store(new_value | 0x80000000, std::memory_order_release);
|
|
||||||
|
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
|
||||||
const char* const type = mbx == MAILBOX_DSP ? "DSP" : "CPU";
|
|
||||||
DEBUG_LOG_FMT(DSP_MAIL, "{}(WM) B:{} M:{:#010x} (pc={:#06x})", type, mbx, gdsp_mbox_peek(mbx),
|
|
||||||
g_dsp.pc);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
u16 gdsp_mbox_read_h(Mailbox mbx)
|
|
||||||
{
|
|
||||||
if (g_init_hax && mbx == MAILBOX_DSP)
|
|
||||||
{
|
|
||||||
return 0x8054;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (u16)(g_dsp.mbox[mbx].load() >> 16); // TODO: mask away the top bit?
|
|
||||||
}
|
|
||||||
|
|
||||||
u16 gdsp_mbox_read_l(Mailbox mbx)
|
|
||||||
{
|
|
||||||
const u32 value = g_dsp.mbox[mbx].load(std::memory_order_acquire);
|
|
||||||
g_dsp.mbox[mbx].store(value & ~0x80000000, std::memory_order_release);
|
|
||||||
|
|
||||||
if (g_init_hax && mbx == MAILBOX_DSP)
|
|
||||||
{
|
|
||||||
g_init_hax = false;
|
|
||||||
DSPCore_Reset();
|
|
||||||
return 0x4348;
|
return 0x4348;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||||
const char* const type = mbx == MAILBOX_DSP ? "DSP" : "CPU";
|
const char* const type = mailbox == MAILBOX_DSP ? "DSP" : "CPU";
|
||||||
DEBUG_LOG_FMT(DSP_MAIL, "{}(RM) B:{} M:0x{:#010x} (pc={:#06x})", type, mbx, gdsp_mbox_peek(mbx),
|
DEBUG_LOG_FMT(DSP_MAIL, "{}(RM) B:{} M:0x{:#010x} (pc={:#06x})", type, mailbox,
|
||||||
g_dsp.pc);
|
PeekMailbox(mailbox), pc);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return (u16)value;
|
return static_cast<u16>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gdsp_ifx_write(u32 addr, u16 val)
|
u16 SDSP::ReadMailboxHigh(Mailbox mailbox)
|
||||||
{
|
{
|
||||||
g_dsp_cap->LogIFXWrite(addr, val);
|
if (m_dsp_core.GetInitHax() && mailbox == MAILBOX_DSP)
|
||||||
|
{
|
||||||
|
return 0x8054;
|
||||||
|
}
|
||||||
|
|
||||||
switch (addr & 0xff)
|
// TODO: mask away the top bit?
|
||||||
|
return static_cast<u16>(PeekMailbox(mailbox) >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDSP::WriteMailboxLow(Mailbox mailbox, u16 value)
|
||||||
|
{
|
||||||
|
const u32 old_value = mbox[mailbox].load(std::memory_order_acquire);
|
||||||
|
const u32 new_value = (old_value & ~0xffff) | value;
|
||||||
|
|
||||||
|
mbox[mailbox].store(new_value | 0x80000000, std::memory_order_release);
|
||||||
|
|
||||||
|
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||||
|
const char* const type = mailbox == MAILBOX_DSP ? "DSP" : "CPU";
|
||||||
|
DEBUG_LOG_FMT(DSP_MAIL, "{}(WM) B:{} M:{:#010x} (pc={:#06x})", type, mailbox,
|
||||||
|
PeekMailbox(mailbox), pc);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDSP::WriteMailboxHigh(Mailbox mailbox, u16 value)
|
||||||
|
{
|
||||||
|
const u32 old_value = mbox[mailbox].load(std::memory_order_acquire);
|
||||||
|
const u32 new_value = (old_value & 0xffff) | (value << 16);
|
||||||
|
|
||||||
|
mbox[mailbox].store(new_value & ~0x80000000, std::memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDSP::WriteIFX(u32 address, u16 value)
|
||||||
|
{
|
||||||
|
m_dsp_core.LogIFXWrite(address, value);
|
||||||
|
|
||||||
|
switch (address & 0xff)
|
||||||
{
|
{
|
||||||
case DSP_DIRQ:
|
case DSP_DIRQ:
|
||||||
if ((val & 1) != 0)
|
if ((value & 1) != 0)
|
||||||
Host::InterruptRequest();
|
Host::InterruptRequest();
|
||||||
else
|
else
|
||||||
WARN_LOG_FMT(DSPLLE, "Unknown Interrupt Request pc={:#06x} ({:#06x})", g_dsp.pc, val);
|
WARN_LOG_FMT(DSPLLE, "Unknown Interrupt Request pc={:#06x} ({:#06x})", pc, value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DSP_DMBH:
|
case DSP_DMBH:
|
||||||
gdsp_mbox_write_h(MAILBOX_DSP, val);
|
WriteMailboxHigh(MAILBOX_DSP, value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DSP_DMBL:
|
case DSP_DMBL:
|
||||||
gdsp_mbox_write_l(MAILBOX_DSP, val);
|
WriteMailboxLow(MAILBOX_DSP, value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DSP_CMBH:
|
case DSP_CMBH:
|
||||||
return gdsp_mbox_write_h(MAILBOX_CPU, val);
|
WriteMailboxHigh(MAILBOX_CPU, value);
|
||||||
|
break;
|
||||||
|
|
||||||
case DSP_CMBL:
|
case DSP_CMBL:
|
||||||
return gdsp_mbox_write_l(MAILBOX_CPU, val);
|
WriteMailboxLow(MAILBOX_CPU, value);
|
||||||
|
break;
|
||||||
|
|
||||||
case DSP_DSBL:
|
case DSP_DSBL:
|
||||||
g_dsp.ifx_regs[DSP_DSBL] = val;
|
ifx_regs[DSP_DSBL] = value;
|
||||||
g_dsp.ifx_regs[DSP_DSCR] |= 4; // Doesn't really matter since we do DMA instantly
|
ifx_regs[DSP_DSCR] |= 4; // Doesn't really matter since we do DMA instantly
|
||||||
if (!g_dsp.ifx_regs[DSP_AMDM])
|
if (!ifx_regs[DSP_AMDM])
|
||||||
gdsp_do_dma();
|
DoDMA();
|
||||||
else
|
else
|
||||||
NOTICE_LOG_FMT(DSPLLE, "Masked DMA skipped");
|
NOTICE_LOG_FMT(DSPLLE, "Masked DMA skipped");
|
||||||
g_dsp.ifx_regs[DSP_DSCR] &= ~4;
|
ifx_regs[DSP_DSCR] &= ~4;
|
||||||
g_dsp.ifx_regs[DSP_DSBL] = 0;
|
ifx_regs[DSP_DSBL] = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DSP_GAIN:
|
case DSP_GAIN:
|
||||||
if (val != 0)
|
if (value != 0)
|
||||||
{
|
{
|
||||||
DEBUG_LOG_FMT(DSPLLE, "Gain Written: {:#06x}", val);
|
DEBUG_LOG_FMT(DSPLLE, "Gain Written: {:#06x}", value);
|
||||||
}
|
}
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case DSP_DSPA:
|
case DSP_DSPA:
|
||||||
case DSP_DSMAH:
|
case DSP_DSMAH:
|
||||||
case DSP_DSMAL:
|
case DSP_DSMAL:
|
||||||
case DSP_DSCR:
|
case DSP_DSCR:
|
||||||
g_dsp.ifx_regs[addr & 0xFF] = val;
|
ifx_regs[address & 0xFF] = value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DSP_ACSAH:
|
case DSP_ACSAH:
|
||||||
g_dsp.accelerator->SetStartAddress(val << 16 |
|
accelerator->SetStartAddress(value << 16 | static_cast<u16>(accelerator->GetStartAddress()));
|
||||||
static_cast<u16>(g_dsp.accelerator->GetStartAddress()));
|
|
||||||
break;
|
break;
|
||||||
case DSP_ACSAL:
|
case DSP_ACSAL:
|
||||||
g_dsp.accelerator->SetStartAddress(
|
accelerator->SetStartAddress(static_cast<u16>(accelerator->GetStartAddress() >> 16) << 16 |
|
||||||
static_cast<u16>(g_dsp.accelerator->GetStartAddress() >> 16) << 16 | val);
|
value);
|
||||||
break;
|
break;
|
||||||
case DSP_ACEAH:
|
case DSP_ACEAH:
|
||||||
g_dsp.accelerator->SetEndAddress(val << 16 |
|
accelerator->SetEndAddress(value << 16 | static_cast<u16>(accelerator->GetEndAddress()));
|
||||||
static_cast<u16>(g_dsp.accelerator->GetEndAddress()));
|
|
||||||
break;
|
break;
|
||||||
case DSP_ACEAL:
|
case DSP_ACEAL:
|
||||||
g_dsp.accelerator->SetEndAddress(
|
accelerator->SetEndAddress(static_cast<u16>(accelerator->GetEndAddress() >> 16) << 16 | value);
|
||||||
static_cast<u16>(g_dsp.accelerator->GetEndAddress() >> 16) << 16 | val);
|
|
||||||
break;
|
break;
|
||||||
case DSP_ACCAH:
|
case DSP_ACCAH:
|
||||||
g_dsp.accelerator->SetCurrentAddress(val << 16 |
|
accelerator->SetCurrentAddress(value << 16 |
|
||||||
static_cast<u16>(g_dsp.accelerator->GetCurrentAddress()));
|
static_cast<u16>(accelerator->GetCurrentAddress()));
|
||||||
break;
|
break;
|
||||||
case DSP_ACCAL:
|
case DSP_ACCAL:
|
||||||
g_dsp.accelerator->SetCurrentAddress(
|
accelerator->SetCurrentAddress(static_cast<u16>(accelerator->GetCurrentAddress() >> 16) << 16 |
|
||||||
static_cast<u16>(g_dsp.accelerator->GetCurrentAddress() >> 16) << 16 | val);
|
value);
|
||||||
break;
|
break;
|
||||||
case DSP_FORMAT:
|
case DSP_FORMAT:
|
||||||
g_dsp.accelerator->SetSampleFormat(val);
|
accelerator->SetSampleFormat(value);
|
||||||
break;
|
break;
|
||||||
case DSP_YN1:
|
case DSP_YN1:
|
||||||
g_dsp.accelerator->SetYn1(val);
|
accelerator->SetYn1(value);
|
||||||
break;
|
break;
|
||||||
case DSP_YN2:
|
case DSP_YN2:
|
||||||
g_dsp.accelerator->SetYn2(val);
|
accelerator->SetYn2(value);
|
||||||
break;
|
break;
|
||||||
case DSP_PRED_SCALE:
|
case DSP_PRED_SCALE:
|
||||||
g_dsp.accelerator->SetPredScale(val);
|
accelerator->SetPredScale(value);
|
||||||
break;
|
break;
|
||||||
case DSP_ACDATA1: // Accelerator write (Zelda type) - "UnkZelda"
|
case DSP_ACDATA1: // Accelerator write (Zelda type) - "UnkZelda"
|
||||||
g_dsp.accelerator->WriteD3(val);
|
accelerator->WriteD3(value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if ((addr & 0xff) >= 0xa0)
|
if ((address & 0xff) >= 0xa0)
|
||||||
{
|
{
|
||||||
const u32 index = (addr & 0xFF) - 0xa0;
|
const u32 index = (address & 0xFF) - 0xa0;
|
||||||
const auto& label = pdlabels[index];
|
const auto& label = pdlabels[index];
|
||||||
|
|
||||||
if (label.name && label.description)
|
if (label.name && label.description)
|
||||||
{
|
{
|
||||||
DEBUG_LOG_FMT(DSPLLE, "{:04x} MW {} ({:04x})", g_dsp.pc, label.name, val);
|
DEBUG_LOG_FMT(DSPLLE, "{:04x} MW {} ({:04x})", pc, label.name, value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(DSPLLE, "{:04x} MW {:04x} ({:04x})", g_dsp.pc, addr, val);
|
ERROR_LOG_FMT(DSPLLE, "{:04x} MW {:04x} ({:04x})", pc, address, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(DSPLLE, "{:04x} MW {:04x} ({:04x})", g_dsp.pc, addr, val);
|
ERROR_LOG_FMT(DSPLLE, "{:04x} MW {:04x} ({:04x})", pc, address, value);
|
||||||
}
|
}
|
||||||
g_dsp.ifx_regs[addr & 0xFF] = val;
|
ifx_regs[address & 0xFF] = value;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static u16 _gdsp_ifx_read(u16 addr)
|
u16 SDSP::ReadIFXImpl(u16 address)
|
||||||
{
|
{
|
||||||
switch (addr & 0xff)
|
switch (address & 0xff)
|
||||||
{
|
{
|
||||||
case DSP_DMBH:
|
case DSP_DMBH:
|
||||||
return gdsp_mbox_read_h(MAILBOX_DSP);
|
return ReadMailboxHigh(MAILBOX_DSP);
|
||||||
|
|
||||||
case DSP_DMBL:
|
case DSP_DMBL:
|
||||||
return gdsp_mbox_read_l(MAILBOX_DSP);
|
return ReadMailboxLow(MAILBOX_DSP);
|
||||||
|
|
||||||
case DSP_CMBH:
|
case DSP_CMBH:
|
||||||
return gdsp_mbox_read_h(MAILBOX_CPU);
|
return ReadMailboxHigh(MAILBOX_CPU);
|
||||||
|
|
||||||
case DSP_CMBL:
|
case DSP_CMBL:
|
||||||
return gdsp_mbox_read_l(MAILBOX_CPU);
|
return ReadMailboxLow(MAILBOX_CPU);
|
||||||
|
|
||||||
case DSP_DSCR:
|
case DSP_DSCR:
|
||||||
return g_dsp.ifx_regs[addr & 0xFF];
|
return ifx_regs[address & 0xFF];
|
||||||
|
|
||||||
case DSP_ACSAH:
|
case DSP_ACSAH:
|
||||||
return static_cast<u16>(g_dsp.accelerator->GetStartAddress() >> 16);
|
return static_cast<u16>(accelerator->GetStartAddress() >> 16);
|
||||||
case DSP_ACSAL:
|
case DSP_ACSAL:
|
||||||
return static_cast<u16>(g_dsp.accelerator->GetStartAddress());
|
return static_cast<u16>(accelerator->GetStartAddress());
|
||||||
case DSP_ACEAH:
|
case DSP_ACEAH:
|
||||||
return static_cast<u16>(g_dsp.accelerator->GetEndAddress() >> 16);
|
return static_cast<u16>(accelerator->GetEndAddress() >> 16);
|
||||||
case DSP_ACEAL:
|
case DSP_ACEAL:
|
||||||
return static_cast<u16>(g_dsp.accelerator->GetEndAddress());
|
return static_cast<u16>(accelerator->GetEndAddress());
|
||||||
case DSP_ACCAH:
|
case DSP_ACCAH:
|
||||||
return static_cast<u16>(g_dsp.accelerator->GetCurrentAddress() >> 16);
|
return static_cast<u16>(accelerator->GetCurrentAddress() >> 16);
|
||||||
case DSP_ACCAL:
|
case DSP_ACCAL:
|
||||||
return static_cast<u16>(g_dsp.accelerator->GetCurrentAddress());
|
return static_cast<u16>(accelerator->GetCurrentAddress());
|
||||||
case DSP_FORMAT:
|
case DSP_FORMAT:
|
||||||
return g_dsp.accelerator->GetSampleFormat();
|
return accelerator->GetSampleFormat();
|
||||||
case DSP_YN1:
|
case DSP_YN1:
|
||||||
return g_dsp.accelerator->GetYn1();
|
return accelerator->GetYn1();
|
||||||
case DSP_YN2:
|
case DSP_YN2:
|
||||||
return g_dsp.accelerator->GetYn2();
|
return accelerator->GetYn2();
|
||||||
case DSP_PRED_SCALE:
|
case DSP_PRED_SCALE:
|
||||||
return g_dsp.accelerator->GetPredScale();
|
return accelerator->GetPredScale();
|
||||||
case DSP_ACCELERATOR: // ADPCM Accelerator reads
|
case DSP_ACCELERATOR: // ADPCM Accelerator reads
|
||||||
return g_dsp.accelerator->Read(reinterpret_cast<s16*>(&g_dsp.ifx_regs[DSP_COEF_A1_0]));
|
return accelerator->Read(reinterpret_cast<s16*>(&ifx_regs[DSP_COEF_A1_0]));
|
||||||
case DSP_ACDATA1: // Accelerator reads (Zelda type) - "UnkZelda"
|
case DSP_ACDATA1: // Accelerator reads (Zelda type) - "UnkZelda"
|
||||||
return g_dsp.accelerator->ReadD3();
|
return accelerator->ReadD3();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
const u16 ifx_reg = g_dsp.ifx_regs[addr & 0xFF];
|
const u16 ifx_reg = ifx_regs[address & 0xFF];
|
||||||
|
|
||||||
if ((addr & 0xff) >= 0xa0)
|
if ((address & 0xff) >= 0xa0)
|
||||||
{
|
{
|
||||||
const u32 index = (addr & 0xFF) - 0xa0;
|
const u32 index = (address & 0xFF) - 0xa0;
|
||||||
const auto& label = pdlabels[index];
|
const auto& label = pdlabels[index];
|
||||||
|
|
||||||
if (label.name && label.description)
|
if (label.name && label.description)
|
||||||
{
|
{
|
||||||
DEBUG_LOG_FMT(DSPLLE, "{:04x} MR {} ({:04x})", g_dsp.pc, label.name, ifx_reg);
|
DEBUG_LOG_FMT(DSPLLE, "{:04x} MR {} ({:04x})", pc, label.name, ifx_reg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(DSPLLE, "{:04x} MR {:04x} ({:04x})", g_dsp.pc, addr, ifx_reg);
|
ERROR_LOG_FMT(DSPLLE, "{:04x} MR {:04x} ({:04x})", pc, address, ifx_reg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(DSPLLE, "{:04x} MR {:04x} ({:04x})", g_dsp.pc, addr, ifx_reg);
|
ERROR_LOG_FMT(DSPLLE, "{:04x} MR {:04x} ({:04x})", pc, address, ifx_reg);
|
||||||
}
|
}
|
||||||
return ifx_reg;
|
return ifx_reg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 gdsp_ifx_read(u16 addr)
|
u16 SDSP::ReadIFX(u16 address)
|
||||||
{
|
{
|
||||||
u16 retval = _gdsp_ifx_read(addr);
|
const u16 retval = ReadIFXImpl(address);
|
||||||
g_dsp_cap->LogIFXRead(addr, retval);
|
m_dsp_core.LogIFXRead(address, retval);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const u8* gdsp_idma_in(u16 dsp_addr, u32 addr, u32 size)
|
const u8* SDSP::IDMAIn(u16 dsp_addr, u32 addr, u32 size)
|
||||||
{
|
{
|
||||||
Common::UnWriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false);
|
Common::UnWriteProtectMemory(iram, DSP_IRAM_BYTE_SIZE, false);
|
||||||
Host::DMAToDSP(g_dsp.iram + dsp_addr / 2, addr, size);
|
Host::DMAToDSP(iram + dsp_addr / 2, addr, size);
|
||||||
Common::WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false);
|
Common::WriteProtectMemory(iram, DSP_IRAM_BYTE_SIZE, false);
|
||||||
|
|
||||||
Host::CodeLoaded(addr, size);
|
Host::CodeLoaded(m_dsp_core, addr, size);
|
||||||
NOTICE_LOG_FMT(DSPLLE, "*** Copy new UCode from {:#010x} to {:#06x} (crc: {:#08x})", addr,
|
NOTICE_LOG_FMT(DSPLLE, "*** Copy new UCode from {:#010x} to {:#06x} (crc: {:#08x})", addr,
|
||||||
dsp_addr, g_dsp.iram_crc);
|
dsp_addr, iram_crc);
|
||||||
|
|
||||||
return reinterpret_cast<u8*>(g_dsp.iram) + dsp_addr;
|
return reinterpret_cast<const u8*>(iram) + dsp_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const u8* gdsp_idma_out(u16 dsp_addr, u32 addr, u32 size)
|
const u8* SDSP::IDMAOut(u16 dsp_addr, u32 addr, u32 size)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(DSPLLE, "*** idma_out IRAM_DSP ({:#06x}) -> RAM ({:#010x}) : size ({:#010x})",
|
ERROR_LOG_FMT(DSPLLE, "*** idma_out IRAM_DSP ({:#06x}) -> RAM ({:#010x}) : size ({:#010x})",
|
||||||
dsp_addr / 2, addr, size);
|
dsp_addr / 2, addr, size);
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: These should eat clock cycles.
|
// TODO: These should eat clock cycles.
|
||||||
static const u8* gdsp_ddma_in(u16 dsp_addr, u32 addr, u32 size)
|
const u8* SDSP::DDMAIn(u16 dsp_addr, u32 addr, u32 size)
|
||||||
{
|
{
|
||||||
Host::DMAToDSP(g_dsp.dram + dsp_addr / 2, addr, size);
|
Host::DMAToDSP(dram + dsp_addr / 2, addr, size);
|
||||||
DEBUG_LOG_FMT(DSPLLE, "*** ddma_in RAM ({:#010x}) -> DRAM_DSP ({:#06x}) : size ({:#010x})", addr,
|
DEBUG_LOG_FMT(DSPLLE, "*** ddma_in RAM ({:#010x}) -> DRAM_DSP ({:#06x}) : size ({:#010x})", addr,
|
||||||
dsp_addr / 2, size);
|
dsp_addr / 2, size);
|
||||||
|
|
||||||
return reinterpret_cast<u8*>(g_dsp.dram) + dsp_addr;
|
return reinterpret_cast<const u8*>(dram) + dsp_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const u8* gdsp_ddma_out(u16 dsp_addr, u32 addr, u32 size)
|
const u8* SDSP::DDMAOut(u16 dsp_addr, u32 addr, u32 size)
|
||||||
{
|
{
|
||||||
Host::DMAFromDSP(g_dsp.dram + dsp_addr / 2, addr, size);
|
Host::DMAFromDSP(dram + dsp_addr / 2, addr, size);
|
||||||
DEBUG_LOG_FMT(DSPLLE, "*** ddma_out DRAM_DSP ({:#06x}) -> RAM ({:#010x}) : size ({:#010x})",
|
DEBUG_LOG_FMT(DSPLLE, "*** ddma_out DRAM_DSP ({:#06x}) -> RAM ({:#010x}) : size ({:#010x})",
|
||||||
dsp_addr / 2, addr, size);
|
dsp_addr / 2, addr, size);
|
||||||
|
|
||||||
return reinterpret_cast<const u8*>(g_dsp.dram) + dsp_addr;
|
return reinterpret_cast<const u8*>(dram) + dsp_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gdsp_do_dma()
|
void SDSP::DoDMA()
|
||||||
{
|
{
|
||||||
const u32 addr = (g_dsp.ifx_regs[DSP_DSMAH] << 16) | g_dsp.ifx_regs[DSP_DSMAL];
|
const u32 addr = (ifx_regs[DSP_DSMAH] << 16) | ifx_regs[DSP_DSMAL];
|
||||||
const u16 ctl = g_dsp.ifx_regs[DSP_DSCR];
|
const u16 ctl = ifx_regs[DSP_DSCR];
|
||||||
const u16 dsp_addr = g_dsp.ifx_regs[DSP_DSPA] * 2;
|
const u16 dsp_addr = ifx_regs[DSP_DSPA] * 2;
|
||||||
const u16 len = g_dsp.ifx_regs[DSP_DSBL];
|
const u16 len = ifx_regs[DSP_DSBL];
|
||||||
|
|
||||||
if (len > 0x4000)
|
if (len > 0x4000)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(DSPLLE,
|
ERROR_LOG_FMT(DSPLLE,
|
||||||
"DMA ERROR: PC: {:04x}, Control: {:04x}, Address: {:08x}, DSP Address: {:04x}, "
|
"DMA ERROR: PC: {:04x}, Control: {:04x}, Address: {:08x}, DSP Address: {:04x}, "
|
||||||
"Size: {:04x}",
|
"Size: {:04x}",
|
||||||
g_dsp.pc, ctl, addr, dsp_addr, len);
|
pc, ctl, addr, dsp_addr, len);
|
||||||
std::exit(0);
|
std::exit(0);
|
||||||
}
|
}
|
||||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||||
DEBUG_LOG_FMT(
|
DEBUG_LOG_FMT(
|
||||||
DSPLLE, "DMA pc: {:04x}, Control: {:04x}, Address: {:08x}, DSP Address: {:04x}, Size: {:04x}",
|
DSPLLE, "DMA pc: {:04x}, Control: {:04x}, Address: {:08x}, DSP Address: {:04x}, Size: {:04x}",
|
||||||
g_dsp.pc, ctl, addr, dsp_addr, len);
|
pc, ctl, addr, dsp_addr, len);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const u8* copied_data_ptr = nullptr;
|
const u8* copied_data_ptr = nullptr;
|
||||||
switch (ctl & 0x3)
|
switch (ctl & 0x3)
|
||||||
{
|
{
|
||||||
case (DSP_CR_DMEM | DSP_CR_TO_CPU):
|
case (DSP_CR_DMEM | DSP_CR_TO_CPU):
|
||||||
copied_data_ptr = gdsp_ddma_out(dsp_addr, addr, len);
|
copied_data_ptr = DDMAOut(dsp_addr, addr, len);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case (DSP_CR_DMEM | DSP_CR_FROM_CPU):
|
case (DSP_CR_DMEM | DSP_CR_FROM_CPU):
|
||||||
copied_data_ptr = gdsp_ddma_in(dsp_addr, addr, len);
|
copied_data_ptr = DDMAIn(dsp_addr, addr, len);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case (DSP_CR_IMEM | DSP_CR_TO_CPU):
|
case (DSP_CR_IMEM | DSP_CR_TO_CPU):
|
||||||
copied_data_ptr = gdsp_idma_out(dsp_addr, addr, len);
|
copied_data_ptr = IDMAOut(dsp_addr, addr, len);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case (DSP_CR_IMEM | DSP_CR_FROM_CPU):
|
case (DSP_CR_IMEM | DSP_CR_FROM_CPU):
|
||||||
copied_data_ptr = gdsp_idma_in(dsp_addr, addr, len);
|
copied_data_ptr = IDMAIn(dsp_addr, addr, len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (copied_data_ptr)
|
if (copied_data_ptr)
|
||||||
g_dsp_cap->LogDMA(ctl, addr, dsp_addr, len, copied_data_ptr);
|
m_dsp_core.LogDMA(ctl, addr, dsp_addr, len, copied_data_ptr);
|
||||||
}
|
}
|
||||||
} // namespace DSP
|
} // namespace DSP
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
// Copyright 2008 Dolphin Emulator Project
|
|
||||||
// Copyright 2004 Duddie & Tratax
|
|
||||||
// Licensed under GPLv2+
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
|
||||||
|
|
||||||
namespace DSP
|
|
||||||
{
|
|
||||||
enum Mailbox
|
|
||||||
{
|
|
||||||
MAILBOX_CPU,
|
|
||||||
MAILBOX_DSP
|
|
||||||
};
|
|
||||||
|
|
||||||
u32 gdsp_mbox_peek(Mailbox mbx);
|
|
||||||
void gdsp_mbox_write_h(Mailbox mbx, u16 val);
|
|
||||||
void gdsp_mbox_write_l(Mailbox mbx, u16 val);
|
|
||||||
u16 gdsp_mbox_read_h(Mailbox mbx);
|
|
||||||
u16 gdsp_mbox_read_l(Mailbox mbx);
|
|
||||||
|
|
||||||
void gdsp_ifx_init();
|
|
||||||
void gdsp_ifx_write(u32 addr, u16 val);
|
|
||||||
u16 gdsp_ifx_read(u16 addr);
|
|
||||||
} // namespace DSP
|
|
|
@ -13,6 +13,11 @@
|
||||||
// core isn't used, for example in an asm/disasm tool, then most of these
|
// core isn't used, for example in an asm/disasm tool, then most of these
|
||||||
// can be stubbed out.
|
// can be stubbed out.
|
||||||
|
|
||||||
|
namespace DSP
|
||||||
|
{
|
||||||
|
class DSPCore;
|
||||||
|
}
|
||||||
|
|
||||||
namespace DSP::Host
|
namespace DSP::Host
|
||||||
{
|
{
|
||||||
u8 ReadHostMemory(u32 addr);
|
u8 ReadHostMemory(u32 addr);
|
||||||
|
@ -23,7 +28,7 @@ void OSD_AddMessage(std::string str, u32 ms);
|
||||||
bool OnThread();
|
bool OnThread();
|
||||||
bool IsWiiHost();
|
bool IsWiiHost();
|
||||||
void InterruptRequest();
|
void InterruptRequest();
|
||||||
void CodeLoaded(u32 addr, size_t size);
|
void CodeLoaded(DSPCore& dsp, u32 addr, size_t size);
|
||||||
void CodeLoaded(const u8* ptr, size_t size);
|
void CodeLoaded(DSPCore& dsp, const u8* ptr, size_t size);
|
||||||
void UpdateDebugger();
|
void UpdateDebugger();
|
||||||
} // namespace DSP::Host
|
} // namespace DSP::Host
|
||||||
|
|
|
@ -3,86 +3,81 @@
|
||||||
// Licensed under GPLv2+
|
// Licensed under GPLv2+
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include "Core/DSP/DSPMemoryMap.h"
|
|
||||||
|
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
|
|
||||||
#include "Core/DSP/DSPCore.h"
|
#include "Core/DSP/DSPCore.h"
|
||||||
#include "Core/DSP/DSPHWInterface.h"
|
|
||||||
#include "Core/DSP/DSPTables.h"
|
#include "Core/DSP/DSPTables.h"
|
||||||
|
|
||||||
namespace DSP
|
namespace DSP
|
||||||
{
|
{
|
||||||
u16 dsp_imem_read(u16 addr)
|
u16 SDSP::ReadIMEM(u16 address) const
|
||||||
{
|
{
|
||||||
switch (addr >> 12)
|
switch (address >> 12)
|
||||||
{
|
{
|
||||||
case 0: // 0xxx IRAM
|
case 0: // 0xxx IRAM
|
||||||
return g_dsp.iram[addr & DSP_IRAM_MASK];
|
return iram[address & DSP_IRAM_MASK];
|
||||||
|
|
||||||
case 8: // 8xxx IROM - contains code to receive code for IRAM, and a bunch of mixing loops.
|
case 8: // 8xxx IROM - contains code to receive code for IRAM, and a bunch of mixing loops.
|
||||||
return g_dsp.irom[addr & DSP_IROM_MASK];
|
return irom[address & DSP_IROM_MASK];
|
||||||
|
|
||||||
default: // Unmapped/non-existing memory
|
default: // Unmapped/non-existing memory
|
||||||
ERROR_LOG_FMT(DSPLLE, "{:04x} DSP ERROR: Executing from invalid ({:04x}) memory", g_dsp.pc,
|
ERROR_LOG_FMT(DSPLLE, "{:04x} DSP ERROR: Executing from invalid ({:04x}) memory", pc, address);
|
||||||
addr);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 dsp_dmem_read(u16 addr)
|
u16 SDSP::ReadDMEM(u16 address)
|
||||||
{
|
{
|
||||||
switch (addr >> 12)
|
switch (address >> 12)
|
||||||
{
|
{
|
||||||
case 0x0: // 0xxx DRAM
|
case 0x0: // 0xxx DRAM
|
||||||
return g_dsp.dram[addr & DSP_DRAM_MASK];
|
return dram[address & DSP_DRAM_MASK];
|
||||||
|
|
||||||
case 0x1: // 1xxx COEF
|
case 0x1: // 1xxx COEF
|
||||||
DEBUG_LOG_FMT(DSPLLE, "{:04x} : Coefficient Read @ {:04x}", g_dsp.pc, addr);
|
DEBUG_LOG_FMT(DSPLLE, "{:04x} : Coefficient Read @ {:04x}", pc, address);
|
||||||
return g_dsp.coef[addr & DSP_COEF_MASK];
|
return coef[address & DSP_COEF_MASK];
|
||||||
|
|
||||||
case 0xf: // Fxxx HW regs
|
case 0xf: // Fxxx HW regs
|
||||||
return gdsp_ifx_read(addr);
|
return ReadIFX(address);
|
||||||
|
|
||||||
default: // Unmapped/non-existing memory
|
default: // Unmapped/non-existing memory
|
||||||
ERROR_LOG_FMT(DSPLLE, "{:04x} DSP ERROR: Read from UNKNOWN ({:04x}) memory", g_dsp.pc, addr);
|
ERROR_LOG_FMT(DSPLLE, "{:04x} DSP ERROR: Read from UNKNOWN ({:04x}) memory", pc, address);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dsp_dmem_write(u16 addr, u16 val)
|
void SDSP::WriteDMEM(u16 address, u16 value)
|
||||||
{
|
{
|
||||||
switch (addr >> 12)
|
switch (address >> 12)
|
||||||
{
|
{
|
||||||
case 0x0: // 0xxx DRAM
|
case 0x0: // 0xxx DRAM
|
||||||
g_dsp.dram[addr & DSP_DRAM_MASK] = val;
|
dram[address & DSP_DRAM_MASK] = value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xf: // Fxxx HW regs
|
case 0xf: // Fxxx HW regs
|
||||||
gdsp_ifx_write(addr, val);
|
WriteIFX(address, value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: // Unmapped/non-existing memory
|
default: // Unmapped/non-existing memory
|
||||||
ERROR_LOG_FMT(DSPLLE, "{:04x} DSP ERROR: Write to UNKNOWN ({:04x}) memory", g_dsp.pc, addr);
|
ERROR_LOG_FMT(DSPLLE, "{:04x} DSP ERROR: Write to UNKNOWN ({:04x}) memory", pc, address);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 dsp_fetch_code()
|
u16 SDSP::FetchInstruction()
|
||||||
{
|
{
|
||||||
u16 opc = dsp_imem_read(g_dsp.pc);
|
const u16 opc = PeekInstruction();
|
||||||
|
pc++;
|
||||||
g_dsp.pc++;
|
|
||||||
return opc;
|
return opc;
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 dsp_peek_code()
|
u16 SDSP::PeekInstruction() const
|
||||||
{
|
{
|
||||||
return dsp_imem_read(g_dsp.pc);
|
return ReadIMEM(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dsp_skip_inst()
|
void SDSP::SkipInstruction()
|
||||||
{
|
{
|
||||||
g_dsp.pc += GetOpTemplate(dsp_peek_code())->size;
|
pc += GetOpTemplate(PeekInstruction())->size;
|
||||||
}
|
}
|
||||||
} // namespace DSP
|
} // namespace DSP
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
// Copyright 2008 Dolphin Emulator Project
|
|
||||||
// Copyright 2004 Duddie & Tratax
|
|
||||||
// Licensed under GPLv2+
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
|
||||||
|
|
||||||
namespace DSP
|
|
||||||
{
|
|
||||||
u16 dsp_imem_read(u16 addr);
|
|
||||||
void dsp_dmem_write(u16 addr, u16 val);
|
|
||||||
u16 dsp_dmem_read(u16 addr);
|
|
||||||
|
|
||||||
u16 dsp_fetch_code();
|
|
||||||
u16 dsp_peek_code();
|
|
||||||
void dsp_skip_inst();
|
|
||||||
} // namespace DSP
|
|
|
@ -3,8 +3,6 @@
|
||||||
// Licensed under GPLv2+
|
// Licensed under GPLv2+
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include "Core/DSP/DSPStacks.h"
|
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
@ -13,34 +11,26 @@
|
||||||
// Stacks. The stacks are outside the DSP RAM, in dedicated hardware.
|
// Stacks. The stacks are outside the DSP RAM, in dedicated hardware.
|
||||||
namespace DSP
|
namespace DSP
|
||||||
{
|
{
|
||||||
static void dsp_reg_stack_push(size_t stack_reg)
|
void SDSP::StoreStack(StackRegister stack_reg, u16 val)
|
||||||
{
|
|
||||||
g_dsp.reg_stack_ptrs[stack_reg]++;
|
|
||||||
g_dsp.reg_stack_ptrs[stack_reg] &= DSP_STACK_MASK;
|
|
||||||
g_dsp.reg_stacks[stack_reg][g_dsp.reg_stack_ptrs[stack_reg]] = g_dsp.r.st[stack_reg];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dsp_reg_stack_pop(size_t stack_reg)
|
|
||||||
{
|
|
||||||
g_dsp.r.st[stack_reg] = g_dsp.reg_stacks[stack_reg][g_dsp.reg_stack_ptrs[stack_reg]];
|
|
||||||
g_dsp.reg_stack_ptrs[stack_reg]--;
|
|
||||||
g_dsp.reg_stack_ptrs[stack_reg] &= DSP_STACK_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dsp_reg_store_stack(StackRegister stack_reg, u16 val)
|
|
||||||
{
|
{
|
||||||
const auto reg_index = static_cast<size_t>(stack_reg);
|
const auto reg_index = static_cast<size_t>(stack_reg);
|
||||||
|
|
||||||
dsp_reg_stack_push(reg_index);
|
reg_stack_ptrs[reg_index]++;
|
||||||
g_dsp.r.st[reg_index] = val;
|
reg_stack_ptrs[reg_index] &= DSP_STACK_MASK;
|
||||||
|
reg_stacks[reg_index][reg_stack_ptrs[reg_index]] = r.st[reg_index];
|
||||||
|
|
||||||
|
r.st[reg_index] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 dsp_reg_load_stack(StackRegister stack_reg)
|
u16 SDSP::PopStack(StackRegister stack_reg)
|
||||||
{
|
{
|
||||||
const auto reg_index = static_cast<size_t>(stack_reg);
|
const auto reg_index = static_cast<size_t>(stack_reg);
|
||||||
|
const u16 val = r.st[reg_index];
|
||||||
|
|
||||||
|
r.st[reg_index] = reg_stacks[reg_index][reg_stack_ptrs[reg_index]];
|
||||||
|
reg_stack_ptrs[reg_index]--;
|
||||||
|
reg_stack_ptrs[reg_index] &= DSP_STACK_MASK;
|
||||||
|
|
||||||
const u16 val = g_dsp.r.st[reg_index];
|
|
||||||
dsp_reg_stack_pop(reg_index);
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
} // namespace DSP
|
} // namespace DSP
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
// Copyright 2008 Dolphin Emulator Project
|
|
||||||
// Copyright 2004 Duddie & Tratax
|
|
||||||
// Licensed under GPLv2+
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
|
||||||
|
|
||||||
namespace DSP
|
|
||||||
{
|
|
||||||
enum class StackRegister;
|
|
||||||
|
|
||||||
void dsp_reg_store_stack(StackRegister stack_reg, u16 val);
|
|
||||||
u16 dsp_reg_load_stack(StackRegister stack_reg);
|
|
||||||
} // namespace DSP
|
|
|
@ -477,9 +477,6 @@ const std::array<pdlabel_t, 36> regnames =
|
||||||
}};
|
}};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
std::array<u16, WRITEBACK_LOG_SIZE> writeBackLog;
|
|
||||||
std::array<int, WRITEBACK_LOG_SIZE> writeBackLogIdx;
|
|
||||||
|
|
||||||
const char* pdname(u16 val)
|
const char* pdname(u16 val)
|
||||||
{
|
{
|
||||||
static char tmpstr[12]; // nasty
|
static char tmpstr[12]; // nasty
|
||||||
|
@ -612,10 +609,5 @@ void InitInstructionTable()
|
||||||
else
|
else
|
||||||
ERROR_LOG_FMT(DSPLLE, "opcode table place {} already in use for {}", i, iter->name);
|
ERROR_LOG_FMT(DSPLLE, "opcode table place {} already in use for {}", i, iter->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
writeBackLogIdx.fill(-1);
|
|
||||||
|
|
||||||
// Ensure the interpreter tables are all set up, as JITs also rely on them.
|
|
||||||
Interpreter::InitInstructionTables();
|
|
||||||
}
|
}
|
||||||
} // namespace DSP
|
} // namespace DSP
|
||||||
|
|
|
@ -85,10 +85,6 @@ struct DSPOPCTemplate
|
||||||
// Opcodes
|
// Opcodes
|
||||||
extern const DSPOPCTemplate cw;
|
extern const DSPOPCTemplate cw;
|
||||||
|
|
||||||
constexpr size_t WRITEBACK_LOG_SIZE = 5;
|
|
||||||
extern std::array<u16, WRITEBACK_LOG_SIZE> writeBackLog;
|
|
||||||
extern std::array<int, WRITEBACK_LOG_SIZE> writeBackLogIdx;
|
|
||||||
|
|
||||||
// Predefined labels
|
// Predefined labels
|
||||||
struct pdlabel_t
|
struct pdlabel_t
|
||||||
{
|
{
|
||||||
|
@ -105,9 +101,6 @@ const char* pdregname(int val);
|
||||||
const char* pdregnamelong(int val);
|
const char* pdregnamelong(int val);
|
||||||
|
|
||||||
void InitInstructionTable();
|
void InitInstructionTable();
|
||||||
void ApplyWriteBackLog();
|
|
||||||
void ZeroWriteBackLog();
|
|
||||||
void ZeroWriteBackLogPreserveAcc(u8 acc);
|
|
||||||
|
|
||||||
// Used by the assembler and disassembler for info retrieval.
|
// Used by the assembler and disassembler for info retrieval.
|
||||||
const DSPOPCTemplate* FindOpInfoByOpcode(UDSPInstruction opcode);
|
const DSPOPCTemplate* FindOpInfoByOpcode(UDSPInstruction opcode);
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,10 +5,6 @@
|
||||||
// Additional copyrights go to Duddie and Tratax (c) 2004
|
// Additional copyrights go to Duddie and Tratax (c) 2004
|
||||||
|
|
||||||
#include "Core/DSP/DSPCore.h"
|
#include "Core/DSP/DSPCore.h"
|
||||||
#include "Core/DSP/DSPMemoryMap.h"
|
|
||||||
#include "Core/DSP/DSPStacks.h"
|
|
||||||
#include "Core/DSP/Interpreter/DSPIntCCUtil.h"
|
|
||||||
#include "Core/DSP/Interpreter/DSPIntUtil.h"
|
|
||||||
#include "Core/DSP/Interpreter/DSPInterpreter.h"
|
#include "Core/DSP/Interpreter/DSPInterpreter.h"
|
||||||
|
|
||||||
namespace DSP::Interpreter
|
namespace DSP::Interpreter
|
||||||
|
@ -20,14 +16,16 @@ namespace DSP::Interpreter
|
||||||
// Call function if condition cc has been met. Push program counter of
|
// Call function if condition cc has been met. Push program counter of
|
||||||
// instruction following "call" to $st0. Set program counter to address
|
// instruction following "call" to $st0. Set program counter to address
|
||||||
// represented by value that follows this "call" instruction.
|
// represented by value that follows this "call" instruction.
|
||||||
void call(const UDSPInstruction opc)
|
void Interpreter::call(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
// must be outside the if.
|
// must be outside the if.
|
||||||
u16 dest = dsp_fetch_code();
|
const u16 dest = state.FetchInstruction();
|
||||||
if (CheckCondition(opc & 0xf))
|
if (CheckCondition(opc & 0xf))
|
||||||
{
|
{
|
||||||
dsp_reg_store_stack(StackRegister::Call, g_dsp.pc);
|
state.StoreStack(StackRegister::Call, state.pc);
|
||||||
g_dsp.pc = dest;
|
state.pc = dest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,28 +35,29 @@ void call(const UDSPInstruction opc)
|
||||||
// Call function if condition cc has been met. Push program counter of
|
// Call function if condition cc has been met. Push program counter of
|
||||||
// instruction following "call" to call stack $st0. Set program counter to
|
// instruction following "call" to call stack $st0. Set program counter to
|
||||||
// register $R.
|
// register $R.
|
||||||
void callr(const UDSPInstruction opc)
|
void Interpreter::callr(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
if (CheckCondition(opc & 0xf))
|
if (!CheckCondition(opc & 0xf))
|
||||||
{
|
return;
|
||||||
u8 reg = (opc >> 5) & 0x7;
|
|
||||||
u16 addr = dsp_op_read_reg(reg);
|
auto& state = m_dsp_core.DSPState();
|
||||||
dsp_reg_store_stack(StackRegister::Call, g_dsp.pc);
|
const u8 reg = (opc >> 5) & 0x7;
|
||||||
g_dsp.pc = addr;
|
const u16 addr = OpReadRegister(reg);
|
||||||
}
|
state.StoreStack(StackRegister::Call, state.pc);
|
||||||
|
state.pc = addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic if implementation
|
// Generic if implementation
|
||||||
// IFcc
|
// IFcc
|
||||||
// 0000 0010 0111 cccc
|
// 0000 0010 0111 cccc
|
||||||
// Execute following opcode if the condition has been met.
|
// Execute following opcode if the condition has been met.
|
||||||
void ifcc(const UDSPInstruction opc)
|
void Interpreter::ifcc(const UDSPInstruction opc)
|
||||||
{
|
|
||||||
if (!CheckCondition(opc & 0xf))
|
|
||||||
{
|
{
|
||||||
|
if (CheckCondition(opc & 0xf))
|
||||||
|
return;
|
||||||
|
|
||||||
// skip the next opcode - we have to lookup its size.
|
// skip the next opcode - we have to lookup its size.
|
||||||
dsp_skip_inst();
|
m_dsp_core.DSPState().SkipInstruction();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic jmp implementation
|
// Generic jmp implementation
|
||||||
|
@ -67,12 +66,13 @@ void ifcc(const UDSPInstruction opc)
|
||||||
// aaaa aaaa aaaa aaaa
|
// aaaa aaaa aaaa aaaa
|
||||||
// Jump to addressA if condition cc has been met. Set program counter to
|
// Jump to addressA if condition cc has been met. Set program counter to
|
||||||
// address represented by value that follows this "jmp" instruction.
|
// address represented by value that follows this "jmp" instruction.
|
||||||
void jcc(const UDSPInstruction opc)
|
void Interpreter::jcc(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u16 dest = dsp_fetch_code();
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
const u16 dest = state.FetchInstruction();
|
||||||
if (CheckCondition(opc & 0xf))
|
if (CheckCondition(opc & 0xf))
|
||||||
{
|
{
|
||||||
g_dsp.pc = dest;
|
state.pc = dest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,13 +80,14 @@ void jcc(const UDSPInstruction opc)
|
||||||
// JMPcc $R
|
// JMPcc $R
|
||||||
// 0001 0111 rrr0 cccc
|
// 0001 0111 rrr0 cccc
|
||||||
// Jump to address; set program counter to a value from register $R.
|
// Jump to address; set program counter to a value from register $R.
|
||||||
void jmprcc(const UDSPInstruction opc)
|
void Interpreter::jmprcc(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
if (CheckCondition(opc & 0xf))
|
if (!CheckCondition(opc & 0xf))
|
||||||
{
|
return;
|
||||||
u8 reg = (opc >> 5) & 0x7;
|
|
||||||
g_dsp.pc = dsp_op_read_reg(reg);
|
auto& state = m_dsp_core.DSPState();
|
||||||
}
|
const u8 reg = (opc >> 5) & 0x7;
|
||||||
|
state.pc = OpReadRegister(reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic ret implementation
|
// Generic ret implementation
|
||||||
|
@ -94,12 +95,13 @@ void jmprcc(const UDSPInstruction opc)
|
||||||
// 0000 0010 1101 cccc
|
// 0000 0010 1101 cccc
|
||||||
// Return from subroutine if condition cc has been met. Pops stored PC
|
// Return from subroutine if condition cc has been met. Pops stored PC
|
||||||
// from call stack $st0 and sets $pc to this location.
|
// from call stack $st0 and sets $pc to this location.
|
||||||
void ret(const UDSPInstruction opc)
|
void Interpreter::ret(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
if (CheckCondition(opc & 0xf))
|
if (!CheckCondition(opc & 0xf))
|
||||||
{
|
return;
|
||||||
g_dsp.pc = dsp_reg_load_stack(StackRegister::Call);
|
|
||||||
}
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
state.pc = state.PopStack(StackRegister::Call);
|
||||||
}
|
}
|
||||||
|
|
||||||
// RTI
|
// RTI
|
||||||
|
@ -107,19 +109,21 @@ void ret(const UDSPInstruction opc)
|
||||||
// Return from exception. Pops stored status register $sr from data stack
|
// Return from exception. Pops stored status register $sr from data stack
|
||||||
// $st1 and program counter PC from call stack $st0 and sets $pc to this
|
// $st1 and program counter PC from call stack $st0 and sets $pc to this
|
||||||
// location.
|
// location.
|
||||||
void rti(const UDSPInstruction opc)
|
void Interpreter::rti(const UDSPInstruction)
|
||||||
{
|
{
|
||||||
g_dsp.r.sr = dsp_reg_load_stack(StackRegister::Data);
|
auto& state = m_dsp_core.DSPState();
|
||||||
g_dsp.pc = dsp_reg_load_stack(StackRegister::Call);
|
state.r.sr = state.PopStack(StackRegister::Data);
|
||||||
|
state.pc = state.PopStack(StackRegister::Call);
|
||||||
}
|
}
|
||||||
|
|
||||||
// HALT
|
// HALT
|
||||||
// 0000 0000 0020 0001
|
// 0000 0000 0020 0001
|
||||||
// Stops execution of DSP code. Sets bit DSP_CR_HALT in register DREG_CR.
|
// Stops execution of DSP code. Sets bit DSP_CR_HALT in register DREG_CR.
|
||||||
void halt(const UDSPInstruction opc)
|
void Interpreter::halt(const UDSPInstruction)
|
||||||
{
|
{
|
||||||
g_dsp.cr |= 0x4;
|
auto& state = m_dsp_core.DSPState();
|
||||||
g_dsp.pc--;
|
state.cr |= 0x4;
|
||||||
|
state.pc--;
|
||||||
}
|
}
|
||||||
|
|
||||||
// LOOP handling: Loop stack is used to control execution of repeated blocks of
|
// LOOP handling: Loop stack is used to control execution of repeated blocks of
|
||||||
|
@ -128,29 +132,31 @@ void halt(const UDSPInstruction opc)
|
||||||
// then PC is modified with value from call stack $st0. Otherwise values from
|
// then PC is modified with value from call stack $st0. Otherwise values from
|
||||||
// call stack $st0 and both loop stacks $st2 and $st3 are popped and execution
|
// call stack $st0 and both loop stacks $st2 and $st3 are popped and execution
|
||||||
// continues at next opcode.
|
// continues at next opcode.
|
||||||
void HandleLoop()
|
void Interpreter::HandleLoop()
|
||||||
{
|
{
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
// Handle looping hardware.
|
// Handle looping hardware.
|
||||||
const u16 rCallAddress = g_dsp.r.st[0];
|
const u16 rCallAddress = state.r.st[0];
|
||||||
const u16 rLoopAddress = g_dsp.r.st[2];
|
const u16 rLoopAddress = state.r.st[2];
|
||||||
u16& rLoopCounter = g_dsp.r.st[3];
|
u16& rLoopCounter = state.r.st[3];
|
||||||
|
|
||||||
if (rLoopAddress > 0 && rLoopCounter > 0)
|
if (rLoopAddress > 0 && rLoopCounter > 0)
|
||||||
{
|
{
|
||||||
// FIXME: why -1? because we just read past it.
|
// FIXME: why -1? because we just read past it.
|
||||||
if (g_dsp.pc - 1 == rLoopAddress)
|
if (state.pc - 1 == rLoopAddress)
|
||||||
{
|
{
|
||||||
rLoopCounter--;
|
rLoopCounter--;
|
||||||
if (rLoopCounter > 0)
|
if (rLoopCounter > 0)
|
||||||
{
|
{
|
||||||
g_dsp.pc = rCallAddress;
|
state.pc = rCallAddress;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// end of loop
|
// end of loop
|
||||||
dsp_reg_load_stack(StackRegister::Call);
|
state.PopStack(StackRegister::Call);
|
||||||
dsp_reg_load_stack(StackRegister::LoopAddress);
|
state.PopStack(StackRegister::LoopAddress);
|
||||||
dsp_reg_load_stack(StackRegister::LoopCounter);
|
state.PopStack(StackRegister::LoopCounter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,21 +170,22 @@ void HandleLoop()
|
||||||
// then looped instruction will not get executed.
|
// then looped instruction will not get executed.
|
||||||
// Actually, this instruction simply prepares the loop stacks for the above.
|
// Actually, this instruction simply prepares the loop stacks for the above.
|
||||||
// The looping hardware takes care of the rest.
|
// The looping hardware takes care of the rest.
|
||||||
void loop(const UDSPInstruction opc)
|
void Interpreter::loop(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u16 reg = opc & 0x1f;
|
auto& state = m_dsp_core.DSPState();
|
||||||
u16 cnt = dsp_op_read_reg(reg);
|
const u16 reg = opc & 0x1f;
|
||||||
u16 loop_pc = g_dsp.pc;
|
const u16 cnt = OpReadRegister(reg);
|
||||||
|
const u16 loop_pc = state.pc;
|
||||||
|
|
||||||
if (cnt)
|
if (cnt != 0)
|
||||||
{
|
{
|
||||||
dsp_reg_store_stack(StackRegister::Call, g_dsp.pc);
|
state.StoreStack(StackRegister::Call, state.pc);
|
||||||
dsp_reg_store_stack(StackRegister::LoopAddress, loop_pc);
|
state.StoreStack(StackRegister::LoopAddress, loop_pc);
|
||||||
dsp_reg_store_stack(StackRegister::LoopCounter, cnt);
|
state.StoreStack(StackRegister::LoopCounter, cnt);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dsp_skip_inst();
|
state.SkipInstruction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,20 +197,21 @@ void loop(const UDSPInstruction opc)
|
||||||
// instruction will not get executed.
|
// instruction will not get executed.
|
||||||
// Actually, this instruction simply prepares the loop stacks for the above.
|
// Actually, this instruction simply prepares the loop stacks for the above.
|
||||||
// The looping hardware takes care of the rest.
|
// The looping hardware takes care of the rest.
|
||||||
void loopi(const UDSPInstruction opc)
|
void Interpreter::loopi(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u16 cnt = opc & 0xff;
|
auto& state = m_dsp_core.DSPState();
|
||||||
u16 loop_pc = g_dsp.pc;
|
const u16 cnt = opc & 0xff;
|
||||||
|
const u16 loop_pc = state.pc;
|
||||||
|
|
||||||
if (cnt)
|
if (cnt != 0)
|
||||||
{
|
{
|
||||||
dsp_reg_store_stack(StackRegister::Call, g_dsp.pc);
|
state.StoreStack(StackRegister::Call, state.pc);
|
||||||
dsp_reg_store_stack(StackRegister::LoopAddress, loop_pc);
|
state.StoreStack(StackRegister::LoopAddress, loop_pc);
|
||||||
dsp_reg_store_stack(StackRegister::LoopCounter, cnt);
|
state.StoreStack(StackRegister::LoopCounter, cnt);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dsp_skip_inst();
|
state.SkipInstruction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,22 +224,23 @@ void loopi(const UDSPInstruction opc)
|
||||||
// included in loop. Counter is pushed on loop stack $st3, end of block address
|
// included in loop. Counter is pushed on loop stack $st3, end of block address
|
||||||
// is pushed on loop stack $st2 and repeat address is pushed on call stack $st0.
|
// is pushed on loop stack $st2 and repeat address is pushed on call stack $st0.
|
||||||
// Up to 4 nested loops are allowed.
|
// Up to 4 nested loops are allowed.
|
||||||
void bloop(const UDSPInstruction opc)
|
void Interpreter::bloop(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u16 reg = opc & 0x1f;
|
auto& state = m_dsp_core.DSPState();
|
||||||
u16 cnt = dsp_op_read_reg(reg);
|
const u16 reg = opc & 0x1f;
|
||||||
u16 loop_pc = dsp_fetch_code();
|
const u16 cnt = OpReadRegister(reg);
|
||||||
|
const u16 loop_pc = state.FetchInstruction();
|
||||||
|
|
||||||
if (cnt)
|
if (cnt != 0)
|
||||||
{
|
{
|
||||||
dsp_reg_store_stack(StackRegister::Call, g_dsp.pc);
|
state.StoreStack(StackRegister::Call, state.pc);
|
||||||
dsp_reg_store_stack(StackRegister::LoopAddress, loop_pc);
|
state.StoreStack(StackRegister::LoopAddress, loop_pc);
|
||||||
dsp_reg_store_stack(StackRegister::LoopCounter, cnt);
|
state.StoreStack(StackRegister::LoopCounter, cnt);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_dsp.pc = loop_pc;
|
state.pc = loop_pc;
|
||||||
dsp_skip_inst();
|
state.SkipInstruction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,21 +253,22 @@ void bloop(const UDSPInstruction opc)
|
||||||
// loop. Counter is pushed on loop stack $st3, end of block address is pushed
|
// loop. Counter is pushed on loop stack $st3, end of block address is pushed
|
||||||
// on loop stack $st2 and repeat address is pushed on call stack $st0. Up to 4
|
// on loop stack $st2 and repeat address is pushed on call stack $st0. Up to 4
|
||||||
// nested loops are allowed.
|
// nested loops are allowed.
|
||||||
void bloopi(const UDSPInstruction opc)
|
void Interpreter::bloopi(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u16 cnt = opc & 0xff;
|
auto& state = m_dsp_core.DSPState();
|
||||||
u16 loop_pc = dsp_fetch_code();
|
const u16 cnt = opc & 0xff;
|
||||||
|
const u16 loop_pc = state.FetchInstruction();
|
||||||
|
|
||||||
if (cnt)
|
if (cnt != 0)
|
||||||
{
|
{
|
||||||
dsp_reg_store_stack(StackRegister::Call, g_dsp.pc);
|
state.StoreStack(StackRegister::Call, state.pc);
|
||||||
dsp_reg_store_stack(StackRegister::LoopAddress, loop_pc);
|
state.StoreStack(StackRegister::LoopAddress, loop_pc);
|
||||||
dsp_reg_store_stack(StackRegister::LoopCounter, cnt);
|
state.StoreStack(StackRegister::LoopCounter, cnt);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_dsp.pc = loop_pc;
|
state.pc = loop_pc;
|
||||||
dsp_skip_inst();
|
state.SkipInstruction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace DSP::Interpreter
|
} // namespace DSP::Interpreter
|
||||||
|
|
|
@ -1,183 +0,0 @@
|
||||||
// Copyright 2009 Dolphin Emulator Project
|
|
||||||
// Licensed under GPLv2+
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
//
|
|
||||||
// Additional copyrights go to Duddie and Tratax (c) 2004
|
|
||||||
|
|
||||||
// HELPER FUNCTIONS
|
|
||||||
|
|
||||||
#include "Core/DSP/Interpreter/DSPIntCCUtil.h"
|
|
||||||
#include "Core/DSP/DSPCore.h"
|
|
||||||
|
|
||||||
namespace DSP::Interpreter
|
|
||||||
{
|
|
||||||
void Update_SR_Register64(s64 _Value, bool carry, bool overflow)
|
|
||||||
{
|
|
||||||
g_dsp.r.sr &= ~SR_CMP_MASK;
|
|
||||||
|
|
||||||
// 0x01
|
|
||||||
if (carry)
|
|
||||||
{
|
|
||||||
g_dsp.r.sr |= SR_CARRY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0x02 and 0x80
|
|
||||||
if (overflow)
|
|
||||||
{
|
|
||||||
g_dsp.r.sr |= SR_OVERFLOW;
|
|
||||||
g_dsp.r.sr |= SR_OVERFLOW_STICKY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0x04
|
|
||||||
if (_Value == 0)
|
|
||||||
{
|
|
||||||
g_dsp.r.sr |= SR_ARITH_ZERO;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0x08
|
|
||||||
if (_Value < 0)
|
|
||||||
{
|
|
||||||
g_dsp.r.sr |= SR_SIGN;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0x10
|
|
||||||
if (_Value != (s32)_Value)
|
|
||||||
{
|
|
||||||
g_dsp.r.sr |= SR_OVER_S32;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0x20 - Checks if top bits of m are equal
|
|
||||||
if (((_Value & 0xc0000000) == 0) || ((_Value & 0xc0000000) == 0xc0000000))
|
|
||||||
{
|
|
||||||
g_dsp.r.sr |= SR_TOP2BITS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Update_SR_Register16(s16 _Value, bool carry, bool overflow, bool overS32)
|
|
||||||
{
|
|
||||||
g_dsp.r.sr &= ~SR_CMP_MASK;
|
|
||||||
|
|
||||||
// 0x01
|
|
||||||
if (carry)
|
|
||||||
{
|
|
||||||
g_dsp.r.sr |= SR_CARRY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0x02 and 0x80
|
|
||||||
if (overflow)
|
|
||||||
{
|
|
||||||
g_dsp.r.sr |= SR_OVERFLOW;
|
|
||||||
g_dsp.r.sr |= SR_OVERFLOW_STICKY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0x04
|
|
||||||
if (_Value == 0)
|
|
||||||
{
|
|
||||||
g_dsp.r.sr |= SR_ARITH_ZERO;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0x08
|
|
||||||
if (_Value < 0)
|
|
||||||
{
|
|
||||||
g_dsp.r.sr |= SR_SIGN;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0x10
|
|
||||||
if (overS32)
|
|
||||||
{
|
|
||||||
g_dsp.r.sr |= SR_OVER_S32;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0x20 - Checks if top bits of m are equal
|
|
||||||
if ((((u16)_Value >> 14) == 0) || (((u16)_Value >> 14) == 3))
|
|
||||||
{
|
|
||||||
g_dsp.r.sr |= SR_TOP2BITS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Update_SR_LZ(bool value)
|
|
||||||
{
|
|
||||||
if (value == true)
|
|
||||||
g_dsp.r.sr |= SR_LOGIC_ZERO;
|
|
||||||
else
|
|
||||||
g_dsp.r.sr &= ~SR_LOGIC_ZERO;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsCarry()
|
|
||||||
{
|
|
||||||
return (g_dsp.r.sr & SR_CARRY) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsOverflow()
|
|
||||||
{
|
|
||||||
return (g_dsp.r.sr & SR_OVERFLOW) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsOverS32()
|
|
||||||
{
|
|
||||||
return (g_dsp.r.sr & SR_OVER_S32) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsLess()
|
|
||||||
{
|
|
||||||
return (g_dsp.r.sr & SR_OVERFLOW) != (g_dsp.r.sr & SR_SIGN);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsZero()
|
|
||||||
{
|
|
||||||
return (g_dsp.r.sr & SR_ARITH_ZERO) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsLogicZero()
|
|
||||||
{
|
|
||||||
return (g_dsp.r.sr & SR_LOGIC_ZERO) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsConditionA()
|
|
||||||
{
|
|
||||||
return (((g_dsp.r.sr & SR_OVER_S32) || (g_dsp.r.sr & SR_TOP2BITS)) &&
|
|
||||||
!(g_dsp.r.sr & SR_ARITH_ZERO)) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// see DSPCore.h for flags
|
|
||||||
bool CheckCondition(u8 _Condition)
|
|
||||||
{
|
|
||||||
switch (_Condition & 0xf)
|
|
||||||
{
|
|
||||||
case 0xf: // Always true.
|
|
||||||
return true;
|
|
||||||
case 0x0: // GE - Greater Equal
|
|
||||||
return !IsLess();
|
|
||||||
case 0x1: // L - Less
|
|
||||||
return IsLess();
|
|
||||||
case 0x2: // G - Greater
|
|
||||||
return !IsLess() && !IsZero();
|
|
||||||
case 0x3: // LE - Less Equal
|
|
||||||
return IsLess() || IsZero();
|
|
||||||
case 0x4: // NZ - Not Zero
|
|
||||||
return !IsZero();
|
|
||||||
case 0x5: // Z - Zero
|
|
||||||
return IsZero();
|
|
||||||
case 0x6: // NC - Not carry
|
|
||||||
return !IsCarry();
|
|
||||||
case 0x7: // C - Carry
|
|
||||||
return IsCarry();
|
|
||||||
case 0x8: // ? - Not over s32
|
|
||||||
return !IsOverS32();
|
|
||||||
case 0x9: // ? - Over s32
|
|
||||||
return IsOverS32();
|
|
||||||
case 0xa: // ?
|
|
||||||
return IsConditionA();
|
|
||||||
case 0xb: // ?
|
|
||||||
return !IsConditionA();
|
|
||||||
case 0xc: // LNZ - Logic Not Zero
|
|
||||||
return !IsLogicZero();
|
|
||||||
case 0xd: // LZ - Logic Zero
|
|
||||||
return IsLogicZero();
|
|
||||||
case 0xe: // 0 - Overflow
|
|
||||||
return IsOverflow();
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace DSP::Interpreter
|
|
|
@ -6,36 +6,29 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// Anything to do with SR and conditions goes here.
|
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
|
// Anything to do with SR and conditions goes here.
|
||||||
|
|
||||||
namespace DSP::Interpreter
|
namespace DSP::Interpreter
|
||||||
{
|
{
|
||||||
bool CheckCondition(u8 _Condition);
|
constexpr bool isCarry(u64 val, u64 result)
|
||||||
|
|
||||||
void Update_SR_Register16(s16 _Value, bool carry = false, bool overflow = false,
|
|
||||||
bool overS32 = false);
|
|
||||||
void Update_SR_Register64(s64 _Value, bool carry = false, bool overflow = false);
|
|
||||||
void Update_SR_LZ(bool value);
|
|
||||||
|
|
||||||
inline bool isCarry(u64 val, u64 result)
|
|
||||||
{
|
{
|
||||||
return (val > result);
|
return val > result;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool isCarry2(u64 val, u64 result)
|
constexpr bool isCarry2(u64 val, u64 result)
|
||||||
{
|
{
|
||||||
return (val >= result);
|
return val >= result;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool isOverflow(s64 val1, s64 val2, s64 res)
|
constexpr bool isOverflow(s64 val1, s64 val2, s64 res)
|
||||||
{
|
{
|
||||||
return ((val1 ^ res) & (val2 ^ res)) < 0;
|
return ((val1 ^ res) & (val2 ^ res)) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool isOverS32(s64 acc)
|
constexpr bool isOverS32(s64 acc)
|
||||||
{
|
{
|
||||||
return (acc != (s32)acc) ? true : false;
|
return acc != static_cast<s32>(acc);
|
||||||
}
|
}
|
||||||
} // namespace DSP::Interpreter
|
} // namespace DSP::Interpreter
|
||||||
|
|
|
@ -2,15 +2,7 @@
|
||||||
// Licensed under GPLv2+
|
// Licensed under GPLv2+
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include "Core/DSP/Interpreter/DSPIntExtOps.h"
|
#include "Core/DSP/Interpreter/DSPInterpreter.h"
|
||||||
|
|
||||||
#include "Core/DSP/DSPMemoryMap.h"
|
|
||||||
#include "Core/DSP/DSPTables.h"
|
|
||||||
#include "Core/DSP/Interpreter/DSPIntUtil.h"
|
|
||||||
|
|
||||||
// not needed for game ucodes (it slows down interpreter/dspjit32 + easier to compare int VS
|
|
||||||
// dspjit64 without it)
|
|
||||||
//#define PRECISE_BACKLOG
|
|
||||||
|
|
||||||
// Extended opcodes do not exist on their own. These opcodes can only be
|
// Extended opcodes do not exist on their own. These opcodes can only be
|
||||||
// attached to opcodes that allow extending (8 (or 7) lower bits of opcode not used by
|
// attached to opcodes that allow extending (8 (or 7) lower bits of opcode not used by
|
||||||
|
@ -22,15 +14,7 @@
|
||||||
// registers will wrap in odd ways, dictated by the corresponding wrapping
|
// registers will wrap in odd ways, dictated by the corresponding wrapping
|
||||||
// register, WR0-3.
|
// register, WR0-3.
|
||||||
|
|
||||||
namespace DSP
|
namespace DSP::Interpreter
|
||||||
{
|
|
||||||
static void WriteToBackLog(int i, int idx, u16 value)
|
|
||||||
{
|
|
||||||
writeBackLog[i] = value;
|
|
||||||
writeBackLogIdx[i] = idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Interpreter::Ext
|
|
||||||
{
|
{
|
||||||
static bool IsSameMemArea(u16 a, u16 b)
|
static bool IsSameMemArea(u16 a, u16 b)
|
||||||
{
|
{
|
||||||
|
@ -41,46 +25,48 @@ static bool IsSameMemArea(u16 a, u16 b)
|
||||||
// DR $arR
|
// DR $arR
|
||||||
// xxxx xxxx 0000 01rr
|
// xxxx xxxx 0000 01rr
|
||||||
// Decrement addressing register $arR.
|
// Decrement addressing register $arR.
|
||||||
void dr(const UDSPInstruction opc)
|
void Interpreter::dr(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
WriteToBackLog(0, opc & 0x3, dsp_decrement_addr_reg(opc & 0x3));
|
WriteToBackLog(0, opc & 0x3, DecrementAddressRegister(opc & 0x3));
|
||||||
}
|
}
|
||||||
|
|
||||||
// IR $arR
|
// IR $arR
|
||||||
// xxxx xxxx 0000 10rr
|
// xxxx xxxx 0000 10rr
|
||||||
// Increment addressing register $arR.
|
// Increment addressing register $arR.
|
||||||
void ir(const UDSPInstruction opc)
|
void Interpreter::ir(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
WriteToBackLog(0, opc & 0x3, dsp_increment_addr_reg(opc & 0x3));
|
WriteToBackLog(0, opc & 0x3, IncrementAddressRegister(opc & 0x3));
|
||||||
}
|
}
|
||||||
|
|
||||||
// NR $arR
|
// NR $arR
|
||||||
// xxxx xxxx 0000 11rr
|
// xxxx xxxx 0000 11rr
|
||||||
// Add corresponding indexing register $ixR to addressing register $arR.
|
// Add corresponding indexing register $ixR to addressing register $arR.
|
||||||
void nr(const UDSPInstruction opc)
|
void Interpreter::nr(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 reg = opc & 0x3;
|
const u8 reg = opc & 0x3;
|
||||||
|
const auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
WriteToBackLog(0, reg, dsp_increase_addr_reg(reg, (s16)g_dsp.r.ix[reg]));
|
WriteToBackLog(0, reg, IncreaseAddressRegister(reg, static_cast<s16>(state.r.ix[reg])));
|
||||||
}
|
}
|
||||||
|
|
||||||
// MV $axD.D, $acS.S
|
// MV $axD.D, $acS.S
|
||||||
// xxxx xxxx 0001 ddss
|
// xxxx xxxx 0001 ddss
|
||||||
// Move value of $acS.S to the $axD.D.
|
// Move value of $acS.S to the $axD.D.
|
||||||
void mv(const UDSPInstruction opc)
|
void Interpreter::mv(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 sreg = (opc & 0x3) + DSP_REG_ACL0;
|
const u8 sreg = (opc & 0x3) + DSP_REG_ACL0;
|
||||||
u8 dreg = ((opc >> 2) & 0x3);
|
const u8 dreg = ((opc >> 2) & 0x3);
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
switch (sreg)
|
switch (sreg)
|
||||||
{
|
{
|
||||||
case DSP_REG_ACL0:
|
case DSP_REG_ACL0:
|
||||||
case DSP_REG_ACL1:
|
case DSP_REG_ACL1:
|
||||||
WriteToBackLog(0, dreg + DSP_REG_AXL0, g_dsp.r.ac[sreg - DSP_REG_ACL0].l);
|
WriteToBackLog(0, dreg + DSP_REG_AXL0, state.r.ac[sreg - DSP_REG_ACL0].l);
|
||||||
break;
|
break;
|
||||||
case DSP_REG_ACM0:
|
case DSP_REG_ACM0:
|
||||||
case DSP_REG_ACM1:
|
case DSP_REG_ACM1:
|
||||||
WriteToBackLog(0, dreg + DSP_REG_AXL0, dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0));
|
WriteToBackLog(0, dreg + DSP_REG_AXL0, OpReadRegisterAndSaturate(sreg - DSP_REG_ACM0));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,69 +75,72 @@ void mv(const UDSPInstruction opc)
|
||||||
// xxxx xxxx 001s s0dd
|
// xxxx xxxx 001s s0dd
|
||||||
// Store value of $acS.S in the memory pointed by register $arD.
|
// Store value of $acS.S in the memory pointed by register $arD.
|
||||||
// Post increment register $arD.
|
// Post increment register $arD.
|
||||||
void s(const UDSPInstruction opc)
|
void Interpreter::s(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 dreg = opc & 0x3;
|
const u8 dreg = opc & 0x3;
|
||||||
u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0;
|
const u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
switch (sreg)
|
switch (sreg)
|
||||||
{
|
{
|
||||||
case DSP_REG_ACL0:
|
case DSP_REG_ACL0:
|
||||||
case DSP_REG_ACL1:
|
case DSP_REG_ACL1:
|
||||||
dsp_dmem_write(g_dsp.r.ar[dreg], g_dsp.r.ac[sreg - DSP_REG_ACL0].l);
|
state.WriteDMEM(state.r.ar[dreg], state.r.ac[sreg - DSP_REG_ACL0].l);
|
||||||
break;
|
break;
|
||||||
case DSP_REG_ACM0:
|
case DSP_REG_ACM0:
|
||||||
case DSP_REG_ACM1:
|
case DSP_REG_ACM1:
|
||||||
dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0));
|
state.WriteDMEM(state.r.ar[dreg], OpReadRegisterAndSaturate(sreg - DSP_REG_ACM0));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
WriteToBackLog(0, dreg, dsp_increment_addr_reg(dreg));
|
WriteToBackLog(0, dreg, IncrementAddressRegister(dreg));
|
||||||
}
|
}
|
||||||
|
|
||||||
// SN @$arD, $acS.S
|
// SN @$arD, $acS.S
|
||||||
// xxxx xxxx 001s s1dd
|
// xxxx xxxx 001s s1dd
|
||||||
// Store value of register $acS.S in the memory pointed by register $arD.
|
// Store value of register $acS.S in the memory pointed by register $arD.
|
||||||
// Add indexing register $ixD to register $arD.
|
// Add indexing register $ixD to register $arD.
|
||||||
void sn(const UDSPInstruction opc)
|
void Interpreter::sn(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 dreg = opc & 0x3;
|
const u8 dreg = opc & 0x3;
|
||||||
u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0;
|
const u8 sreg = ((opc >> 3) & 0x3) + DSP_REG_ACL0;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
switch (sreg)
|
switch (sreg)
|
||||||
{
|
{
|
||||||
case DSP_REG_ACL0:
|
case DSP_REG_ACL0:
|
||||||
case DSP_REG_ACL1:
|
case DSP_REG_ACL1:
|
||||||
dsp_dmem_write(g_dsp.r.ar[dreg], g_dsp.r.ac[sreg - DSP_REG_ACL0].l);
|
state.WriteDMEM(state.r.ar[dreg], state.r.ac[sreg - DSP_REG_ACL0].l);
|
||||||
break;
|
break;
|
||||||
case DSP_REG_ACM0:
|
case DSP_REG_ACM0:
|
||||||
case DSP_REG_ACM1:
|
case DSP_REG_ACM1:
|
||||||
dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0));
|
state.WriteDMEM(state.r.ar[dreg], OpReadRegisterAndSaturate(sreg - DSP_REG_ACM0));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
WriteToBackLog(0, dreg, dsp_increase_addr_reg(dreg, (s16)g_dsp.r.ix[dreg]));
|
WriteToBackLog(0, dreg, IncreaseAddressRegister(dreg, static_cast<s16>(state.r.ix[dreg])));
|
||||||
}
|
}
|
||||||
|
|
||||||
// L $axD.D, @$arS
|
// L $axD.D, @$arS
|
||||||
// xxxx xxxx 01dd d0ss
|
// xxxx xxxx 01dd d0ss
|
||||||
// Load $axD.D/$acD.D with value from memory pointed by register $arS.
|
// Load $axD.D/$acD.D with value from memory pointed by register $arS.
|
||||||
// Post increment register $arS.
|
// Post increment register $arS.
|
||||||
void l(const UDSPInstruction opc)
|
void Interpreter::l(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 sreg = opc & 0x3;
|
const u8 sreg = opc & 0x3;
|
||||||
u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0;
|
const u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
if ((dreg >= DSP_REG_ACM0) && (g_dsp.r.sr & SR_40_MODE_BIT))
|
if (dreg >= DSP_REG_ACM0 && IsSRFlagSet(SR_40_MODE_BIT))
|
||||||
{
|
{
|
||||||
u16 val = dsp_dmem_read(g_dsp.r.ar[sreg]);
|
const u16 val = state.ReadDMEM(state.r.ar[sreg]);
|
||||||
WriteToBackLog(0, dreg - DSP_REG_ACM0 + DSP_REG_ACH0, (val & 0x8000) ? 0xFFFF : 0x0000);
|
WriteToBackLog(0, dreg - DSP_REG_ACM0 + DSP_REG_ACH0, (val & 0x8000) != 0 ? 0xFFFF : 0x0000);
|
||||||
WriteToBackLog(1, dreg, val);
|
WriteToBackLog(1, dreg, val);
|
||||||
WriteToBackLog(2, dreg - DSP_REG_ACM0 + DSP_REG_ACL0, 0);
|
WriteToBackLog(2, dreg - DSP_REG_ACM0 + DSP_REG_ACL0, 0);
|
||||||
WriteToBackLog(3, sreg, dsp_increment_addr_reg(sreg));
|
WriteToBackLog(3, sreg, IncrementAddressRegister(sreg));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[sreg]));
|
WriteToBackLog(0, dreg, state.ReadDMEM(state.r.ar[sreg]));
|
||||||
WriteToBackLog(1, sreg, dsp_increment_addr_reg(sreg));
|
WriteToBackLog(1, sreg, IncrementAddressRegister(sreg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,23 +148,24 @@ void l(const UDSPInstruction opc)
|
||||||
// xxxx xxxx 01dd d0ss
|
// xxxx xxxx 01dd d0ss
|
||||||
// Load $axD.D/$acD.D with value from memory pointed by register $arS.
|
// Load $axD.D/$acD.D with value from memory pointed by register $arS.
|
||||||
// Add indexing register $ixS to register $arS.
|
// Add indexing register $ixS to register $arS.
|
||||||
void ln(const UDSPInstruction opc)
|
void Interpreter::ln(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 sreg = opc & 0x3;
|
const u8 sreg = opc & 0x3;
|
||||||
u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0;
|
const u8 dreg = ((opc >> 3) & 0x7) + DSP_REG_AXL0;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
if ((dreg >= DSP_REG_ACM0) && (g_dsp.r.sr & SR_40_MODE_BIT))
|
if (dreg >= DSP_REG_ACM0 && IsSRFlagSet(SR_40_MODE_BIT))
|
||||||
{
|
{
|
||||||
u16 val = dsp_dmem_read(g_dsp.r.ar[sreg]);
|
const u16 val = state.ReadDMEM(state.r.ar[sreg]);
|
||||||
WriteToBackLog(0, dreg - DSP_REG_ACM0 + DSP_REG_ACH0, (val & 0x8000) ? 0xFFFF : 0x0000);
|
WriteToBackLog(0, dreg - DSP_REG_ACM0 + DSP_REG_ACH0, (val & 0x8000) != 0 ? 0xFFFF : 0x0000);
|
||||||
WriteToBackLog(1, dreg, val);
|
WriteToBackLog(1, dreg, val);
|
||||||
WriteToBackLog(2, dreg - DSP_REG_ACM0 + DSP_REG_ACL0, 0);
|
WriteToBackLog(2, dreg - DSP_REG_ACM0 + DSP_REG_ACL0, 0);
|
||||||
WriteToBackLog(3, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]));
|
WriteToBackLog(3, sreg, IncreaseAddressRegister(sreg, static_cast<s16>(state.r.ix[sreg])));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[sreg]));
|
WriteToBackLog(0, dreg, state.ReadDMEM(state.r.ar[sreg]));
|
||||||
WriteToBackLog(1, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]));
|
WriteToBackLog(1, sreg, IncreaseAddressRegister(sreg, static_cast<s16>(state.r.ix[sreg])));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,16 +174,17 @@ void ln(const UDSPInstruction opc)
|
||||||
// Load register $axD.D with value from memory pointed by register
|
// Load register $axD.D with value from memory pointed by register
|
||||||
// $ar0. Store value from register $acS.m to memory location pointed by
|
// $ar0. Store value from register $acS.m to memory location pointed by
|
||||||
// register $ar3. Increment both $ar0 and $ar3.
|
// register $ar3. Increment both $ar0 and $ar3.
|
||||||
void ls(const UDSPInstruction opc)
|
void Interpreter::ls(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 sreg = opc & 0x1;
|
const u8 sreg = opc & 0x1;
|
||||||
u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
|
const u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
dsp_dmem_write(g_dsp.r.ar[3], dsp_op_read_reg_and_saturate(sreg));
|
state.WriteDMEM(state.r.ar[3], OpReadRegisterAndSaturate(sreg));
|
||||||
|
|
||||||
WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0]));
|
WriteToBackLog(0, dreg, state.ReadDMEM(state.r.ar[0]));
|
||||||
WriteToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3));
|
WriteToBackLog(1, DSP_REG_AR3, IncrementAddressRegister(DSP_REG_AR3));
|
||||||
WriteToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0));
|
WriteToBackLog(2, DSP_REG_AR0, IncrementAddressRegister(DSP_REG_AR0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// LSN $axD.D, $acS.m
|
// LSN $axD.D, $acS.m
|
||||||
|
@ -202,16 +193,18 @@ void ls(const UDSPInstruction opc)
|
||||||
// $ar0. Store value from register $acS.m to memory location pointed by
|
// $ar0. Store value from register $acS.m to memory location pointed by
|
||||||
// register $ar3. Add corresponding indexing register $ix0 to addressing
|
// register $ar3. Add corresponding indexing register $ix0 to addressing
|
||||||
// register $ar0 and increment $ar3.
|
// register $ar0 and increment $ar3.
|
||||||
void lsn(const UDSPInstruction opc)
|
void Interpreter::lsn(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 sreg = opc & 0x1;
|
const u8 sreg = opc & 0x1;
|
||||||
u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
|
const u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
dsp_dmem_write(g_dsp.r.ar[3], dsp_op_read_reg_and_saturate(sreg));
|
state.WriteDMEM(state.r.ar[3], OpReadRegisterAndSaturate(sreg));
|
||||||
|
|
||||||
WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0]));
|
WriteToBackLog(0, dreg, state.ReadDMEM(state.r.ar[0]));
|
||||||
WriteToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3));
|
WriteToBackLog(1, DSP_REG_AR3, IncrementAddressRegister(DSP_REG_AR3));
|
||||||
WriteToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0]));
|
WriteToBackLog(2, DSP_REG_AR0,
|
||||||
|
IncreaseAddressRegister(DSP_REG_AR0, static_cast<s16>(state.r.ix[0])));
|
||||||
}
|
}
|
||||||
|
|
||||||
// LSM $axD.D, $acS.m
|
// LSM $axD.D, $acS.m
|
||||||
|
@ -220,16 +213,18 @@ void lsn(const UDSPInstruction opc)
|
||||||
// $ar0. Store value from register $acS.m to memory location pointed by
|
// $ar0. Store value from register $acS.m to memory location pointed by
|
||||||
// register $ar3. Add corresponding indexing register $ix3 to addressing
|
// register $ar3. Add corresponding indexing register $ix3 to addressing
|
||||||
// register $ar3 and increment $ar0.
|
// register $ar3 and increment $ar0.
|
||||||
void lsm(const UDSPInstruction opc)
|
void Interpreter::lsm(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 sreg = opc & 0x1;
|
const u8 sreg = opc & 0x1;
|
||||||
u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
|
const u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
dsp_dmem_write(g_dsp.r.ar[3], dsp_op_read_reg_and_saturate(sreg));
|
state.WriteDMEM(state.r.ar[3], OpReadRegisterAndSaturate(sreg));
|
||||||
|
|
||||||
WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0]));
|
WriteToBackLog(0, dreg, state.ReadDMEM(state.r.ar[0]));
|
||||||
WriteToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
|
WriteToBackLog(1, DSP_REG_AR3,
|
||||||
WriteToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0));
|
IncreaseAddressRegister(DSP_REG_AR3, static_cast<s16>(state.r.ix[3])));
|
||||||
|
WriteToBackLog(2, DSP_REG_AR0, IncrementAddressRegister(DSP_REG_AR0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// LSMN $axD.D, $acS.m
|
// LSMN $axD.D, $acS.m
|
||||||
|
@ -239,16 +234,19 @@ void lsm(const UDSPInstruction opc)
|
||||||
// register $ar3. Add corresponding indexing register $ix0 to addressing
|
// register $ar3. Add corresponding indexing register $ix0 to addressing
|
||||||
// register $ar0 and add corresponding indexing register $ix3 to addressing
|
// register $ar0 and add corresponding indexing register $ix3 to addressing
|
||||||
// register $ar3.
|
// register $ar3.
|
||||||
void lsnm(const UDSPInstruction opc)
|
void Interpreter::lsnm(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 sreg = opc & 0x1;
|
const u8 sreg = opc & 0x1;
|
||||||
u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
|
const u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
dsp_dmem_write(g_dsp.r.ar[3], dsp_op_read_reg_and_saturate(sreg));
|
state.WriteDMEM(state.r.ar[3], OpReadRegisterAndSaturate(sreg));
|
||||||
|
|
||||||
WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[0]));
|
WriteToBackLog(0, dreg, state.ReadDMEM(state.r.ar[0]));
|
||||||
WriteToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
|
WriteToBackLog(1, DSP_REG_AR3,
|
||||||
WriteToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0]));
|
IncreaseAddressRegister(DSP_REG_AR3, static_cast<s16>(state.r.ix[3])));
|
||||||
|
WriteToBackLog(2, DSP_REG_AR0,
|
||||||
|
IncreaseAddressRegister(DSP_REG_AR0, static_cast<s16>(state.r.ix[0])));
|
||||||
}
|
}
|
||||||
|
|
||||||
// SL $acS.m, $axD.D
|
// SL $acS.m, $axD.D
|
||||||
|
@ -256,16 +254,17 @@ void lsnm(const UDSPInstruction opc)
|
||||||
// Store value from register $acS.m to memory location pointed by register
|
// Store value from register $acS.m to memory location pointed by register
|
||||||
// $ar0. Load register $axD.D with value from memory pointed by register
|
// $ar0. Load register $axD.D with value from memory pointed by register
|
||||||
// $ar3. Increment both $ar0 and $ar3.
|
// $ar3. Increment both $ar0 and $ar3.
|
||||||
void sl(const UDSPInstruction opc)
|
void Interpreter::sl(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 sreg = opc & 0x1;
|
const u8 sreg = opc & 0x1;
|
||||||
u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
|
const u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
dsp_dmem_write(g_dsp.r.ar[0], dsp_op_read_reg_and_saturate(sreg));
|
state.WriteDMEM(state.r.ar[0], OpReadRegisterAndSaturate(sreg));
|
||||||
|
|
||||||
WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3]));
|
WriteToBackLog(0, dreg, state.ReadDMEM(state.r.ar[3]));
|
||||||
WriteToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3));
|
WriteToBackLog(1, DSP_REG_AR3, IncrementAddressRegister(DSP_REG_AR3));
|
||||||
WriteToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0));
|
WriteToBackLog(2, DSP_REG_AR0, IncrementAddressRegister(DSP_REG_AR0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// SLN $acS.m, $axD.D
|
// SLN $acS.m, $axD.D
|
||||||
|
@ -274,16 +273,18 @@ void sl(const UDSPInstruction opc)
|
||||||
// $ar0. Load register $axD.D with value from memory pointed by register
|
// $ar0. Load register $axD.D with value from memory pointed by register
|
||||||
// $ar3. Add corresponding indexing register $ix0 to addressing register $ar0
|
// $ar3. Add corresponding indexing register $ix0 to addressing register $ar0
|
||||||
// and increment $ar3.
|
// and increment $ar3.
|
||||||
void sln(const UDSPInstruction opc)
|
void Interpreter::sln(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 sreg = opc & 0x1;
|
const u8 sreg = opc & 0x1;
|
||||||
u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
|
const u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
dsp_dmem_write(g_dsp.r.ar[0], dsp_op_read_reg_and_saturate(sreg));
|
state.WriteDMEM(state.r.ar[0], OpReadRegisterAndSaturate(sreg));
|
||||||
|
|
||||||
WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3]));
|
WriteToBackLog(0, dreg, state.ReadDMEM(state.r.ar[3]));
|
||||||
WriteToBackLog(1, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3));
|
WriteToBackLog(1, DSP_REG_AR3, IncrementAddressRegister(DSP_REG_AR3));
|
||||||
WriteToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0]));
|
WriteToBackLog(2, DSP_REG_AR0,
|
||||||
|
IncreaseAddressRegister(DSP_REG_AR0, static_cast<s16>(state.r.ix[0])));
|
||||||
}
|
}
|
||||||
|
|
||||||
// SLM $acS.m, $axD.D
|
// SLM $acS.m, $axD.D
|
||||||
|
@ -292,16 +293,18 @@ void sln(const UDSPInstruction opc)
|
||||||
// $ar0. Load register $axD.D with value from memory pointed by register
|
// $ar0. Load register $axD.D with value from memory pointed by register
|
||||||
// $ar3. Add corresponding indexing register $ix3 to addressing register $ar3
|
// $ar3. Add corresponding indexing register $ix3 to addressing register $ar3
|
||||||
// and increment $ar0.
|
// and increment $ar0.
|
||||||
void slm(const UDSPInstruction opc)
|
void Interpreter::slm(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 sreg = opc & 0x1;
|
const u8 sreg = opc & 0x1;
|
||||||
u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
|
const u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
dsp_dmem_write(g_dsp.r.ar[0], dsp_op_read_reg_and_saturate(sreg));
|
state.WriteDMEM(state.r.ar[0], OpReadRegisterAndSaturate(sreg));
|
||||||
|
|
||||||
WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3]));
|
WriteToBackLog(0, dreg, state.ReadDMEM(state.r.ar[3]));
|
||||||
WriteToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
|
WriteToBackLog(1, DSP_REG_AR3,
|
||||||
WriteToBackLog(2, DSP_REG_AR0, dsp_increment_addr_reg(DSP_REG_AR0));
|
IncreaseAddressRegister(DSP_REG_AR3, static_cast<s16>(state.r.ix[3])));
|
||||||
|
WriteToBackLog(2, DSP_REG_AR0, IncrementAddressRegister(DSP_REG_AR0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// SLMN $acS.m, $axD.D
|
// SLMN $acS.m, $axD.D
|
||||||
|
@ -310,16 +313,19 @@ void slm(const UDSPInstruction opc)
|
||||||
// $ar0. Load register $axD.D with value from memory pointed by register
|
// $ar0. Load register $axD.D with value from memory pointed by register
|
||||||
// $ar3. Add corresponding indexing register $ix0 to addressing register $ar0
|
// $ar3. Add corresponding indexing register $ix0 to addressing register $ar0
|
||||||
// and add corresponding indexing register $ix3 to addressing register $ar3.
|
// and add corresponding indexing register $ix3 to addressing register $ar3.
|
||||||
void slnm(const UDSPInstruction opc)
|
void Interpreter::slnm(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 sreg = opc & 0x1;
|
const u8 sreg = opc & 0x1;
|
||||||
u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
|
const u8 dreg = ((opc >> 4) & 0x3) + DSP_REG_AXL0;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
dsp_dmem_write(g_dsp.r.ar[0], dsp_op_read_reg_and_saturate(sreg));
|
state.WriteDMEM(state.r.ar[0], OpReadRegisterAndSaturate(sreg));
|
||||||
|
|
||||||
WriteToBackLog(0, dreg, dsp_dmem_read(g_dsp.r.ar[3]));
|
WriteToBackLog(0, dreg, state.ReadDMEM(state.r.ar[3]));
|
||||||
WriteToBackLog(1, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
|
WriteToBackLog(1, DSP_REG_AR3,
|
||||||
WriteToBackLog(2, DSP_REG_AR0, dsp_increase_addr_reg(DSP_REG_AR0, (s16)g_dsp.r.ix[0]));
|
IncreaseAddressRegister(DSP_REG_AR3, static_cast<s16>(state.r.ix[3])));
|
||||||
|
WriteToBackLog(2, DSP_REG_AR0,
|
||||||
|
IncreaseAddressRegister(DSP_REG_AR0, static_cast<s16>(state.r.ix[0])));
|
||||||
}
|
}
|
||||||
|
|
||||||
// LD $ax0.d, $ax1.r, @$arS
|
// LD $ax0.d, $ax1.r, @$arS
|
||||||
|
@ -334,228 +340,173 @@ void slnm(const UDSPInstruction opc)
|
||||||
// implemented yet)
|
// implemented yet)
|
||||||
// If AR3 points into an invalid memory page, then AX0.L gets the same value as AX0.H. (not
|
// If AR3 points into an invalid memory page, then AX0.L gets the same value as AX0.H. (not
|
||||||
// implemented yet)
|
// implemented yet)
|
||||||
void ld(const UDSPInstruction opc)
|
void Interpreter::ld(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 dreg = (opc >> 5) & 0x1;
|
const u8 dreg = (opc >> 5) & 0x1;
|
||||||
u8 rreg = (opc >> 4) & 0x1;
|
const u8 rreg = (opc >> 4) & 0x1;
|
||||||
u8 sreg = opc & 0x3;
|
const u8 sreg = opc & 0x3;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
WriteToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg]));
|
WriteToBackLog(0, (dreg << 1) + DSP_REG_AXL0, state.ReadDMEM(state.r.ar[sreg]));
|
||||||
|
|
||||||
if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3]))
|
if (IsSameMemArea(state.r.ar[sreg], state.r.ar[3]))
|
||||||
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg]));
|
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, state.ReadDMEM(state.r.ar[sreg]));
|
||||||
else
|
else
|
||||||
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3]));
|
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, state.ReadDMEM(state.r.ar[3]));
|
||||||
|
|
||||||
WriteToBackLog(2, sreg, dsp_increment_addr_reg(sreg));
|
WriteToBackLog(2, sreg, IncrementAddressRegister(sreg));
|
||||||
|
|
||||||
WriteToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3));
|
WriteToBackLog(3, DSP_REG_AR3, IncrementAddressRegister(DSP_REG_AR3));
|
||||||
}
|
}
|
||||||
|
|
||||||
// LDAX $axR, @$arS
|
// LDAX $axR, @$arS
|
||||||
// xxxx xxxx 11sr 0011
|
// xxxx xxxx 11sr 0011
|
||||||
void ldax(const UDSPInstruction opc)
|
void Interpreter::ldax(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 sreg = (opc >> 5) & 0x1;
|
const u8 sreg = (opc >> 5) & 0x1;
|
||||||
u8 rreg = (opc >> 4) & 0x1;
|
const u8 rreg = (opc >> 4) & 0x1;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
WriteToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[sreg]));
|
WriteToBackLog(0, rreg + DSP_REG_AXH0, state.ReadDMEM(state.r.ar[sreg]));
|
||||||
|
|
||||||
if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3]))
|
if (IsSameMemArea(state.r.ar[sreg], state.r.ar[3]))
|
||||||
WriteToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg]));
|
WriteToBackLog(1, rreg + DSP_REG_AXL0, state.ReadDMEM(state.r.ar[sreg]));
|
||||||
else
|
else
|
||||||
WriteToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3]));
|
WriteToBackLog(1, rreg + DSP_REG_AXL0, state.ReadDMEM(state.r.ar[3]));
|
||||||
|
|
||||||
WriteToBackLog(2, sreg, dsp_increment_addr_reg(sreg));
|
WriteToBackLog(2, sreg, IncrementAddressRegister(sreg));
|
||||||
|
|
||||||
WriteToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3));
|
WriteToBackLog(3, DSP_REG_AR3, IncrementAddressRegister(DSP_REG_AR3));
|
||||||
}
|
}
|
||||||
|
|
||||||
// LDN $ax0.d, $ax1.r, @$arS
|
// LDN $ax0.d, $ax1.r, @$arS
|
||||||
// xxxx xxxx 11dr 01ss
|
// xxxx xxxx 11dr 01ss
|
||||||
void ldn(const UDSPInstruction opc)
|
void Interpreter::ldn(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 dreg = (opc >> 5) & 0x1;
|
const u8 dreg = (opc >> 5) & 0x1;
|
||||||
u8 rreg = (opc >> 4) & 0x1;
|
const u8 rreg = (opc >> 4) & 0x1;
|
||||||
u8 sreg = opc & 0x3;
|
const u8 sreg = opc & 0x3;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
WriteToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg]));
|
WriteToBackLog(0, (dreg << 1) + DSP_REG_AXL0, state.ReadDMEM(state.r.ar[sreg]));
|
||||||
|
|
||||||
if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3]))
|
if (IsSameMemArea(state.r.ar[sreg], state.r.ar[3]))
|
||||||
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg]));
|
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, state.ReadDMEM(state.r.ar[sreg]));
|
||||||
else
|
else
|
||||||
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3]));
|
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, state.ReadDMEM(state.r.ar[3]));
|
||||||
|
|
||||||
WriteToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]));
|
WriteToBackLog(2, sreg, IncreaseAddressRegister(sreg, static_cast<s16>(state.r.ix[sreg])));
|
||||||
|
|
||||||
WriteToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3));
|
WriteToBackLog(3, DSP_REG_AR3, IncrementAddressRegister(DSP_REG_AR3));
|
||||||
}
|
}
|
||||||
|
|
||||||
// LDAXN $axR, @$arS
|
// LDAXN $axR, @$arS
|
||||||
// xxxx xxxx 11sr 0111
|
// xxxx xxxx 11sr 0111
|
||||||
void ldaxn(const UDSPInstruction opc)
|
void Interpreter::ldaxn(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 sreg = (opc >> 5) & 0x1;
|
const u8 sreg = (opc >> 5) & 0x1;
|
||||||
u8 rreg = (opc >> 4) & 0x1;
|
const u8 rreg = (opc >> 4) & 0x1;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
WriteToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[sreg]));
|
WriteToBackLog(0, rreg + DSP_REG_AXH0, state.ReadDMEM(state.r.ar[sreg]));
|
||||||
|
|
||||||
if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3]))
|
if (IsSameMemArea(state.r.ar[sreg], state.r.ar[3]))
|
||||||
WriteToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg]));
|
WriteToBackLog(1, rreg + DSP_REG_AXL0, state.ReadDMEM(state.r.ar[sreg]));
|
||||||
else
|
else
|
||||||
WriteToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3]));
|
WriteToBackLog(1, rreg + DSP_REG_AXL0, state.ReadDMEM(state.r.ar[3]));
|
||||||
|
|
||||||
WriteToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]));
|
WriteToBackLog(2, sreg, IncreaseAddressRegister(sreg, static_cast<s16>(state.r.ix[sreg])));
|
||||||
|
|
||||||
WriteToBackLog(3, DSP_REG_AR3, dsp_increment_addr_reg(DSP_REG_AR3));
|
WriteToBackLog(3, DSP_REG_AR3, IncrementAddressRegister(DSP_REG_AR3));
|
||||||
}
|
}
|
||||||
|
|
||||||
// LDM $ax0.d, $ax1.r, @$arS
|
// LDM $ax0.d, $ax1.r, @$arS
|
||||||
// xxxx xxxx 11dr 10ss
|
// xxxx xxxx 11dr 10ss
|
||||||
void ldm(const UDSPInstruction opc)
|
void Interpreter::ldm(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 dreg = (opc >> 5) & 0x1;
|
const u8 dreg = (opc >> 5) & 0x1;
|
||||||
u8 rreg = (opc >> 4) & 0x1;
|
const u8 rreg = (opc >> 4) & 0x1;
|
||||||
u8 sreg = opc & 0x3;
|
const u8 sreg = opc & 0x3;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
WriteToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg]));
|
WriteToBackLog(0, (dreg << 1) + DSP_REG_AXL0, state.ReadDMEM(state.r.ar[sreg]));
|
||||||
|
|
||||||
if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3]))
|
if (IsSameMemArea(state.r.ar[sreg], state.r.ar[3]))
|
||||||
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg]));
|
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, state.ReadDMEM(state.r.ar[sreg]));
|
||||||
else
|
else
|
||||||
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3]));
|
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, state.ReadDMEM(state.r.ar[3]));
|
||||||
|
|
||||||
WriteToBackLog(2, sreg, dsp_increment_addr_reg(sreg));
|
WriteToBackLog(2, sreg, IncrementAddressRegister(sreg));
|
||||||
|
|
||||||
WriteToBackLog(3, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
|
WriteToBackLog(3, DSP_REG_AR3,
|
||||||
|
IncreaseAddressRegister(DSP_REG_AR3, static_cast<s16>(state.r.ix[3])));
|
||||||
}
|
}
|
||||||
|
|
||||||
// LDAXM $axR, @$arS
|
// LDAXM $axR, @$arS
|
||||||
// xxxx xxxx 11sr 1011
|
// xxxx xxxx 11sr 1011
|
||||||
void ldaxm(const UDSPInstruction opc)
|
void Interpreter::ldaxm(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 sreg = (opc >> 5) & 0x1;
|
const u8 sreg = (opc >> 5) & 0x1;
|
||||||
u8 rreg = (opc >> 4) & 0x1;
|
const u8 rreg = (opc >> 4) & 0x1;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
WriteToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[sreg]));
|
WriteToBackLog(0, rreg + DSP_REG_AXH0, state.ReadDMEM(state.r.ar[sreg]));
|
||||||
|
|
||||||
if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3]))
|
if (IsSameMemArea(state.r.ar[sreg], state.r.ar[3]))
|
||||||
WriteToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg]));
|
WriteToBackLog(1, rreg + DSP_REG_AXL0, state.ReadDMEM(state.r.ar[sreg]));
|
||||||
else
|
else
|
||||||
WriteToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3]));
|
WriteToBackLog(1, rreg + DSP_REG_AXL0, state.ReadDMEM(state.r.ar[3]));
|
||||||
|
|
||||||
WriteToBackLog(2, sreg, dsp_increment_addr_reg(sreg));
|
WriteToBackLog(2, sreg, IncrementAddressRegister(sreg));
|
||||||
|
|
||||||
WriteToBackLog(3, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
|
WriteToBackLog(3, DSP_REG_AR3,
|
||||||
|
IncreaseAddressRegister(DSP_REG_AR3, static_cast<s16>(state.r.ix[3])));
|
||||||
}
|
}
|
||||||
|
|
||||||
// LDNM $ax0.d, $ax1.r, @$arS
|
// LDNM $ax0.d, $ax1.r, @$arS
|
||||||
// xxxx xxxx 11dr 11ss
|
// xxxx xxxx 11dr 11ss
|
||||||
void ldnm(const UDSPInstruction opc)
|
void Interpreter::ldnm(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 dreg = (opc >> 5) & 0x1;
|
const u8 dreg = (opc >> 5) & 0x1;
|
||||||
u8 rreg = (opc >> 4) & 0x1;
|
const u8 rreg = (opc >> 4) & 0x1;
|
||||||
u8 sreg = opc & 0x3;
|
const u8 sreg = opc & 0x3;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
WriteToBackLog(0, (dreg << 1) + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg]));
|
WriteToBackLog(0, (dreg << 1) + DSP_REG_AXL0, state.ReadDMEM(state.r.ar[sreg]));
|
||||||
|
|
||||||
if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3]))
|
if (IsSameMemArea(state.r.ar[sreg], state.r.ar[3]))
|
||||||
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[sreg]));
|
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, state.ReadDMEM(state.r.ar[sreg]));
|
||||||
else
|
else
|
||||||
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, dsp_dmem_read(g_dsp.r.ar[3]));
|
WriteToBackLog(1, (rreg << 1) + DSP_REG_AXL1, state.ReadDMEM(state.r.ar[3]));
|
||||||
|
|
||||||
WriteToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]));
|
WriteToBackLog(2, sreg, IncreaseAddressRegister(sreg, static_cast<s16>(state.r.ix[sreg])));
|
||||||
|
|
||||||
WriteToBackLog(3, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
|
WriteToBackLog(3, DSP_REG_AR3,
|
||||||
|
IncreaseAddressRegister(DSP_REG_AR3, static_cast<s16>(state.r.ix[3])));
|
||||||
}
|
}
|
||||||
|
|
||||||
// LDAXNM $axR, @$arS
|
// LDAXNM $axR, @$arS
|
||||||
// xxxx xxxx 11dr 1111
|
// xxxx xxxx 11dr 1111
|
||||||
void ldaxnm(const UDSPInstruction opc)
|
void Interpreter::ldaxnm(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 sreg = (opc >> 5) & 0x1;
|
const u8 sreg = (opc >> 5) & 0x1;
|
||||||
u8 rreg = (opc >> 4) & 0x1;
|
const u8 rreg = (opc >> 4) & 0x1;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
WriteToBackLog(0, rreg + DSP_REG_AXH0, dsp_dmem_read(g_dsp.r.ar[sreg]));
|
WriteToBackLog(0, rreg + DSP_REG_AXH0, state.ReadDMEM(state.r.ar[sreg]));
|
||||||
|
|
||||||
if (IsSameMemArea(g_dsp.r.ar[sreg], g_dsp.r.ar[3]))
|
if (IsSameMemArea(state.r.ar[sreg], state.r.ar[3]))
|
||||||
WriteToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[sreg]));
|
WriteToBackLog(1, rreg + DSP_REG_AXL0, state.ReadDMEM(state.r.ar[sreg]));
|
||||||
else
|
else
|
||||||
WriteToBackLog(1, rreg + DSP_REG_AXL0, dsp_dmem_read(g_dsp.r.ar[3]));
|
WriteToBackLog(1, rreg + DSP_REG_AXL0, state.ReadDMEM(state.r.ar[3]));
|
||||||
|
|
||||||
WriteToBackLog(2, sreg, dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]));
|
WriteToBackLog(2, sreg, IncreaseAddressRegister(sreg, static_cast<s16>(state.r.ix[sreg])));
|
||||||
|
|
||||||
WriteToBackLog(3, DSP_REG_AR3, dsp_increase_addr_reg(DSP_REG_AR3, (s16)g_dsp.r.ix[3]));
|
WriteToBackLog(3, DSP_REG_AR3,
|
||||||
|
IncreaseAddressRegister(DSP_REG_AR3, static_cast<s16>(state.r.ix[3])));
|
||||||
}
|
}
|
||||||
|
|
||||||
void nop(const UDSPInstruction opc)
|
void Interpreter::nop_ext(const UDSPInstruction)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
} // namespace Interpreter::Ext
|
} // namespace DSP::Interpreter
|
||||||
|
|
||||||
// The ext ops are calculated in parallel with the actual op. That means that
|
|
||||||
// both the main op and the ext op see the same register state as input. The
|
|
||||||
// output is simple as long as the main and ext ops don't change the same
|
|
||||||
// register. If they do the output is the bitwise or of the result of both the
|
|
||||||
// main and ext ops.
|
|
||||||
|
|
||||||
// The ext op are writing their output into the backlog which is
|
|
||||||
// being applied to the real registers after the main op was executed
|
|
||||||
void ApplyWriteBackLog()
|
|
||||||
{
|
|
||||||
// always make sure to have an extra entry at the end w/ -1 to avoid
|
|
||||||
// infinitive loops
|
|
||||||
for (int i = 0; writeBackLogIdx[i] != -1; i++)
|
|
||||||
{
|
|
||||||
u16 value = writeBackLog[i];
|
|
||||||
#ifdef PRECISE_BACKLOG
|
|
||||||
value |= Interpreter::dsp_op_read_reg(writeBackLogIdx[i]);
|
|
||||||
#endif
|
|
||||||
Interpreter::dsp_op_write_reg(writeBackLogIdx[i], value);
|
|
||||||
|
|
||||||
// Clear back log
|
|
||||||
writeBackLogIdx[i] = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
// Only needed for cases when mainop and extended are modifying the same ACC
|
|
||||||
// Games are not doing that + in motorola (similar DSP) dox this is forbidden to do.
|
|
||||||
void ZeroWriteBackLog()
|
|
||||||
{
|
|
||||||
#ifdef PRECISE_BACKLOG
|
|
||||||
// always make sure to have an extra entry at the end w/ -1 to avoid
|
|
||||||
// infinitive loops
|
|
||||||
for (int i = 0; writeBackLogIdx[i] != -1; i++)
|
|
||||||
{
|
|
||||||
Interpreter::dsp_op_write_reg(writeBackLogIdx[i], 0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void ZeroWriteBackLogPreserveAcc(u8 acc)
|
|
||||||
{
|
|
||||||
#ifdef PRECISE_BACKLOG
|
|
||||||
for (int i = 0; writeBackLogIdx[i] != -1; i++)
|
|
||||||
{
|
|
||||||
// acc0
|
|
||||||
if ((acc == 0) &&
|
|
||||||
((writeBackLogIdx[i] == DSP_REG_ACL0) || (writeBackLogIdx[i] == DSP_REG_ACM0) ||
|
|
||||||
(writeBackLogIdx[i] == DSP_REG_ACH0)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// acc1
|
|
||||||
if ((acc == 1) &&
|
|
||||||
((writeBackLogIdx[i] == DSP_REG_ACL1) || (writeBackLogIdx[i] == DSP_REG_ACM1) ||
|
|
||||||
(writeBackLogIdx[i] == DSP_REG_ACH1)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Interpreter::dsp_op_write_reg(writeBackLogIdx[i], 0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
} // namespace DSP
|
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
// Copyright 2008 Dolphin Emulator Project
|
|
||||||
// Copyright 2005 Duddie
|
|
||||||
// Licensed under GPLv2+
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Core/DSP/DSPCommon.h"
|
|
||||||
|
|
||||||
// Extended opcode support.
|
|
||||||
// Many opcode have the lower 0xFF (some only 0x7f) free - there, an opcode extension
|
|
||||||
// can be stored.
|
|
||||||
|
|
||||||
namespace DSP::Interpreter::Ext
|
|
||||||
{
|
|
||||||
void l(UDSPInstruction opc);
|
|
||||||
void ln(UDSPInstruction opc);
|
|
||||||
void ls(UDSPInstruction opc);
|
|
||||||
void lsn(UDSPInstruction opc);
|
|
||||||
void lsm(UDSPInstruction opc);
|
|
||||||
void lsnm(UDSPInstruction opc);
|
|
||||||
void sl(UDSPInstruction opc);
|
|
||||||
void sln(UDSPInstruction opc);
|
|
||||||
void slm(UDSPInstruction opc);
|
|
||||||
void slnm(UDSPInstruction opc);
|
|
||||||
void s(UDSPInstruction opc);
|
|
||||||
void sn(UDSPInstruction opc);
|
|
||||||
void ld(UDSPInstruction opc);
|
|
||||||
void ldax(UDSPInstruction opc);
|
|
||||||
void ldn(UDSPInstruction opc);
|
|
||||||
void ldaxn(UDSPInstruction opc);
|
|
||||||
void ldm(UDSPInstruction opc);
|
|
||||||
void ldaxm(UDSPInstruction opc);
|
|
||||||
void ldnm(UDSPInstruction opc);
|
|
||||||
void ldaxnm(UDSPInstruction opc);
|
|
||||||
void mv(UDSPInstruction opc);
|
|
||||||
void dr(UDSPInstruction opc);
|
|
||||||
void ir(UDSPInstruction opc);
|
|
||||||
void nr(UDSPInstruction opc);
|
|
||||||
void nop(UDSPInstruction opc);
|
|
||||||
} // namespace DSP::Interpreter::Ext
|
|
|
@ -4,8 +4,7 @@
|
||||||
//
|
//
|
||||||
// Additional copyrights go to Duddie and Tratax (c) 2004
|
// Additional copyrights go to Duddie and Tratax (c) 2004
|
||||||
|
|
||||||
#include "Core/DSP/DSPMemoryMap.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Core/DSP/Interpreter/DSPIntUtil.h"
|
|
||||||
#include "Core/DSP/Interpreter/DSPInterpreter.h"
|
#include "Core/DSP/Interpreter/DSPInterpreter.h"
|
||||||
|
|
||||||
namespace DSP::Interpreter
|
namespace DSP::Interpreter
|
||||||
|
@ -16,15 +15,16 @@ namespace DSP::Interpreter
|
||||||
// CR[0-7] | M. That is, the upper 8 bits of the address are the
|
// CR[0-7] | M. That is, the upper 8 bits of the address are the
|
||||||
// bottom 8 bits from CR, and the lower 8 bits are from the 8-bit immediate.
|
// bottom 8 bits from CR, and the lower 8 bits are from the 8-bit immediate.
|
||||||
// Note: pc+=2 in duddie's doc seems wrong
|
// Note: pc+=2 in duddie's doc seems wrong
|
||||||
void srs(const UDSPInstruction opc)
|
void Interpreter::srs(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 reg = ((opc >> 8) & 0x7) + 0x18;
|
auto& state = m_dsp_core.DSPState();
|
||||||
u16 addr = (g_dsp.r.cr << 8) | (opc & 0xFF);
|
const auto reg = static_cast<u8>(((opc >> 8) & 0x7) + 0x18);
|
||||||
|
const auto addr = static_cast<u16>((state.r.cr << 8) | (opc & 0xFF));
|
||||||
|
|
||||||
if (reg >= DSP_REG_ACM0)
|
if (reg >= DSP_REG_ACM0)
|
||||||
dsp_dmem_write(addr, dsp_op_read_reg_and_saturate(reg - DSP_REG_ACM0));
|
state.WriteDMEM(addr, OpReadRegisterAndSaturate(reg - DSP_REG_ACM0));
|
||||||
else
|
else
|
||||||
dsp_dmem_write(addr, dsp_op_read_reg(reg));
|
state.WriteDMEM(addr, OpReadRegister(reg));
|
||||||
}
|
}
|
||||||
|
|
||||||
// LRS $(0x18+D), @M
|
// LRS $(0x18+D), @M
|
||||||
|
@ -32,40 +32,45 @@ void srs(const UDSPInstruction opc)
|
||||||
// Move value from data memory pointed by address CR[0-7] | M to register
|
// Move value from data memory pointed by address CR[0-7] | M to register
|
||||||
// $(0x18+D). That is, the upper 8 bits of the address are the bottom 8 bits
|
// $(0x18+D). That is, the upper 8 bits of the address are the bottom 8 bits
|
||||||
// from CR, and the lower 8 bits are from the 8-bit immediate.
|
// from CR, and the lower 8 bits are from the 8-bit immediate.
|
||||||
void lrs(const UDSPInstruction opc)
|
void Interpreter::lrs(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 reg = ((opc >> 8) & 0x7) + 0x18;
|
auto& state = m_dsp_core.DSPState();
|
||||||
u16 addr = (g_dsp.r.cr << 8) | (opc & 0xFF);
|
const auto reg = static_cast<u8>(((opc >> 8) & 0x7) + 0x18);
|
||||||
dsp_op_write_reg(reg, dsp_dmem_read(addr));
|
const auto addr = static_cast<u16>((state.r.cr << 8) | (opc & 0xFF));
|
||||||
dsp_conditional_extend_accum(reg);
|
|
||||||
|
OpWriteRegister(reg, state.ReadDMEM(addr));
|
||||||
|
ConditionalExtendAccum(reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// LR $D, @M
|
// LR $D, @M
|
||||||
// 0000 0000 110d dddd
|
// 0000 0000 110d dddd
|
||||||
// mmmm mmmm mmmm mmmm
|
// mmmm mmmm mmmm mmmm
|
||||||
// Move value from data memory pointed by address M to register $D.
|
// Move value from data memory pointed by address M to register $D.
|
||||||
void lr(const UDSPInstruction opc)
|
void Interpreter::lr(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 reg = opc & 0x1F;
|
auto& state = m_dsp_core.DSPState();
|
||||||
u16 addr = dsp_fetch_code();
|
const u8 reg = opc & 0x1F;
|
||||||
u16 val = dsp_dmem_read(addr);
|
const u16 addr = state.FetchInstruction();
|
||||||
dsp_op_write_reg(reg, val);
|
const u16 val = state.ReadDMEM(addr);
|
||||||
dsp_conditional_extend_accum(reg);
|
|
||||||
|
OpWriteRegister(reg, val);
|
||||||
|
ConditionalExtendAccum(reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SR @M, $S
|
// SR @M, $S
|
||||||
// 0000 0000 111s ssss
|
// 0000 0000 111s ssss
|
||||||
// mmmm mmmm mmmm mmmm
|
// mmmm mmmm mmmm mmmm
|
||||||
// Store value from register $S to a memory pointed by address M.
|
// Store value from register $S to a memory pointed by address M.
|
||||||
void sr(const UDSPInstruction opc)
|
void Interpreter::sr(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 reg = opc & 0x1F;
|
auto& state = m_dsp_core.DSPState();
|
||||||
u16 addr = dsp_fetch_code();
|
const u8 reg = opc & 0x1F;
|
||||||
|
const u16 addr = state.FetchInstruction();
|
||||||
|
|
||||||
if (reg >= DSP_REG_ACM0)
|
if (reg >= DSP_REG_ACM0)
|
||||||
dsp_dmem_write(addr, dsp_op_read_reg_and_saturate(reg - DSP_REG_ACM0));
|
state.WriteDMEM(addr, OpReadRegisterAndSaturate(reg - DSP_REG_ACM0));
|
||||||
else
|
else
|
||||||
dsp_dmem_write(addr, dsp_op_read_reg(reg));
|
state.WriteDMEM(addr, OpReadRegister(reg));
|
||||||
}
|
}
|
||||||
|
|
||||||
// SI @M, #I
|
// SI @M, #I
|
||||||
|
@ -73,176 +78,189 @@ void sr(const UDSPInstruction opc)
|
||||||
// iiii iiii iiii iiii
|
// iiii iiii iiii iiii
|
||||||
// Store 16-bit immediate value I to a memory location pointed by address
|
// Store 16-bit immediate value I to a memory location pointed by address
|
||||||
// M (M is 8-bit value sign extended).
|
// M (M is 8-bit value sign extended).
|
||||||
void si(const UDSPInstruction opc)
|
void Interpreter::si(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u16 addr = (s8)opc;
|
auto& state = m_dsp_core.DSPState();
|
||||||
u16 imm = dsp_fetch_code();
|
const u16 addr = static_cast<u16>(static_cast<s8>(opc));
|
||||||
dsp_dmem_write(addr, imm);
|
const u16 imm = state.FetchInstruction();
|
||||||
|
|
||||||
|
state.WriteDMEM(addr, imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// LRR $D, @$S
|
// LRR $D, @$S
|
||||||
// 0001 1000 0ssd dddd
|
// 0001 1000 0ssd dddd
|
||||||
// Move value from data memory pointed by addressing register $S to register $D.
|
// Move value from data memory pointed by addressing register $S to register $D.
|
||||||
void lrr(const UDSPInstruction opc)
|
void Interpreter::lrr(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 sreg = (opc >> 5) & 0x3;
|
const u8 sreg = (opc >> 5) & 0x3;
|
||||||
u8 dreg = opc & 0x1f;
|
const u8 dreg = opc & 0x1f;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
u16 val = dsp_dmem_read(dsp_op_read_reg(sreg));
|
const u16 val = state.ReadDMEM(OpReadRegister(sreg));
|
||||||
dsp_op_write_reg(dreg, val);
|
OpWriteRegister(dreg, val);
|
||||||
dsp_conditional_extend_accum(dreg);
|
ConditionalExtendAccum(dreg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// LRRD $D, @$S
|
// LRRD $D, @$S
|
||||||
// 0001 1000 1ssd dddd
|
// 0001 1000 1ssd dddd
|
||||||
// Move value from data memory pointed by addressing register $S to register $D.
|
// Move value from data memory pointed by addressing register $S to register $D.
|
||||||
// Decrement register $S.
|
// Decrement register $S.
|
||||||
void lrrd(const UDSPInstruction opc)
|
void Interpreter::lrrd(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 sreg = (opc >> 5) & 0x3;
|
const u8 sreg = (opc >> 5) & 0x3;
|
||||||
u8 dreg = opc & 0x1f;
|
const u8 dreg = opc & 0x1f;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
u16 val = dsp_dmem_read(dsp_op_read_reg(sreg));
|
const u16 val = state.ReadDMEM(OpReadRegister(sreg));
|
||||||
dsp_op_write_reg(dreg, val);
|
OpWriteRegister(dreg, val);
|
||||||
dsp_conditional_extend_accum(dreg);
|
ConditionalExtendAccum(dreg);
|
||||||
g_dsp.r.ar[sreg] = dsp_decrement_addr_reg(sreg);
|
state.r.ar[sreg] = DecrementAddressRegister(sreg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// LRRI $D, @$S
|
// LRRI $D, @$S
|
||||||
// 0001 1001 0ssd dddd
|
// 0001 1001 0ssd dddd
|
||||||
// Move value from data memory pointed by addressing register $S to register $D.
|
// Move value from data memory pointed by addressing register $S to register $D.
|
||||||
// Increment register $S.
|
// Increment register $S.
|
||||||
void lrri(const UDSPInstruction opc)
|
void Interpreter::lrri(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 sreg = (opc >> 5) & 0x3;
|
const u8 sreg = (opc >> 5) & 0x3;
|
||||||
u8 dreg = opc & 0x1f;
|
const u8 dreg = opc & 0x1f;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
u16 val = dsp_dmem_read(dsp_op_read_reg(sreg));
|
const u16 val = state.ReadDMEM(OpReadRegister(sreg));
|
||||||
dsp_op_write_reg(dreg, val);
|
OpWriteRegister(dreg, val);
|
||||||
dsp_conditional_extend_accum(dreg);
|
ConditionalExtendAccum(dreg);
|
||||||
g_dsp.r.ar[sreg] = dsp_increment_addr_reg(sreg);
|
state.r.ar[sreg] = IncrementAddressRegister(sreg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// LRRN $D, @$S
|
// LRRN $D, @$S
|
||||||
// 0001 1001 1ssd dddd
|
// 0001 1001 1ssd dddd
|
||||||
// Move value from data memory pointed by addressing register $S to register $D.
|
// Move value from data memory pointed by addressing register $S to register $D.
|
||||||
// Add indexing register $(0x4+S) to register $S.
|
// Add indexing register $(0x4+S) to register $S.
|
||||||
void lrrn(const UDSPInstruction opc)
|
void Interpreter::lrrn(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 sreg = (opc >> 5) & 0x3;
|
const u8 sreg = (opc >> 5) & 0x3;
|
||||||
u8 dreg = opc & 0x1f;
|
const u8 dreg = opc & 0x1f;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
u16 val = dsp_dmem_read(dsp_op_read_reg(sreg));
|
const u16 val = state.ReadDMEM(OpReadRegister(sreg));
|
||||||
dsp_op_write_reg(dreg, val);
|
OpWriteRegister(dreg, val);
|
||||||
dsp_conditional_extend_accum(dreg);
|
ConditionalExtendAccum(dreg);
|
||||||
g_dsp.r.ar[sreg] = dsp_increase_addr_reg(sreg, (s16)g_dsp.r.ix[sreg]);
|
state.r.ar[sreg] = IncreaseAddressRegister(sreg, static_cast<s16>(state.r.ix[sreg]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// SRR @$D, $S
|
// SRR @$D, $S
|
||||||
// 0001 1010 0dds ssss
|
// 0001 1010 0dds ssss
|
||||||
// Store value from source register $S to a memory location pointed by
|
// Store value from source register $S to a memory location pointed by
|
||||||
// addressing register $D.
|
// addressing register $D.
|
||||||
void srr(const UDSPInstruction opc)
|
void Interpreter::srr(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 dreg = (opc >> 5) & 0x3;
|
const u8 dreg = (opc >> 5) & 0x3;
|
||||||
u8 sreg = opc & 0x1f;
|
const u8 sreg = opc & 0x1f;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
if (sreg >= DSP_REG_ACM0)
|
if (sreg >= DSP_REG_ACM0)
|
||||||
dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0));
|
state.WriteDMEM(state.r.ar[dreg], OpReadRegisterAndSaturate(sreg - DSP_REG_ACM0));
|
||||||
else
|
else
|
||||||
dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg(sreg));
|
state.WriteDMEM(state.r.ar[dreg], OpReadRegister(sreg));
|
||||||
}
|
}
|
||||||
|
|
||||||
// SRRD @$D, $S
|
// SRRD @$D, $S
|
||||||
// 0001 1010 1dds ssss
|
// 0001 1010 1dds ssss
|
||||||
// Store value from source register $S to a memory location pointed by
|
// Store value from source register $S to a memory location pointed by
|
||||||
// addressing register $D. Decrement register $D.
|
// addressing register $D. Decrement register $D.
|
||||||
void srrd(const UDSPInstruction opc)
|
void Interpreter::srrd(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 dreg = (opc >> 5) & 0x3;
|
const u8 dreg = (opc >> 5) & 0x3;
|
||||||
u8 sreg = opc & 0x1f;
|
const u8 sreg = opc & 0x1f;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
if (sreg >= DSP_REG_ACM0)
|
if (sreg >= DSP_REG_ACM0)
|
||||||
dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0));
|
state.WriteDMEM(state.r.ar[dreg], OpReadRegisterAndSaturate(sreg - DSP_REG_ACM0));
|
||||||
else
|
else
|
||||||
dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg(sreg));
|
state.WriteDMEM(state.r.ar[dreg], OpReadRegister(sreg));
|
||||||
|
|
||||||
g_dsp.r.ar[dreg] = dsp_decrement_addr_reg(dreg);
|
state.r.ar[dreg] = DecrementAddressRegister(dreg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SRRI @$D, $S
|
// SRRI @$D, $S
|
||||||
// 0001 1011 0dds ssss
|
// 0001 1011 0dds ssss
|
||||||
// Store value from source register $S to a memory location pointed by
|
// Store value from source register $S to a memory location pointed by
|
||||||
// addressing register $D. Increment register $D.
|
// addressing register $D. Increment register $D.
|
||||||
void srri(const UDSPInstruction opc)
|
void Interpreter::srri(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 dreg = (opc >> 5) & 0x3;
|
const u8 dreg = (opc >> 5) & 0x3;
|
||||||
u8 sreg = opc & 0x1f;
|
const u8 sreg = opc & 0x1f;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
if (sreg >= DSP_REG_ACM0)
|
if (sreg >= DSP_REG_ACM0)
|
||||||
dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0));
|
state.WriteDMEM(state.r.ar[dreg], OpReadRegisterAndSaturate(sreg - DSP_REG_ACM0));
|
||||||
else
|
else
|
||||||
dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg(sreg));
|
state.WriteDMEM(state.r.ar[dreg], OpReadRegister(sreg));
|
||||||
|
|
||||||
g_dsp.r.ar[dreg] = dsp_increment_addr_reg(dreg);
|
state.r.ar[dreg] = IncrementAddressRegister(dreg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SRRN @$D, $S
|
// SRRN @$D, $S
|
||||||
// 0001 1011 1dds ssss
|
// 0001 1011 1dds ssss
|
||||||
// Store value from source register $S to a memory location pointed by
|
// Store value from source register $S to a memory location pointed by
|
||||||
// addressing register $D. Add DSP_REG_IX0 register to register $D.
|
// addressing register $D. Add DSP_REG_IX0 register to register $D.
|
||||||
void srrn(const UDSPInstruction opc)
|
void Interpreter::srrn(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 dreg = (opc >> 5) & 0x3;
|
const u8 dreg = (opc >> 5) & 0x3;
|
||||||
u8 sreg = opc & 0x1f;
|
const u8 sreg = opc & 0x1f;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
if (sreg >= DSP_REG_ACM0)
|
if (sreg >= DSP_REG_ACM0)
|
||||||
dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0));
|
state.WriteDMEM(state.r.ar[dreg], OpReadRegisterAndSaturate(sreg - DSP_REG_ACM0));
|
||||||
else
|
else
|
||||||
dsp_dmem_write(g_dsp.r.ar[dreg], dsp_op_read_reg(sreg));
|
state.WriteDMEM(state.r.ar[dreg], OpReadRegister(sreg));
|
||||||
|
|
||||||
g_dsp.r.ar[dreg] = dsp_increase_addr_reg(dreg, (s16)g_dsp.r.ix[dreg]);
|
state.r.ar[dreg] = IncreaseAddressRegister(dreg, static_cast<s16>(state.r.ix[dreg]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ILRR $acD.m, @$arS
|
// ILRR $acD.m, @$arS
|
||||||
// 0000 001d 0001 00ss
|
// 0000 001d 0001 00ss
|
||||||
// Move value from instruction memory pointed by addressing register
|
// Move value from instruction memory pointed by addressing register
|
||||||
// $arS to mid accumulator register $acD.m.
|
// $arS to mid accumulator register $acD.m.
|
||||||
void ilrr(const UDSPInstruction opc)
|
void Interpreter::ilrr(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u16 reg = opc & 0x3;
|
const u16 reg = opc & 0x3;
|
||||||
u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1);
|
const u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1);
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
g_dsp.r.ac[dreg - DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]);
|
state.r.ac[dreg - DSP_REG_ACM0].m = state.ReadIMEM(state.r.ar[reg]);
|
||||||
dsp_conditional_extend_accum(dreg);
|
ConditionalExtendAccum(dreg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ILRRD $acD.m, @$arS
|
// ILRRD $acD.m, @$arS
|
||||||
// 0000 001d 0001 01ss
|
// 0000 001d 0001 01ss
|
||||||
// Move value from instruction memory pointed by addressing register
|
// Move value from instruction memory pointed by addressing register
|
||||||
// $arS to mid accumulator register $acD.m. Decrement addressing register $arS.
|
// $arS to mid accumulator register $acD.m. Decrement addressing register $arS.
|
||||||
void ilrrd(const UDSPInstruction opc)
|
void Interpreter::ilrrd(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u16 reg = opc & 0x3;
|
const u16 reg = opc & 0x3;
|
||||||
u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1);
|
const u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1);
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
g_dsp.r.ac[dreg - DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]);
|
state.r.ac[dreg - DSP_REG_ACM0].m = state.ReadIMEM(state.r.ar[reg]);
|
||||||
dsp_conditional_extend_accum(dreg);
|
ConditionalExtendAccum(dreg);
|
||||||
g_dsp.r.ar[reg] = dsp_decrement_addr_reg(reg);
|
state.r.ar[reg] = DecrementAddressRegister(reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ILRRI $acD.m, @$S
|
// ILRRI $acD.m, @$S
|
||||||
// 0000 001d 0001 10ss
|
// 0000 001d 0001 10ss
|
||||||
// Move value from instruction memory pointed by addressing register
|
// Move value from instruction memory pointed by addressing register
|
||||||
// $arS to mid accumulator register $acD.m. Increment addressing register $arS.
|
// $arS to mid accumulator register $acD.m. Increment addressing register $arS.
|
||||||
void ilrri(const UDSPInstruction opc)
|
void Interpreter::ilrri(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u16 reg = opc & 0x3;
|
const u16 reg = opc & 0x3;
|
||||||
u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1);
|
const u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1);
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
g_dsp.r.ac[dreg - DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]);
|
state.r.ac[dreg - DSP_REG_ACM0].m = state.ReadIMEM(state.r.ar[reg]);
|
||||||
dsp_conditional_extend_accum(dreg);
|
ConditionalExtendAccum(dreg);
|
||||||
g_dsp.r.ar[reg] = dsp_increment_addr_reg(reg);
|
state.r.ar[reg] = IncrementAddressRegister(reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ILRRN $acD.m, @$arS
|
// ILRRN $acD.m, @$arS
|
||||||
|
@ -250,13 +268,14 @@ void ilrri(const UDSPInstruction opc)
|
||||||
// Move value from instruction memory pointed by addressing register
|
// Move value from instruction memory pointed by addressing register
|
||||||
// $arS to mid accumulator register $acD.m. Add corresponding indexing
|
// $arS to mid accumulator register $acD.m. Add corresponding indexing
|
||||||
// register $ixS to addressing register $arS.
|
// register $ixS to addressing register $arS.
|
||||||
void ilrrn(const UDSPInstruction opc)
|
void Interpreter::ilrrn(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u16 reg = opc & 0x3;
|
const u16 reg = opc & 0x3;
|
||||||
u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1);
|
const u16 dreg = DSP_REG_ACM0 + ((opc >> 8) & 1);
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
g_dsp.r.ac[dreg - DSP_REG_ACM0].m = dsp_imem_read(g_dsp.r.ar[reg]);
|
state.r.ac[dreg - DSP_REG_ACM0].m = state.ReadIMEM(state.r.ar[reg]);
|
||||||
dsp_conditional_extend_accum(dreg);
|
ConditionalExtendAccum(dreg);
|
||||||
g_dsp.r.ar[reg] = dsp_increase_addr_reg(reg, (s16)g_dsp.r.ix[reg]);
|
state.r.ar[reg] = IncreaseAddressRegister(reg, static_cast<s16>(state.r.ix[reg]));
|
||||||
}
|
}
|
||||||
} // namespace DSP::Interpreter
|
} // namespace DSP::Interpreter
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
// Additional copyrights go to Duddie and Tratax (c) 2004
|
// Additional copyrights go to Duddie and Tratax (c) 2004
|
||||||
|
|
||||||
#include "Core/DSP/DSPCore.h"
|
#include "Core/DSP/DSPCore.h"
|
||||||
#include "Core/DSP/DSPMemoryMap.h"
|
|
||||||
#include "Core/DSP/DSPTables.h"
|
#include "Core/DSP/DSPTables.h"
|
||||||
#include "Core/DSP/Interpreter/DSPIntUtil.h"
|
#include "Core/DSP/Interpreter/DSPIntUtil.h"
|
||||||
#include "Core/DSP/Interpreter/DSPInterpreter.h"
|
#include "Core/DSP/Interpreter/DSPInterpreter.h"
|
||||||
|
@ -15,17 +14,17 @@ namespace DSP::Interpreter
|
||||||
// MRR $D, $S
|
// MRR $D, $S
|
||||||
// 0001 11dd ddds ssss
|
// 0001 11dd ddds ssss
|
||||||
// Move value from register $S to register $D.
|
// Move value from register $S to register $D.
|
||||||
void mrr(const UDSPInstruction opc)
|
void Interpreter::mrr(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 sreg = opc & 0x1f;
|
const u8 sreg = opc & 0x1f;
|
||||||
u8 dreg = (opc >> 5) & 0x1f;
|
const u8 dreg = (opc >> 5) & 0x1f;
|
||||||
|
|
||||||
if (sreg >= DSP_REG_ACM0)
|
if (sreg >= DSP_REG_ACM0)
|
||||||
dsp_op_write_reg(dreg, dsp_op_read_reg_and_saturate(sreg - DSP_REG_ACM0));
|
OpWriteRegister(dreg, OpReadRegisterAndSaturate(sreg - DSP_REG_ACM0));
|
||||||
else
|
else
|
||||||
dsp_op_write_reg(dreg, dsp_op_read_reg(sreg));
|
OpWriteRegister(dreg, OpReadRegister(sreg));
|
||||||
|
|
||||||
dsp_conditional_extend_accum(dreg);
|
ConditionalExtendAccum(dreg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// LRI $D, #I
|
// LRI $D, #I
|
||||||
|
@ -37,23 +36,26 @@ void mrr(const UDSPInstruction opc)
|
||||||
// register, has a different behaviour in S40 mode if loaded to AC0.M: The
|
// register, has a different behaviour in S40 mode if loaded to AC0.M: The
|
||||||
// value gets sign extended to the whole accumulator! This does not happen in
|
// value gets sign extended to the whole accumulator! This does not happen in
|
||||||
// S16 mode.
|
// S16 mode.
|
||||||
void lri(const UDSPInstruction opc)
|
void Interpreter::lri(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 reg = opc & 0x1F;
|
auto& state = m_dsp_core.DSPState();
|
||||||
u16 imm = dsp_fetch_code();
|
const u8 reg = opc & 0x1F;
|
||||||
dsp_op_write_reg(reg, imm);
|
const u16 imm = state.FetchInstruction();
|
||||||
dsp_conditional_extend_accum(reg);
|
|
||||||
|
OpWriteRegister(reg, imm);
|
||||||
|
ConditionalExtendAccum(reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// LRIS $(0x18+D), #I
|
// LRIS $(0x18+D), #I
|
||||||
// 0000 1ddd iiii iiii
|
// 0000 1ddd iiii iiii
|
||||||
// Load immediate value I (8-bit sign extended) to accumulator register.
|
// Load immediate value I (8-bit sign extended) to accumulator register.
|
||||||
void lris(const UDSPInstruction opc)
|
void Interpreter::lris(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 reg = ((opc >> 8) & 0x7) + DSP_REG_AXL0;
|
const u8 reg = ((opc >> 8) & 0x7) + DSP_REG_AXL0;
|
||||||
u16 imm = (s8)opc;
|
const u16 imm = static_cast<u16>(static_cast<s8>(opc));
|
||||||
dsp_op_write_reg(reg, imm);
|
|
||||||
dsp_conditional_extend_accum(reg);
|
OpWriteRegister(reg, imm);
|
||||||
|
ConditionalExtendAccum(reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----
|
//----
|
||||||
|
@ -63,7 +65,7 @@ void lris(const UDSPInstruction opc)
|
||||||
// No operation, but can be extended with extended opcode.
|
// No operation, but can be extended with extended opcode.
|
||||||
// This opcode is supposed to do nothing - it's used if you want to use
|
// This opcode is supposed to do nothing - it's used if you want to use
|
||||||
// an opcode extension but not do anything. At least according to duddie.
|
// an opcode extension but not do anything. At least according to duddie.
|
||||||
void nx(const UDSPInstruction opc)
|
void Interpreter::nx(const UDSPInstruction)
|
||||||
{
|
{
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
}
|
}
|
||||||
|
@ -73,38 +75,48 @@ void nx(const UDSPInstruction opc)
|
||||||
// DAR $arD
|
// DAR $arD
|
||||||
// 0000 0000 0000 01dd
|
// 0000 0000 0000 01dd
|
||||||
// Decrement address register $arD.
|
// Decrement address register $arD.
|
||||||
void dar(const UDSPInstruction opc)
|
void Interpreter::dar(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
g_dsp.r.ar[opc & 0x3] = dsp_decrement_addr_reg(opc & 0x3);
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
const u16 index = opc & 3;
|
||||||
|
|
||||||
|
state.r.ar[index] = DecrementAddressRegister(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// IAR $arD
|
// IAR $arD
|
||||||
// 0000 0000 0000 10dd
|
// 0000 0000 0000 10dd
|
||||||
// Increment address register $arD.
|
// Increment address register $arD.
|
||||||
void iar(const UDSPInstruction opc)
|
void Interpreter::iar(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
g_dsp.r.ar[opc & 0x3] = dsp_increment_addr_reg(opc & 0x3);
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
const u16 index = opc & 3;
|
||||||
|
|
||||||
|
state.r.ar[index] = IncrementAddressRegister(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SUBARN $arD
|
// SUBARN $arD
|
||||||
// 0000 0000 0000 11dd
|
// 0000 0000 0000 11dd
|
||||||
// Subtract indexing register $ixD from an addressing register $arD.
|
// Subtract indexing register $ixD from an addressing register $arD.
|
||||||
// used only in IPL-NTSC ucode
|
// used only in IPL-NTSC ucode
|
||||||
void subarn(const UDSPInstruction opc)
|
void Interpreter::subarn(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 dreg = opc & 0x3;
|
auto& state = m_dsp_core.DSPState();
|
||||||
g_dsp.r.ar[dreg] = dsp_decrease_addr_reg(dreg, (s16)g_dsp.r.ix[dreg]);
|
const u8 dreg = opc & 0x3;
|
||||||
|
|
||||||
|
state.r.ar[dreg] = DecreaseAddressRegister(dreg, static_cast<s16>(state.r.ix[dreg]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ADDARN $arD, $ixS
|
// ADDARN $arD, $ixS
|
||||||
// 0000 0000 0001 ssdd
|
// 0000 0000 0001 ssdd
|
||||||
// Adds indexing register $ixS to an addressing register $arD.
|
// Adds indexing register $ixS to an addressing register $arD.
|
||||||
// It is critical for the Zelda ucode that this one wraps correctly.
|
// It is critical for the Zelda ucode that this one wraps correctly.
|
||||||
void addarn(const UDSPInstruction opc)
|
void Interpreter::addarn(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 dreg = opc & 0x3;
|
auto& state = m_dsp_core.DSPState();
|
||||||
u8 sreg = (opc >> 2) & 0x3;
|
const u8 dreg = opc & 0x3;
|
||||||
g_dsp.r.ar[dreg] = dsp_increase_addr_reg(dreg, (s16)g_dsp.r.ix[sreg]);
|
const u8 sreg = (opc >> 2) & 0x3;
|
||||||
|
|
||||||
|
state.r.ar[dreg] = IncreaseAddressRegister(dreg, static_cast<s16>(state.r.ix[sreg]));
|
||||||
}
|
}
|
||||||
|
|
||||||
//----
|
//----
|
||||||
|
@ -113,45 +125,51 @@ void addarn(const UDSPInstruction opc)
|
||||||
// 0001 0010 aaaa aiii
|
// 0001 0010 aaaa aiii
|
||||||
// bit of status register $sr. Bit number is calculated by adding 6 to
|
// bit of status register $sr. Bit number is calculated by adding 6 to
|
||||||
// immediate value I.
|
// immediate value I.
|
||||||
void sbclr(const UDSPInstruction opc)
|
void Interpreter::sbclr(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 bit = (opc & 0x7) + 6;
|
auto& state = m_dsp_core.DSPState();
|
||||||
g_dsp.r.sr &= ~(1 << bit);
|
const u8 bit = (opc & 0x7) + 6;
|
||||||
|
|
||||||
|
state.r.sr &= ~(1U << bit);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SBSET #I
|
// SBSET #I
|
||||||
// 0001 0011 aaaa aiii
|
// 0001 0011 aaaa aiii
|
||||||
// Set bit of status register $sr. Bit number is calculated by adding 6 to
|
// Set bit of status register $sr. Bit number is calculated by adding 6 to
|
||||||
// immediate value I.
|
// immediate value I.
|
||||||
void sbset(const UDSPInstruction opc)
|
void Interpreter::sbset(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 bit = (opc & 0x7) + 6;
|
auto& state = m_dsp_core.DSPState();
|
||||||
g_dsp.r.sr |= (1 << bit);
|
const u8 bit = (opc & 0x7) + 6;
|
||||||
|
|
||||||
|
state.r.sr |= (1U << bit);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a bunch of flag setters, flipping bits in SR.
|
// This is a bunch of flag setters, flipping bits in SR.
|
||||||
void srbith(const UDSPInstruction opc)
|
void Interpreter::srbith(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
switch ((opc >> 8) & 0x7)
|
switch ((opc >> 8) & 0x7)
|
||||||
{
|
{
|
||||||
case 2: // M2
|
case 2: // M2
|
||||||
g_dsp.r.sr &= ~SR_MUL_MODIFY;
|
state.r.sr &= ~SR_MUL_MODIFY;
|
||||||
break;
|
break;
|
||||||
case 3: // M0
|
case 3: // M0
|
||||||
g_dsp.r.sr |= SR_MUL_MODIFY;
|
state.r.sr |= SR_MUL_MODIFY;
|
||||||
break;
|
break;
|
||||||
case 4: // CLR15
|
case 4: // CLR15
|
||||||
g_dsp.r.sr &= ~SR_MUL_UNSIGNED;
|
state.r.sr &= ~SR_MUL_UNSIGNED;
|
||||||
break;
|
break;
|
||||||
case 5: // SET15
|
case 5: // SET15
|
||||||
g_dsp.r.sr |= SR_MUL_UNSIGNED;
|
state.r.sr |= SR_MUL_UNSIGNED;
|
||||||
break;
|
break;
|
||||||
case 6: // SET16 (CLR40)
|
case 6: // SET16 (CLR40)
|
||||||
g_dsp.r.sr &= ~SR_40_MODE_BIT;
|
state.r.sr &= ~SR_40_MODE_BIT;
|
||||||
break;
|
break;
|
||||||
case 7: // SET40
|
case 7: // SET40
|
||||||
g_dsp.r.sr |= SR_40_MODE_BIT;
|
state.r.sr |= SR_40_MODE_BIT;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -13,62 +13,6 @@
|
||||||
|
|
||||||
namespace DSP::Interpreter
|
namespace DSP::Interpreter
|
||||||
{
|
{
|
||||||
namespace
|
|
||||||
{
|
|
||||||
// Only MULX family instructions have unsigned/mixed support.
|
|
||||||
s64 dsp_get_multiply_prod(u16 a, u16 b, u8 sign)
|
|
||||||
{
|
|
||||||
s64 prod;
|
|
||||||
|
|
||||||
if ((sign == 1) && (g_dsp.r.sr & SR_MUL_UNSIGNED)) // unsigned
|
|
||||||
prod = (u32)(a * b);
|
|
||||||
else if ((sign == 2) && (g_dsp.r.sr & SR_MUL_UNSIGNED)) // mixed
|
|
||||||
prod = a * (s16)b;
|
|
||||||
else
|
|
||||||
prod = (s16)a * (s16)b; // signed
|
|
||||||
|
|
||||||
// Conditionally multiply by 2.
|
|
||||||
if ((g_dsp.r.sr & SR_MUL_MODIFY) == 0)
|
|
||||||
prod <<= 1;
|
|
||||||
|
|
||||||
return prod;
|
|
||||||
}
|
|
||||||
|
|
||||||
s64 dsp_multiply(u16 a, u16 b, u8 sign = 0)
|
|
||||||
{
|
|
||||||
s64 prod = dsp_get_multiply_prod(a, b, sign);
|
|
||||||
return prod;
|
|
||||||
}
|
|
||||||
|
|
||||||
s64 dsp_multiply_add(u16 a, u16 b, u8 sign = 0)
|
|
||||||
{
|
|
||||||
s64 prod = dsp_get_long_prod() + dsp_get_multiply_prod(a, b, sign);
|
|
||||||
return prod;
|
|
||||||
}
|
|
||||||
|
|
||||||
s64 dsp_multiply_sub(u16 a, u16 b, u8 sign = 0)
|
|
||||||
{
|
|
||||||
s64 prod = dsp_get_long_prod() - dsp_get_multiply_prod(a, b, sign);
|
|
||||||
return prod;
|
|
||||||
}
|
|
||||||
|
|
||||||
s64 dsp_multiply_mulx(u8 axh0, u8 axh1, u16 val1, u16 val2)
|
|
||||||
{
|
|
||||||
s64 result;
|
|
||||||
|
|
||||||
if ((axh0 == 0) && (axh1 == 0))
|
|
||||||
result = dsp_multiply(val1, val2, 1); // unsigned support ON if both ax?.l regs are used
|
|
||||||
else if ((axh0 == 0) && (axh1 == 1))
|
|
||||||
result = dsp_multiply(val1, val2, 2); // mixed support ON (u16)axl.0 * (s16)axh.1
|
|
||||||
else if ((axh0 == 1) && (axh1 == 0))
|
|
||||||
result = dsp_multiply(val2, val1, 2); // mixed support ON (u16)axl.1 * (s16)axh.0
|
|
||||||
else
|
|
||||||
result = dsp_multiply(val1, val2, 0); // unsigned support OFF if both ax?.h regs are used
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
} // Anonymous namespace
|
|
||||||
|
|
||||||
// CLRP
|
// CLRP
|
||||||
// 1000 0100 xxxx xxxx
|
// 1000 0100 xxxx xxxx
|
||||||
// Clears product register $prod.
|
// Clears product register $prod.
|
||||||
|
@ -78,14 +22,15 @@ s64 dsp_multiply_mulx(u8 axh0, u8 axh1, u16 val1, u16 val2)
|
||||||
//
|
//
|
||||||
// It's not ok, to just zero all of them, correct values should be set because of
|
// It's not ok, to just zero all of them, correct values should be set because of
|
||||||
// direct use of prod regs by AX/AXWII (look @that part of ucode).
|
// direct use of prod regs by AX/AXWII (look @that part of ucode).
|
||||||
void clrp(const UDSPInstruction opc)
|
void Interpreter::clrp(const UDSPInstruction)
|
||||||
{
|
{
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
|
|
||||||
g_dsp.r.prod.l = 0x0000;
|
auto& state = m_dsp_core.DSPState();
|
||||||
g_dsp.r.prod.m = 0xfff0;
|
state.r.prod.l = 0x0000;
|
||||||
g_dsp.r.prod.h = 0x00ff;
|
state.r.prod.m = 0xfff0;
|
||||||
g_dsp.r.prod.m2 = 0x0010;
|
state.r.prod.h = 0x00ff;
|
||||||
|
state.r.prod.m2 = 0x0010;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TSTPROD
|
// TSTPROD
|
||||||
|
@ -93,10 +38,10 @@ void clrp(const UDSPInstruction opc)
|
||||||
// Test prod regs value.
|
// Test prod regs value.
|
||||||
//
|
//
|
||||||
// flags out: --xx xx0x
|
// flags out: --xx xx0x
|
||||||
void tstprod(const UDSPInstruction opc)
|
void Interpreter::tstprod(const UDSPInstruction)
|
||||||
{
|
{
|
||||||
s64 prod = dsp_get_long_prod();
|
const s64 prod = GetLongProduct();
|
||||||
Update_SR_Register64(prod);
|
UpdateSR64(prod);
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,16 +52,15 @@ void tstprod(const UDSPInstruction opc)
|
||||||
// Moves multiply product from $prod register to accumulator $acD register.
|
// Moves multiply product from $prod register to accumulator $acD register.
|
||||||
//
|
//
|
||||||
// flags out: --xx xx0x
|
// flags out: --xx xx0x
|
||||||
void movp(const UDSPInstruction opc)
|
void Interpreter::movp(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 dreg = (opc >> 8) & 0x1;
|
const u8 dreg = (opc >> 8) & 0x1;
|
||||||
|
const s64 acc = GetLongProduct();
|
||||||
s64 acc = dsp_get_long_prod();
|
|
||||||
|
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
|
|
||||||
dsp_set_long_acc(dreg, acc);
|
SetLongAcc(dreg, acc);
|
||||||
Update_SR_Register64(acc);
|
UpdateSR64(acc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// MOVNP $acD
|
// MOVNP $acD
|
||||||
|
@ -125,16 +69,15 @@ void movp(const UDSPInstruction opc)
|
||||||
// $acD register.
|
// $acD register.
|
||||||
//
|
//
|
||||||
// flags out: --xx xx0x
|
// flags out: --xx xx0x
|
||||||
void movnp(const UDSPInstruction opc)
|
void Interpreter::movnp(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 dreg = (opc >> 8) & 0x1;
|
const u8 dreg = (opc >> 8) & 0x1;
|
||||||
|
const s64 acc = -GetLongProduct();
|
||||||
s64 acc = -dsp_get_long_prod();
|
|
||||||
|
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
|
|
||||||
dsp_set_long_acc(dreg, acc);
|
SetLongAcc(dreg, acc);
|
||||||
Update_SR_Register64(acc);
|
UpdateSR64(acc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// MOVPZ $acD
|
// MOVPZ $acD
|
||||||
|
@ -143,16 +86,15 @@ void movnp(const UDSPInstruction opc)
|
||||||
// register and sets (rounds) $acD.l to 0
|
// register and sets (rounds) $acD.l to 0
|
||||||
//
|
//
|
||||||
// flags out: --xx xx0x
|
// flags out: --xx xx0x
|
||||||
void movpz(const UDSPInstruction opc)
|
void Interpreter::movpz(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 dreg = (opc >> 8) & 0x01;
|
const u8 dreg = (opc >> 8) & 0x01;
|
||||||
|
const s64 acc = GetLongProductRounded();
|
||||||
s64 acc = dsp_get_long_prod_round_prodl();
|
|
||||||
|
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
|
|
||||||
dsp_set_long_acc(dreg, acc);
|
SetLongAcc(dreg, acc);
|
||||||
Update_SR_Register64(acc);
|
UpdateSR64(acc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ADDPAXZ $acD, $axS
|
// ADDPAXZ $acD, $axS
|
||||||
|
@ -162,21 +104,21 @@ void movpz(const UDSPInstruction opc)
|
||||||
//
|
//
|
||||||
// TODO: ugly code and still small error here (+/- 1 in .m - randomly)
|
// TODO: ugly code and still small error here (+/- 1 in .m - randomly)
|
||||||
// flags out: --xx xx0x
|
// flags out: --xx xx0x
|
||||||
void addpaxz(const UDSPInstruction opc)
|
void Interpreter::addpaxz(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 dreg = (opc >> 8) & 0x1;
|
const u8 dreg = (opc >> 8) & 0x1;
|
||||||
u8 sreg = (opc >> 9) & 0x1;
|
const u8 sreg = (opc >> 9) & 0x1;
|
||||||
|
|
||||||
s64 oldprod = dsp_get_long_prod();
|
const s64 oldprod = GetLongProduct();
|
||||||
s64 prod = dsp_get_long_prod_round_prodl();
|
const s64 prod = GetLongProductRounded();
|
||||||
s64 ax = dsp_get_long_acx(sreg);
|
const s64 ax = GetLongACX(sreg);
|
||||||
s64 res = prod + (ax & ~0xffff);
|
s64 res = prod + (ax & ~0xffff);
|
||||||
|
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
|
|
||||||
dsp_set_long_acc(dreg, res);
|
SetLongAcc(dreg, res);
|
||||||
res = dsp_get_long_acc(dreg);
|
res = GetLongAcc(dreg);
|
||||||
Update_SR_Register64(res, isCarry(oldprod, res), false);
|
UpdateSR64(res, isCarry(oldprod, res), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----
|
//----
|
||||||
|
@ -184,13 +126,14 @@ void addpaxz(const UDSPInstruction opc)
|
||||||
// MULAXH
|
// MULAXH
|
||||||
// 1000 0011 xxxx xxxx
|
// 1000 0011 xxxx xxxx
|
||||||
// Multiply $ax0.h by $ax0.h
|
// Multiply $ax0.h by $ax0.h
|
||||||
void mulaxh(const UDSPInstruction opc)
|
void Interpreter::mulaxh(const UDSPInstruction)
|
||||||
{
|
{
|
||||||
s64 prod = dsp_multiply(dsp_get_ax_h(0), dsp_get_ax_h(0));
|
const s16 value = GetAXHigh(0);
|
||||||
|
const s64 prod = Multiply(value, value);
|
||||||
|
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
|
|
||||||
dsp_set_long_prod(prod);
|
SetLongProduct(prod);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----
|
//----
|
||||||
|
@ -199,17 +142,16 @@ void mulaxh(const UDSPInstruction opc)
|
||||||
// 1001 s000 xxxx xxxx
|
// 1001 s000 xxxx xxxx
|
||||||
// Multiply low part $axS.l of secondary accumulator $axS by high part
|
// Multiply low part $axS.l of secondary accumulator $axS by high part
|
||||||
// $axS.h of secondary accumulator $axS (treat them both as signed).
|
// $axS.h of secondary accumulator $axS (treat them both as signed).
|
||||||
void mul(const UDSPInstruction opc)
|
void Interpreter::mul(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 sreg = (opc >> 11) & 0x1;
|
const u8 sreg = (opc >> 11) & 0x1;
|
||||||
|
const u16 axl = GetAXLow(sreg);
|
||||||
u16 axl = dsp_get_ax_l(sreg);
|
const u16 axh = GetAXHigh(sreg);
|
||||||
u16 axh = dsp_get_ax_h(sreg);
|
const s64 prod = Multiply(axh, axl);
|
||||||
s64 prod = dsp_multiply(axh, axl);
|
|
||||||
|
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
|
|
||||||
dsp_set_long_prod(prod);
|
SetLongProduct(prod);
|
||||||
}
|
}
|
||||||
|
|
||||||
// MULAC $axS.l, $axS.h, $acR
|
// MULAC $axS.l, $axS.h, $acR
|
||||||
|
@ -219,21 +161,21 @@ void mul(const UDSPInstruction opc)
|
||||||
// accumulator $axS (treat them both as signed).
|
// accumulator $axS (treat them both as signed).
|
||||||
//
|
//
|
||||||
// flags out: --xx xx0x
|
// flags out: --xx xx0x
|
||||||
void mulac(const UDSPInstruction opc)
|
void Interpreter::mulac(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 rreg = (opc >> 8) & 0x1;
|
const u8 rreg = (opc >> 8) & 0x1;
|
||||||
u8 sreg = (opc >> 11) & 0x1;
|
const u8 sreg = (opc >> 11) & 0x1;
|
||||||
|
|
||||||
s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod();
|
const s64 acc = GetLongAcc(rreg) + GetLongProduct();
|
||||||
u16 axl = dsp_get_ax_l(sreg);
|
const u16 axl = GetAXLow(sreg);
|
||||||
u16 axh = dsp_get_ax_h(sreg);
|
const u16 axh = GetAXHigh(sreg);
|
||||||
s64 prod = dsp_multiply(axl, axh);
|
const s64 prod = Multiply(axl, axh);
|
||||||
|
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
|
|
||||||
dsp_set_long_prod(prod);
|
SetLongProduct(prod);
|
||||||
dsp_set_long_acc(rreg, acc);
|
SetLongAcc(rreg, acc);
|
||||||
Update_SR_Register64(dsp_get_long_acc(rreg));
|
UpdateSR64(GetLongAcc(rreg));
|
||||||
}
|
}
|
||||||
|
|
||||||
// MULMV $axS.l, $axS.h, $acR
|
// MULMV $axS.l, $axS.h, $acR
|
||||||
|
@ -243,21 +185,21 @@ void mulac(const UDSPInstruction opc)
|
||||||
// accumulator $axS (treat them both as signed).
|
// accumulator $axS (treat them both as signed).
|
||||||
//
|
//
|
||||||
// flags out: --xx xx0x
|
// flags out: --xx xx0x
|
||||||
void mulmv(const UDSPInstruction opc)
|
void Interpreter::mulmv(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 rreg = (opc >> 8) & 0x1;
|
const u8 rreg = (opc >> 8) & 0x1;
|
||||||
u8 sreg = ((opc >> 11) & 0x1);
|
const u8 sreg = ((opc >> 11) & 0x1);
|
||||||
|
|
||||||
s64 acc = dsp_get_long_prod();
|
const s64 acc = GetLongProduct();
|
||||||
u16 axl = dsp_get_ax_l(sreg);
|
const u16 axl = GetAXLow(sreg);
|
||||||
u16 axh = dsp_get_ax_h(sreg);
|
const u16 axh = GetAXHigh(sreg);
|
||||||
s64 prod = dsp_multiply(axl, axh);
|
const s64 prod = Multiply(axl, axh);
|
||||||
|
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
|
|
||||||
dsp_set_long_prod(prod);
|
SetLongProduct(prod);
|
||||||
dsp_set_long_acc(rreg, acc);
|
SetLongAcc(rreg, acc);
|
||||||
Update_SR_Register64(dsp_get_long_acc(rreg));
|
UpdateSR64(GetLongAcc(rreg));
|
||||||
}
|
}
|
||||||
|
|
||||||
// MULMVZ $axS.l, $axS.h, $acR
|
// MULMVZ $axS.l, $axS.h, $acR
|
||||||
|
@ -268,21 +210,21 @@ void mulmv(const UDSPInstruction opc)
|
||||||
// them both as signed).
|
// them both as signed).
|
||||||
//
|
//
|
||||||
// flags out: --xx xx0x
|
// flags out: --xx xx0x
|
||||||
void mulmvz(const UDSPInstruction opc)
|
void Interpreter::mulmvz(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 rreg = (opc >> 8) & 0x1;
|
const u8 rreg = (opc >> 8) & 0x1;
|
||||||
u8 sreg = (opc >> 11) & 0x1;
|
const u8 sreg = (opc >> 11) & 0x1;
|
||||||
|
|
||||||
s64 acc = dsp_get_long_prod_round_prodl();
|
const s64 acc = GetLongProductRounded();
|
||||||
u16 axl = dsp_get_ax_l(sreg);
|
const u16 axl = GetAXLow(sreg);
|
||||||
u16 axh = dsp_get_ax_h(sreg);
|
const u16 axh = GetAXHigh(sreg);
|
||||||
s64 prod = dsp_multiply(axl, axh);
|
const s64 prod = Multiply(axl, axh);
|
||||||
|
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
|
|
||||||
dsp_set_long_prod(prod);
|
SetLongProduct(prod);
|
||||||
dsp_set_long_acc(rreg, acc);
|
SetLongAcc(rreg, acc);
|
||||||
Update_SR_Register64(dsp_get_long_acc(rreg));
|
UpdateSR64(GetLongAcc(rreg));
|
||||||
}
|
}
|
||||||
|
|
||||||
//----
|
//----
|
||||||
|
@ -291,18 +233,18 @@ void mulmvz(const UDSPInstruction opc)
|
||||||
// 101s t000 xxxx xxxx
|
// 101s t000 xxxx xxxx
|
||||||
// Multiply one part $ax0 by one part $ax1.
|
// Multiply one part $ax0 by one part $ax1.
|
||||||
// Part is selected by S and T bits. Zero selects low part, one selects high part.
|
// Part is selected by S and T bits. Zero selects low part, one selects high part.
|
||||||
void mulx(const UDSPInstruction opc)
|
void Interpreter::mulx(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 treg = ((opc >> 11) & 0x1);
|
const u8 treg = ((opc >> 11) & 0x1);
|
||||||
u8 sreg = ((opc >> 12) & 0x1);
|
const u8 sreg = ((opc >> 12) & 0x1);
|
||||||
|
|
||||||
u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
|
const u16 val1 = (sreg == 0) ? GetAXLow(0) : GetAXHigh(0);
|
||||||
u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
|
const u16 val2 = (treg == 0) ? GetAXLow(1) : GetAXHigh(1);
|
||||||
s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2);
|
const s64 prod = MultiplyMulX(sreg, treg, val1, val2);
|
||||||
|
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
|
|
||||||
dsp_set_long_prod(prod);
|
SetLongProduct(prod);
|
||||||
}
|
}
|
||||||
|
|
||||||
// MULXAC $ax0.S, $ax1.T, $acR
|
// MULXAC $ax0.S, $ax1.T, $acR
|
||||||
|
@ -312,22 +254,22 @@ void mulx(const UDSPInstruction opc)
|
||||||
// T bits. Zero selects low part, one selects high part.
|
// T bits. Zero selects low part, one selects high part.
|
||||||
//
|
//
|
||||||
// flags out: --xx xx0x
|
// flags out: --xx xx0x
|
||||||
void mulxac(const UDSPInstruction opc)
|
void Interpreter::mulxac(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 rreg = (opc >> 8) & 0x1;
|
const u8 rreg = (opc >> 8) & 0x1;
|
||||||
u8 treg = (opc >> 11) & 0x1;
|
const u8 treg = (opc >> 11) & 0x1;
|
||||||
u8 sreg = (opc >> 12) & 0x1;
|
const u8 sreg = (opc >> 12) & 0x1;
|
||||||
|
|
||||||
s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod();
|
const s64 acc = GetLongAcc(rreg) + GetLongProduct();
|
||||||
u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
|
const u16 val1 = (sreg == 0) ? GetAXLow(0) : GetAXHigh(0);
|
||||||
u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
|
const u16 val2 = (treg == 0) ? GetAXLow(1) : GetAXHigh(1);
|
||||||
s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2);
|
const s64 prod = MultiplyMulX(sreg, treg, val1, val2);
|
||||||
|
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
|
|
||||||
dsp_set_long_prod(prod);
|
SetLongProduct(prod);
|
||||||
dsp_set_long_acc(rreg, acc);
|
SetLongAcc(rreg, acc);
|
||||||
Update_SR_Register64(dsp_get_long_acc(rreg));
|
UpdateSR64(GetLongAcc(rreg));
|
||||||
}
|
}
|
||||||
|
|
||||||
// MULXMV $ax0.S, $ax1.T, $acR
|
// MULXMV $ax0.S, $ax1.T, $acR
|
||||||
|
@ -337,22 +279,22 @@ void mulxac(const UDSPInstruction opc)
|
||||||
// T bits. Zero selects low part, one selects high part.
|
// T bits. Zero selects low part, one selects high part.
|
||||||
//
|
//
|
||||||
// flags out: --xx xx0x
|
// flags out: --xx xx0x
|
||||||
void mulxmv(const UDSPInstruction opc)
|
void Interpreter::mulxmv(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 rreg = ((opc >> 8) & 0x1);
|
const u8 rreg = ((opc >> 8) & 0x1);
|
||||||
u8 treg = (opc >> 11) & 0x1;
|
const u8 treg = (opc >> 11) & 0x1;
|
||||||
u8 sreg = (opc >> 12) & 0x1;
|
const u8 sreg = (opc >> 12) & 0x1;
|
||||||
|
|
||||||
s64 acc = dsp_get_long_prod();
|
const s64 acc = GetLongProduct();
|
||||||
u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
|
const u16 val1 = (sreg == 0) ? GetAXLow(0) : GetAXHigh(0);
|
||||||
u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
|
const u16 val2 = (treg == 0) ? GetAXLow(1) : GetAXHigh(1);
|
||||||
s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2);
|
const s64 prod = MultiplyMulX(sreg, treg, val1, val2);
|
||||||
|
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
|
|
||||||
dsp_set_long_prod(prod);
|
SetLongProduct(prod);
|
||||||
dsp_set_long_acc(rreg, acc);
|
SetLongAcc(rreg, acc);
|
||||||
Update_SR_Register64(dsp_get_long_acc(rreg));
|
UpdateSR64(GetLongAcc(rreg));
|
||||||
}
|
}
|
||||||
|
|
||||||
// MULXMVZ $ax0.S, $ax1.T, $acR
|
// MULXMVZ $ax0.S, $ax1.T, $acR
|
||||||
|
@ -363,22 +305,22 @@ void mulxmv(const UDSPInstruction opc)
|
||||||
// one selects high part.
|
// one selects high part.
|
||||||
//
|
//
|
||||||
// flags out: --xx xx0x
|
// flags out: --xx xx0x
|
||||||
void mulxmvz(const UDSPInstruction opc)
|
void Interpreter::mulxmvz(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 rreg = (opc >> 8) & 0x1;
|
const u8 rreg = (opc >> 8) & 0x1;
|
||||||
u8 treg = (opc >> 11) & 0x1;
|
const u8 treg = (opc >> 11) & 0x1;
|
||||||
u8 sreg = (opc >> 12) & 0x1;
|
const u8 sreg = (opc >> 12) & 0x1;
|
||||||
|
|
||||||
s64 acc = dsp_get_long_prod_round_prodl();
|
const s64 acc = GetLongProductRounded();
|
||||||
u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
|
const u16 val1 = (sreg == 0) ? GetAXLow(0) : GetAXHigh(0);
|
||||||
u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
|
const u16 val2 = (treg == 0) ? GetAXLow(1) : GetAXHigh(1);
|
||||||
s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2);
|
const s64 prod = MultiplyMulX(sreg, treg, val1, val2);
|
||||||
|
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
|
|
||||||
dsp_set_long_prod(prod);
|
SetLongProduct(prod);
|
||||||
dsp_set_long_acc(rreg, acc);
|
SetLongAcc(rreg, acc);
|
||||||
Update_SR_Register64(dsp_get_long_acc(rreg));
|
UpdateSR64(GetLongAcc(rreg));
|
||||||
}
|
}
|
||||||
|
|
||||||
//----
|
//----
|
||||||
|
@ -387,18 +329,18 @@ void mulxmvz(const UDSPInstruction opc)
|
||||||
// 110s t000 xxxx xxxx
|
// 110s t000 xxxx xxxx
|
||||||
// Multiply mid part of accumulator register $acS.m by high part $axS.h of
|
// Multiply mid part of accumulator register $acS.m by high part $axS.h of
|
||||||
// secondary accumulator $axS (treat them both as signed).
|
// secondary accumulator $axS (treat them both as signed).
|
||||||
void mulc(const UDSPInstruction opc)
|
void Interpreter::mulc(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 treg = (opc >> 11) & 0x1;
|
const u8 treg = (opc >> 11) & 0x1;
|
||||||
u8 sreg = (opc >> 12) & 0x1;
|
const u8 sreg = (opc >> 12) & 0x1;
|
||||||
|
|
||||||
u16 accm = dsp_get_acc_m(sreg);
|
const u16 accm = GetAccMid(sreg);
|
||||||
u16 axh = dsp_get_ax_h(treg);
|
const u16 axh = GetAXHigh(treg);
|
||||||
s64 prod = dsp_multiply(accm, axh);
|
const s64 prod = Multiply(accm, axh);
|
||||||
|
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
|
|
||||||
dsp_set_long_prod(prod);
|
SetLongProduct(prod);
|
||||||
}
|
}
|
||||||
|
|
||||||
// MULCAC $acS.m, $axT.h, $acR
|
// MULCAC $acS.m, $axT.h, $acR
|
||||||
|
@ -408,22 +350,22 @@ void mulc(const UDSPInstruction opc)
|
||||||
// register before multiplication to accumulator $acR.
|
// register before multiplication to accumulator $acR.
|
||||||
//
|
//
|
||||||
// flags out: --xx xx0x
|
// flags out: --xx xx0x
|
||||||
void mulcac(const UDSPInstruction opc)
|
void Interpreter::mulcac(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 rreg = (opc >> 8) & 0x1;
|
const u8 rreg = (opc >> 8) & 0x1;
|
||||||
u8 treg = (opc >> 11) & 0x1;
|
const u8 treg = (opc >> 11) & 0x1;
|
||||||
u8 sreg = (opc >> 12) & 0x1;
|
const u8 sreg = (opc >> 12) & 0x1;
|
||||||
|
|
||||||
s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod();
|
const s64 acc = GetLongAcc(rreg) + GetLongProduct();
|
||||||
u16 accm = dsp_get_acc_m(sreg);
|
const u16 accm = GetAccMid(sreg);
|
||||||
u16 axh = dsp_get_ax_h(treg);
|
const u16 axh = GetAXHigh(treg);
|
||||||
s64 prod = dsp_multiply(accm, axh);
|
const s64 prod = Multiply(accm, axh);
|
||||||
|
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
|
|
||||||
dsp_set_long_prod(prod);
|
SetLongProduct(prod);
|
||||||
dsp_set_long_acc(rreg, acc);
|
SetLongAcc(rreg, acc);
|
||||||
Update_SR_Register64(dsp_get_long_acc(rreg));
|
UpdateSR64(GetLongAcc(rreg));
|
||||||
}
|
}
|
||||||
|
|
||||||
// MULCMV $acS.m, $axT.h, $acR
|
// MULCMV $acS.m, $axT.h, $acR
|
||||||
|
@ -434,22 +376,22 @@ void mulcac(const UDSPInstruction opc)
|
||||||
// possible mistake in duddie's doc axT.h rather than axS.h
|
// possible mistake in duddie's doc axT.h rather than axS.h
|
||||||
//
|
//
|
||||||
// flags out: --xx xx0x
|
// flags out: --xx xx0x
|
||||||
void mulcmv(const UDSPInstruction opc)
|
void Interpreter::mulcmv(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 rreg = (opc >> 8) & 0x1;
|
const u8 rreg = (opc >> 8) & 0x1;
|
||||||
u8 treg = (opc >> 11) & 0x1;
|
const u8 treg = (opc >> 11) & 0x1;
|
||||||
u8 sreg = (opc >> 12) & 0x1;
|
const u8 sreg = (opc >> 12) & 0x1;
|
||||||
|
|
||||||
s64 acc = dsp_get_long_prod();
|
const s64 acc = GetLongProduct();
|
||||||
u16 accm = dsp_get_acc_m(sreg);
|
const u16 accm = GetAccMid(sreg);
|
||||||
u16 axh = dsp_get_ax_h(treg);
|
const u16 axh = GetAXHigh(treg);
|
||||||
s64 prod = dsp_multiply(accm, axh);
|
const s64 prod = Multiply(accm, axh);
|
||||||
|
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
|
|
||||||
dsp_set_long_prod(prod);
|
SetLongProduct(prod);
|
||||||
dsp_set_long_acc(rreg, acc);
|
SetLongAcc(rreg, acc);
|
||||||
Update_SR_Register64(dsp_get_long_acc(rreg));
|
UpdateSR64(GetLongAcc(rreg));
|
||||||
}
|
}
|
||||||
|
|
||||||
// MULCMVZ $acS.m, $axT.h, $acR
|
// MULCMVZ $acS.m, $axT.h, $acR
|
||||||
|
@ -461,22 +403,22 @@ void mulcmv(const UDSPInstruction opc)
|
||||||
// accumulator $acR.l to zero.
|
// accumulator $acR.l to zero.
|
||||||
//
|
//
|
||||||
// flags out: --xx xx0x
|
// flags out: --xx xx0x
|
||||||
void mulcmvz(const UDSPInstruction opc)
|
void Interpreter::mulcmvz(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 rreg = (opc >> 8) & 0x1;
|
const u8 rreg = (opc >> 8) & 0x1;
|
||||||
u8 treg = (opc >> 11) & 0x1;
|
const u8 treg = (opc >> 11) & 0x1;
|
||||||
u8 sreg = (opc >> 12) & 0x1;
|
const u8 sreg = (opc >> 12) & 0x1;
|
||||||
|
|
||||||
s64 acc = dsp_get_long_prod_round_prodl();
|
const s64 acc = GetLongProductRounded();
|
||||||
u16 accm = dsp_get_acc_m(sreg);
|
const u16 accm = GetAccMid(sreg);
|
||||||
u16 axh = dsp_get_ax_h(treg);
|
const u16 axh = GetAXHigh(treg);
|
||||||
s64 prod = dsp_multiply(accm, axh);
|
const s64 prod = Multiply(accm, axh);
|
||||||
|
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
|
|
||||||
dsp_set_long_prod(prod);
|
SetLongProduct(prod);
|
||||||
dsp_set_long_acc(rreg, acc);
|
SetLongAcc(rreg, acc);
|
||||||
Update_SR_Register64(dsp_get_long_acc(rreg));
|
UpdateSR64(GetLongAcc(rreg));
|
||||||
}
|
}
|
||||||
|
|
||||||
//----
|
//----
|
||||||
|
@ -486,18 +428,18 @@ void mulcmvz(const UDSPInstruction opc)
|
||||||
// Multiply one part of secondary accumulator $ax0 (selected by S) by
|
// Multiply one part of secondary accumulator $ax0 (selected by S) by
|
||||||
// one part of secondary accumulator $ax1 (selected by T) (treat them both as
|
// one part of secondary accumulator $ax1 (selected by T) (treat them both as
|
||||||
// signed) and add result to product register.
|
// signed) and add result to product register.
|
||||||
void maddx(const UDSPInstruction opc)
|
void Interpreter::maddx(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 treg = (opc >> 8) & 0x1;
|
const u8 treg = (opc >> 8) & 0x1;
|
||||||
u8 sreg = (opc >> 9) & 0x1;
|
const u8 sreg = (opc >> 9) & 0x1;
|
||||||
|
|
||||||
u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
|
const u16 val1 = (sreg == 0) ? GetAXLow(0) : GetAXHigh(0);
|
||||||
u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
|
const u16 val2 = (treg == 0) ? GetAXLow(1) : GetAXHigh(1);
|
||||||
s64 prod = dsp_multiply_add(val1, val2);
|
const s64 prod = MultiplyAdd(val1, val2);
|
||||||
|
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
|
|
||||||
dsp_set_long_prod(prod);
|
SetLongProduct(prod);
|
||||||
}
|
}
|
||||||
|
|
||||||
// MSUBX $(0x18+S*2), $(0x19+T*2)
|
// MSUBX $(0x18+S*2), $(0x19+T*2)
|
||||||
|
@ -505,18 +447,18 @@ void maddx(const UDSPInstruction opc)
|
||||||
// Multiply one part of secondary accumulator $ax0 (selected by S) by
|
// Multiply one part of secondary accumulator $ax0 (selected by S) by
|
||||||
// one part of secondary accumulator $ax1 (selected by T) (treat them both as
|
// one part of secondary accumulator $ax1 (selected by T) (treat them both as
|
||||||
// signed) and subtract result from product register.
|
// signed) and subtract result from product register.
|
||||||
void msubx(const UDSPInstruction opc)
|
void Interpreter::msubx(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 treg = (opc >> 8) & 0x1;
|
const u8 treg = (opc >> 8) & 0x1;
|
||||||
u8 sreg = (opc >> 9) & 0x1;
|
const u8 sreg = (opc >> 9) & 0x1;
|
||||||
|
|
||||||
u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
|
const u16 val1 = (sreg == 0) ? GetAXLow(0) : GetAXHigh(0);
|
||||||
u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
|
const u16 val2 = (treg == 0) ? GetAXLow(1) : GetAXHigh(1);
|
||||||
s64 prod = dsp_multiply_sub(val1, val2);
|
const s64 prod = MultiplySub(val1, val2);
|
||||||
|
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
|
|
||||||
dsp_set_long_prod(prod);
|
SetLongProduct(prod);
|
||||||
}
|
}
|
||||||
|
|
||||||
// MADDC $acS.m, $axT.h
|
// MADDC $acS.m, $axT.h
|
||||||
|
@ -524,18 +466,18 @@ void msubx(const UDSPInstruction opc)
|
||||||
// Multiply middle part of accumulator $acS.m by high part of secondary
|
// Multiply middle part of accumulator $acS.m by high part of secondary
|
||||||
// accumulator $axT.h (treat them both as signed) and add result to product
|
// accumulator $axT.h (treat them both as signed) and add result to product
|
||||||
// register.
|
// register.
|
||||||
void maddc(const UDSPInstruction opc)
|
void Interpreter::maddc(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 treg = (opc >> 8) & 0x1;
|
const u8 treg = (opc >> 8) & 0x1;
|
||||||
u8 sreg = (opc >> 9) & 0x1;
|
const u8 sreg = (opc >> 9) & 0x1;
|
||||||
|
|
||||||
u16 accm = dsp_get_acc_m(sreg);
|
const u16 accm = GetAccMid(sreg);
|
||||||
u16 axh = dsp_get_ax_h(treg);
|
const u16 axh = GetAXHigh(treg);
|
||||||
s64 prod = dsp_multiply_add(accm, axh);
|
const s64 prod = MultiplyAdd(accm, axh);
|
||||||
|
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
|
|
||||||
dsp_set_long_prod(prod);
|
SetLongProduct(prod);
|
||||||
}
|
}
|
||||||
|
|
||||||
// MSUBC $acS.m, $axT.h
|
// MSUBC $acS.m, $axT.h
|
||||||
|
@ -543,18 +485,18 @@ void maddc(const UDSPInstruction opc)
|
||||||
// Multiply middle part of accumulator $acS.m by high part of secondary
|
// Multiply middle part of accumulator $acS.m by high part of secondary
|
||||||
// accumulator $axT.h (treat them both as signed) and subtract result from
|
// accumulator $axT.h (treat them both as signed) and subtract result from
|
||||||
// product register.
|
// product register.
|
||||||
void msubc(const UDSPInstruction opc)
|
void Interpreter::msubc(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 treg = (opc >> 8) & 0x1;
|
const u8 treg = (opc >> 8) & 0x1;
|
||||||
u8 sreg = (opc >> 9) & 0x1;
|
const u8 sreg = (opc >> 9) & 0x1;
|
||||||
|
|
||||||
u16 accm = dsp_get_acc_m(sreg);
|
const u16 accm = GetAccMid(sreg);
|
||||||
u16 axh = dsp_get_ax_h(treg);
|
const u16 axh = GetAXHigh(treg);
|
||||||
s64 prod = dsp_multiply_sub(accm, axh);
|
const s64 prod = MultiplySub(accm, axh);
|
||||||
|
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
|
|
||||||
dsp_set_long_prod(prod);
|
SetLongProduct(prod);
|
||||||
}
|
}
|
||||||
|
|
||||||
// MADD $axS.l, $axS.h
|
// MADD $axS.l, $axS.h
|
||||||
|
@ -562,17 +504,16 @@ void msubc(const UDSPInstruction opc)
|
||||||
// Multiply low part $axS.l of secondary accumulator $axS by high part
|
// Multiply low part $axS.l of secondary accumulator $axS by high part
|
||||||
// $axS.h of secondary accumulator $axS (treat them both as signed) and add
|
// $axS.h of secondary accumulator $axS (treat them both as signed) and add
|
||||||
// result to product register.
|
// result to product register.
|
||||||
void madd(const UDSPInstruction opc)
|
void Interpreter::madd(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 sreg = (opc >> 8) & 0x1;
|
const u8 sreg = (opc >> 8) & 0x1;
|
||||||
|
const u16 axl = GetAXLow(sreg);
|
||||||
u16 axl = dsp_get_ax_l(sreg);
|
const u16 axh = GetAXHigh(sreg);
|
||||||
u16 axh = dsp_get_ax_h(sreg);
|
const s64 prod = MultiplyAdd(axl, axh);
|
||||||
s64 prod = dsp_multiply_add(axl, axh);
|
|
||||||
|
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
|
|
||||||
dsp_set_long_prod(prod);
|
SetLongProduct(prod);
|
||||||
}
|
}
|
||||||
|
|
||||||
// MSUB $axS.l, $axS.h
|
// MSUB $axS.l, $axS.h
|
||||||
|
@ -580,16 +521,15 @@ void madd(const UDSPInstruction opc)
|
||||||
// Multiply low part $axS.l of secondary accumulator $axS by high part
|
// Multiply low part $axS.l of secondary accumulator $axS by high part
|
||||||
// $axS.h of secondary accumulator $axS (treat them both as signed) and
|
// $axS.h of secondary accumulator $axS (treat them both as signed) and
|
||||||
// subtract result from product register.
|
// subtract result from product register.
|
||||||
void msub(const UDSPInstruction opc)
|
void Interpreter::msub(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 sreg = (opc >> 8) & 0x1;
|
const u8 sreg = (opc >> 8) & 0x1;
|
||||||
|
const u16 axl = GetAXLow(sreg);
|
||||||
u16 axl = dsp_get_ax_l(sreg);
|
const u16 axh = GetAXHigh(sreg);
|
||||||
u16 axh = dsp_get_ax_h(sreg);
|
const s64 prod = MultiplySub(axl, axh);
|
||||||
s64 prod = dsp_multiply_sub(axl, axh);
|
|
||||||
|
|
||||||
ZeroWriteBackLog();
|
ZeroWriteBackLog();
|
||||||
|
|
||||||
dsp_set_long_prod(prod);
|
SetLongProduct(prod);
|
||||||
}
|
}
|
||||||
} // namespace DSP::Interpreter
|
} // namespace DSP::Interpreter
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Core/DSP/DSPTables.h"
|
#include "Core/DSP/DSPTables.h"
|
||||||
#include "Core/DSP/Interpreter/DSPIntExtOps.h"
|
|
||||||
#include "Core/DSP/Interpreter/DSPInterpreter.h"
|
#include "Core/DSP/Interpreter/DSPInterpreter.h"
|
||||||
|
|
||||||
namespace DSP::Interpreter
|
namespace DSP::Interpreter
|
||||||
|
@ -23,216 +22,216 @@ struct InterpreterOpInfo
|
||||||
// clang-format off
|
// clang-format off
|
||||||
constexpr std::array<InterpreterOpInfo, 124> s_opcodes
|
constexpr std::array<InterpreterOpInfo, 124> s_opcodes
|
||||||
{{
|
{{
|
||||||
{0x0000, 0xfffc, nop},
|
{0x0000, 0xfffc, &Interpreter::nop},
|
||||||
|
|
||||||
{0x0004, 0xfffc, dar},
|
{0x0004, 0xfffc, &Interpreter::dar},
|
||||||
{0x0008, 0xfffc, iar},
|
{0x0008, 0xfffc, &Interpreter::iar},
|
||||||
{0x000c, 0xfffc, subarn},
|
{0x000c, 0xfffc, &Interpreter::subarn},
|
||||||
{0x0010, 0xfff0, addarn},
|
{0x0010, 0xfff0, &Interpreter::addarn},
|
||||||
|
|
||||||
{0x0021, 0xffff, halt},
|
{0x0021, 0xffff, &Interpreter::halt},
|
||||||
|
|
||||||
{0x02d0, 0xfff0, ret},
|
{0x02d0, 0xfff0, &Interpreter::ret},
|
||||||
|
|
||||||
{0x02ff, 0xffff, rti},
|
{0x02ff, 0xffff, &Interpreter::rti},
|
||||||
|
|
||||||
{0x02b0, 0xfff0, call},
|
{0x02b0, 0xfff0, &Interpreter::call},
|
||||||
|
|
||||||
{0x0270, 0xfff0, ifcc},
|
{0x0270, 0xfff0, &Interpreter::ifcc},
|
||||||
|
|
||||||
{0x0290, 0xfff0, jcc},
|
{0x0290, 0xfff0, &Interpreter::jcc},
|
||||||
|
|
||||||
{0x1700, 0xff10, jmprcc},
|
{0x1700, 0xff10, &Interpreter::jmprcc},
|
||||||
|
|
||||||
{0x1710, 0xff10, callr},
|
{0x1710, 0xff10, &Interpreter::callr},
|
||||||
|
|
||||||
{0x1200, 0xff00, sbclr},
|
{0x1200, 0xff00, &Interpreter::sbclr},
|
||||||
{0x1300, 0xff00, sbset},
|
{0x1300, 0xff00, &Interpreter::sbset},
|
||||||
|
|
||||||
{0x1400, 0xfec0, lsl},
|
{0x1400, 0xfec0, &Interpreter::lsl},
|
||||||
{0x1440, 0xfec0, lsr},
|
{0x1440, 0xfec0, &Interpreter::lsr},
|
||||||
{0x1480, 0xfec0, asl},
|
{0x1480, 0xfec0, &Interpreter::asl},
|
||||||
{0x14c0, 0xfec0, asr},
|
{0x14c0, 0xfec0, &Interpreter::asr},
|
||||||
|
|
||||||
// these two were discovered by ector
|
// these two were discovered by ector
|
||||||
{0x02ca, 0xffff, lsrn},
|
{0x02ca, 0xffff, &Interpreter::lsrn},
|
||||||
{0x02cb, 0xffff, asrn},
|
{0x02cb, 0xffff, &Interpreter::asrn},
|
||||||
|
|
||||||
{0x0080, 0xffe0, lri},
|
{0x0080, 0xffe0, &Interpreter::lri},
|
||||||
{0x00c0, 0xffe0, lr},
|
{0x00c0, 0xffe0, &Interpreter::lr},
|
||||||
{0x00e0, 0xffe0, sr},
|
{0x00e0, 0xffe0, &Interpreter::sr},
|
||||||
|
|
||||||
{0x1c00, 0xfc00, mrr},
|
{0x1c00, 0xfc00, &Interpreter::mrr},
|
||||||
|
|
||||||
{0x1600, 0xff00, si},
|
{0x1600, 0xff00, &Interpreter::si},
|
||||||
|
|
||||||
{0x0400, 0xfe00, addis},
|
{0x0400, 0xfe00, &Interpreter::addis},
|
||||||
{0x0600, 0xfe00, cmpis},
|
{0x0600, 0xfe00, &Interpreter::cmpis},
|
||||||
{0x0800, 0xf800, lris},
|
{0x0800, 0xf800, &Interpreter::lris},
|
||||||
|
|
||||||
{0x0200, 0xfeff, addi},
|
{0x0200, 0xfeff, &Interpreter::addi},
|
||||||
{0x0220, 0xfeff, xori},
|
{0x0220, 0xfeff, &Interpreter::xori},
|
||||||
{0x0240, 0xfeff, andi},
|
{0x0240, 0xfeff, &Interpreter::andi},
|
||||||
{0x0260, 0xfeff, ori},
|
{0x0260, 0xfeff, &Interpreter::ori},
|
||||||
{0x0280, 0xfeff, cmpi},
|
{0x0280, 0xfeff, &Interpreter::cmpi},
|
||||||
|
|
||||||
{0x02a0, 0xfeff, andf},
|
{0x02a0, 0xfeff, &Interpreter::andf},
|
||||||
{0x02c0, 0xfeff, andcf},
|
{0x02c0, 0xfeff, &Interpreter::andcf},
|
||||||
|
|
||||||
{0x0210, 0xfefc, ilrr},
|
{0x0210, 0xfefc, &Interpreter::ilrr},
|
||||||
{0x0214, 0xfefc, ilrrd},
|
{0x0214, 0xfefc, &Interpreter::ilrrd},
|
||||||
{0x0218, 0xfefc, ilrri},
|
{0x0218, 0xfefc, &Interpreter::ilrri},
|
||||||
{0x021c, 0xfefc, ilrrn},
|
{0x021c, 0xfefc, &Interpreter::ilrrn},
|
||||||
|
|
||||||
// LOOPS
|
// LOOPS
|
||||||
{0x0040, 0xffe0, loop},
|
{0x0040, 0xffe0, &Interpreter::loop},
|
||||||
{0x0060, 0xffe0, bloop},
|
{0x0060, 0xffe0, &Interpreter::bloop},
|
||||||
{0x1000, 0xff00, loopi},
|
{0x1000, 0xff00, &Interpreter::loopi},
|
||||||
{0x1100, 0xff00, bloopi},
|
{0x1100, 0xff00, &Interpreter::bloopi},
|
||||||
|
|
||||||
// load and store value pointed by indexing reg and increment; LRR/SRR variants
|
// load and store value pointed by indexing reg and increment; LRR/SRR variants
|
||||||
{0x1800, 0xff80, lrr},
|
{0x1800, 0xff80, &Interpreter::lrr},
|
||||||
{0x1880, 0xff80, lrrd},
|
{0x1880, 0xff80, &Interpreter::lrrd},
|
||||||
{0x1900, 0xff80, lrri},
|
{0x1900, 0xff80, &Interpreter::lrri},
|
||||||
{0x1980, 0xff80, lrrn},
|
{0x1980, 0xff80, &Interpreter::lrrn},
|
||||||
|
|
||||||
{0x1a00, 0xff80, srr},
|
{0x1a00, 0xff80, &Interpreter::srr},
|
||||||
{0x1a80, 0xff80, srrd},
|
{0x1a80, 0xff80, &Interpreter::srrd},
|
||||||
{0x1b00, 0xff80, srri},
|
{0x1b00, 0xff80, &Interpreter::srri},
|
||||||
{0x1b80, 0xff80, srrn},
|
{0x1b80, 0xff80, &Interpreter::srrn},
|
||||||
|
|
||||||
// 2
|
// 2
|
||||||
{0x2000, 0xf800, lrs},
|
{0x2000, 0xf800, &Interpreter::lrs},
|
||||||
{0x2800, 0xf800, srs},
|
{0x2800, 0xf800, &Interpreter::srs},
|
||||||
|
|
||||||
// opcodes that can be extended
|
// opcodes that can be extended
|
||||||
|
|
||||||
// 3 - main opcode defined by 9 bits, extension defined by last 7 bits!!
|
// 3 - main opcode defined by 9 bits, extension defined by last 7 bits!!
|
||||||
{0x3000, 0xfc80, xorr},
|
{0x3000, 0xfc80, &Interpreter::xorr},
|
||||||
{0x3400, 0xfc80, andr},
|
{0x3400, 0xfc80, &Interpreter::andr},
|
||||||
{0x3800, 0xfc80, orr},
|
{0x3800, 0xfc80, &Interpreter::orr},
|
||||||
{0x3c00, 0xfe80, andc},
|
{0x3c00, 0xfe80, &Interpreter::andc},
|
||||||
{0x3e00, 0xfe80, orc},
|
{0x3e00, 0xfe80, &Interpreter::orc},
|
||||||
{0x3080, 0xfe80, xorc},
|
{0x3080, 0xfe80, &Interpreter::xorc},
|
||||||
{0x3280, 0xfe80, notc},
|
{0x3280, 0xfe80, &Interpreter::notc},
|
||||||
{0x3480, 0xfc80, lsrnrx},
|
{0x3480, 0xfc80, &Interpreter::lsrnrx},
|
||||||
{0x3880, 0xfc80, asrnrx},
|
{0x3880, 0xfc80, &Interpreter::asrnrx},
|
||||||
{0x3c80, 0xfe80, lsrnr},
|
{0x3c80, 0xfe80, &Interpreter::lsrnr},
|
||||||
{0x3e80, 0xfe80, asrnr},
|
{0x3e80, 0xfe80, &Interpreter::asrnr},
|
||||||
|
|
||||||
// 4
|
// 4
|
||||||
{0x4000, 0xf800, addr},
|
{0x4000, 0xf800, &Interpreter::addr},
|
||||||
{0x4800, 0xfc00, addax},
|
{0x4800, 0xfc00, &Interpreter::addax},
|
||||||
{0x4c00, 0xfe00, add},
|
{0x4c00, 0xfe00, &Interpreter::add},
|
||||||
{0x4e00, 0xfe00, addp},
|
{0x4e00, 0xfe00, &Interpreter::addp},
|
||||||
|
|
||||||
// 5
|
// 5
|
||||||
{0x5000, 0xf800, subr},
|
{0x5000, 0xf800, &Interpreter::subr},
|
||||||
{0x5800, 0xfc00, subax},
|
{0x5800, 0xfc00, &Interpreter::subax},
|
||||||
{0x5c00, 0xfe00, sub},
|
{0x5c00, 0xfe00, &Interpreter::sub},
|
||||||
{0x5e00, 0xfe00, subp},
|
{0x5e00, 0xfe00, &Interpreter::subp},
|
||||||
|
|
||||||
// 6
|
// 6
|
||||||
{0x6000, 0xf800, movr},
|
{0x6000, 0xf800, &Interpreter::movr},
|
||||||
{0x6800, 0xfc00, movax},
|
{0x6800, 0xfc00, &Interpreter::movax},
|
||||||
{0x6c00, 0xfe00, mov},
|
{0x6c00, 0xfe00, &Interpreter::mov},
|
||||||
{0x6e00, 0xfe00, movp},
|
{0x6e00, 0xfe00, &Interpreter::movp},
|
||||||
|
|
||||||
// 7
|
// 7
|
||||||
{0x7000, 0xfc00, addaxl},
|
{0x7000, 0xfc00, &Interpreter::addaxl},
|
||||||
{0x7400, 0xfe00, incm},
|
{0x7400, 0xfe00, &Interpreter::incm},
|
||||||
{0x7600, 0xfe00, inc},
|
{0x7600, 0xfe00, &Interpreter::inc},
|
||||||
{0x7800, 0xfe00, decm},
|
{0x7800, 0xfe00, &Interpreter::decm},
|
||||||
{0x7a00, 0xfe00, dec},
|
{0x7a00, 0xfe00, &Interpreter::dec},
|
||||||
{0x7c00, 0xfe00, neg},
|
{0x7c00, 0xfe00, &Interpreter::neg},
|
||||||
{0x7e00, 0xfe00, movnp},
|
{0x7e00, 0xfe00, &Interpreter::movnp},
|
||||||
|
|
||||||
// 8
|
// 8
|
||||||
{0x8000, 0xf700, nx},
|
{0x8000, 0xf700, &Interpreter::nx},
|
||||||
{0x8100, 0xf700, clr},
|
{0x8100, 0xf700, &Interpreter::clr},
|
||||||
{0x8200, 0xff00, cmp},
|
{0x8200, 0xff00, &Interpreter::cmp},
|
||||||
{0x8300, 0xff00, mulaxh},
|
{0x8300, 0xff00, &Interpreter::mulaxh},
|
||||||
{0x8400, 0xff00, clrp},
|
{0x8400, 0xff00, &Interpreter::clrp},
|
||||||
{0x8500, 0xff00, tstprod},
|
{0x8500, 0xff00, &Interpreter::tstprod},
|
||||||
{0x8600, 0xfe00, tstaxh},
|
{0x8600, 0xfe00, &Interpreter::tstaxh},
|
||||||
{0x8a00, 0xff00, srbith},
|
{0x8a00, 0xff00, &Interpreter::srbith},
|
||||||
{0x8b00, 0xff00, srbith},
|
{0x8b00, 0xff00, &Interpreter::srbith},
|
||||||
{0x8c00, 0xff00, srbith},
|
{0x8c00, 0xff00, &Interpreter::srbith},
|
||||||
{0x8d00, 0xff00, srbith},
|
{0x8d00, 0xff00, &Interpreter::srbith},
|
||||||
{0x8e00, 0xff00, srbith},
|
{0x8e00, 0xff00, &Interpreter::srbith},
|
||||||
{0x8f00, 0xff00, srbith},
|
{0x8f00, 0xff00, &Interpreter::srbith},
|
||||||
|
|
||||||
// 9
|
// 9
|
||||||
{0x9000, 0xf700, mul},
|
{0x9000, 0xf700, &Interpreter::mul},
|
||||||
{0x9100, 0xf700, asr16},
|
{0x9100, 0xf700, &Interpreter::asr16},
|
||||||
{0x9200, 0xf600, mulmvz},
|
{0x9200, 0xf600, &Interpreter::mulmvz},
|
||||||
{0x9400, 0xf600, mulac},
|
{0x9400, 0xf600, &Interpreter::mulac},
|
||||||
{0x9600, 0xf600, mulmv},
|
{0x9600, 0xf600, &Interpreter::mulmv},
|
||||||
|
|
||||||
// A-B
|
// A-B
|
||||||
{0xa000, 0xe700, mulx},
|
{0xa000, 0xe700, &Interpreter::mulx},
|
||||||
{0xa100, 0xf700, abs},
|
{0xa100, 0xf700, &Interpreter::abs},
|
||||||
{0xa200, 0xe600, mulxmvz},
|
{0xa200, 0xe600, &Interpreter::mulxmvz},
|
||||||
{0xa400, 0xe600, mulxac},
|
{0xa400, 0xe600, &Interpreter::mulxac},
|
||||||
{0xa600, 0xe600, mulxmv},
|
{0xa600, 0xe600, &Interpreter::mulxmv},
|
||||||
{0xb100, 0xf700, tst},
|
{0xb100, 0xf700, &Interpreter::tst},
|
||||||
|
|
||||||
// C-D
|
// C-D
|
||||||
{0xc000, 0xe700, mulc},
|
{0xc000, 0xe700, &Interpreter::mulc},
|
||||||
{0xc100, 0xe700, cmpar},
|
{0xc100, 0xe700, &Interpreter::cmpar},
|
||||||
{0xc200, 0xe600, mulcmvz},
|
{0xc200, 0xe600, &Interpreter::mulcmvz},
|
||||||
{0xc400, 0xe600, mulcac},
|
{0xc400, 0xe600, &Interpreter::mulcac},
|
||||||
{0xc600, 0xe600, mulcmv},
|
{0xc600, 0xe600, &Interpreter::mulcmv},
|
||||||
|
|
||||||
// E
|
// E
|
||||||
{0xe000, 0xfc00, maddx},
|
{0xe000, 0xfc00, &Interpreter::maddx},
|
||||||
{0xe400, 0xfc00, msubx},
|
{0xe400, 0xfc00, &Interpreter::msubx},
|
||||||
{0xe800, 0xfc00, maddc},
|
{0xe800, 0xfc00, &Interpreter::maddc},
|
||||||
{0xec00, 0xfc00, msubc},
|
{0xec00, 0xfc00, &Interpreter::msubc},
|
||||||
|
|
||||||
// F
|
// F
|
||||||
{0xf000, 0xfe00, lsl16},
|
{0xf000, 0xfe00, &Interpreter::lsl16},
|
||||||
{0xf200, 0xfe00, madd},
|
{0xf200, 0xfe00, &Interpreter::madd},
|
||||||
{0xf400, 0xfe00, lsr16},
|
{0xf400, 0xfe00, &Interpreter::lsr16},
|
||||||
{0xf600, 0xfe00, msub},
|
{0xf600, 0xfe00, &Interpreter::msub},
|
||||||
{0xf800, 0xfc00, addpaxz},
|
{0xf800, 0xfc00, &Interpreter::addpaxz},
|
||||||
{0xfc00, 0xfe00, clrl},
|
{0xfc00, 0xfe00, &Interpreter::clrl},
|
||||||
{0xfe00, 0xfe00, movpz},
|
{0xfe00, 0xfe00, &Interpreter::movpz},
|
||||||
}};
|
}};
|
||||||
|
|
||||||
constexpr std::array<InterpreterOpInfo, 25> s_opcodes_ext
|
constexpr std::array<InterpreterOpInfo, 25> s_opcodes_ext
|
||||||
{{
|
{{
|
||||||
{0x0000, 0x00fc, Ext::nop},
|
{0x0000, 0x00fc, &Interpreter::nop_ext},
|
||||||
|
|
||||||
{0x0004, 0x00fc, Ext::dr},
|
{0x0004, 0x00fc, &Interpreter::dr},
|
||||||
{0x0008, 0x00fc, Ext::ir},
|
{0x0008, 0x00fc, &Interpreter::ir},
|
||||||
{0x000c, 0x00fc, Ext::nr},
|
{0x000c, 0x00fc, &Interpreter::nr},
|
||||||
{0x0010, 0x00f0, Ext::mv},
|
{0x0010, 0x00f0, &Interpreter::mv},
|
||||||
|
|
||||||
{0x0020, 0x00e4, Ext::s},
|
{0x0020, 0x00e4, &Interpreter::s},
|
||||||
{0x0024, 0x00e4, Ext::sn},
|
{0x0024, 0x00e4, &Interpreter::sn},
|
||||||
|
|
||||||
{0x0040, 0x00c4, Ext::l},
|
{0x0040, 0x00c4, &Interpreter::l},
|
||||||
{0x0044, 0x00c4, Ext::ln},
|
{0x0044, 0x00c4, &Interpreter::ln},
|
||||||
|
|
||||||
{0x0080, 0x00ce, Ext::ls},
|
{0x0080, 0x00ce, &Interpreter::ls},
|
||||||
{0x0082, 0x00ce, Ext::sl},
|
{0x0082, 0x00ce, &Interpreter::sl},
|
||||||
{0x0084, 0x00ce, Ext::lsn},
|
{0x0084, 0x00ce, &Interpreter::lsn},
|
||||||
{0x0086, 0x00ce, Ext::sln},
|
{0x0086, 0x00ce, &Interpreter::sln},
|
||||||
{0x0088, 0x00ce, Ext::lsm},
|
{0x0088, 0x00ce, &Interpreter::lsm},
|
||||||
{0x008a, 0x00ce, Ext::slm},
|
{0x008a, 0x00ce, &Interpreter::slm},
|
||||||
{0x008c, 0x00ce, Ext::lsnm},
|
{0x008c, 0x00ce, &Interpreter::lsnm},
|
||||||
{0x008e, 0x00ce, Ext::slnm},
|
{0x008e, 0x00ce, &Interpreter::slnm},
|
||||||
|
|
||||||
{0x00c3, 0x00cf, Ext::ldax},
|
{0x00c3, 0x00cf, &Interpreter::ldax},
|
||||||
{0x00c7, 0x00cf, Ext::ldaxn},
|
{0x00c7, 0x00cf, &Interpreter::ldaxn},
|
||||||
{0x00cb, 0x00cf, Ext::ldaxm},
|
{0x00cb, 0x00cf, &Interpreter::ldaxm},
|
||||||
{0x00cf, 0x00cf, Ext::ldaxnm},
|
{0x00cf, 0x00cf, &Interpreter::ldaxnm},
|
||||||
|
|
||||||
{0x00c0, 0x00cc, Ext::ld},
|
{0x00c0, 0x00cc, &Interpreter::ld},
|
||||||
{0x00c4, 0x00cc, Ext::ldn},
|
{0x00c4, 0x00cc, &Interpreter::ldn},
|
||||||
{0x00c8, 0x00cc, Ext::ldm},
|
{0x00c8, 0x00cc, &Interpreter::ldm},
|
||||||
{0x00cc, 0x00cc, Ext::ldnm},
|
{0x00cc, 0x00cc, &Interpreter::ldnm},
|
||||||
}};
|
}};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
@ -266,7 +265,7 @@ void InitInstructionTables()
|
||||||
// ext op table
|
// ext op table
|
||||||
for (size_t i = 0; i < s_ext_op_table.size(); i++)
|
for (size_t i = 0; i < s_ext_op_table.size(); i++)
|
||||||
{
|
{
|
||||||
s_ext_op_table[i] = nop;
|
s_ext_op_table[i] = &Interpreter::nop;
|
||||||
|
|
||||||
const auto iter = FindByOpcode(static_cast<UDSPInstruction>(i), s_opcodes_ext);
|
const auto iter = FindByOpcode(static_cast<UDSPInstruction>(i), s_opcodes_ext);
|
||||||
if (iter == s_opcodes_ext.cend())
|
if (iter == s_opcodes_ext.cend())
|
||||||
|
@ -278,7 +277,7 @@ void InitInstructionTables()
|
||||||
// op table
|
// op table
|
||||||
for (size_t i = 0; i < s_op_table.size(); i++)
|
for (size_t i = 0; i < s_op_table.size(); i++)
|
||||||
{
|
{
|
||||||
s_op_table[i] = nop;
|
s_op_table[i] = &Interpreter::nop;
|
||||||
|
|
||||||
const auto iter = FindByOpcode(static_cast<UDSPInstruction>(i), s_opcodes);
|
const auto iter = FindByOpcode(static_cast<UDSPInstruction>(i), s_opcodes);
|
||||||
if (iter == s_opcodes.cend())
|
if (iter == s_opcodes.cend())
|
||||||
|
|
|
@ -8,7 +8,9 @@
|
||||||
|
|
||||||
namespace DSP::Interpreter
|
namespace DSP::Interpreter
|
||||||
{
|
{
|
||||||
using InterpreterFunction = void (*)(UDSPInstruction);
|
class Interpreter;
|
||||||
|
|
||||||
|
using InterpreterFunction = void (Interpreter::*)(UDSPInstruction);
|
||||||
|
|
||||||
InterpreterFunction GetOp(UDSPInstruction inst);
|
InterpreterFunction GetOp(UDSPInstruction inst);
|
||||||
InterpreterFunction GetExtOp(UDSPInstruction inst);
|
InterpreterFunction GetExtOp(UDSPInstruction inst);
|
||||||
|
|
|
@ -5,376 +5,27 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Common/Assert.h"
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
#include "Core/DSP/DSPCore.h"
|
|
||||||
#include "Core/DSP/DSPStacks.h"
|
|
||||||
|
|
||||||
namespace DSP::Interpreter
|
namespace DSP::Interpreter
|
||||||
{
|
{
|
||||||
// ---------------------------------------------------------------------------------------
|
|
||||||
// --- SR
|
|
||||||
// ---------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
static inline void dsp_SR_set_flag(int flag)
|
|
||||||
{
|
|
||||||
g_dsp.r.sr |= flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool dsp_SR_is_flag_set(int flag)
|
|
||||||
{
|
|
||||||
return (g_dsp.r.sr & flag) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------
|
|
||||||
// --- AR increments, decrements
|
|
||||||
// ---------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
static inline u16 dsp_increase_addr_reg(u16 reg, s16 _ix)
|
|
||||||
{
|
|
||||||
u32 ar = g_dsp.r.ar[reg];
|
|
||||||
u32 wr = g_dsp.r.wr[reg];
|
|
||||||
s32 ix = _ix;
|
|
||||||
|
|
||||||
u32 mx = (wr | 1) << 1;
|
|
||||||
u32 nar = ar + ix;
|
|
||||||
u32 dar = (nar ^ ar ^ ix) & mx;
|
|
||||||
|
|
||||||
if (ix >= 0)
|
|
||||||
{
|
|
||||||
if (dar > wr) // overflow
|
|
||||||
nar -= wr + 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ((((nar + wr + 1) ^ nar) & dar) <= wr) // underflow or below min for mask
|
|
||||||
nar += wr + 1;
|
|
||||||
}
|
|
||||||
return nar;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline u16 dsp_decrease_addr_reg(u16 reg, s16 _ix)
|
|
||||||
{
|
|
||||||
u32 ar = g_dsp.r.ar[reg];
|
|
||||||
u32 wr = g_dsp.r.wr[reg];
|
|
||||||
s32 ix = _ix;
|
|
||||||
|
|
||||||
u32 mx = (wr | 1) << 1;
|
|
||||||
u32 nar = ar - ix;
|
|
||||||
u32 dar = (nar ^ ar ^ ~ix) & mx;
|
|
||||||
|
|
||||||
if ((u32)ix > 0xFFFF8000) //(ix < 0 && ix != -0x8000)
|
|
||||||
{
|
|
||||||
if (dar > wr) // overflow
|
|
||||||
nar -= wr + 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ((((nar + wr + 1) ^ nar) & dar) <= wr) // underflow or below min for mask
|
|
||||||
nar += wr + 1;
|
|
||||||
}
|
|
||||||
return nar;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline u16 dsp_increment_addr_reg(u16 reg)
|
|
||||||
{
|
|
||||||
u32 ar = g_dsp.r.ar[reg];
|
|
||||||
u32 wr = g_dsp.r.wr[reg];
|
|
||||||
|
|
||||||
u32 nar = ar + 1;
|
|
||||||
|
|
||||||
if ((nar ^ ar) > ((wr | 1) << 1))
|
|
||||||
nar -= wr + 1;
|
|
||||||
return nar;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline u16 dsp_decrement_addr_reg(u16 reg)
|
|
||||||
{
|
|
||||||
u32 ar = g_dsp.r.ar[reg];
|
|
||||||
u32 wr = g_dsp.r.wr[reg];
|
|
||||||
|
|
||||||
u32 nar = ar + wr;
|
|
||||||
|
|
||||||
if (((nar ^ ar) & ((wr | 1) << 1)) > wr)
|
|
||||||
nar -= wr + 1;
|
|
||||||
return nar;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------
|
|
||||||
// --- reg
|
|
||||||
// ---------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
static inline u16 dsp_op_read_reg(int _reg)
|
|
||||||
{
|
|
||||||
int reg = _reg & 0x1f;
|
|
||||||
|
|
||||||
switch (reg)
|
|
||||||
{
|
|
||||||
case DSP_REG_ST0:
|
|
||||||
case DSP_REG_ST1:
|
|
||||||
case DSP_REG_ST2:
|
|
||||||
case DSP_REG_ST3:
|
|
||||||
return dsp_reg_load_stack(static_cast<StackRegister>(reg - DSP_REG_ST0));
|
|
||||||
case DSP_REG_AR0:
|
|
||||||
case DSP_REG_AR1:
|
|
||||||
case DSP_REG_AR2:
|
|
||||||
case DSP_REG_AR3:
|
|
||||||
return g_dsp.r.ar[reg - DSP_REG_AR0];
|
|
||||||
case DSP_REG_IX0:
|
|
||||||
case DSP_REG_IX1:
|
|
||||||
case DSP_REG_IX2:
|
|
||||||
case DSP_REG_IX3:
|
|
||||||
return g_dsp.r.ix[reg - DSP_REG_IX0];
|
|
||||||
case DSP_REG_WR0:
|
|
||||||
case DSP_REG_WR1:
|
|
||||||
case DSP_REG_WR2:
|
|
||||||
case DSP_REG_WR3:
|
|
||||||
return g_dsp.r.wr[reg - DSP_REG_WR0];
|
|
||||||
case DSP_REG_ACH0:
|
|
||||||
case DSP_REG_ACH1:
|
|
||||||
return g_dsp.r.ac[reg - DSP_REG_ACH0].h;
|
|
||||||
case DSP_REG_CR:
|
|
||||||
return g_dsp.r.cr;
|
|
||||||
case DSP_REG_SR:
|
|
||||||
return g_dsp.r.sr;
|
|
||||||
case DSP_REG_PRODL:
|
|
||||||
return g_dsp.r.prod.l;
|
|
||||||
case DSP_REG_PRODM:
|
|
||||||
return g_dsp.r.prod.m;
|
|
||||||
case DSP_REG_PRODH:
|
|
||||||
return g_dsp.r.prod.h;
|
|
||||||
case DSP_REG_PRODM2:
|
|
||||||
return g_dsp.r.prod.m2;
|
|
||||||
case DSP_REG_AXL0:
|
|
||||||
case DSP_REG_AXL1:
|
|
||||||
return g_dsp.r.ax[reg - DSP_REG_AXL0].l;
|
|
||||||
case DSP_REG_AXH0:
|
|
||||||
case DSP_REG_AXH1:
|
|
||||||
return g_dsp.r.ax[reg - DSP_REG_AXH0].h;
|
|
||||||
case DSP_REG_ACL0:
|
|
||||||
case DSP_REG_ACL1:
|
|
||||||
return g_dsp.r.ac[reg - DSP_REG_ACL0].l;
|
|
||||||
case DSP_REG_ACM0:
|
|
||||||
case DSP_REG_ACM1:
|
|
||||||
return g_dsp.r.ac[reg - DSP_REG_ACM0].m;
|
|
||||||
default:
|
|
||||||
ASSERT_MSG(DSP_INT, 0, "cannot happen");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void dsp_op_write_reg(int _reg, u16 val)
|
|
||||||
{
|
|
||||||
int reg = _reg & 0x1f;
|
|
||||||
|
|
||||||
switch (reg)
|
|
||||||
{
|
|
||||||
// 8-bit sign extended registers. Should look at prod.h too...
|
|
||||||
case DSP_REG_ACH0:
|
|
||||||
case DSP_REG_ACH1:
|
|
||||||
// sign extend from the bottom 8 bits.
|
|
||||||
g_dsp.r.ac[reg - DSP_REG_ACH0].h = (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(static_cast<StackRegister>(reg - DSP_REG_ST0), val);
|
|
||||||
break;
|
|
||||||
case DSP_REG_AR0:
|
|
||||||
case DSP_REG_AR1:
|
|
||||||
case DSP_REG_AR2:
|
|
||||||
case DSP_REG_AR3:
|
|
||||||
g_dsp.r.ar[reg - DSP_REG_AR0] = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_IX0:
|
|
||||||
case DSP_REG_IX1:
|
|
||||||
case DSP_REG_IX2:
|
|
||||||
case DSP_REG_IX3:
|
|
||||||
g_dsp.r.ix[reg - DSP_REG_IX0] = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_WR0:
|
|
||||||
case DSP_REG_WR1:
|
|
||||||
case DSP_REG_WR2:
|
|
||||||
case DSP_REG_WR3:
|
|
||||||
g_dsp.r.wr[reg - DSP_REG_WR0] = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_CR:
|
|
||||||
g_dsp.r.cr = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_SR:
|
|
||||||
g_dsp.r.sr = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_PRODL:
|
|
||||||
g_dsp.r.prod.l = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_PRODM:
|
|
||||||
g_dsp.r.prod.m = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_PRODH:
|
|
||||||
g_dsp.r.prod.h = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_PRODM2:
|
|
||||||
g_dsp.r.prod.m2 = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_AXL0:
|
|
||||||
case DSP_REG_AXL1:
|
|
||||||
g_dsp.r.ax[reg - DSP_REG_AXL0].l = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_AXH0:
|
|
||||||
case DSP_REG_AXH1:
|
|
||||||
g_dsp.r.ax[reg - DSP_REG_AXH0].h = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_ACL0:
|
|
||||||
case DSP_REG_ACL1:
|
|
||||||
g_dsp.r.ac[reg - DSP_REG_ACL0].l = val;
|
|
||||||
break;
|
|
||||||
case DSP_REG_ACM0:
|
|
||||||
case DSP_REG_ACM1:
|
|
||||||
g_dsp.r.ac[reg - DSP_REG_ACM0].m = val;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void dsp_conditional_extend_accum(int reg)
|
|
||||||
{
|
|
||||||
switch (reg)
|
|
||||||
{
|
|
||||||
case DSP_REG_ACM0:
|
|
||||||
case DSP_REG_ACM1:
|
|
||||||
if (g_dsp.r.sr & SR_40_MODE_BIT)
|
|
||||||
{
|
|
||||||
// Sign extend into whole accum.
|
|
||||||
u16 val = g_dsp.r.ac[reg - DSP_REG_ACM0].m;
|
|
||||||
g_dsp.r.ac[reg - DSP_REG_ACM0].h = (val & 0x8000) ? 0xFFFF : 0x0000;
|
|
||||||
g_dsp.r.ac[reg - DSP_REG_ACM0].l = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------
|
|
||||||
// --- prod (40-bit)
|
|
||||||
// ---------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
static inline s64 dsp_get_long_prod()
|
|
||||||
{
|
|
||||||
s64 val = (s8)(u8)g_dsp.r.prod.h;
|
|
||||||
val <<= 32;
|
|
||||||
s64 low_prod = g_dsp.r.prod.m;
|
|
||||||
low_prod += g_dsp.r.prod.m2;
|
|
||||||
low_prod <<= 16;
|
|
||||||
low_prod |= g_dsp.r.prod.l;
|
|
||||||
val += low_prod;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline s64 dsp_get_long_prod_round_prodl()
|
|
||||||
{
|
|
||||||
s64 prod = dsp_get_long_prod();
|
|
||||||
|
|
||||||
if (prod & 0x10000)
|
|
||||||
prod = (prod + 0x8000) & ~0xffff;
|
|
||||||
else
|
|
||||||
prod = (prod + 0x7fff) & ~0xffff;
|
|
||||||
|
|
||||||
return prod;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For accurate emulation, this is wrong - but the real prod registers behave
|
|
||||||
// in completely bizarre ways. Not needed to emulate them correctly for game ucodes.
|
|
||||||
inline void dsp_set_long_prod(s64 val)
|
|
||||||
{
|
|
||||||
g_dsp.r.prod.val = val & 0x000000FFFFFFFFFFULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------
|
||||||
// --- ACC - main accumulators (40-bit)
|
// --- ACC - main accumulators (40-bit)
|
||||||
// ---------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------
|
||||||
|
|
||||||
inline s64 dsp_get_long_acc(int reg)
|
// s64 -> s40
|
||||||
{
|
inline s64 dsp_convert_long_acc(s64 val)
|
||||||
return ((s64)(g_dsp.r.ac[reg].val << 24) >> 24);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void dsp_set_long_acc(int _reg, s64 val)
|
|
||||||
{
|
|
||||||
g_dsp.r.ac[_reg].val = (u64)val;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline s64 dsp_convert_long_acc(s64 val) // s64 -> s40
|
|
||||||
{
|
{
|
||||||
return ((val << 24) >> 24);
|
return ((val << 24) >> 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline s64 dsp_round_long_acc(s64 val)
|
inline s64 dsp_round_long_acc(s64 val)
|
||||||
{
|
{
|
||||||
if (val & 0x10000)
|
if ((val & 0x10000) != 0)
|
||||||
val = (val + 0x8000) & ~0xffff;
|
val = (val + 0x8000) & ~0xffff;
|
||||||
else
|
else
|
||||||
val = (val + 0x7fff) & ~0xffff;
|
val = (val + 0x7fff) & ~0xffff;
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline s16 dsp_get_acc_l(int _reg)
|
|
||||||
{
|
|
||||||
return (s16)g_dsp.r.ac[_reg].l;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline s16 dsp_get_acc_m(int _reg)
|
|
||||||
{
|
|
||||||
return (s16)g_dsp.r.ac[_reg].m;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline s16 dsp_get_acc_h(int _reg)
|
|
||||||
{
|
|
||||||
return (s16)g_dsp.r.ac[_reg].h;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline u16 dsp_op_read_reg_and_saturate(u8 _reg)
|
|
||||||
{
|
|
||||||
if (g_dsp.r.sr & SR_40_MODE_BIT)
|
|
||||||
{
|
|
||||||
s64 acc = dsp_get_long_acc(_reg);
|
|
||||||
|
|
||||||
if (acc != (s32)acc)
|
|
||||||
{
|
|
||||||
if (acc > 0)
|
|
||||||
return 0x7fff;
|
|
||||||
else
|
|
||||||
return 0x8000;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return g_dsp.r.ac[_reg].m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return g_dsp.r.ac[_reg].m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------
|
|
||||||
// --- AX - extra accumulators (32-bit)
|
|
||||||
// ---------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
inline s32 dsp_get_long_acx(int _reg)
|
|
||||||
{
|
|
||||||
return (s32)(((u32)g_dsp.r.ax[_reg].h << 16) | g_dsp.r.ax[_reg].l);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline s16 dsp_get_ax_l(int _reg)
|
|
||||||
{
|
|
||||||
return (s16)g_dsp.r.ax[_reg].l;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline s16 dsp_get_ax_h(int _reg)
|
|
||||||
{
|
|
||||||
return (s16)g_dsp.r.ax[_reg].h;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace DSP::Interpreter
|
} // namespace DSP::Interpreter
|
||||||
|
|
|
@ -5,115 +5,68 @@
|
||||||
|
|
||||||
#include "Core/DSP/Interpreter/DSPInterpreter.h"
|
#include "Core/DSP/Interpreter/DSPInterpreter.h"
|
||||||
|
|
||||||
|
#include "Common/Assert.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
|
|
||||||
#include "Core/DSP/DSPAnalyzer.h"
|
#include "Core/DSP/DSPAnalyzer.h"
|
||||||
#include "Core/DSP/DSPCore.h"
|
#include "Core/DSP/DSPCore.h"
|
||||||
#include "Core/DSP/DSPMemoryMap.h"
|
|
||||||
#include "Core/DSP/DSPTables.h"
|
#include "Core/DSP/DSPTables.h"
|
||||||
#include "Core/DSP/Interpreter/DSPIntTables.h"
|
#include "Core/DSP/Interpreter/DSPIntTables.h"
|
||||||
|
|
||||||
namespace DSP::Interpreter
|
namespace DSP::Interpreter
|
||||||
{
|
{
|
||||||
namespace
|
Interpreter::Interpreter(DSPCore& dsp) : m_dsp_core{dsp}
|
||||||
{
|
{
|
||||||
void ExecuteInstruction(const UDSPInstruction inst)
|
InitInstructionTables();
|
||||||
|
}
|
||||||
|
|
||||||
|
Interpreter::~Interpreter() = default;
|
||||||
|
|
||||||
|
void Interpreter::ExecuteInstruction(const UDSPInstruction inst)
|
||||||
{
|
{
|
||||||
const DSPOPCTemplate* opcode_template = GetOpTemplate(inst);
|
const DSPOPCTemplate* opcode_template = GetOpTemplate(inst);
|
||||||
|
|
||||||
if (opcode_template->extended)
|
if (opcode_template->extended)
|
||||||
{
|
{
|
||||||
GetExtOp(inst)(inst);
|
(this->*GetExtOp(inst))(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
GetOp(inst)(inst);
|
(this->*GetOp(inst))(inst);
|
||||||
|
|
||||||
if (opcode_template->extended)
|
if (opcode_template->extended)
|
||||||
{
|
{
|
||||||
ApplyWriteBackLog();
|
ApplyWriteBackLog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
|
||||||
|
|
||||||
// NOTE: These have nothing to do with g_dsp.r.cr !
|
void Interpreter::Step()
|
||||||
void WriteCR(u16 val)
|
|
||||||
{
|
{
|
||||||
// reset
|
m_dsp_core.CheckExceptions();
|
||||||
if (val & 1)
|
m_dsp_core.DSPState().step_counter++;
|
||||||
{
|
|
||||||
INFO_LOG_FMT(DSPLLE, "DSP_CONTROL RESET");
|
|
||||||
DSPCore_Reset();
|
|
||||||
val &= ~1;
|
|
||||||
}
|
|
||||||
// init
|
|
||||||
else if (val == 4)
|
|
||||||
{
|
|
||||||
// HAX!
|
|
||||||
// OSInitAudioSystem ucode should send this mail - not DSP core itself
|
|
||||||
INFO_LOG_FMT(DSPLLE, "DSP_CONTROL INIT");
|
|
||||||
g_init_hax = true;
|
|
||||||
val |= 0x800;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update cr
|
const u16 opc = m_dsp_core.DSPState().FetchInstruction();
|
||||||
g_dsp.cr = val;
|
ExecuteInstruction(UDSPInstruction{opc});
|
||||||
}
|
|
||||||
|
|
||||||
u16 ReadCR()
|
const auto pc = m_dsp_core.DSPState().pc;
|
||||||
{
|
if ((Analyzer::GetCodeFlags(static_cast<u16>(pc - 1)) & Analyzer::CODE_LOOP_END) != 0)
|
||||||
if (g_dsp.pc & 0x8000)
|
|
||||||
{
|
|
||||||
g_dsp.cr |= 0x800;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_dsp.cr &= ~0x800;
|
|
||||||
}
|
|
||||||
|
|
||||||
return g_dsp.cr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Step()
|
|
||||||
{
|
|
||||||
DSPCore_CheckExceptions();
|
|
||||||
|
|
||||||
g_dsp.step_counter++;
|
|
||||||
|
|
||||||
#if PROFILE
|
|
||||||
g_dsp.err_pc = g_dsp.pc;
|
|
||||||
|
|
||||||
ProfilerAddDelta(g_dsp.err_pc, 1);
|
|
||||||
if (g_dsp.step_counter == 1)
|
|
||||||
{
|
|
||||||
ProfilerInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((g_dsp.step_counter & 0xFFFFF) == 0)
|
|
||||||
{
|
|
||||||
ProfilerDump(g_dsp.step_counter);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
u16 opc = dsp_fetch_code();
|
|
||||||
ExecuteInstruction(UDSPInstruction(opc));
|
|
||||||
|
|
||||||
if (Analyzer::GetCodeFlags(static_cast<u16>(g_dsp.pc - 1u)) & Analyzer::CODE_LOOP_END)
|
|
||||||
HandleLoop();
|
HandleLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used by thread mode.
|
// Used by thread mode.
|
||||||
int RunCyclesThread(int cycles)
|
int Interpreter::RunCyclesThread(int cycles)
|
||||||
{
|
{
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (g_dsp.cr & CR_HALT)
|
if ((state.cr & CR_HALT) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (g_dsp.external_interrupt_waiting)
|
if (state.external_interrupt_waiting)
|
||||||
{
|
{
|
||||||
DSPCore_CheckExternalInterrupt();
|
m_dsp_core.CheckExternalInterrupt();
|
||||||
DSPCore_SetExternalInterrupt(false);
|
m_dsp_core.SetExternalInterrupt(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Step();
|
Step();
|
||||||
|
@ -124,16 +77,19 @@ int RunCyclesThread(int cycles)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This one has basic idle skipping, and checks breakpoints.
|
// This one has basic idle skipping, and checks breakpoints.
|
||||||
int RunCyclesDebug(int cycles)
|
int Interpreter::RunCyclesDebug(int cycles)
|
||||||
{
|
{
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
// First, let's run a few cycles with no idle skipping so that things can progress a bit.
|
// First, let's run a few cycles with no idle skipping so that things can progress a bit.
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
if (g_dsp.cr & CR_HALT)
|
if ((state.cr & CR_HALT) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
if (g_dsp_breakpoints.IsAddressBreakPoint(g_dsp.pc))
|
|
||||||
|
if (m_dsp_core.BreakPoints().IsAddressBreakPoint(state.pc))
|
||||||
{
|
{
|
||||||
DSPCore_SetState(State::Stepping);
|
m_dsp_core.SetState(State::Stepping);
|
||||||
return cycles;
|
return cycles;
|
||||||
}
|
}
|
||||||
Step();
|
Step();
|
||||||
|
@ -148,16 +104,19 @@ int RunCyclesDebug(int cycles)
|
||||||
// idle loops.
|
// idle loops.
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
if (g_dsp.cr & CR_HALT)
|
if ((state.cr & CR_HALT) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
if (g_dsp_breakpoints.IsAddressBreakPoint(g_dsp.pc))
|
|
||||||
|
if (m_dsp_core.BreakPoints().IsAddressBreakPoint(state.pc))
|
||||||
{
|
{
|
||||||
DSPCore_SetState(State::Stepping);
|
m_dsp_core.SetState(State::Stepping);
|
||||||
return cycles;
|
return cycles;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Idle skipping.
|
// Idle skipping.
|
||||||
if (Analyzer::GetCodeFlags(g_dsp.pc) & Analyzer::CODE_IDLE_SKIP)
|
if ((Analyzer::GetCodeFlags(state.pc) & Analyzer::CODE_IDLE_SKIP) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
Step();
|
Step();
|
||||||
cycles--;
|
cycles--;
|
||||||
if (cycles < 0)
|
if (cycles < 0)
|
||||||
|
@ -167,9 +126,9 @@ int RunCyclesDebug(int cycles)
|
||||||
// Now, lets run some more without idle skipping.
|
// Now, lets run some more without idle skipping.
|
||||||
for (int i = 0; i < 200; i++)
|
for (int i = 0; i < 200; i++)
|
||||||
{
|
{
|
||||||
if (g_dsp_breakpoints.IsAddressBreakPoint(g_dsp.pc))
|
if (m_dsp_core.BreakPoints().IsAddressBreakPoint(state.pc))
|
||||||
{
|
{
|
||||||
DSPCore_SetState(State::Stepping);
|
m_dsp_core.SetState(State::Stepping);
|
||||||
return cycles;
|
return cycles;
|
||||||
}
|
}
|
||||||
Step();
|
Step();
|
||||||
|
@ -183,16 +142,20 @@ int RunCyclesDebug(int cycles)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used by non-thread mode. Meant to be efficient.
|
// Used by non-thread mode. Meant to be efficient.
|
||||||
int RunCycles(int cycles)
|
int Interpreter::RunCycles(int cycles)
|
||||||
{
|
{
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
// First, let's run a few cycles with no idle skipping so that things can
|
// First, let's run a few cycles with no idle skipping so that things can
|
||||||
// progress a bit.
|
// progress a bit.
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
if (g_dsp.cr & CR_HALT)
|
if ((state.cr & CR_HALT) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
Step();
|
Step();
|
||||||
cycles--;
|
cycles--;
|
||||||
|
|
||||||
if (cycles < 0)
|
if (cycles < 0)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -203,13 +166,16 @@ int RunCycles(int cycles)
|
||||||
// idle loops.
|
// idle loops.
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
if (g_dsp.cr & CR_HALT)
|
if ((state.cr & CR_HALT) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Idle skipping.
|
// Idle skipping.
|
||||||
if (Analyzer::GetCodeFlags(g_dsp.pc) & Analyzer::CODE_IDLE_SKIP)
|
if ((Analyzer::GetCodeFlags(state.pc) & Analyzer::CODE_IDLE_SKIP) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
Step();
|
Step();
|
||||||
cycles--;
|
cycles--;
|
||||||
|
|
||||||
if (cycles < 0)
|
if (cycles < 0)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -227,7 +193,656 @@ int RunCycles(int cycles)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nop(const UDSPInstruction opc)
|
// NOTE: These have nothing to do with SDSP::r::cr!
|
||||||
|
void Interpreter::WriteCR(u16 val)
|
||||||
|
{
|
||||||
|
// reset
|
||||||
|
if ((val & 1) != 0)
|
||||||
|
{
|
||||||
|
INFO_LOG_FMT(DSPLLE, "DSP_CONTROL RESET");
|
||||||
|
m_dsp_core.Reset();
|
||||||
|
val &= ~1;
|
||||||
|
}
|
||||||
|
// init
|
||||||
|
else if (val == 4)
|
||||||
|
{
|
||||||
|
// HAX!
|
||||||
|
// OSInitAudioSystem ucode should send this mail - not DSP core itself
|
||||||
|
INFO_LOG_FMT(DSPLLE, "DSP_CONTROL INIT");
|
||||||
|
m_dsp_core.SetInitHax(true);
|
||||||
|
val |= 0x800;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update cr
|
||||||
|
m_dsp_core.DSPState().cr = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 Interpreter::ReadCR()
|
||||||
|
{
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
|
if ((state.pc & 0x8000) != 0)
|
||||||
|
{
|
||||||
|
state.cr |= 0x800;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state.cr &= ~0x800;
|
||||||
|
}
|
||||||
|
|
||||||
|
return state.cr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interpreter::SetSRFlag(u16 flag)
|
||||||
|
{
|
||||||
|
m_dsp_core.DSPState().SetSRFlag(flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Interpreter::IsSRFlagSet(u16 flag) const
|
||||||
|
{
|
||||||
|
return m_dsp_core.DSPState().IsSRFlagSet(flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Interpreter::CheckCondition(u8 condition) const
|
||||||
|
{
|
||||||
|
const auto IsCarry = [this] { return IsSRFlagSet(SR_CARRY); };
|
||||||
|
const auto IsOverflow = [this] { return IsSRFlagSet(SR_OVERFLOW); };
|
||||||
|
const auto IsOverS32 = [this] { return IsSRFlagSet(SR_OVER_S32); };
|
||||||
|
const auto IsLess = [this] {
|
||||||
|
const auto& state = m_dsp_core.DSPState();
|
||||||
|
return (state.r.sr & SR_OVERFLOW) != (state.r.sr & SR_SIGN);
|
||||||
|
};
|
||||||
|
const auto IsZero = [this] { return IsSRFlagSet(SR_ARITH_ZERO); };
|
||||||
|
const auto IsLogicZero = [this] { return IsSRFlagSet(SR_LOGIC_ZERO); };
|
||||||
|
const auto IsConditionA = [this] {
|
||||||
|
return (IsSRFlagSet(SR_OVER_S32) || IsSRFlagSet(SR_TOP2BITS)) && !IsSRFlagSet(SR_ARITH_ZERO);
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (condition & 0xf)
|
||||||
|
{
|
||||||
|
case 0xf: // Always true.
|
||||||
|
return true;
|
||||||
|
case 0x0: // GE - Greater Equal
|
||||||
|
return !IsLess();
|
||||||
|
case 0x1: // L - Less
|
||||||
|
return IsLess();
|
||||||
|
case 0x2: // G - Greater
|
||||||
|
return !IsLess() && !IsZero();
|
||||||
|
case 0x3: // LE - Less Equal
|
||||||
|
return IsLess() || IsZero();
|
||||||
|
case 0x4: // NZ - Not Zero
|
||||||
|
return !IsZero();
|
||||||
|
case 0x5: // Z - Zero
|
||||||
|
return IsZero();
|
||||||
|
case 0x6: // NC - Not carry
|
||||||
|
return !IsCarry();
|
||||||
|
case 0x7: // C - Carry
|
||||||
|
return IsCarry();
|
||||||
|
case 0x8: // ? - Not over s32
|
||||||
|
return !IsOverS32();
|
||||||
|
case 0x9: // ? - Over s32
|
||||||
|
return IsOverS32();
|
||||||
|
case 0xa: // ?
|
||||||
|
return IsConditionA();
|
||||||
|
case 0xb: // ?
|
||||||
|
return !IsConditionA();
|
||||||
|
case 0xc: // LNZ - Logic Not Zero
|
||||||
|
return !IsLogicZero();
|
||||||
|
case 0xd: // LZ - Logic Zero
|
||||||
|
return IsLogicZero();
|
||||||
|
case 0xe: // 0 - Overflow
|
||||||
|
return IsOverflow();
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 Interpreter::IncrementAddressRegister(u16 reg) const
|
||||||
|
{
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
const u32 ar = state.r.ar[reg];
|
||||||
|
const u32 wr = state.r.wr[reg];
|
||||||
|
u32 nar = ar + 1;
|
||||||
|
|
||||||
|
if ((nar ^ ar) > ((wr | 1) << 1))
|
||||||
|
nar -= wr + 1;
|
||||||
|
|
||||||
|
return static_cast<u16>(nar);
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 Interpreter::DecrementAddressRegister(u16 reg) const
|
||||||
|
{
|
||||||
|
const auto& state = m_dsp_core.DSPState();
|
||||||
|
const u32 ar = state.r.ar[reg];
|
||||||
|
const u32 wr = state.r.wr[reg];
|
||||||
|
u32 nar = ar + wr;
|
||||||
|
|
||||||
|
if (((nar ^ ar) & ((wr | 1) << 1)) > wr)
|
||||||
|
nar -= wr + 1;
|
||||||
|
|
||||||
|
return static_cast<u16>(nar);
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 Interpreter::IncreaseAddressRegister(u16 reg, s16 ix_) const
|
||||||
|
{
|
||||||
|
const auto& state = m_dsp_core.DSPState();
|
||||||
|
const u32 ar = state.r.ar[reg];
|
||||||
|
const u32 wr = state.r.wr[reg];
|
||||||
|
const s32 ix = ix_;
|
||||||
|
|
||||||
|
const u32 mx = (wr | 1) << 1;
|
||||||
|
u32 nar = ar + ix;
|
||||||
|
const u32 dar = (nar ^ ar ^ ix) & mx;
|
||||||
|
|
||||||
|
if (ix >= 0)
|
||||||
|
{
|
||||||
|
if (dar > wr) // Overflow
|
||||||
|
nar -= wr + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Underflow or below min for mask
|
||||||
|
if ((((nar + wr + 1) ^ nar) & dar) <= wr)
|
||||||
|
nar += wr + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<u16>(nar);
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 Interpreter::DecreaseAddressRegister(u16 reg, s16 ix_) const
|
||||||
|
{
|
||||||
|
const auto& state = m_dsp_core.DSPState();
|
||||||
|
const u32 ar = state.r.ar[reg];
|
||||||
|
const u32 wr = state.r.wr[reg];
|
||||||
|
const s32 ix = ix_;
|
||||||
|
|
||||||
|
const u32 mx = (wr | 1) << 1;
|
||||||
|
u32 nar = ar - ix;
|
||||||
|
const u32 dar = (nar ^ ar ^ ~ix) & mx;
|
||||||
|
|
||||||
|
// (ix < 0 && ix != -0x8000)
|
||||||
|
if (static_cast<u32>(ix) > 0xFFFF8000)
|
||||||
|
{
|
||||||
|
if (dar > wr) // overflow
|
||||||
|
nar -= wr + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Underflow or below min for mask
|
||||||
|
if ((((nar + wr + 1) ^ nar) & dar) <= wr)
|
||||||
|
nar += wr + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<u16>(nar);
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 Interpreter::GetLongACX(s32 reg) const
|
||||||
|
{
|
||||||
|
const auto& state = m_dsp_core.DSPState();
|
||||||
|
return static_cast<s32>((static_cast<u32>(state.r.ax[reg].h) << 16) | state.r.ax[reg].l);
|
||||||
|
}
|
||||||
|
|
||||||
|
s16 Interpreter::GetAXLow(s32 reg) const
|
||||||
|
{
|
||||||
|
return static_cast<s16>(m_dsp_core.DSPState().r.ax[reg].l);
|
||||||
|
}
|
||||||
|
|
||||||
|
s16 Interpreter::GetAXHigh(s32 reg) const
|
||||||
|
{
|
||||||
|
return static_cast<s16>(m_dsp_core.DSPState().r.ax[reg].h);
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 Interpreter::GetLongAcc(s32 reg) const
|
||||||
|
{
|
||||||
|
const auto& state = m_dsp_core.DSPState();
|
||||||
|
return static_cast<s64>(state.r.ac[reg].val << 24) >> 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interpreter::SetLongAcc(s32 reg, s64 value)
|
||||||
|
{
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
state.r.ac[reg].val = static_cast<u64>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
s16 Interpreter::GetAccLow(s32 reg) const
|
||||||
|
{
|
||||||
|
return static_cast<s16>(m_dsp_core.DSPState().r.ac[reg].l);
|
||||||
|
}
|
||||||
|
|
||||||
|
s16 Interpreter::GetAccMid(s32 reg) const
|
||||||
|
{
|
||||||
|
return static_cast<s16>(m_dsp_core.DSPState().r.ac[reg].m);
|
||||||
|
}
|
||||||
|
|
||||||
|
s16 Interpreter::GetAccHigh(s32 reg) const
|
||||||
|
{
|
||||||
|
return static_cast<s16>(m_dsp_core.DSPState().r.ac[reg].h);
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 Interpreter::GetLongProduct() const
|
||||||
|
{
|
||||||
|
const auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
|
s64 val = static_cast<s8>(static_cast<u8>(state.r.prod.h));
|
||||||
|
val <<= 32;
|
||||||
|
|
||||||
|
s64 low_prod = state.r.prod.m;
|
||||||
|
low_prod += state.r.prod.m2;
|
||||||
|
low_prod <<= 16;
|
||||||
|
low_prod |= state.r.prod.l;
|
||||||
|
|
||||||
|
val += low_prod;
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 Interpreter::GetLongProductRounded() const
|
||||||
|
{
|
||||||
|
const s64 prod = GetLongProduct();
|
||||||
|
|
||||||
|
if ((prod & 0x10000) != 0)
|
||||||
|
return (prod + 0x8000) & ~0xffff;
|
||||||
|
else
|
||||||
|
return (prod + 0x7fff) & ~0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interpreter::SetLongProduct(s64 value)
|
||||||
|
{
|
||||||
|
// For accurate emulation, this is wrong - but the real prod registers behave
|
||||||
|
// in completely bizarre ways. Not needed to emulate them correctly for game ucodes.
|
||||||
|
m_dsp_core.DSPState().r.prod.val = static_cast<u64>(value & 0x000000FFFFFFFFFFULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 Interpreter::GetMultiplyProduct(u16 a, u16 b, u8 sign) const
|
||||||
|
{
|
||||||
|
s64 prod;
|
||||||
|
|
||||||
|
// Unsigned
|
||||||
|
if (sign == 1 && IsSRFlagSet(SR_MUL_UNSIGNED))
|
||||||
|
prod = static_cast<u32>(a * b);
|
||||||
|
else if (sign == 2 && IsSRFlagSet(SR_MUL_UNSIGNED)) // mixed
|
||||||
|
prod = a * static_cast<s16>(b);
|
||||||
|
else // Signed
|
||||||
|
prod = static_cast<s16>(a) * static_cast<s16>(b);
|
||||||
|
|
||||||
|
// Conditionally multiply by 2.
|
||||||
|
if (!IsSRFlagSet(SR_MUL_MODIFY))
|
||||||
|
prod <<= 1;
|
||||||
|
|
||||||
|
return prod;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 Interpreter::Multiply(u16 a, u16 b, u8 sign) const
|
||||||
|
{
|
||||||
|
return GetMultiplyProduct(a, b, sign);
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 Interpreter::MultiplyAdd(u16 a, u16 b, u8 sign) const
|
||||||
|
{
|
||||||
|
return GetLongProduct() + GetMultiplyProduct(a, b, sign);
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 Interpreter::MultiplySub(u16 a, u16 b, u8 sign) const
|
||||||
|
{
|
||||||
|
return GetLongProduct() - GetMultiplyProduct(a, b, sign);
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 Interpreter::MultiplyMulX(u8 axh0, u8 axh1, u16 val1, u16 val2) const
|
||||||
|
{
|
||||||
|
s64 result;
|
||||||
|
|
||||||
|
if (axh0 == 0 && axh1 == 0)
|
||||||
|
result = Multiply(val1, val2, 1); // Unsigned support ON if both ax?.l regs are used
|
||||||
|
else if (axh0 == 0 && axh1 == 1)
|
||||||
|
result = Multiply(val1, val2, 2); // Mixed support ON (u16)axl.0 * (s16)axh.1
|
||||||
|
else if (axh0 == 1 && axh1 == 0)
|
||||||
|
result = Multiply(val2, val1, 2); // Mixed support ON (u16)axl.1 * (s16)axh.0
|
||||||
|
else
|
||||||
|
result = Multiply(val1, val2, 0); // Unsigned support OFF if both ax?.h regs are used
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interpreter::UpdateSR16(s16 value, bool carry, bool overflow, bool over_s32)
|
||||||
|
{
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
|
state.r.sr &= ~SR_CMP_MASK;
|
||||||
|
|
||||||
|
// 0x01
|
||||||
|
if (carry)
|
||||||
|
{
|
||||||
|
state.r.sr |= SR_CARRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x02 and 0x80
|
||||||
|
if (overflow)
|
||||||
|
{
|
||||||
|
state.r.sr |= SR_OVERFLOW;
|
||||||
|
state.r.sr |= SR_OVERFLOW_STICKY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x04
|
||||||
|
if (value == 0)
|
||||||
|
{
|
||||||
|
state.r.sr |= SR_ARITH_ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x08
|
||||||
|
if (value < 0)
|
||||||
|
{
|
||||||
|
state.r.sr |= SR_SIGN;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x10
|
||||||
|
if (over_s32)
|
||||||
|
{
|
||||||
|
state.r.sr |= SR_OVER_S32;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x20 - Checks if top bits of m are equal
|
||||||
|
if (((static_cast<u16>(value) >> 14) == 0) || ((static_cast<u16>(value) >> 14) == 3))
|
||||||
|
{
|
||||||
|
state.r.sr |= SR_TOP2BITS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interpreter::UpdateSR64(s64 value, bool carry, bool overflow)
|
||||||
|
{
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
|
state.r.sr &= ~SR_CMP_MASK;
|
||||||
|
|
||||||
|
// 0x01
|
||||||
|
if (carry)
|
||||||
|
{
|
||||||
|
state.r.sr |= SR_CARRY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x02 and 0x80
|
||||||
|
if (overflow)
|
||||||
|
{
|
||||||
|
state.r.sr |= SR_OVERFLOW;
|
||||||
|
state.r.sr |= SR_OVERFLOW_STICKY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x04
|
||||||
|
if (value == 0)
|
||||||
|
{
|
||||||
|
state.r.sr |= SR_ARITH_ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x08
|
||||||
|
if (value < 0)
|
||||||
|
{
|
||||||
|
state.r.sr |= SR_SIGN;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x10
|
||||||
|
if (value != static_cast<s32>(value))
|
||||||
|
{
|
||||||
|
state.r.sr |= SR_OVER_S32;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x20 - Checks if top bits of m are equal
|
||||||
|
if (((value & 0xc0000000) == 0) || ((value & 0xc0000000) == 0xc0000000))
|
||||||
|
{
|
||||||
|
state.r.sr |= SR_TOP2BITS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interpreter::UpdateSRLogicZero(bool value)
|
||||||
|
{
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
state.r.sr |= SR_LOGIC_ZERO;
|
||||||
|
else
|
||||||
|
state.r.sr &= ~SR_LOGIC_ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 Interpreter::OpReadRegister(int reg_)
|
||||||
|
{
|
||||||
|
const int reg = reg_ & 0x1f;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
|
switch (reg)
|
||||||
|
{
|
||||||
|
case DSP_REG_ST0:
|
||||||
|
case DSP_REG_ST1:
|
||||||
|
case DSP_REG_ST2:
|
||||||
|
case DSP_REG_ST3:
|
||||||
|
return state.PopStack(static_cast<StackRegister>(reg - DSP_REG_ST0));
|
||||||
|
case DSP_REG_AR0:
|
||||||
|
case DSP_REG_AR1:
|
||||||
|
case DSP_REG_AR2:
|
||||||
|
case DSP_REG_AR3:
|
||||||
|
return state.r.ar[reg - DSP_REG_AR0];
|
||||||
|
case DSP_REG_IX0:
|
||||||
|
case DSP_REG_IX1:
|
||||||
|
case DSP_REG_IX2:
|
||||||
|
case DSP_REG_IX3:
|
||||||
|
return state.r.ix[reg - DSP_REG_IX0];
|
||||||
|
case DSP_REG_WR0:
|
||||||
|
case DSP_REG_WR1:
|
||||||
|
case DSP_REG_WR2:
|
||||||
|
case DSP_REG_WR3:
|
||||||
|
return state.r.wr[reg - DSP_REG_WR0];
|
||||||
|
case DSP_REG_ACH0:
|
||||||
|
case DSP_REG_ACH1:
|
||||||
|
return state.r.ac[reg - DSP_REG_ACH0].h;
|
||||||
|
case DSP_REG_CR:
|
||||||
|
return state.r.cr;
|
||||||
|
case DSP_REG_SR:
|
||||||
|
return state.r.sr;
|
||||||
|
case DSP_REG_PRODL:
|
||||||
|
return state.r.prod.l;
|
||||||
|
case DSP_REG_PRODM:
|
||||||
|
return state.r.prod.m;
|
||||||
|
case DSP_REG_PRODH:
|
||||||
|
return state.r.prod.h;
|
||||||
|
case DSP_REG_PRODM2:
|
||||||
|
return state.r.prod.m2;
|
||||||
|
case DSP_REG_AXL0:
|
||||||
|
case DSP_REG_AXL1:
|
||||||
|
return state.r.ax[reg - DSP_REG_AXL0].l;
|
||||||
|
case DSP_REG_AXH0:
|
||||||
|
case DSP_REG_AXH1:
|
||||||
|
return state.r.ax[reg - DSP_REG_AXH0].h;
|
||||||
|
case DSP_REG_ACL0:
|
||||||
|
case DSP_REG_ACL1:
|
||||||
|
return state.r.ac[reg - DSP_REG_ACL0].l;
|
||||||
|
case DSP_REG_ACM0:
|
||||||
|
case DSP_REG_ACM1:
|
||||||
|
return state.r.ac[reg - DSP_REG_ACM0].m;
|
||||||
|
default:
|
||||||
|
ASSERT_MSG(DSP_INT, 0, "cannot happen");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 Interpreter::OpReadRegisterAndSaturate(int reg) const
|
||||||
|
{
|
||||||
|
if (IsSRFlagSet(SR_40_MODE_BIT))
|
||||||
|
{
|
||||||
|
const s64 acc = GetLongAcc(reg);
|
||||||
|
|
||||||
|
if (acc != static_cast<s32>(acc))
|
||||||
|
{
|
||||||
|
if (acc > 0)
|
||||||
|
return 0x7fff;
|
||||||
|
else
|
||||||
|
return 0x8000;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_dsp_core.DSPState().r.ac[reg].m;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_dsp_core.DSPState().r.ac[reg].m;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interpreter::OpWriteRegister(int reg_, u16 val)
|
||||||
|
{
|
||||||
|
const int reg = reg_ & 0x1f;
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
|
||||||
|
switch (reg)
|
||||||
|
{
|
||||||
|
// 8-bit sign extended registers. Should look at prod.h too...
|
||||||
|
case DSP_REG_ACH0:
|
||||||
|
case DSP_REG_ACH1:
|
||||||
|
// sign extend from the bottom 8 bits.
|
||||||
|
state.r.ac[reg - DSP_REG_ACH0].h = (u16)(s16)(s8)(u8)val;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Stack registers.
|
||||||
|
case DSP_REG_ST0:
|
||||||
|
case DSP_REG_ST1:
|
||||||
|
case DSP_REG_ST2:
|
||||||
|
case DSP_REG_ST3:
|
||||||
|
state.StoreStack(static_cast<StackRegister>(reg - DSP_REG_ST0), val);
|
||||||
|
break;
|
||||||
|
case DSP_REG_AR0:
|
||||||
|
case DSP_REG_AR1:
|
||||||
|
case DSP_REG_AR2:
|
||||||
|
case DSP_REG_AR3:
|
||||||
|
state.r.ar[reg - DSP_REG_AR0] = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_IX0:
|
||||||
|
case DSP_REG_IX1:
|
||||||
|
case DSP_REG_IX2:
|
||||||
|
case DSP_REG_IX3:
|
||||||
|
state.r.ix[reg - DSP_REG_IX0] = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_WR0:
|
||||||
|
case DSP_REG_WR1:
|
||||||
|
case DSP_REG_WR2:
|
||||||
|
case DSP_REG_WR3:
|
||||||
|
state.r.wr[reg - DSP_REG_WR0] = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_CR:
|
||||||
|
state.r.cr = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_SR:
|
||||||
|
state.r.sr = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_PRODL:
|
||||||
|
state.r.prod.l = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_PRODM:
|
||||||
|
state.r.prod.m = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_PRODH:
|
||||||
|
state.r.prod.h = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_PRODM2:
|
||||||
|
state.r.prod.m2 = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_AXL0:
|
||||||
|
case DSP_REG_AXL1:
|
||||||
|
state.r.ax[reg - DSP_REG_AXL0].l = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_AXH0:
|
||||||
|
case DSP_REG_AXH1:
|
||||||
|
state.r.ax[reg - DSP_REG_AXH0].h = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_ACL0:
|
||||||
|
case DSP_REG_ACL1:
|
||||||
|
state.r.ac[reg - DSP_REG_ACL0].l = val;
|
||||||
|
break;
|
||||||
|
case DSP_REG_ACM0:
|
||||||
|
case DSP_REG_ACM1:
|
||||||
|
state.r.ac[reg - DSP_REG_ACM0].m = val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interpreter::ConditionalExtendAccum(int reg)
|
||||||
|
{
|
||||||
|
if (reg != DSP_REG_ACM0 && reg != DSP_REG_ACM1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!IsSRFlagSet(SR_40_MODE_BIT))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Sign extend into whole accum.
|
||||||
|
auto& state = m_dsp_core.DSPState();
|
||||||
|
const u16 val = state.r.ac[reg - DSP_REG_ACM0].m;
|
||||||
|
state.r.ac[reg - DSP_REG_ACM0].h = (val & 0x8000) != 0 ? 0xFFFF : 0x0000;
|
||||||
|
state.r.ac[reg - DSP_REG_ACM0].l = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The ext op are writing their output into the backlog which is
|
||||||
|
// being applied to the real registers after the main op was executed
|
||||||
|
void Interpreter::ApplyWriteBackLog()
|
||||||
|
{
|
||||||
|
// Always make sure to have an extra entry at the end w/ -1 to avoid
|
||||||
|
// infinitive loops
|
||||||
|
for (int i = 0; m_write_back_log_idx[i] != -1; i++)
|
||||||
|
{
|
||||||
|
u16 value = m_write_back_log[i];
|
||||||
|
#ifdef PRECISE_BACKLOG
|
||||||
|
value |= OpReadRegister(m_write_back_log_idx[i]);
|
||||||
|
#endif
|
||||||
|
OpWriteRegister(m_write_back_log_idx[i], value);
|
||||||
|
|
||||||
|
// Clear back log
|
||||||
|
m_write_back_log_idx[i] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interpreter::WriteToBackLog(int i, int idx, u16 value)
|
||||||
|
{
|
||||||
|
m_write_back_log[i] = value;
|
||||||
|
m_write_back_log_idx[i] = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// Only needed for cases when mainop and extended are modifying the same ACC
|
||||||
|
// Games are not doing that + in motorola (similar DSP) dox this is forbidden to do.
|
||||||
|
void Interpreter::ZeroWriteBackLog()
|
||||||
|
{
|
||||||
|
#ifdef PRECISE_BACKLOG
|
||||||
|
// always make sure to have an extra entry at the end w/ -1 to avoid
|
||||||
|
// infinitive loops
|
||||||
|
for (int i = 0; m_write_back_log_idx[i] != -1; i++)
|
||||||
|
{
|
||||||
|
OpWriteRegister(m_write_back_log_idx[i], 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interpreter::ZeroWriteBackLogPreserveAcc([[maybe_unused]] u8 acc)
|
||||||
|
{
|
||||||
|
#ifdef PRECISE_BACKLOG
|
||||||
|
for (int i = 0; m_write_back_log_idx[i] != -1; i++)
|
||||||
|
{
|
||||||
|
// acc0
|
||||||
|
if (acc == 0 &&
|
||||||
|
((m_write_back_log_idx[i] == DSP_REG_ACL0) || (m_write_back_log_idx[i] == DSP_REG_ACM0) ||
|
||||||
|
(m_write_back_log_idx[i] == DSP_REG_ACH0)))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// acc1
|
||||||
|
if (acc == 1 &&
|
||||||
|
((m_write_back_log_idx[i] == DSP_REG_ACL1) || (m_write_back_log_idx[i] == DSP_REG_ACM1) ||
|
||||||
|
(m_write_back_log_idx[i] == DSP_REG_ACH1)))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
OpWriteRegister(m_write_back_log_idx[i], 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interpreter::nop(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
// The real nop is 0. Anything else is bad.
|
// The real nop is 0. Anything else is bad.
|
||||||
if (opc == 0)
|
if (opc == 0)
|
||||||
|
|
|
@ -4,14 +4,27 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
#include "Core/DSP/DSPCommon.h"
|
#include "Core/DSP/DSPCommon.h"
|
||||||
|
#include "Core/DSP/DSPCore.h"
|
||||||
|
|
||||||
namespace DSP::Interpreter
|
namespace DSP::Interpreter
|
||||||
{
|
{
|
||||||
void Step();
|
class Interpreter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Interpreter(DSPCore& dsp);
|
||||||
|
~Interpreter();
|
||||||
|
|
||||||
// See: DspIntBranch.cpp
|
Interpreter(const Interpreter&) = delete;
|
||||||
void HandleLoop();
|
Interpreter& operator=(const Interpreter&) = delete;
|
||||||
|
|
||||||
|
Interpreter(Interpreter&&) = delete;
|
||||||
|
Interpreter& operator=(Interpreter&&) = delete;
|
||||||
|
|
||||||
|
void Step();
|
||||||
|
|
||||||
// If these simply return the same number of cycles as was passed into them,
|
// If these simply return the same number of cycles as was passed into them,
|
||||||
// chances are that the DSP is halted.
|
// chances are that the DSP is halted.
|
||||||
|
@ -23,6 +36,11 @@ int RunCyclesDebug(int cycles);
|
||||||
void WriteCR(u16 val);
|
void WriteCR(u16 val);
|
||||||
u16 ReadCR();
|
u16 ReadCR();
|
||||||
|
|
||||||
|
void SetSRFlag(u16 flag);
|
||||||
|
bool IsSRFlagSet(u16 flag) const;
|
||||||
|
|
||||||
|
void ApplyWriteBackLog();
|
||||||
|
|
||||||
// All the opcode functions.
|
// All the opcode functions.
|
||||||
void abs(UDSPInstruction opc);
|
void abs(UDSPInstruction opc);
|
||||||
void add(UDSPInstruction opc);
|
void add(UDSPInstruction opc);
|
||||||
|
@ -144,4 +162,90 @@ void xorc(UDSPInstruction opc);
|
||||||
void xori(UDSPInstruction opc);
|
void xori(UDSPInstruction opc);
|
||||||
void xorr(UDSPInstruction opc);
|
void xorr(UDSPInstruction opc);
|
||||||
|
|
||||||
|
// Extended ops
|
||||||
|
void l(UDSPInstruction opc);
|
||||||
|
void ln(UDSPInstruction opc);
|
||||||
|
void ls(UDSPInstruction opc);
|
||||||
|
void lsn(UDSPInstruction opc);
|
||||||
|
void lsm(UDSPInstruction opc);
|
||||||
|
void lsnm(UDSPInstruction opc);
|
||||||
|
void sl(UDSPInstruction opc);
|
||||||
|
void sln(UDSPInstruction opc);
|
||||||
|
void slm(UDSPInstruction opc);
|
||||||
|
void slnm(UDSPInstruction opc);
|
||||||
|
void s(UDSPInstruction opc);
|
||||||
|
void sn(UDSPInstruction opc);
|
||||||
|
void ld(UDSPInstruction opc);
|
||||||
|
void ldax(UDSPInstruction opc);
|
||||||
|
void ldn(UDSPInstruction opc);
|
||||||
|
void ldaxn(UDSPInstruction opc);
|
||||||
|
void ldm(UDSPInstruction opc);
|
||||||
|
void ldaxm(UDSPInstruction opc);
|
||||||
|
void ldnm(UDSPInstruction opc);
|
||||||
|
void ldaxnm(UDSPInstruction opc);
|
||||||
|
void mv(UDSPInstruction opc);
|
||||||
|
void dr(UDSPInstruction opc);
|
||||||
|
void ir(UDSPInstruction opc);
|
||||||
|
void nr(UDSPInstruction opc);
|
||||||
|
void nop_ext(UDSPInstruction opc);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void ExecuteInstruction(UDSPInstruction inst);
|
||||||
|
|
||||||
|
bool CheckCondition(u8 condition) const;
|
||||||
|
|
||||||
|
// See: DspIntBranch.cpp
|
||||||
|
void HandleLoop();
|
||||||
|
|
||||||
|
u16 IncrementAddressRegister(u16 reg) const;
|
||||||
|
u16 DecrementAddressRegister(u16 reg) const;
|
||||||
|
|
||||||
|
u16 IncreaseAddressRegister(u16 reg, s16 ix_) const;
|
||||||
|
u16 DecreaseAddressRegister(u16 reg, s16 ix_) const;
|
||||||
|
|
||||||
|
s32 GetLongACX(s32 reg) const;
|
||||||
|
s16 GetAXLow(s32 reg) const;
|
||||||
|
s16 GetAXHigh(s32 reg) const;
|
||||||
|
|
||||||
|
s64 GetLongAcc(s32 reg) const;
|
||||||
|
void SetLongAcc(s32 reg, s64 value);
|
||||||
|
s16 GetAccLow(s32 reg) const;
|
||||||
|
s16 GetAccMid(s32 reg) const;
|
||||||
|
s16 GetAccHigh(s32 reg) const;
|
||||||
|
|
||||||
|
s64 GetLongProduct() const;
|
||||||
|
s64 GetLongProductRounded() const;
|
||||||
|
void SetLongProduct(s64 value);
|
||||||
|
|
||||||
|
s64 GetMultiplyProduct(u16 a, u16 b, u8 sign = 0) const;
|
||||||
|
s64 Multiply(u16 a, u16 b, u8 sign = 0) const;
|
||||||
|
s64 MultiplyAdd(u16 a, u16 b, u8 sign = 0) const;
|
||||||
|
s64 MultiplySub(u16 a, u16 b, u8 sign = 0) const;
|
||||||
|
s64 MultiplyMulX(u8 axh0, u8 axh1, u16 val1, u16 val2) const;
|
||||||
|
|
||||||
|
void UpdateSR16(s16 value, bool carry = false, bool overflow = false, bool over_s32 = false);
|
||||||
|
void UpdateSR64(s64 value, bool carry = false, bool overflow = false);
|
||||||
|
void UpdateSRLogicZero(bool value);
|
||||||
|
|
||||||
|
u16 OpReadRegister(int reg_);
|
||||||
|
u16 OpReadRegisterAndSaturate(int reg) const;
|
||||||
|
void OpWriteRegister(int reg_, u16 val);
|
||||||
|
|
||||||
|
void ConditionalExtendAccum(int reg);
|
||||||
|
|
||||||
|
// The ext ops are calculated in parallel with the actual op. That means that
|
||||||
|
// both the main op and the ext op see the same register state as input. The
|
||||||
|
// output is simple as long as the main and ext ops don't change the same
|
||||||
|
// register. If they do the output is the bitwise OR of the result of both the
|
||||||
|
// main and ext ops.
|
||||||
|
void WriteToBackLog(int i, int idx, u16 value);
|
||||||
|
void ZeroWriteBackLog();
|
||||||
|
void ZeroWriteBackLogPreserveAcc(u8 acc);
|
||||||
|
|
||||||
|
DSPCore& m_dsp_core;
|
||||||
|
|
||||||
|
static constexpr size_t WRITEBACK_LOG_SIZE = 5;
|
||||||
|
std::array<u16, WRITEBACK_LOG_SIZE> m_write_back_log{};
|
||||||
|
std::array<int, WRITEBACK_LOG_SIZE> m_write_back_log_idx{-1, -1, -1, -1, -1};
|
||||||
|
};
|
||||||
} // namespace DSP::Interpreter
|
} // namespace DSP::Interpreter
|
||||||
|
|
|
@ -12,10 +12,10 @@ namespace DSP::JIT
|
||||||
{
|
{
|
||||||
DSPEmitter::~DSPEmitter() = default;
|
DSPEmitter::~DSPEmitter() = default;
|
||||||
|
|
||||||
std::unique_ptr<DSPEmitter> CreateDSPEmitter()
|
std::unique_ptr<DSPEmitter> CreateDSPEmitter([[maybe_unused]] DSPCore& dsp)
|
||||||
{
|
{
|
||||||
#if defined(_M_X86) || defined(_M_X86_64)
|
#if defined(_M_X86) || defined(_M_X86_64)
|
||||||
return std::make_unique<x64::DSPEmitter>();
|
return std::make_unique<x64::DSPEmitter>(dsp);
|
||||||
#else
|
#else
|
||||||
return std::make_unique<DSPEmitterNull>();
|
return std::make_unique<DSPEmitterNull>();
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -10,6 +10,11 @@
|
||||||
|
|
||||||
class PointerWrap;
|
class PointerWrap;
|
||||||
|
|
||||||
|
namespace DSP
|
||||||
|
{
|
||||||
|
class DSPCore;
|
||||||
|
}
|
||||||
|
|
||||||
namespace DSP::JIT
|
namespace DSP::JIT
|
||||||
{
|
{
|
||||||
class DSPEmitter
|
class DSPEmitter
|
||||||
|
@ -31,5 +36,5 @@ public:
|
||||||
void DoState(PointerWrap&) override {}
|
void DoState(PointerWrap&) override {}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<DSPEmitter> CreateDSPEmitter();
|
std::unique_ptr<DSPEmitter> CreateDSPEmitter(DSPCore& dsp);
|
||||||
} // namespace DSP::JIT
|
} // namespace DSP::JIT
|
||||||
|
|
|
@ -17,9 +17,9 @@
|
||||||
#include "Core/DSP/DSPAnalyzer.h"
|
#include "Core/DSP/DSPAnalyzer.h"
|
||||||
#include "Core/DSP/DSPCore.h"
|
#include "Core/DSP/DSPCore.h"
|
||||||
#include "Core/DSP/DSPHost.h"
|
#include "Core/DSP/DSPHost.h"
|
||||||
#include "Core/DSP/DSPMemoryMap.h"
|
|
||||||
#include "Core/DSP/DSPTables.h"
|
#include "Core/DSP/DSPTables.h"
|
||||||
#include "Core/DSP/Interpreter/DSPIntTables.h"
|
#include "Core/DSP/Interpreter/DSPIntTables.h"
|
||||||
|
#include "Core/DSP/Interpreter/DSPInterpreter.h"
|
||||||
#include "Core/DSP/Jit/x64/DSPJitTables.h"
|
#include "Core/DSP/Jit/x64/DSPJitTables.h"
|
||||||
|
|
||||||
using namespace Gen;
|
using namespace Gen;
|
||||||
|
@ -30,9 +30,9 @@ constexpr size_t COMPILED_CODE_SIZE = 2097152;
|
||||||
constexpr size_t MAX_BLOCK_SIZE = 250;
|
constexpr size_t MAX_BLOCK_SIZE = 250;
|
||||||
constexpr u16 DSP_IDLE_SKIP_CYCLES = 0x1000;
|
constexpr u16 DSP_IDLE_SKIP_CYCLES = 0x1000;
|
||||||
|
|
||||||
DSPEmitter::DSPEmitter()
|
DSPEmitter::DSPEmitter(DSPCore& dsp)
|
||||||
: m_compile_status_register{SR_INT_ENABLE | SR_EXT_INT_ENABLE}, m_blocks(MAX_BLOCKS),
|
: m_compile_status_register{SR_INT_ENABLE | SR_EXT_INT_ENABLE}, m_blocks(MAX_BLOCKS),
|
||||||
m_block_size(MAX_BLOCKS), m_block_links(MAX_BLOCKS)
|
m_block_size(MAX_BLOCKS), m_block_links(MAX_BLOCKS), m_dsp_core{dsp}
|
||||||
{
|
{
|
||||||
x64::InitInstructionTables();
|
x64::InitInstructionTables();
|
||||||
AllocCodeSpace(COMPILED_CODE_SIZE);
|
AllocCodeSpace(COMPILED_CODE_SIZE);
|
||||||
|
@ -51,18 +51,18 @@ DSPEmitter::~DSPEmitter()
|
||||||
|
|
||||||
u16 DSPEmitter::RunCycles(u16 cycles)
|
u16 DSPEmitter::RunCycles(u16 cycles)
|
||||||
{
|
{
|
||||||
if (g_dsp.external_interrupt_waiting)
|
if (m_dsp_core.DSPState().external_interrupt_waiting)
|
||||||
{
|
{
|
||||||
DSPCore_CheckExternalInterrupt();
|
m_dsp_core.CheckExternalInterrupt();
|
||||||
DSPCore_CheckExceptions();
|
m_dsp_core.CheckExceptions();
|
||||||
DSPCore_SetExternalInterrupt(false);
|
m_dsp_core.SetExternalInterrupt(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_cycles_left = cycles;
|
m_cycles_left = cycles;
|
||||||
auto exec_addr = (DSPCompiledCode)m_enter_dispatcher;
|
auto exec_addr = (DSPCompiledCode)m_enter_dispatcher;
|
||||||
exec_addr();
|
exec_addr();
|
||||||
|
|
||||||
if (g_dsp.reset_dspjit_codespace)
|
if (m_dsp_core.DSPState().reset_dspjit_codespace)
|
||||||
ClearIRAMandDSPJITCodespaceReset();
|
ClearIRAMandDSPJITCodespaceReset();
|
||||||
|
|
||||||
return m_cycles_left;
|
return m_cycles_left;
|
||||||
|
@ -82,7 +82,7 @@ void DSPEmitter::ClearIRAM()
|
||||||
m_block_size[i] = 0;
|
m_block_size[i] = 0;
|
||||||
m_unresolved_jumps[i].clear();
|
m_unresolved_jumps[i].clear();
|
||||||
}
|
}
|
||||||
g_dsp.reset_dspjit_codespace = true;
|
m_dsp_core.DSPState().reset_dspjit_codespace = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPEmitter::ClearIRAMandDSPJITCodespaceReset()
|
void DSPEmitter::ClearIRAMandDSPJITCodespaceReset()
|
||||||
|
@ -98,7 +98,12 @@ void DSPEmitter::ClearIRAMandDSPJITCodespaceReset()
|
||||||
m_block_size[i] = 0;
|
m_block_size[i] = 0;
|
||||||
m_unresolved_jumps[i].clear();
|
m_unresolved_jumps[i].clear();
|
||||||
}
|
}
|
||||||
g_dsp.reset_dspjit_codespace = false;
|
m_dsp_core.DSPState().reset_dspjit_codespace = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CheckExceptionsThunk(DSPCore& dsp)
|
||||||
|
{
|
||||||
|
dsp.CheckExceptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must go out of block if exception is detected
|
// Must go out of block if exception is detected
|
||||||
|
@ -112,7 +117,7 @@ void DSPEmitter::checkExceptions(u32 retval)
|
||||||
|
|
||||||
DSPJitRegCache c(m_gpr);
|
DSPJitRegCache c(m_gpr);
|
||||||
m_gpr.SaveRegs();
|
m_gpr.SaveRegs();
|
||||||
ABI_CallFunction(DSPCore_CheckExceptions);
|
ABI_CallFunctionP(CheckExceptionsThunk, &m_dsp_core);
|
||||||
MOV(32, R(EAX), Imm32(retval));
|
MOV(32, R(EAX), Imm32(retval));
|
||||||
JMP(m_return_dispatcher, true);
|
JMP(m_return_dispatcher, true);
|
||||||
m_gpr.LoadRegs(false);
|
m_gpr.LoadRegs(false);
|
||||||
|
@ -128,6 +133,11 @@ bool DSPEmitter::FlagsNeeded() const
|
||||||
return !(flags & Analyzer::CODE_START_OF_INST) || (flags & Analyzer::CODE_UPDATE_SR);
|
return !(flags & Analyzer::CODE_START_OF_INST) || (flags & Analyzer::CODE_UPDATE_SR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void FallbackThunk(Interpreter::Interpreter& interpreter, UDSPInstruction inst)
|
||||||
|
{
|
||||||
|
(interpreter.*Interpreter::GetOp(inst))(inst);
|
||||||
|
}
|
||||||
|
|
||||||
void DSPEmitter::FallBackToInterpreter(UDSPInstruction inst)
|
void DSPEmitter::FallBackToInterpreter(UDSPInstruction inst)
|
||||||
{
|
{
|
||||||
const DSPOPCTemplate* const op_template = GetOpTemplate(inst);
|
const DSPOPCTemplate* const op_template = GetOpTemplate(inst);
|
||||||
|
@ -146,10 +156,20 @@ void DSPEmitter::FallBackToInterpreter(UDSPInstruction inst)
|
||||||
|
|
||||||
m_gpr.PushRegs();
|
m_gpr.PushRegs();
|
||||||
ASSERT_MSG(DSPLLE, interpreter_function != nullptr, "No function for %04x", inst);
|
ASSERT_MSG(DSPLLE, interpreter_function != nullptr, "No function for %04x", inst);
|
||||||
ABI_CallFunctionC16(interpreter_function, inst);
|
ABI_CallFunctionPC(FallbackThunk, &m_dsp_core.GetInterpreter(), inst);
|
||||||
m_gpr.PopRegs();
|
m_gpr.PopRegs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void FallbackExtThunk(Interpreter::Interpreter& interpreter, UDSPInstruction inst)
|
||||||
|
{
|
||||||
|
(interpreter.*Interpreter::GetExtOp(inst))(inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ApplyWriteBackLogThunk(Interpreter::Interpreter& interpreter)
|
||||||
|
{
|
||||||
|
interpreter.ApplyWriteBackLog();
|
||||||
|
}
|
||||||
|
|
||||||
void DSPEmitter::EmitInstruction(UDSPInstruction inst)
|
void DSPEmitter::EmitInstruction(UDSPInstruction inst)
|
||||||
{
|
{
|
||||||
const DSPOPCTemplate* const op_template = GetOpTemplate(inst);
|
const DSPOPCTemplate* const op_template = GetOpTemplate(inst);
|
||||||
|
@ -168,10 +188,8 @@ void DSPEmitter::EmitInstruction(UDSPInstruction inst)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Fall back to interpreter
|
// Fall back to interpreter
|
||||||
const auto interpreter_function = Interpreter::GetExtOp(inst);
|
|
||||||
|
|
||||||
m_gpr.PushRegs();
|
m_gpr.PushRegs();
|
||||||
ABI_CallFunctionC16(interpreter_function, inst);
|
ABI_CallFunctionPC(FallbackExtThunk, &m_dsp_core.GetInterpreter(), inst);
|
||||||
m_gpr.PopRegs();
|
m_gpr.PopRegs();
|
||||||
INFO_LOG_FMT(DSPLLE, "Instruction not JITed(ext part): {:04x}", inst);
|
INFO_LOG_FMT(DSPLLE, "Instruction not JITed(ext part): {:04x}", inst);
|
||||||
ext_is_jit = false;
|
ext_is_jit = false;
|
||||||
|
@ -198,7 +216,7 @@ void DSPEmitter::EmitInstruction(UDSPInstruction inst)
|
||||||
// need to call the online cleanup function because
|
// need to call the online cleanup function because
|
||||||
// the writeBackLog gets populated at runtime
|
// the writeBackLog gets populated at runtime
|
||||||
m_gpr.PushRegs();
|
m_gpr.PushRegs();
|
||||||
ABI_CallFunction(ApplyWriteBackLog);
|
ABI_CallFunctionP(ApplyWriteBackLogThunk, &m_dsp_core.GetInterpreter());
|
||||||
m_gpr.PopRegs();
|
m_gpr.PopRegs();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -229,7 +247,7 @@ void DSPEmitter::Compile(u16 start_addr)
|
||||||
if (Analyzer::GetCodeFlags(m_compile_pc) & Analyzer::CODE_CHECK_INT)
|
if (Analyzer::GetCodeFlags(m_compile_pc) & Analyzer::CODE_CHECK_INT)
|
||||||
checkExceptions(m_block_size[start_addr]);
|
checkExceptions(m_block_size[start_addr]);
|
||||||
|
|
||||||
UDSPInstruction inst = dsp_imem_read(m_compile_pc);
|
const UDSPInstruction inst = m_dsp_core.DSPState().ReadIMEM(m_compile_pc);
|
||||||
const DSPOPCTemplate* opcode = GetOpTemplate(inst);
|
const DSPOPCTemplate* opcode = GetOpTemplate(inst);
|
||||||
|
|
||||||
EmitInstruction(inst);
|
EmitInstruction(inst);
|
||||||
|
@ -377,7 +395,7 @@ void DSPEmitter::Compile(u16 start_addr)
|
||||||
|
|
||||||
void DSPEmitter::CompileCurrent(DSPEmitter& emitter)
|
void DSPEmitter::CompileCurrent(DSPEmitter& emitter)
|
||||||
{
|
{
|
||||||
emitter.Compile(g_dsp.pc);
|
emitter.Compile(emitter.m_dsp_core.DSPState().pc);
|
||||||
|
|
||||||
bool retry = true;
|
bool retry = true;
|
||||||
|
|
||||||
|
@ -414,7 +432,7 @@ void DSPEmitter::CompileDispatcher()
|
||||||
BitSet32 registers_used = ABI_ALL_CALLEE_SAVED & BitSet32(0xffff);
|
BitSet32 registers_used = ABI_ALL_CALLEE_SAVED & BitSet32(0xffff);
|
||||||
ABI_PushRegistersAndAdjustStack(registers_used, 8);
|
ABI_PushRegistersAndAdjustStack(registers_used, 8);
|
||||||
|
|
||||||
MOV(64, R(R15), ImmPtr(&g_dsp));
|
MOV(64, R(R15), ImmPtr(&m_dsp_core.DSPState()));
|
||||||
|
|
||||||
const u8* dispatcherLoop = GetCodePtr();
|
const u8* dispatcherLoop = GetCodePtr();
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ namespace JIT::x64
|
||||||
class DSPEmitter final : public JIT::DSPEmitter, public Gen::X64CodeBlock
|
class DSPEmitter final : public JIT::DSPEmitter, public Gen::X64CodeBlock
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DSPEmitter();
|
explicit DSPEmitter(DSPCore& dsp);
|
||||||
~DSPEmitter() override;
|
~DSPEmitter() override;
|
||||||
|
|
||||||
u16 RunCycles(u16 cycles) override;
|
u16 RunCycles(u16 cycles) override;
|
||||||
|
@ -197,6 +197,9 @@ private:
|
||||||
// within the class itself to allow access to member variables.
|
// within the class itself to allow access to member variables.
|
||||||
static void CompileCurrent(DSPEmitter& emitter);
|
static void CompileCurrent(DSPEmitter& emitter);
|
||||||
|
|
||||||
|
static u16 ReadIFXRegisterHelper(DSPEmitter& emitter, u16 address);
|
||||||
|
static void WriteIFXRegisterHelper(DSPEmitter& emitter, u16 address, u16 value);
|
||||||
|
|
||||||
void EmitInstruction(UDSPInstruction inst);
|
void EmitInstruction(UDSPInstruction inst);
|
||||||
void ClearIRAMandDSPJITCodespaceReset();
|
void ClearIRAMandDSPJITCodespaceReset();
|
||||||
|
|
||||||
|
@ -321,6 +324,8 @@ private:
|
||||||
const u8* m_enter_dispatcher;
|
const u8* m_enter_dispatcher;
|
||||||
const u8* m_return_dispatcher;
|
const u8* m_return_dispatcher;
|
||||||
const u8* m_stub_entry_point;
|
const u8* m_stub_entry_point;
|
||||||
|
|
||||||
|
DSPCore& m_dsp_core;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace JIT::x64
|
} // namespace JIT::x64
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
#include "Core/DSP/DSPCore.h"
|
#include "Core/DSP/DSPCore.h"
|
||||||
#include "Core/DSP/DSPMemoryMap.h"
|
|
||||||
#include "Core/DSP/Jit/x64/DSPEmitter.h"
|
#include "Core/DSP/Jit/x64/DSPEmitter.h"
|
||||||
|
|
||||||
using namespace Gen;
|
using namespace Gen;
|
||||||
|
@ -65,9 +64,9 @@ void DSPEmitter::andcf(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
if (FlagsNeeded())
|
if (FlagsNeeded())
|
||||||
{
|
{
|
||||||
u8 reg = (opc >> 8) & 0x1;
|
const u8 reg = (opc >> 8) & 0x1;
|
||||||
// u16 imm = dsp_fetch_code();
|
// u16 imm = dsp_fetch_code();
|
||||||
u16 imm = dsp_imem_read(m_compile_pc + 1);
|
const u16 imm = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);
|
||||||
// u16 val = dsp_get_acc_m(reg);
|
// u16 val = dsp_get_acc_m(reg);
|
||||||
get_acc_m(reg);
|
get_acc_m(reg);
|
||||||
// Update_SR_LZ(((val & imm) == imm) ? true : false);
|
// Update_SR_LZ(((val & imm) == imm) ? true : false);
|
||||||
|
@ -100,9 +99,9 @@ void DSPEmitter::andf(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
if (FlagsNeeded())
|
if (FlagsNeeded())
|
||||||
{
|
{
|
||||||
u8 reg = (opc >> 8) & 0x1;
|
const u8 reg = (opc >> 8) & 0x1;
|
||||||
// u16 imm = dsp_fetch_code();
|
// u16 imm = dsp_fetch_code();
|
||||||
u16 imm = dsp_imem_read(m_compile_pc + 1);
|
const u16 imm = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);
|
||||||
// u16 val = dsp_get_acc_m(reg);
|
// u16 val = dsp_get_acc_m(reg);
|
||||||
get_acc_m(reg);
|
get_acc_m(reg);
|
||||||
// Update_SR_LZ(((val & imm) == 0) ? true : false);
|
// Update_SR_LZ(((val & imm) == 0) ? true : false);
|
||||||
|
@ -226,14 +225,14 @@ void DSPEmitter::cmpi(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
if (FlagsNeeded())
|
if (FlagsNeeded())
|
||||||
{
|
{
|
||||||
u8 reg = (opc >> 8) & 0x1;
|
const u8 reg = (opc >> 8) & 0x1;
|
||||||
X64Reg tmp1 = m_gpr.GetFreeXReg();
|
const X64Reg tmp1 = m_gpr.GetFreeXReg();
|
||||||
// s64 val = dsp_get_long_acc(reg);
|
// s64 val = dsp_get_long_acc(reg);
|
||||||
get_long_acc(reg, tmp1);
|
get_long_acc(reg, tmp1);
|
||||||
MOV(64, R(RAX), R(tmp1));
|
MOV(64, R(RAX), R(tmp1));
|
||||||
// s64 imm = (s64)(s16)dsp_fetch_code() << 16; // Immediate is considered to be at M level in
|
// s64 imm = (s64)(s16)dsp_fetch_code() << 16; // Immediate is considered to be at M level in
|
||||||
// the 40-bit accumulator.
|
// the 40-bit accumulator.
|
||||||
u16 imm = dsp_imem_read(m_compile_pc + 1);
|
const u16 imm = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);
|
||||||
MOV(64, R(RDX), Imm64((s64)(s16)imm << 16));
|
MOV(64, R(RDX), Imm64((s64)(s16)imm << 16));
|
||||||
// s64 res = dsp_convert_long_acc(val - imm);
|
// s64 res = dsp_convert_long_acc(val - imm);
|
||||||
SUB(64, R(RAX), R(RDX));
|
SUB(64, R(RAX), R(RDX));
|
||||||
|
@ -451,9 +450,9 @@ void DSPEmitter::notc(const UDSPInstruction opc)
|
||||||
// flags out: --xx xx00
|
// flags out: --xx xx00
|
||||||
void DSPEmitter::xori(const UDSPInstruction opc)
|
void DSPEmitter::xori(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 reg = (opc >> 8) & 0x1;
|
const u8 reg = (opc >> 8) & 0x1;
|
||||||
// u16 imm = dsp_fetch_code();
|
// u16 imm = dsp_fetch_code();
|
||||||
u16 imm = dsp_imem_read(m_compile_pc + 1);
|
const u16 imm = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);
|
||||||
// g_dsp.r.acm[reg] ^= imm;
|
// g_dsp.r.acm[reg] ^= imm;
|
||||||
get_acc_m(reg, RAX);
|
get_acc_m(reg, RAX);
|
||||||
XOR(16, R(RAX), Imm16(imm));
|
XOR(16, R(RAX), Imm16(imm));
|
||||||
|
@ -474,9 +473,9 @@ void DSPEmitter::xori(const UDSPInstruction opc)
|
||||||
// flags out: --xx xx00
|
// flags out: --xx xx00
|
||||||
void DSPEmitter::andi(const UDSPInstruction opc)
|
void DSPEmitter::andi(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 reg = (opc >> 8) & 0x1;
|
const u8 reg = (opc >> 8) & 0x1;
|
||||||
// u16 imm = dsp_fetch_code();
|
// u16 imm = dsp_fetch_code();
|
||||||
u16 imm = dsp_imem_read(m_compile_pc + 1);
|
const u16 imm = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);
|
||||||
// g_dsp.r.acm[reg] &= imm;
|
// g_dsp.r.acm[reg] &= imm;
|
||||||
get_acc_m(reg, RAX);
|
get_acc_m(reg, RAX);
|
||||||
AND(16, R(RAX), Imm16(imm));
|
AND(16, R(RAX), Imm16(imm));
|
||||||
|
@ -497,9 +496,9 @@ void DSPEmitter::andi(const UDSPInstruction opc)
|
||||||
// flags out: --xx xx00
|
// flags out: --xx xx00
|
||||||
void DSPEmitter::ori(const UDSPInstruction opc)
|
void DSPEmitter::ori(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 reg = (opc >> 8) & 0x1;
|
const u8 reg = (opc >> 8) & 0x1;
|
||||||
// u16 imm = dsp_fetch_code();
|
// u16 imm = dsp_fetch_code();
|
||||||
u16 imm = dsp_imem_read(m_compile_pc + 1);
|
const u16 imm = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);
|
||||||
// g_dsp.r.acm[reg] |= imm;
|
// g_dsp.r.acm[reg] |= imm;
|
||||||
get_acc_m(reg, RAX);
|
get_acc_m(reg, RAX);
|
||||||
OR(16, R(RAX), Imm16(imm));
|
OR(16, R(RAX), Imm16(imm));
|
||||||
|
@ -699,7 +698,7 @@ void DSPEmitter::addi(const UDSPInstruction opc)
|
||||||
get_long_acc(areg, tmp1);
|
get_long_acc(areg, tmp1);
|
||||||
MOV(64, R(RAX), R(tmp1));
|
MOV(64, R(RAX), R(tmp1));
|
||||||
// s64 imm = (s16)dsp_fetch_code();
|
// s64 imm = (s16)dsp_fetch_code();
|
||||||
s16 imm = dsp_imem_read(m_compile_pc + 1);
|
const s16 imm = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);
|
||||||
// imm <<= 16;
|
// imm <<= 16;
|
||||||
MOV(64, R(RDX), Imm32(imm << 16));
|
MOV(64, R(RDX), Imm32(imm << 16));
|
||||||
// s64 res = acc + imm;
|
// s64 res = acc + imm;
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
#include "Core/DSP/DSPAnalyzer.h"
|
#include "Core/DSP/DSPAnalyzer.h"
|
||||||
#include "Core/DSP/DSPCore.h"
|
#include "Core/DSP/DSPCore.h"
|
||||||
#include "Core/DSP/DSPMemoryMap.h"
|
|
||||||
#include "Core/DSP/DSPTables.h"
|
#include "Core/DSP/DSPTables.h"
|
||||||
#include "Core/DSP/Jit/x64/DSPEmitter.h"
|
#include "Core/DSP/Jit/x64/DSPEmitter.h"
|
||||||
|
|
||||||
|
@ -126,7 +125,7 @@ void DSPEmitter::WriteBlockLink(u16 dest)
|
||||||
|
|
||||||
void DSPEmitter::r_jcc(const UDSPInstruction opc)
|
void DSPEmitter::r_jcc(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u16 dest = dsp_imem_read(m_compile_pc + 1);
|
const u16 dest = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);
|
||||||
const DSPOPCTemplate* opcode = GetOpTemplate(opc);
|
const DSPOPCTemplate* opcode = GetOpTemplate(opc);
|
||||||
|
|
||||||
// If the block is unconditional, attempt to link block
|
// If the block is unconditional, attempt to link block
|
||||||
|
@ -172,7 +171,7 @@ void DSPEmitter::r_call(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
MOV(16, R(DX), Imm16(m_compile_pc + 2));
|
MOV(16, R(DX), Imm16(m_compile_pc + 2));
|
||||||
dsp_reg_store_stack(StackRegister::Call);
|
dsp_reg_store_stack(StackRegister::Call);
|
||||||
u16 dest = dsp_imem_read(m_compile_pc + 1);
|
const u16 dest = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);
|
||||||
const DSPOPCTemplate* opcode = GetOpTemplate(opc);
|
const DSPOPCTemplate* opcode = GetOpTemplate(opc);
|
||||||
|
|
||||||
// If the block is unconditional, attempt to link block
|
// If the block is unconditional, attempt to link block
|
||||||
|
@ -228,8 +227,9 @@ void DSPEmitter::r_ifcc(const UDSPInstruction opc)
|
||||||
// NOTE: Cannot use FallBackToInterpreter(opc) here because of the need to write branch exit
|
// NOTE: Cannot use FallBackToInterpreter(opc) here because of the need to write branch exit
|
||||||
void DSPEmitter::ifcc(const UDSPInstruction opc)
|
void DSPEmitter::ifcc(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
|
const auto& state = m_dsp_core.DSPState();
|
||||||
const u16 address = m_compile_pc + 1;
|
const u16 address = m_compile_pc + 1;
|
||||||
const DSPOPCTemplate* const op_template = GetOpTemplate(dsp_imem_read(address));
|
const DSPOPCTemplate* const op_template = GetOpTemplate(state.ReadIMEM(address));
|
||||||
|
|
||||||
MOV(16, M_SDSP_pc(), Imm16(address + op_template->size));
|
MOV(16, M_SDSP_pc(), Imm16(address + op_template->size));
|
||||||
ReJitConditional(opc, &DSPEmitter::r_ifcc);
|
ReJitConditional(opc, &DSPEmitter::r_ifcc);
|
||||||
|
@ -347,7 +347,8 @@ void DSPEmitter::loop(const UDSPInstruction opc)
|
||||||
|
|
||||||
SetJumpTarget(cnt);
|
SetJumpTarget(cnt);
|
||||||
// dsp_skip_inst();
|
// dsp_skip_inst();
|
||||||
MOV(16, M_SDSP_pc(), Imm16(loop_pc + GetOpTemplate(dsp_imem_read(loop_pc))->size));
|
const auto& state = m_dsp_core.DSPState();
|
||||||
|
MOV(16, M_SDSP_pc(), Imm16(loop_pc + GetOpTemplate(state.ReadIMEM(loop_pc))->size));
|
||||||
WriteBranchExit();
|
WriteBranchExit();
|
||||||
m_gpr.FlushRegs(c, false);
|
m_gpr.FlushRegs(c, false);
|
||||||
SetJumpTarget(exit);
|
SetJumpTarget(exit);
|
||||||
|
@ -380,7 +381,8 @@ void DSPEmitter::loopi(const UDSPInstruction opc)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// dsp_skip_inst();
|
// dsp_skip_inst();
|
||||||
MOV(16, M_SDSP_pc(), Imm16(loop_pc + GetOpTemplate(dsp_imem_read(loop_pc))->size));
|
const auto& state = m_dsp_core.DSPState();
|
||||||
|
MOV(16, M_SDSP_pc(), Imm16(loop_pc + GetOpTemplate(state.ReadIMEM(loop_pc))->size));
|
||||||
WriteBranchExit();
|
WriteBranchExit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -396,11 +398,11 @@ void DSPEmitter::loopi(const UDSPInstruction opc)
|
||||||
// Up to 4 nested loops are allowed.
|
// Up to 4 nested loops are allowed.
|
||||||
void DSPEmitter::bloop(const UDSPInstruction opc)
|
void DSPEmitter::bloop(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u16 reg = opc & 0x1f;
|
const u16 reg = opc & 0x1f;
|
||||||
// u16 cnt = g_dsp.r[reg];
|
// u16 cnt = g_dsp.r[reg];
|
||||||
// todo: check if we can use normal variant here
|
// todo: check if we can use normal variant here
|
||||||
dsp_op_read_reg_dont_saturate(reg, RDX, RegisterExtension::Zero);
|
dsp_op_read_reg_dont_saturate(reg, RDX, RegisterExtension::Zero);
|
||||||
u16 loop_pc = dsp_imem_read(m_compile_pc + 1);
|
const u16 loop_pc = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);
|
||||||
|
|
||||||
TEST(16, R(EDX), R(EDX));
|
TEST(16, R(EDX), R(EDX));
|
||||||
DSPJitRegCache c(m_gpr);
|
DSPJitRegCache c(m_gpr);
|
||||||
|
@ -417,7 +419,8 @@ void DSPEmitter::bloop(const UDSPInstruction opc)
|
||||||
SetJumpTarget(cnt);
|
SetJumpTarget(cnt);
|
||||||
// g_dsp.pc = loop_pc;
|
// g_dsp.pc = loop_pc;
|
||||||
// dsp_skip_inst();
|
// dsp_skip_inst();
|
||||||
MOV(16, M_SDSP_pc(), Imm16(loop_pc + GetOpTemplate(dsp_imem_read(loop_pc))->size));
|
const auto& state = m_dsp_core.DSPState();
|
||||||
|
MOV(16, M_SDSP_pc(), Imm16(loop_pc + GetOpTemplate(state.ReadIMEM(loop_pc))->size));
|
||||||
WriteBranchExit();
|
WriteBranchExit();
|
||||||
m_gpr.FlushRegs(c, false);
|
m_gpr.FlushRegs(c, false);
|
||||||
SetJumpTarget(exit);
|
SetJumpTarget(exit);
|
||||||
|
@ -434,11 +437,12 @@ void DSPEmitter::bloop(const UDSPInstruction opc)
|
||||||
// nested loops are allowed.
|
// nested loops are allowed.
|
||||||
void DSPEmitter::bloopi(const UDSPInstruction opc)
|
void DSPEmitter::bloopi(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u16 cnt = opc & 0xff;
|
const auto& state = m_dsp_core.DSPState();
|
||||||
|
const u16 cnt = opc & 0xff;
|
||||||
// u16 loop_pc = dsp_fetch_code();
|
// u16 loop_pc = dsp_fetch_code();
|
||||||
u16 loop_pc = dsp_imem_read(m_compile_pc + 1);
|
const u16 loop_pc = state.ReadIMEM(m_compile_pc + 1);
|
||||||
|
|
||||||
if (cnt)
|
if (cnt != 0)
|
||||||
{
|
{
|
||||||
MOV(16, R(RDX), Imm16(m_compile_pc + 2));
|
MOV(16, R(RDX), Imm16(m_compile_pc + 2));
|
||||||
dsp_reg_store_stack(StackRegister::Call);
|
dsp_reg_store_stack(StackRegister::Call);
|
||||||
|
@ -453,7 +457,7 @@ void DSPEmitter::bloopi(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
// g_dsp.pc = loop_pc;
|
// g_dsp.pc = loop_pc;
|
||||||
// dsp_skip_inst();
|
// dsp_skip_inst();
|
||||||
MOV(16, M_SDSP_pc(), Imm16(loop_pc + GetOpTemplate(dsp_imem_read(loop_pc))->size));
|
MOV(16, M_SDSP_pc(), Imm16(loop_pc + GetOpTemplate(state.ReadIMEM(loop_pc))->size));
|
||||||
WriteBranchExit();
|
WriteBranchExit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
#include "Core/DSP/DSPCore.h"
|
#include "Core/DSP/DSPCore.h"
|
||||||
#include "Core/DSP/DSPMemoryMap.h"
|
|
||||||
#include "Core/DSP/Jit/x64/DSPEmitter.h"
|
#include "Core/DSP/Jit/x64/DSPEmitter.h"
|
||||||
|
|
||||||
using namespace Gen;
|
using namespace Gen;
|
||||||
|
@ -65,8 +64,8 @@ void DSPEmitter::lrs(const UDSPInstruction opc)
|
||||||
// Move value from data memory pointed by address M to register $D.
|
// Move value from data memory pointed by address M to register $D.
|
||||||
void DSPEmitter::lr(const UDSPInstruction opc)
|
void DSPEmitter::lr(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
int reg = opc & 0x1F;
|
const int reg = opc & 0x1F;
|
||||||
u16 address = dsp_imem_read(m_compile_pc + 1);
|
const u16 address = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);
|
||||||
dmem_read_imm(address);
|
dmem_read_imm(address);
|
||||||
dsp_op_write_reg(reg, EAX);
|
dsp_op_write_reg(reg, EAX);
|
||||||
dsp_conditional_extend_accum(reg);
|
dsp_conditional_extend_accum(reg);
|
||||||
|
@ -78,10 +77,10 @@ void DSPEmitter::lr(const UDSPInstruction opc)
|
||||||
// Store value from register $S to a memory pointed by address M.
|
// Store value from register $S to a memory pointed by address M.
|
||||||
void DSPEmitter::sr(const UDSPInstruction opc)
|
void DSPEmitter::sr(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 reg = opc & 0x1F;
|
const u8 reg = opc & 0x1F;
|
||||||
u16 address = dsp_imem_read(m_compile_pc + 1);
|
const u16 address = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);
|
||||||
|
|
||||||
X64Reg tmp1 = m_gpr.GetFreeXReg();
|
const X64Reg tmp1 = m_gpr.GetFreeXReg();
|
||||||
|
|
||||||
dsp_op_read_reg(reg, tmp1);
|
dsp_op_read_reg(reg, tmp1);
|
||||||
dmem_write_imm(address, tmp1);
|
dmem_write_imm(address, tmp1);
|
||||||
|
@ -96,10 +95,10 @@ void DSPEmitter::sr(const UDSPInstruction opc)
|
||||||
// M (M is 8-bit value sign extended).
|
// M (M is 8-bit value sign extended).
|
||||||
void DSPEmitter::si(const UDSPInstruction opc)
|
void DSPEmitter::si(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u16 address = (s8)opc;
|
const u16 address = static_cast<s8>(opc);
|
||||||
u16 imm = dsp_imem_read(m_compile_pc + 1);
|
const u16 imm = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);
|
||||||
|
|
||||||
X64Reg tmp1 = m_gpr.GetFreeXReg();
|
const X64Reg tmp1 = m_gpr.GetFreeXReg();
|
||||||
|
|
||||||
MOV(32, R(tmp1), Imm32((u32)imm));
|
MOV(32, R(tmp1), Imm32((u32)imm));
|
||||||
dmem_write_imm(address, tmp1);
|
dmem_write_imm(address, tmp1);
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
#include "Core/DSP/DSPCore.h"
|
#include "Core/DSP/DSPCore.h"
|
||||||
#include "Core/DSP/DSPMemoryMap.h"
|
|
||||||
#include "Core/DSP/Jit/x64/DSPEmitter.h"
|
#include "Core/DSP/Jit/x64/DSPEmitter.h"
|
||||||
|
|
||||||
using namespace Gen;
|
using namespace Gen;
|
||||||
|
@ -36,8 +35,8 @@ void DSPEmitter::mrr(const UDSPInstruction opc)
|
||||||
// S16 mode.
|
// S16 mode.
|
||||||
void DSPEmitter::lri(const UDSPInstruction opc)
|
void DSPEmitter::lri(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
u8 reg = opc & 0x1F;
|
const u8 reg = opc & 0x1F;
|
||||||
u16 imm = dsp_imem_read(m_compile_pc + 1);
|
const u16 imm = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1);
|
||||||
dsp_op_write_reg_imm(reg, imm);
|
dsp_op_write_reg_imm(reg, imm);
|
||||||
dsp_conditional_extend_accum_imm(reg, imm);
|
dsp_conditional_extend_accum_imm(reg, imm);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
|
|
||||||
#include "Core/DSP/DSPCore.h"
|
#include "Core/DSP/DSPCore.h"
|
||||||
#include "Core/DSP/DSPMemoryMap.h"
|
|
||||||
#include "Core/DSP/Jit/x64/DSPEmitter.h"
|
#include "Core/DSP/Jit/x64/DSPEmitter.h"
|
||||||
|
|
||||||
using namespace Gen;
|
using namespace Gen;
|
||||||
|
|
|
@ -6,13 +6,22 @@
|
||||||
|
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Core/DSP/DSPCore.h"
|
#include "Core/DSP/DSPCore.h"
|
||||||
#include "Core/DSP/DSPHWInterface.h"
|
|
||||||
#include "Core/DSP/Jit/x64/DSPEmitter.h"
|
#include "Core/DSP/Jit/x64/DSPEmitter.h"
|
||||||
|
|
||||||
using namespace Gen;
|
using namespace Gen;
|
||||||
|
|
||||||
namespace DSP::JIT::x64
|
namespace DSP::JIT::x64
|
||||||
{
|
{
|
||||||
|
u16 DSPEmitter::ReadIFXRegisterHelper(DSPEmitter& emitter, u16 address)
|
||||||
|
{
|
||||||
|
return emitter.m_dsp_core.DSPState().ReadIFX(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPEmitter::WriteIFXRegisterHelper(DSPEmitter& emitter, u16 address, u16 value)
|
||||||
|
{
|
||||||
|
emitter.m_dsp_core.DSPState().WriteIFX(address, value);
|
||||||
|
}
|
||||||
|
|
||||||
// clobbers:
|
// clobbers:
|
||||||
// EAX = (s8)g_dsp.reg_stack_ptrs[reg_index]
|
// EAX = (s8)g_dsp.reg_stack_ptrs[reg_index]
|
||||||
// expects:
|
// expects:
|
||||||
|
@ -32,7 +41,7 @@ void DSPEmitter::dsp_reg_stack_push(StackRegister stack_reg)
|
||||||
// g_dsp.reg_stack[reg_index][g_dsp.reg_stack_ptrs[reg_index]] = g_dsp.r[DSP_REG_ST0 + reg_index];
|
// g_dsp.reg_stack[reg_index][g_dsp.reg_stack_ptrs[reg_index]] = g_dsp.r[DSP_REG_ST0 + reg_index];
|
||||||
MOV(16, R(tmp1), M_SDSP_r_st(reg_index));
|
MOV(16, R(tmp1), M_SDSP_r_st(reg_index));
|
||||||
MOVZX(64, 8, RAX, R(AL));
|
MOVZX(64, 8, RAX, R(AL));
|
||||||
MOV(64, R(tmp2), ImmPtr(g_dsp.reg_stacks[reg_index]));
|
MOV(64, R(tmp2), ImmPtr(m_dsp_core.DSPState().reg_stacks[reg_index]));
|
||||||
MOV(16, MComplex(tmp2, EAX, SCALE_2, 0), R(tmp1));
|
MOV(16, MComplex(tmp2, EAX, SCALE_2, 0), R(tmp1));
|
||||||
m_gpr.PutXReg(tmp1);
|
m_gpr.PutXReg(tmp1);
|
||||||
m_gpr.PutXReg(tmp2);
|
m_gpr.PutXReg(tmp2);
|
||||||
|
@ -50,7 +59,7 @@ void DSPEmitter::dsp_reg_stack_pop(StackRegister stack_reg)
|
||||||
X64Reg tmp1 = m_gpr.GetFreeXReg();
|
X64Reg tmp1 = m_gpr.GetFreeXReg();
|
||||||
X64Reg tmp2 = m_gpr.GetFreeXReg();
|
X64Reg tmp2 = m_gpr.GetFreeXReg();
|
||||||
MOVZX(64, 8, RAX, R(AL));
|
MOVZX(64, 8, RAX, R(AL));
|
||||||
MOV(64, R(tmp2), ImmPtr(g_dsp.reg_stacks[reg_index]));
|
MOV(64, R(tmp2), ImmPtr(m_dsp_core.DSPState().reg_stacks[reg_index]));
|
||||||
MOV(16, R(tmp1), MComplex(tmp2, EAX, SCALE_2, 0));
|
MOV(16, R(tmp1), MComplex(tmp2, EAX, SCALE_2, 0));
|
||||||
MOV(16, M_SDSP_r_st(reg_index), R(tmp1));
|
MOV(16, M_SDSP_r_st(reg_index), R(tmp1));
|
||||||
m_gpr.PutXReg(tmp1);
|
m_gpr.PutXReg(tmp1);
|
||||||
|
@ -520,7 +529,7 @@ void DSPEmitter::dmem_write(X64Reg value)
|
||||||
|
|
||||||
// g_dsp.dram[addr & DSP_DRAM_MASK] = val;
|
// g_dsp.dram[addr & DSP_DRAM_MASK] = val;
|
||||||
AND(16, R(EAX), Imm16(DSP_DRAM_MASK));
|
AND(16, R(EAX), Imm16(DSP_DRAM_MASK));
|
||||||
MOV(64, R(ECX), ImmPtr(g_dsp.dram));
|
MOV(64, R(ECX), ImmPtr(m_dsp_core.DSPState().dram));
|
||||||
MOV(16, MComplex(ECX, EAX, SCALE_2, 0), R(value));
|
MOV(16, MComplex(ECX, EAX, SCALE_2, 0), R(value));
|
||||||
|
|
||||||
FixupBranch end = J(true);
|
FixupBranch end = J(true);
|
||||||
|
@ -530,7 +539,7 @@ void DSPEmitter::dmem_write(X64Reg value)
|
||||||
X64Reg abisafereg = m_gpr.MakeABICallSafe(value);
|
X64Reg abisafereg = m_gpr.MakeABICallSafe(value);
|
||||||
MOVZX(32, 16, abisafereg, R(abisafereg));
|
MOVZX(32, 16, abisafereg, R(abisafereg));
|
||||||
m_gpr.PushRegs();
|
m_gpr.PushRegs();
|
||||||
ABI_CallFunctionRR(gdsp_ifx_write, EAX, abisafereg);
|
ABI_CallFunctionPRR(WriteIFXRegisterHelper, this, EAX, abisafereg);
|
||||||
m_gpr.PopRegs();
|
m_gpr.PopRegs();
|
||||||
m_gpr.FlushRegs(c);
|
m_gpr.FlushRegs(c);
|
||||||
SetJumpTarget(end);
|
SetJumpTarget(end);
|
||||||
|
@ -541,7 +550,7 @@ void DSPEmitter::dmem_write_imm(u16 address, X64Reg value)
|
||||||
switch (address >> 12)
|
switch (address >> 12)
|
||||||
{
|
{
|
||||||
case 0x0: // 0xxx DRAM
|
case 0x0: // 0xxx DRAM
|
||||||
MOV(64, R(RDX), ImmPtr(g_dsp.dram));
|
MOV(64, R(RDX), ImmPtr(m_dsp_core.DSPState().dram));
|
||||||
MOV(16, MDisp(RDX, (address & DSP_DRAM_MASK) * 2), R(value));
|
MOV(16, MDisp(RDX, (address & DSP_DRAM_MASK) * 2), R(value));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -550,12 +559,13 @@ void DSPEmitter::dmem_write_imm(u16 address, X64Reg value)
|
||||||
MOV(16, R(EAX), Imm16(address));
|
MOV(16, R(EAX), Imm16(address));
|
||||||
X64Reg abisafereg = m_gpr.MakeABICallSafe(value);
|
X64Reg abisafereg = m_gpr.MakeABICallSafe(value);
|
||||||
m_gpr.PushRegs();
|
m_gpr.PushRegs();
|
||||||
ABI_CallFunctionRR(gdsp_ifx_write, EAX, abisafereg);
|
ABI_CallFunctionPRR(WriteIFXRegisterHelper, this, EAX, abisafereg);
|
||||||
m_gpr.PopRegs();
|
m_gpr.PopRegs();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: // Unmapped/non-existing memory
|
default: // Unmapped/non-existing memory
|
||||||
ERROR_LOG_FMT(DSPLLE, "{:04x} DSP ERROR: Write to UNKNOWN ({:04x}) memory", g_dsp.pc, address);
|
ERROR_LOG_FMT(DSPLLE, "{:04x} DSP ERROR: Write to UNKNOWN ({:04x}) memory",
|
||||||
|
m_dsp_core.DSPState().pc, address);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -570,7 +580,7 @@ void DSPEmitter::imem_read(X64Reg address)
|
||||||
FixupBranch irom = J_CC(CC_A);
|
FixupBranch irom = J_CC(CC_A);
|
||||||
// return g_dsp.iram[addr & DSP_IRAM_MASK];
|
// return g_dsp.iram[addr & DSP_IRAM_MASK];
|
||||||
AND(16, R(address), Imm16(DSP_IRAM_MASK));
|
AND(16, R(address), Imm16(DSP_IRAM_MASK));
|
||||||
MOV(64, R(ECX), ImmPtr(g_dsp.iram));
|
MOV(64, R(ECX), ImmPtr(m_dsp_core.DSPState().iram));
|
||||||
MOV(16, R(EAX), MComplex(ECX, address, SCALE_2, 0));
|
MOV(16, R(EAX), MComplex(ECX, address, SCALE_2, 0));
|
||||||
|
|
||||||
FixupBranch end = J();
|
FixupBranch end = J();
|
||||||
|
@ -578,7 +588,7 @@ void DSPEmitter::imem_read(X64Reg address)
|
||||||
// else if (addr == 0x8)
|
// else if (addr == 0x8)
|
||||||
// return g_dsp.irom[addr & DSP_IROM_MASK];
|
// return g_dsp.irom[addr & DSP_IROM_MASK];
|
||||||
AND(16, R(address), Imm16(DSP_IROM_MASK));
|
AND(16, R(address), Imm16(DSP_IROM_MASK));
|
||||||
MOV(64, R(ECX), ImmPtr(g_dsp.irom));
|
MOV(64, R(ECX), ImmPtr(m_dsp_core.DSPState().irom));
|
||||||
MOV(16, R(EAX), MComplex(ECX, address, SCALE_2, 0));
|
MOV(16, R(EAX), MComplex(ECX, address, SCALE_2, 0));
|
||||||
|
|
||||||
SetJumpTarget(end);
|
SetJumpTarget(end);
|
||||||
|
@ -594,7 +604,7 @@ void DSPEmitter::dmem_read(X64Reg address)
|
||||||
FixupBranch dram = J_CC(CC_A);
|
FixupBranch dram = J_CC(CC_A);
|
||||||
// return g_dsp.dram[addr & DSP_DRAM_MASK];
|
// return g_dsp.dram[addr & DSP_DRAM_MASK];
|
||||||
AND(32, R(address), Imm32(DSP_DRAM_MASK));
|
AND(32, R(address), Imm32(DSP_DRAM_MASK));
|
||||||
MOV(64, R(ECX), ImmPtr(g_dsp.dram));
|
MOV(64, R(ECX), ImmPtr(m_dsp_core.DSPState().dram));
|
||||||
MOV(16, R(EAX), MComplex(ECX, address, SCALE_2, 0));
|
MOV(16, R(EAX), MComplex(ECX, address, SCALE_2, 0));
|
||||||
|
|
||||||
FixupBranch end = J(true);
|
FixupBranch end = J(true);
|
||||||
|
@ -604,7 +614,7 @@ void DSPEmitter::dmem_read(X64Reg address)
|
||||||
FixupBranch ifx = J_CC(CC_A);
|
FixupBranch ifx = J_CC(CC_A);
|
||||||
// return g_dsp.coef[addr & DSP_COEF_MASK];
|
// return g_dsp.coef[addr & DSP_COEF_MASK];
|
||||||
AND(32, R(address), Imm32(DSP_COEF_MASK));
|
AND(32, R(address), Imm32(DSP_COEF_MASK));
|
||||||
MOV(64, R(ECX), ImmPtr(g_dsp.coef));
|
MOV(64, R(ECX), ImmPtr(m_dsp_core.DSPState().coef));
|
||||||
MOV(16, R(EAX), MComplex(ECX, address, SCALE_2, 0));
|
MOV(16, R(EAX), MComplex(ECX, address, SCALE_2, 0));
|
||||||
|
|
||||||
FixupBranch end2 = J(true);
|
FixupBranch end2 = J(true);
|
||||||
|
@ -614,7 +624,7 @@ void DSPEmitter::dmem_read(X64Reg address)
|
||||||
DSPJitRegCache c(m_gpr);
|
DSPJitRegCache c(m_gpr);
|
||||||
X64Reg abisafereg = m_gpr.MakeABICallSafe(address);
|
X64Reg abisafereg = m_gpr.MakeABICallSafe(address);
|
||||||
m_gpr.PushRegs();
|
m_gpr.PushRegs();
|
||||||
ABI_CallFunctionR(gdsp_ifx_read, abisafereg);
|
ABI_CallFunctionPR(ReadIFXRegisterHelper, this, abisafereg);
|
||||||
m_gpr.PopRegs();
|
m_gpr.PopRegs();
|
||||||
m_gpr.FlushRegs(c);
|
m_gpr.FlushRegs(c);
|
||||||
SetJumpTarget(end);
|
SetJumpTarget(end);
|
||||||
|
@ -626,24 +636,25 @@ void DSPEmitter::dmem_read_imm(u16 address)
|
||||||
switch (address >> 12)
|
switch (address >> 12)
|
||||||
{
|
{
|
||||||
case 0x0: // 0xxx DRAM
|
case 0x0: // 0xxx DRAM
|
||||||
MOV(64, R(RDX), ImmPtr(g_dsp.dram));
|
MOV(64, R(RDX), ImmPtr(m_dsp_core.DSPState().dram));
|
||||||
MOV(16, R(EAX), MDisp(RDX, (address & DSP_DRAM_MASK) * 2));
|
MOV(16, R(EAX), MDisp(RDX, (address & DSP_DRAM_MASK) * 2));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x1: // 1xxx COEF
|
case 0x1: // 1xxx COEF
|
||||||
MOV(64, R(RDX), ImmPtr(g_dsp.coef));
|
MOV(64, R(RDX), ImmPtr(m_dsp_core.DSPState().coef));
|
||||||
MOV(16, R(EAX), MDisp(RDX, (address & DSP_COEF_MASK) * 2));
|
MOV(16, R(EAX), MDisp(RDX, (address & DSP_COEF_MASK) * 2));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xf: // Fxxx HW regs
|
case 0xf: // Fxxx HW regs
|
||||||
{
|
{
|
||||||
m_gpr.PushRegs();
|
m_gpr.PushRegs();
|
||||||
ABI_CallFunctionC16(gdsp_ifx_read, address);
|
ABI_CallFunctionPC(ReadIFXRegisterHelper, this, address);
|
||||||
m_gpr.PopRegs();
|
m_gpr.PopRegs();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: // Unmapped/non-existing memory
|
default: // Unmapped/non-existing memory
|
||||||
ERROR_LOG_FMT(DSPLLE, "{:04x} DSP ERROR: Read from UNKNOWN ({:04x}) memory", g_dsp.pc, address);
|
ERROR_LOG_FMT(DSPLLE, "{:04x} DSP ERROR: Read from UNKNOWN ({:04x}) memory",
|
||||||
|
m_dsp_core.DSPState().pc, address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,323 +0,0 @@
|
||||||
// Copyright 2009 Dolphin Emulator Project
|
|
||||||
// Licensed under GPLv2+
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#include "Core/HW/DSPLLE/DSPDebugInterface.h"
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <fmt/format.h>
|
|
||||||
|
|
||||||
#include "Common/MsgHandler.h"
|
|
||||||
#include "Core/DSP/DSPCore.h"
|
|
||||||
#include "Core/DSP/DSPMemoryMap.h"
|
|
||||||
#include "Core/HW/DSPLLE/DSPSymbols.h"
|
|
||||||
|
|
||||||
namespace DSP::LLE
|
|
||||||
{
|
|
||||||
void DSPPatches::Patch(std::size_t index)
|
|
||||||
{
|
|
||||||
PanicAlertFmt("Patch functionality not supported in DSP module.");
|
|
||||||
}
|
|
||||||
|
|
||||||
DSPDebugInterface::DSPDebugInterface() = default;
|
|
||||||
DSPDebugInterface::~DSPDebugInterface() = default;
|
|
||||||
|
|
||||||
std::size_t DSPDebugInterface::SetWatch(u32 address, std::string name)
|
|
||||||
{
|
|
||||||
return m_watches.SetWatch(address, std::move(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
const Common::Debug::Watch& DSPDebugInterface::GetWatch(std::size_t index) const
|
|
||||||
{
|
|
||||||
return m_watches.GetWatch(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<Common::Debug::Watch>& DSPDebugInterface::GetWatches() const
|
|
||||||
{
|
|
||||||
return m_watches.GetWatches();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDebugInterface::UnsetWatch(u32 address)
|
|
||||||
{
|
|
||||||
m_watches.UnsetWatch(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDebugInterface::UpdateWatch(std::size_t index, u32 address, std::string name)
|
|
||||||
{
|
|
||||||
return m_watches.UpdateWatch(index, address, std::move(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDebugInterface::UpdateWatchAddress(std::size_t index, u32 address)
|
|
||||||
{
|
|
||||||
return m_watches.UpdateWatchAddress(index, address);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDebugInterface::UpdateWatchName(std::size_t index, std::string name)
|
|
||||||
{
|
|
||||||
return m_watches.UpdateWatchName(index, std::move(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDebugInterface::EnableWatch(std::size_t index)
|
|
||||||
{
|
|
||||||
m_watches.EnableWatch(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDebugInterface::DisableWatch(std::size_t index)
|
|
||||||
{
|
|
||||||
m_watches.DisableWatch(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DSPDebugInterface::HasEnabledWatch(u32 address) const
|
|
||||||
{
|
|
||||||
return m_watches.HasEnabledWatch(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDebugInterface::RemoveWatch(std::size_t index)
|
|
||||||
{
|
|
||||||
return m_watches.RemoveWatch(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDebugInterface::LoadWatchesFromStrings(const std::vector<std::string>& watches)
|
|
||||||
{
|
|
||||||
m_watches.LoadFromStrings(watches);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> DSPDebugInterface::SaveWatchesToStrings() const
|
|
||||||
{
|
|
||||||
return m_watches.SaveToStrings();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDebugInterface::ClearWatches()
|
|
||||||
{
|
|
||||||
m_watches.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDebugInterface::SetPatch(u32 address, u32 value)
|
|
||||||
{
|
|
||||||
m_patches.SetPatch(address, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDebugInterface::SetPatch(u32 address, std::vector<u8> value)
|
|
||||||
{
|
|
||||||
m_patches.SetPatch(address, std::move(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<Common::Debug::MemoryPatch>& DSPDebugInterface::GetPatches() const
|
|
||||||
{
|
|
||||||
return m_patches.GetPatches();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDebugInterface::UnsetPatch(u32 address)
|
|
||||||
{
|
|
||||||
m_patches.UnsetPatch(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDebugInterface::EnablePatch(std::size_t index)
|
|
||||||
{
|
|
||||||
m_patches.EnablePatch(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDebugInterface::DisablePatch(std::size_t index)
|
|
||||||
{
|
|
||||||
m_patches.DisablePatch(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDebugInterface::RemovePatch(std::size_t index)
|
|
||||||
{
|
|
||||||
m_patches.RemovePatch(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DSPDebugInterface::HasEnabledPatch(u32 address) const
|
|
||||||
{
|
|
||||||
return m_patches.HasEnabledPatch(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDebugInterface::ClearPatches()
|
|
||||||
{
|
|
||||||
m_patches.ClearPatches();
|
|
||||||
}
|
|
||||||
|
|
||||||
Common::Debug::Threads DSPDebugInterface::GetThreads() const
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string DSPDebugInterface::Disassemble(u32 address) const
|
|
||||||
{
|
|
||||||
// we'll treat addresses as line numbers.
|
|
||||||
return Symbols::GetLineText(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string DSPDebugInterface::GetRawMemoryString(int memory, u32 address) const
|
|
||||||
{
|
|
||||||
if (DSPCore_GetState() == State::Stopped)
|
|
||||||
return "";
|
|
||||||
|
|
||||||
switch (memory)
|
|
||||||
{
|
|
||||||
case 0: // IMEM
|
|
||||||
switch (address >> 12)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
case 0x8:
|
|
||||||
return fmt::format("{:04x}", dsp_imem_read(address));
|
|
||||||
default:
|
|
||||||
return "--IMEM--";
|
|
||||||
}
|
|
||||||
|
|
||||||
case 1: // DMEM
|
|
||||||
switch (address >> 12)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
case 1:
|
|
||||||
return fmt::format("{:04x} (DMEM)", dsp_dmem_read(address));
|
|
||||||
case 0xf:
|
|
||||||
return fmt::format("{:04x} (MMIO)", g_dsp.ifx_regs[address & 0xFF]);
|
|
||||||
default:
|
|
||||||
return "--DMEM--";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 DSPDebugInterface::ReadMemory(u32 address) const
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 DSPDebugInterface::ReadInstruction(u32 address) const
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DSPDebugInterface::IsAlive() const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DSPDebugInterface::IsBreakpoint(u32 address) const
|
|
||||||
{
|
|
||||||
int real_addr = Symbols::Line2Addr(address);
|
|
||||||
if (real_addr >= 0)
|
|
||||||
return g_dsp_breakpoints.IsAddressBreakPoint(real_addr);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDebugInterface::SetBreakpoint(u32 address)
|
|
||||||
{
|
|
||||||
int real_addr = Symbols::Line2Addr(address);
|
|
||||||
|
|
||||||
if (real_addr >= 0)
|
|
||||||
{
|
|
||||||
g_dsp_breakpoints.Add(real_addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDebugInterface::ClearBreakpoint(u32 address)
|
|
||||||
{
|
|
||||||
int real_addr = Symbols::Line2Addr(address);
|
|
||||||
|
|
||||||
if (real_addr >= 0)
|
|
||||||
{
|
|
||||||
g_dsp_breakpoints.Remove(real_addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDebugInterface::ClearAllBreakpoints()
|
|
||||||
{
|
|
||||||
g_dsp_breakpoints.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDebugInterface::ToggleBreakpoint(u32 address)
|
|
||||||
{
|
|
||||||
int real_addr = Symbols::Line2Addr(address);
|
|
||||||
if (real_addr >= 0)
|
|
||||||
{
|
|
||||||
if (g_dsp_breakpoints.IsAddressBreakPoint(real_addr))
|
|
||||||
g_dsp_breakpoints.Remove(real_addr);
|
|
||||||
else
|
|
||||||
g_dsp_breakpoints.Add(real_addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DSPDebugInterface::IsMemCheck(u32 address, size_t size) const
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDebugInterface::ClearAllMemChecks()
|
|
||||||
{
|
|
||||||
PanicAlertFmt("MemCheck functionality not supported in DSP module.");
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDebugInterface::ToggleMemCheck(u32 address, bool read, bool write, bool log)
|
|
||||||
{
|
|
||||||
PanicAlertFmt("MemCheck functionality not supported in DSP module.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// =======================================================
|
|
||||||
// Separate the blocks with colors.
|
|
||||||
// -------------
|
|
||||||
u32 DSPDebugInterface::GetColor(u32 address) const
|
|
||||||
{
|
|
||||||
// Scan backwards so we don't miss it. Hm, actually, let's not - it looks pretty good.
|
|
||||||
int addr = -1;
|
|
||||||
for (int i = 0; i < 1; i++)
|
|
||||||
{
|
|
||||||
addr = Symbols::Line2Addr(address - i);
|
|
||||||
if (addr >= 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (addr == -1)
|
|
||||||
return 0xFFFFFF;
|
|
||||||
|
|
||||||
Common::Symbol* symbol = Symbols::g_dsp_symbol_db.GetSymbolFromAddr(addr);
|
|
||||||
if (!symbol)
|
|
||||||
return 0xFFFFFF;
|
|
||||||
if (symbol->type != Common::Symbol::Type::Function)
|
|
||||||
return 0xEEEEFF;
|
|
||||||
|
|
||||||
static constexpr std::array<u32, 6> colors{
|
|
||||||
0xd0FFFF, // light cyan
|
|
||||||
0xFFd0d0, // light red
|
|
||||||
0xd8d8FF, // light blue
|
|
||||||
0xFFd0FF, // light purple
|
|
||||||
0xd0FFd0, // light green
|
|
||||||
0xFFFFd0, // light yellow
|
|
||||||
};
|
|
||||||
return colors[symbol->index % colors.size()];
|
|
||||||
}
|
|
||||||
// =============
|
|
||||||
|
|
||||||
std::string DSPDebugInterface::GetDescription(u32 address) const
|
|
||||||
{
|
|
||||||
return ""; // g_symbolDB.GetDescription(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 DSPDebugInterface::GetPC() const
|
|
||||||
{
|
|
||||||
return Symbols::Addr2Line(DSP::g_dsp.pc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDebugInterface::SetPC(u32 address)
|
|
||||||
{
|
|
||||||
int new_pc = Symbols::Line2Addr(address);
|
|
||||||
if (new_pc > 0)
|
|
||||||
g_dsp.pc = new_pc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDebugInterface::RunToBreakpoint()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void DSPDebugInterface::Clear()
|
|
||||||
{
|
|
||||||
ClearPatches();
|
|
||||||
ClearWatches();
|
|
||||||
}
|
|
||||||
} // namespace DSP::LLE
|
|
|
@ -1,85 +0,0 @@
|
||||||
// Copyright 2008 Dolphin Emulator Project
|
|
||||||
// Licensed under GPLv2+
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
|
||||||
#include "Common/Debug/MemoryPatches.h"
|
|
||||||
#include "Common/Debug/Watches.h"
|
|
||||||
#include "Common/DebugInterface.h"
|
|
||||||
|
|
||||||
namespace DSP::LLE
|
|
||||||
{
|
|
||||||
class DSPPatches : public Common::Debug::MemoryPatches
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
void Patch(std::size_t index) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DSPDebugInterface final : public Common::DebugInterface
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DSPDebugInterface();
|
|
||||||
~DSPDebugInterface() override;
|
|
||||||
|
|
||||||
// Watches
|
|
||||||
std::size_t SetWatch(u32 address, std::string name = "") override;
|
|
||||||
const Common::Debug::Watch& GetWatch(std::size_t index) const override;
|
|
||||||
const std::vector<Common::Debug::Watch>& GetWatches() const override;
|
|
||||||
void UnsetWatch(u32 address) override;
|
|
||||||
void UpdateWatch(std::size_t index, u32 address, std::string name) override;
|
|
||||||
void UpdateWatchAddress(std::size_t index, u32 address) override;
|
|
||||||
void UpdateWatchName(std::size_t index, std::string name) override;
|
|
||||||
void EnableWatch(std::size_t index) override;
|
|
||||||
void DisableWatch(std::size_t index) override;
|
|
||||||
bool HasEnabledWatch(u32 address) const override;
|
|
||||||
void RemoveWatch(std::size_t index) override;
|
|
||||||
void LoadWatchesFromStrings(const std::vector<std::string>& watches) override;
|
|
||||||
std::vector<std::string> SaveWatchesToStrings() const override;
|
|
||||||
void ClearWatches() override;
|
|
||||||
|
|
||||||
// Memory Patches
|
|
||||||
void SetPatch(u32 address, u32 value) override;
|
|
||||||
void SetPatch(u32 address, std::vector<u8> value) override;
|
|
||||||
const std::vector<Common::Debug::MemoryPatch>& GetPatches() const override;
|
|
||||||
void UnsetPatch(u32 address) override;
|
|
||||||
void EnablePatch(std::size_t index) override;
|
|
||||||
void DisablePatch(std::size_t index) override;
|
|
||||||
void RemovePatch(std::size_t index) override;
|
|
||||||
bool HasEnabledPatch(u32 address) const override;
|
|
||||||
void ClearPatches() override;
|
|
||||||
|
|
||||||
// Threads
|
|
||||||
Common::Debug::Threads GetThreads() const override;
|
|
||||||
|
|
||||||
std::string Disassemble(u32 address) const override;
|
|
||||||
std::string GetRawMemoryString(int memory, u32 address) const override;
|
|
||||||
bool IsAlive() const override;
|
|
||||||
bool IsBreakpoint(u32 address) const override;
|
|
||||||
void SetBreakpoint(u32 address) override;
|
|
||||||
void ClearBreakpoint(u32 address) override;
|
|
||||||
void ClearAllBreakpoints() override;
|
|
||||||
void ToggleBreakpoint(u32 address) override;
|
|
||||||
void ClearAllMemChecks() override;
|
|
||||||
bool IsMemCheck(u32 address, size_t size) const override;
|
|
||||||
void ToggleMemCheck(u32 address, bool read = true, bool write = true, bool log = true) override;
|
|
||||||
u32 ReadMemory(u32 address) const override;
|
|
||||||
u32 ReadInstruction(u32 address) const override;
|
|
||||||
u32 GetPC() const override;
|
|
||||||
void SetPC(u32 address) override;
|
|
||||||
void Step() override {}
|
|
||||||
void RunToBreakpoint() override;
|
|
||||||
u32 GetColor(u32 address) const override;
|
|
||||||
std::string GetDescription(u32 address) const override;
|
|
||||||
|
|
||||||
void Clear() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Common::Debug::Watches m_watches;
|
|
||||||
DSPPatches m_patches;
|
|
||||||
};
|
|
||||||
} // namespace DSP::LLE
|
|
|
@ -68,31 +68,33 @@ void InterruptRequest()
|
||||||
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
|
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeLoaded(u32 addr, size_t size)
|
void CodeLoaded(DSPCore& dsp, u32 addr, size_t size)
|
||||||
{
|
{
|
||||||
CodeLoaded(Memory::GetPointer(addr), size);
|
CodeLoaded(dsp, Memory::GetPointer(addr), size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeLoaded(const u8* ptr, size_t size)
|
void CodeLoaded(DSPCore& dsp, const u8* ptr, size_t size)
|
||||||
{
|
{
|
||||||
g_dsp.iram_crc = Common::HashEctor(ptr, size);
|
auto& state = dsp.DSPState();
|
||||||
|
const u32 iram_crc = Common::HashEctor(ptr, size);
|
||||||
|
state.iram_crc = iram_crc;
|
||||||
|
|
||||||
if (SConfig::GetInstance().m_DumpUCode)
|
if (SConfig::GetInstance().m_DumpUCode)
|
||||||
{
|
{
|
||||||
DSP::DumpDSPCode(ptr, size, g_dsp.iram_crc);
|
DSP::DumpDSPCode(ptr, size, iram_crc);
|
||||||
}
|
}
|
||||||
|
|
||||||
NOTICE_LOG_FMT(DSPLLE, "g_dsp.iram_crc: {:08x}", g_dsp.iram_crc);
|
NOTICE_LOG_FMT(DSPLLE, "g_dsp.iram_crc: {:08x}", iram_crc);
|
||||||
|
|
||||||
Symbols::Clear();
|
Symbols::Clear();
|
||||||
Symbols::AutoDisassembly(0x0, 0x1000);
|
Symbols::AutoDisassembly(state, 0x0, 0x1000);
|
||||||
Symbols::AutoDisassembly(0x8000, 0x9000);
|
Symbols::AutoDisassembly(state, 0x8000, 0x9000);
|
||||||
|
|
||||||
UpdateDebugger();
|
UpdateDebugger();
|
||||||
|
|
||||||
if (g_dsp_jit)
|
dsp.ClearIRAM();
|
||||||
g_dsp_jit->ClearIRAM();
|
|
||||||
|
|
||||||
Analyzer::Analyze();
|
Analyzer::Analyze(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateDebugger()
|
void UpdateDebugger()
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
#include "Core/DSP/DSPAccelerator.h"
|
#include "Core/DSP/DSPAccelerator.h"
|
||||||
#include "Core/DSP/DSPCaptureLogger.h"
|
#include "Core/DSP/DSPCaptureLogger.h"
|
||||||
#include "Core/DSP/DSPCore.h"
|
#include "Core/DSP/DSPCore.h"
|
||||||
#include "Core/DSP/DSPHWInterface.h"
|
|
||||||
#include "Core/DSP/DSPHost.h"
|
#include "Core/DSP/DSPHost.h"
|
||||||
#include "Core/DSP/DSPTables.h"
|
#include "Core/DSP/DSPTables.h"
|
||||||
#include "Core/DSP/Interpreter/DSPInterpreter.h"
|
#include "Core/DSP/Interpreter/DSPInterpreter.h"
|
||||||
|
@ -32,15 +31,11 @@
|
||||||
|
|
||||||
namespace DSP::LLE
|
namespace DSP::LLE
|
||||||
{
|
{
|
||||||
static Common::Event s_dsp_event;
|
|
||||||
static Common::Event s_ppc_event;
|
|
||||||
static bool s_request_disable_thread;
|
|
||||||
|
|
||||||
DSPLLE::DSPLLE() = default;
|
DSPLLE::DSPLLE() = default;
|
||||||
|
|
||||||
DSPLLE::~DSPLLE()
|
DSPLLE::~DSPLLE()
|
||||||
{
|
{
|
||||||
DSPCore_Shutdown();
|
m_dsp_core.Shutdown();
|
||||||
DSP_StopSoundStream();
|
DSP_StopSoundStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,39 +50,8 @@ void DSPLLE::DoState(PointerWrap& p)
|
||||||
p.SetMode(PointerWrap::MODE_VERIFY);
|
p.SetMode(PointerWrap::MODE_VERIFY);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
p.Do(g_dsp.r);
|
m_dsp_core.DoState(p);
|
||||||
p.Do(g_dsp.pc);
|
|
||||||
#if PROFILE
|
|
||||||
p.Do(g_dsp.err_pc);
|
|
||||||
#endif
|
|
||||||
p.Do(g_dsp.cr);
|
|
||||||
p.Do(g_dsp.reg_stack_ptrs);
|
|
||||||
p.Do(g_dsp.exceptions);
|
|
||||||
p.Do(g_dsp.external_interrupt_waiting);
|
|
||||||
|
|
||||||
for (auto& stack : g_dsp.reg_stacks)
|
|
||||||
{
|
|
||||||
p.Do(stack);
|
|
||||||
}
|
|
||||||
|
|
||||||
p.Do(g_dsp.step_counter);
|
|
||||||
p.DoArray(g_dsp.ifx_regs);
|
|
||||||
g_dsp.accelerator->DoState(p);
|
|
||||||
p.Do(g_dsp.mbox[0]);
|
|
||||||
p.Do(g_dsp.mbox[1]);
|
|
||||||
Common::UnWriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false);
|
|
||||||
p.DoArray(g_dsp.iram, DSP_IRAM_SIZE);
|
|
||||||
Common::WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false);
|
|
||||||
// TODO: This uses the wrong endianness (producing bad disassembly)
|
|
||||||
// and a bogus byte count (producing bad hashes)
|
|
||||||
if (p.GetMode() == PointerWrap::MODE_READ)
|
|
||||||
Host::CodeLoaded(reinterpret_cast<const u8*>(g_dsp.iram), DSP_IRAM_BYTE_SIZE);
|
|
||||||
p.DoArray(g_dsp.dram, DSP_DRAM_SIZE);
|
|
||||||
p.Do(g_init_hax);
|
|
||||||
p.Do(m_cycle_count);
|
p.Do(m_cycle_count);
|
||||||
|
|
||||||
if (g_dsp_jit)
|
|
||||||
g_dsp_jit->DoState(p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Regular thread
|
// Regular thread
|
||||||
|
@ -103,21 +67,21 @@ void DSPLLE::DSPThread(DSPLLE* dsp_lle)
|
||||||
std::unique_lock dsp_thread_lock(dsp_lle->m_dsp_thread_mutex, std::try_to_lock);
|
std::unique_lock dsp_thread_lock(dsp_lle->m_dsp_thread_mutex, std::try_to_lock);
|
||||||
if (dsp_thread_lock)
|
if (dsp_thread_lock)
|
||||||
{
|
{
|
||||||
if (g_dsp_jit)
|
if (dsp_lle->m_dsp_core.IsJITCreated())
|
||||||
{
|
{
|
||||||
DSPCore_RunCycles(cycles);
|
dsp_lle->m_dsp_core.RunCycles(cycles);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DSP::Interpreter::RunCyclesThread(cycles);
|
dsp_lle->m_dsp_core.GetInterpreter().RunCyclesThread(cycles);
|
||||||
}
|
}
|
||||||
dsp_lle->m_cycle_count.store(0);
|
dsp_lle->m_cycle_count.store(0);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s_ppc_event.Set();
|
dsp_lle->m_ppc_event.Set();
|
||||||
s_dsp_event.Wait();
|
dsp_lle->m_dsp_event.Wait();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,22 +137,22 @@ static bool FillDSPInitOptions(DSPInitOptions* opts)
|
||||||
|
|
||||||
bool DSPLLE::Initialize(bool wii, bool dsp_thread)
|
bool DSPLLE::Initialize(bool wii, bool dsp_thread)
|
||||||
{
|
{
|
||||||
s_request_disable_thread = false;
|
m_request_disable_thread = false;
|
||||||
|
|
||||||
DSPInitOptions opts;
|
DSPInitOptions opts;
|
||||||
if (!FillDSPInitOptions(&opts))
|
if (!FillDSPInitOptions(&opts))
|
||||||
return false;
|
return false;
|
||||||
if (!DSPCore_Init(opts))
|
if (!m_dsp_core.Initialize(opts))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// needs to be after DSPCore_Init for the dspjit ptr
|
// needs to be after DSPCore_Init for the dspjit ptr
|
||||||
if (Core::WantsDeterminism() || !g_dsp_jit)
|
if (Core::WantsDeterminism() || !m_dsp_core.IsJITCreated())
|
||||||
dsp_thread = false;
|
dsp_thread = false;
|
||||||
|
|
||||||
m_wii = wii;
|
m_wii = wii;
|
||||||
m_is_dsp_on_thread = dsp_thread;
|
m_is_dsp_on_thread = dsp_thread;
|
||||||
|
|
||||||
DSPCore_Reset();
|
m_dsp_core.Reset();
|
||||||
|
|
||||||
InitInstructionTable();
|
InitInstructionTable();
|
||||||
|
|
||||||
|
@ -204,77 +168,70 @@ bool DSPLLE::Initialize(bool wii, bool dsp_thread)
|
||||||
|
|
||||||
void DSPLLE::DSP_StopSoundStream()
|
void DSPLLE::DSP_StopSoundStream()
|
||||||
{
|
{
|
||||||
if (m_is_dsp_on_thread)
|
if (!m_is_dsp_on_thread)
|
||||||
{
|
return;
|
||||||
|
|
||||||
m_is_running.Clear();
|
m_is_running.Clear();
|
||||||
s_ppc_event.Set();
|
m_ppc_event.Set();
|
||||||
s_dsp_event.Set();
|
m_dsp_event.Set();
|
||||||
m_dsp_thread.join();
|
m_dsp_thread.join();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void DSPLLE::Shutdown()
|
void DSPLLE::Shutdown()
|
||||||
{
|
{
|
||||||
DSPCore_Shutdown();
|
m_dsp_core.Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 DSPLLE::DSP_WriteControlRegister(u16 value)
|
u16 DSPLLE::DSP_WriteControlRegister(u16 value)
|
||||||
{
|
{
|
||||||
DSP::Interpreter::WriteCR(value);
|
m_dsp_core.GetInterpreter().WriteCR(value);
|
||||||
|
|
||||||
if (value & 2)
|
if ((value & 2) != 0)
|
||||||
{
|
{
|
||||||
if (!m_is_dsp_on_thread)
|
if (m_is_dsp_on_thread)
|
||||||
{
|
|
||||||
DSPCore_CheckExternalInterrupt();
|
|
||||||
DSPCore_CheckExceptions();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// External interrupt pending: this is the zelda ucode.
|
// External interrupt pending: this is the zelda ucode.
|
||||||
// Disable the DSP thread because there is no performance gain.
|
// Disable the DSP thread because there is no performance gain.
|
||||||
s_request_disable_thread = true;
|
m_request_disable_thread = true;
|
||||||
|
|
||||||
DSPCore_SetExternalInterrupt(true);
|
m_dsp_core.SetExternalInterrupt(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_dsp_core.CheckExternalInterrupt();
|
||||||
|
m_dsp_core.CheckExceptions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return DSP::Interpreter::ReadCR();
|
return DSP_ReadControlRegister();
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 DSPLLE::DSP_ReadControlRegister()
|
u16 DSPLLE::DSP_ReadControlRegister()
|
||||||
{
|
{
|
||||||
return DSP::Interpreter::ReadCR();
|
return m_dsp_core.GetInterpreter().ReadCR();
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 DSPLLE::DSP_ReadMailBoxHigh(bool cpu_mailbox)
|
u16 DSPLLE::DSP_ReadMailBoxHigh(bool cpu_mailbox)
|
||||||
{
|
{
|
||||||
return gdsp_mbox_read_h(cpu_mailbox ? MAILBOX_CPU : MAILBOX_DSP);
|
return m_dsp_core.ReadMailboxHigh(cpu_mailbox ? MAILBOX_CPU : MAILBOX_DSP);
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 DSPLLE::DSP_ReadMailBoxLow(bool cpu_mailbox)
|
u16 DSPLLE::DSP_ReadMailBoxLow(bool cpu_mailbox)
|
||||||
{
|
{
|
||||||
return gdsp_mbox_read_l(cpu_mailbox ? MAILBOX_CPU : MAILBOX_DSP);
|
return m_dsp_core.ReadMailboxLow(cpu_mailbox ? MAILBOX_CPU : MAILBOX_DSP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPLLE::DSP_WriteMailBoxHigh(bool cpu_mailbox, u16 value)
|
void DSPLLE::DSP_WriteMailBoxHigh(bool cpu_mailbox, u16 value)
|
||||||
{
|
{
|
||||||
if (cpu_mailbox)
|
if (cpu_mailbox)
|
||||||
{
|
{
|
||||||
if (gdsp_mbox_peek(MAILBOX_CPU) & 0x80000000)
|
if ((m_dsp_core.PeekMailbox(MAILBOX_CPU) & 0x80000000) != 0)
|
||||||
{
|
{
|
||||||
// the DSP didn't read the previous value
|
// the DSP didn't read the previous value
|
||||||
WARN_LOG_FMT(DSPLLE, "Mailbox isn't empty ... strange");
|
WARN_LOG_FMT(DSPLLE, "Mailbox isn't empty ... strange");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PROFILE
|
m_dsp_core.WriteMailboxHigh(MAILBOX_CPU, value);
|
||||||
if (value == 0xBABE)
|
|
||||||
{
|
|
||||||
ProfilerStart();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
gdsp_mbox_write_h(MAILBOX_CPU, value);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -286,7 +243,7 @@ void DSPLLE::DSP_WriteMailBoxLow(bool cpu_mailbox, u16 value)
|
||||||
{
|
{
|
||||||
if (cpu_mailbox)
|
if (cpu_mailbox)
|
||||||
{
|
{
|
||||||
gdsp_mbox_write_l(MAILBOX_CPU, value);
|
m_dsp_core.WriteMailboxLow(MAILBOX_CPU, value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -296,18 +253,18 @@ void DSPLLE::DSP_WriteMailBoxLow(bool cpu_mailbox, u16 value)
|
||||||
|
|
||||||
void DSPLLE::DSP_Update(int cycles)
|
void DSPLLE::DSP_Update(int cycles)
|
||||||
{
|
{
|
||||||
int dsp_cycles = cycles / 6;
|
const int dsp_cycles = cycles / 6;
|
||||||
|
|
||||||
if (dsp_cycles <= 0)
|
if (dsp_cycles <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (m_is_dsp_on_thread)
|
if (m_is_dsp_on_thread)
|
||||||
{
|
{
|
||||||
if (s_request_disable_thread || Core::WantsDeterminism())
|
if (m_request_disable_thread || Core::WantsDeterminism())
|
||||||
{
|
{
|
||||||
DSP_StopSoundStream();
|
DSP_StopSoundStream();
|
||||||
m_is_dsp_on_thread = false;
|
m_is_dsp_on_thread = false;
|
||||||
s_request_disable_thread = false;
|
m_request_disable_thread = false;
|
||||||
SConfig::GetInstance().bDSPThread = false;
|
SConfig::GetInstance().bDSPThread = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -316,14 +273,14 @@ void DSPLLE::DSP_Update(int cycles)
|
||||||
if (!m_is_dsp_on_thread)
|
if (!m_is_dsp_on_thread)
|
||||||
{
|
{
|
||||||
// ~1/6th as many cycles as the period PPC-side.
|
// ~1/6th as many cycles as the period PPC-side.
|
||||||
DSPCore_RunCycles(dsp_cycles);
|
m_dsp_core.RunCycles(dsp_cycles);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Wait for DSP thread to complete its cycle. Note: this logic should be thought through.
|
// Wait for DSP thread to complete its cycle. Note: this logic should be thought through.
|
||||||
s_ppc_event.Wait();
|
m_ppc_event.Wait();
|
||||||
m_cycle_count.fetch_add(dsp_cycles);
|
m_cycle_count.fetch_add(dsp_cycles);
|
||||||
s_dsp_event.Set();
|
m_dsp_event.Set();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,8 +302,8 @@ void DSPLLE::PauseAndLock(bool do_lock, bool unpause_on_unlock)
|
||||||
if (m_is_dsp_on_thread)
|
if (m_is_dsp_on_thread)
|
||||||
{
|
{
|
||||||
// Signal the DSP thread so it can perform any outstanding work now (if any)
|
// Signal the DSP thread so it can perform any outstanding work now (if any)
|
||||||
s_ppc_event.Wait();
|
m_ppc_event.Wait();
|
||||||
s_dsp_event.Set();
|
m_dsp_event.Set();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/Flag.h"
|
#include "Common/Flag.h"
|
||||||
|
#include "Core/DSP/DSPCore.h"
|
||||||
#include "Core/DSPEmulator.h"
|
#include "Core/DSPEmulator.h"
|
||||||
|
|
||||||
class PointerWrap;
|
class PointerWrap;
|
||||||
|
@ -41,10 +42,15 @@ public:
|
||||||
private:
|
private:
|
||||||
static void DSPThread(DSPLLE* dsp_lle);
|
static void DSPThread(DSPLLE* dsp_lle);
|
||||||
|
|
||||||
|
DSPCore m_dsp_core;
|
||||||
std::thread m_dsp_thread;
|
std::thread m_dsp_thread;
|
||||||
std::mutex m_dsp_thread_mutex;
|
std::mutex m_dsp_thread_mutex;
|
||||||
bool m_is_dsp_on_thread = false;
|
bool m_is_dsp_on_thread = false;
|
||||||
Common::Flag m_is_running;
|
Common::Flag m_is_running;
|
||||||
std::atomic<u32> m_cycle_count{};
|
std::atomic<u32> m_cycle_count{};
|
||||||
|
|
||||||
|
Common::Event m_dsp_event;
|
||||||
|
Common::Event m_ppc_event;
|
||||||
|
bool m_request_disable_thread = false;
|
||||||
};
|
};
|
||||||
} // namespace DSP::LLE
|
} // namespace DSP::LLE
|
||||||
|
|
|
@ -69,7 +69,7 @@ Common::Symbol* DSPSymbolDB::GetSymbolFromAddr(u32 addr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutoDisassembly(u16 start_addr, u16 end_addr)
|
void AutoDisassembly(const SDSP& dsp, u16 start_addr, u16 end_addr)
|
||||||
{
|
{
|
||||||
AssemblerSettings settings;
|
AssemblerSettings settings;
|
||||||
settings.show_pc = true;
|
settings.show_pc = true;
|
||||||
|
@ -77,7 +77,7 @@ void AutoDisassembly(u16 start_addr, u16 end_addr)
|
||||||
DSPDisassembler disasm(settings);
|
DSPDisassembler disasm(settings);
|
||||||
|
|
||||||
u16 addr = start_addr;
|
u16 addr = start_addr;
|
||||||
const u16* ptr = (start_addr >> 15) ? g_dsp.irom : g_dsp.iram;
|
const u16* ptr = (start_addr >> 15) != 0 ? dsp.irom : dsp.iram;
|
||||||
while (addr < end_addr)
|
while (addr < end_addr)
|
||||||
{
|
{
|
||||||
line_to_addr[line_counter] = addr;
|
line_to_addr[line_counter] = addr;
|
||||||
|
|
|
@ -9,6 +9,11 @@
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/SymbolDB.h"
|
#include "Common/SymbolDB.h"
|
||||||
|
|
||||||
|
namespace DSP
|
||||||
|
{
|
||||||
|
struct SDSP;
|
||||||
|
}
|
||||||
|
|
||||||
namespace DSP::Symbols
|
namespace DSP::Symbols
|
||||||
{
|
{
|
||||||
class DSPSymbolDB : public Common::SymbolDB
|
class DSPSymbolDB : public Common::SymbolDB
|
||||||
|
@ -21,7 +26,7 @@ public:
|
||||||
|
|
||||||
extern DSPSymbolDB g_dsp_symbol_db;
|
extern DSPSymbolDB g_dsp_symbol_db;
|
||||||
|
|
||||||
void AutoDisassembly(u16 start_addr, u16 end_addr);
|
void AutoDisassembly(const SDSP& dsp, u16 start_addr, u16 end_addr);
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ static Common::Event g_compressAndDumpStateSyncEvent;
|
||||||
static std::thread g_save_thread;
|
static std::thread g_save_thread;
|
||||||
|
|
||||||
// Don't forget to increase this after doing changes on the savestate system
|
// Don't forget to increase this after doing changes on the savestate system
|
||||||
constexpr u32 STATE_VERSION = 125; // Last changed in PR 8867
|
constexpr u32 STATE_VERSION = 126; // Last changed in PR 9348
|
||||||
|
|
||||||
// Maps savestate versions to Dolphin versions.
|
// Maps savestate versions to Dolphin versions.
|
||||||
// Versions after 42 don't need to be added to this list,
|
// Versions after 42 don't need to be added to this list,
|
||||||
|
|
|
@ -39,10 +39,10 @@ bool DSP::Host::IsWiiHost()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
void DSP::Host::CodeLoaded(u32 addr, size_t size)
|
void DSP::Host::CodeLoaded(DSPCore& dsp, u32 addr, size_t size)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
void DSP::Host::CodeLoaded(const u8* ptr, size_t size)
|
void DSP::Host::CodeLoaded(DSPCore& dsp, const u8* ptr, size_t size)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
void DSP::Host::InterruptRequest()
|
void DSP::Host::InterruptRequest()
|
||||||
|
|
Loading…
Reference in New Issue