mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
Merge pull request #9348 from lioncash/dsp-deglobal
DSP: Eliminate most global state
This commit is contained in:
@@ -1096,6 +1096,13 @@ public:
|
||||
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>
|
||||
void ABI_CallFunctionPC(FunctionPointer func, const void* param1, u32 param2)
|
||||
{
|
||||
@@ -1122,6 +1129,15 @@ public:
|
||||
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.
|
||||
template <typename FunctionPointer>
|
||||
void ABI_CallFunctionRR(FunctionPointer func, X64Reg reg1, X64Reg reg2)
|
||||
@@ -1130,6 +1146,15 @@ public:
|
||||
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>
|
||||
void ABI_CallFunctionAC(int bits, FunctionPointer func, const Gen::OpArg& arg1, u32 param2)
|
||||
{
|
||||
|
||||
@@ -111,23 +111,18 @@ add_library(core
|
||||
DSP/DSPDisassembler.cpp
|
||||
DSP/DSPDisassembler.h
|
||||
DSP/DSPHWInterface.cpp
|
||||
DSP/DSPHWInterface.h
|
||||
DSP/DSPMemoryMap.cpp
|
||||
DSP/DSPMemoryMap.h
|
||||
DSP/DSPStacks.cpp
|
||||
DSP/DSPStacks.h
|
||||
DSP/DSPTables.cpp
|
||||
DSP/DSPTables.h
|
||||
DSP/LabelMap.cpp
|
||||
DSP/LabelMap.h
|
||||
DSP/Interpreter/DSPIntArithmetic.cpp
|
||||
DSP/Interpreter/DSPIntBranch.cpp
|
||||
DSP/Interpreter/DSPIntCCUtil.cpp
|
||||
DSP/Interpreter/DSPIntCCUtil.h
|
||||
DSP/Interpreter/DSPInterpreter.cpp
|
||||
DSP/Interpreter/DSPInterpreter.h
|
||||
DSP/Interpreter/DSPIntExtOps.cpp
|
||||
DSP/Interpreter/DSPIntExtOps.h
|
||||
DSP/Interpreter/DSPIntLoadStore.cpp
|
||||
DSP/Interpreter/DSPIntMisc.cpp
|
||||
DSP/Interpreter/DSPIntMultiplier.cpp
|
||||
@@ -186,8 +181,6 @@ add_library(core
|
||||
HW/DSPHLE/MailHandler.h
|
||||
HW/DSPHLE/DSPHLE.cpp
|
||||
HW/DSPHLE/DSPHLE.h
|
||||
HW/DSPLLE/DSPDebugInterface.cpp
|
||||
HW/DSPLLE/DSPDebugInterface.h
|
||||
HW/DSPLLE/DSPHost.cpp
|
||||
HW/DSPLLE/DSPSymbols.cpp
|
||||
HW/DSPLLE/DSPSymbols.h
|
||||
|
||||
@@ -58,7 +58,6 @@
|
||||
<ClCompile Include="DSP\DSPTables.cpp" />
|
||||
<ClCompile Include="DSP\Interpreter\DSPIntArithmetic.cpp" />
|
||||
<ClCompile Include="DSP\Interpreter\DSPIntBranch.cpp" />
|
||||
<ClCompile Include="DSP\Interpreter\DSPIntCCUtil.cpp" />
|
||||
<ClCompile Include="DSP\Interpreter\DSPInterpreter.cpp" />
|
||||
<ClCompile Include="DSP\Interpreter\DSPIntExtOps.cpp" />
|
||||
<ClCompile Include="DSP\Interpreter\DSPIntLoadStore.cpp" />
|
||||
@@ -107,7 +106,6 @@
|
||||
<ClCompile Include="HW\DSPHLE\UCodes\INIT.cpp" />
|
||||
<ClCompile Include="HW\DSPHLE\UCodes\ROM.cpp" />
|
||||
<ClCompile Include="HW\DSPHLE\UCodes\Zelda.cpp" />
|
||||
<ClCompile Include="HW\DSPLLE\DSPDebugInterface.cpp" />
|
||||
<ClCompile Include="HW\DSPLLE\DSPHost.cpp" />
|
||||
<ClCompile Include="HW\DSPLLE\DSPLLE.cpp" />
|
||||
<ClCompile Include="HW\DSPLLE\DSPLLEGlobals.cpp" />
|
||||
@@ -420,13 +418,9 @@
|
||||
<ClInclude Include="DSP\DSPCore.h" />
|
||||
<ClInclude Include="DSP\DSPDisassembler.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\Interpreter\DSPIntCCUtil.h" />
|
||||
<ClInclude Include="DSP\Interpreter\DSPInterpreter.h" />
|
||||
<ClInclude Include="DSP\Interpreter\DSPIntExtOps.h" />
|
||||
<ClInclude Include="DSP\Interpreter\DSPIntTables.h" />
|
||||
<ClInclude Include="DSP\Interpreter\DSPIntUtil.h" />
|
||||
<ClInclude Include="DSP\Jit\DSPEmitterBase.h" />
|
||||
@@ -466,7 +460,6 @@
|
||||
<ClInclude Include="HW\DSPHLE\UCodes\INIT.h" />
|
||||
<ClInclude Include="HW\DSPHLE\UCodes\ROM.h" />
|
||||
<ClInclude Include="HW\DSPHLE\UCodes\Zelda.h" />
|
||||
<ClInclude Include="HW\DSPLLE\DSPDebugInterface.h" />
|
||||
<ClInclude Include="HW\DSPLLE\DSPLLE.h" />
|
||||
<ClInclude Include="HW\DSPLLE\DSPLLEGlobals.h" />
|
||||
<ClInclude Include="HW\DSPLLE\DSPSymbols.h" />
|
||||
|
||||
@@ -233,9 +233,6 @@
|
||||
<ClCompile Include="DSP\Interpreter\DSPIntBranch.cpp">
|
||||
<Filter>DSPCore\Interpreter</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DSP\Interpreter\DSPIntCCUtil.cpp">
|
||||
<Filter>DSPCore\Interpreter</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DSP\Interpreter\DSPInterpreter.cpp">
|
||||
<Filter>DSPCore\Interpreter</Filter>
|
||||
</ClCompile>
|
||||
@@ -416,9 +413,6 @@
|
||||
<ClCompile Include="HW\DSPHLE\MailHandler.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\DSPLLE\DSPDebugInterface.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\LLE</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\DSPLLE\DSPHost.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\LLE</Filter>
|
||||
</ClCompile>
|
||||
@@ -1070,9 +1064,6 @@
|
||||
<ClInclude Include="DSP\Interpreter\DSPInterpreter.h">
|
||||
<Filter>DSPCore\Interpreter</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DSP\Interpreter\DSPIntExtOps.h">
|
||||
<Filter>DSPCore\Interpreter</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DSP\Interpreter\DSPIntTables.h">
|
||||
<Filter>DSPCore\Interpreter</Filter>
|
||||
</ClInclude>
|
||||
@@ -1199,9 +1190,6 @@
|
||||
<ClInclude Include="HW\DSPHLE\MailHandler.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\DSPLLE\DSPDebugInterface.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\LLE</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DSP\DSPHost.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\LLE</Filter>
|
||||
</ClInclude>
|
||||
@@ -1388,15 +1376,6 @@
|
||||
<ClInclude Include="DSPEmulator.h">
|
||||
<Filter>DSPCore</Filter>
|
||||
</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">
|
||||
<Filter>DSPCore</Filter>
|
||||
</ClInclude>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include "Common/Logging/Log.h"
|
||||
|
||||
#include "Core/DSP/DSPMemoryMap.h"
|
||||
#include "Core/DSP/DSPCore.h"
|
||||
#include "Core/DSP/DSPTables.h"
|
||||
|
||||
namespace DSP::Analyzer
|
||||
@@ -72,7 +72,7 @@ void Reset()
|
||||
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
|
||||
// where all instructions start.
|
||||
@@ -82,7 +82,7 @@ void AnalyzeRange(u16 start_addr, u16 end_addr)
|
||||
u16 last_arithmetic = 0;
|
||||
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);
|
||||
if (!opcode)
|
||||
{
|
||||
@@ -94,7 +94,7 @@ void AnalyzeRange(u16 start_addr, u16 end_addr)
|
||||
if ((inst & 0xffe0) == 0x0060 || (inst & 0xff00) == 0x1100)
|
||||
{
|
||||
// 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[loop_end] |= CODE_LOOP_END;
|
||||
}
|
||||
@@ -139,7 +139,7 @@ void AnalyzeRange(u16 start_addr, u16 end_addr)
|
||||
found = true;
|
||||
if (idle_skip_sigs[s][i] == 0xFFFF)
|
||||
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;
|
||||
}
|
||||
if (found)
|
||||
@@ -153,11 +153,11 @@ void AnalyzeRange(u16 start_addr, u16 end_addr)
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
void Analyze()
|
||||
void Analyze(const SDSP& dsp)
|
||||
{
|
||||
Reset();
|
||||
AnalyzeRange(0x0000, 0x1000); // IRAM
|
||||
AnalyzeRange(0x8000, 0x9000); // IROM
|
||||
AnalyzeRange(dsp, 0x0000, 0x1000); // IRAM
|
||||
AnalyzeRange(dsp, 0x8000, 0x9000); // IROM
|
||||
}
|
||||
|
||||
u8 GetCodeFlags(u16 address)
|
||||
|
||||
@@ -6,6 +6,11 @@
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
namespace DSP
|
||||
{
|
||||
struct SDSP;
|
||||
}
|
||||
|
||||
// Basic code analysis.
|
||||
namespace DSP::Analyzer
|
||||
{
|
||||
@@ -28,7 +33,7 @@ enum
|
||||
// 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
|
||||
// some pretty expensive analysis if necessary.
|
||||
void Analyze();
|
||||
void Analyze(const SDSP& dsp);
|
||||
|
||||
// Retrieves the flags set during analysis for code in memory.
|
||||
u8 GetCodeFlags(u16 address);
|
||||
|
||||
+378
-228
File diff suppressed because it is too large
Load Diff
+272
-72
@@ -11,12 +11,21 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "Common/Event.h"
|
||||
#include "Core/DSP/DSPBreakpoints.h"
|
||||
#include "Core/DSP/DSPCaptureLogger.h"
|
||||
|
||||
class PointerWrap;
|
||||
|
||||
namespace DSP
|
||||
{
|
||||
class Accelerator;
|
||||
class DSPCore;
|
||||
|
||||
namespace Interpreter
|
||||
{
|
||||
class Interpreter;
|
||||
}
|
||||
|
||||
namespace JIT
|
||||
{
|
||||
@@ -216,6 +225,12 @@ enum class ExceptionType
|
||||
ExternalInterrupt = 7 // 0x000e external int (message from CPU)
|
||||
};
|
||||
|
||||
enum Mailbox : int
|
||||
{
|
||||
MAILBOX_CPU,
|
||||
MAILBOX_DSP
|
||||
};
|
||||
|
||||
struct DSP_Regs
|
||||
{
|
||||
u16 ar[4];
|
||||
@@ -259,61 +274,6 @@ struct DSP_Regs
|
||||
} ac[2];
|
||||
};
|
||||
|
||||
// All the state of the DSP should be in this struct. Any DSP state that is not filled on init
|
||||
// should be moved here.
|
||||
struct SDSP
|
||||
{
|
||||
DSP_Regs r;
|
||||
u16 pc;
|
||||
#if PROFILE
|
||||
u16 err_pc;
|
||||
#endif
|
||||
|
||||
// This is NOT the same cr as r.cr.
|
||||
// This register is shared with the main emulation, see DSP.cpp
|
||||
// The engine has control over 0x0C07 of this reg.
|
||||
// Bits are defined in a struct in DSP.cpp.
|
||||
u16 cr;
|
||||
|
||||
u8 reg_stack_ptrs[4];
|
||||
u8 exceptions; // pending exceptions
|
||||
volatile bool external_interrupt_waiting;
|
||||
bool reset_dspjit_codespace;
|
||||
|
||||
// DSP hardware stacks. They're mapped to a bunch of registers, such that writes
|
||||
// to them push and reads pop.
|
||||
// Let's make stack depth 32 for now, which is way more than what's needed.
|
||||
// The real DSP has different depths for the different stacks, but it would
|
||||
// be strange if any ucode relied on stack overflows since on the DSP, when
|
||||
// the stack overflows, you're screwed.
|
||||
u16 reg_stacks[4][DSP_STACK_DEPTH];
|
||||
|
||||
// For debugging.
|
||||
u32 iram_crc;
|
||||
u64 step_counter;
|
||||
|
||||
// Mailbox.
|
||||
std::atomic<u32> mbox[2];
|
||||
|
||||
// Accelerator / DMA / other hardware registers. Not GPRs.
|
||||
std::array<u16, 256> ifx_regs;
|
||||
|
||||
std::unique_ptr<Accelerator> accelerator;
|
||||
|
||||
// When state saving, all of the above can just be memcpy'd into the save state.
|
||||
// The below needs special handling.
|
||||
u16* iram;
|
||||
u16* dram;
|
||||
u16* irom;
|
||||
u16* coef;
|
||||
};
|
||||
|
||||
extern SDSP g_dsp;
|
||||
extern DSPBreakpoints g_dsp_breakpoints;
|
||||
extern bool g_init_hax;
|
||||
extern std::unique_ptr<JIT::DSPEmitter> g_dsp_jit;
|
||||
extern std::unique_ptr<DSPCaptureLogger> g_dsp_cap;
|
||||
|
||||
struct DSPInitOptions
|
||||
{
|
||||
// DSP IROM blob, which is where the DSP boots from. Embedded into the DSP.
|
||||
@@ -338,19 +298,158 @@ struct DSPInitOptions
|
||||
DSPInitOptions() : capture_logger(new DefaultDSPCaptureLogger()) {}
|
||||
};
|
||||
|
||||
// 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);
|
||||
// All the state of the DSP should be in this struct. Any DSP state that is not filled on init
|
||||
// should be moved here.
|
||||
struct SDSP
|
||||
{
|
||||
explicit SDSP(DSPCore& core);
|
||||
~SDSP();
|
||||
|
||||
void DSPCore_Reset();
|
||||
void DSPCore_Shutdown(); // Frees all allocated memory.
|
||||
SDSP(const SDSP&) = delete;
|
||||
SDSP& operator=(const SDSP&) = delete;
|
||||
|
||||
void DSPCore_CheckExternalInterrupt();
|
||||
void DSPCore_CheckExceptions();
|
||||
void DSPCore_SetExternalInterrupt(bool val);
|
||||
SDSP(SDSP&&) = delete;
|
||||
SDSP& operator=(SDSP&&) = delete;
|
||||
|
||||
// sets a flag in the pending exception register.
|
||||
void DSPCore_SetException(ExceptionType exception);
|
||||
// Initializes overall state.
|
||||
bool Initialize(const DSPInitOptions& opts);
|
||||
|
||||
// Shuts down any necessary DSP state.
|
||||
void Shutdown();
|
||||
|
||||
// Resets DSP state as if the reset exception vector has been taken.
|
||||
void Reset();
|
||||
|
||||
// Initializes the IFX registers.
|
||||
void InitializeIFX();
|
||||
|
||||
// Writes to IFX registers.
|
||||
void WriteIFX(u32 address, u16 value);
|
||||
|
||||
// Reads from IFX registers.
|
||||
u16 ReadIFX(u16 address);
|
||||
|
||||
// Checks the whole value within a mailbox.
|
||||
u32 PeekMailbox(Mailbox mailbox) const;
|
||||
|
||||
// Reads the low part of the value in the specified mailbox.
|
||||
u16 ReadMailboxLow(Mailbox mailbox);
|
||||
|
||||
// Reads the high part of the value in the specified mailbox.
|
||||
u16 ReadMailboxHigh(Mailbox mailbox);
|
||||
|
||||
// Writes to the low part of the mailbox.
|
||||
void WriteMailboxLow(Mailbox mailbox, u16 value);
|
||||
|
||||
// Writes to the high part of the mailbox.
|
||||
void WriteMailboxHigh(Mailbox mailbox, u16 value);
|
||||
|
||||
// Reads from instruction memory.
|
||||
u16 ReadIMEM(u16 address) const;
|
||||
|
||||
// Reads from data memory.
|
||||
u16 ReadDMEM(u16 address);
|
||||
|
||||
// Write to data memory.
|
||||
void WriteDMEM(u16 address, u16 value);
|
||||
|
||||
// Fetches the next instruction and increments the PC.
|
||||
u16 FetchInstruction();
|
||||
|
||||
// Fetches the instruction at the PC address, but doesn't increment the PC.
|
||||
u16 PeekInstruction() const;
|
||||
|
||||
// Skips over the next instruction in memory.
|
||||
void SkipInstruction();
|
||||
|
||||
// Sets the given flags in the SR register.
|
||||
void SetSRFlag(u16 flag) { r.sr |= flag; }
|
||||
|
||||
// Whether or not the given flag is set in the SR register.
|
||||
bool IsSRFlagSet(u16 flag) const { return (r.sr & flag) != 0; }
|
||||
|
||||
// Indicates that a particular exception has occurred
|
||||
// and sets a flag in the pending exception register.
|
||||
void SetException(ExceptionType exception);
|
||||
|
||||
// Checks if any exceptions occurred an updates the DSP state as appropriate.
|
||||
void CheckExceptions();
|
||||
|
||||
// Notify that an external interrupt is pending (used by thread mode)
|
||||
void SetExternalInterrupt(bool val);
|
||||
|
||||
// Coming from the CPU
|
||||
void CheckExternalInterrupt();
|
||||
|
||||
// Stores a value into the specified stack
|
||||
void StoreStack(StackRegister stack_reg, u16 val);
|
||||
|
||||
// Pops a value off of the specified stack
|
||||
u16 PopStack(StackRegister stack_reg);
|
||||
|
||||
// Reads the current value from a particular register.
|
||||
u16 ReadRegister(size_t reg) const;
|
||||
|
||||
// Writes a value to a given register.
|
||||
void WriteRegister(size_t reg, u16 val);
|
||||
|
||||
// Saves and loads any necessary state.
|
||||
void DoState(PointerWrap& p);
|
||||
|
||||
DSP_Regs r{};
|
||||
u16 pc = 0;
|
||||
|
||||
// This is NOT the same cr as r.cr.
|
||||
// This register is shared with the main emulation, see DSP.cpp
|
||||
// The engine has control over 0x0C07 of this reg.
|
||||
// Bits are defined in a struct in DSP.cpp.
|
||||
u16 cr = 0;
|
||||
|
||||
u8 reg_stack_ptrs[4]{};
|
||||
u8 exceptions = 0; // pending exceptions
|
||||
volatile bool external_interrupt_waiting = false;
|
||||
bool reset_dspjit_codespace = false;
|
||||
|
||||
// DSP hardware stacks. They're mapped to a bunch of registers, such that writes
|
||||
// to them push and reads pop.
|
||||
// Let's make stack depth 32 for now, which is way more than what's needed.
|
||||
// The real DSP has different depths for the different stacks, but it would
|
||||
// be strange if any ucode relied on stack overflows since on the DSP, when
|
||||
// the stack overflows, you're screwed.
|
||||
u16 reg_stacks[4][DSP_STACK_DEPTH]{};
|
||||
|
||||
// For debugging.
|
||||
u32 iram_crc = 0;
|
||||
u64 step_counter = 0;
|
||||
|
||||
// Mailbox.
|
||||
std::atomic<u32> mbox[2];
|
||||
|
||||
// Accelerator / DMA / other hardware registers. Not GPRs.
|
||||
std::array<u16, 256> ifx_regs{};
|
||||
|
||||
std::unique_ptr<Accelerator> accelerator;
|
||||
|
||||
// When state saving, all of the above can just be memcpy'd into the save state.
|
||||
// The below needs special handling.
|
||||
u16* iram = nullptr;
|
||||
u16* dram = nullptr;
|
||||
u16* irom = nullptr;
|
||||
u16* coef = nullptr;
|
||||
|
||||
private:
|
||||
void FreeMemoryPages();
|
||||
|
||||
void DoDMA();
|
||||
const u8* DDMAIn(u16 dsp_addr, u32 addr, u32 size);
|
||||
const u8* DDMAOut(u16 dsp_addr, u32 addr, u32 size);
|
||||
const u8* IDMAIn(u16 dsp_addr, u32 addr, u32 size);
|
||||
const u8* IDMAOut(u16 dsp_addr, u32 addr, u32 size);
|
||||
|
||||
u16 ReadIFXImpl(u16 address);
|
||||
|
||||
DSPCore& m_dsp_core;
|
||||
};
|
||||
|
||||
enum class State
|
||||
{
|
||||
@@ -359,14 +458,115 @@ enum class State
|
||||
Stepping,
|
||||
};
|
||||
|
||||
int DSPCore_RunCycles(int cycles);
|
||||
class DSPCore
|
||||
{
|
||||
public:
|
||||
DSPCore();
|
||||
~DSPCore();
|
||||
|
||||
// These are meant to be called from the UI thread.
|
||||
void DSPCore_SetState(State new_state);
|
||||
State DSPCore_GetState();
|
||||
DSPCore(const DSPCore&) = delete;
|
||||
DSPCore& operator=(const DSPCore&) = delete;
|
||||
|
||||
void DSPCore_Step();
|
||||
DSPCore(DSPCore&&) = delete;
|
||||
DSPCore& operator=(DSPCore&&) = delete;
|
||||
|
||||
u16 DSPCore_ReadRegister(size_t reg);
|
||||
void DSPCore_WriteRegister(size_t reg, u16 val);
|
||||
// Initializes the DSP emulator using the provided options. Takes ownership of
|
||||
// all the pointers contained in the options structure.
|
||||
bool Initialize(const DSPInitOptions& opts);
|
||||
|
||||
// Shuts down the DSP core and cleans up any necessary state.
|
||||
void Shutdown();
|
||||
|
||||
// Delegates to JIT or interpreter as appropriate.
|
||||
// Handle state changes and stepping.
|
||||
int RunCycles(int cycles);
|
||||
|
||||
// Steps the DSP by a single instruction.
|
||||
void Step();
|
||||
|
||||
// Resets DSP state as if the reset exception vector has been taken.
|
||||
void Reset();
|
||||
|
||||
// Clears the DSP instruction RAM.
|
||||
void ClearIRAM();
|
||||
|
||||
// Dictates whether or not the DSP is currently stopped, running or stepping
|
||||
// through instructions.
|
||||
void SetState(State new_state);
|
||||
|
||||
// Retrieves the current execution state of the DSP.
|
||||
State GetState() const;
|
||||
|
||||
// Indicates that a particular exception has occurred
|
||||
// and sets a flag in the pending exception register.
|
||||
void SetException(ExceptionType exception);
|
||||
|
||||
// Notify that an external interrupt is pending (used by thread mode)
|
||||
void SetExternalInterrupt(bool val);
|
||||
|
||||
// Coming from the CPU
|
||||
void CheckExternalInterrupt();
|
||||
|
||||
// Checks if any exceptions occurred an updates the DSP state as appropriate.
|
||||
void CheckExceptions();
|
||||
|
||||
// Reads the current value from a particular register.
|
||||
u16 ReadRegister(size_t reg) const;
|
||||
|
||||
// Writes a value to a given register.
|
||||
void WriteRegister(size_t reg, u16 val);
|
||||
|
||||
// Checks the value within a mailbox.
|
||||
u32 PeekMailbox(Mailbox mailbox) const;
|
||||
|
||||
// Reads the low part of the specified mailbox register.
|
||||
u16 ReadMailboxLow(Mailbox mailbox);
|
||||
|
||||
// Reads the high part of the specified mailbox register.
|
||||
u16 ReadMailboxHigh(Mailbox mailbox);
|
||||
|
||||
// Writes to the low part of the mailbox register.
|
||||
void WriteMailboxLow(Mailbox mailbox, u16 value);
|
||||
|
||||
// Writes to the high part of the mailbox register.
|
||||
void WriteMailboxHigh(Mailbox mailbox, u16 value);
|
||||
|
||||
// Logs an IFX register read.
|
||||
void LogIFXRead(u16 address, u16 read_value);
|
||||
|
||||
// Logs an IFX register write.
|
||||
void LogIFXWrite(u16 address, u16 written_value);
|
||||
|
||||
// Logs a DMA operation
|
||||
void LogDMA(u16 control, u32 gc_address, u16 dsp_address, u16 length, const u8* data);
|
||||
|
||||
// Whether or not the JIT has been created.
|
||||
bool IsJITCreated() const;
|
||||
|
||||
// Writes or loads state for savestates.
|
||||
void DoState(PointerWrap& p);
|
||||
|
||||
// Accessors for the DSP breakpoint facilities.
|
||||
DSPBreakpoints& BreakPoints() { return m_dsp_breakpoints; }
|
||||
const DSPBreakpoints& BreakPoints() const { return m_dsp_breakpoints; }
|
||||
|
||||
SDSP& DSPState() { return m_dsp; }
|
||||
const SDSP& DSPState() const { return m_dsp; }
|
||||
|
||||
Interpreter::Interpreter& GetInterpreter() { return *m_dsp_interpreter; }
|
||||
const Interpreter::Interpreter& GetInterpreter() const { return *m_dsp_interpreter; }
|
||||
|
||||
bool GetInitHax() const { return m_init_hax; }
|
||||
void SetInitHax(bool value) { m_init_hax = value; }
|
||||
|
||||
private:
|
||||
SDSP m_dsp;
|
||||
DSPBreakpoints m_dsp_breakpoints;
|
||||
State m_core_state = State::Stopped;
|
||||
bool m_init_hax = false;
|
||||
std::unique_ptr<Interpreter::Interpreter> m_dsp_interpreter;
|
||||
std::unique_ptr<JIT::DSPEmitter> m_dsp_jit;
|
||||
std::unique_ptr<DSPCaptureLogger> m_dsp_cap;
|
||||
Common::Event m_step_event;
|
||||
};
|
||||
} // namespace DSP
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,27 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Copyright 2004 Duddie & Tratax
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
namespace DSP
|
||||
{
|
||||
enum Mailbox
|
||||
{
|
||||
MAILBOX_CPU,
|
||||
MAILBOX_DSP
|
||||
};
|
||||
|
||||
u32 gdsp_mbox_peek(Mailbox mbx);
|
||||
void gdsp_mbox_write_h(Mailbox mbx, u16 val);
|
||||
void gdsp_mbox_write_l(Mailbox mbx, u16 val);
|
||||
u16 gdsp_mbox_read_h(Mailbox mbx);
|
||||
u16 gdsp_mbox_read_l(Mailbox mbx);
|
||||
|
||||
void gdsp_ifx_init();
|
||||
void gdsp_ifx_write(u32 addr, u16 val);
|
||||
u16 gdsp_ifx_read(u16 addr);
|
||||
} // namespace DSP
|
||||
@@ -13,6 +13,11 @@
|
||||
// core isn't used, for example in an asm/disasm tool, then most of these
|
||||
// can be stubbed out.
|
||||
|
||||
namespace DSP
|
||||
{
|
||||
class DSPCore;
|
||||
}
|
||||
|
||||
namespace DSP::Host
|
||||
{
|
||||
u8 ReadHostMemory(u32 addr);
|
||||
@@ -23,7 +28,7 @@ void OSD_AddMessage(std::string str, u32 ms);
|
||||
bool OnThread();
|
||||
bool IsWiiHost();
|
||||
void InterruptRequest();
|
||||
void CodeLoaded(u32 addr, size_t size);
|
||||
void CodeLoaded(const u8* ptr, size_t size);
|
||||
void CodeLoaded(DSPCore& dsp, u32 addr, size_t size);
|
||||
void CodeLoaded(DSPCore& dsp, const u8* ptr, size_t size);
|
||||
void UpdateDebugger();
|
||||
} // namespace DSP::Host
|
||||
|
||||
@@ -3,86 +3,81 @@
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Core/DSP/DSPMemoryMap.h"
|
||||
|
||||
#include "Common/Logging/Log.h"
|
||||
|
||||
#include "Core/DSP/DSPCore.h"
|
||||
#include "Core/DSP/DSPHWInterface.h"
|
||||
#include "Core/DSP/DSPTables.h"
|
||||
|
||||
namespace DSP
|
||||
{
|
||||
u16 dsp_imem_read(u16 addr)
|
||||
u16 SDSP::ReadIMEM(u16 address) const
|
||||
{
|
||||
switch (addr >> 12)
|
||||
switch (address >> 12)
|
||||
{
|
||||
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.
|
||||
return g_dsp.irom[addr & DSP_IROM_MASK];
|
||||
return irom[address & DSP_IROM_MASK];
|
||||
|
||||
default: // Unmapped/non-existing memory
|
||||
ERROR_LOG_FMT(DSPLLE, "{:04x} DSP ERROR: Executing from invalid ({:04x}) memory", g_dsp.pc,
|
||||
addr);
|
||||
ERROR_LOG_FMT(DSPLLE, "{:04x} DSP ERROR: Executing from invalid ({:04x}) memory", pc, address);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
u16 dsp_dmem_read(u16 addr)
|
||||
u16 SDSP::ReadDMEM(u16 address)
|
||||
{
|
||||
switch (addr >> 12)
|
||||
switch (address >> 12)
|
||||
{
|
||||
case 0x0: // 0xxx DRAM
|
||||
return g_dsp.dram[addr & DSP_DRAM_MASK];
|
||||
return dram[address & DSP_DRAM_MASK];
|
||||
|
||||
case 0x1: // 1xxx COEF
|
||||
DEBUG_LOG_FMT(DSPLLE, "{:04x} : Coefficient Read @ {:04x}", g_dsp.pc, addr);
|
||||
return g_dsp.coef[addr & DSP_COEF_MASK];
|
||||
DEBUG_LOG_FMT(DSPLLE, "{:04x} : Coefficient Read @ {:04x}", pc, address);
|
||||
return coef[address & DSP_COEF_MASK];
|
||||
|
||||
case 0xf: // Fxxx HW regs
|
||||
return gdsp_ifx_read(addr);
|
||||
return ReadIFX(address);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
g_dsp.dram[addr & DSP_DRAM_MASK] = val;
|
||||
dram[address & DSP_DRAM_MASK] = value;
|
||||
break;
|
||||
|
||||
case 0xf: // Fxxx HW regs
|
||||
gdsp_ifx_write(addr, val);
|
||||
WriteIFX(address, value);
|
||||
break;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
u16 dsp_fetch_code()
|
||||
u16 SDSP::FetchInstruction()
|
||||
{
|
||||
u16 opc = dsp_imem_read(g_dsp.pc);
|
||||
|
||||
g_dsp.pc++;
|
||||
const u16 opc = PeekInstruction();
|
||||
pc++;
|
||||
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
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Copyright 2004 Duddie & Tratax
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
namespace DSP
|
||||
{
|
||||
u16 dsp_imem_read(u16 addr);
|
||||
void dsp_dmem_write(u16 addr, u16 val);
|
||||
u16 dsp_dmem_read(u16 addr);
|
||||
|
||||
u16 dsp_fetch_code();
|
||||
u16 dsp_peek_code();
|
||||
void dsp_skip_inst();
|
||||
} // namespace DSP
|
||||
@@ -3,8 +3,6 @@
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Core/DSP/DSPStacks.h"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
@@ -13,34 +11,26 @@
|
||||
// Stacks. The stacks are outside the DSP RAM, in dedicated hardware.
|
||||
namespace DSP
|
||||
{
|
||||
static void dsp_reg_stack_push(size_t stack_reg)
|
||||
{
|
||||
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)
|
||||
void SDSP::StoreStack(StackRegister stack_reg, u16 val)
|
||||
{
|
||||
const auto reg_index = static_cast<size_t>(stack_reg);
|
||||
|
||||
dsp_reg_stack_push(reg_index);
|
||||
g_dsp.r.st[reg_index] = val;
|
||||
reg_stack_ptrs[reg_index]++;
|
||||
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 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;
|
||||
}
|
||||
} // namespace DSP
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Copyright 2004 Duddie & Tratax
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
namespace DSP
|
||||
{
|
||||
enum class StackRegister;
|
||||
|
||||
void dsp_reg_store_stack(StackRegister stack_reg, u16 val);
|
||||
u16 dsp_reg_load_stack(StackRegister stack_reg);
|
||||
} // namespace DSP
|
||||
@@ -477,9 +477,6 @@ const std::array<pdlabel_t, 36> regnames =
|
||||
}};
|
||||
// clang-format on
|
||||
|
||||
std::array<u16, WRITEBACK_LOG_SIZE> writeBackLog;
|
||||
std::array<int, WRITEBACK_LOG_SIZE> writeBackLogIdx;
|
||||
|
||||
const char* pdname(u16 val)
|
||||
{
|
||||
static char tmpstr[12]; // nasty
|
||||
@@ -612,10 +609,5 @@ void InitInstructionTable()
|
||||
else
|
||||
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
|
||||
|
||||
@@ -85,10 +85,6 @@ struct DSPOPCTemplate
|
||||
// Opcodes
|
||||
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
|
||||
struct pdlabel_t
|
||||
{
|
||||
@@ -105,9 +101,6 @@ const char* pdregname(int val);
|
||||
const char* pdregnamelong(int val);
|
||||
|
||||
void InitInstructionTable();
|
||||
void ApplyWriteBackLog();
|
||||
void ZeroWriteBackLog();
|
||||
void ZeroWriteBackLogPreserveAcc(u8 acc);
|
||||
|
||||
// Used by the assembler and disassembler for info retrieval.
|
||||
const DSPOPCTemplate* FindOpInfoByOpcode(UDSPInstruction opcode);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,10 +5,6 @@
|
||||
// Additional copyrights go to Duddie and Tratax (c) 2004
|
||||
|
||||
#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"
|
||||
|
||||
namespace DSP::Interpreter
|
||||
@@ -20,14 +16,16 @@ namespace DSP::Interpreter
|
||||
// Call function if condition cc has been met. Push program counter of
|
||||
// instruction following "call" to $st0. Set program counter to address
|
||||
// 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.
|
||||
u16 dest = dsp_fetch_code();
|
||||
const u16 dest = state.FetchInstruction();
|
||||
if (CheckCondition(opc & 0xf))
|
||||
{
|
||||
dsp_reg_store_stack(StackRegister::Call, g_dsp.pc);
|
||||
g_dsp.pc = dest;
|
||||
state.StoreStack(StackRegister::Call, state.pc);
|
||||
state.pc = dest;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,28 +35,29 @@ void call(const UDSPInstruction opc)
|
||||
// Call function if condition cc has been met. Push program counter of
|
||||
// instruction following "call" to call stack $st0. Set program counter to
|
||||
// register $R.
|
||||
void callr(const UDSPInstruction opc)
|
||||
void Interpreter::callr(const UDSPInstruction opc)
|
||||
{
|
||||
if (CheckCondition(opc & 0xf))
|
||||
{
|
||||
u8 reg = (opc >> 5) & 0x7;
|
||||
u16 addr = dsp_op_read_reg(reg);
|
||||
dsp_reg_store_stack(StackRegister::Call, g_dsp.pc);
|
||||
g_dsp.pc = addr;
|
||||
}
|
||||
if (!CheckCondition(opc & 0xf))
|
||||
return;
|
||||
|
||||
auto& state = m_dsp_core.DSPState();
|
||||
const u8 reg = (opc >> 5) & 0x7;
|
||||
const u16 addr = OpReadRegister(reg);
|
||||
state.StoreStack(StackRegister::Call, state.pc);
|
||||
state.pc = addr;
|
||||
}
|
||||
|
||||
// Generic if implementation
|
||||
// IFcc
|
||||
// 0000 0010 0111 cccc
|
||||
// Execute following opcode if the condition has been met.
|
||||
void ifcc(const UDSPInstruction opc)
|
||||
void Interpreter::ifcc(const UDSPInstruction opc)
|
||||
{
|
||||
if (!CheckCondition(opc & 0xf))
|
||||
{
|
||||
// skip the next opcode - we have to lookup its size.
|
||||
dsp_skip_inst();
|
||||
}
|
||||
if (CheckCondition(opc & 0xf))
|
||||
return;
|
||||
|
||||
// skip the next opcode - we have to lookup its size.
|
||||
m_dsp_core.DSPState().SkipInstruction();
|
||||
}
|
||||
|
||||
// Generic jmp implementation
|
||||
@@ -67,12 +66,13 @@ void ifcc(const UDSPInstruction opc)
|
||||
// aaaa aaaa aaaa aaaa
|
||||
// Jump to addressA if condition cc has been met. Set program counter to
|
||||
// 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))
|
||||
{
|
||||
g_dsp.pc = dest;
|
||||
state.pc = dest;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,13 +80,14 @@ void jcc(const UDSPInstruction opc)
|
||||
// JMPcc $R
|
||||
// 0001 0111 rrr0 cccc
|
||||
// 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))
|
||||
{
|
||||
u8 reg = (opc >> 5) & 0x7;
|
||||
g_dsp.pc = dsp_op_read_reg(reg);
|
||||
}
|
||||
if (!CheckCondition(opc & 0xf))
|
||||
return;
|
||||
|
||||
auto& state = m_dsp_core.DSPState();
|
||||
const u8 reg = (opc >> 5) & 0x7;
|
||||
state.pc = OpReadRegister(reg);
|
||||
}
|
||||
|
||||
// Generic ret implementation
|
||||
@@ -94,12 +95,13 @@ void jmprcc(const UDSPInstruction opc)
|
||||
// 0000 0010 1101 cccc
|
||||
// Return from subroutine if condition cc has been met. Pops stored PC
|
||||
// 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))
|
||||
{
|
||||
g_dsp.pc = dsp_reg_load_stack(StackRegister::Call);
|
||||
}
|
||||
if (!CheckCondition(opc & 0xf))
|
||||
return;
|
||||
|
||||
auto& state = m_dsp_core.DSPState();
|
||||
state.pc = state.PopStack(StackRegister::Call);
|
||||
}
|
||||
|
||||
// RTI
|
||||
@@ -107,19 +109,21 @@ void ret(const UDSPInstruction opc)
|
||||
// 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
|
||||
// location.
|
||||
void rti(const UDSPInstruction opc)
|
||||
void Interpreter::rti(const UDSPInstruction)
|
||||
{
|
||||
g_dsp.r.sr = dsp_reg_load_stack(StackRegister::Data);
|
||||
g_dsp.pc = dsp_reg_load_stack(StackRegister::Call);
|
||||
auto& state = m_dsp_core.DSPState();
|
||||
state.r.sr = state.PopStack(StackRegister::Data);
|
||||
state.pc = state.PopStack(StackRegister::Call);
|
||||
}
|
||||
|
||||
// HALT
|
||||
// 0000 0000 0020 0001
|
||||
// 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;
|
||||
g_dsp.pc--;
|
||||
auto& state = m_dsp_core.DSPState();
|
||||
state.cr |= 0x4;
|
||||
state.pc--;
|
||||
}
|
||||
|
||||
// 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
|
||||
// call stack $st0 and both loop stacks $st2 and $st3 are popped and execution
|
||||
// continues at next opcode.
|
||||
void HandleLoop()
|
||||
void Interpreter::HandleLoop()
|
||||
{
|
||||
auto& state = m_dsp_core.DSPState();
|
||||
|
||||
// Handle looping hardware.
|
||||
const u16 rCallAddress = g_dsp.r.st[0];
|
||||
const u16 rLoopAddress = g_dsp.r.st[2];
|
||||
u16& rLoopCounter = g_dsp.r.st[3];
|
||||
const u16 rCallAddress = state.r.st[0];
|
||||
const u16 rLoopAddress = state.r.st[2];
|
||||
u16& rLoopCounter = state.r.st[3];
|
||||
|
||||
if (rLoopAddress > 0 && rLoopCounter > 0)
|
||||
{
|
||||
// FIXME: why -1? because we just read past it.
|
||||
if (g_dsp.pc - 1 == rLoopAddress)
|
||||
if (state.pc - 1 == rLoopAddress)
|
||||
{
|
||||
rLoopCounter--;
|
||||
if (rLoopCounter > 0)
|
||||
{
|
||||
g_dsp.pc = rCallAddress;
|
||||
state.pc = rCallAddress;
|
||||
}
|
||||
else
|
||||
{
|
||||
// end of loop
|
||||
dsp_reg_load_stack(StackRegister::Call);
|
||||
dsp_reg_load_stack(StackRegister::LoopAddress);
|
||||
dsp_reg_load_stack(StackRegister::LoopCounter);
|
||||
state.PopStack(StackRegister::Call);
|
||||
state.PopStack(StackRegister::LoopAddress);
|
||||
state.PopStack(StackRegister::LoopCounter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -164,21 +170,22 @@ void HandleLoop()
|
||||
// then looped instruction will not get executed.
|
||||
// Actually, this instruction simply prepares the loop stacks for the above.
|
||||
// The looping hardware takes care of the rest.
|
||||
void loop(const UDSPInstruction opc)
|
||||
void Interpreter::loop(const UDSPInstruction opc)
|
||||
{
|
||||
u16 reg = opc & 0x1f;
|
||||
u16 cnt = dsp_op_read_reg(reg);
|
||||
u16 loop_pc = g_dsp.pc;
|
||||
auto& state = m_dsp_core.DSPState();
|
||||
const u16 reg = opc & 0x1f;
|
||||
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);
|
||||
dsp_reg_store_stack(StackRegister::LoopAddress, loop_pc);
|
||||
dsp_reg_store_stack(StackRegister::LoopCounter, cnt);
|
||||
state.StoreStack(StackRegister::Call, state.pc);
|
||||
state.StoreStack(StackRegister::LoopAddress, loop_pc);
|
||||
state.StoreStack(StackRegister::LoopCounter, cnt);
|
||||
}
|
||||
else
|
||||
{
|
||||
dsp_skip_inst();
|
||||
state.SkipInstruction();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,20 +197,21 @@ void loop(const UDSPInstruction opc)
|
||||
// instruction will not get executed.
|
||||
// Actually, this instruction simply prepares the loop stacks for the above.
|
||||
// The looping hardware takes care of the rest.
|
||||
void loopi(const UDSPInstruction opc)
|
||||
void Interpreter::loopi(const UDSPInstruction opc)
|
||||
{
|
||||
u16 cnt = opc & 0xff;
|
||||
u16 loop_pc = g_dsp.pc;
|
||||
auto& state = m_dsp_core.DSPState();
|
||||
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);
|
||||
dsp_reg_store_stack(StackRegister::LoopAddress, loop_pc);
|
||||
dsp_reg_store_stack(StackRegister::LoopCounter, cnt);
|
||||
state.StoreStack(StackRegister::Call, state.pc);
|
||||
state.StoreStack(StackRegister::LoopAddress, loop_pc);
|
||||
state.StoreStack(StackRegister::LoopCounter, cnt);
|
||||
}
|
||||
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
|
||||
// is pushed on loop stack $st2 and repeat address is pushed on call stack $st0.
|
||||
// Up to 4 nested loops are allowed.
|
||||
void bloop(const UDSPInstruction opc)
|
||||
void Interpreter::bloop(const UDSPInstruction opc)
|
||||
{
|
||||
u16 reg = opc & 0x1f;
|
||||
u16 cnt = dsp_op_read_reg(reg);
|
||||
u16 loop_pc = dsp_fetch_code();
|
||||
auto& state = m_dsp_core.DSPState();
|
||||
const u16 reg = opc & 0x1f;
|
||||
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);
|
||||
dsp_reg_store_stack(StackRegister::LoopAddress, loop_pc);
|
||||
dsp_reg_store_stack(StackRegister::LoopCounter, cnt);
|
||||
state.StoreStack(StackRegister::Call, state.pc);
|
||||
state.StoreStack(StackRegister::LoopAddress, loop_pc);
|
||||
state.StoreStack(StackRegister::LoopCounter, cnt);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_dsp.pc = loop_pc;
|
||||
dsp_skip_inst();
|
||||
state.pc = loop_pc;
|
||||
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
|
||||
// on loop stack $st2 and repeat address is pushed on call stack $st0. Up to 4
|
||||
// nested loops are allowed.
|
||||
void bloopi(const UDSPInstruction opc)
|
||||
void Interpreter::bloopi(const UDSPInstruction opc)
|
||||
{
|
||||
u16 cnt = opc & 0xff;
|
||||
u16 loop_pc = dsp_fetch_code();
|
||||
auto& state = m_dsp_core.DSPState();
|
||||
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);
|
||||
dsp_reg_store_stack(StackRegister::LoopAddress, loop_pc);
|
||||
dsp_reg_store_stack(StackRegister::LoopCounter, cnt);
|
||||
state.StoreStack(StackRegister::Call, state.pc);
|
||||
state.StoreStack(StackRegister::LoopAddress, loop_pc);
|
||||
state.StoreStack(StackRegister::LoopCounter, cnt);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_dsp.pc = loop_pc;
|
||||
dsp_skip_inst();
|
||||
state.pc = loop_pc;
|
||||
state.SkipInstruction();
|
||||
}
|
||||
}
|
||||
} // namespace DSP::Interpreter
|
||||
|
||||
@@ -1,183 +0,0 @@
|
||||
// Copyright 2009 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
//
|
||||
// Additional copyrights go to Duddie and Tratax (c) 2004
|
||||
|
||||
// HELPER FUNCTIONS
|
||||
|
||||
#include "Core/DSP/Interpreter/DSPIntCCUtil.h"
|
||||
#include "Core/DSP/DSPCore.h"
|
||||
|
||||
namespace DSP::Interpreter
|
||||
{
|
||||
void Update_SR_Register64(s64 _Value, bool carry, bool overflow)
|
||||
{
|
||||
g_dsp.r.sr &= ~SR_CMP_MASK;
|
||||
|
||||
// 0x01
|
||||
if (carry)
|
||||
{
|
||||
g_dsp.r.sr |= SR_CARRY;
|
||||
}
|
||||
|
||||
// 0x02 and 0x80
|
||||
if (overflow)
|
||||
{
|
||||
g_dsp.r.sr |= SR_OVERFLOW;
|
||||
g_dsp.r.sr |= SR_OVERFLOW_STICKY;
|
||||
}
|
||||
|
||||
// 0x04
|
||||
if (_Value == 0)
|
||||
{
|
||||
g_dsp.r.sr |= SR_ARITH_ZERO;
|
||||
}
|
||||
|
||||
// 0x08
|
||||
if (_Value < 0)
|
||||
{
|
||||
g_dsp.r.sr |= SR_SIGN;
|
||||
}
|
||||
|
||||
// 0x10
|
||||
if (_Value != (s32)_Value)
|
||||
{
|
||||
g_dsp.r.sr |= SR_OVER_S32;
|
||||
}
|
||||
|
||||
// 0x20 - Checks if top bits of m are equal
|
||||
if (((_Value & 0xc0000000) == 0) || ((_Value & 0xc0000000) == 0xc0000000))
|
||||
{
|
||||
g_dsp.r.sr |= SR_TOP2BITS;
|
||||
}
|
||||
}
|
||||
|
||||
void Update_SR_Register16(s16 _Value, bool carry, bool overflow, bool overS32)
|
||||
{
|
||||
g_dsp.r.sr &= ~SR_CMP_MASK;
|
||||
|
||||
// 0x01
|
||||
if (carry)
|
||||
{
|
||||
g_dsp.r.sr |= SR_CARRY;
|
||||
}
|
||||
|
||||
// 0x02 and 0x80
|
||||
if (overflow)
|
||||
{
|
||||
g_dsp.r.sr |= SR_OVERFLOW;
|
||||
g_dsp.r.sr |= SR_OVERFLOW_STICKY;
|
||||
}
|
||||
|
||||
// 0x04
|
||||
if (_Value == 0)
|
||||
{
|
||||
g_dsp.r.sr |= SR_ARITH_ZERO;
|
||||
}
|
||||
|
||||
// 0x08
|
||||
if (_Value < 0)
|
||||
{
|
||||
g_dsp.r.sr |= SR_SIGN;
|
||||
}
|
||||
|
||||
// 0x10
|
||||
if (overS32)
|
||||
{
|
||||
g_dsp.r.sr |= SR_OVER_S32;
|
||||
}
|
||||
|
||||
// 0x20 - Checks if top bits of m are equal
|
||||
if ((((u16)_Value >> 14) == 0) || (((u16)_Value >> 14) == 3))
|
||||
{
|
||||
g_dsp.r.sr |= SR_TOP2BITS;
|
||||
}
|
||||
}
|
||||
|
||||
void Update_SR_LZ(bool value)
|
||||
{
|
||||
if (value == true)
|
||||
g_dsp.r.sr |= SR_LOGIC_ZERO;
|
||||
else
|
||||
g_dsp.r.sr &= ~SR_LOGIC_ZERO;
|
||||
}
|
||||
|
||||
static bool IsCarry()
|
||||
{
|
||||
return (g_dsp.r.sr & SR_CARRY) != 0;
|
||||
}
|
||||
|
||||
static bool IsOverflow()
|
||||
{
|
||||
return (g_dsp.r.sr & SR_OVERFLOW) != 0;
|
||||
}
|
||||
|
||||
static bool IsOverS32()
|
||||
{
|
||||
return (g_dsp.r.sr & SR_OVER_S32) != 0;
|
||||
}
|
||||
|
||||
static bool IsLess()
|
||||
{
|
||||
return (g_dsp.r.sr & SR_OVERFLOW) != (g_dsp.r.sr & SR_SIGN);
|
||||
}
|
||||
|
||||
static bool IsZero()
|
||||
{
|
||||
return (g_dsp.r.sr & SR_ARITH_ZERO) != 0;
|
||||
}
|
||||
|
||||
static bool IsLogicZero()
|
||||
{
|
||||
return (g_dsp.r.sr & SR_LOGIC_ZERO) != 0;
|
||||
}
|
||||
|
||||
static bool IsConditionA()
|
||||
{
|
||||
return (((g_dsp.r.sr & SR_OVER_S32) || (g_dsp.r.sr & SR_TOP2BITS)) &&
|
||||
!(g_dsp.r.sr & SR_ARITH_ZERO)) != 0;
|
||||
}
|
||||
|
||||
// see DSPCore.h for flags
|
||||
bool CheckCondition(u8 _Condition)
|
||||
{
|
||||
switch (_Condition & 0xf)
|
||||
{
|
||||
case 0xf: // Always true.
|
||||
return true;
|
||||
case 0x0: // GE - Greater Equal
|
||||
return !IsLess();
|
||||
case 0x1: // L - Less
|
||||
return IsLess();
|
||||
case 0x2: // G - Greater
|
||||
return !IsLess() && !IsZero();
|
||||
case 0x3: // LE - Less Equal
|
||||
return IsLess() || IsZero();
|
||||
case 0x4: // NZ - Not Zero
|
||||
return !IsZero();
|
||||
case 0x5: // Z - Zero
|
||||
return IsZero();
|
||||
case 0x6: // NC - Not carry
|
||||
return !IsCarry();
|
||||
case 0x7: // C - Carry
|
||||
return IsCarry();
|
||||
case 0x8: // ? - Not over s32
|
||||
return !IsOverS32();
|
||||
case 0x9: // ? - Over s32
|
||||
return IsOverS32();
|
||||
case 0xa: // ?
|
||||
return IsConditionA();
|
||||
case 0xb: // ?
|
||||
return !IsConditionA();
|
||||
case 0xc: // LNZ - Logic Not Zero
|
||||
return !IsLogicZero();
|
||||
case 0xd: // LZ - Logic Zero
|
||||
return IsLogicZero();
|
||||
case 0xe: // 0 - Overflow
|
||||
return IsOverflow();
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} // namespace DSP::Interpreter
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user