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-27 06:38:02 -05:00
parent 2917af03ec
commit 7d1bd565a6
50 changed files with 3037 additions and 3164 deletions
+25
View File
@@ -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)
{
-7
View File
@@ -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
-7
View File
@@ -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" />
-21
View File
@@ -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>
+8 -8
View File
@@ -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 -1
View File
@@ -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);
File diff suppressed because it is too large Load Diff
+214 -45
View File
@@ -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];
@@ -263,22 +278,82 @@ struct DSP_Regs
// should be moved here.
struct SDSP
{
DSP_Regs r;
u16 pc;
#if PROFILE
u16 err_pc;
#endif
explicit SDSP(DSPCore& core);
~SDSP();
SDSP(const SDSP&) = delete;
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 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;
u16 cr = 0;
u8 reg_stack_ptrs[4];
u8 exceptions; // pending exceptions
volatile bool external_interrupt_waiting;
bool reset_dspjit_codespace;
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.
@@ -286,33 +361,38 @@ struct SDSP
// 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];
u16 reg_stacks[4][DSP_STACK_DEPTH]{};
// For debugging.
u32 iram_crc;
u64 step_counter;
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::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;
};
u16* iram = nullptr;
u16* dram = nullptr;
u16* irom = nullptr;
u16* coef = nullptr;
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;
private:
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;
};
struct DSPInitOptions
{
@@ -338,20 +418,6 @@ 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);
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
{
Stopped,
@@ -359,14 +425,117 @@ 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:
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
File diff suppressed because it is too large Load Diff
-27
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
+7 -2
View File
@@ -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
+24 -29
View File
@@ -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
-19
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
+12 -22
View File
@@ -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
-16
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
-8
View File
@@ -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
-7
View File
@@ -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