DSP: Eliminate most global state

An unfortunately large single commit that deglobalizes the DSP code.
(which I'm very sorry about).

This would have otherwise been extremely difficult to separate due to
extensive use of the globals in very coupling ways that would result in
more scaffolding to work around than is worth it.

Aside from the video code, I believe only the DSP code is the hairiest
to deal with in terms of globals, so I guess it's best to get this dealt
with right off the bat.

A summary of what this commit does:
  - Turns the DSPInterpreter into its own class
    This is the most involved portion of this change.
    The bulk of the changes are turning non-member functions into member
    functions that would be situated into the Interpreter class.

  - Eliminates all usages to globals within DSPCore.
    This generally involves turning a lot of non-member functions into
    member functions that are either situated within SDSP or DSPCore.

  - Discards DSPDebugInterface (it wasn't hooked up to anything,
    and for the sake of eliminating global state, I'd rather get rid of
    it than think up ways for this class to be integrated with
    everything else.

  - Readjusts the DSP JIT to handle calling out to member functions.
    In most cases, this just means wrapping respective member function
    calles into thunk functions.

Surprisingly, this doesn't even make use of the introduced System class.
It was possible all along to do this without it. We can house everything
within the DSPLLE class, which is quite nice =)
This commit is contained in:
Lioncash 2020-12-21 09:22:06 -05:00
parent 2917af03ec
commit 7d1bd565a6
50 changed files with 3037 additions and 3164 deletions

View File

@ -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)
{ {

View File

@ -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

View File

@ -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" />

View File

@ -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>

View File

@ -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)

View File

@ -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);

View File

@ -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 DSPCore& core)
{ {
struct DspRomHashes struct DspRomHashes
{ {
@ -64,8 +59,11 @@ static bool VerifyRoms()
{0x128ea7a2, 0xa4a575f5}, {0x128ea7a2, 0xa4a575f5},
}}; }};
const u32 hash_irom = Common::HashAdler32(reinterpret_cast<u8*>(g_dsp.irom), DSP_IROM_BYTE_SIZE); const auto& state = core.DSPState();
const u32 hash_drom = Common::HashAdler32(reinterpret_cast<u8*>(g_dsp.coef), DSP_COEF_BYTE_SIZE); const u32 hash_irom =
Common::HashAdler32(reinterpret_cast<const u8*>(state.irom), DSP_IROM_BYTE_SIZE);
const u32 hash_drom =
Common::HashAdler32(reinterpret_cast<const u8*>(state.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 +102,228 @@ 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(DSPCore& core) : m_core{core} {}
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_core.SetException(ExceptionType::AcceleratorOverflow); }
private:
DSPCore& m_core;
}; };
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)); DSPCore::DSPCore()
g_dsp.iram = static_cast<u16*>(Common::AllocateMemoryPages(DSP_IRAM_BYTE_SIZE)); : m_dsp{*this}, m_dsp_interpreter{std::make_unique<Interpreter::Interpreter>(*this)}
g_dsp.dram = static_cast<u16*>(Common::AllocateMemoryPages(DSP_DRAM_BYTE_SIZE)); {
g_dsp.coef = static_cast<u16*>(Common::AllocateMemoryPages(DSP_COEF_BYTE_SIZE)); }
memcpy(g_dsp.irom, opts.irom_contents.data(), DSP_IROM_BYTE_SIZE); DSPCore::~DSPCore() = default;
memcpy(g_dsp.coef, opts.coef_contents.data(), DSP_COEF_BYTE_SIZE);
bool DSPCore::Initialize(const DSPInitOptions& opts)
{
m_dsp.step_counter = 0;
m_init_hax = false;
m_dsp.accelerator = std::make_unique<LLEAccelerator>(*this);
m_dsp.irom = static_cast<u16*>(Common::AllocateMemoryPages(DSP_IROM_BYTE_SIZE));
m_dsp.iram = static_cast<u16*>(Common::AllocateMemoryPages(DSP_IRAM_BYTE_SIZE));
m_dsp.dram = static_cast<u16*>(Common::AllocateMemoryPages(DSP_DRAM_BYTE_SIZE));
m_dsp.coef = static_cast<u16*>(Common::AllocateMemoryPages(DSP_COEF_BYTE_SIZE));
std::memcpy(m_dsp.irom, opts.irom_contents.data(), DSP_IROM_BYTE_SIZE);
std::memcpy(m_dsp.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(&m_dsp.r, 0, sizeof(m_dsp.r));
std::fill(std::begin(g_dsp.reg_stack_ptrs), std::end(g_dsp.reg_stack_ptrs), 0); std::fill(std::begin(m_dsp.reg_stack_ptrs), std::end(m_dsp.reg_stack_ptrs), 0);
for (auto& stack : g_dsp.reg_stacks) for (auto& stack : m_dsp.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(m_dsp.iram, m_dsp.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(m_dsp.dram, m_dsp.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(m_dsp.r.wr), std::end(m_dsp.r.wr), 0xffff);
g_dsp.r.sr |= SR_INT_ENABLE; m_dsp.r.sr |= SR_INT_ENABLE;
g_dsp.r.sr |= SR_EXT_INT_ENABLE; m_dsp.r.sr |= SR_EXT_INT_ENABLE;
g_dsp.cr = 0x804; m_dsp.cr = 0x804;
gdsp_ifx_init(); m_dsp.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(m_dsp.iram, DSP_IRAM_BYTE_SIZE, false);
// Initialize JIT, if necessary // Initialize JIT, if necessary
if (opts.core_type == DSPInitOptions::CoreType::JIT64) if (opts.core_type == DSPInitOptions::CoreType::JIT64)
g_dsp_jit = JIT::CreateDSPEmitter(); m_dsp_jit = JIT::CreateDSPEmitter(*this);
g_dsp_cap.reset(opts.capture_logger); m_dsp_cap.reset(opts.capture_logger);
core_state = State::Running; m_core_state = State::Running;
return true; return true;
} }
void DSPCore_Shutdown() void DSPCore::Shutdown()
{ {
if (core_state == State::Stopped) if (m_core_state == State::Stopped)
return; return;
core_state = State::Stopped; m_core_state = State::Stopped;
g_dsp_jit.reset(); m_dsp_jit.reset();
DSPCore_FreeMemoryPages(); FreeMemoryPages();
g_dsp_cap.reset(); m_dsp_cap.reset();
} }
void DSPCore_Reset() // Delegate to JIT or interpreter as appropriate.
// Handle state changes and stepping.
int DSPCore::RunCycles(int cycles)
{ {
g_dsp.pc = DSP_RESET_VECTOR; if (m_dsp_jit)
{
return m_dsp_jit->RunCycles(static_cast<u16>(cycles));
}
std::fill(std::begin(g_dsp.r.wr), std::end(g_dsp.r.wr), 0xffff); while (cycles > 0)
{
switch (m_core_state)
{
case State::Running:
// Seems to slow things down
#if defined(_DEBUG) || defined(DEBUGFAST)
cycles = m_dsp_interpreter->RunCyclesDebug(cycles);
#else
cycles = m_dsp_interpreter->RunCycles(cycles);
#endif
break;
Analyzer::Analyze(); case State::Stepping:
m_step_event.Wait();
if (m_core_state != State::Stepping)
continue;
m_dsp_interpreter->Step();
cycles--;
Host::UpdateDebugger();
break;
case State::Stopped:
break;
}
}
return cycles;
} }
void DSPCore_SetException(ExceptionType exception) void DSPCore::Step()
{ {
g_dsp.exceptions |= 1 << static_cast<std::underlying_type_t<ExceptionType>>(exception); if (m_core_state == State::Stepping)
m_step_event.Set();
} }
// Notify that an external interrupt is pending (used by thread mode) void DSPCore::Reset()
void DSPCore_SetExternalInterrupt(bool val)
{ {
g_dsp.external_interrupt_waiting = val; m_dsp.pc = DSP_RESET_VECTOR;
std::fill(std::begin(m_dsp.r.wr), std::end(m_dsp.r.wr), 0xffff);
Analyzer::Analyze(m_dsp);
} }
// Coming from the CPU void DSPCore::ClearIRAM()
void DSPCore_CheckExternalInterrupt()
{ {
if (!Interpreter::dsp_SR_is_flag_set(SR_EXT_INT_ENABLE)) 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
if (new_state == State::Running)
m_step_event.Set();
Host::UpdateDebugger();
}
State DSPCore::GetState() const
{
return m_core_state;
}
void DSPCore::SetException(ExceptionType exception)
{
m_dsp.exceptions |= 1 << static_cast<std::underlying_type_t<ExceptionType>>(exception);
}
void DSPCore::SetExternalInterrupt(bool val)
{
m_dsp.external_interrupt_waiting = val;
}
void DSPCore::CheckExternalInterrupt()
{
if (!m_dsp.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; m_dsp.cr &= ~CR_EXTERNAL_INT;
} }
void DSPCore_CheckExceptions() void DSPCore::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 (m_dsp.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 ((m_dsp.exceptions & (1U << i)) != 0)
{ {
if (Interpreter::dsp_SR_is_flag_set(SR_INT_ENABLE) || if (m_dsp.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); m_dsp.StoreStack(StackRegister::Call, m_dsp.pc);
dsp_reg_store_stack(StackRegister::Data, g_dsp.r.sr); m_dsp.StoreStack(StackRegister::Data, m_dsp.r.sr);
g_dsp.pc = i * 2; m_dsp.pc = static_cast<u16>(i * 2);
g_dsp.exceptions &= ~(1 << i); m_dsp.exceptions &= ~(1 << i);
if (i == 7) if (i == 7)
g_dsp.r.sr &= ~SR_EXT_INT_ENABLE; m_dsp.r.sr &= ~SR_EXT_INT_ENABLE;
else else
g_dsp.r.sr &= ~SR_INT_ENABLE; m_dsp.r.sr &= ~SR_INT_ENABLE;
break; break;
} }
else else
@ -261,68 +336,7 @@ void DSPCore_CheckExceptions()
} }
} }
// Delegate to JIT or interpreter as appropriate. u16 DSPCore::ReadRegister(size_t reg) const
// Handle state changes and stepping.
int DSPCore_RunCycles(int cycles)
{
if (g_dsp_jit)
{
return g_dsp_jit->RunCycles(static_cast<u16>(cycles));
}
while (cycles > 0)
{
switch (core_state)
{
case State::Running:
// Seems to slow things down
#if defined(_DEBUG) || defined(DEBUGFAST)
cycles = Interpreter::RunCyclesDebug(cycles);
#else
cycles = Interpreter::RunCycles(cycles);
#endif
break;
case State::Stepping:
step_event.Wait();
if (core_state != State::Stepping)
continue;
Interpreter::Step();
cycles--;
Host::UpdateDebugger();
break;
case State::Stopped:
break;
}
}
return cycles;
}
void DSPCore_SetState(State new_state)
{
core_state = new_state;
// kick the event, in case we are waiting
if (new_state == State::Running)
step_event.Set();
Host::UpdateDebugger();
}
State DSPCore_GetState()
{
return core_state;
}
void DSPCore_Step()
{
if (core_state == State::Stepping)
step_event.Set();
}
u16 DSPCore_ReadRegister(size_t reg)
{ {
switch (reg) switch (reg)
{ {
@ -330,56 +344,56 @@ u16 DSPCore_ReadRegister(size_t reg)
case DSP_REG_AR1: case DSP_REG_AR1:
case DSP_REG_AR2: case DSP_REG_AR2:
case DSP_REG_AR3: case DSP_REG_AR3:
return g_dsp.r.ar[reg - DSP_REG_AR0]; return m_dsp.r.ar[reg - DSP_REG_AR0];
case DSP_REG_IX0: case DSP_REG_IX0:
case DSP_REG_IX1: case DSP_REG_IX1:
case DSP_REG_IX2: case DSP_REG_IX2:
case DSP_REG_IX3: case DSP_REG_IX3:
return g_dsp.r.ix[reg - DSP_REG_IX0]; return m_dsp.r.ix[reg - DSP_REG_IX0];
case DSP_REG_WR0: case DSP_REG_WR0:
case DSP_REG_WR1: case DSP_REG_WR1:
case DSP_REG_WR2: case DSP_REG_WR2:
case DSP_REG_WR3: case DSP_REG_WR3:
return g_dsp.r.wr[reg - DSP_REG_WR0]; return m_dsp.r.wr[reg - DSP_REG_WR0];
case DSP_REG_ST0: case DSP_REG_ST0:
case DSP_REG_ST1: case DSP_REG_ST1:
case DSP_REG_ST2: case DSP_REG_ST2:
case DSP_REG_ST3: case DSP_REG_ST3:
return g_dsp.r.st[reg - DSP_REG_ST0]; return m_dsp.r.st[reg - DSP_REG_ST0];
case DSP_REG_ACH0: case DSP_REG_ACH0:
case DSP_REG_ACH1: case DSP_REG_ACH1:
return g_dsp.r.ac[reg - DSP_REG_ACH0].h; return m_dsp.r.ac[reg - DSP_REG_ACH0].h;
case DSP_REG_CR: case DSP_REG_CR:
return g_dsp.r.cr; return m_dsp.r.cr;
case DSP_REG_SR: case DSP_REG_SR:
return g_dsp.r.sr; return m_dsp.r.sr;
case DSP_REG_PRODL: case DSP_REG_PRODL:
return g_dsp.r.prod.l; return m_dsp.r.prod.l;
case DSP_REG_PRODM: case DSP_REG_PRODM:
return g_dsp.r.prod.m; return m_dsp.r.prod.m;
case DSP_REG_PRODH: case DSP_REG_PRODH:
return g_dsp.r.prod.h; return m_dsp.r.prod.h;
case DSP_REG_PRODM2: case DSP_REG_PRODM2:
return g_dsp.r.prod.m2; return m_dsp.r.prod.m2;
case DSP_REG_AXL0: case DSP_REG_AXL0:
case DSP_REG_AXL1: case DSP_REG_AXL1:
return g_dsp.r.ax[reg - DSP_REG_AXL0].l; return m_dsp.r.ax[reg - DSP_REG_AXL0].l;
case DSP_REG_AXH0: case DSP_REG_AXH0:
case DSP_REG_AXH1: case DSP_REG_AXH1:
return g_dsp.r.ax[reg - DSP_REG_AXH0].h; return m_dsp.r.ax[reg - DSP_REG_AXH0].h;
case DSP_REG_ACL0: case DSP_REG_ACL0:
case DSP_REG_ACL1: case DSP_REG_ACL1:
return g_dsp.r.ac[reg - DSP_REG_ACL0].l; return m_dsp.r.ac[reg - DSP_REG_ACL0].l;
case DSP_REG_ACM0: case DSP_REG_ACM0:
case DSP_REG_ACM1: case DSP_REG_ACM1:
return g_dsp.r.ac[reg - DSP_REG_ACM0].m; return m_dsp.r.ac[reg - DSP_REG_ACM0].m;
default: default:
ASSERT_MSG(DSP_CORE, 0, "cannot happen"); ASSERT_MSG(DSP_CORE, 0, "cannot happen");
return 0; return 0;
} }
} }
void DSPCore_WriteRegister(size_t reg, u16 val) void DSPCore::WriteRegister(size_t reg, u16 val)
{ {
switch (reg) switch (reg)
{ {
@ -387,64 +401,154 @@ void DSPCore_WriteRegister(size_t reg, u16 val)
case DSP_REG_AR1: case DSP_REG_AR1:
case DSP_REG_AR2: case DSP_REG_AR2:
case DSP_REG_AR3: case DSP_REG_AR3:
g_dsp.r.ar[reg - DSP_REG_AR0] = val; m_dsp.r.ar[reg - DSP_REG_AR0] = val;
break; break;
case DSP_REG_IX0: case DSP_REG_IX0:
case DSP_REG_IX1: case DSP_REG_IX1:
case DSP_REG_IX2: case DSP_REG_IX2:
case DSP_REG_IX3: case DSP_REG_IX3:
g_dsp.r.ix[reg - DSP_REG_IX0] = val; m_dsp.r.ix[reg - DSP_REG_IX0] = val;
break; break;
case DSP_REG_WR0: case DSP_REG_WR0:
case DSP_REG_WR1: case DSP_REG_WR1:
case DSP_REG_WR2: case DSP_REG_WR2:
case DSP_REG_WR3: case DSP_REG_WR3:
g_dsp.r.wr[reg - DSP_REG_WR0] = val; m_dsp.r.wr[reg - DSP_REG_WR0] = val;
break; break;
case DSP_REG_ST0: case DSP_REG_ST0:
case DSP_REG_ST1: case DSP_REG_ST1:
case DSP_REG_ST2: case DSP_REG_ST2:
case DSP_REG_ST3: case DSP_REG_ST3:
g_dsp.r.st[reg - DSP_REG_ST0] = val; m_dsp.r.st[reg - DSP_REG_ST0] = val;
break; break;
case DSP_REG_ACH0: case DSP_REG_ACH0:
case DSP_REG_ACH1: case DSP_REG_ACH1:
g_dsp.r.ac[reg - DSP_REG_ACH0].h = val; m_dsp.r.ac[reg - DSP_REG_ACH0].h = val;
break; break;
case DSP_REG_CR: case DSP_REG_CR:
g_dsp.r.cr = val; m_dsp.r.cr = val;
break; break;
case DSP_REG_SR: case DSP_REG_SR:
g_dsp.r.sr = val; m_dsp.r.sr = val;
break; break;
case DSP_REG_PRODL: case DSP_REG_PRODL:
g_dsp.r.prod.l = val; m_dsp.r.prod.l = val;
break; break;
case DSP_REG_PRODM: case DSP_REG_PRODM:
g_dsp.r.prod.m = val; m_dsp.r.prod.m = val;
break; break;
case DSP_REG_PRODH: case DSP_REG_PRODH:
g_dsp.r.prod.h = val; m_dsp.r.prod.h = val;
break; break;
case DSP_REG_PRODM2: case DSP_REG_PRODM2:
g_dsp.r.prod.m2 = val; m_dsp.r.prod.m2 = val;
break; break;
case DSP_REG_AXL0: case DSP_REG_AXL0:
case DSP_REG_AXL1: case DSP_REG_AXL1:
g_dsp.r.ax[reg - DSP_REG_AXL0].l = val; m_dsp.r.ax[reg - DSP_REG_AXL0].l = val;
break; break;
case DSP_REG_AXH0: case DSP_REG_AXH0:
case DSP_REG_AXH1: case DSP_REG_AXH1:
g_dsp.r.ax[reg - DSP_REG_AXH0].h = val; m_dsp.r.ax[reg - DSP_REG_AXH0].h = val;
break; break;
case DSP_REG_ACL0: case DSP_REG_ACL0:
case DSP_REG_ACL1: case DSP_REG_ACL1:
g_dsp.r.ac[reg - DSP_REG_ACL0].l = val; m_dsp.r.ac[reg - DSP_REG_ACL0].l = val;
break; break;
case DSP_REG_ACM0: case DSP_REG_ACM0:
case DSP_REG_ACM1: case DSP_REG_ACM1:
g_dsp.r.ac[reg - DSP_REG_ACM0].m = val; m_dsp.r.ac[reg - DSP_REG_ACM0].m = val;
break; break;
} }
} }
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)
{
p.Do(m_dsp.r);
p.Do(m_dsp.pc);
p.Do(m_dsp.cr);
p.Do(m_dsp.reg_stack_ptrs);
p.Do(m_dsp.exceptions);
p.Do(m_dsp.external_interrupt_waiting);
for (auto& stack : m_dsp.reg_stacks)
{
p.Do(stack);
}
p.Do(m_dsp.step_counter);
p.DoArray(m_dsp.ifx_regs);
m_dsp.accelerator->DoState(p);
p.Do(m_dsp.mbox[0]);
p.Do(m_dsp.mbox[1]);
Common::UnWriteProtectMemory(m_dsp.iram, DSP_IRAM_BYTE_SIZE, false);
p.DoArray(m_dsp.iram, DSP_IRAM_SIZE);
Common::WriteProtectMemory(m_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(*this, reinterpret_cast<const u8*>(m_dsp.iram), DSP_IRAM_BYTE_SIZE);
p.DoArray(m_dsp.dram, DSP_DRAM_SIZE);
p.Do(m_init_hax);
if (m_dsp_jit)
m_dsp_jit->DoState(p);
}
void DSPCore::FreeMemoryPages()
{
Common::FreeMemoryPages(m_dsp.irom, DSP_IROM_BYTE_SIZE);
Common::FreeMemoryPages(m_dsp.iram, DSP_IRAM_BYTE_SIZE);
Common::FreeMemoryPages(m_dsp.dram, DSP_DRAM_BYTE_SIZE);
Common::FreeMemoryPages(m_dsp.coef, DSP_COEF_BYTE_SIZE);
m_dsp.irom = nullptr;
m_dsp.iram = nullptr;
m_dsp.dram = nullptr;
m_dsp.coef = nullptr;
}
} // namespace DSP } // namespace DSP

View File

@ -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];
@ -263,22 +278,82 @@ struct DSP_Regs
// should be moved here. // should be moved here.
struct SDSP struct SDSP
{ {
DSP_Regs r; explicit SDSP(DSPCore& core);
u16 pc; ~SDSP();
#if PROFILE
u16 err_pc; SDSP(const SDSP&) = delete;
#endif SDSP& operator=(const SDSP&) = delete;
SDSP(SDSP&&) = delete;
SDSP& operator=(SDSP&&) = delete;
// 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; }
// 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);
DSP_Regs r{};
u16 pc = 0;
// This is NOT the same cr as r.cr. // This is NOT the same cr as r.cr.
// This register is shared with the main emulation, see DSP.cpp // This register is shared with the main emulation, see DSP.cpp
// The engine has control over 0x0C07 of this reg. // The engine has control over 0x0C07 of this reg.
// Bits are defined in a struct in DSP.cpp. // Bits are defined in a struct in DSP.cpp.
u16 cr; u16 cr = 0;
u8 reg_stack_ptrs[4]; u8 reg_stack_ptrs[4]{};
u8 exceptions; // pending exceptions u8 exceptions = 0; // pending exceptions
volatile bool external_interrupt_waiting; volatile bool external_interrupt_waiting = false;
bool reset_dspjit_codespace; bool reset_dspjit_codespace = false;
// DSP hardware stacks. They're mapped to a bunch of registers, such that writes // DSP hardware stacks. They're mapped to a bunch of registers, such that writes
// to them push and reads pop. // to them push and reads pop.
@ -286,33 +361,38 @@ struct SDSP
// The real DSP has different depths for the different stacks, but it would // 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 // be strange if any ucode relied on stack overflows since on the DSP, when
// the stack overflows, you're screwed. // the stack overflows, you're screwed.
u16 reg_stacks[4][DSP_STACK_DEPTH]; u16 reg_stacks[4][DSP_STACK_DEPTH]{};
// For debugging. // For debugging.
u32 iram_crc; u32 iram_crc = 0;
u64 step_counter; u64 step_counter = 0;
// Mailbox. // Mailbox.
std::atomic<u32> mbox[2]; std::atomic<u32> mbox[2];
// Accelerator / DMA / other hardware registers. Not GPRs. // Accelerator / DMA / other hardware registers. Not GPRs.
std::array<u16, 256> ifx_regs; std::array<u16, 256> ifx_regs{};
std::unique_ptr<Accelerator> accelerator; std::unique_ptr<Accelerator> accelerator;
// When state saving, all of the above can just be memcpy'd into the save state. // When state saving, all of the above can just be memcpy'd into the save state.
// The below needs special handling. // The below needs special handling.
u16* iram; u16* iram = nullptr;
u16* dram; u16* dram = nullptr;
u16* irom; u16* irom = nullptr;
u16* coef; u16* coef = nullptr;
};
extern SDSP g_dsp; private:
extern DSPBreakpoints g_dsp_breakpoints; void DoDMA();
extern bool g_init_hax; const u8* DDMAIn(u16 dsp_addr, u32 addr, u32 size);
extern std::unique_ptr<JIT::DSPEmitter> g_dsp_jit; const u8* DDMAOut(u16 dsp_addr, u32 addr, u32 size);
extern std::unique_ptr<DSPCaptureLogger> g_dsp_cap; 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;
};
struct DSPInitOptions struct DSPInitOptions
{ {
@ -338,20 +418,6 @@ 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 pointers contained in the options structure.
bool DSPCore_Init(const DSPInitOptions& opts);
void DSPCore_Reset();
void DSPCore_Shutdown(); // Frees all allocated memory.
void DSPCore_CheckExternalInterrupt();
void DSPCore_CheckExceptions();
void DSPCore_SetExternalInterrupt(bool val);
// sets a flag in the pending exception register.
void DSPCore_SetException(ExceptionType exception);
enum class State enum class State
{ {
Stopped, Stopped,
@ -359,14 +425,117 @@ 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:
void FreeMemoryPages();
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

View File

@ -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);
const u32 new_value = (old_value & ~0xffff) | val;
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; m_dsp_core.SetInitHax(false);
} m_dsp_core.Reset();
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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.
dsp_skip_inst(); // skip the next opcode - we have to lookup its size.
} 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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())

View File

@ -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);

View File

@ -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

View File

@ -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)

View File

@ -4,144 +4,248 @@
#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;
// If these simply return the same number of cycles as was passed into them, Interpreter(Interpreter&&) = delete;
// chances are that the DSP is halted. Interpreter& operator=(Interpreter&&) = delete;
// The difference between them is that the debug one obeys breakpoints.
int RunCyclesThread(int cycles);
int RunCycles(int cycles);
int RunCyclesDebug(int cycles);
void WriteCR(u16 val); void Step();
u16 ReadCR();
// All the opcode functions. // If these simply return the same number of cycles as was passed into them,
void abs(UDSPInstruction opc); // chances are that the DSP is halted.
void add(UDSPInstruction opc); // The difference between them is that the debug one obeys breakpoints.
void addarn(UDSPInstruction opc); int RunCyclesThread(int cycles);
void addax(UDSPInstruction opc); int RunCycles(int cycles);
void addaxl(UDSPInstruction opc); int RunCyclesDebug(int cycles);
void addi(UDSPInstruction opc);
void addis(UDSPInstruction opc);
void addp(UDSPInstruction opc);
void addpaxz(UDSPInstruction opc);
void addr(UDSPInstruction opc);
void andc(UDSPInstruction opc);
void andcf(UDSPInstruction opc);
void andf(UDSPInstruction opc);
void andi(UDSPInstruction opc);
void andr(UDSPInstruction opc);
void asl(UDSPInstruction opc);
void asr(UDSPInstruction opc);
void asr16(UDSPInstruction opc);
void asrn(UDSPInstruction opc);
void asrnr(UDSPInstruction opc);
void asrnrx(UDSPInstruction opc);
void bloop(UDSPInstruction opc);
void bloopi(UDSPInstruction opc);
void call(UDSPInstruction opc);
void callr(UDSPInstruction opc);
void clr(UDSPInstruction opc);
void clrl(UDSPInstruction opc);
void clrp(UDSPInstruction opc);
void cmp(UDSPInstruction opc);
void cmpar(UDSPInstruction opc);
void cmpi(UDSPInstruction opc);
void cmpis(UDSPInstruction opc);
void dar(UDSPInstruction opc);
void dec(UDSPInstruction opc);
void decm(UDSPInstruction opc);
void halt(UDSPInstruction opc);
void iar(UDSPInstruction opc);
void ifcc(UDSPInstruction opc);
void ilrr(UDSPInstruction opc);
void ilrrd(UDSPInstruction opc);
void ilrri(UDSPInstruction opc);
void ilrrn(UDSPInstruction opc);
void inc(UDSPInstruction opc);
void incm(UDSPInstruction opc);
void jcc(UDSPInstruction opc);
void jmprcc(UDSPInstruction opc);
void loop(UDSPInstruction opc);
void loopi(UDSPInstruction opc);
void lr(UDSPInstruction opc);
void lri(UDSPInstruction opc);
void lris(UDSPInstruction opc);
void lrr(UDSPInstruction opc);
void lrrd(UDSPInstruction opc);
void lrri(UDSPInstruction opc);
void lrrn(UDSPInstruction opc);
void lrs(UDSPInstruction opc);
void lsl(UDSPInstruction opc);
void lsl16(UDSPInstruction opc);
void lsr(UDSPInstruction opc);
void lsr16(UDSPInstruction opc);
void lsrn(UDSPInstruction opc);
void lsrnr(UDSPInstruction opc);
void lsrnrx(UDSPInstruction opc);
void madd(UDSPInstruction opc);
void maddc(UDSPInstruction opc);
void maddx(UDSPInstruction opc);
void mov(UDSPInstruction opc);
void movax(UDSPInstruction opc);
void movnp(UDSPInstruction opc);
void movp(UDSPInstruction opc);
void movpz(UDSPInstruction opc);
void movr(UDSPInstruction opc);
void mrr(UDSPInstruction opc);
void msub(UDSPInstruction opc);
void msubc(UDSPInstruction opc);
void msubx(UDSPInstruction opc);
void mul(UDSPInstruction opc);
void mulac(UDSPInstruction opc);
void mulaxh(UDSPInstruction opc);
void mulc(UDSPInstruction opc);
void mulcac(UDSPInstruction opc);
void mulcmv(UDSPInstruction opc);
void mulcmvz(UDSPInstruction opc);
void mulmv(UDSPInstruction opc);
void mulmvz(UDSPInstruction opc);
void mulx(UDSPInstruction opc);
void mulxac(UDSPInstruction opc);
void mulxmv(UDSPInstruction opc);
void mulxmvz(UDSPInstruction opc);
void neg(UDSPInstruction opc);
void nop(UDSPInstruction opc);
void notc(UDSPInstruction opc);
void nx(UDSPInstruction opc);
void orc(UDSPInstruction opc);
void ori(UDSPInstruction opc);
void orr(UDSPInstruction opc);
void ret(UDSPInstruction opc);
void rti(UDSPInstruction opc);
void sbclr(UDSPInstruction opc);
void sbset(UDSPInstruction opc);
void si(UDSPInstruction opc);
void sr(UDSPInstruction opc);
void srbith(UDSPInstruction opc);
void srr(UDSPInstruction opc);
void srrd(UDSPInstruction opc);
void srri(UDSPInstruction opc);
void srrn(UDSPInstruction opc);
void srs(UDSPInstruction opc);
void sub(UDSPInstruction opc);
void subarn(UDSPInstruction opc);
void subax(UDSPInstruction opc);
void subp(UDSPInstruction opc);
void subr(UDSPInstruction opc);
void tst(UDSPInstruction opc);
void tstaxh(UDSPInstruction opc);
void tstprod(UDSPInstruction opc);
void xorc(UDSPInstruction opc);
void xori(UDSPInstruction opc);
void xorr(UDSPInstruction opc);
void WriteCR(u16 val);
u16 ReadCR();
void SetSRFlag(u16 flag);
bool IsSRFlagSet(u16 flag) const;
void ApplyWriteBackLog();
// All the opcode functions.
void abs(UDSPInstruction opc);
void add(UDSPInstruction opc);
void addarn(UDSPInstruction opc);
void addax(UDSPInstruction opc);
void addaxl(UDSPInstruction opc);
void addi(UDSPInstruction opc);
void addis(UDSPInstruction opc);
void addp(UDSPInstruction opc);
void addpaxz(UDSPInstruction opc);
void addr(UDSPInstruction opc);
void andc(UDSPInstruction opc);
void andcf(UDSPInstruction opc);
void andf(UDSPInstruction opc);
void andi(UDSPInstruction opc);
void andr(UDSPInstruction opc);
void asl(UDSPInstruction opc);
void asr(UDSPInstruction opc);
void asr16(UDSPInstruction opc);
void asrn(UDSPInstruction opc);
void asrnr(UDSPInstruction opc);
void asrnrx(UDSPInstruction opc);
void bloop(UDSPInstruction opc);
void bloopi(UDSPInstruction opc);
void call(UDSPInstruction opc);
void callr(UDSPInstruction opc);
void clr(UDSPInstruction opc);
void clrl(UDSPInstruction opc);
void clrp(UDSPInstruction opc);
void cmp(UDSPInstruction opc);
void cmpar(UDSPInstruction opc);
void cmpi(UDSPInstruction opc);
void cmpis(UDSPInstruction opc);
void dar(UDSPInstruction opc);
void dec(UDSPInstruction opc);
void decm(UDSPInstruction opc);
void halt(UDSPInstruction opc);
void iar(UDSPInstruction opc);
void ifcc(UDSPInstruction opc);
void ilrr(UDSPInstruction opc);
void ilrrd(UDSPInstruction opc);
void ilrri(UDSPInstruction opc);
void ilrrn(UDSPInstruction opc);
void inc(UDSPInstruction opc);
void incm(UDSPInstruction opc);
void jcc(UDSPInstruction opc);
void jmprcc(UDSPInstruction opc);
void loop(UDSPInstruction opc);
void loopi(UDSPInstruction opc);
void lr(UDSPInstruction opc);
void lri(UDSPInstruction opc);
void lris(UDSPInstruction opc);
void lrr(UDSPInstruction opc);
void lrrd(UDSPInstruction opc);
void lrri(UDSPInstruction opc);
void lrrn(UDSPInstruction opc);
void lrs(UDSPInstruction opc);
void lsl(UDSPInstruction opc);
void lsl16(UDSPInstruction opc);
void lsr(UDSPInstruction opc);
void lsr16(UDSPInstruction opc);
void lsrn(UDSPInstruction opc);
void lsrnr(UDSPInstruction opc);
void lsrnrx(UDSPInstruction opc);
void madd(UDSPInstruction opc);
void maddc(UDSPInstruction opc);
void maddx(UDSPInstruction opc);
void mov(UDSPInstruction opc);
void movax(UDSPInstruction opc);
void movnp(UDSPInstruction opc);
void movp(UDSPInstruction opc);
void movpz(UDSPInstruction opc);
void movr(UDSPInstruction opc);
void mrr(UDSPInstruction opc);
void msub(UDSPInstruction opc);
void msubc(UDSPInstruction opc);
void msubx(UDSPInstruction opc);
void mul(UDSPInstruction opc);
void mulac(UDSPInstruction opc);
void mulaxh(UDSPInstruction opc);
void mulc(UDSPInstruction opc);
void mulcac(UDSPInstruction opc);
void mulcmv(UDSPInstruction opc);
void mulcmvz(UDSPInstruction opc);
void mulmv(UDSPInstruction opc);
void mulmvz(UDSPInstruction opc);
void mulx(UDSPInstruction opc);
void mulxac(UDSPInstruction opc);
void mulxmv(UDSPInstruction opc);
void mulxmvz(UDSPInstruction opc);
void neg(UDSPInstruction opc);
void nop(UDSPInstruction opc);
void notc(UDSPInstruction opc);
void nx(UDSPInstruction opc);
void orc(UDSPInstruction opc);
void ori(UDSPInstruction opc);
void orr(UDSPInstruction opc);
void ret(UDSPInstruction opc);
void rti(UDSPInstruction opc);
void sbclr(UDSPInstruction opc);
void sbset(UDSPInstruction opc);
void si(UDSPInstruction opc);
void sr(UDSPInstruction opc);
void srbith(UDSPInstruction opc);
void srr(UDSPInstruction opc);
void srrd(UDSPInstruction opc);
void srri(UDSPInstruction opc);
void srrn(UDSPInstruction opc);
void srs(UDSPInstruction opc);
void sub(UDSPInstruction opc);
void subarn(UDSPInstruction opc);
void subax(UDSPInstruction opc);
void subp(UDSPInstruction opc);
void subr(UDSPInstruction opc);
void tst(UDSPInstruction opc);
void tstaxh(UDSPInstruction opc);
void tstprod(UDSPInstruction opc);
void xorc(UDSPInstruction opc);
void xori(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

View File

@ -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

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -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;

View File

@ -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();
} }
} }

View File

@ -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);

View File

@ -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);
} }

View File

@ -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;

View File

@ -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);
} }
} }

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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();
s_ppc_event.Set(); m_is_running.Clear();
s_dsp_event.Set(); m_ppc_event.Set();
m_dsp_thread.join(); m_dsp_event.Set();
} 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();
} }
} }
} }

View File

@ -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

View File

@ -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;

View File

@ -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();

View File

@ -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,

View File

@ -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()